root/jack2/branches/libjacknet/macosx/coreaudio/JackCoreAudioDriver.cpp

Revision 3917, 81.8 kB (checked in by sletz, 7 months ago)

rebase from trunk 3899:3916

  • Property svn:eol-style set to native
Line 
1 /*
2 Copyright (C) 2004-2008 Grame
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "JackCoreAudioDriver.h"
21 #include "JackEngineControl.h"
22 #include "JackMachThread.h"
23 #include "JackGraphManager.h"
24 #include "JackError.h"
25 #include "JackClientControl.h"
26 #include "JackDriverLoader.h"
27 #include "JackGlobals.h"
28 #include "JackTools.h"
29 #include "JackCompilerDeps.h"
30
31 #include <iostream>
32 #include <CoreServices/CoreServices.h>
33 #include <CoreFoundation/CFNumber.h>
34
35 namespace Jack
36 {
37
38 static void Print4CharCode(const char* msg, long c)
39 {
40     UInt32 __4CC_number = (c);
41     char __4CC_string[5];
42     *((SInt32*)__4CC_string) = EndianU32_NtoB(__4CC_number);           
43     __4CC_string[4] = 0;
44     jack_log("%s'%s'", (msg), __4CC_string);
45 }
46
47 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
48 {
49     jack_log("- - - - - - - - - - - - - - - - - - - -");
50     jack_log("  Sample Rate:%f", inDesc->mSampleRate);
51     jack_log("  Format ID:%.*s", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
52     jack_log("  Format Flags:%lX", inDesc->mFormatFlags);
53     jack_log("  Bytes per Packet:%ld", inDesc->mBytesPerPacket);
54     jack_log("  Frames per Packet:%ld", inDesc->mFramesPerPacket);
55     jack_log("  Bytes per Frame:%ld", inDesc->mBytesPerFrame);
56     jack_log("  Channels per Frame:%ld", inDesc->mChannelsPerFrame);
57     jack_log("  Bits per Channel:%ld", inDesc->mBitsPerChannel);
58     jack_log("- - - - - - - - - - - - - - - - - - - -\n");
59 }
60
61 static void printError(OSStatus err)
62 {
63     switch (err) {
64         case kAudioHardwareNoError:
65             jack_log("error code : kAudioHardwareNoError");
66             break;
67         case kAudioConverterErr_FormatNotSupported:
68             jack_log("error code : kAudioConverterErr_FormatNotSupported");
69             break;
70         case kAudioConverterErr_OperationNotSupported:
71             jack_log("error code : kAudioConverterErr_OperationNotSupported");
72             break;
73         case kAudioConverterErr_PropertyNotSupported:
74             jack_log("error code : kAudioConverterErr_PropertyNotSupported");
75             break;
76         case kAudioConverterErr_InvalidInputSize:
77             jack_log("error code : kAudioConverterErr_InvalidInputSize");
78             break;
79         case kAudioConverterErr_InvalidOutputSize:
80             jack_log("error code : kAudioConverterErr_InvalidOutputSize");
81             break;
82         case kAudioConverterErr_UnspecifiedError:
83             jack_log("error code : kAudioConverterErr_UnspecifiedError");
84             break;
85         case kAudioConverterErr_BadPropertySizeError:
86             jack_log("error code : kAudioConverterErr_BadPropertySizeError");
87             break;
88         case kAudioConverterErr_RequiresPacketDescriptionsError:
89             jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
90             break;
91         case kAudioConverterErr_InputSampleRateOutOfRange:
92             jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
93             break;
94         case kAudioConverterErr_OutputSampleRateOutOfRange:
95             jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
96             break;
97         case kAudioHardwareNotRunningError:
98             jack_log("error code : kAudioHardwareNotRunningError");
99             break;
100         case kAudioHardwareUnknownPropertyError:
101             jack_log("error code : kAudioHardwareUnknownPropertyError");
102             break;
103         case kAudioHardwareIllegalOperationError:
104             jack_log("error code : kAudioHardwareIllegalOperationError");
105             break;
106         case kAudioHardwareBadDeviceError:
107             jack_log("error code : kAudioHardwareBadDeviceError");
108             break;
109         case kAudioHardwareBadStreamError:
110             jack_log("error code : kAudioHardwareBadStreamError");
111             break;
112         case kAudioDeviceUnsupportedFormatError:
113             jack_log("error code : kAudioDeviceUnsupportedFormatError");
114             break;
115         case kAudioDevicePermissionsError:
116             jack_log("error code : kAudioDevicePermissionsError");
117             break;
118         case kAudioHardwareBadObjectError:
119             jack_log("error code : kAudioHardwareBadObjectError");
120             break;
121         case kAudioHardwareUnsupportedOperationError:
122             jack_log("error code : kAudioHardwareUnsupportedOperationError");
123             break;
124         default:
125             Print4CharCode("error code : unknown", err);
126             break;
127     }
128 }
129
130 static OSStatus DisplayDeviceNames()
131 {
132     UInt32 size;
133     Boolean isWritable;
134     int i, deviceNum;
135     OSStatus err;
136     CFStringRef UIname;
137
138     err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
139     if (err != noErr)
140         return err;
141
142     deviceNum = size / sizeof(AudioDeviceID);
143     AudioDeviceID devices[deviceNum];
144
145     err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
146     if (err != noErr)
147         return err;
148
149     for (i = 0; i < deviceNum; i++) {
150         char device_name[256];
151         char internal_name[256];
152
153         size = sizeof(CFStringRef);
154         UIname = NULL;
155         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
156         if (err == noErr) {
157             CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
158         } else {
159             goto error;
160         }
161
162         size = 256;
163         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
164         if (err != noErr)
165             return err;
166
167         jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name, internal_name);
168     }
169
170     return noErr;
171
172 error:
173     if (UIname != NULL)
174         CFRelease(UIname);
175     return err;
176 }
177
178 static CFStringRef GetDeviceName(AudioDeviceID id)
179 {
180     UInt32 size = sizeof(CFStringRef);
181     CFStringRef UIname;
182     OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
183     return (err == noErr) ? UIname : NULL;
184 }
185
186 OSStatus JackCoreAudioDriver::Render(void *inRefCon,
187                                      AudioUnitRenderActionFlags *ioActionFlags,
188                                      const AudioTimeStamp *inTimeStamp,
189                                      UInt32 inBusNumber,
190                                      UInt32 inNumberFrames,
191                                      AudioBufferList *ioData)
192 {
193     JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inRefCon;
194     driver->fActionFags = ioActionFlags;
195     driver->fCurrentTime = (AudioTimeStamp *)inTimeStamp;
196     driver->fDriverOutputData = ioData;
197     driver->CycleTakeBeginTime();
198     return driver->Process();
199 }
200
201 int JackCoreAudioDriver::Read()
202 {
203     AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData);
204     return 0;
205 }
206
207 int JackCoreAudioDriver::Write()
208 {
209     for (int i = 0; i < fPlaybackChannels; i++) {
210         if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
211             float* buffer = GetOutputBuffer(i);
212             int size = sizeof(float) * fEngineControl->fBufferSize;
213             memcpy((float*)fDriverOutputData->mBuffers[i].mData, buffer, size);
214             // Monitor ports
215             if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0)
216                 memcpy(GetMonitorBuffer(i), buffer, size);
217         } else {
218             memset((float*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(float) * fEngineControl->fBufferSize);
219         }
220     }
221     return 0;
222 }
223
224 // Will run only once
225 OSStatus JackCoreAudioDriver::MeasureCallback(AudioDeviceID inDevice,
226         const AudioTimeStamp* inNow,
227         const AudioBufferList* inInputData,
228         const AudioTimeStamp* inInputTime,
229         AudioBufferList* outOutputData,
230         const AudioTimeStamp* inOutputTime,
231         void* inClientData)
232 {
233     JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
234     AudioDeviceStop(driver->fDeviceID, MeasureCallback);
235    
236     jack_log("JackCoreAudioDriver::MeasureCallback called");
237     JackMachThread::GetParams(pthread_self(), &driver->fEngineControl->fPeriod, &driver->fEngineControl->fComputation, &driver->fEngineControl->fConstraint);
238    
239     if (driver->fComputationGrain > 0) {
240         jack_log("JackCoreAudioDriver::MeasureCallback : RT thread computation setup to %d percent of period", int(driver->fComputationGrain * 100));
241         driver->fEngineControl->fComputation = driver->fEngineControl->fPeriod * driver->fComputationGrain;
242     }
243    
244     // Signal waiting start function...
245     driver->fState = true;
246    
247     // Setup threadded based log function
248     set_threaded_log_function();
249     return noErr;
250 }
251
252 OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice,
253                                                     UInt32 inChannel,
254                                                     Boolean     isInput,
255                                                     AudioDevicePropertyID inPropertyID,
256                                                     void* inClientData)
257 {
258     JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
259
260     switch (inPropertyID) {
261
262         case kAudioDevicePropertyNominalSampleRate: {
263             jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
264             driver->fState = true;
265             // Check new sample rate
266             Float64 sampleRate;
267             UInt32 outSize =  sizeof(Float64);
268             OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
269             if (err != noErr) {
270                 jack_error("Cannot get current sample rate");
271                 printError(err);
272             } else {
273                 jack_log("SRNotificationCallback : checked sample rate = %f", sampleRate);
274             }
275             break;
276         }
277     }
278
279     return noErr;
280 }
281
282 // A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
283 OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice,
284                                                         UInt32 inChannel,
285                                                         Boolean isInput,
286                                                         AudioDevicePropertyID inPropertyID,
287                                                         void* inClientData)
288 {
289     JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
290          
291     switch (inPropertyID) {
292            
293         case kAudioDevicePropertyDeviceIsRunning: {
294             UInt32 isrunning = 0;
295             UInt32 outsize = sizeof(UInt32);
296             if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceIsRunning, &outsize, &isrunning) == noErr) {
297                 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsRunning = %d", isrunning);
298             }
299             break;
300         }
301        
302         case kAudioDeviceProcessorOverload: {
303             jack_error("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload");
304             jack_time_t cur_time = GetMicroSeconds();
305             driver->NotifyXRun(cur_time, float(cur_time - driver->fBeginDateUst));   // Better this value than nothing...
306             break;
307         }
308        
309         case kAudioDevicePropertyStreamConfiguration: {
310             jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration : server will quit...");
311             driver->NotifyFailure(JackBackendError, "Another application has changed the device configuration.");   // Message length limited to JACK_MESSAGE_SIZE
312             driver->CloseAUHAL();
313             kill(JackTools::GetPID(), SIGINT);
314             return kAudioHardwareUnsupportedOperationError;
315         }
316        
317         case kAudioDevicePropertyNominalSampleRate: {
318             Float64 sampleRate = 0;
319             UInt32 outsize = sizeof(Float64);
320             OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outsize, &sampleRate);
321             if (err != noErr)
322                 return kAudioHardwareUnsupportedOperationError;
323            
324             char device_name[256];
325             const char* digidesign_name = "Digidesign";
326             driver->GetDeviceNameFromID(driver->fDeviceID, device_name);
327        
328             if (sampleRate != driver->fEngineControl->fSampleRate) {
329                
330                // Digidesign hardware, so "special" code : change the SR again here
331                if (strncmp(device_name, digidesign_name, sizeof(digidesign_name)) == 0) {
332                    
333                     jack_log("Digidesign HW = %s", device_name);
334                
335                     // Set sample rate again...
336                     sampleRate = driver->fEngineControl->fSampleRate;
337                     err = AudioDeviceSetProperty(driver->fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outsize, &sampleRate);
338                     if (err != noErr) {
339                         jack_error("Cannot set sample rate = %f", sampleRate);
340                         printError(err);
341                     } else {
342                         jack_log("Set sample rate = %f", sampleRate);
343                     }
344                    
345                     // Check new sample rate again...
346                     outsize = sizeof(Float64);
347                     err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outsize, &sampleRate);
348                     if (err != noErr) {
349                         jack_error("Cannot get current sample rate");
350                         printError(err);
351                     } else {
352                         jack_log("Checked sample rate = %f", sampleRate);
353                     }
354                     return noErr;
355                    
356                 } else {
357                     driver->NotifyFailure(JackBackendError, "Another application has changed the sample rate.");    // Message length limited to JACK_MESSAGE_SIZE
358                     driver->CloseAUHAL();
359                     kill(JackTools::GetPID(), SIGINT);
360                     return kAudioHardwareUnsupportedOperationError;
361                 }
362             }
363         }
364            
365     }
366     return noErr;
367 }
368
369 OSStatus JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id)
370 {
371     UInt32 size = sizeof(AudioValueTranslation);
372     CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
373     AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
374
375     if (inIUD == NULL) {
376         return kAudioHardwareUnspecifiedError;
377     } else {
378         OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
379         CFRelease(inIUD);
380         jack_log("GetDeviceIDFromUID %s %ld", UID, *id);
381         return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
382     }
383 }
384
385 OSStatus JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID* id)
386 {
387     OSStatus res;
388     UInt32 theSize = sizeof(UInt32);
389     AudioDeviceID inDefault;
390     AudioDeviceID outDefault;
391
392     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
393         return res;
394
395     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
396         return res;
397
398     jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);
399
400     // Get the device only if default input and output are the same
401     if (inDefault == outDefault) {
402         *id = inDefault;
403         return noErr;
404     } else {
405         jack_error("Default input and output devices are not the same !!");
406         return kAudioHardwareBadDeviceError;
407     }
408 }
409
410 OSStatus JackCoreAudioDriver::GetDefaultInputDevice(AudioDeviceID* id)
411 {
412     OSStatus res;
413     UInt32 theSize = sizeof(UInt32);
414     AudioDeviceID inDefault;
415
416     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
417         return res;
418
419     jack_log("GetDefaultInputDevice: input = %ld ", inDefault);
420     *id = inDefault;
421     return noErr;
422 }
423
424 OSStatus JackCoreAudioDriver::GetDefaultOutputDevice(AudioDeviceID* id)
425 {
426     OSStatus res;
427     UInt32 theSize = sizeof(UInt32);
428     AudioDeviceID outDefault;
429
430     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
431         return res;
432
433     jack_log("GetDefaultOutputDevice: output = %ld", outDefault);
434     *id = outDefault;
435     return noErr;
436 }
437
438 OSStatus JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id, char* name)
439 {
440     UInt32 size = 256;
441     return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
442 }
443
444 OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput)
445 {
446     OSStatus err = noErr;
447     UInt32      outSize;
448     Boolean     outWritable;
449  
450     channelCount = 0;
451     err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
452     if (err == noErr) {
453         AudioBufferList bufferList[outSize];
454         err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
455         if (err == noErr) {
456             for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++)
457                 channelCount += bufferList->mBuffers[i].mNumberChannels;
458         }
459     }
460     return err;
461 }
462
463 JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
464         : JackAudioDriver(name, alias, engine, table),
465         fJackInputData(NULL),
466         fDriverOutputData(NULL),
467         fPluginID(0),
468         fState(false),
469         fHogged(false),
470         fIOUsage(1.f),
471         fComputationGrain(-1.f),
472         fClockDriftCompensate(false)
473 {}
474
475 JackCoreAudioDriver::~JackCoreAudioDriver()
476 {}
477
478 OSStatus JackCoreAudioDriver::DestroyAggregateDevice()
479 {
480     OSStatus osErr = noErr;
481     AudioObjectPropertyAddress pluginAOPA;
482     pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
483     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
484     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
485     UInt32 outDataSize;
486      
487     if (fPluginID > 0)   {
488      
489         osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
490         if (osErr != noErr) {
491             jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
492             printError(osErr);
493             return osErr;
494         }
495            
496         osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
497         if (osErr != noErr) {
498             jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error");
499             printError(osErr);
500             return osErr;
501         }
502        
503     }
504    
505     return noErr;
506 }
507    
508 OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
509 {
510     OSStatus err = noErr;
511     AudioObjectID sub_device[32];
512     UInt32 outSize = sizeof(sub_device);
513    
514     err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
515     vector<AudioDeviceID> captureDeviceIDArray;
516    
517     if (err != noErr) {
518         jack_log("Input device does not have subdevices");
519         captureDeviceIDArray.push_back(captureDeviceID);
520     } else {
521         int num_devices = outSize / sizeof(AudioObjectID);
522         jack_log("Input device has %d subdevices", num_devices);
523         for (int i = 0; i < num_devices; i++) {
524             captureDeviceIDArray.push_back(sub_device[i]);
525         }
526     }
527    
528     err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);   
529     vector<AudioDeviceID> playbackDeviceIDArray;
530    
531     if (err != noErr) {
532         jack_log("Output device does not have subdevices");
533         playbackDeviceIDArray.push_back(playbackDeviceID);
534     } else {
535         int num_devices = outSize / sizeof(AudioObjectID);
536         jack_log("Output device has %d subdevices", num_devices);
537         for (int i = 0; i < num_devices; i++) {
538             playbackDeviceIDArray.push_back(sub_device[i]);
539         }
540     }
541    
542     return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice);
543 }
544
545 OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
546 {
547     OSStatus osErr = noErr;
548     UInt32 outSize;
549     Boolean outWritable;
550    
551     // Prepare sub-devices for clock drift compensation
552     // Workaround for bug in the HAL : until 10.6.2
553     AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
554     AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
555     UInt32 theQualifierDataSize = sizeof(AudioObjectID);
556     AudioClassID inClass = kAudioSubDeviceClassID;
557     void* theQualifierData = &inClass;
558     UInt32 subDevicesNum = 0;
559      
560     //---------------------------------------------------------------------------
561     // Setup SR of both devices otherwise creating AD may fail...
562     //---------------------------------------------------------------------------
563     UInt32 keptclockdomain = 0;
564     UInt32 clockdomain = 0;
565     outSize = sizeof(UInt32);
566     bool need_clock_drift_compensation = false;
567    
568     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
569         if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) {
570             jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device");
571         } else  {
572             // Check clock domain
573             osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
574             if (osErr != 0) {
575                 jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
576                 printError(osErr);
577             } else {
578                 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
579                 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain);
580                 if (clockdomain != 0 && clockdomain != keptclockdomain) {
581                     jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
582                     need_clock_drift_compensation = true;
583                 }
584             }
585         }
586     }
587    
588     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
589         if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) {
590             jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device");
591         } else {
592             // Check clock domain
593             osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
594             if (osErr != 0) {
595                 jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
596                 printError(osErr);
597             } else {
598                 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
599                 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain);
600                 if (clockdomain != 0 && clockdomain != keptclockdomain) {
601                     jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
602                     need_clock_drift_compensation = true;
603                 }
604             }
605         }
606     }
607    
608     // If no valid clock domain was found, then assume we have to compensate...
609     if (keptclockdomain == 0) {
610         need_clock_drift_compensation = true;
611     }
612
613     //---------------------------------------------------------------------------
614     // Start to create a new aggregate by getting the base audio hardware plugin
615     //---------------------------------------------------------------------------
616    
617     char device_name[256];
618     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
619         GetDeviceNameFromID(captureDeviceID[i], device_name);
620         jack_info("Separated input = '%s' ", device_name);
621     }
622    
623     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
624         GetDeviceNameFromID(playbackDeviceID[i], device_name);
625         jack_info("Separated output = '%s' ", device_name);
626     }
627    
628     osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
629     if (osErr != noErr) {
630         jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
631         printError(osErr);
632         return osErr;
633     }
634
635     AudioValueTranslation pluginAVT;
636
637     CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
638    
639     pluginAVT.mInputData = &inBundleRef;
640     pluginAVT.mInputDataSize = sizeof(inBundleRef);
641     pluginAVT.mOutputData = &fPluginID;
642     pluginAVT.mOutputDataSize = sizeof(fPluginID);
643
644     osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
645     if (osErr != noErr) {
646         jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
647         printError(osErr);
648         return osErr;
649     }
650
651     //-------------------------------------------------
652     // Create a CFDictionary for our aggregate device
653     //-------------------------------------------------
654
655     CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
656
657     CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
658     CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
659    
660     // add the name of the device to the dictionary
661     CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
662
663     // add our choice of UID for the aggregate device to the dictionary
664     CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
665    
666     // add a "private aggregate key" to the dictionary
667     int value = 1;
668     CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
669    
670     SInt32 system;
671     Gestalt(gestaltSystemVersion, &system);
672      
673     jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054);
674    
675     // Starting with 10.5.4 systems, the AD can be internal... (better)
676     if (system < 0x00001054) {
677         jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device....");
678     } else {
679         jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device....");
680         CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
681     }
682    
683     // Prepare sub-devices for clock drift compensation
684     CFMutableArrayRef subDevicesArrayClock = NULL;
685    
686     /*
687     if (fClockDriftCompensate) {
688         if (need_clock_drift_compensation) {
689             jack_info("Clock drift compensation activated...");
690             subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
691            
692             for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
693                 CFStringRef UID = GetDeviceName(captureDeviceID[i]);
694                 if (UID) {
695                     CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
696                     CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
697                     CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
698                     //CFRelease(UID);
699                     CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
700                 }
701             }
702            
703             for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
704                 CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
705                 if (UID) {
706                     CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
707                     CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
708                     CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
709                     //CFRelease(UID);
710                     CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
711                 }
712             }
713            
714             // add sub-device clock array for the aggregate device to the dictionary
715             CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
716         } else {
717             jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
718         }
719     }
720     */
721    
722     //-------------------------------------------------
723     // Create a CFMutableArray for our sub-device list
724     //-------------------------------------------------
725    
726     // we need to append the UID for each device to a CFMutableArray, so create one here
727     CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
728    
729     vector<CFStringRef> captureDeviceUID;
730     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
731         CFStringRef ref = GetDeviceName(captureDeviceID[i]);
732         if (ref == NULL)
733             return -1;
734         captureDeviceUID.push_back(ref);
735         // input sub-devices in this example, so append the sub-device's UID to the CFArray
736         CFArrayAppendValue(subDevicesArray, ref);
737    }
738    
739     vector<CFStringRef> playbackDeviceUID;
740     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
741         CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
742         if (ref == NULL)
743             return -1;
744         playbackDeviceUID.push_back(ref);
745         // output sub-devices in this example, so append the sub-device's UID to the CFArray
746         CFArrayAppendValue(subDevicesArray, ref);
747     }
748  
749     //-----------------------------------------------------------------------
750     // Feed the dictionary to the plugin, to create a blank aggregate device
751     //-----------------------------------------------------------------------
752  
753     AudioObjectPropertyAddress pluginAOPA;
754     pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
755     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
756     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
757     UInt32 outDataSize;
758
759     osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
760     if (osErr != noErr) {
761         jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error");
762         printError(osErr);
763         goto error;
764     }
765    
766     osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
767     if (osErr != noErr) {
768         jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error");
769         printError(osErr);
770         goto error;
771     }
772
773     // pause for a bit to make sure that everything completed correctly
774     // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
775     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
776
777     //-------------------------
778     // Set the sub-device list
779     //-------------------------
780
781     pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
782     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
783     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
784     outDataSize = sizeof(CFMutableArrayRef);
785     osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
786     if (osErr != noErr) {
787         jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error");
788         printError(osErr);
789         goto error;
790     }
791    
792     // pause again to give the changes time to take effect
793     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
794    
795     //-----------------------
796     // Set the master device
797     //-----------------------
798
799     // set the master device manually (this is the device which will act as the master clock for the aggregate device)
800     // pass in the UID of the device you want to use
801     pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
802     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
803     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
804     outDataSize = sizeof(CFStringRef);
805     osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]);  // First apture is master...
806     if (osErr != noErr) {
807         jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for master device error");
808         printError(osErr);
809         goto error;
810     }
811    
812     // pause again to give the changes time to take effect
813     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
814  
815     // Prepare sub-devices for clock drift compensation
816     // Workaround for bug in the HAL : until 10.6.2
817    
818     if (fClockDriftCompensate) {
819         if (need_clock_drift_compensation) {
820             jack_info("Clock drift compensation activated...");
821        
822             // Get the property data size
823             osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
824             if (osErr != noErr) {
825                 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
826                 printError(osErr);
827             }
828            
829             //  Calculate the number of object IDs
830             subDevicesNum = outSize / sizeof(AudioObjectID);
831             jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum);
832             AudioObjectID subDevices[subDevicesNum];
833             outSize = sizeof(subDevices);
834            
835             osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
836             if (osErr != noErr) {
837                 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
838                 printError(osErr);
839             }
840            
841             // Set kAudioSubDevicePropertyDriftCompensation property...
842             for (UInt32 index = 0; index < subDevicesNum; ++index) {
843                 UInt32 theDriftCompensationValue = 1;
844                 osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue);
845                 if (osErr != noErr) {
846                     jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error");
847                     printError(osErr);
848                 }
849             }
850         } else {
851             jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
852         }
853     }   
854    
855     // pause again to give the changes time to take effect
856     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
857        
858     //----------
859     // Clean up
860     //----------
861    
862     // release the private AD key
863     CFRelease(AggregateDeviceNumberRef);
864
865     // release the CF objects we have created - we don't need them any more
866     CFRelease(aggDeviceDict);
867     CFRelease(subDevicesArray);
868    
869     if (subDevicesArrayClock)
870         CFRelease(subDevicesArrayClock);
871
872     // release the device UID
873     for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
874         CFRelease(captureDeviceUID[i]);
875     }
876    
877     for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
878         CFRelease(playbackDeviceUID[i]);
879     }
880    
881     jack_log("New aggregate device %ld", *outAggregateDevice);
882     return noErr;
883    
884 error:
885     DestroyAggregateDevice();
886     return -1;
887 }
888
889 int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid,
890                                       const char* playback_driver_uid,
891                                       char* capture_driver_name,
892                                       char* playback_driver_name,
893                                       jack_nframes_t samplerate)
894 {
895     capture_driver_name[0] = 0;
896     playback_driver_name[0] = 0;
897    
898     // Duplex
899     if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
900         jack_log("JackCoreAudioDriver::Open duplex");
901          
902         // Same device for capture and playback...
903         if (strcmp(capture_driver_uid, playback_driver_uid) == 0)  {
904            
905             if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
906                 jack_log("Will take default in/out");
907                 if (GetDefaultDevice(&fDeviceID) != noErr) {
908                     jack_error("Cannot open default device");
909                     return -1;
910                 }
911             }
912             if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
913                 jack_error("Cannot get device name from device ID");
914                 return -1;
915             }
916            
917         } else {
918        
919             // Creates aggregate device
920             AudioDeviceID captureID, playbackID;
921            
922             if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
923                 jack_log("Will take default input");
924                 if (GetDefaultInputDevice(&captureID) != noErr) {
925                     jack_error("Cannot open default device");
926                     return -1;
927                 }
928             }
929
930             if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
931                 jack_log("Will take default output");
932                 if (GetDefaultOutputDevice(&playbackID) != noErr) {
933                     jack_error("Cannot open default device");
934                     return -1;
935                 }
936             }
937
938             if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr)
939                 return -1;
940         }
941
942     // Capture only
943     } else if (strcmp(capture_driver_uid, "") != 0) {
944         jack_log("JackCoreAudioDriver::Open capture only");
945         if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
946             jack_log("Will take default input");
947             if (GetDefaultInputDevice(&fDeviceID) != noErr) {
948                 jack_error("Cannot open default device");
949                 return -1;
950             }
951         }
952         if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) {
953             jack_error("Cannot get device name from device ID");
954             return -1;
955         }
956
957     // Playback only
958     } else if (strcmp(playback_driver_uid, "") != 0) {
959         jack_log("JackCoreAudioDriver::Open playback only");
960         if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
961             jack_log("Will take default output");
962             if (GetDefaultOutputDevice(&fDeviceID) != noErr) {
963                 jack_error("Cannot open default device");
964                 return -1;
965             }
966         }
967         if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
968             jack_error("Cannot get device name from device ID");
969             return -1;
970         }
971
972     // Use default driver in duplex mode
973     } else {
974         jack_log("JackCoreAudioDriver::Open default driver");
975         if (GetDefaultDevice(&fDeviceID) != noErr) {
976             jack_error("Cannot open default device");
977             return -1;
978         }
979         if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
980             jack_error("Cannot get device name from device ID");
981             return -1;
982         }
983     }
984    
985     if (fHogged) {
986         if (TakeHog()) {
987             jack_info("Device = %ld has been hogged", fDeviceID);
988         }
989     }
990
991     return 0;
992 }
993
994 /*
995 Return the max possible input channels in in_nChannels and output channels in out_nChannels.
996 */
997 int JackCoreAudioDriver::SetupChannels(bool capturing, bool playing, int& inchannels, int& outchannels, int& in_nChannels, int& out_nChannels, bool strict)
998 {
999     OSStatus err = noErr;
1000
1001     if (capturing) {
1002         err = GetTotalChannels(fDeviceID, in_nChannels, true);
1003         if (err != noErr) {
1004             jack_error("Cannot get input channel number");
1005             printError(err);
1006             return -1;
1007         } else {
1008             jack_log("Max input channels : %d", in_nChannels);
1009         }
1010     }
1011
1012     if (playing) {
1013         err = GetTotalChannels(fDeviceID, out_nChannels, false);
1014         if (err != noErr) {
1015             jack_error("Cannot get output channel number");
1016             printError(err);
1017             return -1;
1018         } else {
1019             jack_log("Max output channels : %d", out_nChannels);
1020         }
1021     }
1022
1023     if (inchannels > in_nChannels) {
1024         jack_error("This device hasn't required input channels inchannels = %d in_nChannels = %d", inchannels, in_nChannels);
1025         if (strict)
1026             return -1;
1027     }
1028
1029     if (outchannels > out_nChannels) {
1030         jack_error("This device hasn't required output channels outchannels = %d out_nChannels = %d", outchannels, out_nChannels);
1031         if (strict)
1032             return -1;
1033     }
1034
1035     if (inchannels == -1) {
1036         jack_log("Setup max in channels = %d", in_nChannels);
1037         inchannels = in_nChannels;
1038     }
1039
1040     if (outchannels == -1) {
1041         jack_log("Setup max out channels = %d", out_nChannels);
1042         outchannels = out_nChannels;
1043     }
1044
1045     return 0;
1046 }
1047
1048 int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size)
1049 {
1050     // Setting buffer size
1051     UInt32 outSize = sizeof(UInt32);
1052     OSStatus err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size);
1053     if (err != noErr) {
1054         jack_error("Cannot set buffer size %ld", buffer_size);
1055         printError(err);
1056         return -1;
1057     }
1058
1059     return 0;
1060 }
1061
1062 int JackCoreAudioDriver::SetupSampleRate(jack_nframes_t samplerate)
1063 {
1064     return SetupSampleRateAux(fDeviceID, samplerate);
1065 }
1066
1067 int JackCoreAudioDriver::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframes_t samplerate)
1068 {
1069     OSStatus err = noErr;
1070     UInt32 outSize;
1071     Float64 sampleRate;
1072
1073     // Get sample rate
1074     outSize =  sizeof(Float64);
1075     err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
1076     if (err != noErr) {
1077         jack_error("Cannot get current sample rate");
1078         printError(err);
1079         return -1;
1080     } else {
1081         jack_log("Current sample rate = %f", sampleRate);
1082     }
1083
1084     // If needed, set new sample rate
1085     if (samplerate != (jack_nframes_t)sampleRate) {
1086         sampleRate = (Float64)samplerate;
1087
1088         // To get SR change notification
1089         err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
1090         if (err != noErr) {
1091             jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
1092             printError(err);
1093             return -1;
1094         }
1095         err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
1096         if (err != noErr) {
1097             jack_error("Cannot set sample rate = %ld", samplerate);
1098             printError(err);
1099             return -1;
1100         }
1101
1102         // Waiting for SR change notification
1103         int count = 0;
1104         while (!fState && count++ < WAIT_COUNTER) {
1105             usleep(100000);
1106             jack_log("Wait count = %d", count);
1107         }
1108        
1109         // Check new sample rate
1110         outSize =  sizeof(Float64);
1111         err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
1112         if (err != noErr) {
1113             jack_error("Cannot get current sample rate");
1114             printError(err);
1115         } else {
1116             jack_log("Checked sample rate = %f", sampleRate);
1117         }
1118
1119         // Remove SR change notification
1120         AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
1121     }
1122
1123     return 0;
1124 }
1125
1126 int JackCoreAudioDriver::OpenAUHAL(bool capturing,
1127                                    bool playing,
1128                                    int inchannels,
1129                                    int outchannels,
1130                                    int in_nChannels,
1131                                    int out_nChannels,
1132                                    jack_nframes_t buffer_size,
1133                                    jack_nframes_t samplerate)
1134 {
1135     ComponentResult err1;
1136     UInt32 enableIO;
1137     AudioStreamBasicDescription srcFormat, dstFormat;
1138     AudioDeviceID currAudioDeviceID;
1139     UInt32 size;
1140
1141     jack_log("OpenAUHAL capturing = %d playing = %d inchannels = %d outchannels = %d in_nChannels = %d out_nChannels = %d", capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels);
1142
1143     if (inchannels == 0 && outchannels == 0) {
1144         jack_error("No input and output channels...");
1145         return -1;
1146     }
1147          
1148     // AUHAL
1149     ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
1150     Component HALOutput = FindNextComponent(NULL, &cd);
1151
1152     err1 = OpenAComponent(HALOutput, &fAUHAL);
1153     if (err1 != noErr) {
1154         jack_error("Error calling OpenAComponent");
1155         printError(err1);
1156         goto error;
1157     }
1158
1159     err1 = AudioUnitInitialize(fAUHAL);
1160     if (err1 != noErr) {
1161         jack_error("Cannot initialize AUHAL unit");
1162         printError(err1);
1163         goto error;
1164     }
1165
1166     // Start I/O
1167     if (capturing && inchannels > 0) {
1168         enableIO = 1;
1169         jack_log("Setup AUHAL input on");
1170     } else {
1171         enableIO = 0;
1172         jack_log("Setup AUHAL input off");
1173     }
1174    
1175     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
1176     if (err1 != noErr) {
1177         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
1178         printError(err1);
1179         goto error;
1180     }
1181
1182     if (playing && outchannels > 0) {
1183         enableIO = 1;
1184         jack_log("Setup AUHAL output on");
1185     } else {
1186         enableIO = 0;
1187         jack_log("Setup AUHAL output off");
1188     }
1189    
1190     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
1191     if (err1 != noErr) {
1192         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
1193         printError(err1);
1194         goto error;
1195     }
1196    
1197     size = sizeof(AudioDeviceID);
1198     err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size);
1199     if (err1 != noErr) {
1200         jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
1201         printError(err1);
1202         goto error;
1203     } else {
1204         jack_log("AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID);
1205     }
1206
1207     // Setup up choosen device, in both input and output cases
1208     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
1209     if (err1 != noErr) {
1210         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
1211         printError(err1);
1212         goto error;
1213     }
1214  
1215     // Set buffer size
1216     if (capturing && inchannels > 0) {
1217         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32));
1218         if (err1 != noErr) {
1219             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
1220             printError(err1);
1221             goto error;
1222         }
1223     }
1224
1225     if (playing && outchannels > 0) {
1226         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&buffer_size, sizeof(UInt32));
1227         if (err1 != noErr) {
1228             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
1229             printError(err1);
1230             goto error;
1231         }
1232     }
1233
1234     // Setup channel map
1235     if (capturing && inchannels > 0 && inchannels < in_nChannels) {
1236         SInt32 chanArr[in_nChannels];
1237         for (int i = 0; i < in_nChannels; i++) {
1238             chanArr[i] = -1;
1239         }
1240         for (int i = 0; i < inchannels; i++) {
1241             chanArr[i] = i;
1242         }
1243         AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
1244         if (err1 != noErr) {
1245             jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
1246             printError(err1);
1247             goto error;
1248         }
1249     }
1250
1251     if (playing && outchannels > 0 && outchannels < out_nChannels) {
1252         SInt32 chanArr[out_nChannels];
1253         for (int i = 0; i < out_nChannels; i++) {
1254             chanArr[i] = -1;
1255         }
1256         for (int i = 0; i < outchannels; i++) {
1257             chanArr[i] = i;
1258         }
1259         err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
1260         if (err1 != noErr) {
1261             jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
1262             printError(err1);
1263             goto error;
1264         }
1265     }
1266
1267     // Setup stream converters
1268     if (capturing && inchannels > 0) {
1269    
1270         size = sizeof(AudioStreamBasicDescription);
1271         err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &size);
1272         if (err1 != noErr) {
1273             jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
1274             printError(err1);
1275             goto error;
1276         }
1277         PrintStreamDesc(&srcFormat);
1278              
1279         jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
1280         srcFormat.mSampleRate = samplerate;
1281         srcFormat.mFormatID = kAudioFormatLinearPCM;
1282         srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
1283         srcFormat.mBytesPerPacket = sizeof(float);
1284         srcFormat.mFramesPerPacket = 1;
1285         srcFormat.mBytesPerFrame = sizeof(float);
1286         srcFormat.mChannelsPerFrame = inchannels;
1287         srcFormat.mBitsPerChannel = 32;
1288         PrintStreamDesc(&srcFormat);
1289      
1290         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
1291         if (err1 != noErr) {
1292             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
1293             printError(err1);
1294             goto error;
1295         }
1296     }
1297
1298     if (playing && outchannels > 0) {
1299    
1300         size = sizeof(AudioStreamBasicDescription);
1301         err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &size);
1302         if (err1 != noErr) {
1303             jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
1304             printError(err1);
1305             goto error;
1306         }
1307         PrintStreamDesc(&dstFormat);
1308          
1309         jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
1310         dstFormat.mSampleRate = samplerate;
1311         dstFormat.mFormatID = kAudioFormatLinearPCM;
1312         dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
1313         dstFormat.mBytesPerPacket = sizeof(float);
1314         dstFormat.mFramesPerPacket = 1;
1315         dstFormat.mBytesPerFrame = sizeof(float);
1316         dstFormat.mChannelsPerFrame = outchannels;
1317         dstFormat.mBitsPerChannel = 32;
1318         PrintStreamDesc(&dstFormat);
1319        
1320         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
1321         if (err1 != noErr) {
1322             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
1323             printError(err1);
1324             goto error;
1325         }
1326     }
1327
1328     // Setup callbacks
1329     if (inchannels > 0 && outchannels == 0) {
1330         AURenderCallbackStruct output;
1331         output.inputProc = Render;
1332         output.inputProcRefCon = this;
1333         err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
1334         if (err1 != noErr) {
1335             jack_error("Error calling  AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
1336             printError(err1);
1337             goto error;
1338         }
1339     } else {
1340         AURenderCallbackStruct output;
1341         output.inputProc = Render;
1342         output.inputProcRefCon = this;
1343         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
1344         if (err1 != noErr) {
1345             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
1346             printError(err1);
1347             goto error;
1348         }
1349     }
1350
1351     return 0;
1352    
1353 error:
1354     CloseAUHAL();
1355     return -1;
1356 }
1357
1358 int JackCoreAudioDriver::SetupBuffers(int inchannels)
1359 {
1360     // Prepare buffers
1361     fJackInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
1362     fJackInputData->mNumberBuffers = inchannels;
1363     for (int i = 0; i < fCaptureChannels; i++) {
1364         fJackInputData->mBuffers[i].mNumberChannels = 1;
1365         fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float);
1366     }
1367     return 0;
1368 }
1369
1370 void JackCoreAudioDriver::DisposeBuffers()
1371 {
1372     if (fJackInputData) {
1373         free(fJackInputData);
1374         fJackInputData = 0;
1375     }
1376 }
1377
1378 void JackCoreAudioDriver::CloseAUHAL()
1379 {
1380     AudioUnitUninitialize(fAUHAL);
1381     CloseComponent(fAUHAL);
1382 }
1383
1384 int JackCoreAudioDriver::AddListeners()
1385 {
1386     OSStatus err = noErr;
1387
1388     // Add listeners
1389     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
1390     if (err != noErr) {
1391         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
1392         printError(err);
1393         return -1;
1394     }
1395
1396     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this);
1397     if (err != noErr) {
1398         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices");
1399         printError(err);
1400         return -1;
1401     }
1402
1403     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this);
1404     if (err != noErr) {
1405         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
1406         printError(err);
1407         return -1;
1408     }
1409
1410     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this);
1411     if (err != noErr) {
1412         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
1413         printError(err);
1414         return -1;
1415     }
1416
1417     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
1418     if (err != noErr) {
1419         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1420         printError(err);
1421         return -1;
1422     }
1423
1424     err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
1425     if (err != noErr) {
1426         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1427         printError(err);
1428         return -1;
1429     }
1430
1431     if (!fEngineControl->fSyncMode && fIOUsage != 1.f) {
1432         UInt32 outSize = sizeof(float);
1433         err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyIOCycleUsage, outSize, &fIOUsage);
1434         if (err != noErr) {
1435             jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage");
1436             printError(err);
1437         }
1438     }
1439
1440     return 0;
1441 }
1442
1443 void JackCoreAudioDriver::RemoveListeners()
1444 {
1445     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback);
1446     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback);
1447     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback);
1448     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback);
1449     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
1450     AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
1451 }
1452
1453 int JackCoreAudioDriver::Open(jack_nframes_t buffer_size,
1454                               jack_nframes_t samplerate,
1455                               bool capturing,
1456                               bool playing,
1457                               int inchannels,
1458                               int outchannels,
1459                               bool monitor,
1460                               const char* capture_driver_uid,
1461                               const char* playback_driver_uid,
1462                               jack_nframes_t capture_latency,
1463                               jack_nframes_t playback_latency,
1464                               int async_output_latency,
1465                               int computation_grain,
1466                               bool hogged,
1467                               bool clock_drift)
1468 {
1469     int in_nChannels = 0;
1470     int out_nChannels = 0;
1471     char capture_driver_name[256];
1472     char playback_driver_name[256];
1473
1474     // Keep initial state
1475     fCapturing = capturing;
1476     fPlaying = playing;
1477     fInChannels = inchannels;
1478     fOutChannels = outchannels;
1479     fMonitor = monitor;
1480     strcpy(fCaptureUID, capture_driver_uid);
1481     strcpy(fPlaybackUID, playback_driver_uid);
1482     fCaptureLatency = capture_latency;
1483     fPlaybackLatency = playback_latency;
1484     fIOUsage = float(async_output_latency) / 100.f;
1485     fComputationGrain = float(computation_grain) / 100.f;
1486     fHogged = hogged;
1487     fClockDriftCompensate = clock_drift;
1488    
1489     SInt32 major;
1490     SInt32 minor;
1491     Gestalt(gestaltSystemVersionMajor, &major);
1492     Gestalt(gestaltSystemVersionMinor, &minor);
1493    
1494     // Starting with 10.6 systems, the HAL notification thread is created internally
1495     if (major == 10 && minor >= 6) {
1496         CFRunLoopRef theRunLoop = NULL;
1497         AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1498         OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
1499         if (osErr != noErr) {
1500             jack_error("JackCoreAudioDriver::Open kAudioHardwarePropertyRunLoop error");
1501             printError(osErr);
1502         }
1503     }
1504
1505     if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name, samplerate) < 0)
1506         goto error;
1507
1508     // Generic JackAudioDriver Open
1509     if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
1510         goto error;
1511
1512     if (SetupChannels(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, true) < 0)
1513         goto error;
1514
1515     if (SetupBufferSize(buffer_size) < 0)
1516         goto error;
1517        
1518     if (SetupSampleRate(samplerate) < 0)
1519         goto error;
1520  
1521     if (OpenAUHAL(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, buffer_size, samplerate) < 0)
1522         goto error;
1523
1524     if (capturing && inchannels > 0)
1525         if (SetupBuffers(inchannels) < 0)
1526             goto error;
1527
1528     if (AddListeners() < 0)
1529         goto error;
1530  
1531     // Core driver may have changed the in/out values
1532     fCaptureChannels = inchannels;
1533     fPlaybackChannels = outchannels;
1534     return noErr;
1535
1536 error:
1537     Close();
1538     return -1;
1539 }
1540
1541 int JackCoreAudioDriver::Close()
1542 {
1543     jack_log("JackCoreAudioDriver::Close");
1544     Stop();
1545     JackAudioDriver::Close();
1546     RemoveListeners();
1547     DisposeBuffers();
1548     CloseAUHAL();
1549     DestroyAggregateDevice();
1550     return 0;
1551 }
1552
1553 int JackCoreAudioDriver::Attach()
1554 {
1555     OSStatus err;
1556     JackPort* port;
1557     jack_port_id_t port_index;
1558     UInt32 size;
1559     Boolean isWritable;
1560     char channel_name[64];
1561     char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
1562     char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
1563  
1564     jack_log("JackCoreAudioDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
1565
1566     for (int i = 0; i < fCaptureChannels; i++) {
1567
1568         err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable);
1569         if (err != noErr)
1570             jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error ");
1571         if (err == noErr && size > 0) {
1572             err = AudioDeviceGetProperty(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, channel_name);
1573             if (err != noErr)
1574                 jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error ");
1575             snprintf(alias, sizeof(alias) - 1, "%s:%s:out_%s%u", fAliasName, fCaptureDriverName, channel_name, i + 1);
1576         } else {
1577             snprintf(alias, sizeof(alias) - 1, "%s:%s:out%u", fAliasName, fCaptureDriverName, i + 1);
1578         }
1579
1580         snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
1581
1582         if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
1583             jack_error("Cannot register port for %s", name);
1584             return -1;
1585         }
1586
1587         size = sizeof(UInt32);
1588         UInt32 value1 = 0;
1589         UInt32 value2 = 0;
1590         err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1);
1591         if (err != noErr)
1592             jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error ");
1593         err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2);
1594         if (err != noErr)
1595             jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error ");
1596
1597         port = fGraphManager->GetPort(port_index);
1598         port->SetAlias(alias);
1599         port->SetLatency(fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency);
1600         fCapturePortList[i] = port_index;
1601     }
1602
1603     for (int i = 0; i < fPlaybackChannels; i++) {
1604
1605         err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, &isWritable);
1606         if (err != noErr)
1607             jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error ");
1608         if (err == noErr && size > 0) {
1609             err = AudioDeviceGetProperty(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, channel_name);
1610             if (err != noErr)
1611                 jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error ");
1612             snprintf(alias, sizeof(alias) - 1, "%s:%s:in_%s%u", fAliasName, fPlaybackDriverName, channel_name, i + 1);
1613         } else {
1614             snprintf(alias, sizeof(alias) - 1, "%s:%s:in%u", fAliasName, fPlaybackDriverName, i + 1);
1615         }
1616
1617         snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
1618
1619         if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
1620             jack_error("Cannot register port for %s", name);
1621             return -1;
1622         }
1623
1624         size = sizeof(UInt32);
1625         UInt32 value1 = 0;
1626         UInt32 value2 = 0;
1627         err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyLatency, &size, &value1);
1628         if (err != noErr)
1629             jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error ");
1630         err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2);
1631         if (err != noErr)
1632             jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error ");
1633
1634         port = fGraphManager->GetPort(port_index);
1635         port->SetAlias(alias);
1636         // Add more latency if "async" mode is used...
1637         port->SetLatency(fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize * fIOUsage) + value1 + value2 + fPlaybackLatency);
1638         fPlaybackPortList[i] = port_index;
1639
1640         // Monitor ports
1641         if (fWithMonitorPorts) {
1642             jack_log("Create monitor port ");
1643             snprintf(name, sizeof(name) - 1, "%s:monitor_%u", fClientControl.fName, i + 1);
1644             if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
1645                 jack_error("Cannot register monitor port for %s", name);
1646                 return -1;
1647             } else {
1648                 port = fGraphManager->GetPort(port_index);
1649                 port->SetAlias(alias);
1650                 port->SetLatency(fEngineControl->fBufferSize);
1651                 fMonitorPortList[i] = port_index;
1652             }
1653         }
1654     }
1655
1656     // Input buffers do no change : prepare them only once
1657     for (int i = 0; i < fCaptureChannels; i++) {
1658         fJackInputData->mBuffers[i].mData = GetInputBuffer(i);
1659     }
1660
1661     return 0;
1662 }
1663
1664 int JackCoreAudioDriver::Start()
1665 {
1666     jack_log("JackCoreAudioDriver::Start");
1667     JackAudioDriver::Start();
1668 /*
1669 #ifdef MAC_OS_X_VERSION_10_5
1670     OSStatus err = AudioDeviceCreateIOProcID(fDeviceID, MeasureCallback, this, &fMesureCallbackID);
1671 #else
1672     OSStatus err = AudioDeviceAddIOProc(fDeviceID, MeasureCallback, this);
1673 #endif
1674 */
1675     OSStatus err = AudioDeviceAddIOProc(fDeviceID, MeasureCallback, this);
1676    
1677     if (err != noErr)
1678         return -1;
1679
1680     err = AudioOutputUnitStart(fAUHAL);
1681     if (err != noErr)
1682         return -1;
1683
1684     if ((err = AudioDeviceStart(fDeviceID, MeasureCallback)) != noErr) {
1685         jack_error("Cannot start MeasureCallback");
1686         printError(err);
1687         return -1;
1688     }
1689    
1690     // Waiting for Measure callback to be called (= driver has started)
1691     fState = false;
1692     int count = 0;
1693     while (!fState && count++ < WAIT_COUNTER) {
1694         usleep(100000);
1695         jack_log("JackCoreAudioDriver::Start wait count = %d", count);
1696     }
1697    
1698     if (count < WAIT_COUNTER) {
1699         jack_info("CoreAudio driver is running...");
1700         return 0;
1701     } else {
1702         jack_error("CoreAudio driver cannot start...");
1703         return -1;
1704     }
1705 }
1706
1707 int JackCoreAudioDriver::Stop()
1708 {
1709     jack_log("JackCoreAudioDriver::Stop");
1710     AudioDeviceStop(fDeviceID, MeasureCallback);
1711 /*
1712 #ifdef MAC_OS_X_VERSION_10_5
1713     AudioDeviceDestroyIOProcID(fDeviceID, fMesureCallbackID);
1714 #else
1715     AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback);
1716 #endif
1717 */
1718     AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback);
1719     return (AudioOutputUnitStop(fAUHAL) == noErr) ? 0 : -1;
1720 }
1721
1722 int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
1723 {
1724     OSStatus err;
1725     UInt32 outSize = sizeof(UInt32);
1726
1727     err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size);
1728     if (err != noErr) {
1729         jack_error("Cannot set buffer size %ld", buffer_size);
1730         printError(err);
1731         return -1;
1732     }
1733
1734     JackAudioDriver::SetBufferSize(buffer_size); // never fails
1735
1736     // Input buffers do no change : prepare them only once
1737     for (int i = 0; i < fCaptureChannels; i++) {
1738         fJackInputData->mBuffers[i].mNumberChannels = 1;
1739         fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float);
1740         fJackInputData->mBuffers[i].mData = GetInputBuffer(i);
1741     }
1742
1743     return 0;
1744 }
1745
1746 bool JackCoreAudioDriver::TakeHogAux(AudioDeviceID deviceID, bool isInput)
1747 {
1748     pid_t hog_pid;
1749     OSStatus err;
1750
1751     UInt32 propSize = sizeof(hog_pid);
1752     err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyHogMode, &propSize, &hog_pid);
1753     if (err) {
1754         jack_error("Cannot read hog state...");
1755         printError(err);
1756     }
1757
1758     if (hog_pid != getpid()) {
1759         hog_pid = getpid();
1760         err = AudioDeviceSetProperty(deviceID, 0, 0, isInput, kAudioDevicePropertyHogMode, propSize, &hog_pid);
1761         if (err != noErr) {
1762             jack_error("Can't hog device = %d because it's being hogged by another program or cannot be hogged", deviceID);
1763             return false;
1764         }
1765     }
1766    
1767     return true;
1768 }
1769    
1770 bool JackCoreAudioDriver::TakeHog()
1771 {
1772     OSStatus err = noErr;
1773     AudioObjectID sub_device[32];
1774     UInt32 outSize = sizeof(sub_device);
1775     err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
1776    
1777     if (err != noErr) {
1778         jack_log("Device does not have subdevices");
1779         return TakeHogAux(fDeviceID, true);
1780     } else {
1781         int num_devices = outSize / sizeof(AudioObjectID);
1782         jack_log("Device does has %d subdevices", num_devices);
1783         for (int i = 0; i < num_devices; i++) {
1784             if (!TakeHogAux(sub_device[i], true)) {
1785                 return false;
1786             }
1787         }
1788         return true;
1789     }
1790 }
1791    
1792 bool JackCoreAudioDriver::IsAggregateDevice(AudioDeviceID device)
1793 {
1794     UInt32 deviceType, outSize = sizeof(UInt32);
1795     OSStatus err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyTransportType, &outSize, &deviceType);
1796    
1797     if (err != noErr) {
1798         jack_log("JackCoreAudioDriver::IsAggregateDevice kAudioDevicePropertyTransportType error");
1799         return false;
1800     } else {
1801         return (deviceType == kAudioDeviceTransportTypeAggregate);
1802     }
1803 }
1804
1805
1806 } // end of namespace
1807
1808
1809 #ifdef __cplusplus
1810 extern "C"
1811 {
1812 #endif
1813
1814     SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
1815     {
1816         jack_driver_desc_t *desc;
1817         unsigned int i;
1818         desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
1819
1820         strcpy(desc->name, "coreaudio");                                    // size MUST be less then JACK_DRIVER_NAME_MAX + 1
1821         strcpy(desc->desc, "Apple CoreAudio API based audio backend");      // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
1822        
1823         desc->nparams = 17;
1824         desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
1825
1826         i = 0;
1827         strcpy(desc->params[i].name, "channels");
1828         desc->params[i].character = 'c';
1829         desc->params[i].type = JackDriverParamInt;
1830         desc->params[i].value.ui = -1;
1831         strcpy(desc->params[i].short_desc, "Maximum number of channels");
1832         strcpy(desc->params[i].long_desc, "Maximum number of channels. If -1, max possible number of channels will be used");
1833
1834         i++;
1835         strcpy(desc->params[i].name, "inchannels");
1836         desc->params[i].character = 'i';
1837         desc->params[i].type = JackDriverParamInt;
1838         desc->params[i].value.ui = -1;
1839         strcpy(desc->params[i].short_desc, "Maximum number of input channels");
1840         strcpy(desc->params[i].long_desc, "Maximum number of input channels. If -1, max possible number of input channels will be used");
1841
1842         i++;
1843         strcpy(desc->params[i].name, "outchannels");
1844         desc->params[i].character = 'o';
1845         desc->params[i].type = JackDriverParamInt;
1846         desc->params[i].value.ui = -1;
1847         strcpy(desc->params[i].short_desc, "Maximum number of output channels");
1848         strcpy(desc->params[i].long_desc, "Maximum number of output channels. If -1, max possible number of output channels will be used");
1849
1850         i++;
1851         strcpy(desc->params[i].name, "capture");
1852         desc->params[i].character = 'C';
1853         desc->params[i].type = JackDriverParamString;
1854         strcpy(desc->params[i].short_desc, "Input CoreAudio device name");
1855         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1856
1857         i++;
1858         strcpy(desc->params[i].name, "playback");
1859         desc->params[i].character = 'P';
1860         desc->params[i].type = JackDriverParamString;
1861         strcpy(desc->params[i].short_desc, "Output CoreAudio device name");
1862         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1863
1864         i++;
1865         strcpy (desc->params[i].name, "monitor");
1866         desc->params[i].character = 'm';
1867         desc->params[i].type = JackDriverParamBool;
1868         desc->params[i].value.i = 0;
1869         strcpy(desc->params[i].short_desc, "Provide monitor ports for the output");
1870         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1871
1872         i++;
1873         strcpy(desc->params[i].name, "duplex");
1874         desc->params[i].character = 'D';
1875         desc->params[i].type = JackDriverParamBool;
1876         desc->params[i].value.i = TRUE;
1877         strcpy(desc->params[i].short_desc, "Provide both capture and playback ports");
1878         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1879
1880         i++;
1881         strcpy(desc->params[i].name, "rate");
1882         desc->params[i].character = 'r';
1883         desc->params[i].type = JackDriverParamUInt;
1884         desc->params[i].value.ui = 44100U;
1885         strcpy(desc->params[i].short_desc, "Sample rate");
1886         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1887
1888         i++;
1889         strcpy(desc->params[i].name, "period");
1890         desc->params[i].character = 'p';
1891         desc->params[i].type = JackDriverParamUInt;
1892         desc->params[i].value.ui = 128U;
1893         strcpy(desc->params[i].short_desc, "Frames per period");
1894         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1895
1896         i++;
1897         strcpy(desc->params[i].name, "device");
1898         desc->params[i].character = 'd';
1899         desc->params[i].type = JackDriverParamString;
1900         strcpy(desc->params[i].short_desc, "CoreAudio device name");
1901         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1902
1903         i++;
1904         strcpy(desc->params[i].name, "input-latency");
1905         desc->params[i].character = 'I';
1906         desc->params[i].type = JackDriverParamUInt;
1907         desc->params[i].value.i = 0;
1908         strcpy(desc->params[i].short_desc, "Extra input latency (frames)");
1909         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1910
1911         i++;
1912         strcpy(desc->params[i].name, "output-latency");
1913         desc->params[i].character = 'O';
1914         desc->params[i].type = JackDriverParamUInt;
1915         desc->params[i].value.i = 0;
1916         strcpy(desc->params[i].short_desc, "Extra output latency (frames)");
1917         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1918
1919         i++;
1920         strcpy(desc->params[i].name, "list-devices");
1921         desc->params[i].character = 'l';
1922         desc->params[i].type = JackDriverParamBool;
1923         desc->params[i].value.i = FALSE;
1924         strcpy(desc->params[i].short_desc, "Display available CoreAudio devices");
1925         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1926        
1927         i++;
1928         strcpy(desc->params[i].name, "hog");
1929         desc->params[i].character = 'H';
1930         desc->params[i].type = JackDriverParamBool;
1931         desc->params[i].value.i = FALSE;
1932         strcpy(desc->params[i].short_desc, "Take exclusive access of the audio device");
1933         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1934        
1935         i++;
1936         strcpy(desc->params[i].name, "async-latency");
1937         desc->params[i].character = 'L';
1938         desc->params[i].type = JackDriverParamUInt;
1939         desc->params[i].value.i = 100;
1940         strcpy(desc->params[i].short_desc, "Extra output latency in asynchronous mode (percent)");
1941         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1942        
1943         i++;
1944         strcpy(desc->params[i].name, "grain");
1945         desc->params[i].character = 'G';
1946         desc->params[i].type = JackDriverParamUInt;
1947         desc->params[i].value.i = 100;
1948         strcpy(desc->params[i].short_desc, "Computation grain in RT thread (percent)");
1949         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1950        
1951         i++;
1952         strcpy(desc->params[i].name, "clock-drift");
1953         desc->params[i].character = 's';
1954         desc->params[i].type = JackDriverParamBool;
1955         desc->params[i].value.i = FALSE;
1956         strcpy(desc->params[i].short_desc, "Clock drift compensation");
1957         strcpy(desc->params[i].long_desc, "Whether to compensate clock drift in dynamically created aggregate device");
1958
1959         return desc;
1960     }
1961
1962     SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
1963     {
1964         jack_nframes_t srate = 44100;
1965         jack_nframes_t frames_per_interrupt = 128;
1966         bool capture = false;
1967         bool playback = false;
1968         int chan_in = -1;   // Default: if not explicitely set, then max possible will be used...
1969         int chan_out = -1;  // Default: ifĂ  not explicitely set, then max possible will be used...
1970         bool monitor = false;
1971         const char* capture_driver_uid = "";
1972         const char* playback_driver_uid = "";
1973         const JSList *node;
1974         const jack_driver_param_t *param;
1975         jack_nframes_t systemic_input_latency = 0;
1976         jack_nframes_t systemic_output_latency = 0;
1977         int async_output_latency = 100;
1978         int computation_grain = -1;
1979         bool hogged = false;
1980         bool clock_drift = false;
1981    
1982         for (node = params; node; node = jack_slist_next(node)) {
1983             param = (const jack_driver_param_t *) node->data;
1984        
1985             switch (param->character) {
1986
1987                 case 'd':
1988                     capture_driver_uid = strdup(param->value.str);
1989                     playback_driver_uid = strdup(param->value.str);
1990                     break;
1991
1992                 case 'D':
1993                     capture = true;
1994                     playback = true;
1995                     break;
1996
1997                 case 'c':
1998                     chan_in = chan_out = (int)param->value.ui;
1999                     break;
2000
2001                 case 'i':
2002                     chan_in = (int)param->value.ui;
2003                     break;
2004
2005                 case 'o':
2006                     chan_out = (int)param->value.ui;
2007                     break;
2008
2009                 case 'C':
2010                     capture = true;
2011                     if (strcmp(param->value.str, "none") != 0) {
2012                         capture_driver_uid = strdup(param->value.str);
2013                     }
2014                     break;
2015
2016                 case 'P':
2017                     playback = true;
2018                     if (strcmp(param->value.str, "none") != 0) {
2019                         playback_driver_uid = strdup(param->value.str);
2020                     }
2021                     break;
2022
2023                 case 'm':
2024                     monitor = param->value.i;
2025                     break;
2026
2027                 case 'r':
2028                     srate = param->value.ui;
2029                     break;
2030
2031                 case 'p':
2032                     frames_per_interrupt = (unsigned int)param->value.ui;
2033                     break;
2034
2035                 case 'I':
2036                     systemic_input_latency = param->value.ui;
2037                     break;
2038
2039                 case 'O':
2040                     systemic_output_latency = param->value.ui;
2041                     break;
2042
2043                 case 'l':
2044                     Jack::DisplayDeviceNames();
2045                     break;
2046                    
2047                 case 'H':
2048                     hogged = true;
2049                     break;
2050                    
2051                 case 'L':
2052                     async_output_latency = param->value.ui;
2053                     break;
2054                    
2055                 case 'G':
2056                     computation_grain = param->value.ui;
2057                     break;
2058                    
2059                 case 's':
2060                     clock_drift = true;
2061                     break;
2062             }
2063         }
2064
2065         /* duplex is the default */
2066         if (!capture && !playback) {
2067             capture = true;
2068             playback = true;
2069         }
2070
2071         Jack::JackCoreAudioDriver* driver = new Jack::JackCoreAudioDriver("system", "coreaudio", engine, table);
2072         if (driver->Open(frames_per_interrupt, srate, capture, playback, chan_in, chan_out, monitor, capture_driver_uid,
2073             playback_driver_uid, systemic_input_latency, systemic_output_latency, async_output_latency, computation_grain, hogged, clock_drift) == 0) {
2074             return driver;
2075         } else {
2076             delete driver;
2077             return NULL;
2078         }
2079     }
2080
2081 #ifdef __cplusplus
2082 }
2083 #endif
2084
2085
Note: See TracBrowser for help on using the browser.