hydra

Terminal replacement for Loopback — virtual audio devices and routing on macOS, from a ratatui TUI.
Log | Files | Refs | README | LICENSE

BlackHole.c (216363B)


      1 /*
      2      File: BlackHole.c
      3   
      4  Copyright (C) 2019 Existential Audio Inc.
      5   
      6 */
      7 /*==================================================================================================
      8 	BlackHole.c
      9 ==================================================================================================*/
     10 
     11 //==================================================================================================
     12 //	Includes
     13 //==================================================================================================
     14 
     15 #include <CoreAudio/AudioServerPlugIn.h>
     16 #include <dispatch/dispatch.h>
     17 #include <mach/mach_time.h>
     18 #include <pthread.h>
     19 #include <stdint.h>
     20 #include <sys/syslog.h>
     21 #include <Accelerate/Accelerate.h>
     22 #include <Availability.h>
     23 
     24 //==================================================================================================
     25 #pragma mark -
     26 #pragma mark Macros
     27 //==================================================================================================
     28 
     29 #if TARGET_RT_BIG_ENDIAN
     30 #define    FourCCToCString(the4CC)    { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 }
     31 #else
     32 #define    FourCCToCString(the4CC)    { ((char*)&the4CC)[3], ((char*)&the4CC)[2], ((char*)&the4CC)[1], ((char*)&the4CC)[0], 0 }
     33 #endif
     34 
     35 #ifndef __MAC_12_0
     36 #define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster
     37 #endif
     38 
     39 #if DEBUG
     40 
     41     #define    DebugMsg(inFormat, ...)    syslog(LOG_NOTICE, inFormat, ## __VA_ARGS__)
     42 
     43     #define    FailIf(inCondition, inHandler, inMessage)                           \
     44     if(inCondition)                                                                \
     45     {                                                                              \
     46         DebugMsg(inMessage);                                                       \
     47         goto inHandler;                                                            \
     48     }
     49 
     50     #define    FailWithAction(inCondition, inAction, inHandler, inMessage)         \
     51     if(inCondition)                                                                \
     52     {                                                                              \
     53         DebugMsg(inMessage);                                                       \
     54         { inAction; }                                                              \
     55         goto inHandler;                                                            \
     56         }
     57 
     58 #else
     59 
     60     #define    DebugMsg(inFormat, ...)
     61 
     62     #define    FailIf(inCondition, inHandler, inMessage)                           \
     63     if(inCondition)                                                                \
     64     {                                                                              \
     65     goto inHandler;                                                                \
     66     }
     67 
     68     #define    FailWithAction(inCondition, inAction, inHandler, inMessage)         \
     69     if(inCondition)                                                                \
     70     {                                                                              \
     71     { inAction; }                                                                  \
     72     goto inHandler;                                                                \
     73     }
     74 
     75 #endif
     76 
     77 
     78 //==================================================================================================
     79 #pragma mark -
     80 #pragma mark BlackHole State
     81 //==================================================================================================
     82 
     83 //    The driver has the following
     84 //    qualities:
     85 //    - a box
     86 //    - a device
     87 //        - supports 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000, 8000, 16000 sample rates
     88 
     89 
     90 //        - provides a rate scalar of 1.0 via hard coding
     91 //    - a single output stream
     92 //        - supports 16 channels of 32 bit float LPCM samples
     93 //        - writes to ring buffer
     94 //    - a single input stream
     95 //        - supports 16 channels of 32 bit float LPCM samples
     96 //        - reads from ring buffer
     97 //    - controls
     98 //        - master input volume
     99 //        - master output volume
    100 //        - master input mute
    101 //        - master output mute
    102 
    103 
    104 //    Declare the internal object ID numbers for all the objects this driver implements. Note that
    105 //    because the driver has fixed set of objects that never grows or shrinks. If this were not the
    106 //    case, the driver would need to have a means to dynamically allocate these IDs. It is important
    107 //    to realize that a lot of the structure of this driver is vastly simpler when the IDs are all
    108 //    known a priori. Comments in the code will try to identify some of these simplifications and
    109 //    point out what a more complicated driver will need to do.
    110 enum
    111 {
    112     kObjectID_PlugIn                    = kAudioObjectPlugInObject,
    113     kObjectID_Box                       = 2,
    114     kObjectID_Device                    = 3,
    115     kObjectID_Stream_Input              = 4,
    116     kObjectID_Volume_Input_Master       = 5,
    117     kObjectID_Mute_Input_Master         = 6,
    118     kObjectID_Stream_Output             = 7,
    119     kObjectID_Volume_Output_Master      = 8,
    120     kObjectID_Mute_Output_Master        = 9,
    121     kObjectID_Pitch_Adjust              = 10,
    122     kObjectID_ClockSource               = 11,
    123     kObjectID_Device2                   = 12,
    124 };
    125 
    126 enum
    127 {
    128     ChangeAction_SetSampleRate          = 1,
    129     ChangeAction_EnablePitchControl     = 2,
    130     ChangeAction_DisablePitchControl    = 3,
    131 };
    132 
    133 enum ObjectType
    134 {
    135     kObjectType_Stream,
    136     kObjectType_Control
    137 };
    138 
    139 struct ObjectInfo {
    140     AudioObjectID id;
    141     enum ObjectType type;
    142     AudioObjectPropertyScope scope;
    143 };
    144 
    145 //    Declare the stuff that tracks the state of the plug-in, the device and its sub-objects.
    146 //    Note that we use global variables here because this driver only ever has a single device. If
    147 //    multiple devices were supported, this state would need to be encapsulated in one or more structs
    148 //    so that each object's state can be tracked individually.
    149 //    Note also that we share a single mutex across all objects to be thread safe for the same reason.
    150 
    151 
    152 #ifndef kDriver_Name
    153 #define                             kDriver_Name                        "BlackHole"
    154 #endif
    155 
    156 #ifndef kPlugIn_BundleID
    157 #define                             kPlugIn_BundleID                    "audio.existential.BlackHole2ch"
    158 #endif
    159 
    160 #ifndef kPlugIn_Icon
    161 #define                             kPlugIn_Icon                        "BlackHole.icns"
    162 #endif
    163 
    164 #ifndef kHas_Driver_Name_Format
    165 #define                             kHas_Driver_Name_Format             true
    166 #endif
    167 
    168 #if kHas_Driver_Name_Format
    169 #define                             kDriver_Name_Format                 "%ich"
    170 #define                             kBox_UID                            kDriver_Name kDriver_Name_Format "_UID"
    171 #define                             kDevice_UID                         kDriver_Name kDriver_Name_Format "_UID"
    172 #define                             kDevice2_UID                        kDriver_Name kDriver_Name_Format "_2_UID"
    173 #define                             kDevice_ModelUID                    kDriver_Name kDriver_Name_Format "_ModelUID"
    174 
    175 
    176 #ifndef kDevice_Name
    177 #define                             kDevice_Name                        kDriver_Name " %ich"
    178 #endif
    179 
    180 #ifndef kDevice2_Name
    181 #define                             kDevice2_Name                       kDriver_Name " %ich 2"
    182 #endif
    183 
    184 
    185 #else
    186 #define                             kBox_UID                            kDriver_Name "_UID"
    187 #define                             kDevice_UID                         kDriver_Name "_UID"
    188 #define                             kDevice2_UID                        kDriver_Name "_2_UID"
    189 #define                             kDevice_ModelUID                    kDriver_Name "_ModelUID"
    190 
    191 
    192 #ifndef kDevice_Name
    193 #define                             kDevice_Name                        kDriver_Name " "
    194 #endif
    195 
    196 #ifndef kDevice2_Name
    197 #define                             kDevice2_Name                       kDriver_Name " Mirror"
    198 #endif
    199 
    200 #endif
    201 
    202 #ifndef kDevice_IsHidden
    203 #define                             kDevice_IsHidden                    false
    204 #endif
    205 
    206 #ifndef kDevice2_IsHidden
    207 #define                             kDevice2_IsHidden                   true
    208 #endif
    209 
    210 
    211 
    212 #ifndef kDevice_HasInput
    213 #define                             kDevice_HasInput                    true
    214 #endif
    215 
    216 #ifndef kDevice_HasOutput
    217 #define                             kDevice_HasOutput                   true
    218 #endif
    219 
    220 #ifndef kDevice2_HasInput
    221 #define                             kDevice2_HasInput                   true
    222 #endif
    223 
    224 #ifndef kDevice2_HasOutput
    225 #define                             kDevice2_HasOutput                  true
    226 #endif
    227 
    228 
    229 
    230 #ifndef kManufacturer_Name
    231 #define                             kManufacturer_Name                  "Existential Audio Inc."
    232 #endif
    233 
    234 #define                             kLatency_Frame_Size                 0
    235 
    236 #ifndef kNumber_Of_Channels
    237 #define                             kNumber_Of_Channels                 2
    238 #endif
    239 
    240 #ifndef kEnableVolumeControl
    241 #define                             kEnableVolumeControl                 true
    242 #endif
    243 
    244 #ifndef kCanBeDefaultDevice
    245 #define                             kCanBeDefaultDevice                 true
    246 #endif
    247 
    248 #ifndef kCanBeDefaultSystemDevice
    249 #define                             kCanBeDefaultSystemDevice           true
    250 #endif
    251 
    252 static pthread_mutex_t              gPlugIn_StateMutex                  = PTHREAD_MUTEX_INITIALIZER;
    253 static UInt32                       gPlugIn_RefCount                    = 0;
    254 static AudioServerPlugInHostRef     gPlugIn_Host                        = NULL;
    255 
    256 
    257 static CFStringRef                  gBox_Name                           = NULL;
    258 
    259 #ifndef kBox_Aquired
    260 #define                             kBox_Aquired                 	true
    261 #endif
    262 static Boolean                      gBox_Acquired                       = kBox_Aquired;
    263 
    264 
    265 static pthread_mutex_t              gDevice_IOMutex                     = PTHREAD_MUTEX_INITIALIZER;
    266 // Hydra: startup sample rate is overridable at build time (-DkDefault_SampleRate=44100) so
    267 // the virtual device can come up matching the host's rate. Defaults to 48000 = upstream.
    268 #ifndef kDefault_SampleRate
    269 #define                             kDefault_SampleRate                 48000.0
    270 #endif
    271 static Float64                      gDevice_SampleRate                  = kDefault_SampleRate;
    272 static Float64                      gDevice_RequestedSampleRate         = 0.0;
    273 static UInt64                       gDevice_IOIsRunning                 = 0;
    274 static UInt64                       gDevice2_IOIsRunning                = 0;
    275 static const UInt32                 kDevice_RingBufferSize              = 16384;
    276 static Float64                      gDevice_HostTicksPerFrame           = 0.0;
    277 static Float64                      gDevice_AdjustedTicksPerFrame       = 0.0;
    278 static Float64                      gDevice_PreviousTicks               = 0.0;
    279 static UInt64                       gDevice_NumberTimeStamps            = 0;
    280 static Float64                      gDevice_AnchorSampleTime            = 0.0;
    281 static UInt64                       gDevice_AnchorHostTime              = 0;
    282 
    283 static bool                         gStream_Input_IsActive              = true;
    284 static bool                         gStream_Output_IsActive             = true;
    285 
    286 static const Float32                kVolume_MinDB                       = -64.0;
    287 static const Float32                kVolume_MaxDB                       = 0.0;
    288 static Float32                      gVolume_Master_Value                = 1.0;
    289 static Float32                      gPitch_Adjust                       = 0.5;
    290 static bool                         gMute_Master_Value                  = false;
    291 static UInt32                       kClockSource_NumberItems            = 2;
    292 #define                             kClockSource_InternalFixed         "Internal Fixed"
    293 #define                             kClockSource_InternalAdjustable    "Internal Adjustable"
    294 static UInt32                       gClockSource_Value                  = 0;
    295 static bool                         gPitch_Adjust_Enabled               = false;
    296 
    297 static struct ObjectInfo            kDevice_ObjectList[]                = {
    298 #if kDevice_HasInput
    299     { kObjectID_Stream_Input,           kObjectType_Stream,     kAudioObjectPropertyScopeInput  },
    300     { kObjectID_Volume_Input_Master,    kObjectType_Control,    kAudioObjectPropertyScopeInput  },
    301     { kObjectID_Mute_Input_Master,      kObjectType_Control,    kAudioObjectPropertyScopeInput  },
    302 #endif
    303 #if kDevice_HasOutput
    304     { kObjectID_Stream_Output,          kObjectType_Stream,     kAudioObjectPropertyScopeOutput },
    305     { kObjectID_Volume_Output_Master,   kObjectType_Control,    kAudioObjectPropertyScopeOutput },
    306     { kObjectID_Mute_Output_Master,     kObjectType_Control,    kAudioObjectPropertyScopeOutput },
    307     { kObjectID_Pitch_Adjust,           kObjectType_Control,    kAudioObjectPropertyScopeOutput },
    308 #endif
    309     { kObjectID_ClockSource,            kObjectType_Control,    kAudioObjectPropertyScopeGlobal }
    310 };
    311 
    312 static struct ObjectInfo            kDevice2_ObjectList[]                = {
    313 #if kDevice2_HasInput
    314     { kObjectID_Stream_Input,           kObjectType_Stream,     kAudioObjectPropertyScopeInput  },
    315     { kObjectID_Volume_Input_Master,    kObjectType_Control,    kAudioObjectPropertyScopeInput  },
    316     { kObjectID_Mute_Input_Master,      kObjectType_Control,    kAudioObjectPropertyScopeInput  },
    317 #endif
    318 #if kDevice2_HasOutput
    319     { kObjectID_Stream_Output,          kObjectType_Stream,     kAudioObjectPropertyScopeOutput },
    320     { kObjectID_Volume_Output_Master,   kObjectType_Control,    kAudioObjectPropertyScopeOutput },
    321     { kObjectID_Mute_Output_Master,     kObjectType_Control,    kAudioObjectPropertyScopeOutput },
    322 #endif
    323 };
    324 
    325 static const UInt32                 kDevice_ObjectListSize              = sizeof(kDevice_ObjectList) / sizeof(struct ObjectInfo);
    326 static const UInt32                 kDevice2_ObjectListSize              = sizeof(kDevice2_ObjectList) / sizeof(struct ObjectInfo);
    327 
    328 #ifndef kSampleRates
    329 #define                             kSampleRates       8000, 16000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000
    330 #endif
    331 
    332 static Float64                      kDevice_SampleRates[]               = { kSampleRates };
    333 
    334 static const UInt32                 kDevice_SampleRatesSize             = sizeof(kDevice_SampleRates) / sizeof(Float64);
    335 
    336 
    337 
    338 #define                             kBits_Per_Channel                   32
    339 #define                             kBytes_Per_Channel                  (kBits_Per_Channel/ 8)
    340 #define                             kBytes_Per_Frame                    (kNumber_Of_Channels * kBytes_Per_Channel)
    341 #define                             kRing_Buffer_Frame_Size             ((65536 + kLatency_Frame_Size))
    342 static Float32*                     gRingBuffer = NULL;
    343 
    344 
    345 //==================================================================================================
    346 #pragma mark -
    347 #pragma mark AudioServerPlugInDriverInterface Implementation
    348 //==================================================================================================
    349 
    350 #pragma mark Prototypes
    351 
    352 //    Entry points for the COM methods
    353 void*                BlackHole_Create(CFAllocatorRef inAllocator, CFUUIDRef inRequestedTypeUUID);
    354 static HRESULT        BlackHole_QueryInterface(void* inDriver, REFIID inUUID, LPVOID* outInterface);
    355 static ULONG        BlackHole_AddRef(void* inDriver);
    356 static ULONG        BlackHole_Release(void* inDriver);
    357 static OSStatus        BlackHole_Initialize(AudioServerPlugInDriverRef inDriver, AudioServerPlugInHostRef inHost);
    358 static OSStatus        BlackHole_CreateDevice(AudioServerPlugInDriverRef inDriver, CFDictionaryRef inDescription, const AudioServerPlugInClientInfo* inClientInfo, AudioObjectID* outDeviceObjectID);
    359 static OSStatus        BlackHole_DestroyDevice(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID);
    360 static OSStatus        BlackHole_AddDeviceClient(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo* inClientInfo);
    361 static OSStatus        BlackHole_RemoveDeviceClient(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo* inClientInfo);
    362 static OSStatus        BlackHole_PerformDeviceConfigurationChange(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void* inChangeInfo);
    363 static OSStatus        BlackHole_AbortDeviceConfigurationChange(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void* inChangeInfo);
    364 static Boolean        BlackHole_HasProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress);
    365 static OSStatus        BlackHole_IsPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable);
    366 static OSStatus        BlackHole_GetPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
    367 static OSStatus        BlackHole_GetPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData);
    368 static OSStatus        BlackHole_SetPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData);
    369 static OSStatus        BlackHole_StartIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID);
    370 static OSStatus        BlackHole_StopIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID);
    371 static OSStatus        BlackHole_GetZeroTimeStamp(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, Float64* outSampleTime, UInt64* outHostTime, UInt64* outSeed);
    372 static OSStatus        BlackHole_WillDoIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, Boolean* outWillDo, Boolean* outWillDoInPlace);
    373 static OSStatus        BlackHole_BeginIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo);
    374 static OSStatus        BlackHole_DoIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, AudioObjectID inStreamObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo, void* ioMainBuffer, void* ioSecondaryBuffer);
    375 static OSStatus        BlackHole_EndIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo);
    376 
    377 //    Implementation
    378 static Boolean        BlackHole_HasPlugInProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress);
    379 static OSStatus        BlackHole_IsPlugInPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable);
    380 static OSStatus        BlackHole_GetPlugInPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
    381 static OSStatus        BlackHole_GetPlugInPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData);
    382 static OSStatus        BlackHole_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]);
    383 
    384 static Boolean        BlackHole_HasBoxProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress);
    385 static OSStatus        BlackHole_IsBoxPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable);
    386 static OSStatus        BlackHole_GetBoxPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
    387 static OSStatus        BlackHole_GetBoxPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData);
    388 static OSStatus        BlackHole_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]);
    389 
    390 static Boolean        BlackHole_HasDeviceProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress);
    391 static OSStatus        BlackHole_IsDevicePropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable);
    392 static OSStatus        BlackHole_GetDevicePropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
    393 static OSStatus        BlackHole_GetDevicePropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData);
    394 static OSStatus        BlackHole_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]);
    395 
    396 static Boolean        BlackHole_HasStreamProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress);
    397 static OSStatus        BlackHole_IsStreamPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable);
    398 static OSStatus        BlackHole_GetStreamPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
    399 static OSStatus        BlackHole_GetStreamPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData);
    400 static OSStatus        BlackHole_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]);
    401 
    402 static Boolean        BlackHole_HasControlProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress);
    403 static OSStatus        BlackHole_IsControlPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable);
    404 static OSStatus        BlackHole_GetControlPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
    405 static OSStatus        BlackHole_GetControlPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData);
    406 static OSStatus        BlackHole_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]);
    407 
    408 #pragma mark The Interface
    409 
    410 static AudioServerPlugInDriverInterface    gAudioServerPlugInDriverInterface =
    411 {
    412     NULL,
    413     BlackHole_QueryInterface,
    414     BlackHole_AddRef,
    415     BlackHole_Release,
    416     BlackHole_Initialize,
    417     BlackHole_CreateDevice,
    418     BlackHole_DestroyDevice,
    419     BlackHole_AddDeviceClient,
    420     BlackHole_RemoveDeviceClient,
    421     BlackHole_PerformDeviceConfigurationChange,
    422     BlackHole_AbortDeviceConfigurationChange,
    423     BlackHole_HasProperty,
    424     BlackHole_IsPropertySettable,
    425     BlackHole_GetPropertyDataSize,
    426     BlackHole_GetPropertyData,
    427     BlackHole_SetPropertyData,
    428     BlackHole_StartIO,
    429     BlackHole_StopIO,
    430     BlackHole_GetZeroTimeStamp,
    431     BlackHole_WillDoIOOperation,
    432     BlackHole_BeginIOOperation,
    433     BlackHole_DoIOOperation,
    434     BlackHole_EndIOOperation
    435 };
    436 static AudioServerPlugInDriverInterface*    gAudioServerPlugInDriverInterfacePtr    = &gAudioServerPlugInDriverInterface;
    437 static AudioServerPlugInDriverRef            gAudioServerPlugInDriverRef                = &gAudioServerPlugInDriverInterfacePtr;
    438 
    439 
    440 #define RETURN_FORMATTED_STRING(_string_fmt)                          \
    441 if(kHas_Driver_Name_Format)                                           \
    442 {                                                                     \
    443 	return CFStringCreateWithFormat(NULL, NULL, CFSTR(_string_fmt), kNumber_Of_Channels); \
    444 }                                                                     \
    445 else                                                                  \
    446 {                                                                     \
    447 	return CFStringCreateWithCString(NULL, _string_fmt, kCFStringEncodingUTF8); \
    448 }
    449 
    450 static CFStringRef get_box_uid(void)          { RETURN_FORMATTED_STRING(kBox_UID) }
    451 static CFStringRef get_device_uid(void)       { RETURN_FORMATTED_STRING(kDevice_UID) }
    452 
    453 // Hydra: the device's display name comes from the manifest (set via the Hydra TUI) when
    454 // present, so it can be renamed without rebuilding the driver. Read once and cached; on any
    455 // failure we fall through to the compile-time default, so a missing/bad manifest is safe.
    456 #include "../../hydra_cfg.h"
    457 static CFStringRef get_device_name(void) {
    458     static char nameBuf[256];
    459     static int  loaded = 0;
    460     if (!loaded) {
    461         loaded = 1;
    462         if (!hydra_cfg_device_name(nameBuf, (int)sizeof(nameBuf))) {
    463             nameBuf[0] = '\0';
    464         }
    465     }
    466     if (nameBuf[0] != '\0') {
    467         return CFStringCreateWithCString(NULL, nameBuf, kCFStringEncodingUTF8);
    468     }
    469     RETURN_FORMATTED_STRING(kDevice_Name)
    470 }
    471 static CFStringRef get_device2_uid(void)      { RETURN_FORMATTED_STRING(kDevice2_UID) }
    472 static CFStringRef get_device2_name(void)     { RETURN_FORMATTED_STRING(kDevice2_Name) }
    473 static CFStringRef get_device_model_uid(void) { RETURN_FORMATTED_STRING(kDevice_ModelUID) }
    474 
    475 // Volume conversions
    476 
    477 static Float32 volume_to_decibel(Float32 volume)
    478 {
    479 	if (volume <= powf(10.0f, kVolume_MinDB / 20.0f))
    480 		return kVolume_MinDB;
    481 	else
    482 		return 20.0f * log10f(volume);
    483 }
    484 
    485 static Float32 volume_from_decibel(Float32 decibel)
    486 {
    487 	if (decibel <= kVolume_MinDB)
    488 		return 0.0f;
    489 	else
    490 		return powf(10.0f, decibel / 20.0f);
    491 }
    492 
    493 static Float32 volume_to_scalar(Float32 volume)
    494 {
    495 	Float32 decibel = volume_to_decibel(volume);
    496 	return (decibel - kVolume_MinDB) / (kVolume_MaxDB - kVolume_MinDB);
    497 }
    498 
    499 static Float32 volume_from_scalar(Float32 scalar)
    500 {
    501 	Float32 decibel = scalar * (kVolume_MaxDB - kVolume_MinDB) + kVolume_MinDB;
    502 	return volume_from_decibel(decibel);
    503 }
    504 
    505 static UInt32 device_object_list_size(AudioObjectPropertyScope scope, AudioObjectID objectID) {
    506     
    507     switch (objectID) {
    508         case kObjectID_Device:
    509             {
    510                 if (scope == kAudioObjectPropertyScopeGlobal)
    511                 {
    512                     return kDevice_ObjectListSize;
    513                 }
    514 
    515                 UInt32 count = 0;
    516                 for (UInt32 i = 0; i < kDevice_ObjectListSize; i++)
    517                 {
    518                     count += (kDevice_ObjectList[i].scope == scope);
    519                 }
    520 
    521                 return count;
    522             }
    523             break;
    524             
    525         case kObjectID_Device2:
    526             {
    527                 if (scope == kAudioObjectPropertyScopeGlobal)
    528                 {
    529                     return kDevice2_ObjectListSize;
    530                 }
    531 
    532                 UInt32 count = 0;
    533                 for (UInt32 i = 0; i < kDevice2_ObjectListSize; i++)
    534                 {
    535                     count += (kDevice2_ObjectList[i].scope == scope);
    536                 }
    537 
    538                 return count;
    539             }
    540             break;
    541             
    542         default:
    543             return 0;
    544             break;
    545     }
    546 }
    547 
    548 static UInt32 device_stream_list_size(AudioObjectPropertyScope scope, AudioObjectID objectID) {
    549     
    550     switch (objectID) {
    551         case kObjectID_Device:
    552             {
    553                 UInt32 count = 0;
    554                 for (UInt32 i = 0; i < kDevice_ObjectListSize; i++)
    555                 {
    556                     count += (kDevice_ObjectList[i].type == kObjectType_Stream && (kDevice_ObjectList[i].scope == scope || scope == kAudioObjectPropertyScopeGlobal));
    557                 }
    558 
    559                 return count;
    560             }
    561             break;
    562             
    563         case kObjectID_Device2:
    564             {
    565                 UInt32 count = 0;
    566                 for (UInt32 i = 0; i < kDevice2_ObjectListSize; i++)
    567                 {
    568                     count += (kDevice2_ObjectList[i].type == kObjectType_Stream && (kDevice2_ObjectList[i].scope == scope || scope == kAudioObjectPropertyScopeGlobal));
    569                 }
    570 
    571                 return count;
    572             }
    573             break;
    574             
    575         default:
    576             return 0;
    577             break;
    578     }
    579     
    580 
    581 }
    582 
    583 static UInt32 device_control_list_size(AudioObjectPropertyScope scope, AudioObjectID objectID) {
    584     
    585     switch (objectID) {
    586         case kObjectID_Device:
    587         {
    588             
    589             UInt32 count = 0;
    590             for (UInt32 i = 0; i < kDevice_ObjectListSize; i++)
    591             {
    592                 count += (kDevice_ObjectList[i].type == kObjectType_Control && (kDevice_ObjectList[i].scope == scope || scope == kAudioObjectPropertyScopeGlobal));
    593             }
    594 
    595             return count;
    596         }
    597             break;
    598         case kObjectID_Device2:
    599         {
    600             
    601             UInt32 count = 0;
    602             for (UInt32 i = 0; i < kDevice2_ObjectListSize; i++)
    603             {
    604                 count += (kDevice2_ObjectList[i].type == kObjectType_Control && (kDevice2_ObjectList[i].scope == scope || scope == kAudioObjectPropertyScopeGlobal));
    605             }
    606 
    607             return count;
    608         }
    609             break;
    610             
    611         default:
    612             return 0;
    613             break;
    614     }
    615 
    616 }
    617 
    618 static UInt32 minimum(UInt32 a, UInt32 b) {
    619     return a < b ? a : b;
    620 }
    621 
    622 static bool is_valid_sample_rate(Float64 sample_rate)
    623 {
    624     for(UInt32 i = 0; i < kDevice_SampleRatesSize; i++)
    625     {
    626         if (sample_rate == kDevice_SampleRates[i])
    627         {
    628             return true;
    629         }
    630     }
    631 
    632     return false;
    633 }
    634 
    635 #pragma mark Factory
    636 
    637 void*	BlackHole_Create(CFAllocatorRef inAllocator, CFUUIDRef inRequestedTypeUUID)
    638 {
    639 	//	This is the CFPlugIn factory function. Its job is to create the implementation for the given
    640 	//	type provided that the type is supported. Because this driver is simple and all its
    641 	//	initialization is handled via static initialization when the bundle is loaded, all that
    642 	//	needs to be done is to return the AudioServerPlugInDriverRef that points to the driver's
    643 	//	interface. A more complicated driver would create any base line objects it needs to satisfy
    644 	//	the IUnknown methods that are used to discover that actual interface to talk to the driver.
    645 	//	The majority of the driver's initialization should be handled in the Initialize() method of
    646 	//	the driver's AudioServerPlugInDriverInterface.
    647 	
    648 	#pragma unused(inAllocator)
    649     void* theAnswer = NULL;
    650     if(CFEqual(inRequestedTypeUUID, kAudioServerPlugInTypeUUID))
    651     {
    652 		theAnswer = gAudioServerPlugInDriverRef;
    653     }
    654     return theAnswer;
    655 }
    656 
    657 #pragma mark Inheritance
    658 
    659 static HRESULT	BlackHole_QueryInterface(void* inDriver, REFIID inUUID, LPVOID* outInterface)
    660 {
    661 	//	This function is called by the HAL to get the interface to talk to the plug-in through.
    662 	//	AudioServerPlugIns are required to support the IUnknown interface and the
    663 	//	AudioServerPlugInDriverInterface. As it happens, all interfaces must also provide the
    664 	//	IUnknown interface, so we can always just return the single interface we made with
    665 	//	gAudioServerPlugInDriverInterfacePtr regardless of which one is asked for.
    666 
    667 	//	declare the local variables
    668 	HRESULT theAnswer = 0;
    669 	CFUUIDRef theRequestedUUID = NULL;
    670 	
    671 	//	validate the arguments
    672 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_QueryInterface: bad driver reference");
    673 	FailWithAction(outInterface == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_QueryInterface: no place to store the returned interface");
    674 
    675 	//	make a CFUUIDRef from inUUID
    676 	theRequestedUUID = CFUUIDCreateFromUUIDBytes(NULL, inUUID);
    677 	FailWithAction(theRequestedUUID == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_QueryInterface: failed to create the CFUUIDRef");
    678 
    679 	//	AudioServerPlugIns only support two interfaces, IUnknown (which has to be supported by all
    680 	//	CFPlugIns and AudioServerPlugInDriverInterface (which is the actual interface the HAL will
    681 	//	use).
    682 	if(CFEqual(theRequestedUUID, IUnknownUUID) || CFEqual(theRequestedUUID, kAudioServerPlugInDriverInterfaceUUID))
    683 	{
    684 		pthread_mutex_lock(&gPlugIn_StateMutex);
    685 		++gPlugIn_RefCount;
    686 		pthread_mutex_unlock(&gPlugIn_StateMutex);
    687 		*outInterface = gAudioServerPlugInDriverRef;
    688 	}
    689 	else
    690 	{
    691 		theAnswer = E_NOINTERFACE;
    692 	}
    693 	
    694 	//	make sure to release the UUID we created
    695 	CFRelease(theRequestedUUID);
    696 		
    697 Done:
    698 	return theAnswer;
    699 }
    700 
    701 static ULONG	BlackHole_AddRef(void* inDriver)
    702 {
    703 	//	This call returns the resulting reference count after the increment.
    704 	
    705 	//	declare the local variables
    706 	ULONG theAnswer = 0;
    707 	
    708 	//	check the arguments
    709 	FailIf(inDriver != gAudioServerPlugInDriverRef, Done, "BlackHole_AddRef: bad driver reference");
    710 
    711 	//	increment the refcount
    712 	pthread_mutex_lock(&gPlugIn_StateMutex);
    713 	if(gPlugIn_RefCount < UINT32_MAX)
    714 	{
    715 		++gPlugIn_RefCount;
    716 	}
    717 	theAnswer = gPlugIn_RefCount;
    718 	pthread_mutex_unlock(&gPlugIn_StateMutex);
    719 
    720 Done:
    721 	return theAnswer;
    722 }
    723 
    724 static ULONG	BlackHole_Release(void* inDriver)
    725 {
    726 	//	This call returns the resulting reference count after the decrement.
    727 
    728 	//	declare the local variables
    729 	ULONG theAnswer = 0;
    730 	
    731 	//	check the arguments
    732 	FailIf(inDriver != gAudioServerPlugInDriverRef, Done, "BlackHole_Release: bad driver reference");
    733 
    734 	//	decrement the refcount
    735 	pthread_mutex_lock(&gPlugIn_StateMutex);
    736 	if(gPlugIn_RefCount > 0)
    737 	{
    738 		--gPlugIn_RefCount;
    739 		//	Note that we don't do anything special if the refcount goes to zero as the HAL
    740 		//	will never fully release a plug-in it opens. We keep managing the refcount so that
    741 		//	the API semantics are correct though.
    742 	}
    743 	theAnswer = gPlugIn_RefCount;
    744 	pthread_mutex_unlock(&gPlugIn_StateMutex);
    745 
    746 Done:
    747 	return theAnswer;
    748 }
    749 
    750 #pragma mark Basic Operations
    751 
    752 static OSStatus	BlackHole_Initialize(AudioServerPlugInDriverRef inDriver, AudioServerPlugInHostRef inHost)
    753 {
    754 	//	The job of this method is, as the name implies, to get the driver initialized. One specific
    755 	//	thing that needs to be done is to store the AudioServerPlugInHostRef so that it can be used
    756 	//	later. Note that when this call returns, the HAL will scan the various lists the driver
    757 	//	maintains (such as the device list) to get the initial set of objects the driver is
    758 	//	publishing. So, there is no need to notify the HAL about any objects created as part of the
    759 	//	execution of this method.
    760 
    761 	//	declare the local variables
    762 	OSStatus theAnswer = 0;
    763 	
    764 	//	check the arguments
    765 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_Initialize: bad driver reference");
    766 	
    767 	//	store the AudioServerPlugInHostRef
    768 	gPlugIn_Host = inHost;
    769 	
    770 	//	initialize the box acquired property from the settings
    771 	CFPropertyListRef theSettingsData = NULL;
    772 	gPlugIn_Host->CopyFromStorage(gPlugIn_Host, CFSTR("box acquired"), &theSettingsData);
    773 	if(theSettingsData != NULL)
    774 	{
    775 		if(CFGetTypeID(theSettingsData) == CFBooleanGetTypeID())
    776 		{
    777 			gBox_Acquired = CFBooleanGetValue((CFBooleanRef)theSettingsData);
    778 		}
    779 		else if(CFGetTypeID(theSettingsData) == CFNumberGetTypeID())
    780 		{
    781 			SInt32 theValue = 0;
    782 			CFNumberGetValue((CFNumberRef)theSettingsData, kCFNumberSInt32Type, &theValue);
    783 			gBox_Acquired = theValue ? 1 : 0;
    784 		}
    785 		CFRelease(theSettingsData);
    786 	}
    787 	
    788 	//	initialize the box name from the settings
    789 	gPlugIn_Host->CopyFromStorage(gPlugIn_Host, CFSTR("box acquired"), &theSettingsData);
    790 	if(theSettingsData != NULL)
    791 	{
    792 		if(CFGetTypeID(theSettingsData) == CFStringGetTypeID())
    793 		{
    794 			gBox_Name = (CFStringRef)theSettingsData;
    795 			CFRetain(gBox_Name);
    796 		}
    797 		CFRelease(theSettingsData);
    798 	}
    799 	
    800 	//	set the box name directly as a last resort
    801 	if(gBox_Name == NULL)
    802 	{
    803 		gBox_Name = CFSTR("BlackHole Box");
    804 	}
    805 	
    806 	//	calculate the host ticks per frame
    807 	struct mach_timebase_info theTimeBaseInfo;
    808 	mach_timebase_info(&theTimeBaseInfo);
    809 	Float64 theHostClockFrequency = (Float64)theTimeBaseInfo.denom / (Float64)theTimeBaseInfo.numer;
    810 	theHostClockFrequency *= 1000000000.0;
    811 	gDevice_HostTicksPerFrame = theHostClockFrequency / gDevice_SampleRate;
    812     gDevice_AdjustedTicksPerFrame = gDevice_HostTicksPerFrame - gDevice_HostTicksPerFrame/100.0 * 2.0*(gPitch_Adjust - 0.5);
    813     
    814     // DebugMsg("BlackHole theTimeBaseInfo.numer: %u \t theTimeBaseInfo.denom: %u", theTimeBaseInfo.numer, theTimeBaseInfo.denom);
    815 	
    816 Done:
    817 	return theAnswer;
    818 }
    819 
    820 static OSStatus	BlackHole_CreateDevice(AudioServerPlugInDriverRef inDriver, CFDictionaryRef inDescription, const AudioServerPlugInClientInfo* inClientInfo, AudioObjectID* outDeviceObjectID)
    821 {
    822 	//	This method is used to tell a driver that implements the Transport Manager semantics to
    823 	//	create an AudioEndpointDevice from a set of AudioEndpoints. Since this driver is not a
    824 	//	Transport Manager, we just check the arguments and return
    825 	//	kAudioHardwareUnsupportedOperationError.
    826 	
    827 	#pragma unused(inDescription, inClientInfo, outDeviceObjectID)
    828 	
    829 	//	declare the local variables
    830 	OSStatus theAnswer = kAudioHardwareUnsupportedOperationError;
    831 	
    832 	//	check the arguments
    833 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_CreateDevice: bad driver reference");
    834 
    835 Done:
    836 	return theAnswer;
    837 }
    838 
    839 static OSStatus	BlackHole_DestroyDevice(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID)
    840 {
    841 	//	This method is used to tell a driver that implements the Transport Manager semantics to
    842 	//	destroy an AudioEndpointDevice. Since this driver is not a Transport Manager, we just check
    843 	//	the arguments and return kAudioHardwareUnsupportedOperationError.
    844 	
    845 	#pragma unused(inDeviceObjectID)
    846 	
    847 	//	declare the local variables
    848 	OSStatus theAnswer = kAudioHardwareUnsupportedOperationError;
    849 	
    850 	//	check the arguments
    851 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_DestroyDevice: bad driver reference");
    852 
    853 Done:
    854 	return theAnswer;
    855 }
    856 
    857 static OSStatus	BlackHole_AddDeviceClient(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo* inClientInfo)
    858 {
    859 	//	This method is used to inform the driver about a new client that is using the given device.
    860 	//	This allows the device to act differently depending on who the client is. This driver does
    861 	//	not need to track the clients using the device, so we just check the arguments and return
    862 	//	successfully.
    863 	
    864 	#pragma unused(inClientInfo)
    865 	
    866 	//	declare the local variables
    867 	OSStatus theAnswer = 0;
    868 	
    869 	//	check the arguments
    870 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_AddDeviceClient: bad driver reference");
    871 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_AddDeviceClient: bad device ID");
    872 
    873 Done:
    874 	return theAnswer;
    875 }
    876 
    877 static OSStatus	BlackHole_RemoveDeviceClient(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo* inClientInfo)
    878 {
    879 	//	This method is used to inform the driver about a client that is no longer using the given
    880 	//	device. This driver does not track clients, so we just check the arguments and return
    881 	//	successfully.
    882 	
    883 	#pragma unused(inClientInfo)
    884 	
    885 	//	declare the local variables
    886 	OSStatus theAnswer = 0;
    887 	
    888 	//	check the arguments
    889 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_RemoveDeviceClient: bad driver reference");
    890 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_RemoveDeviceClient: bad device ID");
    891 
    892 Done:
    893 	return theAnswer;
    894 }
    895 
    896 static OSStatus	BlackHole_PerformDeviceConfigurationChange(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void* inChangeInfo)
    897 {
    898 	//	This method is called to tell the device that it can perform the configuration change that it
    899 	//	had requested via a call to the host method, RequestDeviceConfigurationChange(). The
    900 	//	arguments, inChangeAction and inChangeInfo are the same as what was passed to
    901 	//	RequestDeviceConfigurationChange().
    902 	//
    903 	//	The HAL guarantees that IO will be stopped while this method is in progress. The HAL will
    904 	//	also handle figuring out exactly what changed for the non-control related properties. This
    905 	//	means that the only notifications that would need to be sent here would be for either
    906 	//	custom properties the HAL doesn't know about or for controls.
    907 	//
    908 	//	For the device implemented by this driver, sample rate changes and enabling/disabling
    909 	//	the pitch adjust go through this process.
    910 	//	These are the only states that can be changed for the device that aren't controls.
    911 	//	Which change is requested is passed in the inChangeAction argument.
    912 	
    913 	#pragma unused(inChangeInfo)
    914 
    915 	//	declare the local variables
    916 	OSStatus theAnswer = 0;
    917     Float64 newSampleRate = 0.0;
    918 	
    919 	//	check the arguments
    920 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_PerformDeviceConfigurationChange: bad driver reference");
    921     FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_PerformDeviceConfigurationChange: bad device ID");
    922     switch(inChangeAction)
    923     {
    924         case ChangeAction_EnablePitchControl:
    925             pthread_mutex_lock(&gPlugIn_StateMutex);
    926             gPitch_Adjust_Enabled = true;
    927             pthread_mutex_unlock(&gPlugIn_StateMutex);
    928             break;
    929         case ChangeAction_DisablePitchControl:
    930             pthread_mutex_lock(&gPlugIn_StateMutex);
    931             gPitch_Adjust_Enabled = false;
    932             pthread_mutex_unlock(&gPlugIn_StateMutex);
    933             break;
    934         case ChangeAction_SetSampleRate:
    935             pthread_mutex_lock(&gPlugIn_StateMutex);
    936             newSampleRate = gDevice_RequestedSampleRate;
    937             pthread_mutex_unlock(&gPlugIn_StateMutex);
    938             FailWithAction(!is_valid_sample_rate(newSampleRate), theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_PerformDeviceConfigurationChange: bad sample rate");
    939             
    940             //	lock the state mutex
    941             pthread_mutex_lock(&gPlugIn_StateMutex);
    942             
    943             //	change the sample rate
    944             gDevice_SampleRate = newSampleRate;
    945             
    946             //	recalculate the state that depends on the sample rate
    947             struct mach_timebase_info theTimeBaseInfo;
    948             mach_timebase_info(&theTimeBaseInfo);
    949             Float64 theHostClockFrequency = (Float64)theTimeBaseInfo.denom / (Float64)theTimeBaseInfo.numer;
    950             theHostClockFrequency *= 1000000000.0;
    951             gDevice_HostTicksPerFrame = theHostClockFrequency / gDevice_SampleRate;
    952             gDevice_AdjustedTicksPerFrame = gDevice_HostTicksPerFrame - gDevice_HostTicksPerFrame/100.0 * 2.0*(gPitch_Adjust - 0.5);
    953             
    954             //	unlock the state mutex
    955             pthread_mutex_unlock(&gPlugIn_StateMutex);
    956             
    957             // DebugMsg("BlackHole theTimeBaseInfo.numer: %u \t theTimeBaseInfo.denom: %u", theTimeBaseInfo.numer, theTimeBaseInfo.denom);
    958             break;
    959     };
    960 	
    961 Done:
    962 	return theAnswer;
    963 }
    964 
    965 static OSStatus	BlackHole_AbortDeviceConfigurationChange(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void* inChangeInfo)
    966 {
    967 	//	This method is called to tell the driver that a request for a config change has been denied.
    968 	//	This provides the driver an opportunity to clean up any state associated with the request.
    969 	//	For this driver, an aborted config change requires no action. So we just check the arguments
    970 	//	and return
    971 
    972 	#pragma unused(inChangeAction, inChangeInfo)
    973 
    974 	//	declare the local variables
    975 	OSStatus theAnswer = 0;
    976 	
    977 	//	check the arguments
    978 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_PerformDeviceConfigurationChange: bad driver reference");
    979 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_PerformDeviceConfigurationChange: bad device ID");
    980 
    981 Done:
    982 	return theAnswer;
    983 }
    984 
    985 #pragma mark Property Operations
    986 
    987 static Boolean	BlackHole_HasProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress)
    988 {
    989 	//	This method returns whether or not the given object has the given property.
    990 	
    991 	//	declare the local variables
    992 	Boolean theAnswer = false;
    993 	
    994 	//	check the arguments
    995 	FailIf(inDriver != gAudioServerPlugInDriverRef, Done, "BlackHole_HasProperty: bad driver reference");
    996 	FailIf(inAddress == NULL, Done, "BlackHole_HasProperty: no address");
    997 	
    998 	//	Note that for each object, this driver implements all the required properties plus a few
    999 	//	extras that are useful but not required. There is more detailed commentary about each
   1000 	//	property in the BlackHole_GetPropertyData() method.
   1001 	switch(inObjectID)
   1002 	{
   1003 		case kObjectID_PlugIn:
   1004 			theAnswer = BlackHole_HasPlugInProperty(inDriver, inObjectID, inClientProcessID, inAddress);
   1005 			break;
   1006 		
   1007 		case kObjectID_Box:
   1008 			theAnswer = BlackHole_HasBoxProperty(inDriver, inObjectID, inClientProcessID, inAddress);
   1009 			break;
   1010 		
   1011 		case kObjectID_Device:
   1012         case kObjectID_Device2:
   1013 			theAnswer = BlackHole_HasDeviceProperty(inDriver, inObjectID, inClientProcessID, inAddress);
   1014 			break;
   1015 		
   1016 		case kObjectID_Stream_Input:
   1017 		case kObjectID_Stream_Output:
   1018 			theAnswer = BlackHole_HasStreamProperty(inDriver, inObjectID, inClientProcessID, inAddress);
   1019 			break;
   1020 		
   1021 		case kObjectID_Volume_Output_Master:
   1022 		case kObjectID_Mute_Output_Master:
   1023 		case kObjectID_Volume_Input_Master:
   1024 		case kObjectID_Mute_Input_Master:
   1025 		case kObjectID_Pitch_Adjust:
   1026         case kObjectID_ClockSource:
   1027 			theAnswer = BlackHole_HasControlProperty(inDriver, inObjectID, inClientProcessID, inAddress);
   1028 			break;
   1029 	};
   1030 
   1031 Done:
   1032 	return theAnswer;
   1033 }
   1034 
   1035 static OSStatus	BlackHole_IsPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable)
   1036 {
   1037 	//	This method returns whether or not the given property on the object can have its value
   1038 	//	changed.
   1039 	
   1040 	//	declare the local variables
   1041 	OSStatus theAnswer = 0;
   1042 	
   1043 	//	check the arguments
   1044 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsPropertySettable: bad driver reference");
   1045 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsPropertySettable: no address");
   1046 	FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsPropertySettable: no place to put the return value");
   1047 	
   1048 	//	Note that for each object, this driver implements all the required properties plus a few
   1049 	//	extras that are useful but not required. There is more detailed commentary about each
   1050 	//	property in the BlackHole_GetPropertyData() method.
   1051 	switch(inObjectID)
   1052 	{
   1053 		case kObjectID_PlugIn:
   1054 			theAnswer = BlackHole_IsPlugInPropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable);
   1055 			break;
   1056 		
   1057 		case kObjectID_Box:
   1058 			theAnswer = BlackHole_IsBoxPropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable);
   1059 			break;
   1060 		
   1061 		case kObjectID_Device:
   1062         case kObjectID_Device2:
   1063 			theAnswer = BlackHole_IsDevicePropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable);
   1064 			break;
   1065 		
   1066 		case kObjectID_Stream_Input:
   1067 		case kObjectID_Stream_Output:
   1068 			theAnswer = BlackHole_IsStreamPropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable);
   1069 			break;
   1070 
   1071 		case kObjectID_Volume_Output_Master:
   1072 		case kObjectID_Mute_Output_Master:
   1073 		case kObjectID_Volume_Input_Master:
   1074 		case kObjectID_Mute_Input_Master:
   1075 		case kObjectID_Pitch_Adjust:
   1076         case kObjectID_ClockSource:
   1077 			theAnswer = BlackHole_IsControlPropertySettable(inDriver, inObjectID, inClientProcessID, inAddress, outIsSettable);
   1078 			break;
   1079 
   1080 		default:
   1081 			theAnswer = kAudioHardwareBadObjectError;
   1082 			break;
   1083 	};
   1084 
   1085 Done:
   1086 	return theAnswer;
   1087 }
   1088 
   1089 static OSStatus	BlackHole_GetPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize)
   1090 {
   1091 	//	This method returns the byte size of the property's data.
   1092 	
   1093 	//	declare the local variables
   1094 	OSStatus theAnswer = 0;
   1095 	
   1096 	//	check the arguments
   1097 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetPropertyDataSize: bad driver reference");
   1098 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPropertyDataSize: no address");
   1099 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPropertyDataSize: no place to put the return value");
   1100 	
   1101 	//	Note that for each object, this driver implements all the required properties plus a few
   1102 	//	extras that are useful but not required. There is more detailed commentary about each
   1103 	//	property in the BlackHole_GetPropertyData() method.
   1104 	switch(inObjectID)
   1105 	{
   1106 		case kObjectID_PlugIn:
   1107 			theAnswer = BlackHole_GetPlugInPropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize);
   1108 			break;
   1109 		
   1110 		case kObjectID_Box:
   1111 			theAnswer = BlackHole_GetBoxPropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize);
   1112 			break;
   1113 		
   1114 		case kObjectID_Device:
   1115         case kObjectID_Device2:
   1116 			theAnswer = BlackHole_GetDevicePropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize);
   1117 			break;
   1118 		
   1119 		case kObjectID_Stream_Input:
   1120 		case kObjectID_Stream_Output:
   1121 			theAnswer = BlackHole_GetStreamPropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize);
   1122 			break;
   1123 			
   1124 		case kObjectID_Volume_Output_Master:
   1125 		case kObjectID_Mute_Output_Master:
   1126 		case kObjectID_Volume_Input_Master:
   1127 		case kObjectID_Mute_Input_Master:
   1128 		case kObjectID_Pitch_Adjust:
   1129         case kObjectID_ClockSource:
   1130 			theAnswer = BlackHole_GetControlPropertyDataSize(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, outDataSize);
   1131 			break;
   1132 			
   1133 		default:
   1134 			theAnswer = kAudioHardwareBadObjectError;
   1135 			break;
   1136 	};
   1137 
   1138 Done:
   1139 	return theAnswer;
   1140 }
   1141 
   1142 static OSStatus	BlackHole_GetPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData)
   1143 {
   1144 	//	declare the local variables
   1145 	OSStatus theAnswer = 0;
   1146 	
   1147 	//	check the arguments
   1148 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetPropertyData: bad driver reference");
   1149 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPropertyData: no address");
   1150 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPropertyData: no place to put the return value size");
   1151 	FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPropertyData: no place to put the return value");
   1152 	
   1153 	//	Note that for each object, this driver implements all the required properties plus a few
   1154 	//	extras that are useful but not required.
   1155 	//
   1156 	//	Also, since most of the data that will get returned is static, there are few instances where
   1157 	//	it is necessary to lock the state mutex.
   1158 	switch(inObjectID)
   1159 	{
   1160 		case kObjectID_PlugIn:
   1161 			theAnswer = BlackHole_GetPlugInPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData);
   1162 			break;
   1163 		
   1164 		case kObjectID_Box:
   1165 			theAnswer = BlackHole_GetBoxPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData);
   1166 			break;
   1167 		
   1168 		case kObjectID_Device:
   1169         case kObjectID_Device2:
   1170 			theAnswer = BlackHole_GetDevicePropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData);
   1171 			break;
   1172 		
   1173 		case kObjectID_Stream_Input:
   1174 		case kObjectID_Stream_Output:
   1175 			theAnswer = BlackHole_GetStreamPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData);
   1176 			break;
   1177 		
   1178 		case kObjectID_Volume_Output_Master:
   1179 		case kObjectID_Mute_Output_Master:
   1180 		case kObjectID_Volume_Input_Master:
   1181 		case kObjectID_Mute_Input_Master:
   1182 		case kObjectID_Pitch_Adjust:
   1183         case kObjectID_ClockSource:
   1184 			theAnswer = BlackHole_GetControlPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData);
   1185 			break;
   1186 			
   1187 		default:
   1188 			theAnswer = kAudioHardwareBadObjectError;
   1189 			break;
   1190 	};
   1191 
   1192 Done:
   1193 	return theAnswer;
   1194 }
   1195 
   1196 static OSStatus	BlackHole_SetPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData)
   1197 {
   1198 	//	declare the local variables
   1199 	OSStatus theAnswer = 0;
   1200 	UInt32 theNumberPropertiesChanged = 0;
   1201 	AudioObjectPropertyAddress theChangedAddresses[2];
   1202 	
   1203 	//	check the arguments
   1204 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetPropertyData: bad driver reference");
   1205 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetPropertyData: no address");
   1206 	
   1207 	//	Note that for each object, this driver implements all the required properties plus a few
   1208 	//	extras that are useful but not required. There is more detailed commentary about each
   1209 	//	property in the BlackHole_GetPropertyData() method.
   1210 	switch(inObjectID)
   1211 	{
   1212 		case kObjectID_PlugIn:
   1213 			theAnswer = BlackHole_SetPlugInPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses);
   1214 			break;
   1215 		
   1216 		case kObjectID_Box:
   1217 			theAnswer = BlackHole_SetBoxPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses);
   1218 			break;
   1219 		
   1220 		case kObjectID_Device:
   1221         case kObjectID_Device2:
   1222 			theAnswer = BlackHole_SetDevicePropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses);
   1223 			break;
   1224 		
   1225 		case kObjectID_Stream_Input:
   1226 		case kObjectID_Stream_Output:
   1227 			theAnswer = BlackHole_SetStreamPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses);
   1228 			break;
   1229 			
   1230 		case kObjectID_Volume_Output_Master:
   1231 		case kObjectID_Mute_Output_Master:
   1232 		case kObjectID_Volume_Input_Master:
   1233 		case kObjectID_Mute_Input_Master:
   1234 		case kObjectID_Pitch_Adjust:
   1235         case kObjectID_ClockSource:
   1236 			theAnswer = BlackHole_SetControlPropertyData(inDriver, inObjectID, inClientProcessID, inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData, &theNumberPropertiesChanged, theChangedAddresses);
   1237 			break;
   1238 			
   1239 		default:
   1240 			theAnswer = kAudioHardwareBadObjectError;
   1241 			break;
   1242 	};
   1243 
   1244 	//	send any notifications
   1245 	if(theNumberPropertiesChanged > 0)
   1246 	{
   1247 		gPlugIn_Host->PropertiesChanged(gPlugIn_Host, inObjectID, theNumberPropertiesChanged, theChangedAddresses);
   1248 	}
   1249 
   1250 Done:
   1251 	return theAnswer;
   1252 }
   1253 
   1254 #pragma mark PlugIn Property Operations
   1255 
   1256 static Boolean	BlackHole_HasPlugInProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress)
   1257 {
   1258 	//	This method returns whether or not the plug-in object has the given property.
   1259 	
   1260 	#pragma unused(inClientProcessID)
   1261 	
   1262 	//	declare the local variables
   1263 	Boolean theAnswer = false;
   1264 	
   1265 	//	check the arguments
   1266 	FailIf(inDriver != gAudioServerPlugInDriverRef, Done, "BlackHole_HasPlugInProperty: bad driver reference");
   1267 	FailIf(inAddress == NULL, Done, "BlackHole_HasPlugInProperty: no address");
   1268 	FailIf(inObjectID != kObjectID_PlugIn, Done, "BlackHole_HasPlugInProperty: not the plug-in object");
   1269 	
   1270 	
   1271 	//	Note that for each object, this driver implements all the required properties plus a few
   1272 	//	extras that are useful but not required. There is more detailed commentary about each
   1273 	//	property in the BlackHole_GetPlugInPropertyData() method.
   1274 	switch(inAddress->mSelector)
   1275 	{
   1276 		case kAudioObjectPropertyBaseClass:
   1277 		case kAudioObjectPropertyClass:
   1278 		case kAudioObjectPropertyOwner:
   1279 		case kAudioObjectPropertyManufacturer:
   1280 		case kAudioObjectPropertyOwnedObjects:
   1281 		case kAudioPlugInPropertyBoxList:
   1282 		case kAudioPlugInPropertyTranslateUIDToBox:
   1283 		case kAudioPlugInPropertyDeviceList:
   1284 		case kAudioPlugInPropertyTranslateUIDToDevice:
   1285 		case kAudioPlugInPropertyResourceBundle:
   1286 			theAnswer = true;
   1287 			break;
   1288 	};
   1289 
   1290 Done:
   1291 	return theAnswer;
   1292 }
   1293 
   1294 static OSStatus	BlackHole_IsPlugInPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable)
   1295 {
   1296 	//	This method returns whether or not the given property on the plug-in object can have its
   1297 	//	value changed.
   1298 	
   1299 	#pragma unused(inClientProcessID)
   1300 	
   1301 	//	declare the local variables
   1302 	OSStatus theAnswer = 0;
   1303 	
   1304 	//	check the arguments
   1305 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsPlugInPropertySettable: bad driver reference");
   1306 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsPlugInPropertySettable: no address");
   1307 	FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsPlugInPropertySettable: no place to put the return value");
   1308 	FailWithAction(inObjectID != kObjectID_PlugIn, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsPlugInPropertySettable: not the plug-in object");
   1309 	
   1310 	//	Note that for each object, this driver implements all the required properties plus a few
   1311 	//	extras that are useful but not required. There is more detailed commentary about each
   1312 	//	property in the BlackHole_GetPlugInPropertyData() method.
   1313 	switch(inAddress->mSelector)
   1314 	{
   1315 		case kAudioObjectPropertyBaseClass:
   1316 		case kAudioObjectPropertyClass:
   1317 		case kAudioObjectPropertyOwner:
   1318 		case kAudioObjectPropertyManufacturer:
   1319 		case kAudioObjectPropertyOwnedObjects:
   1320 		case kAudioPlugInPropertyBoxList:
   1321 		case kAudioPlugInPropertyTranslateUIDToBox:
   1322 		case kAudioPlugInPropertyDeviceList:
   1323 		case kAudioPlugInPropertyTranslateUIDToDevice:
   1324 		case kAudioPlugInPropertyResourceBundle:
   1325 			*outIsSettable = false;
   1326 			break;
   1327 		
   1328 		default:
   1329 			theAnswer = kAudioHardwareUnknownPropertyError;
   1330 			break;
   1331 	};
   1332 
   1333 Done:
   1334 	return theAnswer;
   1335 }
   1336 
   1337 static OSStatus	BlackHole_GetPlugInPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize)
   1338 {
   1339 	//	This method returns the byte size of the property's data.
   1340 	
   1341 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   1342 	
   1343 	//	declare the local variables
   1344 	OSStatus theAnswer = 0;
   1345 	
   1346 	//	check the arguments
   1347 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetPlugInPropertyDataSize: bad driver reference");
   1348 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPlugInPropertyDataSize: no address");
   1349 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPlugInPropertyDataSize: no place to put the return value");
   1350 	FailWithAction(inObjectID != kObjectID_PlugIn, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetPlugInPropertyDataSize: not the plug-in object");
   1351 	
   1352 	//	Note that for each object, this driver implements all the required properties plus a few
   1353 	//	extras that are useful but not required. There is more detailed commentary about each
   1354 	//	property in the BlackHole_GetPlugInPropertyData() method.
   1355 	switch(inAddress->mSelector)
   1356 	{
   1357 		case kAudioObjectPropertyBaseClass:
   1358 			*outDataSize = sizeof(AudioClassID);
   1359 			break;
   1360 			
   1361 		case kAudioObjectPropertyClass:
   1362 			*outDataSize = sizeof(AudioClassID);
   1363 			break;
   1364 			
   1365 		case kAudioObjectPropertyOwner:
   1366 			*outDataSize = sizeof(AudioObjectID);
   1367 			break;
   1368 			
   1369 		case kAudioObjectPropertyManufacturer:
   1370 			*outDataSize = sizeof(CFStringRef);
   1371 			break;
   1372 			
   1373 		case kAudioObjectPropertyOwnedObjects:
   1374 			if(gBox_Acquired)
   1375 			{
   1376 				*outDataSize = 2 * sizeof(AudioClassID);
   1377 			}
   1378 			else
   1379 			{
   1380 				*outDataSize = sizeof(AudioClassID);
   1381 			}
   1382 			break;
   1383 			
   1384 		case kAudioPlugInPropertyBoxList:
   1385 			*outDataSize = sizeof(AudioClassID);
   1386 			break;
   1387 			
   1388 		case kAudioPlugInPropertyTranslateUIDToBox:
   1389 			*outDataSize = sizeof(AudioObjectID);
   1390 			break;
   1391 			
   1392 		case kAudioPlugInPropertyDeviceList:
   1393 			if(gBox_Acquired)
   1394 			{
   1395 				*outDataSize = sizeof(AudioClassID)*2;
   1396 			}
   1397 			else
   1398 			{
   1399 				*outDataSize = 0;
   1400 			}
   1401 			break;
   1402 			
   1403 		case kAudioPlugInPropertyTranslateUIDToDevice:
   1404 			*outDataSize = sizeof(AudioObjectID);
   1405 			break;
   1406 			
   1407 		case kAudioPlugInPropertyResourceBundle:
   1408 			*outDataSize = sizeof(CFStringRef);
   1409 			break;
   1410 			
   1411 		default:
   1412 			theAnswer = kAudioHardwareUnknownPropertyError;
   1413 			break;
   1414 	};
   1415 
   1416 Done:
   1417 	return theAnswer;
   1418 }
   1419 
   1420 static OSStatus	BlackHole_GetPlugInPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData)
   1421 {
   1422 	#pragma unused(inClientProcessID)
   1423 	
   1424 	//	declare the local variables
   1425 	OSStatus theAnswer = 0;
   1426 	UInt32 theNumberItemsToFetch;
   1427 	
   1428 	//	check the arguments
   1429 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetPlugInPropertyData: bad driver reference");
   1430 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPlugInPropertyData: no address");
   1431 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPlugInPropertyData: no place to put the return value size");
   1432 	FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetPlugInPropertyData: no place to put the return value");
   1433 	FailWithAction(inObjectID != kObjectID_PlugIn, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetPlugInPropertyData: not the plug-in object");
   1434 	
   1435 	//	Note that for each object, this driver implements all the required properties plus a few
   1436 	//	extras that are useful but not required.
   1437 	//
   1438 	//	Also, since most of the data that will get returned is static, there are few instances where
   1439 	//	it is necessary to lock the state mutex.
   1440 	switch(inAddress->mSelector)
   1441 	{
   1442 		case kAudioObjectPropertyBaseClass:
   1443 			//	The base class for kAudioPlugInClassID is kAudioObjectClassID
   1444 			FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the plug-in");
   1445 			*((AudioClassID*)outData) = kAudioObjectClassID;
   1446 			*outDataSize = sizeof(AudioClassID);
   1447 			break;
   1448 			
   1449 		case kAudioObjectPropertyClass:
   1450 			//	The class is always kAudioPlugInClassID for regular drivers
   1451 			FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the plug-in");
   1452 			*((AudioClassID*)outData) = kAudioPlugInClassID;
   1453 			*outDataSize = sizeof(AudioClassID);
   1454 			break;
   1455 			
   1456 		case kAudioObjectPropertyOwner:
   1457 			//	The plug-in doesn't have an owning object
   1458 			FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the plug-in");
   1459 			*((AudioObjectID*)outData) = kAudioObjectUnknown;
   1460 			*outDataSize = sizeof(AudioObjectID);
   1461 			break;
   1462 			
   1463 		case kAudioObjectPropertyManufacturer:
   1464 			//	This is the human readable name of the maker of the plug-in.
   1465 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the plug-in");
   1466 			*((CFStringRef*)outData) = CFSTR("Apple Inc.");
   1467 			*outDataSize = sizeof(CFStringRef);
   1468 			break;
   1469 			
   1470 		case kAudioObjectPropertyOwnedObjects:
   1471 			//	Calculate the number of items that have been requested. Note that this
   1472 			//	number is allowed to be smaller than the actual size of the list. In such
   1473 			//	case, only that number of items will be returned
   1474 			theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID);
   1475 			
   1476 			//	Clamp that to the number of boxes this driver implements (which is just 1)
   1477 			if(theNumberItemsToFetch > (gBox_Acquired ? 2 : 1))
   1478 			{
   1479 				theNumberItemsToFetch = (gBox_Acquired ? 2 : 1);
   1480 			}
   1481 			
   1482 			//	Write the devices' object IDs into the return value
   1483 			if(theNumberItemsToFetch > 1)
   1484 			{
   1485 				((AudioObjectID*)outData)[0] = kObjectID_Box;
   1486 				((AudioObjectID*)outData)[0] = kObjectID_Device;
   1487 			}
   1488 			else if(theNumberItemsToFetch > 0)
   1489 			{
   1490 				((AudioObjectID*)outData)[0] = kObjectID_Box;
   1491 			}
   1492 			
   1493 			//	Return how many bytes we wrote to
   1494 			*outDataSize = theNumberItemsToFetch * sizeof(AudioClassID);
   1495 			break;
   1496 			
   1497 		case kAudioPlugInPropertyBoxList:
   1498 			//	Calculate the number of items that have been requested. Note that this
   1499 			//	number is allowed to be smaller than the actual size of the list. In such
   1500 			//	case, only that number of items will be returned
   1501 			theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID);
   1502 			
   1503 			//	Clamp that to the number of boxes this driver implements (which is just 1)
   1504 			if(theNumberItemsToFetch > 1)
   1505 			{
   1506 				theNumberItemsToFetch = 1;
   1507 			}
   1508 			
   1509 			//	Write the devices' object IDs into the return value
   1510 			if(theNumberItemsToFetch > 0)
   1511 			{
   1512 				((AudioObjectID*)outData)[0] = kObjectID_Box;
   1513 			}
   1514 			
   1515 			//	Return how many bytes we wrote to
   1516 			*outDataSize = theNumberItemsToFetch * sizeof(AudioClassID);
   1517 			break;
   1518 			
   1519 		case kAudioPlugInPropertyTranslateUIDToBox:
   1520 			//	This property takes the CFString passed in the qualifier and converts that
   1521 			//	to the object ID of the box it corresponds to. For this driver, there is
   1522 			//	just the one box. Note that it is not an error if the string in the
   1523 			//	qualifier doesn't match any devices. In such case, kAudioObjectUnknown is
   1524 			//	the object ID to return.
   1525 			FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: not enough space for the return value of kAudioPlugInPropertyTranslateUIDToBox");
   1526 			FailWithAction(inQualifierDataSize == sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: the qualifier is the wrong size for kAudioPlugInPropertyTranslateUIDToBox");
   1527 			FailWithAction(inQualifierData == NULL, theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: no qualifier for kAudioPlugInPropertyTranslateUIDToBox");
   1528 
   1529 			CFStringRef boxUID = get_box_uid();
   1530 
   1531 			if(CFStringCompare(*((CFStringRef*)inQualifierData), boxUID, 0) == kCFCompareEqualTo)
   1532 			{
   1533 				CFStringRef formattedString = CFStringCreateWithFormat(NULL, NULL, CFSTR(kBox_UID), kNumber_Of_Channels);
   1534 				if(CFStringCompare(*((CFStringRef*)inQualifierData), formattedString, 0) == kCFCompareEqualTo)
   1535 				{
   1536 					*((AudioObjectID*)outData) = kObjectID_Box;
   1537 				}
   1538 				else
   1539 				{
   1540 					*((AudioObjectID*)outData) = kAudioObjectUnknown;
   1541 				}
   1542 				*outDataSize = sizeof(AudioObjectID);
   1543 				CFRelease(formattedString);
   1544 
   1545 				*((AudioObjectID*)outData) = kObjectID_Box;
   1546 			}
   1547 			else
   1548 			{
   1549 				*((AudioObjectID*)outData) = kAudioObjectUnknown;
   1550 			}
   1551 			*outDataSize = sizeof(AudioObjectID);
   1552 			CFRelease(boxUID);
   1553 			break;
   1554 			
   1555 		case kAudioPlugInPropertyDeviceList:
   1556 			//	Calculate the number of items that have been requested. Note that this
   1557 			//	number is allowed to be smaller than the actual size of the list. In such
   1558 			//	case, only that number of items will be returned
   1559 			theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID);
   1560 			
   1561 			//	Clamp that to the number of devices this driver implements (which is just 1 if the
   1562 			//	box has been acquired)
   1563 			if(theNumberItemsToFetch > (gBox_Acquired ? 2 : 0))
   1564 			{
   1565 				theNumberItemsToFetch = (gBox_Acquired ? 2 : 0);
   1566 			}
   1567 			
   1568 			//	Write the devices' object IDs into the return value
   1569 			if(theNumberItemsToFetch > 1)
   1570 			{
   1571 				((AudioObjectID*)outData)[0] = kObjectID_Device;
   1572                 ((AudioObjectID*)outData)[1] = kObjectID_Device2;
   1573 			}
   1574             else if(theNumberItemsToFetch > 0)
   1575             {
   1576                 ((AudioObjectID*)outData)[0] = kObjectID_Device;
   1577             }
   1578 			
   1579 			//	Return how many bytes we wrote to
   1580 			*outDataSize = theNumberItemsToFetch * sizeof(AudioClassID);
   1581 			break;
   1582 			
   1583 		case kAudioPlugInPropertyTranslateUIDToDevice:
   1584 			//	This property takes the CFString passed in the qualifier and converts that
   1585 			//	to the object ID of the device it corresponds to. For this driver, there is
   1586 			//	just the one device. Note that it is not an error if the string in the
   1587 			//	qualifier doesn't match any devices. In such case, kAudioObjectUnknown is
   1588 			//	the object ID to return.
   1589 			FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: not enough space for the return value of kAudioPlugInPropertyTranslateUIDToDevice");
   1590 			FailWithAction(inQualifierDataSize == sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: the qualifier is the wrong size for kAudioPlugInPropertyTranslateUIDToDevice");
   1591 			FailWithAction(inQualifierData == NULL, theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: no qualifier for kAudioPlugInPropertyTranslateUIDToDevice");
   1592             
   1593             
   1594 			
   1595 			CFStringRef deviceUID = get_device_uid();
   1596             CFStringRef device2UID = get_device2_uid();
   1597 
   1598 			if(CFStringCompare(*((CFStringRef*)inQualifierData), deviceUID, 0) == kCFCompareEqualTo)
   1599 			{
   1600 				*((AudioObjectID*)outData) = kObjectID_Device;
   1601 			}
   1602             else if(CFStringCompare(*((CFStringRef*)inQualifierData), device2UID, 0) == kCFCompareEqualTo)
   1603             {
   1604                 *((AudioObjectID*)outData) = kObjectID_Device2;
   1605             }
   1606 			else
   1607 			{
   1608 				*((AudioObjectID*)outData) = kAudioObjectUnknown;
   1609 			}
   1610 			*outDataSize = sizeof(AudioObjectID);
   1611 			CFRelease(deviceUID);
   1612             CFRelease(device2UID);
   1613 			break;
   1614 			
   1615 		case kAudioPlugInPropertyResourceBundle:
   1616 			//	The resource bundle is a path relative to the path of the plug-in's bundle.
   1617 			//	To specify that the plug-in bundle itself should be used, we just return the
   1618 			//	empty string.
   1619 			FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetPlugInPropertyData: not enough space for the return value of kAudioPlugInPropertyResourceBundle");
   1620 			*((CFStringRef*)outData) = CFSTR("");
   1621 			*outDataSize = sizeof(CFStringRef);
   1622 			break;
   1623 			
   1624 		default:
   1625 			theAnswer = kAudioHardwareUnknownPropertyError;
   1626 			break;
   1627 	};
   1628 
   1629 Done:
   1630 	return theAnswer;
   1631 }
   1632 
   1633 static OSStatus	BlackHole_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])
   1634 {
   1635 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData, inDataSize, inData)
   1636 	
   1637 	//	declare the local variables
   1638 	OSStatus theAnswer = 0;
   1639 	
   1640 	//	check the arguments
   1641 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetPlugInPropertyData: bad driver reference");
   1642 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetPlugInPropertyData: no address");
   1643 	FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetPlugInPropertyData: no place to return the number of properties that changed");
   1644 	FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetPlugInPropertyData: no place to return the properties that changed");
   1645 	FailWithAction(inObjectID != kObjectID_PlugIn, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetPlugInPropertyData: not the plug-in object");
   1646 	
   1647 	//	initialize the returned number of changed properties
   1648 	*outNumberPropertiesChanged = 0;
   1649 	
   1650 	//	Note that for each object, this driver implements all the required properties plus a few
   1651 	//	extras that are useful but not required. There is more detailed commentary about each
   1652 	//	property in the BlackHole_GetPlugInPropertyData() method.
   1653 	switch(inAddress->mSelector)
   1654 	{
   1655 		default:
   1656 			theAnswer = kAudioHardwareUnknownPropertyError;
   1657 			break;
   1658 	};
   1659 
   1660 Done:
   1661 	return theAnswer;
   1662 }
   1663 
   1664 #pragma mark Box Property Operations
   1665 
   1666 static Boolean	BlackHole_HasBoxProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress)
   1667 {
   1668 	//	This method returns whether or not the box object has the given property.
   1669 	
   1670 	#pragma unused(inClientProcessID)
   1671 	
   1672 	//	declare the local variables
   1673 	Boolean theAnswer = false;
   1674 	
   1675 	//	check the arguments
   1676 	FailIf(inDriver != gAudioServerPlugInDriverRef, Done, "BlackHole_HasBoxProperty: bad driver reference");
   1677 	FailIf(inAddress == NULL, Done, "BlackHole_HasBoxProperty: no address");
   1678 	FailIf(inObjectID != kObjectID_Box, Done, "BlackHole_HasBoxProperty: not the box object");
   1679 	
   1680 	
   1681 	//	Note that for each object, this driver implements all the required properties plus a few
   1682 	//	extras that are useful but not required. There is more detailed commentary about each
   1683 	//	property in the BlackHole_GetBoxPropertyData() method.
   1684 	switch(inAddress->mSelector)
   1685 	{
   1686 		case kAudioObjectPropertyBaseClass:
   1687 		case kAudioObjectPropertyClass:
   1688 		case kAudioObjectPropertyOwner:
   1689 		case kAudioObjectPropertyName:
   1690 		case kAudioObjectPropertyModelName:
   1691 		case kAudioObjectPropertyManufacturer:
   1692 		case kAudioObjectPropertyOwnedObjects:
   1693 		case kAudioObjectPropertyIdentify:
   1694 		case kAudioObjectPropertySerialNumber:
   1695 		case kAudioObjectPropertyFirmwareVersion:
   1696 		case kAudioBoxPropertyBoxUID:
   1697 		case kAudioBoxPropertyTransportType:
   1698 		case kAudioBoxPropertyHasAudio:
   1699 		case kAudioBoxPropertyHasVideo:
   1700 		case kAudioBoxPropertyHasMIDI:
   1701 		case kAudioBoxPropertyIsProtected:
   1702 		case kAudioBoxPropertyAcquired:
   1703 		case kAudioBoxPropertyAcquisitionFailed:
   1704 		case kAudioBoxPropertyDeviceList:
   1705 			theAnswer = true;
   1706 			break;
   1707 	};
   1708 
   1709 Done:
   1710 	return theAnswer;
   1711 }
   1712 
   1713 static OSStatus	BlackHole_IsBoxPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable)
   1714 {
   1715 	//	This method returns whether or not the given property on the plug-in object can have its
   1716 	//	value changed.
   1717 	
   1718 	#pragma unused(inClientProcessID)
   1719 	
   1720 	//	declare the local variables
   1721 	OSStatus theAnswer = 0;
   1722 	
   1723 	//	check the arguments
   1724 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsBoxPropertySettable: bad driver reference");
   1725 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsBoxPropertySettable: no address");
   1726 	FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsBoxPropertySettable: no place to put the return value");
   1727 	FailWithAction(inObjectID != kObjectID_Box, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsBoxPropertySettable: not the plug-in object");
   1728 	
   1729 	//	Note that for each object, this driver implements all the required properties plus a few
   1730 	//	extras that are useful but not required. There is more detailed commentary about each
   1731 	//	property in the BlackHole_GetBoxPropertyData() method.
   1732 	switch(inAddress->mSelector)
   1733 	{
   1734 		case kAudioObjectPropertyBaseClass:
   1735 		case kAudioObjectPropertyClass:
   1736 		case kAudioObjectPropertyOwner:
   1737 		case kAudioObjectPropertyModelName:
   1738 		case kAudioObjectPropertyManufacturer:
   1739 		case kAudioObjectPropertyOwnedObjects:
   1740 		case kAudioObjectPropertySerialNumber:
   1741 		case kAudioObjectPropertyFirmwareVersion:
   1742 		case kAudioBoxPropertyBoxUID:
   1743 		case kAudioBoxPropertyTransportType:
   1744 		case kAudioBoxPropertyHasAudio:
   1745 		case kAudioBoxPropertyHasVideo:
   1746 		case kAudioBoxPropertyHasMIDI:
   1747 		case kAudioBoxPropertyIsProtected:
   1748 		case kAudioBoxPropertyAcquisitionFailed:
   1749 		case kAudioBoxPropertyDeviceList:
   1750 			*outIsSettable = false;
   1751 			break;
   1752 		
   1753 		case kAudioObjectPropertyName:
   1754 		case kAudioObjectPropertyIdentify:
   1755 		case kAudioBoxPropertyAcquired:
   1756 			*outIsSettable = true;
   1757 			break;
   1758 		
   1759 		default:
   1760 			theAnswer = kAudioHardwareUnknownPropertyError;
   1761 			break;
   1762 	};
   1763 
   1764 Done:
   1765 	return theAnswer;
   1766 }
   1767 
   1768 static OSStatus	BlackHole_GetBoxPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize)
   1769 {
   1770 	//	This method returns the byte size of the property's data.
   1771 	
   1772 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   1773 	
   1774 	//	declare the local variables
   1775 	OSStatus theAnswer = 0;
   1776 	
   1777 	//	check the arguments
   1778 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetBoxPropertyDataSize: bad driver reference");
   1779 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetBoxPropertyDataSize: no address");
   1780 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetBoxPropertyDataSize: no place to put the return value");
   1781 	FailWithAction(inObjectID != kObjectID_Box, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetBoxPropertyDataSize: not the plug-in object");
   1782 	
   1783 	//	Note that for each object, this driver implements all the required properties plus a few
   1784 	//	extras that are useful but not required. There is more detailed commentary about each
   1785 	//	property in the BlackHole_GetBoxPropertyData() method.
   1786 	switch(inAddress->mSelector)
   1787 	{
   1788 		case kAudioObjectPropertyBaseClass:
   1789 			*outDataSize = sizeof(AudioClassID);
   1790 			break;
   1791 			
   1792 		case kAudioObjectPropertyClass:
   1793 			*outDataSize = sizeof(AudioClassID);
   1794 			break;
   1795 			
   1796 		case kAudioObjectPropertyOwner:
   1797 			*outDataSize = sizeof(AudioObjectID);
   1798 			break;
   1799 			
   1800 		case kAudioObjectPropertyName:
   1801 			*outDataSize = sizeof(CFStringRef);
   1802 			break;
   1803 			
   1804 		case kAudioObjectPropertyModelName:
   1805 			*outDataSize = sizeof(CFStringRef);
   1806 			break;
   1807 			
   1808 		case kAudioObjectPropertyManufacturer:
   1809 			*outDataSize = sizeof(CFStringRef);
   1810 			break;
   1811 			
   1812 		case kAudioObjectPropertyOwnedObjects:
   1813 			*outDataSize = 0;
   1814 			break;
   1815 			
   1816 		case kAudioObjectPropertyIdentify:
   1817 			*outDataSize = sizeof(UInt32);
   1818 			break;
   1819 			
   1820 		case kAudioObjectPropertySerialNumber:
   1821 			*outDataSize = sizeof(CFStringRef);
   1822 			break;
   1823 			
   1824 		case kAudioObjectPropertyFirmwareVersion:
   1825 			*outDataSize = sizeof(CFStringRef);
   1826 			break;
   1827 			
   1828 		case kAudioBoxPropertyBoxUID:
   1829 			*outDataSize = sizeof(CFStringRef);
   1830 			break;
   1831 			
   1832 		case kAudioBoxPropertyTransportType:
   1833 			*outDataSize = sizeof(UInt32);
   1834 			break;
   1835 			
   1836 		case kAudioBoxPropertyHasAudio:
   1837 			*outDataSize = sizeof(UInt32);
   1838 			break;
   1839 			
   1840 		case kAudioBoxPropertyHasVideo:
   1841 			*outDataSize = sizeof(UInt32);
   1842 			break;
   1843 			
   1844 		case kAudioBoxPropertyHasMIDI:
   1845 			*outDataSize = sizeof(UInt32);
   1846 			break;
   1847 			
   1848 		case kAudioBoxPropertyIsProtected:
   1849 			*outDataSize = sizeof(UInt32);
   1850 			break;
   1851 			
   1852 		case kAudioBoxPropertyAcquired:
   1853 			*outDataSize = sizeof(UInt32);
   1854 			break;
   1855 			
   1856 		case kAudioBoxPropertyAcquisitionFailed:
   1857 			*outDataSize = sizeof(UInt32);
   1858 			break;
   1859 			
   1860 		case kAudioBoxPropertyDeviceList:
   1861 			{
   1862 				pthread_mutex_lock(&gPlugIn_StateMutex);
   1863 				*outDataSize = gBox_Acquired ? sizeof(AudioObjectID) * 2 : 0;
   1864 				pthread_mutex_unlock(&gPlugIn_StateMutex);
   1865 			}
   1866 			break;
   1867 			
   1868 		default:
   1869 			theAnswer = kAudioHardwareUnknownPropertyError;
   1870 			break;
   1871 	};
   1872 
   1873 Done:
   1874 	return theAnswer;
   1875 }
   1876 
   1877 static OSStatus	BlackHole_GetBoxPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData)
   1878 {
   1879 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   1880 	
   1881 	//	declare the local variables
   1882 	OSStatus theAnswer = 0;
   1883 	
   1884 	//	check the arguments
   1885 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetBoxPropertyData: bad driver reference");
   1886 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetBoxPropertyData: no address");
   1887 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetBoxPropertyData: no place to put the return value size");
   1888 	FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetBoxPropertyData: no place to put the return value");
   1889 	FailWithAction(inObjectID != kObjectID_Box, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetBoxPropertyData: not the plug-in object");
   1890 	
   1891 	//	Note that for each object, this driver implements all the required properties plus a few
   1892 	//	extras that are useful but not required.
   1893 	//
   1894 	//	Also, since most of the data that will get returned is static, there are few instances where
   1895 	//	it is necessary to lock the state mutex.
   1896 	switch(inAddress->mSelector)
   1897 	{
   1898 		case kAudioObjectPropertyBaseClass:
   1899 			//	The base class for kAudioBoxClassID is kAudioObjectClassID
   1900 			FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the box");
   1901 			*((AudioClassID*)outData) = kAudioObjectClassID;
   1902 			*outDataSize = sizeof(AudioClassID);
   1903 			break;
   1904 			
   1905 		case kAudioObjectPropertyClass:
   1906 			//	The class is always kAudioBoxClassID for regular drivers
   1907 			FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the box");
   1908 			*((AudioClassID*)outData) = kAudioBoxClassID;
   1909 			*outDataSize = sizeof(AudioClassID);
   1910 			break;
   1911 			
   1912 		case kAudioObjectPropertyOwner:
   1913 			//	The owner is the plug-in object
   1914 			FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the box");
   1915 			*((AudioObjectID*)outData) = kObjectID_PlugIn;
   1916 			*outDataSize = sizeof(AudioObjectID);
   1917 			break;
   1918 			
   1919 		case kAudioObjectPropertyName:
   1920 			//	This is the human readable name of the maker of the box.
   1921 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the box");
   1922 			pthread_mutex_lock(&gPlugIn_StateMutex);
   1923 			*((CFStringRef*)outData) = gBox_Name;
   1924 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   1925 			if(*((CFStringRef*)outData) != NULL)
   1926 			{
   1927 				CFRetain(*((CFStringRef*)outData));
   1928 			}
   1929 			*outDataSize = sizeof(CFStringRef);
   1930 			break;
   1931 			
   1932 		case kAudioObjectPropertyModelName:
   1933 			//	This is the human readable name of the maker of the box.
   1934 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the box");
   1935 			*((CFStringRef*)outData) = CFSTR("BlackHole");
   1936 			*outDataSize = sizeof(CFStringRef);
   1937 			break;
   1938 			
   1939 		case kAudioObjectPropertyManufacturer:
   1940 			//	This is the human readable name of the maker of the box.
   1941 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the box");
   1942 			*((CFStringRef*)outData) = CFSTR("Existential Audio Inc.");
   1943 			*outDataSize = sizeof(CFStringRef);
   1944 			break;
   1945 			
   1946 		case kAudioObjectPropertyOwnedObjects:
   1947 			//	This returns the objects directly owned by the object. Boxes don't own anything.
   1948 			*outDataSize = 0;
   1949 			break;
   1950 			
   1951 		case kAudioObjectPropertyIdentify:
   1952 			//	This is used to highling the device in the UI, but it's value has no meaning
   1953 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyIdentify for the box");
   1954 			*((UInt32*)outData) = 0;
   1955 			*outDataSize = sizeof(UInt32);
   1956 			break;
   1957 			
   1958 		case kAudioObjectPropertySerialNumber:
   1959 			//	This is the human readable serial number of the box.
   1960 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertySerialNumber for the box");
   1961 			*((CFStringRef*)outData) = CFSTR("dd658747-4b9a-4de8-a001-c6a2ef1bb235");
   1962 			*outDataSize = sizeof(CFStringRef);
   1963 			break;
   1964 			
   1965 		case kAudioObjectPropertyFirmwareVersion:
   1966 			//	This is the human readable firmware version of the box.
   1967 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyFirmwareVersion for the box");
   1968 			*((CFStringRef*)outData) = CFSTR("0.5.1");
   1969 			*outDataSize = sizeof(CFStringRef);
   1970 			break;
   1971 			
   1972 		case kAudioBoxPropertyBoxUID:
   1973 			//	Boxes have UIDs the same as devices
   1974 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the box");
   1975 
   1976 			*((CFStringRef*)outData) = get_box_uid();
   1977 			break;
   1978 			
   1979 		case kAudioBoxPropertyTransportType:
   1980 			//	This value represents how the device is attached to the system. This can be
   1981 			//	any 32 bit integer, but common values for this property are defined in
   1982 			//	<CoreAudio/AudioHardwareBase.h>
   1983 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioDevicePropertyTransportType for the box");
   1984 			*((UInt32*)outData) = kAudioDeviceTransportTypeVirtual;
   1985 			*outDataSize = sizeof(UInt32);
   1986 			break;
   1987 			
   1988 		case kAudioBoxPropertyHasAudio:
   1989 			//	Indicates whether or not the box has audio capabilities
   1990 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyHasAudio for the box");
   1991 			*((UInt32*)outData) = 1;
   1992 			*outDataSize = sizeof(UInt32);
   1993 			break;
   1994 			
   1995 		case kAudioBoxPropertyHasVideo:
   1996 			//	Indicates whether or not the box has video capabilities
   1997 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyHasVideo for the box");
   1998 			*((UInt32*)outData) = 0;
   1999 			*outDataSize = sizeof(UInt32);
   2000 			break;
   2001 			
   2002 		case kAudioBoxPropertyHasMIDI:
   2003 			//	Indicates whether or not the box has MIDI capabilities
   2004 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyHasMIDI for the box");
   2005 			*((UInt32*)outData) = 0;
   2006 			*outDataSize = sizeof(UInt32);
   2007 			break;
   2008 			
   2009 		case kAudioBoxPropertyIsProtected:
   2010 			//	Indicates whether or not the box has requires authentication to use
   2011 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyIsProtected for the box");
   2012 			*((UInt32*)outData) = 0;
   2013 			*outDataSize = sizeof(UInt32);
   2014 			break;
   2015 			
   2016 		case kAudioBoxPropertyAcquired:
   2017 			//	When set to a non-zero value, the device is acquired for use by the local machine
   2018 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyAcquired for the box");
   2019 			pthread_mutex_lock(&gPlugIn_StateMutex);
   2020 			*((UInt32*)outData) = gBox_Acquired ? 1 : 0;
   2021 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   2022 			*outDataSize = sizeof(UInt32);
   2023 			break;
   2024 			
   2025 		case kAudioBoxPropertyAcquisitionFailed:
   2026 			//	This is used for notifications to say when an attempt to acquire a device has failed.
   2027 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetBoxPropertyData: not enough space for the return value of kAudioBoxPropertyAcquisitionFailed for the box");
   2028 			*((UInt32*)outData) = 0;
   2029 			*outDataSize = sizeof(UInt32);
   2030 			break;
   2031 			
   2032 		case kAudioBoxPropertyDeviceList:
   2033 			//	This is used to indicate which devices came from this box
   2034 			pthread_mutex_lock(&gPlugIn_StateMutex);
   2035 			if(gBox_Acquired)
   2036 			{
   2037                 if(inDataSize < sizeof(AudioObjectID))
   2038                 {
   2039                     theAnswer = kAudioHardwareBadPropertySizeError;
   2040                     *outDataSize = 0;
   2041                 }
   2042                 else
   2043                 {
   2044                     if (inDataSize >= sizeof(AudioObjectID) * 2)
   2045                     {
   2046                         ((AudioObjectID*)outData)[0] = kObjectID_Device;
   2047                         ((AudioObjectID*)outData)[1] = kObjectID_Device2;
   2048                         *outDataSize = sizeof(AudioObjectID) * 2;
   2049                     }
   2050                     else
   2051                     {
   2052                         ((AudioObjectID*)outData)[0] = kObjectID_Device;
   2053                         *outDataSize = sizeof(AudioObjectID) * 1;
   2054                     }
   2055                 }
   2056 			}
   2057 			else
   2058 			{
   2059 				*outDataSize = 0;
   2060 			}
   2061             
   2062 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   2063 			break;
   2064 			
   2065 		default:
   2066 			theAnswer = kAudioHardwareUnknownPropertyError;
   2067 			break;
   2068 	};
   2069 
   2070 Done:
   2071 	return theAnswer;
   2072 }
   2073 
   2074 static OSStatus	BlackHole_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])
   2075 {
   2076 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData, inDataSize, inData)
   2077 	
   2078 	//	declare the local variables
   2079 	OSStatus theAnswer = 0;
   2080 	
   2081 	//	check the arguments
   2082 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetBoxPropertyData: bad driver reference");
   2083 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetBoxPropertyData: no address");
   2084 	FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetBoxPropertyData: no place to return the number of properties that changed");
   2085 	FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetBoxPropertyData: no place to return the properties that changed");
   2086 	FailWithAction(inObjectID != kObjectID_Box, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetBoxPropertyData: not the box object");
   2087 	
   2088 	//	initialize the returned number of changed properties
   2089 	*outNumberPropertiesChanged = 0;
   2090 	
   2091 	//	Note that for each object, this driver implements all the required properties plus a few
   2092 	//	extras that are useful but not required. There is more detailed commentary about each
   2093 	//	property in the BlackHole_GetPlugInPropertyData() method.
   2094 	switch(inAddress->mSelector)
   2095 	{
   2096 		case kAudioObjectPropertyName:
   2097 			//	Boxes should allow their name to be editable
   2098 			{
   2099 				FailWithAction(inData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetBoxPropertyData: NULL data for kAudioObjectPropertyName");
   2100 				FailWithAction(inDataSize != sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetBoxPropertyData: wrong size for the data for kAudioObjectPropertyName");
   2101 				CFStringRef* theNewName = (CFStringRef*)inData;
   2102 				pthread_mutex_lock(&gPlugIn_StateMutex);
   2103 				if((theNewName != NULL) && (*theNewName != NULL))
   2104 				{
   2105 					CFRetain(*theNewName);
   2106 				}
   2107 				if(gBox_Name != NULL)
   2108 				{
   2109 					CFRelease(gBox_Name);
   2110 				}
   2111 				gBox_Name = *theNewName;
   2112 				pthread_mutex_unlock(&gPlugIn_StateMutex);
   2113 				*outNumberPropertiesChanged = 1;
   2114 				outChangedAddresses[0].mSelector = kAudioObjectPropertyName;
   2115 				outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   2116 				outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   2117 			}
   2118 			break;
   2119 			
   2120 		case kAudioObjectPropertyIdentify:
   2121 			//	since we don't have any actual hardware to flash, we will schedule a notification for
   2122 			//	this property off into the future as a testing thing. Note that a real implementation
   2123 			//	of this property should only send the notification if the hardware wants the app to
   2124 			//	flash it's UI for the device.
   2125 			{
   2126 				syslog(LOG_NOTICE, "The identify property has been set on the Box implemented by the BlackHole driver.");
   2127 				FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetBoxPropertyData: wrong size for the data for kAudioObjectPropertyIdentify");
   2128 				dispatch_after(dispatch_time(0, 2ULL * 1000ULL * 1000ULL * 1000ULL), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),	^()
   2129 																																		{
   2130 																																			AudioObjectPropertyAddress theAddress = { kAudioObjectPropertyIdentify, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain };
   2131 																																			gPlugIn_Host->PropertiesChanged(gPlugIn_Host, kObjectID_Box, 1, &theAddress);
   2132 																																		});
   2133 			}
   2134 			break;
   2135 			
   2136 		case kAudioBoxPropertyAcquired:
   2137 			//	When the box is acquired, it means the contents, namely the device, are available to the system
   2138 			{
   2139 				FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetBoxPropertyData: wrong size for the data for kAudioBoxPropertyAcquired");
   2140 				pthread_mutex_lock(&gPlugIn_StateMutex);
   2141 				if(gBox_Acquired != (*((UInt32*)inData) != 0))
   2142 				{
   2143 					//	the new value is different from the old value, so save it
   2144 					gBox_Acquired = *((UInt32*)inData) != 0;
   2145 					gPlugIn_Host->WriteToStorage(gPlugIn_Host, CFSTR("box acquired"), gBox_Acquired ? kCFBooleanTrue : kCFBooleanFalse);
   2146 					
   2147 					//	and it means that this property and the device list property have changed
   2148 					*outNumberPropertiesChanged = 2;
   2149 					outChangedAddresses[0].mSelector = kAudioBoxPropertyAcquired;
   2150 					outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   2151 					outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   2152 					outChangedAddresses[1].mSelector = kAudioBoxPropertyDeviceList;
   2153 					outChangedAddresses[1].mScope = kAudioObjectPropertyScopeGlobal;
   2154 					outChangedAddresses[1].mElement = kAudioObjectPropertyElementMain;
   2155 					
   2156 					//	but it also means that the device list has changed for the plug-in too
   2157 					dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),	^()
   2158 																									{
   2159 																										AudioObjectPropertyAddress theAddress = { kAudioPlugInPropertyDeviceList, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain };
   2160 																										gPlugIn_Host->PropertiesChanged(gPlugIn_Host, kObjectID_PlugIn, 1, &theAddress);
   2161 																									});
   2162 				}
   2163 				pthread_mutex_unlock(&gPlugIn_StateMutex);
   2164 			}
   2165 			break;
   2166 			
   2167 		default:
   2168 			theAnswer = kAudioHardwareUnknownPropertyError;
   2169 			break;
   2170 	};
   2171 
   2172 Done:
   2173 	return theAnswer;
   2174 }
   2175 
   2176 #pragma mark Device Property Operations
   2177 
   2178 static Boolean	BlackHole_HasDeviceProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress)
   2179 {
   2180 	//	This method returns whether or not the given object has the given property.
   2181 	
   2182 	#pragma unused(inClientProcessID)
   2183 	
   2184 	//	declare the local variables
   2185 	Boolean theAnswer = false;
   2186 	
   2187 	//	check the arguments
   2188 	FailIf(inDriver != gAudioServerPlugInDriverRef, Done, "BlackHole_HasDeviceProperty: bad driver reference");
   2189 	FailIf(inAddress == NULL, Done, "BlackHole_HasDeviceProperty: no address");
   2190 	FailIf(inObjectID != kObjectID_Device && inObjectID != kObjectID_Device2, Done, "BlackHole_HasDeviceProperty: not the device object");
   2191 	
   2192 	//	Note that for each object, this driver implements all the required properties plus a few
   2193 	//	extras that are useful but not required. There is more detailed commentary about each
   2194 	//	property in the BlackHole_GetDevicePropertyData() method.
   2195 	switch(inAddress->mSelector)
   2196 	{
   2197 		case kAudioObjectPropertyBaseClass:
   2198 		case kAudioObjectPropertyClass:
   2199 		case kAudioObjectPropertyOwner:
   2200 		case kAudioObjectPropertyName:
   2201 		case kAudioObjectPropertyManufacturer:
   2202 		case kAudioObjectPropertyOwnedObjects:
   2203 		case kAudioDevicePropertyDeviceUID:
   2204 		case kAudioDevicePropertyModelUID:
   2205 		case kAudioDevicePropertyTransportType:
   2206 		case kAudioDevicePropertyRelatedDevices:
   2207 		case kAudioDevicePropertyClockDomain:
   2208 		case kAudioDevicePropertyDeviceIsAlive:
   2209 		case kAudioDevicePropertyDeviceIsRunning:
   2210 		case kAudioObjectPropertyControlList:
   2211 		case kAudioDevicePropertyNominalSampleRate:
   2212 		case kAudioDevicePropertyAvailableNominalSampleRates:
   2213 		case kAudioDevicePropertyIsHidden:
   2214 		case kAudioDevicePropertyZeroTimeStampPeriod:
   2215 		case kAudioDevicePropertyIcon:
   2216 		case kAudioDevicePropertyStreams:
   2217 			theAnswer = true;
   2218 			break;
   2219 			
   2220 		case kAudioDevicePropertyDeviceCanBeDefaultDevice:
   2221 		case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
   2222 		case kAudioDevicePropertyLatency:
   2223 		case kAudioDevicePropertySafetyOffset:
   2224 		case kAudioDevicePropertyPreferredChannelsForStereo:
   2225 		case kAudioDevicePropertyPreferredChannelLayout:
   2226 			theAnswer = (inAddress->mScope == kAudioObjectPropertyScopeInput) || (inAddress->mScope == kAudioObjectPropertyScopeOutput);
   2227 			break;
   2228 	};
   2229 
   2230 Done:
   2231 	return theAnswer;
   2232 }
   2233 
   2234 static OSStatus	BlackHole_IsDevicePropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable)
   2235 {
   2236 	//	This method returns whether or not the given property on the object can have its value
   2237 	//	changed.
   2238 	
   2239 	#pragma unused(inClientProcessID)
   2240 	
   2241 	//	declare the local variables
   2242 	OSStatus theAnswer = 0;
   2243 	
   2244 	//	check the arguments
   2245 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsDevicePropertySettable: bad driver reference");
   2246 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsDevicePropertySettable: no address");
   2247 	FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsDevicePropertySettable: no place to put the return value");
   2248 	FailWithAction(inObjectID != kObjectID_Device && inObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsDevicePropertySettable: not the device object");
   2249 	
   2250 	//	Note that for each object, this driver implements all the required properties plus a few
   2251 	//	extras that are useful but not required. There is more detailed commentary about each
   2252 	//	property in the BlackHole_GetDevicePropertyData() method.
   2253 	switch(inAddress->mSelector)
   2254 	{
   2255 		case kAudioObjectPropertyBaseClass:
   2256 		case kAudioObjectPropertyClass:
   2257 		case kAudioObjectPropertyOwner:
   2258 		case kAudioObjectPropertyName:
   2259 		case kAudioObjectPropertyManufacturer:
   2260 		case kAudioObjectPropertyOwnedObjects:
   2261 		case kAudioDevicePropertyDeviceUID:
   2262 		case kAudioDevicePropertyModelUID:
   2263 		case kAudioDevicePropertyTransportType:
   2264 		case kAudioDevicePropertyRelatedDevices:
   2265 		case kAudioDevicePropertyClockDomain:
   2266 		case kAudioDevicePropertyDeviceIsAlive:
   2267 		case kAudioDevicePropertyDeviceIsRunning:
   2268 		case kAudioDevicePropertyDeviceCanBeDefaultDevice:
   2269 		case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
   2270 		case kAudioDevicePropertyLatency:
   2271 		case kAudioDevicePropertyStreams:
   2272 		case kAudioObjectPropertyControlList:
   2273 		case kAudioDevicePropertySafetyOffset:
   2274 		case kAudioDevicePropertyAvailableNominalSampleRates:
   2275 		case kAudioDevicePropertyIsHidden:
   2276 		case kAudioDevicePropertyPreferredChannelsForStereo:
   2277 		case kAudioDevicePropertyPreferredChannelLayout:
   2278 		case kAudioDevicePropertyZeroTimeStampPeriod:
   2279 		case kAudioDevicePropertyIcon:
   2280 			*outIsSettable = false;
   2281 			break;
   2282 		
   2283 		case kAudioDevicePropertyNominalSampleRate:
   2284 			*outIsSettable = true;
   2285 			break;
   2286 		
   2287 		default:
   2288 			theAnswer = kAudioHardwareUnknownPropertyError;
   2289 			break;
   2290 	};
   2291 
   2292 Done:
   2293 	return theAnswer;
   2294 }
   2295 
   2296 static OSStatus	BlackHole_GetDevicePropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize)
   2297 {
   2298 	//	This method returns the byte size of the property's data.
   2299 	
   2300 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   2301 	
   2302 	//	declare the local variables
   2303 	OSStatus theAnswer = 0;
   2304 	
   2305 	//	check the arguments
   2306 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetDevicePropertyDataSize: bad driver reference");
   2307 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetDevicePropertyDataSize: no address");
   2308 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetDevicePropertyDataSize: no place to put the return value");
   2309 	FailWithAction(inObjectID != kObjectID_Device && inObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetDevicePropertyDataSize: not the device object");
   2310 	
   2311 	//	Note that for each object, this driver implements all the required properties plus a few
   2312 	//	extras that are useful but not required. There is more detailed commentary about each
   2313 	//	property in the BlackHole_GetDevicePropertyData() method.
   2314 	switch(inAddress->mSelector)
   2315 	{
   2316 		case kAudioObjectPropertyBaseClass:
   2317 			*outDataSize = sizeof(AudioClassID);
   2318 			break;
   2319 			
   2320 		case kAudioObjectPropertyClass:
   2321 			*outDataSize = sizeof(AudioClassID);
   2322 			break;
   2323 			
   2324 		case kAudioObjectPropertyOwner:
   2325 			*outDataSize = sizeof(AudioObjectID);
   2326 			break;
   2327 			
   2328 		case kAudioObjectPropertyName:
   2329 			*outDataSize = sizeof(CFStringRef);
   2330 			break;
   2331 			
   2332 		case kAudioObjectPropertyManufacturer:
   2333 			*outDataSize = sizeof(CFStringRef);
   2334 			break;
   2335 			
   2336 		case kAudioObjectPropertyOwnedObjects:
   2337             *outDataSize = device_object_list_size(inAddress->mScope, inObjectID) * sizeof(AudioObjectID);
   2338 			break;
   2339 
   2340 		case kAudioDevicePropertyDeviceUID:
   2341 			*outDataSize = sizeof(CFStringRef);
   2342 			break;
   2343 
   2344 		case kAudioDevicePropertyModelUID:
   2345 			*outDataSize = sizeof(CFStringRef);
   2346 			break;
   2347 
   2348 		case kAudioDevicePropertyTransportType:
   2349 			*outDataSize = sizeof(UInt32);
   2350 			break;
   2351 
   2352 		case kAudioDevicePropertyRelatedDevices:
   2353 			*outDataSize = sizeof(AudioObjectID);
   2354 			break;
   2355 
   2356 		case kAudioDevicePropertyClockDomain:
   2357 			*outDataSize = sizeof(UInt32);
   2358 			break;
   2359 
   2360 		case kAudioDevicePropertyDeviceIsAlive:
   2361 			*outDataSize = sizeof(AudioClassID);
   2362 			break;
   2363 
   2364 		case kAudioDevicePropertyDeviceIsRunning:
   2365 			*outDataSize = sizeof(UInt32);
   2366 			break;
   2367 
   2368 		case kAudioDevicePropertyDeviceCanBeDefaultDevice:
   2369 			*outDataSize = sizeof(UInt32);
   2370 			break;
   2371 
   2372 		case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
   2373 			*outDataSize = sizeof(UInt32);
   2374 			break;
   2375 
   2376 		case kAudioDevicePropertyLatency:
   2377 			*outDataSize = sizeof(UInt32);
   2378 			break;
   2379 
   2380 		case kAudioDevicePropertyStreams:
   2381             *outDataSize = device_stream_list_size(inAddress->mScope, inObjectID) * sizeof(AudioObjectID);
   2382 			break;
   2383 
   2384 		case kAudioObjectPropertyControlList:
   2385             *outDataSize = device_control_list_size(inAddress->mScope, inObjectID) * sizeof(AudioObjectID);
   2386 			break;
   2387 
   2388 		case kAudioDevicePropertySafetyOffset:
   2389 			*outDataSize = sizeof(UInt32);
   2390 			break;
   2391 
   2392 		case kAudioDevicePropertyNominalSampleRate:
   2393 			*outDataSize = sizeof(Float64);
   2394 			break;
   2395 
   2396 		case kAudioDevicePropertyAvailableNominalSampleRates:
   2397 			*outDataSize = kDevice_SampleRatesSize * sizeof(AudioValueRange);
   2398 			break;
   2399 		
   2400 		case kAudioDevicePropertyIsHidden:
   2401 			*outDataSize = sizeof(UInt32);
   2402 			break;
   2403 
   2404 		case kAudioDevicePropertyPreferredChannelsForStereo:
   2405 			*outDataSize = 2 * sizeof(UInt32);
   2406 			break;
   2407 
   2408 		case kAudioDevicePropertyPreferredChannelLayout:
   2409 			*outDataSize = offsetof(AudioChannelLayout, mChannelDescriptions) + (kNumber_Of_Channels * sizeof(AudioChannelDescription));
   2410 			break;
   2411 
   2412 		case kAudioDevicePropertyZeroTimeStampPeriod:
   2413 			*outDataSize = sizeof(UInt32);
   2414 			break;
   2415 
   2416 		case kAudioDevicePropertyIcon:
   2417 			*outDataSize = sizeof(CFURLRef);
   2418 			break;
   2419 
   2420 		default:
   2421 			theAnswer = kAudioHardwareUnknownPropertyError;
   2422 			break;
   2423 	};
   2424 
   2425 Done:
   2426 	return theAnswer;
   2427 }
   2428 
   2429 static OSStatus	BlackHole_GetDevicePropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData)
   2430 {
   2431 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   2432 	
   2433 	//	declare the local variables
   2434 	OSStatus theAnswer = 0;
   2435 	UInt32 theNumberItemsToFetch;
   2436 	UInt32 theItemIndex;
   2437 	
   2438 	//	check the arguments
   2439 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetDevicePropertyData: bad driver reference");
   2440 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetDevicePropertyData: no address");
   2441 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetDevicePropertyData: no place to put the return value size");
   2442 	FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetDevicePropertyData: no place to put the return value");
   2443 	FailWithAction(inObjectID != kObjectID_Device && inObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetDevicePropertyData: not the device object");
   2444 	
   2445 	//	Note that for each object, this driver implements all the required properties plus a few
   2446 	//	extras that are useful but not required.
   2447 	//
   2448 	//	Also, since most of the data that will get returned is static, there are few instances where
   2449 	//	it is necessary to lock the state mutex.
   2450 	switch(inAddress->mSelector)
   2451 	{
   2452 		case kAudioObjectPropertyBaseClass:
   2453 			//	The base class for kAudioDeviceClassID is kAudioObjectClassID
   2454 			FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the device");
   2455 			*((AudioClassID*)outData) = kAudioObjectClassID;
   2456 			*outDataSize = sizeof(AudioClassID);
   2457 			break;
   2458 			
   2459 		case kAudioObjectPropertyClass:
   2460 			//	The class is always kAudioDeviceClassID for devices created by drivers
   2461 			FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyClass for the device");
   2462 			*((AudioClassID*)outData) = kAudioDeviceClassID;
   2463 			*outDataSize = sizeof(AudioClassID);
   2464 			break;
   2465 			
   2466 		case kAudioObjectPropertyOwner:
   2467 			//	The device's owner is the plug-in object
   2468 			FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the device");
   2469 			*((AudioObjectID*)outData) = kObjectID_PlugIn;
   2470 			*outDataSize = sizeof(AudioObjectID);
   2471 			break;
   2472 			
   2473 		case kAudioObjectPropertyName:
   2474 			//	This is the human readable name of the device.
   2475 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the device");
   2476             
   2477             switch (inObjectID) {
   2478                 case kObjectID_Device:
   2479                     *((CFStringRef*)outData) = get_device_name();
   2480                     *outDataSize = sizeof(CFStringRef);
   2481                     break;
   2482                     
   2483                 case kObjectID_Device2:
   2484                     *((CFStringRef*)outData) = get_device2_name();
   2485                     *outDataSize = sizeof(CFStringRef);
   2486                     break;
   2487             }
   2488 			break;
   2489 			
   2490 		case kAudioObjectPropertyManufacturer:
   2491 			//	This is the human readable name of the maker of the plug-in.
   2492 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioObjectPropertyManufacturer for the device");
   2493 			*((CFStringRef*)outData) = CFSTR(kManufacturer_Name);
   2494 			*outDataSize = sizeof(CFStringRef);
   2495 			break;
   2496 			
   2497 		case kAudioObjectPropertyOwnedObjects:
   2498 			//	Calculate the number of items that have been requested. Note that this
   2499 			//	number is allowed to be smaller than the actual size of the list. In such
   2500 			//	case, only that number of items will be returned
   2501             theNumberItemsToFetch = minimum(inDataSize / sizeof(AudioObjectID), device_object_list_size(inAddress->mScope, inObjectID));
   2502 
   2503             //    fill out the list with the right objects
   2504             switch (inObjectID) {
   2505                 case kObjectID_Device:
   2506                     for (UInt32 i = 0, k = 0; k < theNumberItemsToFetch; i++)
   2507                     {
   2508                         if (kDevice_ObjectList[i].scope == inAddress->mScope || inAddress->mScope == kAudioObjectPropertyScopeGlobal)
   2509                         {
   2510                             ((AudioObjectID*)outData)[k++] = kDevice_ObjectList[i].id;
   2511                         }
   2512                     }
   2513                     break;
   2514 
   2515                 case kObjectID_Device2:
   2516                     for (UInt32 i = 0, k = 0; k < theNumberItemsToFetch; i++)
   2517                     {
   2518                         if (kDevice2_ObjectList[i].scope == inAddress->mScope || inAddress->mScope == kAudioObjectPropertyScopeGlobal)
   2519                         {
   2520                             ((AudioObjectID*)outData)[k++] = kDevice2_ObjectList[i].id;
   2521                         }
   2522                     }
   2523                     break;
   2524             }
   2525 
   2526 			//	report how much we wrote
   2527 			*outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID);
   2528 			break;
   2529 
   2530 		case kAudioDevicePropertyDeviceUID:
   2531 			//	This is a CFString that is a persistent token that can identify the same
   2532 			//	audio device across boot sessions. Note that two instances of the same
   2533 			//	device must have different values for this property.
   2534 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceUID for the device");
   2535 
   2536             switch (inObjectID) {
   2537                 case kObjectID_Device:
   2538                     *((CFStringRef*)outData) = get_device_uid();
   2539                     *outDataSize = sizeof(CFStringRef);
   2540                     break;
   2541                     
   2542                 case kObjectID_Device2:
   2543                     *((CFStringRef*)outData) = get_device2_uid();
   2544                     *outDataSize = sizeof(CFStringRef);
   2545                     break;
   2546             }
   2547             
   2548 
   2549 			break;
   2550 
   2551 		case kAudioDevicePropertyModelUID:
   2552 			//	This is a CFString that is a persistent token that can identify audio
   2553 			//	devices that are the same kind of device. Note that two instances of the
   2554 			//	save device must have the same value for this property.
   2555 			FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyModelUID for the device");
   2556 
   2557             *((CFStringRef*)outData) = get_device_model_uid();
   2558 			*outDataSize = sizeof(CFStringRef);
   2559 			break;
   2560 
   2561 		case kAudioDevicePropertyTransportType:
   2562 			//	This value represents how the device is attached to the system. This can be
   2563 			//	any 32 bit integer, but common values for this property are defined in
   2564 			//	<CoreAudio/AudioHardwareBase.h>
   2565 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyTransportType for the device");
   2566 			*((UInt32*)outData) = kAudioDeviceTransportTypeVirtual;
   2567 			*outDataSize = sizeof(UInt32);
   2568 			break;
   2569 
   2570 		case kAudioDevicePropertyRelatedDevices:
   2571 			//	The related devices property identifys device objects that are very closely
   2572 			//	related. Generally, this is for relating devices that are packaged together
   2573 			//	in the hardware such as when the input side and the output side of a piece
   2574 			//	of hardware can be clocked separately and therefore need to be represented
   2575 			//	as separate AudioDevice objects. In such case, both devices would report
   2576 			//	that they are related to each other. Note that at minimum, a device is
   2577 			//	related to itself, so this list will always be at least one item long.
   2578 
   2579 			//	Calculate the number of items that have been requested. Note that this
   2580 			//	number is allowed to be smaller than the actual size of the list. In such
   2581 			//	case, only that number of items will be returned
   2582 			theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID);
   2583 			
   2584 			//	we only have the one device...
   2585 			if(theNumberItemsToFetch > 1)
   2586 			{
   2587 				theNumberItemsToFetch = 1;
   2588 			}
   2589 			
   2590 			//	Write the devices' object IDs into the return value
   2591 			if(theNumberItemsToFetch > 0)
   2592 			{
   2593                 switch (inObjectID) {
   2594                     case kObjectID_Device:
   2595                         ((AudioObjectID*)outData)[0] = kObjectID_Device;
   2596                         break;
   2597                         
   2598                     case kObjectID_Device2:
   2599                         ((AudioObjectID*)outData)[0] = kObjectID_Device2;
   2600                         break;
   2601                 }
   2602 				
   2603 			}
   2604 			
   2605 			//	report how much we wrote
   2606 			*outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID);
   2607 			break;
   2608 
   2609 		case kAudioDevicePropertyClockDomain:
   2610 			//	This property allows the device to declare what other devices it is
   2611 			//	synchronized with in hardware. The way it works is that if two devices have
   2612 			//	the same value for this property and the value is not zero, then the two
   2613 			//	devices are synchronized in hardware. Note that a device that either can't
   2614 			//	be synchronized with others or doesn't know should return 0 for this
   2615 			//	property.
   2616 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyClockDomain for the device");
   2617 			*((UInt32*)outData) = 0;
   2618 			*outDataSize = sizeof(UInt32);
   2619 			break;
   2620 
   2621 		case kAudioDevicePropertyDeviceIsAlive:
   2622 			//	This property returns whether or not the device is alive. Note that it is
   2623 			//	not uncommon for a device to be dead but still momentarily available in the
   2624 			//	device list. In the case of this device, it will always be alive.
   2625 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceIsAlive for the device");
   2626 			*((UInt32*)outData) = 1;
   2627 			*outDataSize = sizeof(UInt32);
   2628 			break;
   2629 
   2630         case kAudioDevicePropertyDeviceIsRunning:
   2631             //    This property returns whether or not IO is running for the device. Note that
   2632             //    we need to take both the state lock to check this value for thread safety.
   2633             FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceIsRunning for the device");
   2634             pthread_mutex_lock(&gPlugIn_StateMutex);
   2635             if (inObjectID == kObjectID_Device) {
   2636                 *((UInt32*)outData) = ((gDevice_IOIsRunning > 0) > 0) ? 1 : 0;
   2637             }
   2638             
   2639             switch (inObjectID) {
   2640                 case kObjectID_Device:
   2641                     *((UInt32*)outData) = ((gDevice_IOIsRunning > 0) > 0) ? 1 : 0;
   2642                     break;
   2643                 case kObjectID_Device2:
   2644                     *((UInt32*)outData) = ((gDevice2_IOIsRunning > 0) > 0) ? 1 : 0;
   2645                     break;
   2646                 default:
   2647                     *((UInt32*)outData) = 0;
   2648                     break;
   2649             }
   2650             
   2651             pthread_mutex_unlock(&gPlugIn_StateMutex);
   2652             *outDataSize = sizeof(UInt32);
   2653             break;
   2654 
   2655 		case kAudioDevicePropertyDeviceCanBeDefaultDevice:
   2656 			//	This property returns whether or not the device wants to be able to be the
   2657 			//	default device for content. This is the device that iTunes and QuickTime
   2658 			//	will use to play their content on and FaceTime will use as it's microhphone.
   2659 			//	Nearly all devices should allow for this.
   2660 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceCanBeDefaultDevice for the device");
   2661 			*((UInt32*)outData) = kCanBeDefaultDevice;
   2662 			*outDataSize = sizeof(UInt32);
   2663 			break;
   2664 
   2665 		case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
   2666 			//	This property returns whether or not the device wants to be the system
   2667 			//	default device. This is the device that is used to play interface sounds and
   2668 			//	other incidental or UI-related sounds on. Most devices should allow this
   2669 			//	although devices with lots of latency may not want to.
   2670 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceCanBeDefaultSystemDevice for the device");
   2671 			*((UInt32*)outData) = kCanBeDefaultSystemDevice;
   2672 			*outDataSize = sizeof(UInt32);
   2673 			break;
   2674 
   2675 		case kAudioDevicePropertyLatency:
   2676 			//	This property returns the presentation latency of the device. For this,
   2677 			//	device, the value is 0 due to the fact that it always vends silence.
   2678 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyLatency for the device");
   2679 			*((UInt32*)outData) = 0;
   2680 			*outDataSize = sizeof(UInt32);
   2681 			break;
   2682 
   2683 		case kAudioDevicePropertyStreams:
   2684 			//	Calculate the number of items that have been requested. Note that this
   2685 			//	number is allowed to be smaller than the actual size of the list. In such
   2686 			//	case, only that number of items will be returned
   2687             theNumberItemsToFetch = minimum(inDataSize / sizeof(AudioObjectID), device_stream_list_size(inAddress->mScope, inObjectID));
   2688 
   2689             //    fill out the list with as many objects as requested
   2690             switch (inObjectID) {
   2691                 case kObjectID_Device:
   2692                     for (UInt32 i = 0, k = 0; k < theNumberItemsToFetch; i++)
   2693                     {
   2694                         if ((kDevice_ObjectList[i].type == kObjectType_Stream) &&
   2695                             (kDevice_ObjectList[i].scope == inAddress->mScope || inAddress->mScope == kAudioObjectPropertyScopeGlobal))
   2696                         {
   2697                             ((AudioObjectID*)outData)[k++] = kDevice_ObjectList[i].id;
   2698                         }
   2699                     }
   2700                     break;
   2701 
   2702                 case kObjectID_Device2:
   2703                     for (UInt32 i = 0, k = 0; k < theNumberItemsToFetch; i++)
   2704                     {
   2705                         if ((kDevice2_ObjectList[i].type == kObjectType_Stream) &&
   2706                             (kDevice2_ObjectList[i].scope == inAddress->mScope || inAddress->mScope == kAudioObjectPropertyScopeGlobal))
   2707                         {
   2708                             ((AudioObjectID*)outData)[k++] = kDevice2_ObjectList[i].id;
   2709                         }
   2710                     }
   2711                     break;
   2712             }
   2713 
   2714 			//	report how much we wrote
   2715 			*outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID);
   2716 			break;
   2717 
   2718 		case kAudioObjectPropertyControlList:
   2719 			//	Calculate the number of items that have been requested. Note that this
   2720 			//	number is allowed to be smaller than the actual size of the list. In such
   2721 			//	case, only that number of items will be returned
   2722 
   2723             theNumberItemsToFetch = minimum(inDataSize / sizeof(AudioObjectID), device_control_list_size(inAddress->mScope, inObjectID));
   2724 
   2725             //    fill out the list with as many objects as requested
   2726             switch (inObjectID) {
   2727                 case kObjectID_Device:
   2728                     pthread_mutex_lock(&gPlugIn_StateMutex);
   2729                     for (UInt32 i = 0, k = 0; k < theNumberItemsToFetch; i++)
   2730                     {
   2731                         // TODO remove hack! There must be a better way than looking for a fixed i
   2732                         if ((kDevice_ObjectList[i].type == kObjectType_Control) && !(!gPitch_Adjust_Enabled && kDevice_ObjectList[i].id==kObjectID_Pitch_Adjust))
   2733                         {
   2734                             ((AudioObjectID*)outData)[k++] = kDevice_ObjectList[i].id;
   2735                         }
   2736                     }
   2737                     pthread_mutex_unlock(&gPlugIn_StateMutex);
   2738                     break;
   2739 
   2740                 case kObjectID_Device2:
   2741                     for (UInt32 i = 0, k = 0; k < theNumberItemsToFetch; i++)
   2742                     {
   2743                         if ((kDevice_ObjectList[i].type == kObjectType_Control) && !(!gPitch_Adjust_Enabled && kDevice_ObjectList[i].id==kObjectID_Pitch_Adjust))
   2744                         {
   2745                             ((AudioObjectID*)outData)[k++] = kDevice2_ObjectList[i].id;
   2746                         }
   2747                     }
   2748                     break;
   2749             }
   2750 
   2751 			//	report how much we wrote
   2752 			*outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID);
   2753 			break;
   2754 
   2755 		case kAudioDevicePropertySafetyOffset:
   2756 			//	This property returns the how close to now the HAL can read and write. For
   2757 			//	this, device, the value is 0 due to the fact that it always vends silence.
   2758 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertySafetyOffset for the device");
   2759 			*((UInt32*)outData) = kLatency_Frame_Size;
   2760 			*outDataSize = sizeof(UInt32);
   2761 			break;
   2762 
   2763 		case kAudioDevicePropertyNominalSampleRate:
   2764 			//	This property returns the nominal sample rate of the device. Note that we
   2765 			//	only need to take the state lock to get this value.
   2766 			FailWithAction(inDataSize < sizeof(Float64), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyNominalSampleRate for the device");
   2767 			pthread_mutex_lock(&gPlugIn_StateMutex);
   2768 			*((Float64*)outData) = gDevice_SampleRate;
   2769 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   2770 			*outDataSize = sizeof(Float64);
   2771 			break;
   2772 
   2773 		case kAudioDevicePropertyAvailableNominalSampleRates:
   2774 			//	This returns all nominal sample rates the device supports as an array of
   2775 			//	AudioValueRangeStructs. Note that for discrete sampler rates, the range
   2776 			//	will have the minimum value equal to the maximum value.
   2777 			
   2778 			//	Calculate the number of items that have been requested. Note that this
   2779 			//	number is allowed to be smaller than the actual size of the list. In such
   2780 			//	case, only that number of items will be returned
   2781 			theNumberItemsToFetch = inDataSize / sizeof(AudioValueRange);
   2782 			
   2783 			//	clamp it to the number of items we have
   2784 			if(theNumberItemsToFetch > kDevice_SampleRatesSize)
   2785 			{
   2786 				theNumberItemsToFetch = kDevice_SampleRatesSize;
   2787 			}
   2788 			
   2789             //	fill out the return array
   2790             for(UInt32 i = 0; i < theNumberItemsToFetch; i++)
   2791             {
   2792                 ((AudioValueRange*)outData)[i].mMinimum = kDevice_SampleRates[i];
   2793                 ((AudioValueRange*)outData)[i].mMaximum = kDevice_SampleRates[i];
   2794             }
   2795 
   2796 			//	report how much we wrote
   2797 			*outDataSize = theNumberItemsToFetch * sizeof(AudioValueRange);
   2798 			break;
   2799 		
   2800 		case kAudioDevicePropertyIsHidden:
   2801 			//	This returns whether or not the device is visible to clients.
   2802 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyIsHidden for the device");
   2803             
   2804             switch (inObjectID) {
   2805                 case kObjectID_Device:
   2806                     *((UInt32*)outData) = kDevice_IsHidden;
   2807                     break;
   2808                 
   2809                 case kObjectID_Device2:
   2810                     *((UInt32*)outData) = kDevice2_IsHidden;
   2811                     break;
   2812             }
   2813 			*outDataSize = sizeof(UInt32);
   2814 			break;
   2815 
   2816 		case kAudioDevicePropertyPreferredChannelsForStereo:
   2817 			//	This property returns which two channels to use as left/right for stereo
   2818 			//	data by default. Note that the channel numbers are 1-based.xz
   2819 			FailWithAction(inDataSize < (2 * sizeof(UInt32)), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyPreferredChannelsForStereo for the device");
   2820 			((UInt32*)outData)[0] = 1;
   2821 			((UInt32*)outData)[1] = 2;
   2822 			*outDataSize = 2 * sizeof(UInt32);
   2823 			break;
   2824 
   2825 		case kAudioDevicePropertyPreferredChannelLayout:
   2826 			//	This property returns the default AudioChannelLayout to use for the device
   2827 			//	by default. For this device, we return a stereo ACL.
   2828 			{
   2829 				//	calculate how big the
   2830 				UInt32 theACLSize = offsetof(AudioChannelLayout, mChannelDescriptions) + (kNumber_Of_Channels * sizeof(AudioChannelDescription));
   2831 				FailWithAction(inDataSize < theACLSize, theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyPreferredChannelLayout for the device");
   2832 				((AudioChannelLayout*)outData)->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
   2833 				((AudioChannelLayout*)outData)->mChannelBitmap = 0;
   2834 				((AudioChannelLayout*)outData)->mNumberChannelDescriptions = kNumber_Of_Channels;
   2835 				for(theItemIndex = 0; theItemIndex < kNumber_Of_Channels; ++theItemIndex)
   2836 				{
   2837 					((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mChannelLabel = kAudioChannelLabel_Left + theItemIndex;
   2838 					((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mChannelFlags = 0;
   2839 					((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mCoordinates[0] = 0;
   2840 					((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mCoordinates[1] = 0;
   2841 					((AudioChannelLayout*)outData)->mChannelDescriptions[theItemIndex].mCoordinates[2] = 0;
   2842 				}
   2843 				*outDataSize = theACLSize;
   2844 			}
   2845 			break;
   2846 
   2847 		case kAudioDevicePropertyZeroTimeStampPeriod:
   2848 			//	This property returns how many frames the HAL should expect to see between
   2849 			//	successive sample times in the zero time stamps this device provides.
   2850 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyZeroTimeStampPeriod for the device");
   2851 			*((UInt32*)outData) = kDevice_RingBufferSize;
   2852 			*outDataSize = sizeof(UInt32);
   2853 			break;
   2854 
   2855 		case kAudioDevicePropertyIcon:
   2856 			{
   2857 				//	This is a CFURL that points to the device's Icon in the plug-in's resource bundle.
   2858 				FailWithAction(inDataSize < sizeof(CFURLRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyDeviceUID for the device");
   2859 				CFBundleRef theBundle = CFBundleGetBundleWithIdentifier(CFSTR(kPlugIn_BundleID));
   2860 				FailWithAction(theBundle == NULL, theAnswer = kAudioHardwareUnspecifiedError, Done, "BlackHole_GetDevicePropertyData: could not get the plug-in bundle for kAudioDevicePropertyIcon");
   2861 				CFURLRef theURL = CFBundleCopyResourceURL(theBundle, CFSTR(kPlugIn_Icon), NULL, NULL);
   2862 				FailWithAction(theURL == NULL, theAnswer = kAudioHardwareUnspecifiedError, Done, "BlackHole_GetDevicePropertyData: could not get the URL for kAudioDevicePropertyIcon");
   2863 				*((CFURLRef*)outData) = theURL;
   2864 				*outDataSize = sizeof(CFURLRef);
   2865 			}
   2866 			break;
   2867 			
   2868 		default:
   2869 			theAnswer = kAudioHardwareUnknownPropertyError;
   2870 			break;
   2871 	};
   2872 
   2873 Done:
   2874 	return theAnswer;
   2875 }
   2876 
   2877 static OSStatus	BlackHole_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])
   2878 {
   2879 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   2880 	
   2881 	//	declare the local variables
   2882 	OSStatus theAnswer = 0;
   2883 	Float64 theOldSampleRate;
   2884 	
   2885 	//	check the arguments
   2886 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetDevicePropertyData: bad driver reference");
   2887 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetDevicePropertyData: no address");
   2888 	FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetDevicePropertyData: no place to return the number of properties that changed");
   2889 	FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetDevicePropertyData: no place to return the properties that changed");
   2890 	FailWithAction(inObjectID != kObjectID_Device && inObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetDevicePropertyData: not the device object");
   2891 	
   2892 	//	initialize the returned number of changed properties
   2893 	*outNumberPropertiesChanged = 0;
   2894 	
   2895 	//	Note that for each object, this driver implements all the required properties plus a few
   2896 	//	extras that are useful but not required. There is more detailed commentary about each
   2897 	//	property in the BlackHole_GetDevicePropertyData() method.
   2898 	switch(inAddress->mSelector)
   2899 	{
   2900 		case kAudioDevicePropertyNominalSampleRate:
   2901 			//	Changing the sample rate needs to be handled via the
   2902 			//	RequestConfigChange/PerformConfigChange machinery.
   2903 
   2904 			//	check the arguments
   2905 			FailWithAction(inDataSize != sizeof(Float64), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetDevicePropertyData: wrong size for the data for kAudioDevicePropertyNominalSampleRate");
   2906 			FailWithAction(!is_valid_sample_rate(*(const Float64*)inData), theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetDevicePropertyData: unsupported value for kAudioDevicePropertyNominalSampleRate");
   2907 			
   2908 			//	make sure that the new value is different than the old value
   2909 			pthread_mutex_lock(&gPlugIn_StateMutex);
   2910 			theOldSampleRate = gDevice_SampleRate;
   2911 			gDevice_RequestedSampleRate = *((const Float64*)inData);
   2912 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   2913 			if(*((const Float64*)inData) != theOldSampleRate)
   2914 			{
   2915 				//	we dispatch this so that the change can happen asynchronously
   2916 				dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ gPlugIn_Host->RequestDeviceConfigurationChange(gPlugIn_Host, kObjectID_Device, ChangeAction_SetSampleRate, NULL); });
   2917 			}
   2918 			break;
   2919 		
   2920 		default:
   2921 			theAnswer = kAudioHardwareUnknownPropertyError;
   2922 			break;
   2923 	};
   2924 
   2925 Done:
   2926 	return theAnswer;
   2927 }
   2928 
   2929 #pragma mark Stream Property Operations
   2930 
   2931 static Boolean	BlackHole_HasStreamProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress)
   2932 {
   2933 	//	This method returns whether or not the given object has the given property.
   2934 	
   2935 	#pragma unused(inClientProcessID)
   2936 	
   2937 	//	declare the local variables
   2938 	Boolean theAnswer = false;
   2939 	
   2940 	//	check the arguments
   2941 	FailIf(inDriver != gAudioServerPlugInDriverRef, Done, "BlackHole_HasStreamProperty: bad driver reference");
   2942 	FailIf(inAddress == NULL, Done, "BlackHole_HasStreamProperty: no address");
   2943 	FailIf((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), Done, "BlackHole_HasStreamProperty: not a stream object");
   2944 	
   2945 	//	Note that for each object, this driver implements all the required properties plus a few
   2946 	//	extras that are useful but not required. There is more detailed commentary about each
   2947 	//	property in the BlackHole_GetStreamPropertyData() method.
   2948 	switch(inAddress->mSelector)
   2949 	{
   2950 		case kAudioObjectPropertyBaseClass:
   2951 		case kAudioObjectPropertyClass:
   2952 		case kAudioObjectPropertyOwner:
   2953 		case kAudioObjectPropertyOwnedObjects:
   2954 		case kAudioStreamPropertyIsActive:
   2955 		case kAudioStreamPropertyDirection:
   2956 		case kAudioStreamPropertyTerminalType:
   2957 		case kAudioStreamPropertyStartingChannel:
   2958 		case kAudioStreamPropertyLatency:
   2959 		case kAudioStreamPropertyVirtualFormat:
   2960 		case kAudioStreamPropertyPhysicalFormat:
   2961 		case kAudioStreamPropertyAvailableVirtualFormats:
   2962 		case kAudioStreamPropertyAvailablePhysicalFormats:
   2963 			theAnswer = true;
   2964 			break;
   2965 	};
   2966 
   2967 Done:
   2968 	return theAnswer;
   2969 }
   2970 
   2971 static OSStatus	BlackHole_IsStreamPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable)
   2972 {
   2973 	//	This method returns whether or not the given property on the object can have its value
   2974 	//	changed.
   2975 	
   2976 	#pragma unused(inClientProcessID)
   2977 	
   2978 	//	declare the local variables
   2979 	OSStatus theAnswer = 0;
   2980 	
   2981 	//	check the arguments
   2982 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsStreamPropertySettable: bad driver reference");
   2983 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsStreamPropertySettable: no address");
   2984 	FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsStreamPropertySettable: no place to put the return value");
   2985 	FailWithAction((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsStreamPropertySettable: not a stream object");
   2986 	
   2987 	//	Note that for each object, this driver implements all the required properties plus a few
   2988 	//	extras that are useful but not required. There is more detailed commentary about each
   2989 	//	property in the BlackHole_GetStreamPropertyData() method.
   2990 	switch(inAddress->mSelector)
   2991 	{
   2992 		case kAudioObjectPropertyBaseClass:
   2993 		case kAudioObjectPropertyClass:
   2994 		case kAudioObjectPropertyOwner:
   2995 		case kAudioObjectPropertyOwnedObjects:
   2996 		case kAudioStreamPropertyDirection:
   2997 		case kAudioStreamPropertyTerminalType:
   2998 		case kAudioStreamPropertyStartingChannel:
   2999 		case kAudioStreamPropertyLatency:
   3000 		case kAudioStreamPropertyAvailableVirtualFormats:
   3001 		case kAudioStreamPropertyAvailablePhysicalFormats:
   3002 			*outIsSettable = false;
   3003 			break;
   3004 		
   3005 		case kAudioStreamPropertyIsActive:
   3006 		case kAudioStreamPropertyVirtualFormat:
   3007 		case kAudioStreamPropertyPhysicalFormat:
   3008 			*outIsSettable = true;
   3009 			break;
   3010 		
   3011 		default:
   3012 			theAnswer = kAudioHardwareUnknownPropertyError;
   3013 			break;
   3014 	};
   3015 
   3016 Done:
   3017 	return theAnswer;
   3018 }
   3019 
   3020 static OSStatus	BlackHole_GetStreamPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize)
   3021 {
   3022 	//	This method returns the byte size of the property's data.
   3023 	
   3024 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   3025 	
   3026 	//	declare the local variables
   3027 	OSStatus theAnswer = 0;
   3028 	
   3029 	//	check the arguments
   3030 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetStreamPropertyDataSize: bad driver reference");
   3031 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetStreamPropertyDataSize: no address");
   3032 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetStreamPropertyDataSize: no place to put the return value");
   3033 	FailWithAction((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetStreamPropertyDataSize: not a stream object");
   3034 	
   3035 	//	Note that for each object, this driver implements all the required properties plus a few
   3036 	//	extras that are useful but not required. There is more detailed commentary about each
   3037 	//	property in the BlackHole_GetStreamPropertyData() method.
   3038 	switch(inAddress->mSelector)
   3039 	{
   3040 		case kAudioObjectPropertyBaseClass:
   3041 			*outDataSize = sizeof(AudioClassID);
   3042 			break;
   3043 
   3044 		case kAudioObjectPropertyClass:
   3045 			*outDataSize = sizeof(AudioClassID);
   3046 			break;
   3047 
   3048 		case kAudioObjectPropertyOwner:
   3049 			*outDataSize = sizeof(AudioObjectID);
   3050 			break;
   3051 
   3052 		case kAudioObjectPropertyOwnedObjects:
   3053 			*outDataSize = 0 * sizeof(AudioObjectID);
   3054 			break;
   3055 
   3056 		case kAudioStreamPropertyIsActive:
   3057 			*outDataSize = sizeof(UInt32);
   3058 			break;
   3059 
   3060 		case kAudioStreamPropertyDirection:
   3061 			*outDataSize = sizeof(UInt32);
   3062 			break;
   3063 
   3064 		case kAudioStreamPropertyTerminalType:
   3065 			*outDataSize = sizeof(UInt32);
   3066 			break;
   3067 
   3068 		case kAudioStreamPropertyStartingChannel:
   3069 			*outDataSize = sizeof(UInt32);
   3070 			break;
   3071 		
   3072 		case kAudioStreamPropertyLatency:
   3073 			*outDataSize = sizeof(UInt32);
   3074 			break;
   3075 
   3076 		case kAudioStreamPropertyVirtualFormat:
   3077 		case kAudioStreamPropertyPhysicalFormat:
   3078 			*outDataSize = sizeof(AudioStreamBasicDescription);
   3079 			break;
   3080 
   3081 		case kAudioStreamPropertyAvailableVirtualFormats:
   3082 		case kAudioStreamPropertyAvailablePhysicalFormats:
   3083 			*outDataSize = kDevice_SampleRatesSize * sizeof(AudioStreamRangedDescription);
   3084 			break;
   3085 
   3086 		default:
   3087 			theAnswer = kAudioHardwareUnknownPropertyError;
   3088 			break;
   3089 	};
   3090 
   3091 Done:
   3092 	return theAnswer;
   3093 }
   3094 
   3095 static OSStatus	BlackHole_GetStreamPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData)
   3096 {
   3097 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   3098 	
   3099 	//	declare the local variables
   3100 	OSStatus theAnswer = 0;
   3101 	UInt32 theNumberItemsToFetch;
   3102 	
   3103 	//	check the arguments
   3104 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetStreamPropertyData: bad driver reference");
   3105 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetStreamPropertyData: no address");
   3106 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetStreamPropertyData: no place to put the return value size");
   3107 	FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetStreamPropertyData: no place to put the return value");
   3108 	FailWithAction((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetStreamPropertyData: not a stream object");
   3109 	
   3110 	//	Note that for each object, this driver implements all the required properties plus a few
   3111 	//	extras that are useful but not required.
   3112 	//
   3113 	//	Also, since most of the data that will get returned is static, there are few instances where
   3114 	//	it is necessary to lock the state mutex.
   3115 	switch(inAddress->mSelector)
   3116 	{
   3117 		case kAudioObjectPropertyBaseClass:
   3118 			//	The base class for kAudioStreamClassID is kAudioObjectClassID
   3119 			FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the stream");
   3120 			*((AudioClassID*)outData) = kAudioObjectClassID;
   3121 			*outDataSize = sizeof(AudioClassID);
   3122 			break;
   3123 			
   3124 		case kAudioObjectPropertyClass:
   3125 			//	The class is always kAudioStreamClassID for streams created by drivers
   3126 			FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the stream");
   3127 			*((AudioClassID*)outData) = kAudioStreamClassID;
   3128 			*outDataSize = sizeof(AudioClassID);
   3129 			break;
   3130 			
   3131 		case kAudioObjectPropertyOwner:
   3132 			//	The stream's owner is the device object
   3133 			FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the stream");
   3134 			*((AudioObjectID*)outData) = kObjectID_Device;
   3135 			*outDataSize = sizeof(AudioObjectID);
   3136 			break;
   3137 			
   3138 		case kAudioObjectPropertyOwnedObjects:
   3139 			//	Streams do not own any objects
   3140 			*outDataSize = 0 * sizeof(AudioObjectID);
   3141 			break;
   3142 
   3143 		case kAudioStreamPropertyIsActive:
   3144 			//	This property tells the device whether or not the given stream is going to
   3145 			//	be used for IO. Note that we need to take the state lock to examine this
   3146 			//	value.
   3147 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyIsActive for the stream");
   3148 			pthread_mutex_lock(&gPlugIn_StateMutex);
   3149 			*((UInt32*)outData) = (inObjectID == kObjectID_Stream_Input) ? gStream_Input_IsActive : gStream_Output_IsActive;
   3150 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   3151 			*outDataSize = sizeof(UInt32);
   3152 			break;
   3153 
   3154 		case kAudioStreamPropertyDirection:
   3155 			//	This returns whether the stream is an input stream or an output stream.
   3156 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyDirection for the stream");
   3157 			*((UInt32*)outData) = (inObjectID == kObjectID_Stream_Input) ? 1 : 0;
   3158 			*outDataSize = sizeof(UInt32);
   3159 			break;
   3160 
   3161 		case kAudioStreamPropertyTerminalType:
   3162 			//	This returns a value that indicates what is at the other end of the stream
   3163 			//	such as a speaker or headphones, or a microphone. Values for this property
   3164 			//	are defined in <CoreAudio/AudioHardwareBase.h>
   3165 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyTerminalType for the stream");
   3166 			*((UInt32*)outData) = (inObjectID == kObjectID_Stream_Input) ? kAudioStreamTerminalTypeMicrophone : kAudioStreamTerminalTypeSpeaker;
   3167 			*outDataSize = sizeof(UInt32);
   3168 			break;
   3169 
   3170 		case kAudioStreamPropertyStartingChannel:
   3171 			//	This property returns the absolute channel number for the first channel in
   3172 			//	the stream. For example, if a device has two output streams with two
   3173 			//	channels each, then the starting channel number for the first stream is 1
   3174 			//	and the starting channel number fo the second stream is 3.
   3175 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyStartingChannel for the stream");
   3176 			*((UInt32*)outData) = 1;
   3177 			*outDataSize = sizeof(UInt32);
   3178 			break;
   3179 
   3180 		case kAudioStreamPropertyLatency:
   3181 			//	This property returns any additional presentation latency the stream has.
   3182 			FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyStartingChannel for the stream");
   3183 			*((UInt32*)outData) = kLatency_Frame_Size;
   3184 			*outDataSize = sizeof(UInt32);
   3185 			break;
   3186 
   3187 		case kAudioStreamPropertyVirtualFormat:
   3188 		case kAudioStreamPropertyPhysicalFormat:
   3189 			//	This returns the current format of the stream in an
   3190 			//	AudioStreamBasicDescription. Note that we need to hold the state lock to get
   3191 			//	this value.
   3192 			//	Note that for devices that don't override the mix operation, the virtual
   3193 			//	format has to be the same as the physical format.
   3194 			FailWithAction(inDataSize < sizeof(AudioStreamBasicDescription), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyVirtualFormat for the stream");
   3195 			pthread_mutex_lock(&gPlugIn_StateMutex);
   3196             ((AudioStreamBasicDescription*)outData)->mSampleRate = gDevice_SampleRate;
   3197             ((AudioStreamBasicDescription*)outData)->mFormatID = kAudioFormatLinearPCM;
   3198             ((AudioStreamBasicDescription*)outData)->mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
   3199             ((AudioStreamBasicDescription*)outData)->mBytesPerPacket = kBytes_Per_Channel * kNumber_Of_Channels;
   3200             ((AudioStreamBasicDescription*)outData)->mFramesPerPacket = 1;
   3201             ((AudioStreamBasicDescription*)outData)->mBytesPerFrame = kBytes_Per_Channel * kNumber_Of_Channels;
   3202             ((AudioStreamBasicDescription*)outData)->mChannelsPerFrame = kNumber_Of_Channels;
   3203             ((AudioStreamBasicDescription*)outData)->mBitsPerChannel = kBits_Per_Channel;
   3204 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   3205 			*outDataSize = sizeof(AudioStreamBasicDescription);
   3206 			break;
   3207 
   3208 		case kAudioStreamPropertyAvailableVirtualFormats:
   3209 		case kAudioStreamPropertyAvailablePhysicalFormats:
   3210 			//	This returns an array of AudioStreamRangedDescriptions that describe what
   3211 			//	formats are supported.
   3212 
   3213 			//	Calculate the number of items that have been requested. Note that this
   3214 			//	number is allowed to be smaller than the actual size of the list. In such
   3215 			//	case, only that number of items will be returned
   3216 			theNumberItemsToFetch = inDataSize / sizeof(AudioStreamRangedDescription);
   3217 			
   3218 			//	clamp it to the number of items we have
   3219 			if(theNumberItemsToFetch > kDevice_SampleRatesSize)
   3220 			{
   3221 				theNumberItemsToFetch = kDevice_SampleRatesSize;
   3222 			}
   3223 
   3224             //	fill out the return array
   3225             for(UInt32 i = 0; i < theNumberItemsToFetch; i++)
   3226             {
   3227                 ((AudioStreamRangedDescription*)outData)[i].mFormat.mSampleRate = kDevice_SampleRates[i];
   3228                 ((AudioStreamRangedDescription*)outData)[i].mFormat.mFormatID = kAudioFormatLinearPCM;
   3229                 ((AudioStreamRangedDescription*)outData)[i].mFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
   3230                 ((AudioStreamRangedDescription*)outData)[i].mFormat.mBytesPerPacket = kBytes_Per_Frame;
   3231                 ((AudioStreamRangedDescription*)outData)[i].mFormat.mFramesPerPacket = 1;
   3232                 ((AudioStreamRangedDescription*)outData)[i].mFormat.mBytesPerFrame = kBytes_Per_Frame;
   3233                 ((AudioStreamRangedDescription*)outData)[i].mFormat.mChannelsPerFrame = kNumber_Of_Channels;
   3234                 ((AudioStreamRangedDescription*)outData)[i].mFormat.mBitsPerChannel = kBits_Per_Channel;
   3235                 ((AudioStreamRangedDescription*)outData)[i].mSampleRateRange.mMinimum = kDevice_SampleRates[i];
   3236                 ((AudioStreamRangedDescription*)outData)[i].mSampleRateRange.mMaximum = kDevice_SampleRates[i];
   3237             }
   3238 
   3239 			//	report how much we wrote
   3240 			*outDataSize = theNumberItemsToFetch * sizeof(AudioStreamRangedDescription);
   3241 			break;
   3242 
   3243 		default:
   3244 			theAnswer = kAudioHardwareUnknownPropertyError;
   3245 			break;
   3246 	};
   3247 
   3248 Done:
   3249 	return theAnswer;
   3250 }
   3251 
   3252 static OSStatus	BlackHole_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])
   3253 {
   3254 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   3255 	
   3256 	//	declare the local variables
   3257 	OSStatus theAnswer = 0;
   3258 	Float64 theOldSampleRate;
   3259 	
   3260 	//	check the arguments
   3261 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetStreamPropertyData: bad driver reference");
   3262 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetStreamPropertyData: no address");
   3263 	FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetStreamPropertyData: no place to return the number of properties that changed");
   3264 	FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetStreamPropertyData: no place to return the properties that changed");
   3265 	FailWithAction((inObjectID != kObjectID_Stream_Input) && (inObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetStreamPropertyData: not a stream object");
   3266 	
   3267 	//	initialize the returned number of changed properties
   3268 	*outNumberPropertiesChanged = 0;
   3269 	
   3270 	//	Note that for each object, this driver implements all the required properties plus a few
   3271 	//	extras that are useful but not required. There is more detailed commentary about each
   3272 	//	property in the BlackHole_GetStreamPropertyData() method.
   3273 	switch(inAddress->mSelector)
   3274 	{
   3275 		case kAudioStreamPropertyIsActive:
   3276 			//	Changing the active state of a stream doesn't affect IO or change the structure
   3277 			//	so we can just save the state and send the notification.
   3278 			FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetStreamPropertyData: wrong size for the data for kAudioDevicePropertyNominalSampleRate");
   3279 			pthread_mutex_lock(&gPlugIn_StateMutex);
   3280 			if(inObjectID == kObjectID_Stream_Input)
   3281 			{
   3282 				if(gStream_Input_IsActive != (*((const UInt32*)inData) != 0))
   3283 				{
   3284 					gStream_Input_IsActive = *((const UInt32*)inData) != 0;
   3285 					*outNumberPropertiesChanged = 1;
   3286 					outChangedAddresses[0].mSelector = kAudioStreamPropertyIsActive;
   3287 					outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   3288 					outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   3289 				}
   3290 			}
   3291 			else
   3292 			{
   3293 				if(gStream_Output_IsActive != (*((const UInt32*)inData) != 0))
   3294 				{
   3295 					gStream_Output_IsActive = *((const UInt32*)inData) != 0;
   3296 					*outNumberPropertiesChanged = 1;
   3297 					outChangedAddresses[0].mSelector = kAudioStreamPropertyIsActive;
   3298 					outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   3299 					outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   3300 				}
   3301 			}
   3302 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   3303 			break;
   3304 			
   3305 		case kAudioStreamPropertyVirtualFormat:
   3306 		case kAudioStreamPropertyPhysicalFormat:
   3307 			//	Changing the stream format needs to be handled via the
   3308 			//	RequestConfigChange/PerformConfigChange machinery. Note that because this
   3309 			//	device only supports 2 channel 32 bit float data, the only thing that can
   3310 			//	change is the sample rate.
   3311 			FailWithAction(inDataSize != sizeof(AudioStreamBasicDescription), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetStreamPropertyData: wrong size for the data for kAudioStreamPropertyPhysicalFormat");
   3312 			FailWithAction(((const AudioStreamBasicDescription*)inData)->mFormatID != kAudioFormatLinearPCM, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "BlackHole_SetStreamPropertyData: unsupported format ID for kAudioStreamPropertyPhysicalFormat");
   3313 			FailWithAction(((const AudioStreamBasicDescription*)inData)->mFormatFlags != (kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked), theAnswer = kAudioDeviceUnsupportedFormatError, Done, "BlackHole_SetStreamPropertyData: unsupported format flags for kAudioStreamPropertyPhysicalFormat");
   3314 			FailWithAction(((const AudioStreamBasicDescription*)inData)->mBytesPerPacket != kBytes_Per_Frame, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "BlackHole_SetStreamPropertyData: unsupported bytes per packet for kAudioStreamPropertyPhysicalFormat");
   3315 			FailWithAction(((const AudioStreamBasicDescription*)inData)->mFramesPerPacket != 1, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "BlackHole_SetStreamPropertyData: unsupported frames per packet for kAudioStreamPropertyPhysicalFormat");
   3316 			FailWithAction(((const AudioStreamBasicDescription*)inData)->mBytesPerFrame != kBytes_Per_Frame, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "BlackHole_SetStreamPropertyData: unsupported bytes per frame for kAudioStreamPropertyPhysicalFormat");
   3317 			FailWithAction(((const AudioStreamBasicDescription*)inData)->mChannelsPerFrame != kNumber_Of_Channels, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "BlackHole_SetStreamPropertyData: unsupported channels per frame for kAudioStreamPropertyPhysicalFormat");
   3318 			FailWithAction(((const AudioStreamBasicDescription*)inData)->mBitsPerChannel != kBits_Per_Channel, theAnswer = kAudioDeviceUnsupportedFormatError, Done, "BlackHole_SetStreamPropertyData: unsupported bits per channel for kAudioStreamPropertyPhysicalFormat");
   3319 			FailWithAction(!is_valid_sample_rate(((const AudioStreamBasicDescription*)inData)->mSampleRate), theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetStreamPropertyData: unsupported sample rate for kAudioStreamPropertyPhysicalFormat");
   3320 			
   3321 			//	If we made it this far, the requested format is something we support, so make sure the sample rate is actually different
   3322 			pthread_mutex_lock(&gPlugIn_StateMutex);
   3323 			theOldSampleRate = gDevice_SampleRate;
   3324 			gDevice_RequestedSampleRate = ((const AudioStreamBasicDescription*)inData)->mSampleRate;
   3325 			pthread_mutex_unlock(&gPlugIn_StateMutex);
   3326 			if(((const AudioStreamBasicDescription*)inData)->mSampleRate != theOldSampleRate)
   3327 			{
   3328 				//	we dispatch this so that the change can happen asynchronously
   3329 				dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ gPlugIn_Host->RequestDeviceConfigurationChange(gPlugIn_Host, kObjectID_Device, ChangeAction_SetSampleRate, NULL); });
   3330 			}
   3331 			break;
   3332 		
   3333 		default:
   3334 			theAnswer = kAudioHardwareUnknownPropertyError;
   3335 			break;
   3336 	};
   3337 
   3338 Done:
   3339 	return theAnswer;
   3340 }
   3341 
   3342 #pragma mark Control Property Operations
   3343 
   3344 static Boolean	BlackHole_HasControlProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress)
   3345 {
   3346 	//	This method returns whether or not the given object has the given property.
   3347 	
   3348 	#pragma unused(inClientProcessID)
   3349 	
   3350 	//	declare the local variables
   3351 	Boolean theAnswer = false;
   3352 	
   3353 	//	check the arguments
   3354 	FailIf(inDriver != gAudioServerPlugInDriverRef, Done, "BlackHole_HasControlProperty: bad driver reference");
   3355 	FailIf(inAddress == NULL, Done, "BlackHole_HasControlProperty: no address");
   3356 	
   3357 	//	Note that for each object, this driver implements all the required properties plus a few
   3358 	//	extras that are useful but not required. There is more detailed commentary about each
   3359 	//	property in the BlackHole_GetControlPropertyData() method.
   3360 	switch(inObjectID)
   3361 	{
   3362 		case kObjectID_Volume_Input_Master:
   3363 		case kObjectID_Volume_Output_Master:
   3364 			switch(inAddress->mSelector)
   3365 			{
   3366 				case kAudioObjectPropertyBaseClass:
   3367 				case kAudioObjectPropertyClass:
   3368 				case kAudioObjectPropertyOwner:
   3369 				case kAudioObjectPropertyOwnedObjects:
   3370 				case kAudioControlPropertyScope:
   3371 				case kAudioControlPropertyElement:
   3372 				case kAudioLevelControlPropertyScalarValue:
   3373 				case kAudioLevelControlPropertyDecibelValue:
   3374 				case kAudioLevelControlPropertyDecibelRange:
   3375 				case kAudioLevelControlPropertyConvertScalarToDecibels:
   3376 				case kAudioLevelControlPropertyConvertDecibelsToScalar:
   3377 					theAnswer = true;
   3378 					break;
   3379 			};
   3380 			break;
   3381 		
   3382 		case kObjectID_Mute_Input_Master:
   3383 		case kObjectID_Mute_Output_Master:
   3384 			switch(inAddress->mSelector)
   3385 			{
   3386 				case kAudioObjectPropertyBaseClass:
   3387 				case kAudioObjectPropertyClass:
   3388 				case kAudioObjectPropertyOwner:
   3389 				case kAudioObjectPropertyOwnedObjects:
   3390 				case kAudioControlPropertyScope:
   3391 				case kAudioControlPropertyElement:
   3392 				case kAudioBooleanControlPropertyValue:
   3393 					theAnswer = true;
   3394 					break;
   3395 			};
   3396 			break;
   3397 
   3398 		case kObjectID_Pitch_Adjust:
   3399 			switch(inAddress->mSelector)
   3400 			{
   3401 				case kAudioObjectPropertyBaseClass:
   3402 				case kAudioObjectPropertyClass:
   3403 				case kAudioObjectPropertyOwner:
   3404 				case kAudioObjectPropertyOwnedObjects:
   3405 				case kAudioControlPropertyScope:
   3406 				case kAudioControlPropertyElement:
   3407 				case kAudioStereoPanControlPropertyValue:
   3408 					theAnswer = true;
   3409 					break;
   3410 			};
   3411 			break;
   3412 			
   3413 		case kObjectID_ClockSource:
   3414 			switch(inAddress->mSelector)
   3415 			{
   3416 				case kAudioObjectPropertyBaseClass:
   3417 				case kAudioObjectPropertyClass:
   3418 				case kAudioObjectPropertyOwner:
   3419 				case kAudioObjectPropertyOwnedObjects:
   3420 				case kAudioControlPropertyScope:
   3421 				case kAudioControlPropertyElement:
   3422 				case kAudioSelectorControlPropertyCurrentItem:
   3423 				case kAudioSelectorControlPropertyAvailableItems:
   3424 				case kAudioSelectorControlPropertyItemName:
   3425 					theAnswer = true;
   3426 					break;
   3427 			};
   3428 			break;
   3429 	};
   3430 
   3431 Done:
   3432 	return theAnswer;
   3433 }
   3434 
   3435 static OSStatus	BlackHole_IsControlPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable)
   3436 {
   3437 	//	This method returns whether or not the given property on the object can have its value
   3438 	//	changed.
   3439 	
   3440 	#pragma unused(inClientProcessID)
   3441 	
   3442 	//	declare the local variables
   3443 	OSStatus theAnswer = 0;
   3444 	
   3445 	//	check the arguments
   3446 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_IsControlPropertySettable: bad driver reference");
   3447 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsControlPropertySettable: no address");
   3448 	FailWithAction(outIsSettable == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_IsControlPropertySettable: no place to put the return value");
   3449 	
   3450 	//	Note that for each object, this driver implements all the required properties plus a few
   3451 	//	extras that are useful but not required. There is more detailed commentary about each
   3452 	//	property in the BlackHole_GetControlPropertyData() method.
   3453 	switch(inObjectID)
   3454 	{
   3455 		case kObjectID_Volume_Input_Master:
   3456 		case kObjectID_Volume_Output_Master:
   3457 			switch(inAddress->mSelector)
   3458 			{
   3459 				case kAudioObjectPropertyBaseClass:
   3460 				case kAudioObjectPropertyClass:
   3461 				case kAudioObjectPropertyOwner:
   3462 				case kAudioObjectPropertyOwnedObjects:
   3463 				case kAudioControlPropertyScope:
   3464 				case kAudioControlPropertyElement:
   3465 				case kAudioLevelControlPropertyDecibelRange:
   3466 				case kAudioLevelControlPropertyConvertScalarToDecibels:
   3467 				case kAudioLevelControlPropertyConvertDecibelsToScalar:
   3468 					*outIsSettable = false;
   3469 					break;
   3470 				
   3471 				case kAudioLevelControlPropertyScalarValue:
   3472 				case kAudioLevelControlPropertyDecibelValue:
   3473 					*outIsSettable = true;
   3474 					break;
   3475 				
   3476 				default:
   3477 					theAnswer = kAudioHardwareUnknownPropertyError;
   3478 					break;
   3479 			};
   3480 			break;
   3481 		
   3482 		case kObjectID_Mute_Input_Master:
   3483 		case kObjectID_Mute_Output_Master:
   3484 			switch(inAddress->mSelector)
   3485 			{
   3486 				case kAudioObjectPropertyBaseClass:
   3487 				case kAudioObjectPropertyClass:
   3488 				case kAudioObjectPropertyOwner:
   3489 				case kAudioObjectPropertyOwnedObjects:
   3490 				case kAudioControlPropertyScope:
   3491 				case kAudioControlPropertyElement:
   3492 					*outIsSettable = false;
   3493 					break;
   3494 				
   3495 				case kAudioBooleanControlPropertyValue:
   3496 					*outIsSettable = true;
   3497 					break;
   3498 				
   3499 				default:
   3500 					theAnswer = kAudioHardwareUnknownPropertyError;
   3501 					break;
   3502 			};
   3503 			break;
   3504 
   3505 		case kObjectID_Pitch_Adjust:
   3506 			switch(inAddress->mSelector)
   3507 			{
   3508 				case kAudioObjectPropertyBaseClass:
   3509 				case kAudioObjectPropertyClass:
   3510 				case kAudioObjectPropertyOwner:
   3511 				case kAudioObjectPropertyOwnedObjects:
   3512 				case kAudioControlPropertyScope:
   3513 				case kAudioControlPropertyElement:
   3514 					*outIsSettable = false;
   3515 					break;
   3516 
   3517 				case kAudioStereoPanControlPropertyValue:
   3518 					*outIsSettable = true;
   3519 					break;
   3520 
   3521 				default:
   3522 					theAnswer = kAudioHardwareUnknownPropertyError;
   3523 					break;
   3524 			};
   3525 			break;
   3526 		case kObjectID_ClockSource:
   3527 			switch(inAddress->mSelector)
   3528 			{
   3529 				case kAudioObjectPropertyBaseClass:
   3530 				case kAudioObjectPropertyClass:
   3531 				case kAudioObjectPropertyOwner:
   3532 				case kAudioObjectPropertyOwnedObjects:
   3533 				case kAudioControlPropertyScope:
   3534 				case kAudioControlPropertyElement:
   3535 					*outIsSettable = false;
   3536 					break;
   3537 					
   3538 				case kAudioSelectorControlPropertyCurrentItem:
   3539 					*outIsSettable = true;
   3540 					break;
   3541 					
   3542 				default:
   3543 					theAnswer = kAudioHardwareUnknownPropertyError;
   3544 					break;
   3545 			};
   3546 			break;
   3547 
   3548 		default:
   3549 			theAnswer = kAudioHardwareBadObjectError;
   3550 			break;
   3551 	};
   3552 
   3553 Done:
   3554 	return theAnswer;
   3555 }
   3556 
   3557 static OSStatus	BlackHole_GetControlPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize)
   3558 {
   3559 	//	This method returns the byte size of the property's data.
   3560 	
   3561 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   3562 	
   3563 	//	declare the local variables
   3564 	OSStatus theAnswer = 0;
   3565 	
   3566 	//	check the arguments
   3567 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetControlPropertyDataSize: bad driver reference");
   3568 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetControlPropertyDataSize: no address");
   3569 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetControlPropertyDataSize: no place to put the return value");
   3570 	
   3571 	//	Note that for each object, this driver implements all the required properties plus a few
   3572 	//	extras that are useful but not required. There is more detailed commentary about each
   3573 	//	property in the BlackHole_GetControlPropertyData() method.
   3574 	switch(inObjectID)
   3575 	{
   3576 		case kObjectID_Volume_Input_Master:
   3577 		case kObjectID_Volume_Output_Master:
   3578 			switch(inAddress->mSelector)
   3579 			{
   3580 				case kAudioObjectPropertyBaseClass:
   3581 					*outDataSize = sizeof(AudioClassID);
   3582 					break;
   3583 
   3584 				case kAudioObjectPropertyClass:
   3585 					*outDataSize = sizeof(AudioClassID);
   3586 					break;
   3587 
   3588 				case kAudioObjectPropertyOwner:
   3589 					*outDataSize = sizeof(AudioObjectID);
   3590 					break;
   3591 
   3592 				case kAudioObjectPropertyOwnedObjects:
   3593 					*outDataSize = 0 * sizeof(AudioObjectID);
   3594 					break;
   3595 
   3596 				case kAudioControlPropertyScope:
   3597 					*outDataSize = sizeof(AudioObjectPropertyScope);
   3598 					break;
   3599 
   3600 				case kAudioControlPropertyElement:
   3601 					*outDataSize = sizeof(AudioObjectPropertyElement);
   3602 					break;
   3603 
   3604 				case kAudioLevelControlPropertyScalarValue:
   3605 					*outDataSize = sizeof(Float32);
   3606 					break;
   3607 
   3608 				case kAudioLevelControlPropertyDecibelValue:
   3609 					*outDataSize = sizeof(Float32);
   3610 					break;
   3611 
   3612 				case kAudioLevelControlPropertyDecibelRange:
   3613 					*outDataSize = sizeof(AudioValueRange);
   3614 					break;
   3615 
   3616 				case kAudioLevelControlPropertyConvertScalarToDecibels:
   3617 					*outDataSize = sizeof(Float32);
   3618 					break;
   3619 
   3620 				case kAudioLevelControlPropertyConvertDecibelsToScalar:
   3621 					*outDataSize = sizeof(Float32);
   3622 					break;
   3623 
   3624 				default:
   3625 					theAnswer = kAudioHardwareUnknownPropertyError;
   3626 					break;
   3627 			};
   3628 			break;
   3629 		
   3630 		case kObjectID_Mute_Input_Master:
   3631 		case kObjectID_Mute_Output_Master:
   3632 			switch(inAddress->mSelector)
   3633 			{
   3634 				case kAudioObjectPropertyBaseClass:
   3635 					*outDataSize = sizeof(AudioClassID);
   3636 					break;
   3637 
   3638 				case kAudioObjectPropertyClass:
   3639 					*outDataSize = sizeof(AudioClassID);
   3640 					break;
   3641 
   3642 				case kAudioObjectPropertyOwner:
   3643 					*outDataSize = sizeof(AudioObjectID);
   3644 					break;
   3645 
   3646 				case kAudioObjectPropertyOwnedObjects:
   3647 					*outDataSize = 0 * sizeof(AudioObjectID);
   3648 					break;
   3649 
   3650 				case kAudioControlPropertyScope:
   3651 					*outDataSize = sizeof(AudioObjectPropertyScope);
   3652 					break;
   3653 
   3654 				case kAudioControlPropertyElement:
   3655 					*outDataSize = sizeof(AudioObjectPropertyElement);
   3656 					break;
   3657 
   3658 				case kAudioBooleanControlPropertyValue:
   3659 					*outDataSize = sizeof(UInt32);
   3660 					break;
   3661 
   3662 				default:
   3663 					theAnswer = kAudioHardwareUnknownPropertyError;
   3664 					break;
   3665 			};
   3666 			break;
   3667 			
   3668 		case kObjectID_Pitch_Adjust:
   3669 			switch(inAddress->mSelector)
   3670 			{
   3671 				case kAudioObjectPropertyBaseClass:
   3672 					*outDataSize = sizeof(AudioClassID);
   3673 					break;
   3674 
   3675 				case kAudioObjectPropertyClass:
   3676 					*outDataSize = sizeof(AudioClassID);
   3677 					break;
   3678 
   3679 				case kAudioObjectPropertyOwner:
   3680 					*outDataSize = sizeof(AudioObjectID);
   3681 					break;
   3682 
   3683 				case kAudioObjectPropertyOwnedObjects:
   3684 					*outDataSize = 0 * sizeof(AudioObjectID);
   3685 					break;
   3686 
   3687 				case kAudioControlPropertyScope:
   3688 					*outDataSize = sizeof(AudioObjectPropertyScope);
   3689 					break;
   3690 
   3691 				case kAudioControlPropertyElement:
   3692 					*outDataSize = sizeof(AudioObjectPropertyElement);
   3693 					break;
   3694 
   3695 				case kAudioStereoPanControlPropertyValue:
   3696 					*outDataSize = sizeof(Float32);
   3697 					break;
   3698 
   3699 				default:
   3700 					theAnswer = kAudioHardwareUnknownPropertyError;
   3701 					break;
   3702 			};
   3703 			break;
   3704 			
   3705 		case kObjectID_ClockSource:
   3706 			switch(inAddress->mSelector)
   3707 			{
   3708 				case kAudioObjectPropertyBaseClass:
   3709 					*outDataSize = sizeof(AudioClassID);
   3710 					break;
   3711 				case kAudioObjectPropertyClass:
   3712 					*outDataSize = sizeof(AudioClassID);
   3713 					break;
   3714 				case kAudioObjectPropertyOwner:
   3715 					*outDataSize = sizeof(AudioObjectID);
   3716 					break;
   3717 				case kAudioObjectPropertyOwnedObjects:
   3718 					*outDataSize = 0 * sizeof(AudioObjectID);
   3719 					break;
   3720 				case kAudioControlPropertyScope:
   3721 					*outDataSize = sizeof(AudioObjectPropertyScope);
   3722 					break;
   3723 				case kAudioControlPropertyElement:
   3724 					*outDataSize = sizeof(AudioObjectPropertyElement);
   3725 					break;
   3726 					
   3727 				case kAudioSelectorControlPropertyCurrentItem:
   3728 					*outDataSize = sizeof(UInt32);
   3729 					break;
   3730 					
   3731 				case kAudioSelectorControlPropertyAvailableItems:
   3732 					*outDataSize = kClockSource_NumberItems * sizeof(UInt32);
   3733 					break;
   3734 				case kAudioSelectorControlPropertyItemName:
   3735 					*outDataSize = sizeof(CFStringRef);
   3736 					break;
   3737 				default:
   3738 					theAnswer = kAudioHardwareUnknownPropertyError;
   3739 					break;
   3740 			};
   3741 			break;
   3742 		default:
   3743 			theAnswer = kAudioHardwareBadObjectError;
   3744 			break;
   3745 	};
   3746 
   3747 Done:
   3748 	return theAnswer;
   3749 }
   3750 
   3751 static OSStatus	BlackHole_GetControlPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32* outDataSize, void* outData)
   3752 {
   3753 	#pragma unused(inClientProcessID, inQualifierData, inQualifierDataSize)
   3754 	
   3755 	//	declare the local variables
   3756 	OSStatus theAnswer = 0;
   3757     UInt32 theNumberItemsToFetch;
   3758     UInt32 theItemIndex;
   3759 	
   3760 	//	check the arguments
   3761 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetControlPropertyData: bad driver reference");
   3762 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetControlPropertyData: no address");
   3763 	FailWithAction(outDataSize == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetControlPropertyData: no place to put the return value size");
   3764 	FailWithAction(outData == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetControlPropertyData: no place to put the return value");
   3765 	
   3766 	//	Note that for each object, this driver implements all the required properties plus a few
   3767 	//	extras that are useful but not required.
   3768 	//
   3769 	//	Also, since most of the data that will get returned is static, there are few instances where
   3770 	//	it is necessary to lock the state mutex.
   3771 	switch(inObjectID)
   3772 	{
   3773 		case kObjectID_Volume_Input_Master:
   3774 		case kObjectID_Volume_Output_Master:
   3775 			switch(inAddress->mSelector)
   3776 			{
   3777 				case kAudioObjectPropertyBaseClass:
   3778 					//	The base class for kAudioVolumeControlClassID is kAudioLevelControlClassID
   3779 					FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the volume control");
   3780 					*((AudioClassID*)outData) = kAudioLevelControlClassID;
   3781 					*outDataSize = sizeof(AudioClassID);
   3782 					break;
   3783 					
   3784 				case kAudioObjectPropertyClass:
   3785 					//	Volume controls are of the class, kAudioVolumeControlClassID
   3786 					FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the volume control");
   3787 					*((AudioClassID*)outData) = kAudioVolumeControlClassID;
   3788 					*outDataSize = sizeof(AudioClassID);
   3789 					break;
   3790 					
   3791 				case kAudioObjectPropertyOwner:
   3792 					//	The control's owner is the device object
   3793 					FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the volume control");
   3794 					*((AudioObjectID*)outData) = kObjectID_Device;
   3795 					*outDataSize = sizeof(AudioObjectID);
   3796 					break;
   3797 					
   3798 				case kAudioObjectPropertyOwnedObjects:
   3799 					//	Controls do not own any objects
   3800 					*outDataSize = 0 * sizeof(AudioObjectID);
   3801 					break;
   3802 
   3803 				case kAudioControlPropertyScope:
   3804 					//	This property returns the scope that the control is attached to.
   3805 					FailWithAction(inDataSize < sizeof(AudioObjectPropertyScope), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyScope for the volume control");
   3806 					*((AudioObjectPropertyScope*)outData) = (inObjectID == kObjectID_Volume_Input_Master) ? kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
   3807 					*outDataSize = sizeof(AudioObjectPropertyScope);
   3808 					break;
   3809 
   3810 				case kAudioControlPropertyElement:
   3811 					//	This property returns the element that the control is attached to.
   3812 					FailWithAction(inDataSize < sizeof(AudioObjectPropertyElement), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyElement for the volume control");
   3813 					*((AudioObjectPropertyElement*)outData) = kAudioObjectPropertyElementMain;
   3814 					*outDataSize = sizeof(AudioObjectPropertyElement);
   3815 					break;
   3816 
   3817 				case kAudioLevelControlPropertyScalarValue:
   3818 					//	This returns the value of the control in the normalized range of 0 to 1.
   3819 					//	Note that we need to take the state lock to examine the value.
   3820 					FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyScalarValue for the volume control");
   3821 					pthread_mutex_lock(&gPlugIn_StateMutex);
   3822 					*((Float32*)outData) = volume_to_scalar(gVolume_Master_Value);
   3823 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   3824 					*outDataSize = sizeof(Float32);
   3825 					break;
   3826 
   3827 				case kAudioLevelControlPropertyDecibelValue:
   3828 					//	This returns the dB value of the control.
   3829 					//	Note that we need to take the state lock to examine the value.
   3830 					FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyDecibelValue for the volume control");
   3831 					pthread_mutex_lock(&gPlugIn_StateMutex);
   3832 					*((Float32*)outData) = gVolume_Master_Value;
   3833 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   3834 					*((Float32*)outData) = volume_to_decibel(*((Float32*)outData));
   3835 					
   3836 					//	report how much we wrote
   3837 					*outDataSize = sizeof(Float32);
   3838 					break;
   3839 
   3840 				case kAudioLevelControlPropertyDecibelRange:
   3841 					//	This returns the dB range of the control.
   3842 					FailWithAction(inDataSize < sizeof(AudioValueRange), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyDecibelRange for the volume control");
   3843 					((AudioValueRange*)outData)->mMinimum = kVolume_MinDB;
   3844 					((AudioValueRange*)outData)->mMaximum = kVolume_MaxDB;
   3845 					*outDataSize = sizeof(AudioValueRange);
   3846 					break;
   3847 
   3848 				case kAudioLevelControlPropertyConvertScalarToDecibels:
   3849 					//	This takes the scalar value in outData and converts it to dB.
   3850 					FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyDecibelValue for the volume control");
   3851 					
   3852 					//	clamp the value to be between 0 and 1
   3853 					if(*((Float32*)outData) < 0.0)
   3854 					{
   3855 						*((Float32*)outData) = 0;
   3856 					}
   3857 					if(*((Float32*)outData) > 1.0)
   3858 					{
   3859 						*((Float32*)outData) = 1.0;
   3860 					}
   3861 					
   3862 					//	Note that we square the scalar value before converting to dB so as to
   3863 					//	provide a better curve for the slider
   3864 					*((Float32*)outData) *= *((Float32*)outData);
   3865 					*((Float32*)outData) = kVolume_MinDB + (*((Float32*)outData) * (kVolume_MaxDB - kVolume_MinDB));
   3866 					
   3867 					//	report how much we wrote
   3868 					*outDataSize = sizeof(Float32);
   3869 					break;
   3870 
   3871 				case kAudioLevelControlPropertyConvertDecibelsToScalar:
   3872 					//	This takes the dB value in outData and converts it to scalar.
   3873 					FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioLevelControlPropertyDecibelValue for the volume control");
   3874 					
   3875 					//	clamp the value to be between kVolume_MinDB and kVolume_MaxDB
   3876 					if(*((Float32*)outData) < kVolume_MinDB)
   3877 					{
   3878 						*((Float32*)outData) = kVolume_MinDB;
   3879 					}
   3880 					if(*((Float32*)outData) > kVolume_MaxDB)
   3881 					{
   3882 						*((Float32*)outData) = kVolume_MaxDB;
   3883 					}
   3884 					
   3885 					//	Note that we square the scalar value before converting to dB so as to
   3886 					//	provide a better curve for the slider. We undo that here.
   3887 					*((Float32*)outData) = *((Float32*)outData) - kVolume_MinDB;
   3888 					*((Float32*)outData) /= kVolume_MaxDB - kVolume_MinDB;
   3889 					*((Float32*)outData) = sqrtf(*((Float32*)outData));
   3890 					
   3891 					//	report how much we wrote
   3892 					*outDataSize = sizeof(Float32);
   3893 					break;
   3894 
   3895 				default:
   3896 					theAnswer = kAudioHardwareUnknownPropertyError;
   3897 					break;
   3898 			};
   3899 			break;
   3900 		
   3901 		case kObjectID_Mute_Input_Master:
   3902 		case kObjectID_Mute_Output_Master:
   3903 			switch(inAddress->mSelector)
   3904 			{
   3905 				case kAudioObjectPropertyBaseClass:
   3906 					//	The base class for kAudioMuteControlClassID is kAudioBooleanControlClassID
   3907 					FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the mute control");
   3908 					*((AudioClassID*)outData) = kAudioBooleanControlClassID;
   3909 					*outDataSize = sizeof(AudioClassID);
   3910 					break;
   3911 					
   3912 				case kAudioObjectPropertyClass:
   3913 					//	Mute controls are of the class, kAudioMuteControlClassID
   3914 					FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the mute control");
   3915 					*((AudioClassID*)outData) = kAudioMuteControlClassID;
   3916 					*outDataSize = sizeof(AudioClassID);
   3917 					break;
   3918 					
   3919 				case kAudioObjectPropertyOwner:
   3920 					//	The control's owner is the device object
   3921 					FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the mute control");
   3922 					*((AudioObjectID*)outData) = kObjectID_Device;
   3923 					*outDataSize = sizeof(AudioObjectID);
   3924 					break;
   3925 					
   3926 				case kAudioObjectPropertyOwnedObjects:
   3927 					//	Controls do not own any objects
   3928 					*outDataSize = 0 * sizeof(AudioObjectID);
   3929 					break;
   3930 
   3931 				case kAudioControlPropertyScope:
   3932 					//	This property returns the scope that the control is attached to.
   3933 					FailWithAction(inDataSize < sizeof(AudioObjectPropertyScope), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyScope for the mute control");
   3934 					*((AudioObjectPropertyScope*)outData) = (inObjectID == kObjectID_Mute_Input_Master) ? kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
   3935 					*outDataSize = sizeof(AudioObjectPropertyScope);
   3936 					break;
   3937 
   3938 				case kAudioControlPropertyElement:
   3939 					//	This property returns the element that the control is attached to.
   3940 					FailWithAction(inDataSize < sizeof(AudioObjectPropertyElement), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyElement for the mute control");
   3941 					*((AudioObjectPropertyElement*)outData) = kAudioObjectPropertyElementMain;
   3942 					*outDataSize = sizeof(AudioObjectPropertyElement);
   3943 					break;
   3944 
   3945 				case kAudioBooleanControlPropertyValue:
   3946 					//	This returns the value of the mute control where 0 means that mute is off
   3947 					//	and audio can be heard and 1 means that mute is on and audio cannot be heard.
   3948 					//	Note that we need to take the state lock to examine this value.
   3949 					FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioBooleanControlPropertyValue for the mute control");
   3950 					pthread_mutex_lock(&gPlugIn_StateMutex);
   3951 					*((UInt32*)outData) = gMute_Master_Value ? 1 : 0;
   3952 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   3953 					*outDataSize = sizeof(UInt32);
   3954 					break;
   3955 
   3956 				default:
   3957 					theAnswer = kAudioHardwareUnknownPropertyError;
   3958 					break;
   3959 			};
   3960 			break;
   3961 
   3962 		case kObjectID_Pitch_Adjust:
   3963 			switch(inAddress->mSelector)
   3964 			{
   3965 				case kAudioObjectPropertyBaseClass:
   3966 					//    The base class for kAudioMuteControlClassID is kAudioBooleanControlClassID
   3967 					FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the pitch control");
   3968 					*((AudioClassID*)outData) = kAudioStereoPanControlClassID;
   3969 					*outDataSize = sizeof(AudioClassID);
   3970 					break;
   3971 
   3972 				case kAudioObjectPropertyClass:
   3973 					//    Level controls are of the class, kAudioLevelControlClassID
   3974 					FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the pitch control");
   3975 					*((AudioClassID*)outData) = kAudioStereoPanControlClassID;
   3976 					*outDataSize = sizeof(AudioClassID);
   3977 					break;
   3978 
   3979 				case kAudioObjectPropertyOwner:
   3980 					//    The control's owner is the device object
   3981 					FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the pitch control");
   3982 					*((AudioObjectID*)outData) = kObjectID_Device;
   3983 					*outDataSize = sizeof(AudioObjectID);
   3984 					break;
   3985 
   3986 				case kAudioObjectPropertyOwnedObjects:
   3987 					//    Controls do not own any objects
   3988 					*outDataSize = 0 * sizeof(AudioObjectID);
   3989 					break;
   3990 
   3991 				case kAudioControlPropertyScope:
   3992 					//    This property returns the scope that the control is attached to.
   3993 					FailWithAction(inDataSize < sizeof(AudioObjectPropertyScope), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyScope for the pitch control");
   3994 					*((AudioObjectPropertyScope*)outData) = kAudioObjectPropertyScopeOutput;
   3995 					*outDataSize = sizeof(AudioObjectPropertyScope);
   3996 					break;
   3997 
   3998 				case kAudioControlPropertyElement:
   3999 					//    This property returns the element that the control is attached to.
   4000 					FailWithAction(inDataSize < sizeof(AudioObjectPropertyElement), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyElement for the pitch control");
   4001 					*((AudioObjectPropertyElement*)outData) = kAudioObjectPropertyElementMain;
   4002 					*outDataSize = sizeof(AudioObjectPropertyElement);
   4003 					break;
   4004 
   4005 				case kAudioStereoPanControlPropertyValue:
   4006 					//    This returns the value of the pitch control.
   4007 					//    Note that we need to take the state lock to examine this value.
   4008 					FailWithAction(inDataSize < sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioLevelControlScalarValue for the pitch control");
   4009 					pthread_mutex_lock(&gPlugIn_StateMutex);
   4010 					*((Float32*)outData) = (inObjectID == kObjectID_Pitch_Adjust) ? gPitch_Adjust : 0.5;
   4011 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   4012 					*outDataSize = sizeof(Float32);
   4013 					break;
   4014 
   4015 				default:
   4016 					theAnswer = kAudioHardwareUnknownPropertyError;
   4017 					break;
   4018 			};
   4019 			break;
   4020 		case kObjectID_ClockSource:
   4021 			switch(inAddress->mSelector)
   4022 			{
   4023 				case kAudioObjectPropertyBaseClass:
   4024 					//    The base class for kAudioDataSourceControlClassID is kAudioSelectorControlClassID
   4025 					FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass for the data source control");
   4026 					*((AudioClassID*)outData) = kAudioSelectorControlClassID;
   4027 					*outDataSize = sizeof(AudioClassID);
   4028 					break;
   4029 					
   4030 				case kAudioObjectPropertyClass:
   4031 					//    Data Source controls are of the class, kAudioDataSourceControlClassID
   4032 					FailWithAction(inDataSize < sizeof(AudioClassID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyClass for the data source control");
   4033 					*((AudioClassID*)outData) = kAudioClockSourceControlClassID;
   4034 					*outDataSize = sizeof(AudioClassID);
   4035 					break;
   4036 					
   4037 				case kAudioObjectPropertyOwner:
   4038 					//    The control's owner is the device object
   4039 					FailWithAction(inDataSize < sizeof(AudioObjectID), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioObjectPropertyOwner for the data source control");
   4040 					*((AudioObjectID*)outData) = kObjectID_Device;
   4041 					*outDataSize = sizeof(AudioObjectID);
   4042 					break;
   4043 					
   4044 				case kAudioObjectPropertyOwnedObjects:
   4045 					//    Controls do not own any objects
   4046 					*outDataSize = 0 * sizeof(AudioObjectID);
   4047 					break;
   4048 					
   4049 				case kAudioControlPropertyScope:
   4050 					//    This property returns the scope that the control is attached to.
   4051 					FailWithAction(inDataSize < sizeof(AudioObjectPropertyScope), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyScope for the data source control");
   4052 					*((AudioObjectPropertyScope*)outData) = kAudioObjectPropertyScopeGlobal;
   4053 					*outDataSize = sizeof(AudioObjectPropertyScope);
   4054 					break;
   4055 					
   4056 				case kAudioControlPropertyElement:
   4057 					//    This property returns the element that the control is attached to.
   4058 					FailWithAction(inDataSize < sizeof(AudioObjectPropertyElement), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioControlPropertyElement for the data source control");
   4059 					*((AudioObjectPropertyElement*)outData) = kAudioObjectPropertyElementMain;
   4060 					*outDataSize = sizeof(AudioObjectPropertyElement);
   4061 					break;
   4062 					
   4063 				case kAudioSelectorControlPropertyCurrentItem:
   4064 					//    This returns the value of the data source selector.
   4065 					//    Note that we need to take the state lock to examine this value.
   4066 					FailWithAction(inDataSize < sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioSelectorControlPropertyCurrentItem for the data source control");
   4067 					pthread_mutex_lock(&gPlugIn_StateMutex);
   4068 					*((UInt32*)outData) = gClockSource_Value;
   4069 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   4070 					*outDataSize = sizeof(UInt32);
   4071 					break;
   4072 					
   4073 				case kAudioSelectorControlPropertyAvailableItems:
   4074 					//    This returns the IDs for all the items the data source control supports.
   4075 					
   4076 					//    Calculate the number of items that have been requested. Note that this
   4077 					//    number is allowed to be smaller than the actual size of the list. In such
   4078 					//    case, only that number of items will be returned
   4079 					theNumberItemsToFetch = inDataSize / sizeof(UInt32);
   4080 					
   4081 					//    clamp it to the number of items we have
   4082 					if(theNumberItemsToFetch > kClockSource_NumberItems)
   4083 					{
   4084 						theNumberItemsToFetch = kClockSource_NumberItems;
   4085 					}
   4086 					
   4087 					//    fill out the return array
   4088 					for(theItemIndex = 0; theItemIndex < theNumberItemsToFetch; ++theItemIndex)
   4089 					{
   4090 						((UInt32*)outData)[theItemIndex] = theItemIndex;
   4091 					}
   4092 					
   4093 					//    report how much we wrote
   4094 					*outDataSize = theNumberItemsToFetch * sizeof(UInt32);
   4095 
   4096 					break;
   4097 
   4098 				case kAudioSelectorControlPropertyItemName:
   4099 					//    This returns the user-readable name for the selector item in the qualifier
   4100 					FailWithAction(inDataSize < sizeof(CFStringRef), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: not enough space for the return value of kAudioSelectorControlPropertyItemName for the clock source control");
   4101 					FailWithAction(inQualifierDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_GetControlPropertyData: wrong size for the qualifier of kAudioSelectorControlPropertyItemName for the clock source control");
   4102 					FailWithAction(*((const UInt32*)inQualifierData) >= kClockSource_NumberItems, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_GetControlPropertyData: the item in the qualifier is not valid for kAudioSelectorControlPropertyItemName for the data source control");
   4103 					if (*(UInt32*)inQualifierData == 0) {
   4104 						*(CFStringRef*)outData = CFSTR(kClockSource_InternalFixed);
   4105 					}
   4106 					else if (*(UInt32*)inQualifierData == 1) {
   4107 						*(CFStringRef*)outData = CFSTR(kClockSource_InternalAdjustable);
   4108 					}
   4109 					//else {
   4110 					//    *(CFStringRef*)outData = CFSTR("Unknown");
   4111 					//}
   4112 					*outDataSize = sizeof(CFStringRef);
   4113 
   4114 					break;
   4115 
   4116 				default:
   4117 					theAnswer = kAudioHardwareUnknownPropertyError;
   4118 					break;
   4119 			};
   4120 			break;
   4121 		default:
   4122 			theAnswer = kAudioHardwareBadObjectError;
   4123 			break;
   4124 	};
   4125 
   4126 Done:
   4127 	return theAnswer;
   4128 }
   4129 
   4130 static OSStatus	BlackHole_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])
   4131 {
   4132 	#pragma unused(inClientProcessID, inQualifierDataSize, inQualifierData)
   4133 	
   4134 	//	declare the local variables
   4135 	OSStatus theAnswer = 0;
   4136 	Float32 theNewVolume;
   4137     Float32 theNewPitch;
   4138     UInt32 theNewSource;
   4139 	
   4140 	//	check the arguments
   4141 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_SetControlPropertyData: bad driver reference");
   4142 	FailWithAction(inAddress == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetControlPropertyData: no address");
   4143 	FailWithAction(outNumberPropertiesChanged == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetControlPropertyData: no place to return the number of properties that changed");
   4144 	FailWithAction(outChangedAddresses == NULL, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_SetControlPropertyData: no place to return the properties that changed");
   4145 	
   4146 	//	initialize the returned number of changed properties
   4147 	*outNumberPropertiesChanged = 0;
   4148 	
   4149 	//	Note that for each object, this driver implements all the required properties plus a few
   4150 	//	extras that are useful but not required. There is more detailed commentary about each
   4151 	//	property in the BlackHole_GetControlPropertyData() method.
   4152 	switch(inObjectID)
   4153 	{
   4154 		case kObjectID_Volume_Input_Master:
   4155 		case kObjectID_Volume_Output_Master:
   4156 			switch(inAddress->mSelector)
   4157 			{
   4158 				case kAudioLevelControlPropertyScalarValue:
   4159 					//	For the scalar volume, we clamp the new value to [0, 1]. Note that if this
   4160 					//	value changes, it implies that the dB value changed too.
   4161 					FailWithAction(inDataSize != sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetControlPropertyData: wrong size for the data for kAudioLevelControlPropertyScalarValue");
   4162 					theNewVolume = volume_from_scalar(*((const Float32*)inData));
   4163 					if(theNewVolume < 0.0)
   4164 					{
   4165 						theNewVolume = 0.0;
   4166 					}
   4167 					else if(theNewVolume > 1.0)
   4168 					{
   4169 						theNewVolume = 1.0;
   4170 					}
   4171 					pthread_mutex_lock(&gPlugIn_StateMutex);
   4172                     if(gVolume_Master_Value != theNewVolume)
   4173                     {
   4174                         gVolume_Master_Value = theNewVolume;
   4175                         *outNumberPropertiesChanged = 2;
   4176                         outChangedAddresses[0].mSelector = kAudioLevelControlPropertyScalarValue;
   4177                         outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   4178                         outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   4179                         outChangedAddresses[1].mSelector = kAudioLevelControlPropertyDecibelValue;
   4180                         outChangedAddresses[1].mScope = kAudioObjectPropertyScopeGlobal;
   4181                         outChangedAddresses[1].mElement = kAudioObjectPropertyElementMain;
   4182                     }
   4183 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   4184 					break;
   4185 				
   4186 				case kAudioLevelControlPropertyDecibelValue:
   4187 					//	For the dB value, we first convert it to a scalar value since that is how
   4188 					//	the value is tracked. Note that if this value changes, it implies that the
   4189 					//	scalar value changes as well.
   4190 					FailWithAction(inDataSize != sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetControlPropertyData: wrong size for the data for kAudioLevelControlPropertyScalarValue");
   4191 					theNewVolume = *((const Float32*)inData);
   4192 					if(theNewVolume < kVolume_MinDB)
   4193 					{
   4194 						theNewVolume = kVolume_MinDB;
   4195 					}
   4196 					else if(theNewVolume > kVolume_MaxDB)
   4197 					{
   4198 						theNewVolume = kVolume_MaxDB;
   4199 					}
   4200 					theNewVolume = volume_from_decibel(theNewVolume);
   4201 					pthread_mutex_lock(&gPlugIn_StateMutex);
   4202                     if(gVolume_Master_Value != theNewVolume)
   4203                     {
   4204                         gVolume_Master_Value = theNewVolume;
   4205                         *outNumberPropertiesChanged = 2;
   4206                         outChangedAddresses[0].mSelector = kAudioLevelControlPropertyScalarValue;
   4207                         outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   4208                         outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   4209                         outChangedAddresses[1].mSelector = kAudioLevelControlPropertyDecibelValue;
   4210                         outChangedAddresses[1].mScope = kAudioObjectPropertyScopeGlobal;
   4211                         outChangedAddresses[1].mElement = kAudioObjectPropertyElementMain;
   4212                     }
   4213 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   4214 					break;
   4215 				
   4216 				default:
   4217 					theAnswer = kAudioHardwareUnknownPropertyError;
   4218 					break;
   4219 			};
   4220 			break;
   4221 		
   4222 		case kObjectID_Mute_Input_Master:
   4223 		case kObjectID_Mute_Output_Master:
   4224 			switch(inAddress->mSelector)
   4225 			{
   4226 				case kAudioBooleanControlPropertyValue:
   4227 					FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetControlPropertyData: wrong size for the data for kAudioBooleanControlPropertyValue");
   4228 					pthread_mutex_lock(&gPlugIn_StateMutex);
   4229                     if(gMute_Master_Value != (*((const UInt32*)inData) != 0))
   4230                     {
   4231                         gMute_Master_Value = *((const UInt32*)inData) != 0;
   4232                         *outNumberPropertiesChanged = 1;
   4233                         outChangedAddresses[0].mSelector = kAudioBooleanControlPropertyValue;
   4234                         outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   4235                         outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   4236                     }
   4237 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   4238 					break;
   4239 				
   4240 				default:
   4241 					theAnswer = kAudioHardwareUnknownPropertyError;
   4242 					break;
   4243 			};
   4244 			break;
   4245 
   4246 		case kObjectID_Pitch_Adjust:
   4247 			switch(inAddress->mSelector)
   4248 			{
   4249 				case kAudioStereoPanControlPropertyValue:
   4250 					//    For the scalar pitch, we clamp the new value to [0, 1].
   4251 					FailWithAction(inDataSize != sizeof(Float32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetControlPropertyData: wrong size for the data for kAudioLevelControlPropertyScalarValue");
   4252 					theNewPitch = *((const Float32*)inData);
   4253 					if(theNewPitch < 0.0)
   4254 					{
   4255 						theNewPitch = 0.0;
   4256 					}
   4257 					else if(theNewPitch > 1.0)
   4258 					{
   4259 						theNewPitch = 1.0;
   4260 					}
   4261 					pthread_mutex_lock(&gPlugIn_StateMutex);
   4262 
   4263 					if(gPitch_Adjust != theNewPitch)
   4264 					{
   4265 						gPitch_Adjust = theNewPitch;
   4266 						gDevice_AdjustedTicksPerFrame = gDevice_HostTicksPerFrame - gDevice_HostTicksPerFrame/100.0 * 2.0*(gPitch_Adjust - 0.5);
   4267 						*outNumberPropertiesChanged = 1;
   4268 						outChangedAddresses[0].mSelector = kAudioStereoPanControlPropertyValue;
   4269 						outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   4270 						outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   4271 					}
   4272 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   4273 					break;
   4274 					
   4275 				default:
   4276 					theAnswer = kAudioHardwareUnknownPropertyError;
   4277 					break;
   4278 			};
   4279 			break;
   4280 			
   4281 		case kObjectID_ClockSource:
   4282 			switch(inAddress->mSelector)
   4283 			{
   4284 				case kAudioSelectorControlPropertyCurrentItem:
   4285 					FailWithAction(inDataSize != sizeof(UInt32), theAnswer = kAudioHardwareBadPropertySizeError, Done, "BlackHole_SetControlPropertyData: wrong size for the data for kAudioSelectorControlPropertyCurrentItem");
   4286 					theNewSource = *((const UInt32*)inData);
   4287 					if(theNewSource >= kClockSource_NumberItems)
   4288 					{
   4289 						theNewSource = kClockSource_NumberItems - 1;
   4290 					}
   4291 					pthread_mutex_lock(&gPlugIn_StateMutex);
   4292 					if(gClockSource_Value != theNewSource)
   4293 					{
   4294 						gClockSource_Value = theNewSource;
   4295 						UInt64 changeAction = (theNewSource > 0) ? ChangeAction_EnablePitchControl : ChangeAction_DisablePitchControl;
   4296 
   4297 						*outNumberPropertiesChanged = 1;
   4298 						outChangedAddresses[0].mSelector = kAudioSelectorControlPropertyCurrentItem;
   4299 						outChangedAddresses[0].mScope = kAudioObjectPropertyScopeGlobal;
   4300 						outChangedAddresses[0].mElement = kAudioObjectPropertyElementMain;
   4301 
   4302 						// Notify HAL about device configuration change
   4303 						dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   4304 							gPlugIn_Host->RequestDeviceConfigurationChange(gPlugIn_Host, kObjectID_Device, changeAction, NULL);
   4305 						});
   4306 					}
   4307 					pthread_mutex_unlock(&gPlugIn_StateMutex);
   4308 					break;
   4309 
   4310 				default:
   4311 					theAnswer = kAudioHardwareUnknownPropertyError;
   4312 					break;
   4313 			};
   4314 			break;
   4315 
   4316 		default:
   4317 			theAnswer = kAudioHardwareBadObjectError;
   4318 			break;
   4319 	};
   4320 
   4321 Done:
   4322 	return theAnswer;
   4323 }
   4324 
   4325 #pragma mark IO Operations
   4326 
   4327 static OSStatus	BlackHole_StartIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID)
   4328 {
   4329 	//	This call tells the device that IO is starting for the given client. When this routine
   4330 	//	returns, the device's clock is running and it is ready to have data read/written. It is
   4331 	//	important to note that multiple clients can have IO running on the device at the same time.
   4332 	//	So, work only needs to be done when the first client starts. All subsequent starts simply
   4333 	//	increment the counter.
   4334     
   4335     DebugMsg("BlackHole_StartIO");
   4336 	
   4337 	#pragma unused(inClientID, inDeviceObjectID)
   4338 	
   4339 	//	declare the local variables
   4340 	OSStatus theAnswer = 0;
   4341 	
   4342 	//	check the arguments
   4343 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_StartIO: bad driver reference");
   4344 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_StartIO: bad device ID");
   4345     FailWithAction(inDeviceObjectID == kObjectID_Device && gDevice_IOIsRunning == UINT64_MAX, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_StartIO: overflow error.");
   4346     FailWithAction(inDeviceObjectID == kObjectID_Device2 && gDevice2_IOIsRunning == UINT64_MAX, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_StartIO: overflow error.");
   4347 
   4348 	//	we need to hold the state lock
   4349 	pthread_mutex_lock(&gPlugIn_StateMutex);
   4350 	
   4351     
   4352     if (inDeviceObjectID == kObjectID_Device) { gDevice_IOIsRunning += 1; }
   4353     if (inDeviceObjectID == kObjectID_Device2) { gDevice2_IOIsRunning += 1; }
   4354     
   4355     // allocate ring buffer
   4356     if ((gDevice_IOIsRunning || gDevice2_IOIsRunning) && gRingBuffer == NULL)
   4357     {
   4358         gDevice_NumberTimeStamps = 0;
   4359         gDevice_AnchorSampleTime = 0;
   4360         gDevice_AnchorHostTime = mach_absolute_time();
   4361         gDevice_PreviousTicks = 0;
   4362         gRingBuffer = calloc(kRing_Buffer_Frame_Size * kNumber_Of_Channels, sizeof(Float32));
   4363     }
   4364     
   4365     
   4366 	//	unlock the state lock
   4367 	pthread_mutex_unlock(&gPlugIn_StateMutex);
   4368 	
   4369 Done:
   4370 	return theAnswer;
   4371 }
   4372 
   4373 static OSStatus	BlackHole_StopIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID)
   4374 {
   4375 	//	This call tells the device that the client has stopped IO. The driver can stop the hardware
   4376 	//	once all clients have stopped.
   4377 	
   4378 	#pragma unused(inClientID, inDeviceObjectID)
   4379 	
   4380 	//	declare the local variables
   4381 	OSStatus theAnswer = 0;
   4382 	
   4383 	//	check the arguments
   4384 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_StopIO: bad driver reference");
   4385 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_StopIO: bad device ID");
   4386     FailWithAction(inDeviceObjectID == kObjectID_Device && gDevice_IOIsRunning == 0, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_StartIO: underflow error.");
   4387     FailWithAction(inDeviceObjectID == kObjectID_Device2 && gDevice2_IOIsRunning == 0, theAnswer = kAudioHardwareIllegalOperationError, Done, "BlackHole_StartIO: underflow error.");
   4388 
   4389 	//	we need to hold the state lock
   4390 	pthread_mutex_lock(&gPlugIn_StateMutex);
   4391 	
   4392     
   4393     if (inDeviceObjectID == kObjectID_Device) { gDevice_IOIsRunning -= 1; }
   4394     if (inDeviceObjectID == kObjectID_Device2) { gDevice2_IOIsRunning -= 1; }
   4395     
   4396     // free the ring buffer
   4397     if (!gDevice_IOIsRunning && !gDevice2_IOIsRunning && gRingBuffer != NULL)
   4398     {
   4399         free(gRingBuffer);
   4400         gRingBuffer = NULL;
   4401     }
   4402 	
   4403 	//	unlock the state lock
   4404 	pthread_mutex_unlock(&gPlugIn_StateMutex);
   4405 	
   4406 Done:
   4407 	return theAnswer;
   4408 }
   4409 
   4410 static OSStatus	BlackHole_GetZeroTimeStamp(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, Float64* outSampleTime, UInt64* outHostTime, UInt64* outSeed)
   4411 {
   4412 	//	This method returns the current zero time stamp for the device. The HAL models the timing of
   4413 	//	a device as a series of time stamps that relate the sample time to a host time. The zero
   4414 	//	time stamps are spaced such that the sample times are the value of
   4415 	//	kAudioDevicePropertyZeroTimeStampPeriod apart. This is often modeled using a ring buffer
   4416 	//	where the zero time stamp is updated when wrapping around the ring buffer.
   4417 	//
   4418 	//	For this device, the zero time stamps' sample time increments every kDevice_RingBufferSize
   4419 	//	frames and the host time increments by kDevice_RingBufferSize * gDevice_HostTicksPerFrame.
   4420 	
   4421 	#pragma unused(inClientID, inDeviceObjectID)
   4422 	
   4423 	//	declare the local variables
   4424 	OSStatus theAnswer = 0;
   4425 	UInt64 theCurrentHostTime;
   4426 	Float64 theHostTicksPerRingBuffer;
   4427 	Float64 theAdjustedTicksPerRingBuffer;
   4428 	Float64 theNextTickOffset;
   4429 	UInt64 theNextHostTime;
   4430 	
   4431 	//	check the arguments
   4432 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetZeroTimeStamp: bad driver reference");
   4433 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_GetZeroTimeStamp: bad device ID");
   4434 
   4435 	//	we need to hold the locks
   4436 	pthread_mutex_lock(&gDevice_IOMutex);
   4437 	
   4438 	//	get the current host time
   4439 	theCurrentHostTime = mach_absolute_time();
   4440 	
   4441 	//	calculate the next host time
   4442 	theHostTicksPerRingBuffer = gDevice_HostTicksPerFrame * ((Float64)kDevice_RingBufferSize);
   4443     if (gClockSource_Value > 0) {
   4444         theAdjustedTicksPerRingBuffer = gDevice_AdjustedTicksPerFrame * ((Float64)kDevice_RingBufferSize);
   4445     }
   4446     else {
   4447         theAdjustedTicksPerRingBuffer = gDevice_HostTicksPerFrame * ((Float64)kDevice_RingBufferSize);
   4448     }
   4449     
   4450 	theNextTickOffset = gDevice_PreviousTicks + theAdjustedTicksPerRingBuffer;
   4451     
   4452 	theNextHostTime = gDevice_AnchorHostTime + ((UInt64)theNextTickOffset);
   4453 	
   4454 	//	go to the next time if the next host time is less than the current time
   4455 	if(theNextHostTime <= theCurrentHostTime)
   4456 	{
   4457 		++gDevice_NumberTimeStamps;
   4458 		gDevice_PreviousTicks = theNextTickOffset;
   4459 	}
   4460 	
   4461 	//	set the return values
   4462 	*outSampleTime = gDevice_NumberTimeStamps * kDevice_RingBufferSize;
   4463 	*outHostTime = gDevice_AnchorHostTime + gDevice_PreviousTicks;
   4464 	*outSeed = 1;
   4465     
   4466     // DebugMsg("SampleTime: %f \t HostTime: %llu", *outSampleTime, *outHostTime);
   4467 	
   4468 	//	unlock the state lock
   4469 	pthread_mutex_unlock(&gDevice_IOMutex);
   4470 	
   4471 Done:
   4472 	return theAnswer;
   4473 }
   4474 
   4475 static OSStatus	BlackHole_WillDoIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, Boolean* outWillDo, Boolean* outWillDoInPlace)
   4476 {
   4477 	//	This method returns whether or not the device will do a given IO operation. For this device,
   4478 	//	we only support reading input data and writing output data.
   4479 	
   4480 	#pragma unused(inClientID, inDeviceObjectID)
   4481 	
   4482 	//	declare the local variables
   4483 	OSStatus theAnswer = 0;
   4484 	
   4485 	//	check the arguments
   4486 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_WillDoIOOperation: bad driver reference");
   4487 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_WillDoIOOperation: bad device ID");
   4488 
   4489 	//	figure out if we support the operation
   4490 	bool willDo = false;
   4491 	bool willDoInPlace = true;
   4492 	switch(inOperationID)
   4493 	{
   4494 		case kAudioServerPlugInIOOperationReadInput:
   4495 			willDo = true;
   4496 			willDoInPlace = true;
   4497 			break;
   4498 			
   4499 		case kAudioServerPlugInIOOperationWriteMix:
   4500 			willDo = true;
   4501 			willDoInPlace = true;
   4502 			break;
   4503 			
   4504 	};
   4505 	
   4506 	//	fill out the return values
   4507 	if(outWillDo != NULL)
   4508 	{
   4509 		*outWillDo = willDo;
   4510 	}
   4511 	if(outWillDoInPlace != NULL)
   4512 	{
   4513 		*outWillDoInPlace = willDoInPlace;
   4514 	}
   4515 
   4516 Done:
   4517 	return theAnswer;
   4518 }
   4519 
   4520 static OSStatus	BlackHole_BeginIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo)
   4521 {
   4522 	//	This is called at the beginning of an IO operation. This device doesn't do anything, so just
   4523 	//	check the arguments and return.
   4524 	
   4525 	#pragma unused(inClientID, inOperationID, inIOBufferFrameSize, inIOCycleInfo, inDeviceObjectID)
   4526 	
   4527 	//	declare the local variables
   4528 	OSStatus theAnswer = 0;
   4529 	
   4530 	//	check the arguments
   4531 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_BeginIOOperation: bad driver reference");
   4532 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_BeginIOOperation: bad device ID");
   4533 
   4534 Done:
   4535 	return theAnswer;
   4536 }
   4537 
   4538 static OSStatus	BlackHole_DoIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, AudioObjectID inStreamObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo, void* ioMainBuffer, void* ioSecondaryBuffer)
   4539 {
   4540 	//	This is called to actually perform a given operation. 
   4541 	
   4542 	#pragma unused(inClientID, inIOCycleInfo, ioSecondaryBuffer, inDeviceObjectID)
   4543 	
   4544 	//	declare the local variables
   4545 	OSStatus theAnswer = 0;
   4546 	
   4547 	//	check the arguments
   4548 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_DoIOOperation: bad driver reference");
   4549 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_DoIOOperation: bad device ID");
   4550 	FailWithAction((inStreamObjectID != kObjectID_Stream_Input) && (inStreamObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_DoIOOperation: bad stream ID");
   4551 
   4552     // Calculate the ring buffer offsets and splits.
   4553     UInt64 mSampleTime = inOperationID == kAudioServerPlugInIOOperationReadInput ? inIOCycleInfo->mInputTime.mSampleTime : inIOCycleInfo->mOutputTime.mSampleTime;
   4554     UInt32 ringBufferFrameLocationStart = mSampleTime % kRing_Buffer_Frame_Size;
   4555     UInt32 firstPartFrameSize = kRing_Buffer_Frame_Size - ringBufferFrameLocationStart;
   4556     UInt32 secondPartFrameSize = 0;
   4557     
   4558     if (firstPartFrameSize >= inIOBufferFrameSize)
   4559     {
   4560         firstPartFrameSize = inIOBufferFrameSize;
   4561     }
   4562     else
   4563     {
   4564         secondPartFrameSize = inIOBufferFrameSize - firstPartFrameSize;
   4565     }
   4566     
   4567     // Keep track of last outputSampleTime and the cleared buffer status.
   4568     static Float64 lastOutputSampleTime = 0;
   4569     static Boolean isBufferClear = true;
   4570     
   4571     // From BlackHole to Application
   4572     if(inOperationID == kAudioServerPlugInIOOperationReadInput)
   4573     {
   4574         // If mute is one let's just fill the buffer with zeros or if there's no apps outputting audio
   4575         if (gMute_Master_Value || lastOutputSampleTime - inIOBufferFrameSize < inIOCycleInfo->mInputTime.mSampleTime)
   4576         {
   4577             // Clear the ioMainBuffer
   4578             vDSP_vclr(ioMainBuffer, 1, inIOBufferFrameSize * kNumber_Of_Channels);
   4579             
   4580             // Clear the ring buffer.
   4581             if (!isBufferClear)
   4582             {
   4583                 vDSP_vclr(gRingBuffer, 1, kRing_Buffer_Frame_Size * kNumber_Of_Channels);
   4584                 isBufferClear = true;
   4585             }
   4586         }
   4587         else
   4588         {
   4589             // Copy the buffers.
   4590             memcpy(ioMainBuffer, gRingBuffer + ringBufferFrameLocationStart * kNumber_Of_Channels, firstPartFrameSize * kNumber_Of_Channels * sizeof(Float32));
   4591             memcpy((Float32*)ioMainBuffer + firstPartFrameSize * kNumber_Of_Channels, gRingBuffer, secondPartFrameSize * kNumber_Of_Channels * sizeof(Float32));
   4592             
   4593             // Finally we'll apply the output volume to the buffer.
   4594 	    if(kEnableVolumeControl)
   4595 	    {
   4596 	 	vDSP_vsmul(ioMainBuffer, 1, &gVolume_Master_Value, ioMainBuffer, 1, inIOBufferFrameSize * kNumber_Of_Channels);
   4597 	    }
   4598 
   4599         }
   4600     }
   4601     
   4602     // From Application to BlackHole
   4603     if(inOperationID == kAudioServerPlugInIOOperationWriteMix)
   4604     {
   4605         
   4606         // Overload error.
   4607         if (inIOCycleInfo->mCurrentTime.mSampleTime > inIOCycleInfo->mOutputTime.mSampleTime + inIOBufferFrameSize + kLatency_Frame_Size)
   4608         {
   4609             DebugMsg("BlackHole overload error. kAudioServerPlugInIOOperationWriteMix was unable to complete operation before the deadline. Try increasing the buffer frame size.");
   4610             return kAudioHardwareUnspecifiedError;
   4611         }
   4612         
   4613         
   4614         // Copy the buffers.
   4615         memcpy(gRingBuffer + ringBufferFrameLocationStart * kNumber_Of_Channels, ioMainBuffer, firstPartFrameSize * kNumber_Of_Channels * sizeof(Float32));
   4616         memcpy(gRingBuffer, (Float32*)ioMainBuffer + firstPartFrameSize * kNumber_Of_Channels, secondPartFrameSize * kNumber_Of_Channels * sizeof(Float32));
   4617         
   4618         // Save the last output time.
   4619         lastOutputSampleTime = inIOCycleInfo->mOutputTime.mSampleTime + inIOBufferFrameSize;
   4620         isBufferClear = false;
   4621     }
   4622 
   4623 Done:
   4624 	return theAnswer;
   4625 }
   4626 
   4627 static OSStatus	BlackHole_EndIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo* inIOCycleInfo)
   4628 {
   4629 	//	This is called at the end of an IO operation. This device doesn't do anything, so just check
   4630 	//	the arguments and return.
   4631 	
   4632 	#pragma unused(inClientID, inOperationID, inIOBufferFrameSize, inIOCycleInfo, inDeviceObjectID)
   4633 	
   4634 	//	declare the local variables
   4635 	OSStatus theAnswer = 0;
   4636 	
   4637 	//	check the arguments
   4638 	FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_EndIOOperation: bad driver reference");
   4639 	FailWithAction(inDeviceObjectID != kObjectID_Device && inDeviceObjectID != kObjectID_Device2, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_EndIOOperation: bad device ID");
   4640 
   4641 Done:
   4642 	return theAnswer;
   4643 }