More cleanup in JackCoreAudioDriver::DeviceNotificationCallback.
[jack2.git] / macosx / coreaudio / JackCoreAudioDriver.cpp
blob0652a5ccf4562372939ca553fe8a25d9ea9b7a25
1 /*
2 Copyright (C) 2004-2008 Grame
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.
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.
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.
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"
31 #include <iostream>
32 #include <CoreServices/CoreServices.h>
34 namespace Jack
37 static void Print4CharCode(const char* msg, long c)
39 UInt32 __4CC_number = (c);
40 char __4CC_string[5];
41 *((SInt32*)__4CC_string) = EndianU32_NtoB(__4CC_number);
42 __4CC_string[4] = 0;
43 jack_log("%s'%s'", (msg), __4CC_string);
46 static void printError(OSStatus err)
48 switch (err) {
49 case kAudioHardwareNoError:
50 jack_log("error code : kAudioHardwareNoError");
51 break;
52 case kAudioConverterErr_FormatNotSupported:
53 jack_log("error code : kAudioConverterErr_FormatNotSupported");
54 break;
55 case kAudioConverterErr_OperationNotSupported:
56 jack_log("error code : kAudioConverterErr_OperationNotSupported");
57 break;
58 case kAudioConverterErr_PropertyNotSupported:
59 jack_log("error code : kAudioConverterErr_PropertyNotSupported");
60 break;
61 case kAudioConverterErr_InvalidInputSize:
62 jack_log("error code : kAudioConverterErr_InvalidInputSize");
63 break;
64 case kAudioConverterErr_InvalidOutputSize:
65 jack_log("error code : kAudioConverterErr_InvalidOutputSize");
66 break;
67 case kAudioConverterErr_UnspecifiedError:
68 jack_log("error code : kAudioConverterErr_UnspecifiedError");
69 break;
70 case kAudioConverterErr_BadPropertySizeError:
71 jack_log("error code : kAudioConverterErr_BadPropertySizeError");
72 break;
73 case kAudioConverterErr_RequiresPacketDescriptionsError:
74 jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
75 break;
76 case kAudioConverterErr_InputSampleRateOutOfRange:
77 jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
78 break;
79 case kAudioConverterErr_OutputSampleRateOutOfRange:
80 jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
81 break;
82 case kAudioHardwareNotRunningError:
83 jack_log("error code : kAudioHardwareNotRunningError");
84 break;
85 case kAudioHardwareUnknownPropertyError:
86 jack_log("error code : kAudioHardwareUnknownPropertyError");
87 break;
88 case kAudioHardwareIllegalOperationError:
89 jack_log("error code : kAudioHardwareIllegalOperationError");
90 break;
91 case kAudioHardwareBadDeviceError:
92 jack_log("error code : kAudioHardwareBadDeviceError");
93 break;
94 case kAudioHardwareBadStreamError:
95 jack_log("error code : kAudioHardwareBadStreamError");
96 break;
97 case kAudioDeviceUnsupportedFormatError:
98 jack_log("error code : kAudioDeviceUnsupportedFormatError");
99 break;
100 case kAudioDevicePermissionsError:
101 jack_log("error code : kAudioDevicePermissionsError");
102 break;
103 case kAudioHardwareBadObjectError:
104 jack_log("error code : kAudioHardwareBadObjectError");
105 break;
106 case kAudioHardwareUnsupportedOperationError:
107 jack_log("error code : kAudioHardwareUnsupportedOperationError");
108 break;
109 default:
110 Print4CharCode("error code : unknown", err);
111 break;
115 static OSStatus DisplayDeviceNames()
117 UInt32 size;
118 Boolean isWritable;
119 int i, deviceNum;
120 OSStatus err;
121 CFStringRef UIname;
123 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
124 if (err != noErr)
125 return err;
127 deviceNum = size / sizeof(AudioDeviceID);
128 AudioDeviceID devices[deviceNum];
130 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
131 if (err != noErr)
132 return err;
134 for (i = 0; i < deviceNum; i++) {
135 char device_name[256];
136 char internal_name[256];
138 size = sizeof(CFStringRef);
139 UIname = NULL;
140 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
141 if (err == noErr) {
142 CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
143 } else {
144 goto error;
147 size = 256;
148 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
149 if (err != noErr)
150 return err;
152 jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name, internal_name);
155 return noErr;
157 error:
158 if (UIname != NULL)
159 CFRelease(UIname);
160 return err;
163 static CFStringRef GetDeviceName(AudioDeviceID id)
165 UInt32 size = sizeof(CFStringRef);
166 CFStringRef UIname;
167 OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
168 return (err == noErr) ? UIname : NULL;
171 OSStatus JackCoreAudioDriver::Render(void *inRefCon,
172 AudioUnitRenderActionFlags *ioActionFlags,
173 const AudioTimeStamp *inTimeStamp,
174 UInt32 inBusNumber,
175 UInt32 inNumberFrames,
176 AudioBufferList *ioData)
178 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inRefCon;
179 driver->fActionFags = ioActionFlags;
180 driver->fCurrentTime = (AudioTimeStamp *)inTimeStamp;
181 driver->fDriverOutputData = ioData;
182 driver->CycleTakeBeginTime();
183 return driver->Process();
186 int JackCoreAudioDriver::Read()
188 AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData);
189 return 0;
192 int JackCoreAudioDriver::Write()
194 for (int i = 0; i < fPlaybackChannels; i++) {
195 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
196 float* buffer = GetOutputBuffer(i);
197 int size = sizeof(float) * fEngineControl->fBufferSize;
198 memcpy((float*)fDriverOutputData->mBuffers[i].mData, buffer, size);
199 // Monitor ports
200 if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0)
201 memcpy(GetMonitorBuffer(i), buffer, size);
202 } else {
203 memset((float*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(float) * fEngineControl->fBufferSize);
206 return 0;
209 // Will run only once
210 OSStatus JackCoreAudioDriver::MeasureCallback(AudioDeviceID inDevice,
211 const AudioTimeStamp* inNow,
212 const AudioBufferList* inInputData,
213 const AudioTimeStamp* inInputTime,
214 AudioBufferList* outOutputData,
215 const AudioTimeStamp* inOutputTime,
216 void* inClientData)
218 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
219 AudioDeviceStop(driver->fDeviceID, MeasureCallback);
221 jack_log("JackCoreAudioDriver::MeasureCallback called");
222 JackMachThread::GetParams(pthread_self(), &driver->fEngineControl->fPeriod, &driver->fEngineControl->fComputation, &driver->fEngineControl->fConstraint);
224 if (driver->fComputationGrain > 0) {
225 jack_log("JackCoreAudioDriver::MeasureCallback : RT thread computation setup to %ld percent of period", int(driver->fComputationGrain * 100));
226 driver->fEngineControl->fComputation = driver->fEngineControl->fPeriod * driver->fComputationGrain;
229 // Setup threadded based log function
230 set_threaded_log_function();
231 return noErr;
234 OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice,
235 UInt32 inChannel,
236 Boolean isInput,
237 AudioDevicePropertyID inPropertyID,
238 void* inClientData)
240 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
242 switch (inPropertyID) {
244 case kAudioDevicePropertyNominalSampleRate: {
245 jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
246 driver->fState = true;
247 break;
251 return noErr;
254 // A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
255 OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice,
256 UInt32 inChannel,
257 Boolean isInput,
258 AudioDevicePropertyID inPropertyID,
259 void* inClientData)
261 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
263 switch (inPropertyID) {
265 case kAudioDeviceProcessorOverload: {
266 jack_error("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload");
267 jack_time_t cur_time = GetMicroSeconds();
268 driver->NotifyXRun(cur_time, float(cur_time - driver->fBeginDateUst)); // Better this value than nothing...
269 break;
272 case kAudioDevicePropertyStreamConfiguration: {
273 jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration : server will quit...");
274 driver->NotifyFailure(JackBackendError, "CoreAudio device stream configuration has changed, backend stopped.");
275 driver->CloseAUHAL();
276 kill(JackTools::GetPID(), SIGINT);
277 return kAudioHardwareUnsupportedOperationError;
280 case kAudioDevicePropertyNominalSampleRate: {
281 jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate : server will quit...");
282 driver->NotifyFailure(JackBackendError, "CoreAudio device sampling rate has changed, backend stopped.");
283 driver->CloseAUHAL();
284 kill(JackTools::GetPID(), SIGINT);
285 return kAudioHardwareUnsupportedOperationError;
289 return noErr;
292 OSStatus JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id)
294 UInt32 size = sizeof(AudioValueTranslation);
295 CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
296 AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
298 if (inIUD == NULL) {
299 return kAudioHardwareUnspecifiedError;
300 } else {
301 OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
302 CFRelease(inIUD);
303 jack_log("GetDeviceIDFromUID %s %ld", UID, *id);
304 return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
308 OSStatus JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID* id)
310 OSStatus res;
311 UInt32 theSize = sizeof(UInt32);
312 AudioDeviceID inDefault;
313 AudioDeviceID outDefault;
315 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
316 return res;
318 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
319 return res;
321 jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);
323 // Get the device only if default input and ouput are the same
324 if (inDefault == outDefault) {
325 *id = inDefault;
326 return noErr;
327 } else {
328 jack_error("Default input and output devices are not the same !!");
329 return kAudioHardwareBadDeviceError;
333 OSStatus JackCoreAudioDriver::GetDefaultInputDevice(AudioDeviceID* id)
335 OSStatus res;
336 UInt32 theSize = sizeof(UInt32);
337 AudioDeviceID inDefault;
339 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
340 return res;
342 jack_log("GetDefaultInputDevice: input = %ld ", inDefault);
343 *id = inDefault;
344 return noErr;
347 OSStatus JackCoreAudioDriver::GetDefaultOutputDevice(AudioDeviceID* id)
349 OSStatus res;
350 UInt32 theSize = sizeof(UInt32);
351 AudioDeviceID outDefault;
353 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
354 return res;
356 jack_log("GetDefaultOutputDevice: output = %ld", outDefault);
357 *id = outDefault;
358 return noErr;
361 OSStatus JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id, char* name)
363 UInt32 size = 256;
364 return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
367 OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput)
369 OSStatus err = noErr;
370 UInt32 outSize;
371 Boolean outWritable;
372 AudioBufferList* bufferList = 0;
374 channelCount = 0;
375 err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
376 if (err == noErr) {
377 bufferList = (AudioBufferList*)malloc(outSize);
378 err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
379 if (err == noErr) {
380 for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++)
381 channelCount += bufferList->mBuffers[i].mNumberChannels;
384 if (bufferList)
385 free(bufferList);
388 return err;
391 JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
392 : JackAudioDriver(name, alias, engine, table), fJackInputData(NULL), fDriverOutputData(NULL), fState(false), fIOUsage(1.f),fComputationGrain(-1.f)
395 JackCoreAudioDriver::~JackCoreAudioDriver()
398 OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, AudioDeviceID* outAggregateDevice)
400 OSStatus osErr = noErr;
401 UInt32 outSize;
402 Boolean outWritable;
404 //-----------------------
405 // Start to create a new aggregate by getting the base audio hardware plugin
406 //-----------------------
408 osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
409 if (osErr != noErr)
410 return osErr;
412 AudioValueTranslation pluginAVT;
414 CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
415 AudioObjectID pluginID;
417 pluginAVT.mInputData = &inBundleRef;
418 pluginAVT.mInputDataSize = sizeof(inBundleRef);
419 pluginAVT.mOutputData = &pluginID;
420 pluginAVT.mOutputDataSize = sizeof(pluginID);
422 osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
423 if (osErr != noErr)
424 return osErr;
426 //-----------------------
427 // Create a CFDictionary for our aggregate device
428 //-----------------------
430 CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
432 CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
433 CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
435 // add the name of the device to the dictionary
436 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
438 // add our choice of UID for the aggregate device to the dictionary
439 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
441 //-------------------------------------------------
442 // Create a CFMutableArray for our sub-device list
443 //-------------------------------------------------
445 CFStringRef captureDeviceUID = GetDeviceName(captureDeviceID);
446 CFStringRef playbackDeviceUID = GetDeviceName(playbackDeviceID);
448 if (captureDeviceUID == NULL || playbackDeviceUID == NULL)
449 return -1;
451 // we need to append the UID for each device to a CFMutableArray, so create one here
452 CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
454 // two sub-devices in this example, so append the sub-device's UID to the CFArray
455 CFArrayAppendValue(subDevicesArray, captureDeviceUID);
456 CFArrayAppendValue(subDevicesArray, playbackDeviceUID);
458 //-----------------------------------------------------------------------
459 // Feed the dictionary to the plugin, to create a blank aggregate device
460 //-----------------------------------------------------------------------
462 AudioObjectPropertyAddress pluginAOPA;
463 pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
464 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
465 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
466 UInt32 outDataSize;
468 osErr = AudioObjectGetPropertyDataSize(pluginID, &pluginAOPA, 0, NULL, &outDataSize);
469 if (osErr != noErr)
470 return osErr;
472 osErr = AudioObjectGetPropertyData(pluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
473 if (osErr != noErr)
474 return osErr;
476 // pause for a bit to make sure that everything completed correctly
477 // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
478 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
480 //-------------------------
481 // Set the sub-device list
482 //-------------------------
484 pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
485 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
486 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
487 outDataSize = sizeof(CFMutableArrayRef);
488 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
489 if (osErr != noErr)
490 return osErr;
492 // pause again to give the changes time to take effect
493 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
495 //-----------------------
496 // Set the master device
497 //-----------------------
499 // set the master device manually (this is the device which will act as the master clock for the aggregate device)
500 // pass in the UID of the device you want to use
501 pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
502 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
503 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
504 outDataSize = sizeof(CFStringRef);
505 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID); // capture is master...
506 if (osErr != noErr)
507 return osErr;
509 // pause again to give the changes time to take effect
510 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
512 //----------
513 // Clean up
514 //----------
516 // release the CF objects we have created - we don't need them any more
517 CFRelease(aggDeviceDict);
518 CFRelease(subDevicesArray);
520 // release the device UID
521 CFRelease(captureDeviceUID);
522 CFRelease(playbackDeviceUID);
524 jack_log("New aggregate device %ld", *outAggregateDevice);
525 return noErr;
528 int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char* playback_driver_uid, char* capture_driver_name, char* playback_driver_name)
530 capture_driver_name[0] = 0;
531 playback_driver_name[0] = 0;
533 // Duplex
534 if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
535 jack_log("JackCoreAudioDriver::Open duplex");
538 AudioDeviceID captureID, playbackID;
539 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr)
540 return -1;
541 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr)
542 return -1;
543 if (CreateAggregateDevice(captureID, playbackID, &fDeviceID) != noErr)
544 return -1;
547 // Same device for capture and playback...
548 if (strcmp(capture_driver_uid, playback_driver_uid) == 0) {
550 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
551 jack_log("Will take default in/out");
552 if (GetDefaultDevice(&fDeviceID) != noErr) {
553 jack_error("Cannot open default device");
554 return -1;
557 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
558 jack_error("Cannot get device name from device ID");
559 return -1;
562 } else {
564 // Creates agregate device
565 AudioDeviceID captureID, playbackID;
566 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr)
567 return -1;
568 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr)
569 return -1;
570 if (CreateAggregateDevice(captureID, playbackID, &fDeviceID) != noErr)
571 return -1;
574 // Capture only
575 } else if (strcmp(capture_driver_uid, "") != 0) {
576 jack_log("JackCoreAudioDriver::Open capture only");
577 if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
578 jack_log("Will take default input");
579 if (GetDefaultInputDevice(&fDeviceID) != noErr) {
580 jack_error("Cannot open default device");
581 return -1;
584 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) {
585 jack_error("Cannot get device name from device ID");
586 return -1;
589 // Playback only
590 } else if (strcmp(playback_driver_uid, "") != 0) {
591 jack_log("JackCoreAudioDriver::Open playback only");
592 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
593 jack_log("Will take default output");
594 if (GetDefaultOutputDevice(&fDeviceID) != noErr) {
595 jack_error("Cannot open default device");
596 return -1;
599 if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
600 jack_error("Cannot get device name from device ID");
601 return -1;
604 // Use default driver in duplex mode
605 } else {
606 jack_log("JackCoreAudioDriver::Open default driver");
607 if (GetDefaultDevice(&fDeviceID) != noErr) {
608 jack_error("Cannot open default device");
609 return -1;
611 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
612 jack_error("Cannot get device name from device ID");
613 return -1;
617 return 0;
621 Return the max possible input channels in in_nChannels and output channels in out_nChannels.
623 int JackCoreAudioDriver::SetupChannels(bool capturing, bool playing, int& inchannels, int& outchannels, int& in_nChannels, int& out_nChannels, bool strict)
625 OSStatus err = noErr;
627 if (capturing) {
628 err = GetTotalChannels(fDeviceID, in_nChannels, true);
629 if (err != noErr) {
630 jack_error("Cannot get input channel number");
631 printError(err);
632 return -1;
633 } else {
634 jack_log("Max input channels : %d", in_nChannels);
638 if (playing) {
639 err = GetTotalChannels(fDeviceID, out_nChannels, false);
640 if (err != noErr) {
641 jack_error("Cannot get output channel number");
642 printError(err);
643 return -1;
644 } else {
645 jack_log("Max output channels : %d", out_nChannels);
649 if (inchannels > in_nChannels) {
650 jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels);
651 if (strict)
652 return -1;
655 if (outchannels > out_nChannels) {
656 jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels);
657 if (strict)
658 return -1;
661 if (inchannels == 0) {
662 jack_log("Setup max in channels = %ld", in_nChannels);
663 inchannels = in_nChannels;
666 if (outchannels == 0) {
667 jack_log("Setup max out channels = %ld", out_nChannels);
668 outchannels = out_nChannels;
671 return 0;
674 int JackCoreAudioDriver::SetupBufferSizeAndSampleRate(jack_nframes_t buffer_size, jack_nframes_t samplerate)
676 OSStatus err = noErr;
677 UInt32 outSize;
678 Float64 sampleRate;
680 // Setting buffer size
681 outSize = sizeof(UInt32);
682 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size);
683 if (err != noErr) {
684 jack_error("Cannot set buffer size %ld", buffer_size);
685 printError(err);
686 return -1;
689 // Get sample rate
690 outSize = sizeof(Float64);
691 err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
692 if (err != noErr) {
693 jack_error("Cannot get current sample rate");
694 printError(err);
695 return -1;
698 // If needed, set new sample rate
699 if (samplerate != (jack_nframes_t)sampleRate) {
700 sampleRate = (Float64)samplerate;
702 // To get SR change notification
703 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
704 if (err != noErr) {
705 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
706 printError(err);
707 return -1;
709 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
710 if (err != noErr) {
711 jack_error("Cannot set sample rate = %ld", samplerate);
712 printError(err);
713 return -1;
716 // Waiting for SR change notification
717 int count = 0;
718 while (!fState && count++ < 100) {
719 usleep(100000);
720 jack_log("Wait count = %ld", count);
723 // Remove SR change notification
724 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
727 return 0;
730 int JackCoreAudioDriver::OpenAUHAL(bool capturing,
731 bool playing,
732 int inchannels,
733 int outchannels,
734 int in_nChannels,
735 int out_nChannels,
736 jack_nframes_t buffer_size,
737 jack_nframes_t samplerate,
738 bool strict)
740 ComponentResult err1;
741 UInt32 enableIO;
742 AudioStreamBasicDescription srcFormat, dstFormat;
744 jack_log("OpenAUHAL capturing = %ld playing = %ld inchannels = %ld outchannels = %ld in_nChannels = %ld out_nChannels = %ld ", capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels);
746 if (inchannels == 0 && outchannels == 0) {
747 jack_error("No input and output channels...");
748 return -1;
751 // AUHAL
752 ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
753 Component HALOutput = FindNextComponent(NULL, &cd);
755 err1 = OpenAComponent(HALOutput, &fAUHAL);
756 if (err1 != noErr) {
757 jack_error("Error calling OpenAComponent");
758 printError(err1);
759 return -1;
762 err1 = AudioUnitInitialize(fAUHAL);
763 if (err1 != noErr) {
764 jack_error("Cannot initialize AUHAL unit");
765 printError(err1);
766 return -1;
769 // Start I/O
770 if (capturing && inchannels > 0) {
771 enableIO = 1;
772 jack_log("Setup AUHAL input on");
773 } else {
774 enableIO = 0;
775 jack_log("Setup AUHAL input off");
778 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
779 if (err1 != noErr) {
780 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
781 printError(err1);
782 if (strict)
783 return -1;
786 if (playing && outchannels > 0) {
787 enableIO = 1;
788 jack_log("Setup AUHAL output on");
789 } else {
790 enableIO = 0;
791 jack_log("Setup AUHAL output off");
794 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
795 if (err1 != noErr) {
796 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
797 printError(err1);
798 if (strict)
799 return -1;
802 AudioDeviceID currAudioDeviceID;
803 UInt32 size = sizeof(AudioDeviceID);
804 err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size);
805 if (err1 != noErr) {
806 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
807 printError(err1);
808 if (strict)
809 return -1;
810 } else {
811 jack_log("AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID);
814 // Setup up choosen device, in both input and output cases
815 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
816 if (err1 != noErr) {
817 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
818 printError(err1);
819 if (strict)
820 return -1;
823 err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size);
824 if (err1 != noErr) {
825 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
826 printError(err1);
827 if (strict)
828 return -1;
829 } else {
830 jack_log("AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID);
833 // Set buffer size
834 if (capturing && inchannels > 0) {
835 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32));
836 if (err1 != noErr) {
837 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
838 printError(err1);
839 if (strict)
840 return -1;
844 if (playing && outchannels > 0) {
845 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&buffer_size, sizeof(UInt32));
846 if (err1 != noErr) {
847 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
848 printError(err1);
849 if (strict)
850 return -1;
854 // Setup channel map
855 if (capturing && inchannels > 0 && inchannels < in_nChannels) {
856 SInt32 chanArr[in_nChannels];
857 for (int i = 0; i < in_nChannels; i++) {
858 chanArr[i] = -1;
860 for (int i = 0; i < inchannels; i++) {
861 chanArr[i] = i;
863 AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
864 if (err1 != noErr) {
865 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
866 printError(err1);
870 if (playing && outchannels > 0 && outchannels < out_nChannels) {
871 SInt32 chanArr[out_nChannels];
872 for (int i = 0; i < out_nChannels; i++) {
873 chanArr[i] = -1;
875 for (int i = 0; i < outchannels; i++) {
876 chanArr[i] = i;
878 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
879 if (err1 != noErr) {
880 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
881 printError(err1);
885 // Setup stream converters
886 jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
887 srcFormat.mSampleRate = samplerate;
888 srcFormat.mFormatID = kAudioFormatLinearPCM;
889 srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
890 srcFormat.mBytesPerPacket = sizeof(float);
891 srcFormat.mFramesPerPacket = 1;
892 srcFormat.mBytesPerFrame = sizeof(float);
893 srcFormat.mChannelsPerFrame = outchannels;
894 srcFormat.mBitsPerChannel = 32;
896 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription));
897 if (err1 != noErr) {
898 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
899 printError(err1);
902 jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
903 dstFormat.mSampleRate = samplerate;
904 dstFormat.mFormatID = kAudioFormatLinearPCM;
905 dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
906 dstFormat.mBytesPerPacket = sizeof(float);
907 dstFormat.mFramesPerPacket = 1;
908 dstFormat.mBytesPerFrame = sizeof(float);
909 dstFormat.mChannelsPerFrame = inchannels;
910 dstFormat.mBitsPerChannel = 32;
912 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription));
913 if (err1 != noErr) {
914 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
915 printError(err1);
918 // Setup callbacks
919 if (inchannels > 0 && outchannels == 0) {
920 AURenderCallbackStruct output;
921 output.inputProc = Render;
922 output.inputProcRefCon = this;
923 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
924 if (err1 != noErr) {
925 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
926 printError(err1);
927 return -1;
929 } else {
930 AURenderCallbackStruct output;
931 output.inputProc = Render;
932 output.inputProcRefCon = this;
933 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
934 if (err1 != noErr) {
935 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
936 printError(err1);
937 return -1;
941 return 0;
944 int JackCoreAudioDriver::SetupBuffers(int inchannels)
946 // Prepare buffers
947 fJackInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
948 if (fJackInputData == 0) {
949 jack_error("Cannot allocate memory for input buffers");
950 return -1;
952 fJackInputData->mNumberBuffers = inchannels;
953 for (int i = 0; i < fCaptureChannels; i++) {
954 fJackInputData->mBuffers[i].mNumberChannels = 1;
955 fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float);
957 return 0;
960 void JackCoreAudioDriver::DisposeBuffers()
962 if (fJackInputData) {
963 free(fJackInputData);
964 fJackInputData = 0;
968 void JackCoreAudioDriver::CloseAUHAL()
970 AudioUnitUninitialize(fAUHAL);
971 CloseComponent(fAUHAL);
974 int JackCoreAudioDriver::AddListeners()
976 OSStatus err = noErr;
978 // Add listeners
979 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
980 if (err != noErr) {
981 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
982 printError(err);
983 return -1;
986 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this);
987 if (err != noErr) {
988 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices");
989 printError(err);
990 return -1;
993 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this);
994 if (err != noErr) {
995 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
996 printError(err);
997 return -1;
1000 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this);
1001 if (err != noErr) {
1002 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
1003 printError(err);
1004 return -1;
1007 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
1008 if (err != noErr) {
1009 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1010 printError(err);
1011 return -1;
1014 err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
1015 if (err != noErr) {
1016 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1017 printError(err);
1018 return -1;
1021 if (!fEngineControl->fSyncMode && fIOUsage != 1.f) {
1022 UInt32 outSize = sizeof(float);
1023 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyIOCycleUsage, outSize, &fIOUsage);
1024 if (err != noErr) {
1025 jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage");
1026 printError(err);
1030 return 0;
1033 void JackCoreAudioDriver::RemoveListeners()
1035 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback);
1036 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback);
1037 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback);
1038 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback);
1039 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
1040 AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
1043 int JackCoreAudioDriver::Open(jack_nframes_t buffer_size,
1044 jack_nframes_t samplerate,
1045 bool capturing,
1046 bool playing,
1047 int inchannels,
1048 int outchannels,
1049 bool monitor,
1050 const char* capture_driver_uid,
1051 const char* playback_driver_uid,
1052 jack_nframes_t capture_latency,
1053 jack_nframes_t playback_latency,
1054 int async_output_latency,
1055 int computation_grain)
1057 int in_nChannels = 0;
1058 int out_nChannels = 0;
1059 char capture_driver_name[256];
1060 char playback_driver_name[256];
1062 // Keep initial state
1063 fCapturing = capturing;
1064 fPlaying = playing;
1065 fInChannels = inchannels;
1066 fOutChannels = outchannels;
1067 fMonitor = monitor;
1068 strcpy(fCaptureUID, capture_driver_uid);
1069 strcpy(fPlaybackUID, playback_driver_uid);
1070 fCaptureLatency = capture_latency;
1071 fPlaybackLatency = playback_latency;
1072 fIOUsage = float(async_output_latency) / 100.f;
1073 fComputationGrain = float(computation_grain) / 100.f;
1075 CFRunLoopRef theRunLoop = NULL;
1076 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1077 OSStatus theError = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
1078 if (theError != noErr) {
1079 jack_error("JackCoreAudioDriver::Open kAudioHardwarePropertyRunLoop error");
1082 if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name) < 0)
1083 return -1;
1085 // Generic JackAudioDriver Open
1086 if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
1087 return -1;
1089 if (SetupChannels(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, true) < 0)
1090 return -1;
1092 if (SetupBufferSizeAndSampleRate(buffer_size, samplerate) < 0)
1093 return -1;
1095 if (OpenAUHAL(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, buffer_size, samplerate, true) < 0)
1096 goto error;
1098 if (capturing && inchannels > 0)
1099 if (SetupBuffers(inchannels) < 0)
1100 goto error;
1102 if (AddListeners() < 0)
1103 goto error;
1105 // Core driver may have changed the in/out values
1106 fCaptureChannels = inchannels;
1107 fPlaybackChannels = outchannels;
1108 return noErr;
1110 error:
1111 Close();
1112 return -1;
1115 int JackCoreAudioDriver::Close()
1117 jack_log("JackCoreAudioDriver::Close");
1118 Stop();
1119 JackAudioDriver::Close();
1120 RemoveListeners();
1121 DisposeBuffers();
1122 CloseAUHAL();
1123 return 0;
1126 int JackCoreAudioDriver::Attach()
1128 OSStatus err;
1129 JackPort* port;
1130 jack_port_id_t port_index;
1131 UInt32 size;
1132 Boolean isWritable;
1133 char channel_name[64];
1134 char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
1135 char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
1136 unsigned long port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
1138 jack_log("JackCoreAudioDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
1140 for (int i = 0; i < fCaptureChannels; i++) {
1142 err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable);
1143 if (err != noErr)
1144 jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error ");
1145 if (err == noErr && size > 0) {
1146 err = AudioDeviceGetProperty(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, channel_name);
1147 if (err != noErr)
1148 jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error ");
1149 snprintf(alias, sizeof(alias) - 1, "%s:%s:out_%s%u", fAliasName, fCaptureDriverName, channel_name, i + 1);
1150 } else {
1151 snprintf(alias, sizeof(alias) - 1, "%s:%s:out%u", fAliasName, fCaptureDriverName, i + 1);
1154 snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
1156 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) {
1157 jack_error("Cannot register port for %s", name);
1158 return -1;
1161 size = sizeof(UInt32);
1162 UInt32 value1 = 0;
1163 UInt32 value2 = 0;
1164 err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1);
1165 if (err != noErr)
1166 jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error ");
1167 err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2);
1168 if (err != noErr)
1169 jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error ");
1171 port = fGraphManager->GetPort(port_index);
1172 port->SetAlias(alias);
1173 port->SetLatency(fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency);
1174 fCapturePortList[i] = port_index;
1177 port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;
1179 for (int i = 0; i < fPlaybackChannels; i++) {
1181 err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, &isWritable);
1182 if (err != noErr)
1183 jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error ");
1184 if (err == noErr && size > 0) {
1185 err = AudioDeviceGetProperty(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, channel_name);
1186 if (err != noErr)
1187 jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error ");
1188 snprintf(alias, sizeof(alias) - 1, "%s:%s:in_%s%u", fAliasName, fPlaybackDriverName, channel_name, i + 1);
1189 } else {
1190 snprintf(alias, sizeof(alias) - 1, "%s:%s:in%u", fAliasName, fPlaybackDriverName, i + 1);
1193 snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
1195 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) {
1196 jack_error("Cannot register port for %s", name);
1197 return -1;
1200 size = sizeof(UInt32);
1201 UInt32 value1 = 0;
1202 UInt32 value2 = 0;
1203 err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyLatency, &size, &value1);
1204 if (err != noErr)
1205 jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error ");
1206 err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2);
1207 if (err != noErr)
1208 jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error ");
1210 port = fGraphManager->GetPort(port_index);
1211 port->SetAlias(alias);
1212 // Add more latency if "async" mode is used...
1213 port->SetLatency(fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize * fIOUsage) + value1 + value2 + fPlaybackLatency);
1214 fPlaybackPortList[i] = port_index;
1216 // Monitor ports
1217 if (fWithMonitorPorts) {
1218 jack_log("Create monitor port ");
1219 snprintf(name, sizeof(name) - 1, "%s:monitor_%u", fClientControl.fName, i + 1);
1220 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, fEngineControl->fBufferSize)) == NO_PORT) {
1221 jack_error("Cannot register monitor port for %s", name);
1222 return -1;
1223 } else {
1224 port = fGraphManager->GetPort(port_index);
1225 port->SetAlias(alias);
1226 port->SetLatency(fEngineControl->fBufferSize);
1227 fMonitorPortList[i] = port_index;
1232 // Input buffers do no change : prepare them only once
1233 for (int i = 0; i < fCaptureChannels; i++) {
1234 fJackInputData->mBuffers[i].mData = GetInputBuffer(i);
1237 return 0;
1240 int JackCoreAudioDriver::Start()
1242 jack_log("JackCoreAudioDriver::Start");
1243 JackAudioDriver::Start();
1245 #ifdef MAC_OS_X_VERSION_10_5
1246 OSStatus err = AudioDeviceCreateIOProcID(fDeviceID, MeasureCallback, this, &fMesureCallbackID);
1247 #else
1248 OSStatus err = AudioDeviceAddIOProc(fDeviceID, MeasureCallback, this);
1249 #endif
1251 OSStatus err = AudioDeviceAddIOProc(fDeviceID, MeasureCallback, this);
1253 if (err != noErr)
1254 return -1;
1256 err = AudioOutputUnitStart(fAUHAL);
1257 if (err != noErr)
1258 return -1;
1260 if ((err = AudioDeviceStart(fDeviceID, MeasureCallback)) != noErr) {
1261 jack_error("Cannot start MeasureCallback");
1262 printError(err);
1263 return -1;
1266 return 0;
1269 int JackCoreAudioDriver::Stop()
1271 jack_log("JackCoreAudioDriver::Stop");
1272 AudioDeviceStop(fDeviceID, MeasureCallback);
1274 #ifdef MAC_OS_X_VERSION_10_5
1275 AudioDeviceDestroyIOProcID(fDeviceID, fMesureCallbackID);
1276 #else
1277 AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback);
1278 #endif
1280 AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback);
1281 return (AudioOutputUnitStop(fAUHAL) == noErr) ? 0 : -1;
1284 int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
1286 OSStatus err;
1287 UInt32 outSize = sizeof(UInt32);
1289 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size);
1290 if (err != noErr) {
1291 jack_error("Cannot set buffer size %ld", buffer_size);
1292 printError(err);
1293 return -1;
1296 JackAudioDriver::SetBufferSize(buffer_size); // never fails
1298 // Input buffers do no change : prepare them only once
1299 for (int i = 0; i < fCaptureChannels; i++) {
1300 fJackInputData->mBuffers[i].mNumberChannels = 1;
1301 fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float);
1302 fJackInputData->mBuffers[i].mData = GetInputBuffer(i);
1305 return 0;
1308 } // end of namespace
1311 #ifdef __cplusplus
1312 extern "C"
1314 #endif
1316 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
1318 jack_driver_desc_t *desc;
1319 unsigned int i;
1320 desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
1322 strcpy(desc->name, "coreaudio"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
1323 strcpy(desc->desc, "Apple CoreAudio API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
1325 desc->nparams = 15;
1326 desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
1328 i = 0;
1329 strcpy(desc->params[i].name, "channels");
1330 desc->params[i].character = 'c';
1331 desc->params[i].type = JackDriverParamInt;
1332 desc->params[i].value.ui = 0;
1333 strcpy(desc->params[i].short_desc, "Maximum number of channels");
1334 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1336 i++;
1337 strcpy(desc->params[i].name, "inchannels");
1338 desc->params[i].character = 'i';
1339 desc->params[i].type = JackDriverParamInt;
1340 desc->params[i].value.ui = 0;
1341 strcpy(desc->params[i].short_desc, "Maximum number of input channels");
1342 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1344 i++;
1345 strcpy(desc->params[i].name, "outchannels");
1346 desc->params[i].character = 'o';
1347 desc->params[i].type = JackDriverParamInt;
1348 desc->params[i].value.ui = 0;
1349 strcpy(desc->params[i].short_desc, "Maximum number of output channels");
1350 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1352 i++;
1353 strcpy(desc->params[i].name, "capture");
1354 desc->params[i].character = 'C';
1355 desc->params[i].type = JackDriverParamString;
1356 strcpy(desc->params[i].value.str, "will take default CoreAudio input device");
1357 strcpy(desc->params[i].short_desc, "Provide capture ports. Optionally set CoreAudio device name");
1358 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1360 i++;
1361 strcpy(desc->params[i].name, "playback");
1362 desc->params[i].character = 'P';
1363 desc->params[i].type = JackDriverParamString;
1364 strcpy(desc->params[i].value.str, "will take default CoreAudio output device");
1365 strcpy(desc->params[i].short_desc, "Provide playback ports. Optionally set CoreAudio device name");
1366 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1368 i++;
1369 strcpy (desc->params[i].name, "monitor");
1370 desc->params[i].character = 'm';
1371 desc->params[i].type = JackDriverParamBool;
1372 desc->params[i].value.i = 0;
1373 strcpy(desc->params[i].short_desc, "Provide monitor ports for the output");
1374 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1376 i++;
1377 strcpy(desc->params[i].name, "duplex");
1378 desc->params[i].character = 'D';
1379 desc->params[i].type = JackDriverParamBool;
1380 desc->params[i].value.i = TRUE;
1381 strcpy(desc->params[i].short_desc, "Provide both capture and playback ports");
1382 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1384 i++;
1385 strcpy(desc->params[i].name, "rate");
1386 desc->params[i].character = 'r';
1387 desc->params[i].type = JackDriverParamUInt;
1388 desc->params[i].value.ui = 44100U;
1389 strcpy(desc->params[i].short_desc, "Sample rate");
1390 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1392 i++;
1393 strcpy(desc->params[i].name, "period");
1394 desc->params[i].character = 'p';
1395 desc->params[i].type = JackDriverParamUInt;
1396 desc->params[i].value.ui = 128U;
1397 strcpy(desc->params[i].short_desc, "Frames per period");
1398 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1400 i++;
1401 strcpy(desc->params[i].name, "device");
1402 desc->params[i].character = 'd';
1403 desc->params[i].type = JackDriverParamString;
1404 strcpy(desc->params[i].value.str, "will take default CoreAudio device name");
1405 strcpy(desc->params[i].short_desc, "CoreAudio device name");
1406 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1408 i++;
1409 strcpy(desc->params[i].name, "input-latency");
1410 desc->params[i].character = 'I';
1411 desc->params[i].type = JackDriverParamUInt;
1412 desc->params[i].value.i = 0;
1413 strcpy(desc->params[i].short_desc, "Extra input latency (frames)");
1414 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1416 i++;
1417 strcpy(desc->params[i].name, "output-latency");
1418 desc->params[i].character = 'O';
1419 desc->params[i].type = JackDriverParamUInt;
1420 desc->params[i].value.i = 0;
1421 strcpy(desc->params[i].short_desc, "Extra output latency (frames)");
1422 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1424 i++;
1425 strcpy(desc->params[i].name, "list-devices");
1426 desc->params[i].character = 'l';
1427 desc->params[i].type = JackDriverParamBool;
1428 desc->params[i].value.i = TRUE;
1429 strcpy(desc->params[i].short_desc, "Display available CoreAudio devices");
1430 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1432 i++;
1433 strcpy(desc->params[i].name, "async-latency");
1434 desc->params[i].character = 'L';
1435 desc->params[i].type = JackDriverParamUInt;
1436 desc->params[i].value.i = 100;
1437 strcpy(desc->params[i].short_desc, "Extra output latency in aynchronous mode (percent)");
1438 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1440 i++;
1441 strcpy(desc->params[i].name, "grain");
1442 desc->params[i].character = 'G';
1443 desc->params[i].type = JackDriverParamUInt;
1444 desc->params[i].value.i = 100;
1445 strcpy(desc->params[i].short_desc, "Computation grain in RT thread (percent)");
1446 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
1448 return desc;
1451 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
1453 jack_nframes_t srate = 44100;
1454 jack_nframes_t frames_per_interrupt = 128;
1455 int capture = FALSE;
1456 int playback = FALSE;
1457 int chan_in = 0;
1458 int chan_out = 0;
1459 bool monitor = false;
1460 const char* capture_driver_uid = "";
1461 const char* playback_driver_uid = "";
1462 const JSList *node;
1463 const jack_driver_param_t *param;
1464 jack_nframes_t systemic_input_latency = 0;
1465 jack_nframes_t systemic_output_latency = 0;
1466 int async_output_latency = 100;
1467 int computation_grain = -1;
1469 for (node = params; node; node = jack_slist_next(node)) {
1470 param = (const jack_driver_param_t *) node->data;
1472 switch (param->character) {
1474 case 'd':
1475 capture_driver_uid = strdup(param->value.str);
1476 playback_driver_uid = strdup(param->value.str);
1477 break;
1479 case 'D':
1480 capture = TRUE;
1481 playback = TRUE;
1482 break;
1484 case 'c':
1485 chan_in = chan_out = (int) param->value.ui;
1486 break;
1488 case 'i':
1489 chan_in = (int) param->value.ui;
1490 break;
1492 case 'o':
1493 chan_out = (int) param->value.ui;
1494 break;
1496 case 'C':
1497 capture = TRUE;
1498 if (strcmp(param->value.str, "none") != 0) {
1499 capture_driver_uid = strdup(param->value.str);
1501 break;
1503 case 'P':
1504 playback = TRUE;
1505 if (strcmp(param->value.str, "none") != 0) {
1506 playback_driver_uid = strdup(param->value.str);
1508 break;
1510 case 'm':
1511 monitor = param->value.i;
1512 break;
1514 case 'r':
1515 srate = param->value.ui;
1516 break;
1518 case 'p':
1519 frames_per_interrupt = (unsigned int) param->value.ui;
1520 break;
1522 case 'I':
1523 systemic_input_latency = param->value.ui;
1524 break;
1526 case 'O':
1527 systemic_output_latency = param->value.ui;
1528 break;
1530 case 'l':
1531 Jack::DisplayDeviceNames();
1532 break;
1534 case 'L':
1535 async_output_latency = param->value.ui;
1536 break;
1538 case 'G':
1539 computation_grain = param->value.ui;
1540 break;
1544 /* duplex is the default */
1545 if (!capture && !playback) {
1546 capture = TRUE;
1547 playback = TRUE;
1550 Jack::JackCoreAudioDriver* driver = new Jack::JackCoreAudioDriver("system", "coreaudio", engine, table);
1551 if (driver->Open(frames_per_interrupt, srate, capture, playback, chan_in, chan_out, monitor, capture_driver_uid,
1552 playback_driver_uid, systemic_input_latency, systemic_output_latency, async_output_latency, computation_grain) == 0) {
1553 return driver;
1554 } else {
1555 delete driver;
1556 return NULL;
1560 #ifdef __cplusplus
1562 #endif