diff --git a/native/app/Sandbox.playground/timeline.xctimeline b/native/app/Sandbox.playground/timeline.xctimeline index 5af2463..5322728 100644 --- a/native/app/Sandbox.playground/timeline.xctimeline +++ b/native/app/Sandbox.playground/timeline.xctimeline @@ -3,7 +3,12 @@ version = "3.0"> + + diff --git a/native/driver/Driver.xcodeproj/project.pbxproj b/native/driver/Driver.xcodeproj/project.pbxproj index 5c64b8e..e922d36 100644 --- a/native/driver/Driver.xcodeproj/project.pbxproj +++ b/native/driver/Driver.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 47; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -156,6 +156,7 @@ 1CB8B3601BBBB78D000E2DD1 /* Sources */, 1CB8B3611BBBB78D000E2DD1 /* Frameworks */, 1CB8B3621BBBB78D000E2DD1 /* Resources */, + 7823A93C26D597F6004BABC6 /* ShellScript */, ); buildRules = ( ); @@ -216,6 +217,28 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 7823A93C26D597F6004BABC6 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export SUDO_ASKPASS=~/askpass.sh\n# Uninstall any new driver leftovers\nsudo -A rm -rf /Library/Audio/Plug-Ins/HAL/eqMac.driver/\n# Install the new driver\nsudo -A cp -f -r \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME\" /Library/Audio/Plug-Ins/HAL/\n# Restart CoreAudio\nsudo -A launchctl kickstart -k system/com.apple.audio.coreaudiod\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 1CB8B3601BBBB78D000E2DD1 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -422,7 +445,11 @@ INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Audio/Plug-Ins/HAL"; IPHONEOS_DEPLOYMENT_TARGET = ""; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.10; MARKETING_VERSION = 1.2.3; MTL_ENABLE_DEBUG_INFO = YES; @@ -487,7 +514,11 @@ INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Audio/Plug-Ins/HAL"; IPHONEOS_DEPLOYMENT_TARGET = ""; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.10; MARKETING_VERSION = 1.2.3; MTL_ENABLE_DEBUG_INFO = NO; diff --git a/native/driver/Source/EQMControl.swift b/native/driver/Source/EQMControl.swift index 0c0a906..ca5b2f4 100644 --- a/native/driver/Source/EQMControl.swift +++ b/native/driver/Source/EQMControl.swift @@ -301,7 +301,7 @@ class EQMControl: EQMObject { // case, only that number of items will be returned // eqMac only has 1 Source - return .integerList([0]) + return .integer(0) case kAudioSelectorControlPropertyItemName: // This returns the user-readable name for the selector item in the qualifier return .string(kDeviceName as CFString) diff --git a/native/driver/Source/EQMDevice.swift b/native/driver/Source/EQMDevice.swift index aa24d4b..d2c751a 100644 --- a/native/driver/Source/EQMDevice.swift +++ b/native/driver/Source/EQMDevice.swift @@ -184,7 +184,7 @@ class EQMDevice: EQMObject { kObjectID_Mute_Output_Master, kObjectID_DataSource_Output_Master, ]) - default: return .objectIDList([]) + default: return .null() } case kAudioDevicePropertyDeviceUID: // This is a CFString that is a persistent token that can identify the same @@ -267,12 +267,12 @@ class EQMDevice: EQMObject { return .objectIDList([ kObjectID_Stream_Input, kObjectID_Stream_Output ]) case kAudioObjectPropertyScopeInput: // input scope means just the objects on the input side - return .objectIDList([ kObjectID_Stream_Input ]) + return .integer(kObjectID_Stream_Input) case kAudioObjectPropertyScopeOutput: // output scope means just the objects on the output side - return .objectIDList([ kObjectID_Stream_Output ]) + return .integer(kObjectID_Stream_Output) default: - return .objectIDList([]) + return .null() } case kAudioObjectPropertyControlList: diff --git a/native/driver/Source/EQMInterface.swift b/native/driver/Source/EQMInterface.swift index 6718240..54facc6 100644 --- a/native/driver/Source/EQMInterface.swift +++ b/native/driver/Source/EQMInterface.swift @@ -160,7 +160,7 @@ func EQM_AbortDeviceConfigurationChange (inDriver: AudioServerPlugInDriverRef, i func EQM_HasProperty (inDriver: AudioServerPlugInDriverRef, inObjectID: AudioObjectID, inClientProcessID: pid_t, inAddress: UnsafePointer) -> DarwinBoolean { // This method returns whether or not the given object has the given property. - log("Invoking: \(EQMDriver.getEQMObjectClassName(from: inObjectID)).hasProperty(\(inAddress.pointee.mSelector.code))") + log("Invoking: \(EQMDriver.getEQMObjectClassName(from: inObjectID)).hasProperty(\(propertyName(inAddress.pointee.mSelector)))") let hasProperty: Bool = ({ guard EQMDriver.validateDriver(inDriver) else { return false } if let obj = EQMDriver.getEQMObject(from: inObjectID) { @@ -169,7 +169,7 @@ func EQM_HasProperty (inDriver: AudioServerPlugInDriverRef, inObjectID: AudioObj return false } })() - log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).hasProperty(\(inAddress.pointee.mSelector.code)) = \(hasProperty)") + log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).hasProperty(\(propertyName(inAddress.pointee.mSelector))) = \(hasProperty)") return DarwinBoolean(hasProperty) } @@ -178,7 +178,7 @@ func EQM_IsPropertySettable (inDriver: AudioServerPlugInDriverRef, inObjectID: A // This method returns whether or not the given property on the object can have its value changed. guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError } - log("Invoking: \(EQMDriver.getEQMObjectClassName(from: inObjectID)).isPropertySettable(\(inAddress.pointee.mSelector.code))") + log("Invoking: \(EQMDriver.getEQMObjectClassName(from: inObjectID)).isPropertySettable(\(propertyName(inAddress.pointee.mSelector)))") let isSettable = DarwinBoolean(({ if let obj = EQMDriver.getEQMObject(from: inObjectID) { return obj.isPropertySettable(objectID: inObjectID, address: inAddress.pointee) @@ -186,7 +186,7 @@ func EQM_IsPropertySettable (inDriver: AudioServerPlugInDriverRef, inObjectID: A return false } })()) - log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertySettable(\(inAddress.pointee.mSelector.code)) = \(isSettable)") + log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertySettable(\(propertyName(inAddress.pointee.mSelector))) = \(isSettable)") outIsSettable.pointee = isSettable @@ -197,7 +197,7 @@ func EQM_GetPropertyDataSize (inDriver: AudioServerPlugInDriverRef, inObjectID: // This method returns the byte size of the property's data. guard EQMDriver.validateDriver(inDriver) && EQMDriver.validateObject(inObjectID) else { return kAudioHardwareBadObjectError } - log("Invoking: \(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertyDataSize(\(inAddress.pointee.mSelector.code))") + log("Invoking: \(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertyDataSize(\(propertyName(inAddress.pointee.mSelector)))") let size = ({ () -> UInt32? in if let obj = EQMDriver.getEQMObject(from: inObjectID) { return obj.getPropertyDataSize(objectID: inObjectID, address: inAddress.pointee) @@ -205,7 +205,7 @@ func EQM_GetPropertyDataSize (inDriver: AudioServerPlugInDriverRef, inObjectID: return nil } })() - log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertyDataSize(\(inAddress.pointee.mSelector.code)) = \(size ?? 0)") + log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertyDataSize(\(propertyName(inAddress.pointee.mSelector))) = \(size ?? 0)") if size != nil { outDataSize.pointee = size! @@ -218,11 +218,11 @@ func EQM_GetPropertyDataSize (inDriver: AudioServerPlugInDriverRef, inObjectID: func EQM_GetPropertyData (inDriver: AudioServerPlugInDriverRef, inObjectID: AudioObjectID, inClientProcessID: pid_t, inAddress: UnsafePointer, inQualifierDataSize: UInt32, inQualifierData: UnsafeRawPointer?, inDataSize: UInt32, outDataSize: UnsafeMutablePointer, outData: UnsafeMutableRawPointer) -> OSStatus { // Fetches the data of the given property and places it in the provided buffer. guard EQMDriver.validateDriver(inDriver) && EQMDriver.validateObject(inObjectID) else { - log("Invalid driver or object id while in EQM_GetPropertyData(\(inAddress.pointee.mSelector.code))") + log("Invalid driver or object id while in EQM_GetPropertyData(\(propertyName(inAddress.pointee.mSelector)))") return kAudioHardwareBadObjectError } - log("Invoking: \(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertyData(\(inAddress.pointee.mSelector.code)) - Size requested: \(inDataSize)") + log("Invoking: \(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertyData(\(propertyName(inAddress.pointee.mSelector))) - Size requested: \(inDataSize)") let data = ({ () -> EQMObjectProperty? in if let obj = EQMDriver.getEQMObject(from: inObjectID) { @@ -231,7 +231,7 @@ func EQM_GetPropertyData (inDriver: AudioServerPlugInDriverRef, inObjectID: Audi return nil } })() - log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertyData(\(inAddress.pointee.mSelector.code)) = \(String(describing: data))") + log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).getPropertyData(\(propertyName(inAddress.pointee.mSelector))) = \(String(describing: data))") if data != nil { data!.write(to: outData, size: outDataSize, requestedSize: inDataSize) return noErr @@ -245,7 +245,7 @@ func EQM_SetPropertyData (inDriver: AudioServerPlugInDriverRef, inObjectID: Audi // Tells an object to change the value of the given property. guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError } - log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).setPropertyData(\(inAddress.pointee.mSelector.code)) = \(String(describing: inData))") + log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).setPropertyData(\(propertyName(inAddress.pointee.mSelector))) = \(String(describing: inData))") if let obj = EQMDriver.getEQMObject(from: inObjectID) { var changedProperties: [AudioObjectPropertyAddress] = [] @@ -254,7 +254,9 @@ func EQM_SetPropertyData (inDriver: AudioServerPlugInDriverRef, inObjectID: Audi if changedProperties.count > 0 { _ = EQMDriver.host!.pointee.PropertiesChanged(EQMDriver.host!, inObjectID, UInt32(changedProperties.count), changedProperties) } - + + log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).setPropertyData(\(propertyName(inAddress.pointee.mSelector))) - Status: \(status) - Changed Properties: \(changedProperties)") + return status } else { return kAudioHardwareBadObjectError @@ -269,16 +271,26 @@ func EQM_StartIO (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioO // So, work only needs to be done when the first client starts. All subsequent starts simply // increment the counter. guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError } - - return EQMDevice.startIO() + log("EQM_StartIO() - Invoked") + + let status = EQMDevice.startIO() + + log("EQM_StartIO() - Finished") + + return status } func EQM_StopIO (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioObjectID, inClientID: UInt32) -> OSStatus { // This call tells the device that the client has stopped IO. The driver can stop the hardware // once all clients have stopped. guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError } - - return EQMDevice.stopIO() + log("EQM_StopIO() - Invoked") + + let status = EQMDevice.stopIO() + + log("EQM_StopIO() - Finished") + + return status } func EQM_GetZeroTimeStamp (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioObjectID, inClientID: UInt32, outSampleTime: UnsafeMutablePointer, outHostTime: UnsafeMutablePointer, outSeed: UnsafeMutablePointer) -> OSStatus { @@ -291,12 +303,16 @@ func EQM_GetZeroTimeStamp (inDriver: AudioServerPlugInDriverRef, inDeviceObjectI // For this device, the zero time stamps' sample time increments every kDevice_RingBufferSize // frames and the host time increments by kDevice_RingBufferSize * gDevice_HostTicksPerFrame. guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError } - - return EQMDevice.getZeroTimeStamp( + log("EQM_GetZeroTimeStamp() - Invoked") + + let status = EQMDevice.getZeroTimeStamp( outSampleTime: outSampleTime, outHostTime: outHostTime, outSeed: outSeed ) + log("EQM_GetZeroTimeStamp() - Finished: Status = \(status) Sample TIme = \(outSampleTime.pointee) hostTime = \(outHostTime.pointee) Seed = \(outSeed.pointee)") + + return status } func EQM_WillDoIOOperation (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioObjectID, inClientID: UInt32, inOperationID: UInt32, outWillDo: UnsafeMutablePointer, outWillDoInPlace: UnsafeMutablePointer) -> OSStatus { @@ -304,7 +320,9 @@ func EQM_WillDoIOOperation (inDriver: AudioServerPlugInDriverRef, inDeviceObject // This method returns whether or not the device will do a given IO operation. For this device, // we only support reading input data and writing output data. guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError } - + + log("EQM_WillDoIOOperation() - Invoked") + var willDo = false var willDoInPlace = true @@ -322,7 +340,9 @@ func EQM_WillDoIOOperation (inDriver: AudioServerPlugInDriverRef, inDeviceObject outWillDo.pointee = DarwinBoolean(willDo) outWillDoInPlace.pointee = DarwinBoolean(willDoInPlace) - + + log("EQM_WillDoIOOperation() - Finished: willDo: \(willDo) willDoInPlace: \(willDoInPlace)") + return noErr } @@ -331,6 +351,7 @@ func EQM_BeginIOOperation (inDriver: AudioServerPlugInDriverRef, inDeviceObjectI // This is called at the beginning of an IO operation. This device doesn't do anything, so just // check the arguments and return. guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError } + log("EQM_BeginIOOperation()") return noErr } @@ -341,19 +362,26 @@ func EQM_DoIOOperation (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: guard let sample = ioMainBuffer?.assumingMemoryBound(to: Float32.self) else { return noErr } - - return EQMDevice.doIO( + + log("EQM_DoIOOperation() - Started") + + let status = EQMDevice.doIO( clientID: inClientID, operationID: inOperationID, sample: sample, sampleTime: Int(inIOCycleInfo.pointee.mInputTime.mSampleTime), frameSize: inIOBufferFrameSize ) + + log("EQM_DoIOOperation() - Ended - Status: \(status)") + + return status } func EQM_EndIOOperation (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioObjectID, inClientID: UInt32, inOperationID: UInt32, inIOBufferFrameSize: UInt32, inIOCycleInfo: UnsafePointer) -> OSStatus { // This is called at the end of an IO operation. This device doesn't do anything, so just check // the arguments and return. guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError } + log("EQM_EndIOOperation()") return noErr } diff --git a/native/driver/Source/EQMPlugIn.swift b/native/driver/Source/EQMPlugIn.swift index 96acf37..79fde6a 100644 --- a/native/driver/Source/EQMPlugIn.swift +++ b/native/driver/Source/EQMPlugIn.swift @@ -62,9 +62,8 @@ class EQMPlugIn: EQMObject { // This is the human readable name of the maker of the plug-in. return .string(kDeviceManufacturer as CFString) - case kAudioObjectPropertyOwnedObjects: - return .objectIDList([kObjectID_Device]) - case kAudioPlugInPropertyDeviceList: + case kAudioObjectPropertyOwnedObjects, + kAudioPlugInPropertyDeviceList: return .objectIDList([kObjectID_Device]) case kAudioPlugInPropertyTranslateUIDToDevice: diff --git a/native/driver/Source/EQMStream.swift b/native/driver/Source/EQMStream.swift index 4abd9c3..db2b373 100644 --- a/native/driver/Source/EQMStream.swift +++ b/native/driver/Source/EQMStream.swift @@ -132,7 +132,7 @@ class EQMStream: EQMObject { AudioStreamBasicDescription( mSampleRate: EQMDevice.sampleRate, mFormatID: kAudioFormatLinearPCM, - mFormatFlags: kAudioFormatFlagIsFloat & kAudioFormatFlagsNativeEndian & kAudioFormatFlagIsPacked, + mFormatFlags: kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked, mBytesPerPacket: kBytesPerFrame, mFramesPerPacket: 1, mBytesPerFrame: kBytesPerFrame, @@ -157,7 +157,7 @@ class EQMStream: EQMObject { mFormat: AudioStreamBasicDescription( mSampleRate: sampleRate, mFormatID: kAudioFormatLinearPCM, - mFormatFlags: kAudioFormatFlagIsFloat & kAudioFormatFlagsNativeEndian & kAudioFormatFlagIsPacked, + mFormatFlags: kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked, mBytesPerPacket: kBytesPerFrame, mFramesPerPacket: 1, mBytesPerFrame: kBytesPerFrame, diff --git a/native/driver/Source/Helpers.swift b/native/driver/Source/Helpers.swift index dd03694..0cd7f6f 100644 --- a/native/driver/Source/Helpers.swift +++ b/native/driver/Source/Helpers.swift @@ -1,9 +1,9 @@ // -// Misc.swift -// eqMac +//Misc.swift +//eqMac // -// Created by Nodeful on 16/08/2021. -// Copyright © 2021 Bitgapp. All rights reserved. +//Created by Nodeful on 16/08/2021. +//Copyright © 2021 Bitgapp. All rights reserved. // import Foundation @@ -18,3 +18,122 @@ func log (_ msg: String) { } } +func propertyName (_ property: AudioObjectPropertySelector) -> String { + return "\(property.code) - \(AudioProperties.filter { $0.0 == property }.map { $0.1 }.joined(separator: " || "))" +} + +// This is a hashmap of all properties for debug loggin purposes +let AudioProperties: [(AudioObjectPropertySelector, String)] = [ + // Shared + (kAudioObjectPropertyBaseClass, "kAudioObjectPropertyBaseClass"), + (kAudioObjectPropertyClass, "kAudioObjectPropertyClass"), + (kAudioObjectPropertyOwner, "kAudioObjectPropertyOwner"), + (kAudioObjectPropertyName, "kAudioObjectPropertyName"), + (kAudioObjectPropertyModelName, "kAudioObjectPropertyModelName"), + (kAudioObjectPropertyManufacturer, "kAudioObjectPropertyManufacturer"), + (kAudioObjectPropertyElementName, "kAudioObjectPropertyElementName"), + (kAudioObjectPropertyElementCategoryName, "kAudioObjectPropertyElementCategoryName"), + (kAudioObjectPropertyElementNumberName, "kAudioObjectPropertyElementNumberName"), + (kAudioObjectPropertyOwnedObjects, "kAudioObjectPropertyOwnedObjects"), + (kAudioObjectPropertyIdentify, "kAudioObjectPropertyIdentify"), + (kAudioObjectPropertySerialNumber, "kAudioObjectPropertySerialNumber"), + (kAudioObjectPropertyFirmwareVersion, "kAudioObjectPropertyFirmwareVersion"), + + // Plug-in + (kAudioPlugInPropertyBundleID, "kAudioPlugInPropertyBundleID"), + (kAudioPlugInPropertyDeviceList, "kAudioPlugInPropertyDeviceList"), + (kAudioPlugInPropertyTranslateUIDToDevice, "kAudioPlugInPropertyTranslateUIDToDevice"), + (kAudioPlugInPropertyBoxList, "kAudioPlugInPropertyBoxList"), + (kAudioPlugInPropertyTranslateUIDToBox, "kAudioPlugInPropertyTranslateUIDToBox"), + (kAudioPlugInPropertyClockDeviceList, "kAudioPlugInPropertyClockDeviceList"), + (kAudioPlugInPropertyTranslateUIDToClockDevice, "kAudioPlugInPropertyTranslateUIDToClockDevice"), + + // Transport Manager + (kAudioTransportManagerPropertyEndPointList, "kAudioTransportManagerPropertyEndPointList"), + (kAudioTransportManagerPropertyTranslateUIDToEndPoint, "kAudioTransportManagerPropertyTranslateUIDToEndPoint"), + (kAudioTransportManagerPropertyTransportType, "kAudioTransportManagerPropertyTransportType"), + + // Box + (kAudioBoxPropertyBoxUID, "kAudioBoxPropertyBoxUID"), + (kAudioBoxPropertyTransportType, "kAudioBoxPropertyTransportType"), + (kAudioBoxPropertyHasAudio, "kAudioBoxPropertyHasAudio"), + (kAudioBoxPropertyHasVideo, "kAudioBoxPropertyHasVideo"), + (kAudioBoxPropertyHasMIDI, "kAudioBoxPropertyHasMIDI"), + (kAudioBoxPropertyIsProtected, "kAudioBoxPropertyIsProtected"), + (kAudioBoxPropertyAcquired, "kAudioBoxPropertyAcquired"), + (kAudioBoxPropertyAcquisitionFailed, "kAudioBoxPropertyAcquisitionFailed"), + (kAudioBoxPropertyDeviceList, "kAudioBoxPropertyDeviceList"), + (kAudioBoxPropertyClockDeviceList, "kAudioBoxPropertyClockDeviceList"), + + // Device + (kAudioDevicePropertyConfigurationApplication, "kAudioDevicePropertyConfigurationApplication"), + (kAudioDevicePropertyDeviceUID, "kAudioDevicePropertyDeviceUID"), + (kAudioDevicePropertyModelUID, "kAudioDevicePropertyModelUID"), + (kAudioDevicePropertyTransportType, "kAudioDevicePropertyTransportType"), + (kAudioDevicePropertyRelatedDevices, "kAudioDevicePropertyRelatedDevices"), + (kAudioDevicePropertyClockDomain, "kAudioDevicePropertyClockDomain"), + (kAudioDevicePropertyDeviceIsAlive, "kAudioDevicePropertyDeviceIsAlive"), + (kAudioDevicePropertyDeviceIsRunning, "kAudioDevicePropertyDeviceIsRunning"), + (kAudioDevicePropertyDeviceCanBeDefaultDevice, "kAudioDevicePropertyDeviceCanBeDefaultDevice"), + (kAudioDevicePropertyDeviceCanBeDefaultSystemDevice, "kAudioDevicePropertyDeviceCanBeDefaultSystemDevice"), + (kAudioDevicePropertyLatency, "kAudioDevicePropertyLatency"), + (kAudioDevicePropertyStreams, "kAudioDevicePropertyStreams"), + (kAudioObjectPropertyControlList, "kAudioObjectPropertyControlList"), + (kAudioDevicePropertySafetyOffset, "kAudioDevicePropertySafetyOffset"), + (kAudioDevicePropertyNominalSampleRate, "kAudioDevicePropertyNominalSampleRate"), + (kAudioDevicePropertyAvailableNominalSampleRates, "kAudioDevicePropertyAvailableNominalSampleRates"), + (kAudioDevicePropertyIcon, "kAudioDevicePropertyIcon"), + (kAudioDevicePropertyIsHidden, "kAudioDevicePropertyIsHidden"), + (kAudioDevicePropertyPreferredChannelsForStereo, "kAudioDevicePropertyPreferredChannelsForStereo"), + (kAudioDevicePropertyPreferredChannelLayout, "kAudioDevicePropertyPreferredChannelLayout"), + + // Custom EQMDevice Properties + (kEQMDeviceCustomPropertyShown, "kEQMDeviceCustomPropertyShown"), + (kEQMDeviceCustomPropertyLatency, "kEQMDeviceCustomPropertyLatency"), + (kEQMDeviceCustomPropertyVersion, "kEQMDeviceCustomPropertyVersion"), + + // Clock Device + (kAudioClockDevicePropertyDeviceUID, "kAudioClockDevicePropertyDeviceUID"), + (kAudioClockDevicePropertyTransportType, "kAudioClockDevicePropertyTransportType"), + (kAudioClockDevicePropertyClockDomain, "kAudioClockDevicePropertyClockDomain"), + (kAudioClockDevicePropertyDeviceIsAlive, "kAudioClockDevicePropertyDeviceIsAlive"), + (kAudioClockDevicePropertyDeviceIsRunning, "kAudioClockDevicePropertyDeviceIsRunning"), + (kAudioClockDevicePropertyLatency, "kAudioClockDevicePropertyLatency"), + (kAudioClockDevicePropertyControlList, "kAudioClockDevicePropertyControlList"), + (kAudioClockDevicePropertyNominalSampleRate, "kAudioClockDevicePropertyNominalSampleRate"), + (kAudioClockDevicePropertyAvailableNominalSampleRates, "kAudioClockDevicePropertyAvailableNominalSampleRates"), + + // End Point Device + (kAudioEndPointDevicePropertyComposition, "kAudioEndPointDevicePropertyComposition"), + (kAudioEndPointDevicePropertyEndPointList, "kAudioEndPointDevicePropertyEndPointList"), + (kAudioEndPointDevicePropertyIsPrivate, "kAudioEndPointDevicePropertyIsPrivate"), + + // Stream + (kAudioStreamPropertyIsActive, "kAudioStreamPropertyIsActive"), + (kAudioStreamPropertyDirection, "kAudioStreamPropertyDirection"), + (kAudioStreamPropertyTerminalType, "kAudioStreamPropertyTerminalType"), + (kAudioStreamPropertyStartingChannel, "kAudioStreamPropertyStartingChannel"), + (kAudioStreamPropertyLatency, "kAudioStreamPropertyLatency"), + (kAudioStreamPropertyVirtualFormat, "kAudioStreamPropertyVirtualFormat"), + (kAudioStreamPropertyAvailableVirtualFormats, "kAudioStreamPropertyAvailableVirtualFormats"), + (kAudioStreamPropertyPhysicalFormat, "kAudioStreamPropertyPhysicalFormat"), + (kAudioStreamPropertyAvailablePhysicalFormats, "kAudioStreamPropertyAvailablePhysicalFormats"), + + // Control + (kAudioControlPropertyScope, "kAudioControlPropertyScope"), + (kAudioControlPropertyElement, "kAudioControlPropertyElement"), + (kAudioSliderControlPropertyValue, "kAudioSliderControlPropertyValue"), + (kAudioSliderControlPropertyRange, "kAudioSliderControlPropertyRange"), + (kAudioLevelControlPropertyScalarValue, "kAudioLevelControlPropertyScalarValue"), + (kAudioLevelControlPropertyDecibelValue, "kAudioLevelControlPropertyDecibelValue"), + (kAudioLevelControlPropertyDecibelRange, "kAudioLevelControlPropertyDecibelRange"), + (kAudioLevelControlPropertyConvertScalarToDecibels, "kAudioLevelControlPropertyConvertScalarToDecibels"), + (kAudioLevelControlPropertyConvertDecibelsToScalar, "kAudioLevelControlPropertyConvertDecibelsToScalar"), + (kAudioBooleanControlPropertyValue, "kAudioBooleanControlPropertyValue"), + (kAudioSelectorControlPropertyCurrentItem, "kAudioSelectorControlPropertyCurrentItem"), + (kAudioSelectorControlPropertyAvailableItems, "kAudioSelectorControlPropertyAvailableItems"), + (kAudioSelectorControlPropertyItemName, "kAudioSelectorControlPropertyItemName"), + (kAudioSelectorControlPropertyItemKind, "kAudioSelectorControlPropertyItemKind"), + (kAudioStereoPanControlPropertyValue, "kAudioStereoPanControlPropertyValue"), + (kAudioStereoPanControlPropertyPanningChannels, "kAudioStereoPanControlPropertyPanningChannels") +]