diff --git a/native/driver/Driver.xcodeproj/project.pbxproj b/native/driver/Driver.xcodeproj/project.pbxproj index 1801cb5..9371ebd 100644 --- a/native/driver/Driver.xcodeproj/project.pbxproj +++ b/native/driver/Driver.xcodeproj/project.pbxproj @@ -7,7 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 789B5F202699153000C72029 /* eqMac.c in Sources */ = {isa = PBXBuildFile; fileRef = 789B5F1F2699153000C72029 /* eqMac.c */; }; + 78A8049E26C4866D0021981C /* eqMacBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 78A8049D26C4866D0021981C /* eqMacBridge.m */; }; + 78A804D726C4903E0021981C /* eqMac.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78A804D626C4903E0021981C /* eqMac.swift */; }; E01A29F82456E50500369F41 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E01A29F72456E50500369F41 /* CoreFoundation.framework */; }; E0DAAFBD21FE545F00DCCCEC /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = E0DAAFBC21FE545F00DCCCEC /* icon.icns */; }; /* End PBXBuildFile section */ @@ -15,8 +16,10 @@ /* Begin PBXFileReference section */ 1CB8B3641BBBB78D000E2DD1 /* eqMac.driver */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = eqMac.driver; sourceTree = BUILT_PRODUCTS_DIR; }; 1CB8B3681BBBB78D000E2DD1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 789B5F1E2699153000C72029 /* eqMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eqMac.h; sourceTree = ""; }; - 789B5F1F2699153000C72029 /* eqMac.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = eqMac.c; sourceTree = ""; }; + 78A8049D26C4866D0021981C /* eqMacBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = eqMacBridge.m; sourceTree = ""; }; + 78A804A026C486820021981C /* eqMacBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eqMacBridge.h; sourceTree = ""; }; + 78A804D526C4903E0021981C /* eqMac-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "eqMac-Bridging-Header.h"; sourceTree = ""; }; + 78A804D626C4903E0021981C /* eqMac.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = eqMac.swift; sourceTree = ""; }; E01A29F72456E50500369F41 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; E0DAAFBC21FE545F00DCCCEC /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = icon.icns; sourceTree = ""; }; E0FA2BB021FBB917001C99CD /* build.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build.sh; sourceTree = ""; }; @@ -56,8 +59,9 @@ 1CB8B3661BBBB78D000E2DD1 /* Source */ = { isa = PBXGroup; children = ( - 789B5F1E2699153000C72029 /* eqMac.h */, - 789B5F1F2699153000C72029 /* eqMac.c */, + 78A8049C26C486350021981C /* Bridge */, + 78A804D626C4903E0021981C /* eqMac.swift */, + 78A804D526C4903E0021981C /* eqMac-Bridging-Header.h */, ); path = Source; sourceTree = ""; @@ -71,6 +75,15 @@ path = "Supporting Files"; sourceTree = ""; }; + 78A8049C26C486350021981C /* Bridge */ = { + isa = PBXGroup; + children = ( + 78A8049D26C4866D0021981C /* eqMacBridge.m */, + 78A804A026C486820021981C /* eqMacBridge.h */, + ); + path = Bridge; + sourceTree = ""; + }; E00879C7237EC3D3006AACF8 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -121,6 +134,7 @@ 1CB8B3631BBBB78D000E2DD1 = { CreatedOnToolsVersion = 6.4; DevelopmentTeam = JZA6C97KJA; + LastSwiftMigration = 1240; ProvisioningStyle = Manual; }; }; @@ -179,7 +193,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 789B5F202699153000C72029 /* eqMac.c in Sources */, + 78A8049E26C4866D0021981C /* eqMacBridge.m in Sources */, + 78A804D726C4903E0021981C /* eqMac.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -322,10 +337,11 @@ 1CB8B36A1BBBB78D000E2DD1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; - CLANG_ENABLE_MODULES = NO; - CLANG_ENABLE_OBJC_ARC = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_ASSIGN_ENUM = NO; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; @@ -341,10 +357,12 @@ CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1.2.3; + DEAD_CODE_STRIPPING = NO; DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; DEVELOPMENT_TEAM = JZA6C97KJA; ENABLE_NS_ASSERTIONS = YES; - GCC_C_LANGUAGE_STANDARD = c11; + GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_CPP_RTTI = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; @@ -359,6 +377,7 @@ 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"; MACOSX_DEPLOYMENT_TARGET = 10.10; MARKETING_VERSION = 1.2.3; MTL_ENABLE_DEBUG_INFO = YES; @@ -369,6 +388,9 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; SKIP_INSTALL = NO; + SWIFT_OBJC_BRIDGING_HEADER = "Source/eqMac-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; TVOS_DEPLOYMENT_TARGET = ""; WARNING_CFLAGS = ""; WATCHOS_DEPLOYMENT_TARGET = ""; @@ -379,10 +401,11 @@ 1CB8B36B1BBBB78D000E2DD1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; - CLANG_ENABLE_MODULES = NO; - CLANG_ENABLE_OBJC_ARC = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_ASSIGN_ENUM = NO; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; @@ -398,10 +421,12 @@ CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1.2.3; + DEAD_CODE_STRIPPING = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; DEVELOPMENT_TEAM = JZA6C97KJA; ENABLE_NS_ASSERTIONS = YES; - GCC_C_LANGUAGE_STANDARD = c11; + GCC_C_LANGUAGE_STANDARD = gnu11; GCC_ENABLE_CPP_RTTI = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; GCC_PREPROCESSOR_DEFINITIONS = ""; @@ -415,6 +440,7 @@ 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"; MACOSX_DEPLOYMENT_TARGET = 10.10; MARKETING_VERSION = 1.2.3; MTL_ENABLE_DEBUG_INFO = NO; @@ -424,6 +450,8 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; SKIP_INSTALL = NO; + SWIFT_OBJC_BRIDGING_HEADER = "Source/eqMac-Bridging-Header.h"; + SWIFT_VERSION = 5.0; TVOS_DEPLOYMENT_TARGET = ""; WARNING_CFLAGS = ""; WATCHOS_DEPLOYMENT_TARGET = ""; diff --git a/native/driver/Source/Bridge/eqMacBridge.h b/native/driver/Source/Bridge/eqMacBridge.h new file mode 100644 index 0000000..07eda88 --- /dev/null +++ b/native/driver/Source/Bridge/eqMacBridge.h @@ -0,0 +1,11 @@ +// +// eqMacBridge.h +// Driver +// +// Created by Nodeful on 12/08/2021. +// Copyright © 2021 Bitgapp. All rights reserved. +// + +#import + +void *eqMac_Create(CFAllocatorRef allocator, CFUUIDRef requestedTypeUUID); diff --git a/native/driver/Source/Bridge/eqMacBridge.m b/native/driver/Source/Bridge/eqMacBridge.m new file mode 100644 index 0000000..a0e9b8b --- /dev/null +++ b/native/driver/Source/Bridge/eqMacBridge.m @@ -0,0 +1,14 @@ +// +// eqMacBridge.m +// eqMac +// +// Created by Nodeful on 12/08/2021. +// Copyright © 2021 Bitgapp. All rights reserved. +// + +#import "eqMacBridge.h" +#import "eqMac-Swift.h" + +void *eqMac_Create(CFAllocatorRef allocator, CFUUIDRef requestedTypeUUID) { + return [eqMac createWithAllocator:allocator requestedTypeUUID:requestedTypeUUID]; +} diff --git a/native/driver/Source/eqMac-Bridging-Header.h b/native/driver/Source/eqMac-Bridging-Header.h new file mode 100644 index 0000000..1b2cb5d --- /dev/null +++ b/native/driver/Source/eqMac-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/native/driver/Source/eqMac.c b/native/driver/Source/eqMac.c deleted file mode 100644 index 5445694..0000000 --- a/native/driver/Source/eqMac.c +++ /dev/null @@ -1,4058 +0,0 @@ -// -// eqMac.c -// eqMac -// -// Created by Nodeful on 10/07/2021. -// Copyright © 2021 Bitgapp. All rights reserved. -// - -#include "eqMac.h" - -static Float32 volumeToDecibel (Float32 volume) { - if (volume <= powf(10.0f, kVolume_MinDB / 20.0f)) { - return kVolume_MinDB; - } else { - return 20.0f * log10f(volume); - } -} - -static Float32 decibelToVolume (Float32 decibel) { - if (decibel <= kVolume_MinDB) { - return 0.0f; - } else { - return powf(10.0f, decibel / 20.0f); - } -} - -static Float32 volumeToScalar (Float32 volume) { - Float32 decibel = volumeToDecibel(volume); - return (decibel - kVolume_MinDB) / (kVolume_MaxDB - kVolume_MinDB); -} - -static Float32 scalarToVolume (Float32 scalar) { - Float32 decibel = scalar * (kVolume_MaxDB - kVolume_MinDB) + kVolume_MinDB; - return decibelToVolume(decibel); -} - -#pragma mark Factory - -void* eqMac_Create (CFAllocatorRef inAllocator, CFUUIDRef inRequestedTypeUUID) { - - // This is the CFPlugIn factory function. Its job is to create the implementation for the given - // type provided that the type is supported. Because this driver is simple and all its - // initialization is handled via static iniitalization when the bundle is loaded, all that - // needs to be done is to return the AudioServerPlugInDriverRef that points to the driver's - // interface. A more complicated driver would create any base line objects it needs to satisfy - // the IUnknown methods that are used to discover that actual interface to talk to the driver. - // The majority of the driver's initilization should be handled in the Initialize() method of - // the driver's AudioServerPlugInDriverInterface. - -#pragma unused(inAllocator) - void* theAnswer = NULL; - if (CFEqual(inRequestedTypeUUID, kAudioServerPlugInTypeUUID)) { - theAnswer = gAudioServerPlugInDriverRef; - } - return theAnswer; -} - -#pragma mark Inheritence - -static HRESULT eqMac_QueryInterface (void* inDriver, REFIID inUUID, LPVOID* outInterface) { - - // This function is called by the HAL to get the interface to talk to the plug-in through. - // AudioServerPlugIns are required to support the IUnknown interface and the - // AudioServerPlugInDriverInterface. As it happens, all interfaces must also provide the - // IUnknown interface, so we can always just return the single interface we made with - // gAudioServerPlugInDriverInterfacePtr regardless of which one is asked for. - - // declare the local variables - HRESULT theAnswer = 0; - CFUUIDRef theRequestedUUID = NULL; - - // validate the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_QueryInterface: bad driver reference"); - FailWithAction(outInterface == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_QueryInterface: no place to store the returned interface"); - - // make a CFUUIDRef from inUUID - theRequestedUUID = CFUUIDCreateFromUUIDBytes(NULL, inUUID); - FailWithAction(theRequestedUUID == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_QueryInterface: failed to create the CFUUIDRef"); - - // AudioServerPlugIns only support two interfaces, IUnknown (which has to be supported by all - // CFPlugIns and AudioServerPlugInDriverInterface (which is the actual interface the HAL will - // use). - if (CFEqual(theRequestedUUID, IUnknownUUID) || CFEqual(theRequestedUUID, kAudioServerPlugInDriverInterfaceUUID)) { - pthread_mutex_lock(&gPlugIn_StateMutex); - ++gPlugIn_RefCount; - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outInterface = gAudioServerPlugInDriverRef; - } else { - theAnswer = E_NOINTERFACE; - } - - // make sure to release the UUID we created - CFRelease(theRequestedUUID); - -Done: - return theAnswer; -} - -static ULONG eqMac_AddRef (void* inDriver) { - - // This call returns the resulting reference count after the increment. - - // declare the local variables - ULONG theAnswer = 0; - - // check the arguments - FailIf (inDriver != gAudioServerPlugInDriverRef, Done, "eqMac_AddRef: bad driver reference"); - - // decrement the refcount - pthread_mutex_lock(&gPlugIn_StateMutex); - if (gPlugIn_RefCount < UINT32_MAX) { - ++gPlugIn_RefCount; - } - theAnswer = gPlugIn_RefCount; - pthread_mutex_unlock(&gPlugIn_StateMutex); - -Done: - return theAnswer; -} - -static ULONG eqMac_Release (void* inDriver) { - - // This call returns the resulting reference count after the decrement. - - // declare the local variables - ULONG theAnswer = 0; - - // check the arguments - FailIf (inDriver != gAudioServerPlugInDriverRef, Done, "eqMac_Release: bad driver reference"); - - // increment the refcount - pthread_mutex_lock(&gPlugIn_StateMutex); - if (gPlugIn_RefCount > 0) { - --gPlugIn_RefCount; - // Note that we don't do anything special if the refcount goes to zero as the HAL - // will never fully release a plug-in it opens. We keep managing the refcount so that - // the API semantics are correct though. - } - theAnswer = gPlugIn_RefCount; - pthread_mutex_unlock(&gPlugIn_StateMutex); - -Done: - return theAnswer; -} - -#pragma mark Basic Operations - -static OSStatus eqMac_Initialize (AudioServerPlugInDriverRef inDriver, AudioServerPlugInHostRef inHost) { - - // The job of this method is, as the name implies, to get the driver initialized. One specific - // thing that needs to be done is to store the AudioServerPlugInHostRef so that it can be used - // later. Note that when this call returns, the HAL will scan the various lists the driver - // maintains (such as the device list) to get the inital set of objects the driver is - // publishing. So, there is no need to notifiy the HAL about any objects created as part of the - // execution of this method. - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_Initialize: bad driver reference"); - - // store the AudioServerPlugInHostRef - gPlugIn_Host = inHost; - - // initialize the box acquired property from the settings - CFPropertyListRef theSettingsData = NULL; - gPlugIn_Host->CopyFromStorage(gPlugIn_Host, CFSTR("box acquired"), &theSettingsData); - if (theSettingsData != NULL) { - if (CFGetTypeID(theSettingsData) == CFBooleanGetTypeID()) { - gBox_Acquired = CFBooleanGetValue((CFBooleanRef)theSettingsData); - } else if (CFGetTypeID(theSettingsData) == CFNumberGetTypeID()) { - SInt32 theValue = 0; - CFNumberGetValue((CFNumberRef)theSettingsData, kCFNumberSInt32Type, &theValue); - gBox_Acquired = theValue ? 1 : 0; - } - CFRelease(theSettingsData); - } - - // initialize the box name from the settings - gPlugIn_Host->CopyFromStorage(gPlugIn_Host, CFSTR("box acquired"), &theSettingsData); - if (theSettingsData != NULL) { - if (CFGetTypeID(theSettingsData) == CFStringGetTypeID()) { - gBox_Name = (CFStringRef)theSettingsData; - CFRetain(gBox_Name); - } - CFRelease(theSettingsData); - } - - // set the box name directly as a last resort - if (gBox_Name == NULL) { - gBox_Name = CFSTR("eqMac Box"); - } - - // calculate the host ticks per frame - struct mach_timebase_info theTimeBaseInfo; - mach_timebase_info(&theTimeBaseInfo); - Float64 theHostClockFrequency = (Float64)theTimeBaseInfo.denom / (Float64)theTimeBaseInfo.numer; - theHostClockFrequency *= 1000000000.0; - gDevice_HostTicksPerFrame = theHostClockFrequency / gDevice_SampleRate; - -Done: - return theAnswer; -} - -static OSStatus eqMac_CreateDevice (AudioServerPlugInDriverRef inDriver, CFDictionaryRef inDescription, const AudioServerPlugInClientInfo* inClientInfo, AudioObjectID* outDeviceObjectID) { - - // This method is used to tell a driver that implements the Transport Manager semantics to - // create an AudioEndpointDevice from a set of AudioEndpoints. Since this driver is not a - // Transport Manager, we just check the arguments and return - // kAudioHardwareUnsupportedOperationError. - -#pragma unused(inDescription, inClientInfo, outDeviceObjectID) - - // declare the local variables - OSStatus theAnswer = kAudioHardwareUnsupportedOperationError; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_CreateDevice: bad driver reference"); - -Done: - return theAnswer; -} - -static OSStatus eqMac_DestroyDevice (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID) { - - // This method is used to tell a driver that implements the Transport Manager semantics to - // destroy an AudioEndpointDevice. Since this driver is not a Transport Manager, we just check - // the arguments and return kAudioHardwareUnsupportedOperationError. - -#pragma unused(inDeviceObjectID) - - // declare the local variables - OSStatus theAnswer = kAudioHardwareUnsupportedOperationError; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_DestroyDevice: bad driver reference"); - -Done: - return theAnswer; -} - -static OSStatus eqMac_AddDeviceClient (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo* inClientInfo) { - - // This method is used to inform the driver about a new client that is using the given device. - // This allows the device to act differently depending on who the client is. This driver does - // not need to track the clients using the device, so we just check the arguments and return - // successfully. - -#pragma unused(inClientInfo) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_AddDeviceClient: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_AddDeviceClient: bad device ID"); - -Done: - return theAnswer; -} - -static OSStatus eqMac_RemoveDeviceClient (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo* inClientInfo) { - - // This method is used to inform the driver about a client that is no longer using the given - // device. This driver does not track clients, so we just check the arguments and return - // successfully. - -#pragma unused(inClientInfo) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_RemoveDeviceClient: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_RemoveDeviceClient: bad device ID"); - -Done: - return theAnswer; -} - -static OSStatus eqMac_PerformDeviceConfigurationChange (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void* inChangeInfo) { - - // This method is called to tell the device that it can perform the configuation change that it - // had requested via a call to the host method, RequestDeviceConfigurationChange(). The - // arguments, inChangeAction and inChangeInfo are the same as what was passed to - // RequestDeviceConfigurationChange(). - // - // The HAL guarantees that IO will be stopped while this method is in progress. The HAL will - // also handle figuring out exactly what changed for the non-control related properties. This - // means that the only notifications that would need to be sent here would be for either - // custom properties the HAL doesn't know about or for controls. - // - // For the device implemented by this driver, only sample rate changes go through this process - // as it is the only state that can be changed for the device that isn't a control. For this - // change, the new sample rate is passed in the inChangeAction argument. - -#pragma unused(inChangeInfo) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_PerformDeviceConfigurationChange: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_PerformDeviceConfigurationChange: bad device ID"); - FailWithAction((inChangeAction != 44100) - && (inChangeAction != 48000) - && (inChangeAction != 88200) - && (inChangeAction != 96000) - && (inChangeAction != 176400) - && (inChangeAction != 192000), - theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_PerformDeviceConfigurationChange: bad sample rate"); - - // lock the state mutex - pthread_mutex_lock(&gPlugIn_StateMutex); - - // change the sample rate - gDevice_SampleRate = inChangeAction; - - // recalculate the state that depends on the sample rate - struct mach_timebase_info theTimeBaseInfo; - mach_timebase_info(&theTimeBaseInfo); - Float64 theHostClockFrequency = (Float64)theTimeBaseInfo.denom / (Float64)theTimeBaseInfo.numer; - theHostClockFrequency *= 1000000000.0; - gDevice_HostTicksPerFrame = theHostClockFrequency / gDevice_SampleRate; - - // unlock the state mutex - pthread_mutex_unlock(&gPlugIn_StateMutex); - -Done: - return theAnswer; -} - -static OSStatus eqMac_AbortDeviceConfigurationChange (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void* inChangeInfo) { - - // This method is called to tell the driver that a request for a config change has been denied. - // This provides the driver an opportunity to clean up any state associated with the request. - // For this driver, an aborted config change requires no action. So we just check the arguments - // and return - -#pragma unused(inChangeAction, inChangeInfo) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_PerformDeviceConfigurationChange: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_PerformDeviceConfigurationChange: bad device ID"); - -Done: - return theAnswer; -} - -#pragma mark Property Operations - -static Boolean eqMac_HasProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress) { - - // This method returns whether or not the given object has the given property. - - // declare the local variables - Boolean theAnswer = false; - - // check the arguments - FailIf (inDriver != gAudioServerPlugInDriverRef, Done, "eqMac_HasProperty: bad driver reference"); - FailIf (inAddress == NULL, Done, "eqMac_HasProperty: no address"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPropertyData() method. - switch(inObjectID) { - case kObjectID_PlugIn: - theAnswer = eqMac_HasPlugInProperty(inDriver, inObjectID, inClientProcessID, inAddress); - break; - - case kObjectID_Box: - theAnswer = eqMac_HasBoxProperty(inDriver, inObjectID, inClientProcessID, inAddress); - break; - - case kObjectID_Device: - theAnswer = eqMac_HasDeviceProperty(inDriver, inObjectID, inClientProcessID, inAddress); - break; - - case kObjectID_Stream_Input: - case kObjectID_Stream_Output: - theAnswer = eqMac_HasStreamProperty(inDriver, inObjectID, inClientProcessID, inAddress); - break; - - case kObjectID_Volume_Output_Master: - case kObjectID_Mute_Output_Master: - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - theAnswer = eqMac_HasControlProperty(inDriver, inObjectID, inClientProcessID, inAddress); - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_IsPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable) { - - // This method returns whether or not the given property on the object can have its value - // changed. - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsPropertySettable: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsPropertySettable: no address"); - FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsPropertySettable: no place to put the return value"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPropertyData() method. - switch(inObjectID) { - case kObjectID_PlugIn: - theAnswer = eqMac_IsPlugInPropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable); - break; - - case kObjectID_Box: - theAnswer = eqMac_IsBoxPropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable); - break; - - case kObjectID_Device: - theAnswer = eqMac_IsDevicePropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable); - break; - - case kObjectID_Stream_Input: - case kObjectID_Stream_Output: - theAnswer = eqMac_IsStreamPropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable); - break; - - case kObjectID_Volume_Output_Master: - case kObjectID_Mute_Output_Master: - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - theAnswer = eqMac_IsControlPropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable); - break; - - default: - theAnswer = kAudioHardwareBadObjectError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize) { - - // This method returns the byte size of the property's data. - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetPropertyDataSize: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPropertyDataSize: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPropertyDataSize: no place to put the return value"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPropertyData() method. - switch(inObjectID) { - case kObjectID_PlugIn: - theAnswer = eqMac_GetPlugInPropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize); - break; - - case kObjectID_Box: - theAnswer = eqMac_GetBoxPropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize); - break; - - case kObjectID_Device: - theAnswer = eqMac_GetDevicePropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize); - break; - - case kObjectID_Stream_Input: - case kObjectID_Stream_Output: - theAnswer = eqMac_GetStreamPropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize); - break; - - case kObjectID_Volume_Output_Master: - case kObjectID_Mute_Output_Master: - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - theAnswer = eqMac_GetControlPropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize); - break; - - default: - theAnswer = kAudioHardwareBadObjectError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData) { - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPropertyData: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPropertyData: no place to put the return value size"); - FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPropertyData: no place to put the return value"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. - // - // Also, since most of the data that will get returned is static, there are few instances where - // it is necessary to lock the state mutex. - switch(inObjectID) { - case kObjectID_PlugIn: - theAnswer = eqMac_GetPlugInPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData); - break; - - case kObjectID_Box: - theAnswer = eqMac_GetBoxPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData); - break; - - case kObjectID_Device: - theAnswer = eqMac_GetDevicePropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData); - break; - - case kObjectID_Stream_Input: - case kObjectID_Stream_Output: - theAnswer = eqMac_GetStreamPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData); - break; - - case kObjectID_Volume_Output_Master: - case kObjectID_Mute_Output_Master: - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - theAnswer = eqMac_GetControlPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData); - break; - - default: - theAnswer = kAudioHardwareBadObjectError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_SetPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData) { - - // declare the local variables - OSStatus theAnswer = 0; - UInt32 theNumberPropertiesChanged = 0; - AudioObjectPropertyAddress theChangedAddresses[2]; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetPropertyData: no address"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPropertyData() method. - switch(inObjectID) { - case kObjectID_PlugIn: - theAnswer = eqMac_SetPlugInPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses); - break; - - case kObjectID_Box: - theAnswer = eqMac_SetBoxPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses); - break; - - case kObjectID_Device: - theAnswer = eqMac_SetDevicePropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses); - break; - - case kObjectID_Stream_Input: - case kObjectID_Stream_Output: - theAnswer = eqMac_SetStreamPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses); - break; - - case kObjectID_Volume_Output_Master: - case kObjectID_Mute_Output_Master: - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - theAnswer = eqMac_SetControlPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses); - break; - - default: - theAnswer = kAudioHardwareBadObjectError; - break; - }; - - // send any notifications - if (theNumberPropertiesChanged > 0) { - gPlugIn_Host->PropertiesChanged(gPlugIn_Host, inObjectID, theNumberPropertiesChanged, theChangedAddresses); - } - -Done: - return theAnswer; -} - -#pragma mark PlugIn Property Operations - -static Boolean eqMac_HasPlugInProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress) { - - // This method returns whether or not the plug-in object has the given property. - -#pragma unused(inClientProcessID) - - // declare the local variables - Boolean theAnswer = false; - - // check the arguments - FailIf (inDriver != gAudioServerPlugInDriverRef, Done, "eqMac_HasPlugInProperty: bad driver reference"); - FailIf (inAddress == NULL, Done, "eqMac_HasPlugInProperty: no address"); - FailIf (inObjectID != kObjectID_PlugIn, Done, "eqMac_HasPlugInProperty: not the plug-in object"); - - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPlugInPropertyData() method. - switch (inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyManufacturer: - case kAudioObjectPropertyOwnedObjects: - case kAudioPlugInPropertyBoxList: - case kAudioPlugInPropertyTranslateUIDToBox: - case kAudioPlugInPropertyDeviceList: - case kAudioPlugInPropertyTranslateUIDToDevice: - case kAudioPlugInPropertyResourceBundle: - case kAudioObjectPropertyCustomPropertyInfoList: - case kPlugIn_CustomPropertyID: - theAnswer = true; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_IsPlugInPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable) { - - // This method returns whether or not the given property on the plug-in object can have its - // value changed. - -#pragma unused(inClientProcessID) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsPlugInPropertySettable: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsPlugInPropertySettable: no address"); - FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsPlugInPropertySettable: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_PlugIn, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsPlugInPropertySettable: not the plug-in object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPlugInPropertyData() method. - switch (inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyManufacturer: - case kAudioObjectPropertyOwnedObjects: - case kAudioPlugInPropertyBoxList: - case kAudioPlugInPropertyTranslateUIDToBox: - case kAudioPlugInPropertyDeviceList: - case kAudioPlugInPropertyTranslateUIDToDevice: - case kAudioPlugInPropertyResourceBundle: - case kAudioObjectPropertyCustomPropertyInfoList: - *outIsSettable = false; - break; - - case kPlugIn_CustomPropertyID: - *outIsSettable = true; - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetPlugInPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize) { - - // This method returns the byte size of the property's data. - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetPlugInPropertyDataSize: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPlugInPropertyDataSize: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPlugInPropertyDataSize: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_PlugIn, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetPlugInPropertyDataSize: not the plug-in object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPlugInPropertyData() method. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyManufacturer: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyOwnedObjects: - if (gBox_Acquired) { - *outDataSize = 2 * sizeof(AudioClassID); - } else { - *outDataSize = sizeof(AudioClassID); - } - break; - - case kAudioPlugInPropertyBoxList: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioPlugInPropertyTranslateUIDToBox: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioPlugInPropertyDeviceList: - if (gBox_Acquired) { - *outDataSize = sizeof(AudioClassID); - } else { - *outDataSize = 0; - } - break; - - case kAudioPlugInPropertyTranslateUIDToDevice: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioPlugInPropertyResourceBundle: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyCustomPropertyInfoList: - *outDataSize = sizeof(AudioServerPlugInCustomPropertyInfo) * 0; - break; - - case kPlugIn_CustomPropertyID: - FailWithAction(inQualifierDataSize != sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyDataSize: the qualifier is the wrong size for kPlugIn_CustomPropertyID"); - FailWithAction(inQualifierData == NULL, theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyDataSize: no qualifier for kPlugIn_CustomPropertyID"); - DebugMsg("eqMac_GetPlugInPropertyDataSize: the qualifier passed to us was:"); - CFShow(*((CFPropertyListRef*)inQualifierData)); - *outDataSize = sizeof(CFPropertyListRef); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetPlugInPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData) { - -#pragma unused(inClientProcessID) - - // declare the local variables - OSStatus theAnswer = 0; - UInt32 theNumberItemsToFetch; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetPlugInPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPlugInPropertyData: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPlugInPropertyData: no place to put the return value size"); - FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetPlugInPropertyData: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_PlugIn, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetPlugInPropertyData: not the plug-in object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. - // - // Also, since most of the data that will get returned is static, there are few instances where - // it is necessary to lock the state mutex. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - // The base class for kAudioPlugInClassID is kAudioObjectClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the plug-in"); - *((AudioClassID*)outData) = kAudioObjectClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - // The class is always kAudioPlugInClassID for regular drivers - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the plug-in"); - *((AudioClassID*)outData) = kAudioPlugInClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - // The plug-in doesn't have an owning object - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the plug-in"); - *((AudioObjectID*)outData) = kAudioObjectUnknown; - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyManufacturer: - // This is the human readable name of the maker of the plug-in. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the plug-in"); - *((CFStringRef*)outData) = CFSTR(kDevice_Manufacturer); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyOwnedObjects: - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID); - - // Clamp that to the number of boxes this driver implements (which is just 1) - if (theNumberItemsToFetch > (gBox_Acquired ? 2 : 1)) { - theNumberItemsToFetch = (gBox_Acquired ? 2 : 1); - } - - // Write the devices' object IDs into the return value - if (theNumberItemsToFetch > 1) { - ((AudioObjectID*)outData)[0] = kObjectID_Box; - ((AudioObjectID*)outData)[0] = kObjectID_Device; - } else if (theNumberItemsToFetch > 0) { - ((AudioObjectID*)outData)[0] = kObjectID_Box; - } - - // Return how many bytes we wrote to - *outDataSize = theNumberItemsToFetch * sizeof(AudioClassID); - break; - - case kAudioPlugInPropertyBoxList: - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID); - - // Clamp that to the number of boxes this driver implements (which is just 1) - if (theNumberItemsToFetch > 1) { - theNumberItemsToFetch = 1; - } - - // Write the devices' object IDs into the return value - if (theNumberItemsToFetch > 0) { - ((AudioObjectID*)outData)[0] = kObjectID_Box; - } - - // Return how many bytes we wrote to - *outDataSize = theNumberItemsToFetch * sizeof(AudioClassID); - break; - - case kAudioPlugInPropertyTranslateUIDToBox: - // This property takes the CFString passed in the qualifier and converts that - // to the object ID of the box it corresponds to. For this driver, there is - // just the one box. Note that it is not an error if the string in the - // qualifier doesn't match any devices. In such case, kAudioObjectUnknown is - // the object ID to return. - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioPlugInPropertyTranslateUIDToBox"); - FailWithAction(inQualifierDataSize != sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: the qualifier is the wrong size for kAudioPlugInPropertyTranslateUIDToBox"); - FailWithAction(inQualifierData == NULL, theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: no qualifier for kAudioPlugInPropertyTranslateUIDToBox"); - if (CFStringCompare(*((CFStringRef*)inQualifierData), CFSTR(kBox_UID), 0) == kCFCompareEqualTo) { - *((AudioObjectID*)outData) = kObjectID_Box; - } else { - *((AudioObjectID*)outData) = kAudioObjectUnknown; - } - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioPlugInPropertyDeviceList: - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID); - - // Clamp that to the number of devices this driver implements (which is just 1 if the - // box has been acquired) - if (theNumberItemsToFetch > (gBox_Acquired ? 1 : 0)) { - theNumberItemsToFetch = (gBox_Acquired ? 1 : 0); - } - - // Write the devices' object IDs into the return value - if (theNumberItemsToFetch > 0) { - ((AudioObjectID*)outData)[0] = kObjectID_Device; - } - - // Return how many bytes we wrote to - *outDataSize = theNumberItemsToFetch * sizeof(AudioClassID); - break; - - case kAudioPlugInPropertyTranslateUIDToDevice: - // 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 - // just the one device. Note that it is not an error if the string in the - // qualifier doesn't match any devices. In such case, kAudioObjectUnknown is - // the object ID to return. - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioPlugInPropertyTranslateUIDToDevice"); - FailWithAction(inQualifierDataSize != sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: the qualifier is the wrong size for kAudioPlugInPropertyTranslateUIDToDevice"); - FailWithAction(inQualifierData == NULL, theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: no qualifier for kAudioPlugInPropertyTranslateUIDToDevice"); - if (CFStringCompare(*((CFStringRef*)inQualifierData), CFSTR(kDevice_UID), 0) == kCFCompareEqualTo) { - *((AudioObjectID*)outData) = kObjectID_Device; - } else { - *((AudioObjectID*)outData) = kAudioObjectUnknown; - } - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioPlugInPropertyResourceBundle: - // The resource bundle is a path relative to the path of the plug-in's bundle. - // To specify that the plug-in bundle itself should be used, we just return the - // empty string. - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioPlugInPropertyResourceBundle"); - *((CFStringRef*)outData) = CFSTR(""); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyCustomPropertyInfoList: - // This property returns an array of AudioServerPlugInCustomPropertyInfo's that - // describe the type of data used by any custom properties. For this example, - // the plug-in supports a single property whose data type is a CFString and - // whose qualifier is a CFString. - FailWithAction(inDataSize < sizeof(AudioServerPlugInCustomPropertyInfo), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyCustomPropertyInfoList"); - ((AudioServerPlugInCustomPropertyInfo*)outData)->mSelector = kPlugIn_CustomPropertyID; - ((AudioServerPlugInCustomPropertyInfo*)outData)->mPropertyDataType = kAudioServerPlugInCustomPropertyDataTypeCFString; - ((AudioServerPlugInCustomPropertyInfo*)outData)->mQualifierDataType = kAudioServerPlugInCustomPropertyDataTypeCFPropertyList; - *outDataSize = sizeof(AudioServerPlugInCustomPropertyInfo); - break; - - case kPlugIn_CustomPropertyID: - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kPlugIn_CustomPropertyID"); - FailWithAction(inQualifierDataSize != sizeof(CFPropertyListRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: the qualifier is the wrong size for kPlugIn_CustomPropertyID"); - FailWithAction(inQualifierData == NULL, theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: no qualifier for kPlugIn_CustomPropertyID"); - DebugMsg("eqMac_GetPlugInPropertyData: the qualifier passed to us was:"); - CFShow(*((CFPropertyListRef*)inQualifierData)); - *((CFStringRef*)outData) = CFSTR("eqMac PlugIn Custom Property"); - *outDataSize = sizeof(CFStringRef); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_SetPlugInPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]) { - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData, inDataSize, inData) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetPlugInPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetPlugInPropertyData: no address"); - FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetPlugInPropertyData: no place to return the number of properties that changed"); - FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetPlugInPropertyData: no place to return the properties that changed"); - FailWithAction(inObjectID != kObjectID_PlugIn, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetPlugInPropertyData: not the plug-in object"); - - // initialize the returned number of changed properties - *outNumberPropertiesChanged = 0; - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPlugInPropertyData() method. - switch(inAddress->mSelector) { - case kPlugIn_CustomPropertyID: - FailWithAction(inDataSize != sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetPlugInPropertyData: not enough space for the return value of kPlugIn_CustomPropertyID"); - FailWithAction(inQualifierDataSize != sizeof(CFPropertyListRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetPlugInPropertyData: the qualifier is the wrong size for kPlugIn_CustomPropertyID"); - FailWithAction(inQualifierData == NULL, theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetPlugInPropertyData: no qualifier for kPlugIn_CustomPropertyID"); - DebugMsg("eqMac_SetPlugInPropertyData: the qualifier passed to us was:"); - CFShow(*((CFPropertyListRef*)inQualifierData)); - DebugMsg("eqMac_SetPlugInPropertyData: the data passed to us was:"); - CFShow(*((CFStringRef*)inData)); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -#pragma mark Box Property Operations - -static Boolean eqMac_HasBoxProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress) { - - // This method returns whether or not the box object has the given property. - -#pragma unused(inClientProcessID) - - // declare the local variables - Boolean theAnswer = false; - - // check the arguments - FailIf (inDriver != gAudioServerPlugInDriverRef, Done, "eqMac_HasBoxProperty: bad driver reference"); - FailIf (inAddress == NULL, Done, "eqMac_HasBoxProperty: no address"); - FailIf (inObjectID != kObjectID_Box, Done, "eqMac_HasBoxProperty: not the box object"); - - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetBoxPropertyData() method. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyName: - case kAudioObjectPropertyModelName: - case kAudioObjectPropertyManufacturer: - case kAudioObjectPropertyOwnedObjects: - case kAudioObjectPropertyIdentify: - case kAudioObjectPropertySerialNumber: - case kAudioObjectPropertyFirmwareVersion: - case kAudioBoxPropertyBoxUID: - case kAudioBoxPropertyTransportType: - case kAudioBoxPropertyHasAudio: - case kAudioBoxPropertyHasVideo: - case kAudioBoxPropertyHasMIDI: - case kAudioBoxPropertyIsProtected: - case kAudioBoxPropertyAcquired: - case kAudioBoxPropertyAcquisitionFailed: - case kAudioBoxPropertyDeviceList: - theAnswer = true; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_IsBoxPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable) { - - // This method returns whether or not the given property on the plug-in object can have its - // value changed. - -#pragma unused(inClientProcessID) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsBoxPropertySettable: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsBoxPropertySettable: no address"); - FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsBoxPropertySettable: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_Box, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsBoxPropertySettable: not the plug-in object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetBoxPropertyData() method. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyModelName: - case kAudioObjectPropertyManufacturer: - case kAudioObjectPropertyOwnedObjects: - case kAudioObjectPropertySerialNumber: - case kAudioObjectPropertyFirmwareVersion: - case kAudioBoxPropertyBoxUID: - case kAudioBoxPropertyTransportType: - case kAudioBoxPropertyHasAudio: - case kAudioBoxPropertyHasVideo: - case kAudioBoxPropertyHasMIDI: - case kAudioBoxPropertyIsProtected: - case kAudioBoxPropertyAcquisitionFailed: - case kAudioBoxPropertyDeviceList: - *outIsSettable = false; - break; - - case kAudioObjectPropertyName: - case kAudioObjectPropertyIdentify: - case kAudioBoxPropertyAcquired: - *outIsSettable = true; - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetBoxPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize) { - - // This method returns the byte size of the property's data. - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetBoxPropertyDataSize: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetBoxPropertyDataSize: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetBoxPropertyDataSize: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_Box, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetBoxPropertyDataSize: not the plug-in object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetBoxPropertyData() method. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyName: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyModelName: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyManufacturer: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyOwnedObjects: - *outDataSize = 0; - break; - - case kAudioObjectPropertyIdentify: - *outDataSize = sizeof(UInt32); - break; - - case kAudioObjectPropertySerialNumber: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyFirmwareVersion: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioBoxPropertyBoxUID: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioBoxPropertyTransportType: - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyHasAudio: - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyHasVideo: - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyHasMIDI: - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyIsProtected: - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyAcquired: - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyAcquisitionFailed: - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyDeviceList:{ - pthread_mutex_lock(&gPlugIn_StateMutex); - *outDataSize = gBox_Acquired ? sizeof(AudioObjectID) : 0; - pthread_mutex_unlock(&gPlugIn_StateMutex); - } - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetBoxPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData) { - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetBoxPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetBoxPropertyData: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetBoxPropertyData: no place to put the return value size"); - FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetBoxPropertyData: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_Box, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetBoxPropertyData: not the plug-in object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. - // - // Also, since most of the data that will get returned is static, there are few instances where - // it is necessary to lock the state mutex. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - // The base class for kAudioBoxClassID is kAudioObjectClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the box"); - *((AudioClassID*)outData) = kAudioObjectClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - // The class is always kAudioBoxClassID for regular drivers - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the box"); - *((AudioClassID*)outData) = kAudioBoxClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - // The owner is the plug-in object - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the box"); - *((AudioObjectID*)outData) = kObjectID_PlugIn; - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyName: - // This is the human readable name of the maker of the box. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the box"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((CFStringRef*)outData) = gBox_Name; - pthread_mutex_unlock(&gPlugIn_StateMutex); - if (*((CFStringRef*)outData) != NULL) { - CFRetain(*((CFStringRef*)outData)); - } - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyModelName: - // This is the human readable name of the maker of the box. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the box"); - *((CFStringRef*)outData) = CFSTR("eqMac Model"); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyManufacturer: - // This is the human readable name of the maker of the box. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the box"); - *((CFStringRef*)outData) = CFSTR(kDevice_Manufacturer); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyOwnedObjects: - // This returns the objects directly owned by the object. Boxes don't own anything. - *outDataSize = 0; - break; - - case kAudioObjectPropertyIdentify: - // This is used to highling the device in the UI, but it's value has no meaning - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyIdentify for the box"); - *((UInt32*)outData) = 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioObjectPropertySerialNumber: - // This is the human readable serial number of the box. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertySerialNumber for the box"); - *((CFStringRef*)outData) = CFSTR("00000001"); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyFirmwareVersion: - // This is the human readable firmware version of the box. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyFirmwareVersion for the box"); - *((CFStringRef*)outData) = CFSTR("1.0"); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioBoxPropertyBoxUID: - // Boxes have UIDs the same as devices - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the box"); - *((CFStringRef*)outData) = CFSTR(kBox_UID); - break; - - case kAudioBoxPropertyTransportType: - // This value represents how the device is attached to the system. This can be - // any 32 bit integer, but common values for this property are defined in - // - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioDevicePropertyTransportType for the box"); - *((UInt32*)outData) = kAudioDeviceTransportTypeVirtual; - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyHasAudio: - // Indicates whether or not the box has audio capabilities - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyHasAudio for the box"); - *((UInt32*)outData) = 1; - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyHasVideo: - // Indicates whether or not the box has video capabilities - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyHasVideo for the box"); - *((UInt32*)outData) = 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyHasMIDI: - // Indicates whether or not the box has MIDI capabilities - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyHasMIDI for the box"); - *((UInt32*)outData) = 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyIsProtected: - // Indicates whether or not the box has requires authentication to use - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyIsProtected for the box"); - *((UInt32*)outData) = 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyAcquired: - // When set to a non-zero value, the device is acquired for use by the local machine - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyAcquired for the box"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((UInt32*)outData) = gBox_Acquired ? 1 : 0; - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyAcquisitionFailed: - // This is used for notifications to say when an attempt to acquire a device has failed. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyAcquisitionFailed for the box"); - *((UInt32*)outData) = 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioBoxPropertyDeviceList: - // This is used to indicate which devices came from this box - pthread_mutex_lock(&gPlugIn_StateMutex); - if (gBox_Acquired) { - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyDeviceList for the box"); - *((AudioObjectID*)outData) = kObjectID_Device; - *outDataSize = sizeof(AudioObjectID); - } else { - *outDataSize = 0; - } - pthread_mutex_unlock(&gPlugIn_StateMutex); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_SetBoxPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]) { - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData, inDataSize, inData) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetBoxPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetBoxPropertyData: no address"); - FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetBoxPropertyData: no place to return the number of properties that changed"); - FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetBoxPropertyData: no place to return the properties that changed"); - FailWithAction(inObjectID != kObjectID_Box, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetBoxPropertyData: not the box object"); - - // initialize the returned number of changed properties - *outNumberPropertiesChanged = 0; - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetPlugInPropertyData() method. - switch(inAddress->mSelector) { - case kAudioObjectPropertyName: { - // Boxes should allow their name to be editable - FailWithAction(inDataSize != sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetBoxPropertyData: wrong size for the data for kAudioObjectPropertyName"); - // FailWithAction(inData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetBoxPropertyData: no data to set for kAudioObjectPropertyName"); - CFStringRef* theNewName = (CFStringRef*)inData; - pthread_mutex_lock(&gPlugIn_StateMutex); - if ((theNewName != NULL) && (*theNewName != NULL)) { - CFRetain(*theNewName); - } - if (gBox_Name != NULL) { - CFRelease(gBox_Name); - } - gBox_Name = *theNewName; - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outNumberPropertiesChanged = 1; - outChangedAddresses[0].mSelector = kAudioObjectPropertyName; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - } - break; - - case kAudioObjectPropertyIdentify: { - // since we don't have any actual hardware to flash, we will schedule a notificaiton for - // this property off into the future as a testing thing. Note that a real implementation - // of this property should only send the notificaiton if the hardware wants the app to - // flash it's UI for the device. - syslog(LOG_NOTICE, "The identify property has been set on the Box implemented by the eqMac driver."); - FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetBoxPropertyData: wrong size for the data for kAudioObjectPropertyIdentify"); - dispatch_after(dispatch_time(0, 2ULL * 1000ULL * 1000ULL * 1000ULL), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() - { - AudioObjectPropertyAddress theAddress = { kAudioObjectPropertyIdentify, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; - gPlugIn_Host->PropertiesChanged(gPlugIn_Host, kObjectID_Box, 1, &theAddress); - }); - } - break; - - case kAudioBoxPropertyAcquired: { - // When the box is acquired, it means the contents, namely the device, are available to the system - FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetBoxPropertyData: wrong size for the data for kAudioBoxPropertyAcquired"); - pthread_mutex_lock(&gPlugIn_StateMutex); - if (gBox_Acquired != (*((UInt32*)inData) != 0)) { - // the new value is different from the old value, so save it - gBox_Acquired = *((UInt32*)inData) != 0; - gPlugIn_Host->WriteToStorage(gPlugIn_Host, CFSTR("box acquired"), gBox_Acquired ? kCFBooleanTrue : kCFBooleanFalse); - - // and it means that this property and the device list property have changed - *outNumberPropertiesChanged = 2; - outChangedAddresses[0].mSelector = kAudioBoxPropertyAcquired; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - outChangedAddresses[1].mSelector = kAudioBoxPropertyDeviceList; - outChangedAddresses[1].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[1].mElement = kAudioObjectPropertyElementMaster; - - // but it also means that the device list has changed for the plug-in too - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() - { - AudioObjectPropertyAddress theAddress = { kAudioPlugInPropertyDeviceList, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; - gPlugIn_Host->PropertiesChanged(gPlugIn_Host, kObjectID_PlugIn, 1, &theAddress); - }); - } - pthread_mutex_unlock(&gPlugIn_StateMutex); - } - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -#pragma mark Device Property Operations - -static Boolean eqMac_HasDeviceProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress) { - - // This method returns whether or not the given object has the given property. - -#pragma unused(inClientProcessID) - - // declare the local variables - Boolean theAnswer = false; - - // check the arguments - FailIf (inDriver != gAudioServerPlugInDriverRef, Done, "eqMac_HasDeviceProperty: bad driver reference"); - FailIf (inAddress == NULL, Done, "eqMac_HasDeviceProperty: no address"); - FailIf (inObjectID != kObjectID_Device, Done, "eqMac_HasDeviceProperty: not the device object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetDevicePropertyData() method. - switch (inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyName: - case kAudioObjectPropertyManufacturer: - case kAudioObjectPropertyOwnedObjects: - case kAudioDevicePropertyDeviceUID: - case kAudioDevicePropertyModelUID: - case kAudioDevicePropertyTransportType: - case kAudioDevicePropertyRelatedDevices: - case kAudioDevicePropertyClockDomain: - case kAudioDevicePropertyDeviceIsAlive: - case kAudioDevicePropertyDeviceIsRunning: - case kAudioObjectPropertyControlList: - case kAudioDevicePropertyNominalSampleRate: - case kAudioDevicePropertyAvailableNominalSampleRates: - case kAudioDevicePropertyIsHidden: - case kAudioDevicePropertyZeroTimeStampPeriod: - case kAudioDevicePropertyIcon: - case kAudioDevicePropertyStreams: - case kAudioDeviceCustomPropertyShown: - case kAudioDeviceCustomPropertyVersion: - case kAudioDeviceCustomPropertyLatency: - case kAudioDeviceCustomPropertySafetyOffset: - case kAudioObjectPropertyCustomPropertyInfoList: - theAnswer = true; - break; - - case kAudioDevicePropertyDeviceCanBeDefaultDevice: - case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice: - case kAudioDevicePropertyLatency: - case kAudioDevicePropertySafetyOffset: - case kAudioDevicePropertyPreferredChannelsForStereo: - case kAudioDevicePropertyPreferredChannelLayout: - theAnswer = (inAddress->mScope == kAudioObjectPropertyScopeInput) || (inAddress->mScope == kAudioObjectPropertyScopeOutput); - break; - - // case kAudioObjectPropertyElementName: - // theAnswer = inAddress->mElement <= 2; - // break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_IsDevicePropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable) { - - // This method returns whether or not the given property on the object can have its value - // changed. - -#pragma unused(inClientProcessID) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsDevicePropertySettable: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsDevicePropertySettable: no address"); - FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsDevicePropertySettable: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsDevicePropertySettable: not the device object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetDevicePropertyData() method. - switch (inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyName: - case kAudioObjectPropertyManufacturer: - // case kAudioObjectPropertyElementName: - case kAudioObjectPropertyOwnedObjects: - case kAudioDevicePropertyDeviceUID: - case kAudioDevicePropertyModelUID: - case kAudioDevicePropertyTransportType: - case kAudioDevicePropertyRelatedDevices: - case kAudioDevicePropertyClockDomain: - case kAudioDevicePropertyDeviceIsAlive: - case kAudioDevicePropertyDeviceIsRunning: - case kAudioDevicePropertyDeviceCanBeDefaultDevice: - case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice: - case kAudioDevicePropertyLatency: - case kAudioDevicePropertyStreams: - case kAudioObjectPropertyControlList: - case kAudioDevicePropertySafetyOffset: - case kAudioDevicePropertyAvailableNominalSampleRates: - case kAudioDevicePropertyIsHidden: - case kAudioDevicePropertyPreferredChannelsForStereo: - case kAudioDevicePropertyPreferredChannelLayout: - case kAudioDevicePropertyZeroTimeStampPeriod: - case kAudioDevicePropertyIcon: - case kAudioDeviceCustomPropertyVersion: - case kAudioObjectPropertyCustomPropertyInfoList: - *outIsSettable = false; - break; - - case kAudioDevicePropertyNominalSampleRate: - case kAudioDeviceCustomPropertyShown: - case kAudioDeviceCustomPropertyLatency: - case kAudioDeviceCustomPropertySafetyOffset: - *outIsSettable = true; - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetDevicePropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize) { - - // This method returns the byte size of the property's data. - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetDevicePropertyDataSize: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetDevicePropertyDataSize: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetDevicePropertyDataSize: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetDevicePropertyDataSize: not the device object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetDevicePropertyData() method. - switch (inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyName: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyManufacturer: - *outDataSize = sizeof(CFStringRef); - break; - // - // case kAudioObjectPropertyElementName: - // *outDataSize = sizeof(CFStringRef); - // break; - - case kAudioObjectPropertyOwnedObjects: - switch (inAddress->mScope) { - case kAudioObjectPropertyScopeGlobal: - *outDataSize = 8 * sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyScopeInput: - *outDataSize = 4 * sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyScopeOutput: - *outDataSize = 4 * sizeof(AudioObjectID); - break; - }; - break; - - case kAudioDevicePropertyDeviceUID: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioDevicePropertyModelUID: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioDevicePropertyTransportType: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyRelatedDevices: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioDevicePropertyClockDomain: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyDeviceIsAlive: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioDevicePropertyDeviceIsRunning: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyDeviceCanBeDefaultDevice: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyLatency: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyStreams: - switch(inAddress->mScope) { - case kAudioObjectPropertyScopeGlobal: - *outDataSize = 2 * sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyScopeInput: - *outDataSize = 1 * sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyScopeOutput: - *outDataSize = 1 * sizeof(AudioObjectID); - break; - }; - break; - - case kAudioObjectPropertyControlList: - *outDataSize = 6 * sizeof(AudioObjectID); - break; - - case kAudioDevicePropertySafetyOffset: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyNominalSampleRate: - *outDataSize = sizeof(Float64); - break; - - case kAudioDevicePropertyAvailableNominalSampleRates: - *outDataSize = 6 * sizeof(AudioValueRange); - break; - - case kAudioDevicePropertyIsHidden: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyPreferredChannelsForStereo: - *outDataSize = 2 * sizeof(UInt32); - break; - - case kAudioDevicePropertyPreferredChannelLayout: - *outDataSize = offsetof(AudioChannelLayout, mChannelDescriptions) + (kChannelCount * sizeof(AudioChannelDescription)); - break; - - case kAudioDevicePropertyZeroTimeStampPeriod: - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyIcon: - *outDataSize = sizeof(CFURLRef); - break; - - case kAudioDeviceCustomPropertyLatency: - *outDataSize = sizeof(CFNumberRef); - break; - - case kAudioDeviceCustomPropertySafetyOffset: - *outDataSize = sizeof(CFNumberRef); - break; - - case kAudioDeviceCustomPropertyShown: - *outDataSize = sizeof(CFBooleanRef); - break; - - case kAudioDeviceCustomPropertyVersion: - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyCustomPropertyInfoList: - *outDataSize = sizeof(AudioServerPlugInCustomPropertyInfo) * 4; - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetDevicePropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData) { - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - UInt32 theNumberItemsToFetch; - UInt32 theItemIndex; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetDevicePropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetDevicePropertyData: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetDevicePropertyData: no place to put the return value size"); - FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetDevicePropertyData: no place to put the return value"); - FailWithAction(inObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetDevicePropertyData: not the device object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. - // - // Also, since most of the data that will get returned is static, there are few instances where - // it is necessary to lock the state mutex. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - // The base class for kAudioDeviceClassID is kAudioObjectClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the device"); - *((AudioClassID*)outData) = kAudioObjectClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - // The class is always kAudioDeviceClassID for devices created by drivers - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyClass for the device"); - *((AudioClassID*)outData) = kAudioDeviceClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - // The device's owner is the plug-in object - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the device"); - *((AudioObjectID*)outData) = kObjectID_PlugIn; - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyName: - // This is the human readable name of the device. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyName for the device"); - *((CFStringRef*)outData) = CFSTR(kDevice_Name); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioObjectPropertyManufacturer: - // This is the human readable name of the maker of the plug-in. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the device"); - *((CFStringRef*)outData) = CFSTR(kDevice_Manufacturer); - *outDataSize = sizeof(CFStringRef); - break; - - // case kAudioObjectPropertyElementName: - // // This is the human readable name of the maker of the plug-in. - // FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyElementName for the device"); - // switch(inAddress->mElement) - // { - // case 0: - // *((CFStringRef*)outData) = CFSTR("MasterElementName"); - // break; - // - // case 1: - // *((CFStringRef*)outData) = CFSTR("LeftElementName"); - // break; - // - // case 2: - // *((CFStringRef*)outData) = CFSTR("RightElementName"); - // break; - // - // default: - // *((CFStringRef*)outData) = CFSTR("unknown"); - // break; - // - // }; - // *outDataSize = sizeof(CFStringRef); - // break; - - case kAudioObjectPropertyOwnedObjects: - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID); - - // The device owns its streams and controls. Note that what is returned here - // depends on the scope requested. - switch(inAddress->mScope) { - case kAudioObjectPropertyScopeGlobal: - // global scope means return all objects - if (theNumberItemsToFetch > 8) { - theNumberItemsToFetch = 8; - } - - // fill out the list with as many objects as requested, which is everything - for (theItemIndex = 0; theItemIndex < theNumberItemsToFetch; ++theItemIndex) { - ((AudioObjectID*)outData)[theItemIndex] = kObjectID_Stream_Input + theItemIndex; - } - break; - - case kAudioObjectPropertyScopeInput: - // input scope means just the objects on the input side - if (theNumberItemsToFetch > 4) { - theNumberItemsToFetch = 4; - } - - // fill out the list with the right objects - for (theItemIndex = 0; theItemIndex < theNumberItemsToFetch; ++theItemIndex) { - ((AudioObjectID*)outData)[theItemIndex] = kObjectID_Stream_Input + theItemIndex; - } - break; - - case kAudioObjectPropertyScopeOutput: - // output scope means just the objects on the output side - if (theNumberItemsToFetch > 4) { - theNumberItemsToFetch = 4; - } - - // fill out the list with the right objects - for (theItemIndex = 0; theItemIndex < theNumberItemsToFetch; ++theItemIndex) { - ((AudioObjectID*)outData)[theItemIndex] = kObjectID_Stream_Output + theItemIndex; - } - break; - }; - - // report how much we wrote - *outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID); - break; - - case kAudioDevicePropertyDeviceUID: - // This is a CFString that is a persistent token that can identify the same - // audio device across boot sessions. Note that two instances of the same - // device must have different values for this property. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceUID for the device"); - *((CFStringRef*)outData) = CFSTR(kDevice_UID); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioDevicePropertyModelUID: - // This is a CFString that is a persistent token that can identify audio - // devices that are the same kind of device. Note that two instances of the - // save device must have the same value for this property. - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyModelUID for the device"); - *((CFStringRef*)outData) = CFSTR(kDevice_ModelUID); - *outDataSize = sizeof(CFStringRef); - break; - - case kAudioDevicePropertyTransportType: - // This value represents how the device is attached to the system. This can be - // any 32 bit integer, but common values for this property are defined in - // - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyTransportType for the device"); - *((UInt32*)outData) = kAudioDeviceTransportTypeVirtual; - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyRelatedDevices: - // The related devices property identifys device objects that are very closely - // related. Generally, this is for relating devices that are packaged together - // in the hardware such as when the input side and the output side of a piece - // of hardware can be clocked separately and therefore need to be represented - // as separate AudioDevice objects. In such case, both devices would report - // that they are related to each other. Note that at minimum, a device is - // related to itself, so this list will always be at least one item long. - - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID); - - // we only have the one device... - if (theNumberItemsToFetch > 1) { - theNumberItemsToFetch = 1; - } - - // Write the devices' object IDs into the return value - if (theNumberItemsToFetch > 0) { - ((AudioObjectID*)outData)[0] = kObjectID_Device; - } - - // report how much we wrote - *outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID); - break; - - case kAudioDevicePropertyClockDomain: - // This property allows the device to declare what other devices it is - // synchronized with in hardware. The way it works is that if two devices have - // the same value for this property and the value is not zero, then the two - // devices are synchronized in hardware. Note that a device that either can't - // be synchronized with others or doesn't know should return 0 for this - // property. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyClockDomain for the device"); - *((UInt32*)outData) = 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyDeviceIsAlive: - // This property returns whether or not the device is alive. Note that it is - // note uncommon for a device to be dead but still momentarily availble in the - // device list. In the case of this device, it will always be alive. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceIsAlive for the device"); - *((UInt32*)outData) = 1; - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyDeviceIsRunning: - // This property returns whether or not IO is running for the device. Note that - // we need to take both the state lock to check this value for thread safety. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceIsRunning for the device"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((UInt32*)outData) = ((gDevice_IOIsRunning > 0) > 0) ? 1 : 0; - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyDeviceCanBeDefaultDevice: - // This property returns whether or not the device wants to be able to be the - // default device for content. This is the device that iTunes and QuickTime - // will use to play their content on and FaceTime will use as it's microhphone. - // Nearly all devices should allow for this. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceCanBeDefaultDevice for the device"); - *((UInt32*)outData) = inAddress->mScope == kAudioObjectPropertyScopeInput ? 0 : (mShown ? 1 : 0); - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice: - // This property returns whether or not the device wants to be the system - // default device. This is the device that is used to play interface sounds and - // other incidental or UI-related sounds on. Most devices should allow this - // although devices with lots of latency may not want to. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceCanBeDefaultSystemDevice for the device"); - *((UInt32*)outData) = mShown ? 1 : 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyLatency: - // This property returns the presentation latency of the device. For this, - // device, the value is 0 due to the fact that it always vends silence. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyLatency for the device"); - *((UInt32*)outData) = inAddress->mScope == kAudioObjectPropertyScopeInput ? 0 : mLatency; - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyStreams: - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID); - - // Note that what is returned here depends on the scope requested. - switch(inAddress->mScope) { - case kAudioObjectPropertyScopeGlobal: - // global scope means return all streams - if (theNumberItemsToFetch > 2) { - theNumberItemsToFetch = 2; - } - - // fill out the list with as many objects as requested - if (theNumberItemsToFetch > 0) { - ((AudioObjectID*)outData)[0] = kObjectID_Stream_Input; - } - if (theNumberItemsToFetch > 1) { - ((AudioObjectID*)outData)[1] = kObjectID_Stream_Output; - } - break; - - case kAudioObjectPropertyScopeInput: - // input scope means just the objects on the input side - if (theNumberItemsToFetch > 1) { - theNumberItemsToFetch = 1; - } - - // fill out the list with as many objects as requested - if (theNumberItemsToFetch > 0) { - ((AudioObjectID*)outData)[0] = kObjectID_Stream_Input; - } - break; - - case kAudioObjectPropertyScopeOutput: - // output scope means just the objects on the output side - if (theNumberItemsToFetch > 1) { - theNumberItemsToFetch = 1; - } - - // fill out the list with as many objects as requested - if (theNumberItemsToFetch > 0) { - ((AudioObjectID*)outData)[0] = kObjectID_Stream_Output; - } - break; - }; - - // report how much we wrote - *outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyControlList: - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID); - if (theNumberItemsToFetch > 6) { - theNumberItemsToFetch = 6; - } - - // fill out the list with as many objects as requested, which is everything - for (theItemIndex = 0; theItemIndex < theNumberItemsToFetch; ++theItemIndex) { - if (theItemIndex < 3) { - ((AudioObjectID*)outData)[theItemIndex] = kObjectID_Volume_Input_Master + theItemIndex; - } else { - ((AudioObjectID*)outData)[theItemIndex] = kObjectID_Volume_Output_Master + (theItemIndex - 3); - } - } - - // report how much we wrote - *outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID); - break; - - case kAudioDevicePropertySafetyOffset: - // This property returns the how close to now the HAL can read and write. For - // this, device, the value is 0 due to the fact that it always vends silence. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertySafetyOffset for the device"); - *((UInt32*)outData) = inAddress->mScope == kAudioObjectPropertyScopeInput ? 0 : mSafetyOffset; - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyNominalSampleRate: - // This property returns the nominal sample rate of the device. Note that we - // only need to take the state lock to get this value. - FailWithAction(inDataSize < sizeof(Float64), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyNominalSampleRate for the device"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((Float64*)outData) = gDevice_SampleRate; - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outDataSize = sizeof(Float64); - break; - - case kAudioDevicePropertyAvailableNominalSampleRates: - // This returns all nominal sample rates the device supports as an array of - // AudioValueRangeStructs. Note that for discrete sampler rates, the range - // will have the minimum value equal to the maximum value. - - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioValueRange); - - // clamp it to the number of items we have - if (theNumberItemsToFetch > 6) { - theNumberItemsToFetch = 6; - } - - // fill out the return array - if (theNumberItemsToFetch > 0) { - ((AudioValueRange*)outData)[0].mMinimum = 44100.0; - ((AudioValueRange*)outData)[0].mMaximum = 44100.0; - } - if (theNumberItemsToFetch > 1) { - ((AudioValueRange*)outData)[1].mMinimum = 48000.0; - ((AudioValueRange*)outData)[1].mMaximum = 48000.0; - } - if (theNumberItemsToFetch > 2) { - ((AudioValueRange*)outData)[2].mMinimum = 88200.0; - ((AudioValueRange*)outData)[2].mMaximum = 88200.0; - } - if (theNumberItemsToFetch > 3) { - ((AudioValueRange*)outData)[3].mMinimum = 96000.0; - ((AudioValueRange*)outData)[3].mMaximum = 96000.0; - } - if (theNumberItemsToFetch > 4) { - ((AudioValueRange*)outData)[4].mMinimum = 176400.0; - ((AudioValueRange*)outData)[4].mMaximum = 176400.0; - } - if (theNumberItemsToFetch > 5) { - ((AudioValueRange*)outData)[5].mMinimum = 192000.0; - ((AudioValueRange*)outData)[5].mMaximum = 192000.0; - } - - // report how much we wrote - *outDataSize = theNumberItemsToFetch * sizeof(AudioValueRange); - break; - - case kAudioDevicePropertyIsHidden: - // This returns whether or not the device is visible to clients. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyIsHidden for the device"); - *((UInt32*)outData) = 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyPreferredChannelsForStereo: - // This property returns which two channesl to use as left/right for stereo - // data by default. Note that the channel numbers are 1-based.xz - FailWithAction(inDataSize < (2 * sizeof(UInt32)), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyPreferredChannelsForStereo for the device"); - ((UInt32*)outData)[0] = 1; - ((UInt32*)outData)[1] = 2; - *outDataSize = 2 * sizeof(UInt32); - break; - - case kAudioDevicePropertyPreferredChannelLayout: { - // This property returns the default AudioChannelLayout to use for the device - // by default. For this device, we return a stereo ACL. - // calcualte how big the - UInt32 theACLSize = offsetof(AudioChannelLayout, mChannelDescriptions) + (kChannelCount * sizeof(AudioChannelDescription)); - FailWithAction(inDataSize < theACLSize, theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyPreferredChannelLayout for the device"); - ((AudioChannelLayout*)outData)->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; - ((AudioChannelLayout*)outData)->mChannelBitmap = 0; - ((AudioChannelLayout*)outData)->mNumberChannelDescriptions = kChannelCount; - for (theItemIndex = 0; theItemIndex < kChannelCount; ++theItemIndex) { - ((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mChannelLabel = kAudioChannelLabel_Left + theItemIndex; - ((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mChannelFlags = 0; - ((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mCoordinates[0] = 0; - ((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mCoordinates[1] = 0; - ((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mCoordinates[2] = 0; - } - *outDataSize = theACLSize; - } - break; - - case kAudioDevicePropertyZeroTimeStampPeriod: - // This property returns how many frames the HAL should expect to see between - // successive sample times in the zero time stamps this device provides. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyZeroTimeStampPeriod for the device"); - *((UInt32*)outData) = kDevice_RingBufferSize; - *outDataSize = sizeof(UInt32); - break; - - case kAudioDevicePropertyIcon:{ - // This is a CFURL that points to the device's Icon in the plug-in's resource bundle. - FailWithAction(inDataSize < sizeof(CFURLRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceUID for the device"); - CFBundleRef theBundle = CFBundleGetBundleWithIdentifier(CFSTR(kPlugIn_BundleID)); - FailWithAction(theBundle == NULL, theAnswer = kAudioHardwareUnspecifiedError, Done, "eqMac_GetDevicePropertyData: could not get the plug-in bundle for kAudioDevicePropertyIcon"); - CFURLRef theURL = CFBundleCopyResourceURL(theBundle, CFSTR("icon.icns"), NULL, NULL); - FailWithAction(theURL == NULL, theAnswer = kAudioHardwareUnspecifiedError, Done, "eqMac_GetDevicePropertyData: could not get the URL for kAudioDevicePropertyIcon"); - *((CFURLRef*)outData) = theURL; - *outDataSize = sizeof(CFURLRef); - } - break; - - case kAudioObjectPropertyCustomPropertyInfoList: - // This property returns an array of AudioServerPlugInCustomPropertyInfo's that - // describe the type of data used by any custom properties. For this example, - // the plug-in supports a single property whose data type is a CFString and - // whose qualifier is a CFString. - FailWithAction(inDataSize < sizeof(AudioServerPlugInCustomPropertyInfo), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyCustomPropertyInfoList"); - theNumberItemsToFetch = inDataSize / sizeof(AudioServerPlugInCustomPropertyInfo); - - // clamp it to the number of items we have - if (theNumberItemsToFetch > 4) { - theNumberItemsToFetch = 4; - } - - if (theNumberItemsToFetch > 0) { - ((AudioServerPlugInCustomPropertyInfo*)outData)[0].mSelector = kAudioDeviceCustomPropertyLatency; - ((AudioServerPlugInCustomPropertyInfo*)outData)[0].mPropertyDataType = kAudioServerPlugInCustomPropertyDataTypeCFPropertyList; - ((AudioServerPlugInCustomPropertyInfo*)outData)[0].mQualifierDataType = kAudioServerPlugInCustomPropertyDataTypeNone; - } - - if (theNumberItemsToFetch > 1) { - ((AudioServerPlugInCustomPropertyInfo*)outData)[1].mSelector = kAudioDeviceCustomPropertySafetyOffset; - ((AudioServerPlugInCustomPropertyInfo*)outData)[1].mPropertyDataType = kAudioServerPlugInCustomPropertyDataTypeCFPropertyList; - ((AudioServerPlugInCustomPropertyInfo*)outData)[1].mQualifierDataType = kAudioServerPlugInCustomPropertyDataTypeNone; - } - - if (theNumberItemsToFetch > 2) { - ((AudioServerPlugInCustomPropertyInfo*)outData)[2].mSelector = kAudioDeviceCustomPropertyShown; - ((AudioServerPlugInCustomPropertyInfo*)outData)[2].mPropertyDataType = kAudioServerPlugInCustomPropertyDataTypeCFPropertyList; - ((AudioServerPlugInCustomPropertyInfo*)outData)[2].mQualifierDataType = kAudioServerPlugInCustomPropertyDataTypeNone; - } - - if (theNumberItemsToFetch > 3) { - ((AudioServerPlugInCustomPropertyInfo*)outData)[3].mSelector = kAudioDeviceCustomPropertyVersion; - ((AudioServerPlugInCustomPropertyInfo*)outData)[3].mPropertyDataType = kAudioServerPlugInCustomPropertyDataTypeCFString; - ((AudioServerPlugInCustomPropertyInfo*)outData)[3].mQualifierDataType = kAudioServerPlugInCustomPropertyDataTypeNone; - } - - *outDataSize = theNumberItemsToFetch * sizeof(AudioServerPlugInCustomPropertyInfo); - break; - - case kAudioDeviceCustomPropertyVersion: { - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "EQM_Device::Device_GetPropertyData: not enough space for the return value of kAudioDeviceCustomPropertyVersion for the device"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((CFStringRef*)outData) = - CFCopyDescription( - CFBundleGetValueForInfoDictionaryKey( - CFBundleGetBundleWithIdentifier(CFSTR(kPlugIn_BundleID)), - kCFBundleVersionKey - ) - ); - pthread_mutex_unlock(&gPlugIn_StateMutex); - if (*((CFStringRef*)outData) != NULL) { - CFRetain(*((CFStringRef*)outData)); - } - *outDataSize = sizeof(CFStringRef); - break; - } - - case kAudioDeviceCustomPropertyShown: - FailWithAction(inDataSize < sizeof(CFBooleanRef), theAnswer = kAudioHardwareBadPropertySizeError, Done,"EQM_Device::Device_GetPropertyData: not enough space for the return value of kAudioDeviceCustomPropertyShown for the device"); - *((CFBooleanRef*)outData) = mShown ? kCFBooleanTrue : kCFBooleanFalse; - *outDataSize = sizeof(CFBooleanRef); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_SetDevicePropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]) { - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - Float64 theOldSampleRate; - UInt64 theNewSampleRate; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetDevicePropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetDevicePropertyData: no address"); - FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetDevicePropertyData: no place to return the number of properties that changed"); - FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetDevicePropertyData: no place to return the properties that changed"); - FailWithAction(inObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetDevicePropertyData: not the device object"); - - // initialize the returned number of changed properties - *outNumberPropertiesChanged = 0; - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetDevicePropertyData() method. - switch(inAddress->mSelector) { - case kAudioDevicePropertyNominalSampleRate: - // Changing the sample rate needs to be handled via the - // RequestConfigChange/PerformConfigChange machinery. - - // check the arguments - FailWithAction(inDataSize != sizeof(Float64), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetDevicePropertyData: wrong size for the data for kAudioDevicePropertyNominalSampleRate"); - FailWithAction((*((const Float64*)inData) != 44100.0) && (*((const Float64*)inData) != 48000.0) && (*((const Float64*)inData) != 88200.0) && (*((const Float64*)inData) != 96000.0) && (*((const Float64*)inData) != 176400.0) && (*((const Float64*)inData) != 192000.0), theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetDevicePropertyData: unsupported value for kAudioDevicePropertyNominalSampleRate"); - - // make sure that the new value is different than the old value - pthread_mutex_lock(&gPlugIn_StateMutex); - theOldSampleRate = gDevice_SampleRate; - pthread_mutex_unlock(&gPlugIn_StateMutex); - if (*((const Float64*)inData) != theOldSampleRate) { - // *outNumberPropertiesChanged = 1; - // outChangedAddresses[0].mSelector = kAudioDevicePropertyNominalSampleRate; - // outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - // outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - // we dispatch this so that the change can happen asynchronously - theOldSampleRate = *((const Float64*)inData); - theNewSampleRate = (UInt64)theOldSampleRate; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ gPlugIn_Host->RequestDeviceConfigurationChange(gPlugIn_Host, kObjectID_Device, theNewSampleRate, NULL); }); - } - break; - - case kAudioDeviceCustomPropertyShown: { - FailWithAction(inDataSize != sizeof(CFBooleanRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "EQM_Device::Device_SetPropertyData: wrong size for the data for kAudioDeviceCustomPropertyShown"); - CFBooleanRef shownRef = *((const CFBooleanRef*)inData); - mShown = CFBooleanGetValue(shownRef); - break; - } - - case kAudioDeviceCustomPropertyLatency: { - FailWithAction(inDataSize != sizeof(CFNumberRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "EQM_Device::Device_SetPropertyData: wrong size for the data for kAudioDeviceCustomPropertyLatency"); - CFNumberRef latencyRef = *((const CFNumberRef*)inData); - uint32_t latency = 0; - CFNumberGetValue(latencyRef, kCFNumberSInt32Type, &latency); - FailWithAction(latency < 0, - theAnswer = kAudioHardwareIllegalOperationError, - Done, - "EQM_Device::Device_SetPropertyData: kAudioDeviceCustomPropertyLatency cannot be lower than 0"); - mLatency = latency; - break; - } - - case kAudioDeviceCustomPropertySafetyOffset: { - FailWithAction(inDataSize != sizeof(CFNumberRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "EQM_Device::Device_SetPropertyData: wrong size for the data for kAudioDeviceCustomPropertySafetyOffset"); - CFNumberRef safetyOffsetRef = *((const CFNumberRef*)inData); - uint32_t safetyOffset = 0; - CFNumberGetValue(safetyOffsetRef, kCFNumberSInt32Type, &safetyOffset); - FailWithAction(safetyOffset < 0, - theAnswer = kAudioHardwareIllegalOperationError, - Done, - "EQM_Device::Device_SetPropertyData: kAudioDeviceCustomPropertySafetyOffset cannot be lower than 0"); - mSafetyOffset = safetyOffset; - break; - } - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -#pragma mark Stream Property Operations - -static Boolean eqMac_HasStreamProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress) { - - // This method returns whether or not the given object has the given property. - -#pragma unused(inClientProcessID) - - // declare the local variables - Boolean theAnswer = false; - - // check the arguments - FailIf (inDriver != gAudioServerPlugInDriverRef, Done, "eqMac_HasStreamProperty: bad driver reference"); - FailIf (inAddress == NULL, Done, "eqMac_HasStreamProperty: no address"); - FailIf ((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), Done, "eqMac_HasStreamProperty: not a stream object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetStreamPropertyData() method. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyOwnedObjects: - // case kAudioObjectPropertyName: - case kAudioStreamPropertyIsActive: - case kAudioStreamPropertyDirection: - case kAudioStreamPropertyTerminalType: - case kAudioStreamPropertyStartingChannel: - case kAudioStreamPropertyLatency: - case kAudioStreamPropertyVirtualFormat: - case kAudioStreamPropertyPhysicalFormat: - case kAudioStreamPropertyAvailableVirtualFormats: - case kAudioStreamPropertyAvailablePhysicalFormats: - theAnswer = true; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_IsStreamPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable) { - - // This method returns whether or not the given property on the object can have its value - // changed. - -#pragma unused(inClientProcessID) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsStreamPropertySettable: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsStreamPropertySettable: no address"); - FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsStreamPropertySettable: no place to put the return value"); - FailWithAction((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsStreamPropertySettable: not a stream object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetStreamPropertyData() method. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyOwnedObjects: - // case kAudioObjectPropertyName: - case kAudioStreamPropertyDirection: - case kAudioStreamPropertyTerminalType: - case kAudioStreamPropertyStartingChannel: - case kAudioStreamPropertyLatency: - case kAudioStreamPropertyAvailableVirtualFormats: - case kAudioStreamPropertyAvailablePhysicalFormats: - *outIsSettable = false; - break; - - case kAudioStreamPropertyIsActive: - case kAudioStreamPropertyVirtualFormat: - case kAudioStreamPropertyPhysicalFormat: - *outIsSettable = true; - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetStreamPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize) { - - // This method returns the byte size of the property's data. - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetStreamPropertyDataSize: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetStreamPropertyDataSize: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetStreamPropertyDataSize: no place to put the return value"); - FailWithAction((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetStreamPropertyDataSize: not a stream object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetStreamPropertyData() method. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyOwnedObjects: - *outDataSize = 0 * sizeof(AudioObjectID); - break; - - // case kAudioObjectPropertyName: - // *outDataSize = sizeof(CFStringRef); - // break; - - case kAudioStreamPropertyIsActive: - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyDirection: - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyTerminalType: - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyStartingChannel: - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyLatency: - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyVirtualFormat: - case kAudioStreamPropertyPhysicalFormat: - *outDataSize = sizeof(AudioStreamBasicDescription); - break; - - case kAudioStreamPropertyAvailableVirtualFormats: - case kAudioStreamPropertyAvailablePhysicalFormats: - *outDataSize = 6 * sizeof(AudioStreamRangedDescription); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetStreamPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData) { - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - UInt32 theNumberItemsToFetch; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetStreamPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetStreamPropertyData: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetStreamPropertyData: no place to put the return value size"); - FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetStreamPropertyData: no place to put the return value"); - FailWithAction((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetStreamPropertyData: not a stream object"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. - // - // Also, since most of the data that will get returned is static, there are few instances where - // it is necessary to lock the state mutex. - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - // The base class for kAudioStreamClassID is kAudioObjectClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the stream"); - *((AudioClassID*)outData) = kAudioObjectClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - // The class is always kAudioStreamClassID for streams created by drivers - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the stream"); - *((AudioClassID*)outData) = kAudioStreamClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - // The stream's owner is the device object - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the stream"); - *((AudioObjectID*)outData) = kObjectID_Device; - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyOwnedObjects: - // Streams do not own any objects - *outDataSize = 0 * sizeof(AudioObjectID); - break; - - // case kAudioObjectPropertyName: - // // This is the human readable name of the stream - // FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioObjectPropertyName for the stream"); - // *((CFStringRef*)outData) = (inObjectID == kObjectID_Stream_Input) ? CFSTR("InputStreamName") : CFSTR("OutputStreamName"); - // *outDataSize = sizeof(CFStringRef); - // break; - - case kAudioStreamPropertyIsActive: - // This property tells the device whether or not the given stream is going to - // be used for IO. Note that we need to take the state lock to examine this - // value. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyIsActive for the stream"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((UInt32*)outData) = (inObjectID == kObjectID_Stream_Input) ? gStream_Input_IsActive : gStream_Output_IsActive; - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyDirection: - // This returns whether the stream is an input stream or an output stream. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyDirection for the stream"); - *((UInt32*)outData) = (inObjectID == kObjectID_Stream_Input) ? 1 : 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyTerminalType: - // This returns a value that indicates what is at the other end of the stream - // such as a speaker or headphones, or a microphone. Values for this property - // are defined in - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyTerminalType for the stream"); - *((UInt32*)outData) = (inObjectID == kObjectID_Stream_Input) ? kAudioStreamTerminalTypeMicrophone : kAudioStreamTerminalTypeSpeaker; - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyStartingChannel: - // This property returns the absolute channel number for the first channel in - // the stream. For exmaple, if a device has two output streams with two - // channels each, then the starting channel number for the first stream is 1 - // and ths starting channel number fo the second stream is 3. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyStartingChannel for the stream"); - *((UInt32*)outData) = 1; - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyLatency: - // This property returns any additonal presentation latency the stream has. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyStartingChannel for the stream"); - *((UInt32*)outData) = 0; - *outDataSize = sizeof(UInt32); - break; - - case kAudioStreamPropertyVirtualFormat: - case kAudioStreamPropertyPhysicalFormat: - // This returns the current format of the stream in an - // AudioStreamBasicDescription. Note that we need to hold the state lock to get - // this value. - // Note that for devices that don't override the mix operation, the virtual - // format has to be the same as the physical format. - FailWithAction(inDataSize < sizeof(AudioStreamBasicDescription), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyVirtualFormat for the stream"); - pthread_mutex_lock(&gPlugIn_StateMutex); - ((AudioStreamBasicDescription*)outData)->mSampleRate = gDevice_SampleRate; - ((AudioStreamBasicDescription*)outData)->mFormatID = kAudioFormatLinearPCM; - ((AudioStreamBasicDescription*)outData)->mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - ((AudioStreamBasicDescription*)outData)->mBytesPerPacket = kBytesPerChannel * kChannelCount; - ((AudioStreamBasicDescription*)outData)->mFramesPerPacket = 1; - ((AudioStreamBasicDescription*)outData)->mBytesPerFrame = kBytesPerChannel * kChannelCount; - ((AudioStreamBasicDescription*)outData)->mChannelsPerFrame = kChannelCount; - ((AudioStreamBasicDescription*)outData)->mBitsPerChannel = kBitsPerChannel; - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outDataSize = sizeof(AudioStreamBasicDescription); - break; - - case kAudioStreamPropertyAvailableVirtualFormats: - case kAudioStreamPropertyAvailablePhysicalFormats: - // This returns an array of AudioStreamRangedDescriptions that describe what - // formats are supported. - - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(AudioStreamRangedDescription); - - // clamp it to the number of items we have - if (theNumberItemsToFetch > 6) { - theNumberItemsToFetch = 6; - } - - // fill out the return array - if (theNumberItemsToFetch > 0) { - ((AudioStreamRangedDescription*)outData)[0].mFormat.mSampleRate = 44100.0; - ((AudioStreamRangedDescription*)outData)[0].mFormat.mFormatID = kAudioFormatLinearPCM; - ((AudioStreamRangedDescription*)outData)[0].mFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - ((AudioStreamRangedDescription*)outData)[0].mFormat.mBytesPerPacket = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[0].mFormat.mFramesPerPacket = 1; - ((AudioStreamRangedDescription*)outData)[0].mFormat.mBytesPerFrame = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[0].mFormat.mChannelsPerFrame = kChannelCount; - ((AudioStreamRangedDescription*)outData)[0].mFormat.mBitsPerChannel = kBitsPerChannel; - ((AudioStreamRangedDescription*)outData)[0].mSampleRateRange.mMinimum = 44100.0; - ((AudioStreamRangedDescription*)outData)[0].mSampleRateRange.mMaximum = 44100.0; - } - if (theNumberItemsToFetch > 1) { - ((AudioStreamRangedDescription*)outData)[1].mFormat.mSampleRate = 48000.0; - ((AudioStreamRangedDescription*)outData)[1].mFormat.mFormatID = kAudioFormatLinearPCM; - ((AudioStreamRangedDescription*)outData)[1].mFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - ((AudioStreamRangedDescription*)outData)[1].mFormat.mBytesPerPacket = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[1].mFormat.mFramesPerPacket = 1; - ((AudioStreamRangedDescription*)outData)[1].mFormat.mBytesPerFrame = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[1].mFormat.mChannelsPerFrame = kChannelCount; - ((AudioStreamRangedDescription*)outData)[1].mFormat.mBitsPerChannel = kBitsPerChannel; - ((AudioStreamRangedDescription*)outData)[1].mSampleRateRange.mMinimum = 48000.0; - ((AudioStreamRangedDescription*)outData)[1].mSampleRateRange.mMaximum = 48000.0; - } - if (theNumberItemsToFetch > 2) { - ((AudioStreamRangedDescription*)outData)[2].mFormat.mSampleRate = 88200.0; - ((AudioStreamRangedDescription*)outData)[2].mFormat.mFormatID = kAudioFormatLinearPCM; - ((AudioStreamRangedDescription*)outData)[2].mFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - ((AudioStreamRangedDescription*)outData)[2].mFormat.mBytesPerPacket = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[2].mFormat.mFramesPerPacket = 1; - ((AudioStreamRangedDescription*)outData)[2].mFormat.mBytesPerFrame = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[2].mFormat.mChannelsPerFrame = kChannelCount; - ((AudioStreamRangedDescription*)outData)[2].mFormat.mBitsPerChannel = kBitsPerChannel; - ((AudioStreamRangedDescription*)outData)[2].mSampleRateRange.mMinimum = 88200.0; - ((AudioStreamRangedDescription*)outData)[2].mSampleRateRange.mMaximum = 88200.0; - } - if (theNumberItemsToFetch > 3) { - ((AudioStreamRangedDescription*)outData)[3].mFormat.mSampleRate = 96000.0; - ((AudioStreamRangedDescription*)outData)[3].mFormat.mFormatID = kAudioFormatLinearPCM; - ((AudioStreamRangedDescription*)outData)[3].mFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - ((AudioStreamRangedDescription*)outData)[3].mFormat.mBytesPerPacket = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[3].mFormat.mFramesPerPacket = 1; - ((AudioStreamRangedDescription*)outData)[3].mFormat.mBytesPerFrame = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[3].mFormat.mChannelsPerFrame = kChannelCount; - ((AudioStreamRangedDescription*)outData)[3].mFormat.mBitsPerChannel = kBitsPerChannel; - ((AudioStreamRangedDescription*)outData)[3].mSampleRateRange.mMinimum = 96000.0; - ((AudioStreamRangedDescription*)outData)[3].mSampleRateRange.mMaximum = 96000.0; - } - if (theNumberItemsToFetch > 4) { - ((AudioStreamRangedDescription*)outData)[4].mFormat.mSampleRate = 176400.0; - ((AudioStreamRangedDescription*)outData)[4].mFormat.mFormatID = kAudioFormatLinearPCM; - ((AudioStreamRangedDescription*)outData)[4].mFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - ((AudioStreamRangedDescription*)outData)[4].mFormat.mBytesPerPacket = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[4].mFormat.mFramesPerPacket = 1; - ((AudioStreamRangedDescription*)outData)[4].mFormat.mBytesPerFrame = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[4].mFormat.mChannelsPerFrame = kChannelCount; - ((AudioStreamRangedDescription*)outData)[4].mFormat.mBitsPerChannel = kBitsPerChannel; - ((AudioStreamRangedDescription*)outData)[4].mSampleRateRange.mMinimum = 176400.0; - ((AudioStreamRangedDescription*)outData)[4].mSampleRateRange.mMaximum = 176400.0; - } - if (theNumberItemsToFetch > 5) { - ((AudioStreamRangedDescription*)outData)[5].mFormat.mSampleRate = 192000.0; - ((AudioStreamRangedDescription*)outData)[5].mFormat.mFormatID = kAudioFormatLinearPCM; - ((AudioStreamRangedDescription*)outData)[5].mFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - ((AudioStreamRangedDescription*)outData)[5].mFormat.mBytesPerPacket = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[5].mFormat.mFramesPerPacket = 1; - ((AudioStreamRangedDescription*)outData)[5].mFormat.mBytesPerFrame = kBytesPerFrame; - ((AudioStreamRangedDescription*)outData)[5].mFormat.mChannelsPerFrame = kChannelCount; - ((AudioStreamRangedDescription*)outData)[5].mFormat.mBitsPerChannel = kBitsPerChannel; - ((AudioStreamRangedDescription*)outData)[5].mSampleRateRange.mMinimum = 192000.0; - ((AudioStreamRangedDescription*)outData)[5].mSampleRateRange.mMaximum = 192000.0; - } - - // report how much we wrote - *outDataSize = theNumberItemsToFetch * sizeof(AudioStreamRangedDescription); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_SetStreamPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]) { - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - Float64 theOldSampleRate; - UInt64 theNewSampleRate; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetStreamPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetStreamPropertyData: no address"); - FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetStreamPropertyData: no place to return the number of properties that changed"); - FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetStreamPropertyData: no place to return the properties that changed"); - FailWithAction((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetStreamPropertyData: not a stream object"); - - // initialize the returned number of changed properties - *outNumberPropertiesChanged = 0; - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetStreamPropertyData() method. - switch(inAddress->mSelector) { - case kAudioStreamPropertyIsActive: - // Changing the active state of a stream doesn't affect IO or change the structure - // so we can just save the state and send the notification. - FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetStreamPropertyData: wrong size for the data for kAudioDevicePropertyNominalSampleRate"); - pthread_mutex_lock(&gPlugIn_StateMutex); - if (inObjectID == kObjectID_Stream_Input) { - if (gStream_Input_IsActive != (*((const UInt32*)inData) != 0)) { - gStream_Input_IsActive = *((const UInt32*)inData) != 0; - *outNumberPropertiesChanged = 1; - outChangedAddresses[0].mSelector = kAudioStreamPropertyIsActive; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - } - } else { - if (gStream_Output_IsActive != (*((const UInt32*)inData) != 0)) { - gStream_Output_IsActive = *((const UInt32*)inData) != 0; - *outNumberPropertiesChanged = 1; - outChangedAddresses[0].mSelector = kAudioStreamPropertyIsActive; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - } - } - pthread_mutex_unlock(&gPlugIn_StateMutex); - break; - - case kAudioStreamPropertyVirtualFormat: - case kAudioStreamPropertyPhysicalFormat: - // Changing the stream format needs to be handled via the - // RequestConfigChange/PerformConfigChange machinery. Note that because this - // device only supports 2 channel 32 bit float data, the only thing that can - // change is the sample rate. - FailWithAction(inDataSize != sizeof(AudioStreamBasicDescription), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetStreamPropertyData: wrong size for the data for kAudioStreamPropertyPhysicalFormat"); - FailWithAction(((const AudioStreamBasicDescription*)inData)->mFormatID != kAudioFormatLinearPCM, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "eqMac_SetStreamPropertyData: unsupported format ID for kAudioStreamPropertyPhysicalFormat"); - FailWithAction(((const AudioStreamBasicDescription*)inData)->mFormatFlags != (kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked), theAnswer = kAudioDeviceUnsupportedFormatError, Done, "eqMac_SetStreamPropertyData: unsupported format flags for kAudioStreamPropertyPhysicalFormat"); - FailWithAction(((const AudioStreamBasicDescription*)inData)->mBytesPerPacket != kBytesPerFrame, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "eqMac_SetStreamPropertyData: unsupported bytes per packet for kAudioStreamPropertyPhysicalFormat"); - FailWithAction(((const AudioStreamBasicDescription*)inData)->mFramesPerPacket != 1, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "eqMac_SetStreamPropertyData: unsupported frames per packet for kAudioStreamPropertyPhysicalFormat"); - FailWithAction(((const AudioStreamBasicDescription*)inData)->mBytesPerFrame != kBytesPerFrame, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "eqMac_SetStreamPropertyData: unsupported bytes per frame for kAudioStreamPropertyPhysicalFormat"); - FailWithAction(((const AudioStreamBasicDescription*)inData)->mChannelsPerFrame != kChannelCount, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "eqMac_SetStreamPropertyData: unsupported channels per frame for kAudioStreamPropertyPhysicalFormat"); - FailWithAction(((const AudioStreamBasicDescription*)inData)->mBitsPerChannel != kBitsPerChannel, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "eqMac_SetStreamPropertyData: unsupported bits per channel for kAudioStreamPropertyPhysicalFormat"); - FailWithAction((((const AudioStreamBasicDescription*)inData)->mSampleRate != 44100.0) - && (((const AudioStreamBasicDescription*)inData)->mSampleRate != 48000.0) - && (((const AudioStreamBasicDescription*)inData)->mSampleRate != 88200.0) - && (((const AudioStreamBasicDescription*)inData)->mSampleRate != 96000.0) - && (((const AudioStreamBasicDescription*)inData)->mSampleRate != 176400.0) - && (((const AudioStreamBasicDescription*)inData)->mSampleRate != 192000.0), - theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetStreamPropertyData: unsupported sample rate for kAudioStreamPropertyPhysicalFormat"); - - // If we made it this far, the requested format is something we support, so make sure the sample rate is actually different - pthread_mutex_lock(&gPlugIn_StateMutex); - theOldSampleRate = gDevice_SampleRate; - pthread_mutex_unlock(&gPlugIn_StateMutex); - if (((const AudioStreamBasicDescription*)inData)->mSampleRate != theOldSampleRate) { - // we dispatch this so that the change can happen asynchronously - theOldSampleRate = ((const AudioStreamBasicDescription*)inData)->mSampleRate; - theNewSampleRate = (UInt64)theOldSampleRate; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ gPlugIn_Host->RequestDeviceConfigurationChange(gPlugIn_Host, kObjectID_Device, theNewSampleRate, NULL); }); - } - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - -Done: - return theAnswer; -} - -#pragma mark Control Property Operations - -static Boolean eqMac_HasControlProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress) { - - // This method returns whether or not the given object has the given property. - -#pragma unused(inClientProcessID) - - // declare the local variables - Boolean theAnswer = false; - - // check the arguments - FailIf (inDriver != gAudioServerPlugInDriverRef, Done, "eqMac_HasControlProperty: bad driver reference"); - FailIf (inAddress == NULL, Done, "eqMac_HasControlProperty: no address"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetControlPropertyData() method. - switch(inObjectID) { - case kObjectID_Volume_Input_Master: - case kObjectID_Volume_Output_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyOwnedObjects: - case kAudioControlPropertyScope: - case kAudioControlPropertyElement: - case kAudioLevelControlPropertyScalarValue: - case kAudioLevelControlPropertyDecibelValue: - case kAudioLevelControlPropertyDecibelRange: - case kAudioLevelControlPropertyConvertScalarToDecibels: - case kAudioLevelControlPropertyConvertDecibelsToScalar: - theAnswer = true; - break; - }; - break; - - case kObjectID_Mute_Input_Master: - case kObjectID_Mute_Output_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyOwnedObjects: - case kAudioControlPropertyScope: - case kAudioControlPropertyElement: - case kAudioBooleanControlPropertyValue: - theAnswer = true; - break; - }; - break; - - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - // case kObjectID_DataDestination_PlayThru_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyOwnedObjects: - case kAudioControlPropertyScope: - case kAudioControlPropertyElement: - case kAudioSelectorControlPropertyCurrentItem: - case kAudioSelectorControlPropertyAvailableItems: - case kAudioSelectorControlPropertyItemName: - theAnswer = true; - break; - }; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_IsControlPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable) { - - // This method returns whether or not the given property on the object can have its value - // changed. - -#pragma unused(inClientProcessID) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_IsControlPropertySettable: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsControlPropertySettable: no address"); - FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_IsControlPropertySettable: no place to put the return value"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetControlPropertyData() method. - switch(inObjectID) { - case kObjectID_Volume_Input_Master: - case kObjectID_Volume_Output_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyOwnedObjects: - case kAudioControlPropertyScope: - case kAudioControlPropertyElement: - case kAudioLevelControlPropertyDecibelRange: - case kAudioLevelControlPropertyConvertScalarToDecibels: - case kAudioLevelControlPropertyConvertDecibelsToScalar: - *outIsSettable = false; - break; - - case kAudioLevelControlPropertyScalarValue: - case kAudioLevelControlPropertyDecibelValue: - *outIsSettable = true; - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - case kObjectID_Mute_Input_Master: - case kObjectID_Mute_Output_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyOwnedObjects: - case kAudioControlPropertyScope: - case kAudioControlPropertyElement: - *outIsSettable = false; - break; - - case kAudioBooleanControlPropertyValue: - *outIsSettable = true; - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - // case kObjectID_DataDestination_PlayThru_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - case kAudioObjectPropertyClass: - case kAudioObjectPropertyOwner: - case kAudioObjectPropertyOwnedObjects: - case kAudioControlPropertyScope: - case kAudioControlPropertyElement: - case kAudioSelectorControlPropertyAvailableItems: - case kAudioSelectorControlPropertyItemName: - *outIsSettable = false; - break; - - case kAudioSelectorControlPropertyCurrentItem: - *outIsSettable = true; - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - default: - theAnswer = kAudioHardwareBadObjectError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetControlPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize) { - - // This method returns the byte size of the property's data. - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetControlPropertyDataSize: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetControlPropertyDataSize: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetControlPropertyDataSize: no place to put the return value"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetControlPropertyData() method. - switch(inObjectID) { - case kObjectID_Volume_Input_Master: - case kObjectID_Volume_Output_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyOwnedObjects: - *outDataSize = 0 * sizeof(AudioObjectID); - break; - - case kAudioControlPropertyScope: - *outDataSize = sizeof(AudioObjectPropertyScope); - break; - - case kAudioControlPropertyElement: - *outDataSize = sizeof(AudioObjectPropertyElement); - break; - - case kAudioLevelControlPropertyScalarValue: - *outDataSize = sizeof(Float32); - break; - - case kAudioLevelControlPropertyDecibelValue: - *outDataSize = sizeof(Float32); - break; - - case kAudioLevelControlPropertyDecibelRange: - *outDataSize = sizeof(AudioValueRange); - break; - - case kAudioLevelControlPropertyConvertScalarToDecibels: - *outDataSize = sizeof(Float32); - break; - - case kAudioLevelControlPropertyConvertDecibelsToScalar: - *outDataSize = sizeof(Float32); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - case kObjectID_Mute_Input_Master: - case kObjectID_Mute_Output_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyOwnedObjects: - *outDataSize = 0 * sizeof(AudioObjectID); - break; - - case kAudioControlPropertyScope: - *outDataSize = sizeof(AudioObjectPropertyScope); - break; - - case kAudioControlPropertyElement: - *outDataSize = sizeof(AudioObjectPropertyElement); - break; - - case kAudioBooleanControlPropertyValue: - *outDataSize = sizeof(UInt32); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - // case kObjectID_DataDestination_PlayThru_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyOwnedObjects: - *outDataSize = 0 * sizeof(AudioObjectID); - break; - - case kAudioControlPropertyScope: - *outDataSize = sizeof(AudioObjectPropertyScope); - break; - - case kAudioControlPropertyElement: - *outDataSize = sizeof(AudioObjectPropertyElement); - break; - - case kAudioSelectorControlPropertyCurrentItem: - *outDataSize = sizeof(UInt32); - break; - - case kAudioSelectorControlPropertyAvailableItems: - *outDataSize = kDataSource_NumberItems * sizeof(UInt32); - break; - - case kAudioSelectorControlPropertyItemName: - *outDataSize = sizeof(CFStringRef); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - default: - theAnswer = kAudioHardwareBadObjectError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetControlPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData) { - -#pragma unused(inClientProcessID) - - // declare the local variables - OSStatus theAnswer = 0; - UInt32 theNumberItemsToFetch; - UInt32 theItemIndex; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetControlPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetControlPropertyData: no address"); - FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetControlPropertyData: no place to put the return value size"); - FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetControlPropertyData: no place to put the return value"); - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. - // - // Also, since most of the data that will get returned is static, there are few instances where - // it is necessary to lock the state mutex. - switch(inObjectID) { - case kObjectID_Volume_Input_Master: - case kObjectID_Volume_Output_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - // The base class for kAudioVolumeControlClassID is kAudioLevelControlClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the volume control"); - *((AudioClassID*)outData) = kAudioLevelControlClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - // Volume controls are of the class, kAudioVolumeControlClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the volume control"); - *((AudioClassID*)outData) = kAudioVolumeControlClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - // The control's owner is the device object - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the volume control"); - *((AudioObjectID*)outData) = kObjectID_Device; - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyOwnedObjects: - // Controls do not own any objects - *outDataSize = 0 * sizeof(AudioObjectID); - break; - - case kAudioControlPropertyScope: - // This property returns the scope that the control is attached to. - FailWithAction(inDataSize < sizeof(AudioObjectPropertyScope), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyScope for the volume control"); - *((AudioObjectPropertyScope*)outData) = (inObjectID == kObjectID_Volume_Input_Master) ? kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput; - *outDataSize = sizeof(AudioObjectPropertyScope); - break; - - case kAudioControlPropertyElement: - // This property returns the element that the control is attached to. - FailWithAction(inDataSize < sizeof(AudioObjectPropertyElement), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyElement for the volume control"); - *((AudioObjectPropertyElement*)outData) = kAudioObjectPropertyElementMaster; - *outDataSize = sizeof(AudioObjectPropertyElement); - break; - - case kAudioLevelControlPropertyScalarValue: - // This returns the value of the control in the normalized range of 0 to 1. - // Note that we need to take the state lock to examine the value. - FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyScalarValue for the volume control"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((Float32*)outData) = volumeToScalar((inObjectID == kObjectID_Volume_Input_Master) ? gVolume_Input_Master_Value : gVolume_Output_Master_Value); - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outDataSize = sizeof(Float32); - break; - - case kAudioLevelControlPropertyDecibelValue: - // This returns the dB value of the control. - // Note that we need to take the state lock to examine the value. - FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyDecibelValue for the volume control"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((Float32*)outData) = (inObjectID == kObjectID_Volume_Input_Master) ? gVolume_Input_Master_Value : gVolume_Output_Master_Value; - pthread_mutex_unlock(&gPlugIn_StateMutex); - - // Note that we square the scalar value before converting to dB so as to - // provide a better curve for the slider - // *((Float32*)outData) *= *((Float32*)outData); - // *((Float32*)outData) = kVolume_MinDB + (*((Float32*)outData) * (kVolume_MaxDB - kVolume_MinDB)); - - // eqMac converts straight to decibel - *((Float32*)outData) = volumeToDecibel(*((Float32*)outData)); - - // report how much we wrote - *outDataSize = sizeof(Float32); - break; - - case kAudioLevelControlPropertyDecibelRange: - // This returns the dB range of the control. - FailWithAction(inDataSize < sizeof(AudioValueRange), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyDecibelRange for the volume control"); - ((AudioValueRange*)outData)->mMinimum = kVolume_MinDB; - ((AudioValueRange*)outData)->mMaximum = kVolume_MaxDB; - *outDataSize = sizeof(AudioValueRange); - break; - - case kAudioLevelControlPropertyConvertScalarToDecibels: - // This takes the scalar value in outData and converts it to dB. - FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyDecibelValue for the volume control"); - - // clamp the value to be between 0 and 1 - if (*((Float32*)outData) < 0.0) { - *((Float32*)outData) = 0; - } - if (*((Float32*)outData) > 1.0) { - *((Float32*)outData) = 1.0; - } - - // Note that we square the scalar value before converting to dB so as to - // provide a better curve for the slider - *((Float32*)outData) *= *((Float32*)outData); - *((Float32*)outData) = kVolume_MinDB + (*((Float32*)outData) * (kVolume_MaxDB - kVolume_MinDB)); - - // report how much we wrote - *outDataSize = sizeof(Float32); - break; - - case kAudioLevelControlPropertyConvertDecibelsToScalar: - // This takes the dB value in outData and converts it to scalar. - FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyDecibelValue for the volume control"); - - // clamp the value to be between kVolume_MinDB and kVolume_MaxDB - if (*((Float32*)outData) < kVolume_MinDB) { - *((Float32*)outData) = kVolume_MinDB; - } - if (*((Float32*)outData) > kVolume_MaxDB) { - *((Float32*)outData) = kVolume_MaxDB; - } - - // Note that we square the scalar value before converting to dB so as to - // provide a better curve for the slider. We undo that here. - *((Float32*)outData) = *((Float32*)outData) - kVolume_MinDB; - *((Float32*)outData) /= kVolume_MaxDB - kVolume_MinDB; - *((Float32*)outData) = sqrtf(*((Float32*)outData)); - - // report how much we wrote - *outDataSize = sizeof(Float32); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - case kObjectID_Mute_Input_Master: - case kObjectID_Mute_Output_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - // The base class for kAudioMuteControlClassID is kAudioBooleanControlClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the mute control"); - *((AudioClassID*)outData) = kAudioBooleanControlClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - // Mute controls are of the class, kAudioMuteControlClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the mute control"); - *((AudioClassID*)outData) = kAudioMuteControlClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - // The control's owner is the device object - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the mute control"); - *((AudioObjectID*)outData) = kObjectID_Device; - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyOwnedObjects: - // Controls do not own any objects - *outDataSize = 0 * sizeof(AudioObjectID); - break; - - case kAudioControlPropertyScope: - // This property returns the scope that the control is attached to. - FailWithAction(inDataSize < sizeof(AudioObjectPropertyScope), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyScope for the mute control"); - *((AudioObjectPropertyScope*)outData) = (inObjectID == kObjectID_Mute_Input_Master) ? kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput; - *outDataSize = sizeof(AudioObjectPropertyScope); - break; - - case kAudioControlPropertyElement: - // This property returns the element that the control is attached to. - FailWithAction(inDataSize < sizeof(AudioObjectPropertyElement), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyElement for the mute control"); - *((AudioObjectPropertyElement*)outData) = kAudioObjectPropertyElementMaster; - *outDataSize = sizeof(AudioObjectPropertyElement); - break; - - case kAudioBooleanControlPropertyValue: - // This returns the value of the mute control where 0 means that mute is off - // and audio can be heard and 1 means that mute is on and audio cannot be heard. - // Note that we need to take the state lock to examine this value. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioBooleanControlPropertyValue for the mute control"); - pthread_mutex_lock(&gPlugIn_StateMutex); - *((UInt32*)outData) = (inObjectID == kObjectID_Mute_Input_Master) ? (gMute_Input_Master_Value ? 1 : 0) : (gMute_Output_Master_Value ? 1 : 0); - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outDataSize = sizeof(UInt32); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - // case kObjectID_DataDestination_PlayThru_Master: - switch(inAddress->mSelector) { - case kAudioObjectPropertyBaseClass: - // The base class for kAudioDataSourceControlClassID is kAudioSelectorControlClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the data source control"); - *((AudioClassID*)outData) = kAudioSelectorControlClassID; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyClass: - // Data Source controls are of the class, kAudioDataSourceControlClassID - FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the data source control"); - *((AudioClassID*)outData) = kAudioDataSourceControlClassID; - // switch(inObjectID) - // { - // case kObjectID_DataSource_Input_Master: - // case kObjectID_DataSource_Output_Master: - // *((AudioClassID*)outData) = kAudioDataSourceControlClassID; - // break; - // - // case kObjectID_DataDestination_PlayThru_Master: - // *((AudioClassID*)outData) = kAudioDataDestinationControlClassID; - // break; - // - // }; - *outDataSize = sizeof(AudioClassID); - break; - - case kAudioObjectPropertyOwner: - // The control's owner is the device object - FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the data source control"); - *((AudioObjectID*)outData) = kObjectID_Device; - *outDataSize = sizeof(AudioObjectID); - break; - - case kAudioObjectPropertyOwnedObjects: - // Controls do not own any objects - *outDataSize = 0 * sizeof(AudioObjectID); - break; - - case kAudioControlPropertyScope: - // This property returns the scope that the control is attached to. - FailWithAction(inDataSize < sizeof(AudioObjectPropertyScope), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyScope for the data source control"); - switch(inObjectID) { - case kObjectID_DataSource_Input_Master: - *((AudioObjectPropertyScope*)outData) = kAudioObjectPropertyScopeInput; - break; - - case kObjectID_DataSource_Output_Master: - *((AudioObjectPropertyScope*)outData) = kAudioObjectPropertyScopeOutput; - break; - - // case kObjectID_DataDestination_PlayThru_Master: - // *((AudioObjectPropertyScope*)outData) = kAudioObjectPropertyScopePlayThrough; - // break; - - }; - *outDataSize = sizeof(AudioObjectPropertyScope); - break; - - case kAudioControlPropertyElement: - // This property returns the element that the control is attached to. - FailWithAction(inDataSize < sizeof(AudioObjectPropertyElement), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyElement for the data source control"); - *((AudioObjectPropertyElement*)outData) = kAudioObjectPropertyElementMaster; - *outDataSize = sizeof(AudioObjectPropertyElement); - break; - - case kAudioSelectorControlPropertyCurrentItem: - // This returns the value of the data source selector. - // Note that we need to take the state lock to examine this value. - FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioSelectorControlPropertyCurrentItem for the data source control"); - pthread_mutex_lock(&gPlugIn_StateMutex); - switch(inObjectID) { - case kObjectID_DataSource_Input_Master: - *((UInt32*)outData) = gDataSource_Input_Master_Value; - break; - - case kObjectID_DataSource_Output_Master: - *((UInt32*)outData) = gDataSource_Output_Master_Value; - break; - - // case kObjectID_DataDestination_PlayThru_Master: - // *((UInt32*)outData) = gDataDestination_PlayThru_Master_Value; - // break; - - }; - pthread_mutex_unlock(&gPlugIn_StateMutex); - *outDataSize = sizeof(UInt32); - break; - - case kAudioSelectorControlPropertyAvailableItems: - // This returns the IDs for all the items the data source control supports. - - // Calculate the number of items that have been requested. Note that this - // number is allowed to be smaller than the actual size of the list. In such - // case, only that number of items will be returned - theNumberItemsToFetch = inDataSize / sizeof(UInt32); - - // clamp it to the number of items we have - if (theNumberItemsToFetch > kDataSource_NumberItems) { - theNumberItemsToFetch = kDataSource_NumberItems; - } - - // fill out the return array - for (theItemIndex = 0; theItemIndex < theNumberItemsToFetch; ++theItemIndex) { - ((UInt32*)outData)[theItemIndex] = theItemIndex; - } - - // report how much we wrote - *outDataSize = theNumberItemsToFetch * sizeof(UInt32); - break; - - case kAudioSelectorControlPropertyItemName: - // This returns the user-readable name for the selector item in the qualifier - FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: not enough space for the return value of kAudioSelectorControlPropertyItemName for the data source control"); - FailWithAction(inQualifierDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_GetControlPropertyData: wrong size for the qualifier of kAudioSelectorControlPropertyItemName for the data source control"); - FailWithAction(*((const UInt32*)inQualifierData) >= kDataSource_NumberItems, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_GetControlPropertyData: the item in the qualifier is not valid for kAudioSelectorControlPropertyItemName for the data source control"); - *((CFStringRef*)outData) = CFStringCreateWithFormat(NULL, NULL, CFSTR(kDataSource_ItemNamePattern), *((const UInt32*)inQualifierData)); - *outDataSize = sizeof(CFStringRef); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - default: - theAnswer = kAudioHardwareBadObjectError; - break; - }; - -Done: - return theAnswer; -} - -static OSStatus eqMac_SetControlPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]) { - -#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData) - - // declare the local variables - OSStatus theAnswer = 0; - Float32 theNewVolume; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_SetControlPropertyData: bad driver reference"); - FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetControlPropertyData: no address"); - FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetControlPropertyData: no place to return the number of properties that changed"); - FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetControlPropertyData: no place to return the properties that changed"); - - // initialize the returned number of changed properties - *outNumberPropertiesChanged = 0; - - // Note that for each object, this driver implements all the required properties plus a few - // extras that are useful but not required. There is more detailed commentary about each - // property in the eqMac_GetControlPropertyData() method. - switch(inObjectID) { - case kObjectID_Volume_Input_Master: - case kObjectID_Volume_Output_Master: - switch(inAddress->mSelector) { - case kAudioLevelControlPropertyScalarValue: - // For the scalar volume, we clamp the new value to [0, 1]. Note that if this - // value changes, it implies that the dB value changed too. - FailWithAction(inDataSize != sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetControlPropertyData: wrong size for the data for kAudioLevelControlPropertyScalarValue"); - theNewVolume = scalarToVolume(*((const Float32*)inData)); - if (theNewVolume < 0.0) { - theNewVolume = 0.0; - } else if (theNewVolume > 1.0) { - theNewVolume = 1.0; - } - pthread_mutex_lock(&gPlugIn_StateMutex); - if (inObjectID == kObjectID_Volume_Input_Master) { - if (gVolume_Input_Master_Value != theNewVolume) { - gVolume_Input_Master_Value = theNewVolume; - *outNumberPropertiesChanged = 2; - outChangedAddresses[0].mSelector = kAudioLevelControlPropertyScalarValue; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - outChangedAddresses[1].mSelector = kAudioLevelControlPropertyDecibelValue; - outChangedAddresses[1].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[1].mElement = kAudioObjectPropertyElementMaster; - } - } else { - if (gVolume_Output_Master_Value != theNewVolume) { - gVolume_Output_Master_Value = theNewVolume; - *outNumberPropertiesChanged = 2; - outChangedAddresses[0].mSelector = kAudioLevelControlPropertyScalarValue; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - outChangedAddresses[1].mSelector = kAudioLevelControlPropertyDecibelValue; - outChangedAddresses[1].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[1].mElement = kAudioObjectPropertyElementMaster; - } - } - pthread_mutex_unlock(&gPlugIn_StateMutex); - break; - - case kAudioLevelControlPropertyDecibelValue: - // For the dB value, we first convert it to a scalar value since that is how - // the value is tracked. Note that if this value changes, it implies that the - // scalar value changes as well. - FailWithAction(inDataSize != sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetControlPropertyData: wrong size for the data for kAudioLevelControlPropertyScalarValue"); - theNewVolume = *((const Float32*)inData); - if (theNewVolume < kVolume_MinDB) { - theNewVolume = kVolume_MinDB; - } else if (theNewVolume > kVolume_MaxDB) { - theNewVolume = kVolume_MaxDB; - } - theNewVolume = decibelToVolume(theNewVolume); - pthread_mutex_lock(&gPlugIn_StateMutex); - if (inObjectID == kObjectID_Volume_Input_Master) { - if (gVolume_Input_Master_Value != theNewVolume) { - gVolume_Input_Master_Value = theNewVolume; - *outNumberPropertiesChanged = 2; - outChangedAddresses[0].mSelector = gVolume_Output_Master_Value; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - outChangedAddresses[1].mSelector = kAudioLevelControlPropertyDecibelValue; - outChangedAddresses[1].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[1].mElement = kAudioObjectPropertyElementMaster; - } - } else { - if (gVolume_Output_Master_Value != theNewVolume) { - gVolume_Output_Master_Value = theNewVolume; - *outNumberPropertiesChanged = 2; - outChangedAddresses[0].mSelector = kAudioLevelControlPropertyScalarValue; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - outChangedAddresses[1].mSelector = kAudioLevelControlPropertyDecibelValue; - outChangedAddresses[1].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[1].mElement = kAudioObjectPropertyElementMaster; - } - } - pthread_mutex_unlock(&gPlugIn_StateMutex); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - case kObjectID_Mute_Input_Master: - case kObjectID_Mute_Output_Master: - switch(inAddress->mSelector) { - case kAudioBooleanControlPropertyValue: - FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetControlPropertyData: wrong size for the data for kAudioBooleanControlPropertyValue"); - pthread_mutex_lock(&gPlugIn_StateMutex); - if (inObjectID == kObjectID_Mute_Input_Master) { - if (gMute_Input_Master_Value != (*((const UInt32*)inData) != 0)) { - gMute_Input_Master_Value = *((const UInt32*)inData) != 0; - *outNumberPropertiesChanged = 1; - outChangedAddresses[0].mSelector = kAudioBooleanControlPropertyValue; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - } - } else { - if (gMute_Output_Master_Value != (*((const UInt32*)inData) != 0)) { - gMute_Output_Master_Value = *((const UInt32*)inData) != 0; - *outNumberPropertiesChanged = 1; - outChangedAddresses[0].mSelector = kAudioBooleanControlPropertyValue; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - } - } - pthread_mutex_unlock(&gPlugIn_StateMutex); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - case kObjectID_DataSource_Input_Master: - case kObjectID_DataSource_Output_Master: - // case kObjectID_DataDestination_PlayThru_Master: - switch(inAddress->mSelector) { - case kAudioSelectorControlPropertyCurrentItem: - // For selector controls, we check to make sure the requested value is in the - // available items list and just store the value. - FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "eqMac_SetControlPropertyData: wrong size for the data for kAudioSelectorControlPropertyCurrentItem"); - FailWithAction(*((const UInt32*)inData) >= kDataSource_NumberItems, theAnswer = kAudioHardwareIllegalOperationError, Done, "eqMac_SetControlPropertyData: requested item not in available items list for kAudioSelectorControlPropertyCurrentItem"); - pthread_mutex_lock(&gPlugIn_StateMutex); - switch(inObjectID) { - case kObjectID_DataSource_Input_Master:{ - if (gDataSource_Input_Master_Value != *((const UInt32*)inData)) { - gDataSource_Input_Master_Value = *((const UInt32*)inData); - *outNumberPropertiesChanged = 1; - outChangedAddresses[0].mSelector = kAudioSelectorControlPropertyCurrentItem; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - } - } - break; - - case kObjectID_DataSource_Output_Master:{ - if (gDataSource_Output_Master_Value != *((const UInt32*)inData)) { - gDataSource_Output_Master_Value = *((const UInt32*)inData); - *outNumberPropertiesChanged = 1; - outChangedAddresses[0].mSelector = kAudioSelectorControlPropertyCurrentItem; - outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - } - } - break; - - // case kObjectID_DataDestination_PlayThru_Master: - // { - // if (gDataDestination_PlayThru_Master_Value != *((const UInt32*)inData)) - // { - // gDataDestination_PlayThru_Master_Value = *((const UInt32*)inData); - // *outNumberPropertiesChanged = 1; - // outChangedAddresses[0].mSelector = kAudioSelectorControlPropertyCurrentItem; - // outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal; - // outChangedAddresses[0].mElement = kAudioObjectPropertyElementMaster; - // } - // } - // break; - }; - pthread_mutex_unlock(&gPlugIn_StateMutex); - break; - - default: - theAnswer = kAudioHardwareUnknownPropertyError; - break; - }; - break; - - default: - theAnswer = kAudioHardwareBadObjectError; - break; - }; - -Done: - return theAnswer; -} - -#pragma mark IO Operations - -static OSStatus eqMac_StartIO (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID) { - - // This call tells the device that IO is starting for the given client. When this routine - // returns, the device's clock is running and it is ready to have data read/written. It is - // important to note that multiple clients can have IO running on the device at the same time. - // So, work only needs to be done when the first client starts. All subsequent starts simply - // increment the counter. - -#pragma unused(inClientID) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_StartIO: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_StartIO: bad device ID"); - - // we need to hold the state lock - pthread_mutex_lock(&gPlugIn_StateMutex); - - // figure out what we need to do - if (gDevice_IOIsRunning == UINT64_MAX) { - // overflowing is an error - theAnswer = kAudioHardwareIllegalOperationError; - } else if (gDevice_IOIsRunning == 0) { - // We need to start the hardware, which in this case is just anchoring the time line. - gDevice_IOIsRunning = 1; - gDevice_NumberTimeStamps = 0; - gDevice_AnchorSampleTime = 0; - gDevice_AnchorHostTime = mach_absolute_time(); - buffer = calloc(kBufferSize * kChannelCount, sizeof(Float32)); - } else { - // IO is already running, so just bump the counter - ++gDevice_IOIsRunning; - } - - // unlock the state lock - pthread_mutex_unlock(&gPlugIn_StateMutex); - -Done: - return theAnswer; -} - -static OSStatus eqMac_StopIO (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID) { - - // This call tells the device that the client has stopped IO. The driver can stop the hardware - // once all clients have stopped. - -#pragma unused(inClientID) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_StopIO: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_StopIO: bad device ID"); - - // we need to hold the state lock - pthread_mutex_lock(&gPlugIn_StateMutex); - - // figure out what we need to do - if (gDevice_IOIsRunning == 0) { - // underflowing is an error - theAnswer = kAudioHardwareIllegalOperationError; - } else if (gDevice_IOIsRunning == 1) { - // We need to stop the hardware, which in this case means that there's nothing to do. - gDevice_IOIsRunning = 0; - free(buffer); - } else { - // IO is still running, so just bump the counter - --gDevice_IOIsRunning; - } - - // unlock the state lock - pthread_mutex_unlock(&gPlugIn_StateMutex); - -Done: - return theAnswer; -} - -static OSStatus eqMac_GetZeroTimeStamp (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, Float64* outSampleTime, UInt64* outHostTime, UInt64* outSeed) { - - // This method returns the current zero time stamp for the device. The HAL models the timing of - // a device as a series of time stamps that relate the sample time to a host time. The zero - // time stamps are spaced such that the sample times are the value of - // kAudioDevicePropertyZeroTimeStampPeriod apart. This is often modeled using a ring buffer - // where the zero time stamp is updated when wrapping around the ring buffer. - // - // For this device, the zero time stamps' sample time increments every kDevice_RingBufferSize - // frames and the host time increments by kDevice_RingBufferSize * gDevice_HostTicksPerFrame. - -#pragma unused(inClientID) - - // declare the local variables - OSStatus theAnswer = 0; - UInt64 theCurrentHostTime; - Float64 theHostTicksPerRingBuffer; - Float64 theHostTickOffset; - UInt64 theNextHostTime; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetZeroTimeStamp: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_GetZeroTimeStamp: bad device ID"); - - // we need to hold the locks - pthread_mutex_lock(&gDevice_IOMutex); - - // get the current host time - theCurrentHostTime = mach_absolute_time(); - - // calculate the next host time - theHostTicksPerRingBuffer = gDevice_HostTicksPerFrame * ((Float64)kDevice_RingBufferSize); - theHostTickOffset = ((Float64)(gDevice_NumberTimeStamps + 1)) * theHostTicksPerRingBuffer; - theNextHostTime = gDevice_AnchorHostTime + ((UInt64)theHostTickOffset); - - // go to the next time if the next host time is less than the current time - if (theNextHostTime <= theCurrentHostTime) { - ++gDevice_NumberTimeStamps; - } - - // set the return values - *outSampleTime = gDevice_NumberTimeStamps * kDevice_RingBufferSize; - *outHostTime = gDevice_AnchorHostTime + (((Float64)gDevice_NumberTimeStamps) * theHostTicksPerRingBuffer); - *outSeed = 1; - - // unlock the state lock - pthread_mutex_unlock(&gDevice_IOMutex); - -Done: - return theAnswer; -} - -static OSStatus eqMac_WillDoIOOperation (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, Boolean* outWillDo, Boolean* outWillDoInPlace) { - - // 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. - -#pragma unused(inClientID) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_WillDoIOOperation: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_WillDoIOOperation: bad device ID"); - - // figure out if we support the operation - bool willDo = false; - bool willDoInPlace = true; - switch(inOperationID) { - case kAudioServerPlugInIOOperationReadInput: - willDo = true; - willDoInPlace = true; - break; - - case kAudioServerPlugInIOOperationWriteMix: - willDo = true; - willDoInPlace = true; - break; - - }; - - // fill out the return values - if (outWillDo != NULL) { - *outWillDo = willDo; - } - if (outWillDoInPlace != NULL) { - *outWillDoInPlace = willDoInPlace; - } - -Done: - return theAnswer; -} - -static OSStatus eqMac_BeginIOOperation (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo) { - - // This is called at the beginning of an IO operation. This device doesn't do anything, so just - // check the arguments and return. - -#pragma unused(inClientID, inOperationID, inIOBufferFrameSize, inIOCycleInfo) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_BeginIOOperation: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_BeginIOOperation: bad device ID"); - -Done: - return theAnswer; -} - -static OSStatus eqMac_DoIOOperation (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, AudioObjectID inStreamObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo, void* ioMainBuffer, void* ioSecondaryBuffer) { - - // This is called to actuall perform a given operation. For this device, all we need to do is - // clear the buffer for the ReadInput operation. - -#pragma unused(inClientID, inIOCycleInfo, ioSecondaryBuffer) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_DoIOOperation: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_DoIOOperation: bad device ID"); - FailWithAction((inStreamObjectID != kObjectID_Stream_Input) && (inStreamObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_DoIOOperation: bad stream ID"); - - // Lock - pthread_mutex_lock(&gDevice_IOMutex); - - // Store - if (inOperationID == kAudioServerPlugInIOOperationWriteMix) { - Float32* sample = (Float32*)ioMainBuffer; - UInt64 sampleTime = inIOCycleInfo->mOutputTime.mSampleTime; - - for (UInt32 frame = 0; frame < inIOBufferFrameSize; frame++) { - for (int channel = 0; channel < kChannelCount; channel++) { - - UInt64 readFrame = frame * kChannelCount + channel; - if (gMute_Output_Master_Value) { - // Muted - sample[readFrame] = 0; - } else { - - UInt64 writeFrame = ((sampleTime + frame) % kDevice_RingBufferSize) * kChannelCount + channel; - buffer[writeFrame] += sample[readFrame]; // Store full volume data - } - - // Clean up buffer - UInt64 cleanFrame = ((sampleTime + frame + 8192) % kDevice_RingBufferSize) * kChannelCount + channel; - buffer[cleanFrame] = 0; - } - - } - - // Make output buffer silent - memset(ioMainBuffer, 0, inIOBufferFrameSize * kChannelCount * sizeof(Float32)); - } - - // Read - if (inOperationID == kAudioServerPlugInIOOperationReadInput) { - - Float32* sample = (Float32*)ioMainBuffer; - UInt64 sampleTime = inIOCycleInfo->mInputTime.mSampleTime; - - for (UInt32 frame = 0; frame < inIOBufferFrameSize; frame++) { - for (int channel = 0; channel < kChannelCount; channel++) { - - UInt64 writeFrame = frame * kChannelCount + channel; - if (gMute_Output_Master_Value) { - // Mute - sample[writeFrame] = 0; - } else { - UInt64 readFrame = ((sampleTime + frame) % kDevice_RingBufferSize) * kChannelCount + channel; - sample[writeFrame] = buffer[readFrame]; - } - - // Clean up buffer - UInt64 cleanFrame = ((sampleTime + frame - 16384) % kDevice_RingBufferSize) * kChannelCount + channel; - buffer[cleanFrame] = 0; - } - } - } - - // Unlock - pthread_mutex_unlock(&gDevice_IOMutex); - -Done: - return theAnswer; -} - -static OSStatus eqMac_EndIOOperation (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo) { - - // This is called at the end of an IO operation. This device doesn't do anything, so just check - // the arguments and return. - -#pragma unused(inClientID, inOperationID, inIOBufferFrameSize, inIOCycleInfo) - - // declare the local variables - OSStatus theAnswer = 0; - - // check the arguments - FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_EndIOOperation: bad driver reference"); - FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "eqMac_EndIOOperation: bad device ID"); - -Done: - return theAnswer; -} diff --git a/native/driver/Source/eqMac.h b/native/driver/Source/eqMac.h deleted file mode 100644 index 5a62a28..0000000 --- a/native/driver/Source/eqMac.h +++ /dev/null @@ -1,277 +0,0 @@ -// -// eqMac.h -// eqMac Driver -// -// Created by Nodeful on 09/07/2021. -// Copyright © 2021 Apple. All rights reserved. -// - -#ifndef eqMac_h -#define eqMac_h - -#endif /* eqMac_h */ - -#include -#include -#include -#include -#include -#include - -//================================================================================================== -#pragma mark - -#pragma mark Macros -//================================================================================================== - -#if TARGET_RT_BIG_ENDIAN -#define FourCCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 } -#else -#define FourCCToCString(the4CC) { ((char*)&the4CC)[3], ((char*)&the4CC)[2], ((char*)&the4CC)[1], ((char*)&the4CC)[0], 0 } -#endif - -#if DEBUG - -#define DebugMsg(inFormat, ...) printf(inFormat "\n", ## __VA_ARGS__) - -#define FailIf(inCondition, inHandler, inMessage) \ -if (inCondition) { \ -DebugMsg(inMessage); \ -goto inHandler; \ -} - -#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ -if (inCondition) { \ -DebugMsg(inMessage); \ -{ inAction; } \ -goto inHandler; \ -} - -#else - -#define DebugMsg(inFormat, ...) - -#define FailIf(inCondition, inHandler, inMessage) \ -if (inCondition) { \ -goto inHandler; \ -} - -#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ -if (inCondition) { \ -{ inAction; } \ -goto inHandler; \ -} - -#endif - -//================================================================================================== -#pragma mark - -#pragma mark eqMac State -//================================================================================================== - -// The purpose of the eqMac sample is to provide a bare bones implementations to -// illustrate the minimal set of things a driver has to do. The sample driver has the following -// qualities: -// - a plug-in -// - custom property with the selector kPlugIn_CustomPropertyID = 'PCst' -// - a box -// - a device -// - supports 44100 and 48000 sample rates -// - provides a rate scalar of 1.0 via hard coding -// - a single input stream -// - supports 2 channels of 32 bit float LPCM samples -// - always produces zeros -// - a single output stream -// - supports 2 channels of 32 bit float LPCM samples -// - data written to it is ignored -// - controls -// - master input volume -// - master output volume -// - master input mute -// - master output mute -// - master input data source -// - master output data source -// - master play-through data destination -// - all are for illustration purposes only and do not actually manipulate data - - -// Declare the internal object ID numbers for all the objects this driver implements. Note that -// this driver has a fixed set of objects that never grows or shrinks. If this were not the case, -// the driver would need to have a means to dynamically allocate these IDs. It's important to -// realize that a lot of the structure of this driver is vastly simpler when the IDs are all -// known a priori. Comments in the code will try to identify some of these simplifications and -// point out what a more complicated driver will need to do. -enum { - kObjectID_PlugIn = kAudioObjectPlugInObject, - kObjectID_Box = 2, - kObjectID_Device = 3, - kObjectID_Stream_Input = 4, - kObjectID_Volume_Input_Master = 5, - kObjectID_Mute_Input_Master = 6, - kObjectID_DataSource_Input_Master = 7, - kObjectID_Stream_Output = 8, - kObjectID_Volume_Output_Master = 9, - kObjectID_Mute_Output_Master = 10, - kObjectID_DataSource_Output_Master = 11, - // kObjectID_DataDestination_PlayThru_Master = 12 -}; - - -// Custom Properties -enum { - kAudioDeviceCustomPropertyLatency = 'cltc', - kAudioDeviceCustomPropertySafetyOffset = 'csfo', - kAudioDeviceCustomPropertyShown = 'shwn', - kAudioDeviceCustomPropertyVersion = 'vrsn' -}; - - -// Declare the stuff that tracks the state of the plug-in, the device and its sub-objects. -// Note that we use global variables here because this driver only ever has a single device. If -// multiple devices were supported, this state would need to be encapsulated in one or more structs -// so that each object's state can be tracked individually. -// Note also that we share a single mutex across all objects to be thread safe for the same reason. - -#define kChannelCount 2 -#define kBitsPerChannel 32 -#define kBytesPerChannel (kBitsPerChannel / 8) -#define kBytesPerFrame (kChannelCount * kBytesPerChannel) -#define kDevice_Name "eqMac" -#define kDevice_Manufacturer "Bitgapp Ltd" - -static Float32* buffer; -#define kBufferSize (65536 * kChannelCount) - -#define kPlugIn_BundleID "com.bitgapp.eqmac.driver" -static pthread_mutex_t gPlugIn_StateMutex = PTHREAD_MUTEX_INITIALIZER; -static UInt32 gPlugIn_RefCount = 0; -static AudioServerPlugInHostRef gPlugIn_Host = NULL; -static const AudioObjectPropertySelector kPlugIn_CustomPropertyID = 'PCst'; - -#define kBox_UID "eqMacBox_UID" -static CFStringRef gBox_Name = NULL; -static Boolean gBox_Acquired = true; - -#define kDevice_UID "EQMDevice" -#define kDevice_ModelUID "EQMDeviceModelUID" -static pthread_mutex_t gDevice_IOMutex = PTHREAD_MUTEX_INITIALIZER; -static Float64 gDevice_SampleRate = 44100.0; -static UInt64 gDevice_IOIsRunning = 0; -static const UInt32 kDevice_RingBufferSize = 16384; -static Float64 gDevice_HostTicksPerFrame = 0.0; -static UInt64 gDevice_NumberTimeStamps = 0; -static Float64 gDevice_AnchorSampleTime = 0.0; -static UInt64 gDevice_AnchorHostTime = 0; - -static bool gStream_Input_IsActive = true; -static bool gStream_Output_IsActive = true; - -static const Float32 kVolume_MinDB = -96.0; -static const Float32 kVolume_MaxDB = 0.0; -static Float32 gVolume_Input_Master_Value = 1.0; -static Float32 gVolume_Output_Master_Value = 1.0; - -static bool gMute_Input_Master_Value = false; -static bool gMute_Output_Master_Value = false; - -static const UInt32 kDataSource_NumberItems = 1; -#define kDataSource_ItemNamePattern kDevice_Name -static UInt32 gDataSource_Input_Master_Value = 0; -static UInt32 gDataSource_Output_Master_Value = 0; -//static UInt32 gDataDestination_PlayThru_Master_Value = 0; - -static UInt32 mShown = 0; -static UInt32 mSafetyOffset = 0; -static UInt32 mLatency = 0; -# -//================================================================================================== -#pragma mark - -#pragma mark AudioServerPlugInDriverInterface Implementation -//================================================================================================== - -#pragma mark Prototypes - -// Entry points for the COM methods -void* eqMac_Create (CFAllocatorRef inAllocator, CFUUIDRef inRequestedTypeUUID); -static HRESULT eqMac_QueryInterface (void* inDriver, REFIID inUUID, LPVOID* outInterface); -static ULONG eqMac_AddRef (void* inDriver); -static ULONG eqMac_Release (void* inDriver); -static OSStatus eqMac_Initialize (AudioServerPlugInDriverRef inDriver, AudioServerPlugInHostRef inHost); -static OSStatus eqMac_CreateDevice (AudioServerPlugInDriverRef inDriver, CFDictionaryRef inDescription, const AudioServerPlugInClientInfo* inClientInfo, AudioObjectID* outDeviceObjectID); -static OSStatus eqMac_DestroyDevice (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID); -static OSStatus eqMac_AddDeviceClient (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo* inClientInfo); -static OSStatus eqMac_RemoveDeviceClient (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo* inClientInfo); -static OSStatus eqMac_PerformDeviceConfigurationChange (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void* inChangeInfo); -static OSStatus eqMac_AbortDeviceConfigurationChange (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void* inChangeInfo); -static Boolean eqMac_HasProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress); -static OSStatus eqMac_IsPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable); -static OSStatus eqMac_GetPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize); -static OSStatus eqMac_GetPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData); -static OSStatus eqMac_SetPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData); -static OSStatus eqMac_StartIO (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID); -static OSStatus eqMac_StopIO (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID); -static OSStatus eqMac_GetZeroTimeStamp (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, Float64* outSampleTime, UInt64* outHostTime, UInt64* outSeed); -static OSStatus eqMac_WillDoIOOperation (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, Boolean* outWillDo, Boolean* outWillDoInPlace); -static OSStatus eqMac_BeginIOOperation (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo); -static OSStatus eqMac_DoIOOperation (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, AudioObjectID inStreamObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo, void* ioMainBuffer, void* ioSecondaryBuffer); -static OSStatus eqMac_EndIOOperation (AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo); - -// Implementation -static Boolean eqMac_HasPlugInProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress); -static OSStatus eqMac_IsPlugInPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable); -static OSStatus eqMac_GetPlugInPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize); -static OSStatus eqMac_GetPlugInPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData); -static OSStatus eqMac_SetPlugInPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]); - -static Boolean eqMac_HasBoxProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress); -static OSStatus eqMac_IsBoxPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable); -static OSStatus eqMac_GetBoxPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize); -static OSStatus eqMac_GetBoxPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData); -static OSStatus eqMac_SetBoxPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]); - -static Boolean eqMac_HasDeviceProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress); -static OSStatus eqMac_IsDevicePropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable); -static OSStatus eqMac_GetDevicePropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize); -static OSStatus eqMac_GetDevicePropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData); -static OSStatus eqMac_SetDevicePropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]); - -static Boolean eqMac_HasStreamProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress); -static OSStatus eqMac_IsStreamPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable); -static OSStatus eqMac_GetStreamPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize); -static OSStatus eqMac_GetStreamPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData); -static OSStatus eqMac_SetStreamPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]); - -static Boolean eqMac_HasControlProperty (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress); -static OSStatus eqMac_IsControlPropertySettable (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable); -static OSStatus eqMac_GetControlPropertyDataSize (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize); -static OSStatus eqMac_GetControlPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData); -static OSStatus eqMac_SetControlPropertyData (AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData, UInt32* outNumberPropertiesChanged, AudioObjectPropertyAddress outChangedAddresses[2]); - -#pragma mark The Interface - -static AudioServerPlugInDriverInterface gAudioServerPlugInDriverInterface = { - NULL, - eqMac_QueryInterface, - eqMac_AddRef, - eqMac_Release, - eqMac_Initialize, - eqMac_CreateDevice, - eqMac_DestroyDevice, - eqMac_AddDeviceClient, - eqMac_RemoveDeviceClient, - eqMac_PerformDeviceConfigurationChange, - eqMac_AbortDeviceConfigurationChange, - eqMac_HasProperty, - eqMac_IsPropertySettable, - eqMac_GetPropertyDataSize, - eqMac_GetPropertyData, - eqMac_SetPropertyData, - eqMac_StartIO, - eqMac_StopIO, - eqMac_GetZeroTimeStamp, - eqMac_WillDoIOOperation, - eqMac_BeginIOOperation, - eqMac_DoIOOperation, - eqMac_EndIOOperation -}; -static AudioServerPlugInDriverInterface* gAudioServerPlugInDriverInterfacePtr = &gAudioServerPlugInDriverInterface; -static AudioServerPlugInDriverRef gAudioServerPlugInDriverRef = &gAudioServerPlugInDriverInterfacePtr; diff --git a/native/driver/Source/eqMac.swift b/native/driver/Source/eqMac.swift new file mode 100644 index 0000000..a0d46fc --- /dev/null +++ b/native/driver/Source/eqMac.swift @@ -0,0 +1,20 @@ +// +// eqMac.swift +// eqMac +// +// Created by Nodeful on 12/08/2021. +// Copyright © 2021 Bitgapp. All rights reserved. +// + +import Foundation +import CoreAudio.AudioServerPlugIn + +@objc +class eqMac: NSObject { + + @objc + static func create (allocator: CFAllocator!, requestedTypeUUID: CFUUID!) -> UnsafeMutablePointer? { + return nil + } + +}