1
1
mirror of https://github.com/bitgapp/eqMac.git synced 2024-11-22 22:32:17 +03:00
This commit is contained in:
Nodeful 2021-08-23 02:16:36 +03:00
parent e712cb55b1
commit 1e18a933ad
8 changed files with 46 additions and 32 deletions

View File

@ -30,7 +30,7 @@ let kDeviceManufacturer = "Bitgapp Ltd"
let kBoxDefaultName = "eqMac Box" let kBoxDefaultName = "eqMac Box"
let kPlugInBundleId = "com.bitgapp.eqmac.driver" let kPlugInBundleId = "com.bitgapp.eqmac.driver"
let kBoxUID = "eqMacBox_UID" let kBoxUID = "EQMBox"
let kDeviceUID = "EQMDevice" let kDeviceUID = "EQMDevice"
let kDeviceModelUID = "EQMDeviceModelUID" let kDeviceModelUID = "EQMDeviceModelUID"

View File

@ -137,7 +137,11 @@ class EQMBox: EQMObject {
return .integer(0) return .integer(0)
case kAudioBoxPropertyDeviceList: case kAudioBoxPropertyDeviceList:
// This is used to indicate which devices came from this box // This is used to indicate which devices came from this box
return .integer(acquired ? kObjectID_Device : 0) if acquired {
return .integer(kObjectID_Device)
} else {
return .null()
}
default: return nil default: return nil
} }
} }

View File

@ -113,7 +113,7 @@ class EQMDevice: EQMObject {
case kAudioObjectPropertyControlList: return 6 * sizeof(AudioObjectID.self) case kAudioObjectPropertyControlList: return 6 * sizeof(AudioObjectID.self)
case kAudioDevicePropertySafetyOffset: return sizeof(UInt32.self) case kAudioDevicePropertySafetyOffset: return sizeof(UInt32.self)
case kAudioDevicePropertyNominalSampleRate: return sizeof(Float64.self) case kAudioDevicePropertyNominalSampleRate: return sizeof(Float64.self)
case kAudioDevicePropertyAvailableNominalSampleRates: return 6 * sizeof(AudioValueRange.self) case kAudioDevicePropertyAvailableNominalSampleRates: return UInt32(kSupportedSamplingRates.count) * sizeof(AudioValueRange.self)
case kAudioDevicePropertyIsHidden: return sizeof(UInt32.self) case kAudioDevicePropertyIsHidden: return sizeof(UInt32.self)
case kAudioDevicePropertyPreferredChannelsForStereo: return 2 * sizeof(UInt32.self) case kAudioDevicePropertyPreferredChannelsForStereo: return 2 * sizeof(UInt32.self)
case kAudioDevicePropertyPreferredChannelLayout: case kAudioDevicePropertyPreferredChannelLayout:
@ -183,7 +183,8 @@ class EQMDevice: EQMObject {
kObjectID_Volume_Output_Master, kObjectID_Volume_Output_Master,
kObjectID_Mute_Output_Master, kObjectID_Mute_Output_Master,
kObjectID_DataSource_Output_Master, kObjectID_DataSource_Output_Master,
]) default: return .objectIDList([]) ])
default: return .objectIDList([])
} }
case kAudioDevicePropertyDeviceUID: case kAudioDevicePropertyDeviceUID:
// This is a CFString that is a persistent token that can identify the same // This is a CFString that is a persistent token that can identify the same
@ -335,7 +336,8 @@ class EQMDevice: EQMObject {
mNumberChannelDescriptions: UInt32(kChannelCount), mNumberChannelDescriptions: UInt32(kChannelCount),
mChannelDescriptions: AudioChannelDescription() mChannelDescriptions: AudioChannelDescription()
) )
let channelSize = MemoryLayout<AudioChannelDescription>.stride * channelDescriptions.count // INFO: have to go with channelDescriptions.count - 1 as MemoryLayout<AudioChannelDescription>.stride might already contain the size for 1 channel
let channelSize = MemoryLayout<AudioChannelDescription>.stride * channelDescriptions.count - 1
memcpy(&channelLayout.mChannelDescriptions, &channelDescriptions, channelSize) memcpy(&channelLayout.mChannelDescriptions, &channelDescriptions, channelSize)
return .channelLayout(channelLayout) return .channelLayout(channelLayout)
case kAudioDevicePropertyZeroTimeStampPeriod: case kAudioDevicePropertyZeroTimeStampPeriod:

View File

@ -115,12 +115,12 @@ import CoreAudio.AudioServerPlugIn
return "Unknown" return "Unknown"
} }
static func calculateHostTicksPerFrame () -> Float64 { static func calculateHostTicksPerFrame () {
// calculate the host ticks per frame // calculate the host ticks per frame
var theTimeBaseInfo = mach_timebase_info() var theTimeBaseInfo = mach_timebase_info()
mach_timebase_info(&theTimeBaseInfo) mach_timebase_info(&theTimeBaseInfo)
var theHostClockFrequency = Float64(theTimeBaseInfo.denom) / Float64(theTimeBaseInfo.numer) var theHostClockFrequency = Float64(theTimeBaseInfo.denom) / Float64(theTimeBaseInfo.numer)
theHostClockFrequency *= 1000000000.0 theHostClockFrequency *= 1000000000.0
return theHostClockFrequency / EQMDevice.sampleRate hostTicksPerFrame = theHostClockFrequency / EQMDevice.sampleRate
} }
} }

View File

@ -84,11 +84,10 @@ func EQM_Initialize (inDriver: AudioServerPlugInDriverRef, inHost: AudioServerPl
if (EQMBox.name == nil) { if (EQMBox.name == nil) {
EQMBox.name = kBoxDefaultName EQMBox.name = kBoxDefaultName
} }
EQMDriver.calculateHostTicksPerFrame()
EQMBox.acquired = true return noErr
EQMDriver.hostTicksPerFrame = EQMDriver.calculateHostTicksPerFrame()
return kAudioHardwareNoError
} }
func EQM_CreateDevice (inDriver: AudioServerPlugInDriverRef, inDescription: CFDictionary, inClientInfo: UnsafePointer<AudioServerPlugInClientInfo>, outDeviceObjectID: UnsafeMutablePointer<AudioObjectID>) -> OSStatus { func EQM_CreateDevice (inDriver: AudioServerPlugInDriverRef, inDescription: CFDictionary, inClientInfo: UnsafePointer<AudioServerPlugInClientInfo>, outDeviceObjectID: UnsafeMutablePointer<AudioObjectID>) -> OSStatus {
@ -150,9 +149,9 @@ func EQM_PerformDeviceConfigurationChange (inDriver: AudioServerPlugInDriverRef,
if !kSupportedSamplingRates.contains(where: { UInt64($0) == inChangeAction }) { return kAudioHardwareBadObjectError } if !kSupportedSamplingRates.contains(where: { UInt64($0) == inChangeAction }) { return kAudioHardwareBadObjectError }
EQMDevice.sampleRate = Float64(inChangeAction) EQMDevice.sampleRate = Float64(inChangeAction)
EQMDriver.hostTicksPerFrame = EQMDriver.calculateHostTicksPerFrame() EQMDriver.calculateHostTicksPerFrame()
return kAudioHardwareNoError return noErr
} }
func EQM_AbortDeviceConfigurationChange (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioObjectID, inChangeAction: UInt64, inChangeInfo: UnsafeMutableRawPointer?) -> OSStatus { func EQM_AbortDeviceConfigurationChange (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioObjectID, inChangeAction: UInt64, inChangeInfo: UnsafeMutableRawPointer?) -> OSStatus {

View File

@ -19,6 +19,7 @@ protocol EQMObject: class {
enum EQMObjectProperty { enum EQMObjectProperty {
// Primitives // Primitives
case null (Void? = nil)
case audioClassID(AudioClassID) case audioClassID(AudioClassID)
case bool(CFBoolean) case bool(CFBoolean)
case string(CFString) case string(CFString)
@ -43,6 +44,7 @@ enum EQMObjectProperty {
func write(to address: UnsafeMutableRawPointer?, size: UnsafeMutablePointer<UInt32>, requestedSize: UInt32?) { func write(to address: UnsafeMutableRawPointer?, size: UnsafeMutablePointer<UInt32>, requestedSize: UInt32?) {
switch self { switch self {
case .null(_): self.write(element: NSNull(), address: address, size: size)
case .bool(let data): self.write(element: data, address: address, size: size) case .bool(let data): self.write(element: data, address: address, size: size)
case .string(let data): self.write(element: data, address: address, size: size) case .string(let data): self.write(element: data, address: address, size: size)
case .float32(let data): self.write(element: data, address: address, size: size) case .float32(let data): self.write(element: data, address: address, size: size)
@ -67,10 +69,12 @@ enum EQMObjectProperty {
private func write<T>(element: T, address: UnsafeMutableRawPointer?, size: UnsafeMutablePointer<UInt32>) { private func write<T>(element: T, address: UnsafeMutableRawPointer?, size: UnsafeMutablePointer<UInt32>) {
// Write data size if T.self != NSNull.self {
size.pointee = UInt32(MemoryLayout.size(ofValue: element)) size.pointee = UInt32(MemoryLayout.size(ofValue: element))
// Write data address?.assumingMemoryBound(to: T.self).pointee = element
address?.assumingMemoryBound(to: T.self).pointee = element } else {
size.pointee = 0
}
} }
private func write<T: Any>(array arr: ContiguousArray<T>, address: UnsafeMutableRawPointer?, size: UnsafeMutablePointer<UInt32>, requestedSize: UInt32?) { private func write<T: Any>(array arr: ContiguousArray<T>, address: UnsafeMutableRawPointer?, size: UnsafeMutablePointer<UInt32>, requestedSize: UInt32?) {

View File

@ -32,18 +32,7 @@ class EQMPlugIn: EQMObject {
static func isPropertySettable (objectID: AudioObjectID? = nil, address: AudioObjectPropertyAddress) -> Bool { static func isPropertySettable (objectID: AudioObjectID? = nil, address: AudioObjectPropertyAddress) -> Bool {
switch address.mSelector { switch address.mSelector {
case kAudioObjectPropertyBaseClass, default: return false
kAudioObjectPropertyClass,
kAudioObjectPropertyOwner,
kAudioObjectPropertyManufacturer,
kAudioObjectPropertyOwnedObjects,
kAudioPlugInPropertyBoxList,
kAudioPlugInPropertyTranslateUIDToBox,
kAudioPlugInPropertyDeviceList,
kAudioPlugInPropertyTranslateUIDToDevice,
kAudioPlugInPropertyResourceBundle,
kAudioObjectPropertyCustomPropertyInfoList: return true
default: return false
} }
} }
@ -88,19 +77,35 @@ class EQMPlugIn: EQMObject {
case kAudioObjectPropertyManufacturer: case kAudioObjectPropertyManufacturer:
// This is the human readable name of the maker of the plug-in. // This is the human readable name of the maker of the plug-in.
return .string(kDeviceManufacturer as CFString) return .string(kDeviceManufacturer as CFString)
case kAudioObjectPropertyOwnedObjects: case kAudioObjectPropertyOwnedObjects:
return .objectIDList([kObjectID_Box, kObjectID_Device]) var objects = ContiguousArray<AudioObjectID>()
objects.append(kObjectID_Box)
if EQMBox.acquired {
objects.append(kObjectID_Device)
}
return .objectIDList(objects)
case kAudioPlugInPropertyBoxList: case kAudioPlugInPropertyBoxList:
return .objectIDList([kObjectID_Box]) return .objectIDList([kObjectID_Box])
case kAudioPlugInPropertyTranslateUIDToBox: case kAudioPlugInPropertyTranslateUIDToBox:
let uid = inData?.assumingMemoryBound(to: CFString?.self).pointee let uid = inData?.assumingMemoryBound(to: CFString?.self).pointee
if (CFStringCompare(uid, kBoxUID as CFString, .init(rawValue: 0)) == CFComparisonResult.compareEqualTo) { if (CFStringCompare(uid, kBoxUID as CFString, .init(rawValue: 0)) == CFComparisonResult.compareEqualTo) {
return .integer(kObjectID_Box) return .integer(kObjectID_Box)
} else { } else {
return .integer(kAudioObjectUnknown) return .integer(kAudioObjectUnknown)
} }
case kAudioPlugInPropertyDeviceList: case kAudioPlugInPropertyDeviceList:
return .objectIDList([kObjectID_Device]) var devices = ContiguousArray<AudioObjectID>()
if EQMBox.acquired {
devices.append(kObjectID_Device)
}
return .objectIDList(devices)
case kAudioPlugInPropertyTranslateUIDToDevice: case kAudioPlugInPropertyTranslateUIDToDevice:
// This property takes the CFString passed in the qualifier and converts that // This property takes the CFString passed in the qualifier and converts that
// to the object ID of the device it corresponds to. For this driver, there is // to the object ID of the device it corresponds to. For this driver, there is

View File

@ -72,7 +72,7 @@ class EQMStream: EQMObject {
case kAudioStreamPropertyVirtualFormat, case kAudioStreamPropertyVirtualFormat,
kAudioStreamPropertyPhysicalFormat: return sizeof(AudioStreamBasicDescription.self) kAudioStreamPropertyPhysicalFormat: return sizeof(AudioStreamBasicDescription.self)
case kAudioStreamPropertyAvailableVirtualFormats, case kAudioStreamPropertyAvailableVirtualFormats,
kAudioStreamPropertyAvailablePhysicalFormats: return 6 * sizeof(AudioStreamRangedDescription.self) kAudioStreamPropertyAvailablePhysicalFormats: return UInt32(kSupportedSamplingRates.count) * sizeof(AudioStreamRangedDescription.self)
default: default:
return nil return nil
} }