Remove warning, renaming.
[jack2.git] / macosx / coreaudio / JackCoreAudioDriver.cpp
blobf066bc87e703d0469c9d6752c72d694d446346c6
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 "JackLockedEngine.h"
30 #include "JackAC3Encoder.h"
32 #include <sstream>
33 #include <iostream>
34 #include <CoreServices/CoreServices.h>
35 #include <CoreFoundation/CFNumber.h>
37 namespace Jack
40 static void Print4CharCode(const char* msg, long c)
42 UInt32 __4CC_number = (c);
43 char __4CC_string[5];
44 *((SInt32*)__4CC_string) = EndianU32_NtoB(__4CC_number);
45 __4CC_string[4] = 0;
46 jack_log("%s'%s'", (msg), __4CC_string);
49 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
51 jack_log("- - - - - - - - - - - - - - - - - - - -");
52 jack_log(" Sample Rate:%f", inDesc->mSampleRate);
53 jack_log(" Format ID:%.*s", (int)sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
54 jack_log(" Format Flags:%lX", inDesc->mFormatFlags);
55 jack_log(" Bytes per Packet:%ld", inDesc->mBytesPerPacket);
56 jack_log(" Frames per Packet:%ld", inDesc->mFramesPerPacket);
57 jack_log(" Bytes per Frame:%ld", inDesc->mBytesPerFrame);
58 jack_log(" Channels per Frame:%ld", inDesc->mChannelsPerFrame);
59 jack_log(" Bits per Channel:%ld", inDesc->mBitsPerChannel);
60 jack_log("- - - - - - - - - - - - - - - - - - - -");
63 static void printError(OSStatus err)
65 switch (err) {
66 case kAudioHardwareNoError:
67 jack_log("error code : kAudioHardwareNoError");
68 break;
69 case kAudioConverterErr_FormatNotSupported:
70 jack_log("error code : kAudioConverterErr_FormatNotSupported");
71 break;
72 case kAudioConverterErr_OperationNotSupported:
73 jack_log("error code : kAudioConverterErr_OperationNotSupported");
74 break;
75 case kAudioConverterErr_PropertyNotSupported:
76 jack_log("error code : kAudioConverterErr_PropertyNotSupported");
77 break;
78 case kAudioConverterErr_InvalidInputSize:
79 jack_log("error code : kAudioConverterErr_InvalidInputSize");
80 break;
81 case kAudioConverterErr_InvalidOutputSize:
82 jack_log("error code : kAudioConverterErr_InvalidOutputSize");
83 break;
84 case kAudioConverterErr_UnspecifiedError:
85 jack_log("error code : kAudioConverterErr_UnspecifiedError");
86 break;
87 case kAudioConverterErr_BadPropertySizeError:
88 jack_log("error code : kAudioConverterErr_BadPropertySizeError");
89 break;
90 case kAudioConverterErr_RequiresPacketDescriptionsError:
91 jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
92 break;
93 case kAudioConverterErr_InputSampleRateOutOfRange:
94 jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
95 break;
96 case kAudioConverterErr_OutputSampleRateOutOfRange:
97 jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
98 break;
99 case kAudioHardwareNotRunningError:
100 jack_log("error code : kAudioHardwareNotRunningError");
101 break;
102 case kAudioHardwareUnknownPropertyError:
103 jack_log("error code : kAudioHardwareUnknownPropertyError");
104 break;
105 case kAudioHardwareIllegalOperationError:
106 jack_log("error code : kAudioHardwareIllegalOperationError");
107 break;
108 case kAudioHardwareBadDeviceError:
109 jack_log("error code : kAudioHardwareBadDeviceError");
110 break;
111 case kAudioHardwareBadStreamError:
112 jack_log("error code : kAudioHardwareBadStreamError");
113 break;
114 case kAudioDeviceUnsupportedFormatError:
115 jack_log("error code : kAudioDeviceUnsupportedFormatError");
116 break;
117 case kAudioDevicePermissionsError:
118 jack_log("error code : kAudioDevicePermissionsError");
119 break;
120 case kAudioHardwareBadObjectError:
121 jack_log("error code : kAudioHardwareBadObjectError");
122 break;
123 case kAudioHardwareUnsupportedOperationError:
124 jack_log("error code : kAudioHardwareUnsupportedOperationError");
125 break;
126 default:
127 Print4CharCode("error code : unknown ", err);
128 break;
132 static bool CheckAvailableDeviceName(const char* device_name, AudioDeviceID* device_id)
134 UInt32 size;
135 Boolean isWritable;
136 int i, deviceNum;
137 OSStatus err;
139 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
140 if (err != noErr) {
141 return false;
144 deviceNum = size / sizeof(AudioDeviceID);
145 AudioDeviceID devices[deviceNum];
147 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
148 if (err != noErr) {
149 return false;
152 for (i = 0; i < deviceNum; i++) {
153 char device_name_aux[256];
155 size = 256;
156 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name_aux);
157 if (err != noErr) {
158 return false;
161 if (strcmp(device_name_aux, device_name) == 0) {
162 *device_id = devices[i];
163 return true;
168 return false;
171 static bool CheckAvailableDevice(AudioDeviceID device_id)
173 UInt32 size;
174 Boolean isWritable;
175 int i, deviceNum;
176 OSStatus err;
178 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
179 if (err != noErr) {
180 return false;
183 deviceNum = size / sizeof(AudioDeviceID);
184 AudioDeviceID devices[deviceNum];
186 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
187 if (err != noErr) {
188 return false;
191 for (i = 0; i < deviceNum; i++) {
192 if (device_id == devices[i]) {
193 return true;
197 return false;
201 static OSStatus DisplayDeviceNames()
203 UInt32 size;
204 Boolean isWritable;
205 int i, deviceNum;
206 OSStatus err;
207 CFStringRef UIname;
209 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
210 if (err != noErr) {
211 return err;
214 deviceNum = size / sizeof(AudioDeviceID);
215 AudioDeviceID devices[deviceNum];
217 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
218 if (err != noErr) {
219 return err;
222 for (i = 0; i < deviceNum; i++) {
223 char device_name[256];
224 char internal_name[256];
226 size = sizeof(CFStringRef);
227 UIname = NULL;
228 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
229 if (err == noErr) {
230 CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
231 } else {
232 goto error;
235 size = 256;
236 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
237 if (err != noErr) {
238 return err;
241 jack_info("Device ID = \'%d\' name = \'%s\', internal name = \'%s\' (to be used as -C, -P, or -d parameter)", devices[i], device_name, internal_name);
244 return noErr;
246 error:
247 if (UIname != NULL) {
248 CFRelease(UIname);
250 return err;
253 static CFStringRef GetDeviceName(AudioDeviceID id)
255 UInt32 size = sizeof(CFStringRef);
256 CFStringRef UIname;
257 OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
258 return (err == noErr) ? UIname : NULL;
261 static void ParseChannelList(const string& list, vector<int>& result, int max_chan)
263 stringstream ss(list);
264 string token;
265 int chan;
267 while (ss >> token) {
268 istringstream ins;
269 ins.str(token);
270 ins >> chan;
271 if (chan < 0 || chan >= max_chan) {
272 jack_error("Ignore incorrect channel mapping value = %d", chan);
273 } else {
274 result.push_back(chan);
279 OSStatus JackCoreAudioDriver::Render(void* inRefCon,
280 AudioUnitRenderActionFlags* ioActionFlags,
281 const AudioTimeStamp* inTimeStamp,
282 UInt32 inBusNumber,
283 UInt32 inNumberFrames,
284 AudioBufferList* ioData)
286 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inRefCon;
287 driver->fActionFags = ioActionFlags;
288 driver->fCurrentTime = inTimeStamp;
289 driver->fDriverOutputData = ioData;
291 // Setup threaded based log function et get RT thread parameters once...
292 if (set_threaded_log_function()) {
294 jack_log("JackCoreAudioDriver::Render : set_threaded_log_function");
295 JackMachThread::GetParams(pthread_self(), &driver->fEngineControl->fPeriod, &driver->fEngineControl->fComputation, &driver->fEngineControl->fConstraint);
297 if (driver->fComputationGrain > 0) {
298 jack_log("JackCoreAudioDriver::Render : RT thread computation setup to %d percent of period", int(driver->fComputationGrain * 100));
299 driver->fEngineControl->fComputation = driver->fEngineControl->fPeriod * driver->fComputationGrain;
303 // Signal waiting start function...
304 driver->fState = true;
306 driver->CycleTakeBeginTime();
308 if (driver->Process() < 0) {
309 jack_error("Process error, stopping driver");
310 driver->NotifyFailure(JackBackendError, "Process error, stopping driver"); // Message length limited to JACK_MESSAGE_SIZE
311 driver->Stop();
312 kill(JackTools::GetPID(), SIGINT);
313 return kAudioHardwareUnsupportedOperationError;
314 } else {
315 return noErr;
319 int JackCoreAudioDriver::Read()
321 if (fCaptureChannels > 0) { // Calling AudioUnitRender with no input returns a '????' error (callback setting issue ??), so hack to avoid it here...
322 return (AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData) == noErr) ? 0 : -1;
323 } else {
324 return 0;
328 int JackCoreAudioDriver::Write()
330 if (fAC3Encoder) {
332 // AC3 encoding and SPDIF write
333 jack_default_audio_sample_t* AC3_inputs[MAX_AC3_CHANNELS];
334 jack_default_audio_sample_t* AC3_outputs[2];
335 for (int i = 0; i < fPlaybackChannels; i++) {
336 AC3_inputs[i] = GetOutputBuffer(i);
337 // If not connected, clear the buffer
338 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) == 0) {
339 memset(AC3_inputs[i], 0, sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize);
342 AC3_outputs[0] = (jack_default_audio_sample_t*)fDriverOutputData->mBuffers[0].mData;
343 AC3_outputs[1] = (jack_default_audio_sample_t*)fDriverOutputData->mBuffers[1].mData;
344 fAC3Encoder->Process(AC3_inputs, AC3_outputs, fEngineControl->fBufferSize);
346 } else {
348 // Standard write
349 for (int i = 0; i < fPlaybackChannels; i++) {
350 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
351 jack_default_audio_sample_t* buffer = GetOutputBuffer(i);
352 int size = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize;
353 memcpy((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, buffer, size);
354 // Monitor ports
355 if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) {
356 memcpy(GetMonitorBuffer(i), buffer, size);
358 } else {
359 memset((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize);
363 return 0;
366 OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice,
367 UInt32 inChannel,
368 Boolean isInput,
369 AudioDevicePropertyID inPropertyID,
370 void* inClientData)
372 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
374 switch (inPropertyID) {
376 case kAudioDevicePropertyNominalSampleRate: {
377 jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
378 // Check new sample rate
379 Float64 tmp_sample_rate;
380 UInt32 outSize = sizeof(Float64);
381 OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &tmp_sample_rate);
382 if (err != noErr) {
383 jack_error("Cannot get current sample rate");
384 printError(err);
385 } else {
386 jack_log("JackCoreAudioDriver::SRNotificationCallback : checked sample rate = %f", tmp_sample_rate);
388 driver->fState = true;
389 break;
393 return noErr;
396 OSStatus JackCoreAudioDriver::BSNotificationCallback(AudioDeviceID inDevice,
397 UInt32 inChannel,
398 Boolean isInput,
399 AudioDevicePropertyID inPropertyID,
400 void* inClientData)
402 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
404 switch (inPropertyID) {
406 case kAudioDevicePropertyBufferFrameSize: {
407 jack_log("JackCoreAudioDriver::BSNotificationCallback kAudioDevicePropertyBufferFrameSize");
408 // Check new buffer size
409 UInt32 tmp_buffer_size;
410 UInt32 outSize = sizeof(UInt32);
411 OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &tmp_buffer_size);
412 if (err != noErr) {
413 jack_error("Cannot get current buffer size");
414 printError(err);
415 } else {
416 jack_log("JackCoreAudioDriver::BSNotificationCallback : checked buffer size = %d", tmp_buffer_size);
418 driver->fState = true;
419 break;
423 return noErr;
426 // A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
427 OSStatus JackCoreAudioDriver::AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID, void* inClientData)
429 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
431 switch (inPropertyID) {
433 case kAudioHardwarePropertyDevices: {
434 jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices");
435 DisplayDeviceNames();
436 AudioDeviceID captureID, playbackID;
437 if (CheckAvailableDevice(driver->fDeviceID) ||
438 (CheckAvailableDeviceName(driver->fCaptureUID, &captureID)
439 && CheckAvailableDeviceName(driver->fPlaybackUID, &playbackID))) {
442 break;
446 return noErr;
449 OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice,
450 UInt32 inChannel,
451 Boolean isInput,
452 AudioDevicePropertyID inPropertyID,
453 void* inClientData)
455 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
457 switch (inPropertyID) {
459 case kAudioDevicePropertyDeviceIsRunning: {
460 UInt32 isrunning = 0;
461 UInt32 outsize = sizeof(UInt32);
462 if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceIsRunning, &outsize, &isrunning) == noErr) {
463 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsRunning = %d", isrunning);
465 break;
468 case kAudioDevicePropertyDeviceIsAlive: {
469 UInt32 isalive = 0;
470 UInt32 outsize = sizeof(UInt32);
471 if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceIsAlive, &outsize, &isalive) == noErr) {
472 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsAlive = %d", isalive);
474 break;
477 case kAudioDevicePropertyDeviceHasChanged: {
478 UInt32 hachanged = 0;
479 UInt32 outsize = sizeof(UInt32);
480 if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceHasChanged, &outsize, &hachanged) == noErr) {
481 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceHasChanged = %d", hachanged);
483 break;
486 case kAudioDeviceProcessorOverload: {
487 jack_error("DeviceNotificationCallback kAudioDeviceProcessorOverload");
488 jack_time_t cur_time = GetMicroSeconds();
489 driver->NotifyXRun(cur_time, float(cur_time - driver->fBeginDateUst)); // Better this value than nothing...
490 break;
493 case kAudioDevicePropertyStreamConfiguration: {
494 jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration : server will quit...");
495 driver->NotifyFailure(JackBackendError, "Another application has changed the device configuration"); // Message length limited to JACK_MESSAGE_SIZE
496 driver->CloseAUHAL();
497 kill(JackTools::GetPID(), SIGINT);
498 return kAudioHardwareUnsupportedOperationError;
501 case kAudioDevicePropertyNominalSampleRate: {
502 Float64 sample_rate = 0;
503 UInt32 outsize = sizeof(Float64);
504 OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outsize, &sample_rate);
505 if (err != noErr) {
506 return kAudioHardwareUnsupportedOperationError;
509 char device_name[256];
510 const char* digidesign_name = "Digidesign";
511 driver->GetDeviceNameFromID(driver->fDeviceID, device_name);
513 if (sample_rate != driver->fEngineControl->fSampleRate) {
515 // Digidesign hardware, so "special" code : change the SR again here
516 if (strncmp(device_name, digidesign_name, 10) == 0) {
518 jack_log("JackCoreAudioDriver::DeviceNotificationCallback Digidesign HW = %s", device_name);
520 // Set sample rate again...
521 sample_rate = driver->fEngineControl->fSampleRate;
522 err = AudioDeviceSetProperty(driver->fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outsize, &sample_rate);
523 if (err != noErr) {
524 jack_error("Cannot set sample rate = %f", sample_rate);
525 printError(err);
526 } else {
527 jack_log("JackCoreAudioDriver::DeviceNotificationCallback : set sample rate = %f", sample_rate);
530 // Check new sample rate again...
531 outsize = sizeof(Float64);
532 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outsize, &sample_rate);
533 if (err != noErr) {
534 jack_error("Cannot get current sample rate");
535 printError(err);
536 } else {
537 jack_log("JackCoreAudioDriver::DeviceNotificationCallback : checked sample rate = %f", sample_rate);
539 return noErr;
541 } else {
542 driver->NotifyFailure(JackBackendError, "Another application has changed the sample rate"); // Message length limited to JACK_MESSAGE_SIZE
543 driver->CloseAUHAL();
544 kill(JackTools::GetPID(), SIGINT);
545 return kAudioHardwareUnsupportedOperationError;
551 return noErr;
554 OSStatus JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id)
556 UInt32 size = sizeof(AudioValueTranslation);
557 CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
558 AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
560 if (inIUD == NULL) {
561 return kAudioHardwareUnspecifiedError;
562 } else {
563 OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
564 CFRelease(inIUD);
565 jack_log("JackCoreAudioDriver::GetDeviceIDFromUID %s %ld", UID, *id);
566 return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
570 OSStatus JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID* id)
572 OSStatus res;
573 UInt32 theSize = sizeof(UInt32);
574 AudioDeviceID inDefault;
575 AudioDeviceID outDefault;
577 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) {
578 return res;
581 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) {
582 return res;
585 jack_log("JackCoreAudioDriver::GetDefaultDevice : input = %ld output = %ld", inDefault, outDefault);
587 // Get the device only if default input and output are the same
588 if (inDefault != outDefault) {
589 jack_error("Default input and output devices are not the same !!");
590 return kAudioHardwareBadDeviceError;
591 } else if (inDefault == 0) {
592 jack_error("Default input and output devices are null !!");
593 return kAudioHardwareBadDeviceError;
594 } else {
595 *id = inDefault;
596 return noErr;
600 OSStatus JackCoreAudioDriver::GetDefaultInputDevice(AudioDeviceID* id)
602 OSStatus res;
603 UInt32 theSize = sizeof(UInt32);
604 AudioDeviceID inDefault;
606 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) {
607 return res;
610 if (inDefault == 0) {
611 jack_error("Error default input device is 0, please select a correct one !!");
612 return -1;
614 jack_log("JackCoreAudioDriver::GetDefaultInputDevice : input = %ld ", inDefault);
615 *id = inDefault;
616 return noErr;
619 OSStatus JackCoreAudioDriver::GetDefaultOutputDevice(AudioDeviceID* id)
621 OSStatus res;
622 UInt32 theSize = sizeof(UInt32);
623 AudioDeviceID outDefault;
625 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) {
626 return res;
629 if (outDefault == 0) {
630 jack_error("Error default output device is 0, please select a correct one !!");
631 return -1;
633 jack_log("JackCoreAudioDriver::GetDefaultOutputDevice : output = %ld", outDefault);
634 *id = outDefault;
635 return noErr;
638 OSStatus JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id, char* name)
640 UInt32 size = 256;
641 return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
644 OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput)
646 OSStatus err = noErr;
647 UInt32 outSize;
648 Boolean outWritable;
650 channelCount = 0;
651 err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
652 if (err == noErr) {
653 int stream_count = outSize / sizeof(AudioBufferList);
654 jack_log("JackCoreAudioDriver::GetTotalChannels stream_count = %d", stream_count);
655 AudioBufferList bufferList[stream_count];
656 err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
657 if (err == noErr) {
658 for (uint i = 0; i < bufferList->mNumberBuffers; i++) {
659 channelCount += bufferList->mBuffers[i].mNumberChannels;
660 jack_log("JackCoreAudioDriver::GetTotalChannels stream = %d channels = %d", i, bufferList->mBuffers[i].mNumberChannels);
664 return err;
667 OSStatus JackCoreAudioDriver::GetStreamLatencies(AudioDeviceID device, bool isInput, vector<int>& latencies)
669 OSStatus err = noErr;
670 UInt32 outSize1, outSize2, outSize3;
671 Boolean outWritable;
673 err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, &outWritable);
674 if (err == noErr) {
675 int stream_count = outSize1 / sizeof(UInt32);
676 AudioStreamID streamIDs[stream_count];
677 AudioBufferList bufferList[stream_count];
678 UInt32 streamLatency;
679 outSize2 = sizeof(UInt32);
681 err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, streamIDs);
682 if (err != noErr) {
683 jack_error("GetStreamLatencies kAudioDevicePropertyStreams err = %d", err);
684 return err;
687 err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, &outWritable);
688 if (err != noErr) {
689 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err);
690 return err;
693 for (int i = 0; i < stream_count; i++) {
694 err = AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &outSize2, &streamLatency);
695 if (err != noErr) {
696 jack_error("GetStreamLatencies kAudioStreamPropertyLatency err = %d", err);
697 return err;
699 err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, bufferList);
700 if (err != noErr) {
701 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err);
702 return err;
704 // Push 'channel' time the stream latency
705 for (uint k = 0; k < bufferList->mBuffers[i].mNumberChannels; k++) {
706 latencies.push_back(streamLatency);
710 return err;
713 bool JackCoreAudioDriver::IsDigitalDevice(AudioDeviceID device)
715 OSStatus err = noErr;
716 UInt32 outSize1;
717 bool is_digital = false;
719 /* Get a list of all the streams on this device */
720 AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
721 err = AudioObjectGetPropertyDataSize(device, &streamsAddress, 0, NULL, &outSize1);
722 if (err != noErr) {
723 jack_error("IsDigitalDevice kAudioDevicePropertyStreams err = %d", err);
724 return false;
727 int stream_count = outSize1 / sizeof(AudioStreamID);
728 AudioStreamID streamIDs[stream_count];
730 err = AudioObjectGetPropertyData(device, &streamsAddress, 0, NULL, &outSize1, streamIDs);
732 if (err != noErr) {
733 jack_error("IsDigitalDevice kAudioDevicePropertyStreams list err = %d", err);
734 return false;
737 AudioObjectPropertyAddress physicalFormatsAddress = { kAudioStreamPropertyAvailablePhysicalFormats, kAudioObjectPropertyScopeGlobal, 0 };
739 for (int i = 0; i < stream_count ; i++) {
741 /* Find a stream with a cac3 stream */
742 int format_num = 0;
744 /* Retrieve all the stream formats supported by each output stream */
745 err = AudioObjectGetPropertyDataSize(streamIDs[i], &physicalFormatsAddress, 0, NULL, &outSize1);
747 if (err != noErr) {
748 jack_error("IsDigitalDevice kAudioStreamPropertyAvailablePhysicalFormats err = %d", err);
749 return false;
752 format_num = outSize1 / sizeof(AudioStreamRangedDescription);
753 AudioStreamRangedDescription format_list[format_num];
755 err = AudioObjectGetPropertyData(streamIDs[i], &physicalFormatsAddress, 0, NULL, &outSize1, format_list);
757 if (err != noErr) {
758 jack_error("IsDigitalDevice could not get the list of streamformats err = %d", err);
759 return false;
762 /* Check if one of the supported formats is a digital format */
763 for (int j = 0; j < format_num; j++) {
765 PrintStreamDesc(&format_list[j].mFormat);
767 if (format_list[j].mFormat.mFormatID == 'IAC3' ||
768 format_list[j].mFormat.mFormatID == 'iac3' ||
769 format_list[j].mFormat.mFormatID == kAudioFormat60958AC3 ||
770 format_list[j].mFormat.mFormatID == kAudioFormatAC3)
772 is_digital = true;
773 break;
778 return is_digital;
781 JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
782 : JackAudioDriver(name, alias, engine, table),
783 fAC3Encoder(NULL),
784 fJackInputData(NULL),
785 fDriverOutputData(NULL),
786 fPluginID(0),
787 fState(false),
788 fHogged(false),
789 fIOUsage(1.f),
790 fComputationGrain(-1.f),
791 fClockDriftCompensate(false),
792 fDigitalPlayback(false)
795 JackCoreAudioDriver::~JackCoreAudioDriver()
797 delete fAC3Encoder;
800 OSStatus JackCoreAudioDriver::DestroyAggregateDevice()
802 OSStatus osErr = noErr;
803 AudioObjectPropertyAddress pluginAOPA;
804 pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
805 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
806 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
807 UInt32 outDataSize;
809 if (fPluginID > 0) {
811 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
812 if (osErr != noErr) {
813 jack_error("DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
814 printError(osErr);
815 return osErr;
818 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
819 if (osErr != noErr) {
820 jack_error("DestroyAggregateDevice : AudioObjectGetPropertyData error");
821 printError(osErr);
822 return osErr;
827 return noErr;
830 OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
832 OSStatus err = noErr;
833 AudioObjectID sub_device[32];
834 UInt32 outSize = sizeof(sub_device);
836 err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
837 vector<AudioDeviceID> captureDeviceIDArray;
839 if (err != noErr) {
840 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input device does not have subdevices");
841 captureDeviceIDArray.push_back(captureDeviceID);
842 } else {
843 int num_devices = outSize / sizeof(AudioObjectID);
844 jack_log("JackCoreAudioDriver::CreateAggregateDevice :Input device has %d subdevices", num_devices);
845 for (int i = 0; i < num_devices; i++) {
846 captureDeviceIDArray.push_back(sub_device[i]);
850 err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
851 vector<AudioDeviceID> playbackDeviceIDArray;
853 if (err != noErr) {
854 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device does not have subdevices");
855 playbackDeviceIDArray.push_back(playbackDeviceID);
856 } else {
857 int num_devices = outSize / sizeof(AudioObjectID);
858 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device has %d subdevices", num_devices);
859 for (int i = 0; i < num_devices; i++) {
860 playbackDeviceIDArray.push_back(sub_device[i]);
864 return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice);
867 OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
869 OSStatus osErr = noErr;
870 UInt32 outSize;
871 Boolean outWritable;
873 // Prepare sub-devices for clock drift compensation
874 // Workaround for bug in the HAL : until 10.6.2
875 AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
876 AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
877 UInt32 theQualifierDataSize = sizeof(AudioObjectID);
878 AudioClassID inClass = kAudioSubDeviceClassID;
879 void* theQualifierData = &inClass;
880 UInt32 subDevicesNum = 0;
882 //---------------------------------------------------------------------------
883 // Setup SR of both devices otherwise creating AD may fail...
884 //---------------------------------------------------------------------------
885 UInt32 keptclockdomain = 0;
886 UInt32 clockdomain = 0;
887 outSize = sizeof(UInt32);
888 bool need_clock_drift_compensation = false;
890 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
891 if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) {
892 jack_error("CreateAggregateDevice : cannot set SR of input device");
893 } else {
894 // Check clock domain
895 osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
896 if (osErr != 0) {
897 jack_error("CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
898 printError(osErr);
899 } else {
900 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
901 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain);
902 if (clockdomain != 0 && clockdomain != keptclockdomain) {
903 jack_error("CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
904 need_clock_drift_compensation = true;
910 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
911 if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) {
912 jack_error("CreateAggregateDevice : cannot set SR of output device");
913 } else {
914 // Check clock domain
915 osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
916 if (osErr != 0) {
917 jack_error("CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
918 printError(osErr);
919 } else {
920 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
921 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain);
922 if (clockdomain != 0 && clockdomain != keptclockdomain) {
923 jack_error("CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
924 need_clock_drift_compensation = true;
930 // If no valid clock domain was found, then assume we have to compensate...
931 if (keptclockdomain == 0) {
932 need_clock_drift_compensation = true;
935 //---------------------------------------------------------------------------
936 // Start to create a new aggregate by getting the base audio hardware plugin
937 //---------------------------------------------------------------------------
939 char device_name[256];
940 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
941 GetDeviceNameFromID(captureDeviceID[i], device_name);
942 jack_info("Separated input = '%s' ", device_name);
945 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
946 GetDeviceNameFromID(playbackDeviceID[i], device_name);
947 jack_info("Separated output = '%s' ", device_name);
950 osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
951 if (osErr != noErr) {
952 jack_error("CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
953 printError(osErr);
954 return osErr;
957 AudioValueTranslation pluginAVT;
959 CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
961 pluginAVT.mInputData = &inBundleRef;
962 pluginAVT.mInputDataSize = sizeof(inBundleRef);
963 pluginAVT.mOutputData = &fPluginID;
964 pluginAVT.mOutputDataSize = sizeof(fPluginID);
966 osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
967 if (osErr != noErr) {
968 jack_error("CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
969 printError(osErr);
970 return osErr;
973 //-------------------------------------------------
974 // Create a CFDictionary for our aggregate device
975 //-------------------------------------------------
977 CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
979 CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
980 CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
982 // add the name of the device to the dictionary
983 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
985 // add our choice of UID for the aggregate device to the dictionary
986 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
988 // add a "private aggregate key" to the dictionary
989 int value = 1;
990 CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
992 SInt32 system;
993 Gestalt(gestaltSystemVersion, &system);
995 jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054);
997 // Starting with 10.5.4 systems, the AD can be internal... (better)
998 if (system < 0x00001054) {
999 jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device....");
1000 } else {
1001 jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device....");
1002 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
1005 // Prepare sub-devices for clock drift compensation
1006 CFMutableArrayRef subDevicesArrayClock = NULL;
1009 if (fClockDriftCompensate) {
1010 if (need_clock_drift_compensation) {
1011 jack_info("Clock drift compensation activated...");
1012 subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1014 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
1015 CFStringRef UID = GetDeviceName(captureDeviceID[i]);
1016 if (UID) {
1017 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1018 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
1019 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
1020 //CFRelease(UID);
1021 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
1025 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
1026 CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
1027 if (UID) {
1028 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1029 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
1030 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
1031 //CFRelease(UID);
1032 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
1036 // add sub-device clock array for the aggregate device to the dictionary
1037 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
1038 } else {
1039 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
1044 //-------------------------------------------------
1045 // Create a CFMutableArray for our sub-device list
1046 //-------------------------------------------------
1048 // we need to append the UID for each device to a CFMutableArray, so create one here
1049 CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1051 vector<CFStringRef> captureDeviceUID;
1052 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
1053 CFStringRef ref = GetDeviceName(captureDeviceID[i]);
1054 if (ref == NULL) {
1055 return -1;
1057 captureDeviceUID.push_back(ref);
1058 // input sub-devices in this example, so append the sub-device's UID to the CFArray
1059 CFArrayAppendValue(subDevicesArray, ref);
1062 vector<CFStringRef> playbackDeviceUID;
1063 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
1064 CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
1065 if (ref == NULL) {
1066 return -1;
1068 playbackDeviceUID.push_back(ref);
1069 // output sub-devices in this example, so append the sub-device's UID to the CFArray
1070 CFArrayAppendValue(subDevicesArray, ref);
1073 //-----------------------------------------------------------------------
1074 // Feed the dictionary to the plugin, to create a blank aggregate device
1075 //-----------------------------------------------------------------------
1077 AudioObjectPropertyAddress pluginAOPA;
1078 pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
1079 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
1080 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
1081 UInt32 outDataSize;
1083 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
1084 if (osErr != noErr) {
1085 jack_error("CreateAggregateDevice : AudioObjectGetPropertyDataSize error");
1086 printError(osErr);
1087 goto error;
1090 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
1091 if (osErr != noErr) {
1092 jack_error("CreateAggregateDevice : AudioObjectGetPropertyData error");
1093 printError(osErr);
1094 goto error;
1097 // pause for a bit to make sure that everything completed correctly
1098 // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
1099 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
1101 //-------------------------
1102 // Set the sub-device list
1103 //-------------------------
1105 pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
1106 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
1107 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
1108 outDataSize = sizeof(CFMutableArrayRef);
1109 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
1110 if (osErr != noErr) {
1111 jack_error("CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error");
1112 printError(osErr);
1113 goto error;
1116 // pause again to give the changes time to take effect
1117 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
1119 //-----------------------
1120 // Set the master device
1121 //-----------------------
1123 // set the master device manually (this is the device which will act as the master clock for the aggregate device)
1124 // pass in the UID of the device you want to use
1125 pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
1126 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
1127 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
1128 outDataSize = sizeof(CFStringRef);
1129 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]); // First apture is master...
1130 if (osErr != noErr) {
1131 jack_error("CreateAggregateDevice : AudioObjectSetPropertyData for master device error");
1132 printError(osErr);
1133 goto error;
1136 // pause again to give the changes time to take effect
1137 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
1139 // Prepare sub-devices for clock drift compensation
1140 // Workaround for bug in the HAL : until 10.6.2
1142 if (fClockDriftCompensate) {
1143 if (need_clock_drift_compensation) {
1144 jack_info("Clock drift compensation activated...");
1146 // Get the property data size
1147 osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
1148 if (osErr != noErr) {
1149 jack_error("CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
1150 printError(osErr);
1153 // Calculate the number of object IDs
1154 subDevicesNum = outSize / sizeof(AudioObjectID);
1155 jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum);
1156 AudioObjectID subDevices[subDevicesNum];
1157 outSize = sizeof(subDevices);
1159 osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
1160 if (osErr != noErr) {
1161 jack_error("CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
1162 printError(osErr);
1165 // Set kAudioSubDevicePropertyDriftCompensation property...
1166 for (UInt32 index = 0; index < subDevicesNum; ++index) {
1167 UInt32 theDriftCompensationValue = 1;
1168 osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue);
1169 if (osErr != noErr) {
1170 jack_error("CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error");
1171 printError(osErr);
1174 } else {
1175 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
1179 // pause again to give the changes time to take effect
1180 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
1182 //----------
1183 // Clean up
1184 //----------
1186 // release the private AD key
1187 CFRelease(AggregateDeviceNumberRef);
1189 // release the CF objects we have created - we don't need them any more
1190 CFRelease(aggDeviceDict);
1191 CFRelease(subDevicesArray);
1193 if (subDevicesArrayClock) {
1194 CFRelease(subDevicesArrayClock);
1197 // release the device UID
1198 for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
1199 CFRelease(captureDeviceUID[i]);
1202 for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
1203 CFRelease(playbackDeviceUID[i]);
1206 jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : new aggregate device %ld", *outAggregateDevice);
1207 return noErr;
1209 error:
1210 DestroyAggregateDevice();
1211 return -1;
1214 int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid,
1215 const char* playback_driver_uid,
1216 char* capture_driver_name,
1217 char* playback_driver_name,
1218 jack_nframes_t samplerate,
1219 bool ac3_encoding)
1221 capture_driver_name[0] = 0;
1222 playback_driver_name[0] = 0;
1224 // Duplex
1225 if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
1226 jack_log("JackCoreAudioDriver::SetupDevices : duplex");
1228 // Same device for capture and playback...
1229 if (strcmp(capture_driver_uid, playback_driver_uid) == 0) {
1231 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
1232 jack_log("JackCoreAudioDriver::SetupDevices : will take default in/out");
1233 if (GetDefaultDevice(&fDeviceID) != noErr) {
1234 jack_error("Cannot open default device");
1235 return -1;
1238 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
1239 jack_error("Cannot get device name from device ID");
1240 return -1;
1243 if (fHogged) {
1244 if (!TakeHogAux(fDeviceID, false)) {
1245 jack_error("Cannot take hog mode");
1247 if (ac3_encoding) {
1248 fDigitalPlayback = IsDigitalDevice(fDeviceID);
1252 } else {
1254 // Creates aggregate device
1255 AudioDeviceID captureID = -1;
1256 AudioDeviceID playbackID = -1;
1258 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
1259 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1260 if (GetDefaultInputDevice(&captureID) != noErr) {
1261 jack_error("Cannot open default input device");
1262 return -1;
1266 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
1267 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1268 if (GetDefaultOutputDevice(&playbackID) != noErr) {
1269 jack_error("Cannot open default output device");
1270 return -1;
1274 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
1275 return -1;
1278 GetDeviceNameFromID(captureID, fCaptureUID);
1279 GetDeviceNameFromID(playbackID, fPlaybackUID);
1281 if (fHogged) {
1282 if (!TakeHogAux(captureID, true)) {
1283 jack_error("Cannot take hog mode for capture device");
1285 if (!TakeHogAux(playbackID, false)) {
1286 jack_error("Cannot take hog mode for playback device");
1288 if (ac3_encoding) {
1289 fDigitalPlayback = IsDigitalDevice(playbackID);
1295 // Capture only
1296 } else if (strcmp(capture_driver_uid, "") != 0) {
1297 jack_log("JackCoreAudioDriver::SetupDevices : capture only");
1298 if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
1299 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1300 if (GetDefaultInputDevice(&fDeviceID) != noErr) {
1301 jack_error("Cannot open default input device");
1302 return -1;
1305 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) {
1306 jack_error("Cannot get device name from device ID");
1307 return -1;
1310 if (fHogged) {
1311 if (!TakeHogAux(fDeviceID, true)) {
1312 jack_error("Cannot take hog mode for capture device");
1316 // Playback only
1317 } else if (strcmp(playback_driver_uid, "") != 0) {
1318 jack_log("JackCoreAudioDriver::SetupDevices : playback only");
1319 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
1320 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1321 if (GetDefaultOutputDevice(&fDeviceID) != noErr) {
1322 jack_error("Cannot open default output device");
1323 return -1;
1326 if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
1327 jack_error("Cannot get device name from device ID");
1328 return -1;
1331 if (fHogged) {
1332 if (!TakeHogAux(fDeviceID, false)) {
1333 jack_error("Cannot take hog mode for playback device");
1335 if (ac3_encoding) {
1336 fDigitalPlayback = IsDigitalDevice(fDeviceID);
1340 // Use default driver in duplex mode
1341 } else {
1342 jack_log("JackCoreAudioDriver::SetupDevices : default driver");
1343 if (GetDefaultDevice(&fDeviceID) != noErr) {
1344 jack_error("Cannot open default device in duplex mode, so aggregate default input and default output");
1346 // Creates aggregate device
1347 AudioDeviceID captureID = -1;
1348 AudioDeviceID playbackID = -1;
1350 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
1351 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1352 if (GetDefaultInputDevice(&captureID) != noErr) {
1353 jack_error("Cannot open default input device");
1354 return -1;
1358 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
1359 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1360 if (GetDefaultOutputDevice(&playbackID) != noErr) {
1361 jack_error("Cannot open default output device");
1362 return -1;
1366 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
1367 return -1;
1370 GetDeviceNameFromID(captureID, fCaptureUID);
1371 GetDeviceNameFromID(playbackID, fPlaybackUID);
1373 if (fHogged) {
1374 if (!TakeHogAux(captureID, true)) {
1375 jack_error("Cannot take hog mode for capture device");
1377 if (!TakeHogAux(playbackID, false)) {
1378 jack_error("Cannot take hog mode for playback device");
1380 if (ac3_encoding) {
1381 fDigitalPlayback = IsDigitalDevice(playbackID);
1387 return 0;
1391 Return the max possible input channels in in_maxChannels and output channels in out_maxChannels.
1393 int JackCoreAudioDriver::SetupChannels(bool capturing, bool playing, int& inchannels, int& outchannels, int& in_maxChannels, int& out_maxChannels, bool strict)
1395 OSStatus err = noErr;
1397 if (capturing) {
1398 err = GetTotalChannels(fDeviceID, in_maxChannels, true);
1399 if (err != noErr) {
1400 jack_error("SetupChannels : cannot get input channel number");
1401 printError(err);
1402 return -1;
1403 } else {
1404 jack_log("JackCoreAudioDriver::SetupChannels : max input channels : %d", in_maxChannels);
1408 if (playing) {
1409 err = GetTotalChannels(fDeviceID, out_maxChannels, false);
1410 if (err != noErr) {
1411 jack_error("Cannot get output channel number");
1412 printError(err);
1413 return -1;
1414 } else {
1415 jack_log("JackCoreAudioDriver::SetupChannels : max output channels : %d", out_maxChannels);
1419 if (inchannels > in_maxChannels) {
1420 jack_error("This device hasn't required input channels inchannels = %d in_maxChannels = %d", inchannels, in_maxChannels);
1421 if (strict) {
1422 return -1;
1426 if (outchannels > out_maxChannels) {
1427 jack_error("This device hasn't required output channels outchannels = %d out_maxChannels = %d", outchannels, out_maxChannels);
1428 if (strict) {
1429 return -1;
1433 if (inchannels == -1) {
1434 jack_log("JackCoreAudioDriver::SetupChannels : setup max in channels = %d", in_maxChannels);
1435 inchannels = in_maxChannels;
1438 if (outchannels == -1) {
1439 jack_log("JackCoreAudioDriver::SetupChannels : setup max out channels = %d", out_maxChannels);
1440 outchannels = out_maxChannels;
1443 return 0;
1446 int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size)
1448 // Setting buffer size
1449 OSStatus err = noErr;
1450 UInt32 tmp_buffer_size = buffer_size;
1451 UInt32 outSize = sizeof(UInt32);
1453 err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &tmp_buffer_size);
1454 if (err != noErr) {
1455 jack_error("Cannot get buffer size %ld", buffer_size);
1456 printError(err);
1457 return -1;
1458 } else {
1459 jack_log("JackCoreAudioDriver::SetupBufferSize : current buffer size = %ld", tmp_buffer_size);
1462 // If needed, set new buffer size
1463 if (buffer_size != tmp_buffer_size) {
1464 tmp_buffer_size = buffer_size;
1466 // To get BS change notification
1467 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback, this);
1468 if (err != noErr) {
1469 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyBufferFrameSize");
1470 printError(err);
1471 return -1;
1474 // Waiting for BS change notification
1475 int count = 0;
1476 fState = false;
1478 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, outSize, &tmp_buffer_size);
1479 if (err != noErr) {
1480 jack_error("SetupBufferSize : cannot set buffer size = %ld", tmp_buffer_size);
1481 printError(err);
1482 goto error;
1485 while (!fState && count++ < WAIT_NOTIFICATION_COUNTER) {
1486 usleep(100000);
1487 jack_log("JackCoreAudioDriver::SetupBufferSize : wait count = %d", count);
1490 if (count >= WAIT_NOTIFICATION_COUNTER) {
1491 jack_error("Did not get buffer size notification...");
1492 goto error;
1495 // Check new buffer size
1496 outSize = sizeof(UInt32);
1497 err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &tmp_buffer_size);
1498 if (err != noErr) {
1499 jack_error("Cannot get current buffer size");
1500 printError(err);
1501 } else {
1502 jack_log("JackCoreAudioDriver::SetupBufferSize : checked buffer size = %ld", tmp_buffer_size);
1505 // Remove BS change notification
1506 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback);
1509 return 0;
1511 error:
1513 // Remove BS change notification
1514 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback);
1515 return -1;
1519 int JackCoreAudioDriver::SetupSampleRate(jack_nframes_t sample_rate)
1521 return SetupSampleRateAux(fDeviceID, sample_rate);
1524 int JackCoreAudioDriver::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframes_t sample_rate)
1526 OSStatus err = noErr;
1527 UInt32 outSize;
1528 Float64 tmp_sample_rate;
1530 // Get sample rate
1531 outSize = sizeof(Float64);
1532 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &tmp_sample_rate);
1533 if (err != noErr) {
1534 jack_error("Cannot get current sample rate");
1535 printError(err);
1536 return -1;
1537 } else {
1538 jack_log("JackCoreAudioDriver::SetupSampleRateAux : current sample rate = %f", tmp_sample_rate);
1541 // If needed, set new sample rate
1542 if (sample_rate != (jack_nframes_t)tmp_sample_rate) {
1543 tmp_sample_rate = (Float64)sample_rate;
1545 // To get SR change notification
1546 err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
1547 if (err != noErr) {
1548 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
1549 printError(err);
1550 return -1;
1553 // Waiting for SR change notification
1554 int count = 0;
1555 fState = false;
1557 err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &tmp_sample_rate);
1558 if (err != noErr) {
1559 jack_error("Cannot set sample rate = %ld", sample_rate);
1560 printError(err);
1561 goto error;
1564 while (!fState && count++ < WAIT_NOTIFICATION_COUNTER) {
1565 usleep(100000);
1566 jack_log("JackCoreAudioDriver::SetupSampleRateAux : wait count = %d", count);
1569 if (count >= WAIT_NOTIFICATION_COUNTER) {
1570 jack_error("Did not get sample rate notification...");
1571 goto error;
1574 // Check new sample rate
1575 outSize = sizeof(Float64);
1576 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &tmp_sample_rate);
1577 if (err != noErr) {
1578 jack_error("Cannot get current sample rate");
1579 printError(err);
1580 } else {
1581 jack_log("JackCoreAudioDriver::SetupSampleRateAux : checked sample rate = %f", tmp_sample_rate);
1584 // Remove SR change notification
1585 AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
1588 return 0;
1590 error:
1592 // Remove SR change notification
1593 AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
1594 return -1;
1597 int JackCoreAudioDriver::OpenAUHAL(bool capturing,
1598 bool playing,
1599 int inchannels,
1600 int outchannels,
1601 int in_maxChannels,
1602 int out_maxChannels,
1603 const vector<int>& chan_in_list,
1604 const vector<int>& chan_out_list,
1605 jack_nframes_t buffer_size,
1606 jack_nframes_t sample_rate)
1608 ComponentResult err1;
1609 UInt32 enableIO;
1610 AudioStreamBasicDescription srcFormat, dstFormat;
1611 AudioDeviceID currAudioDeviceID;
1612 UInt32 size;
1614 jack_log("JackCoreAudioDriver::OpenAUHAL : capturing = %d playing = %d inchannels = %d outchannels = %d in_maxChannels = %d out_maxChannels = %d chan_in_list = %d chan_out_list = %d",
1615 capturing, playing, inchannels, outchannels, in_maxChannels, out_maxChannels, chan_in_list.size(), chan_out_list.size());
1617 if (inchannels == 0 && outchannels == 0) {
1618 jack_error("No input and output channels...");
1619 return -1;
1622 // AUHAL
1623 SInt32 major;
1624 SInt32 minor;
1625 Gestalt(gestaltSystemVersionMajor, &major);
1626 Gestalt(gestaltSystemVersionMinor, &minor);
1628 if (major == 10 && minor >= 6) {
1629 AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
1630 AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
1631 err1 = AudioComponentInstanceNew(HALOutput, &fAUHAL);
1632 if (err1 != noErr) {
1633 jack_error("Error calling AudioComponentInstanceNew");
1634 printError(err1);
1635 goto error;
1637 } else {
1638 ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
1639 Component HALOutput = FindNextComponent(NULL, &cd);
1640 err1 = OpenAComponent(HALOutput, &fAUHAL);
1641 if (err1 != noErr) {
1642 jack_error("Error calling OpenAComponent");
1643 printError(err1);
1644 goto error;
1648 err1 = AudioUnitInitialize(fAUHAL);
1649 if (err1 != noErr) {
1650 jack_error("Cannot initialize AUHAL unit");
1651 printError(err1);
1652 goto error;
1655 // Start I/O
1656 if (capturing && inchannels > 0) {
1657 enableIO = 1;
1658 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input on");
1659 } else {
1660 enableIO = 0;
1661 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input off");
1664 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
1665 if (err1 != noErr) {
1666 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
1667 printError(err1);
1668 goto error;
1671 if (playing && outchannels > 0) {
1672 enableIO = 1;
1673 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output on");
1674 } else {
1675 enableIO = 0;
1676 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output off");
1679 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
1680 if (err1 != noErr) {
1681 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
1682 printError(err1);
1683 goto error;
1686 size = sizeof(AudioDeviceID);
1687 err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size);
1688 if (err1 != noErr) {
1689 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
1690 printError(err1);
1691 goto error;
1692 } else {
1693 jack_log("JackCoreAudioDriver::OpenAUHAL : AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID);
1696 // Setup up choosen device, in both input and output cases
1697 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
1698 if (err1 != noErr) {
1699 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
1700 printError(err1);
1701 goto error;
1704 // Set buffer size
1705 if (capturing && inchannels > 0) {
1706 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32));
1707 if (err1 != noErr) {
1708 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
1709 printError(err1);
1710 goto error;
1714 if (playing && outchannels > 0) {
1715 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&buffer_size, sizeof(UInt32));
1716 if (err1 != noErr) {
1717 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
1718 printError(err1);
1719 goto error;
1723 // Setup input channel map
1724 if (capturing && inchannels > 0 && inchannels <= in_maxChannels) {
1725 SInt32 chanArr[in_maxChannels];
1726 for (int i = 0; i < in_maxChannels; i++) {
1727 chanArr[i] = -1;
1729 // Explicit mapping
1730 if (chan_in_list.size() > 0) {
1731 for (uint i = 0; i < chan_in_list.size(); i++) {
1732 int chan = chan_in_list[i];
1733 if (chan < out_maxChannels) {
1734 // The wanted JACK input index for the 'chan' channel value
1735 chanArr[chan] = i;
1736 jack_info("Input channel = %d ==> JACK input port = %d", chan, i);
1737 } else {
1738 jack_info("Error input channel number is incorrect : %d", chan);
1739 goto error;
1742 } else {
1743 for (int i = 0; i < inchannels; i++) {
1744 chanArr[i] = i;
1745 jack_info("Input channel = %d ==> JACK input port = %d", chanArr[i], i);
1749 AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_maxChannels);
1750 if (err1 != noErr) {
1751 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap for input");
1752 printError(err1);
1753 goto error;
1757 // Setup output channel map
1758 if (playing && outchannels > 0 && outchannels <= out_maxChannels) {
1759 SInt32 chanArr[out_maxChannels];
1760 for (int i = 0; i < out_maxChannels; i++) {
1761 chanArr[i] = -1;
1763 // Explicit mapping
1764 if (chan_out_list.size() > 0) {
1765 for (uint i = 0; i < chan_out_list.size(); i++) {
1766 int chan = chan_out_list[i];
1767 if (chan < out_maxChannels) {
1768 // The wanted JACK output index for the 'chan' channel value
1769 chanArr[chan] = i;
1770 jack_info("JACK output port = %d ==> output channel = %d", i, chan);
1771 } else {
1772 jack_info("Error output channel number is incorrect : %d", chan);
1773 goto error;
1776 } else {
1777 for (int i = 0; i < outchannels; i++) {
1778 chanArr[i] = i;
1779 jack_info("JACK output port = %d ==> output channel = %d", i, chanArr[i]);
1783 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_maxChannels);
1784 if (err1 != noErr) {
1785 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap for output");
1786 printError(err1);
1787 goto error;
1791 // Setup stream converters
1792 if (capturing && inchannels > 0) {
1794 size = sizeof(AudioStreamBasicDescription);
1795 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &size);
1796 if (err1 != noErr) {
1797 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
1798 printError(err1);
1799 goto error;
1801 PrintStreamDesc(&srcFormat);
1803 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input stream converter SR = %ld", sample_rate);
1804 srcFormat.mSampleRate = sample_rate;
1805 srcFormat.mFormatID = kAudioFormatLinearPCM;
1806 srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
1807 srcFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t);
1808 srcFormat.mFramesPerPacket = 1;
1809 srcFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t);
1810 srcFormat.mChannelsPerFrame = inchannels;
1811 srcFormat.mBitsPerChannel = 32;
1812 PrintStreamDesc(&srcFormat);
1814 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
1815 if (err1 != noErr) {
1816 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
1817 printError(err1);
1818 goto error;
1822 if (playing && outchannels > 0) {
1824 size = sizeof(AudioStreamBasicDescription);
1825 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &size);
1826 if (err1 != noErr) {
1827 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
1828 printError(err1);
1829 goto error;
1831 PrintStreamDesc(&dstFormat);
1833 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output stream converter SR = %ld", sample_rate);
1834 dstFormat.mSampleRate = sample_rate;
1835 dstFormat.mFormatID = kAudioFormatLinearPCM;
1836 dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
1837 dstFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t);
1838 dstFormat.mFramesPerPacket = 1;
1839 dstFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t);
1840 dstFormat.mChannelsPerFrame = outchannels;
1841 dstFormat.mBitsPerChannel = 32;
1842 PrintStreamDesc(&dstFormat);
1844 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
1845 if (err1 != noErr) {
1846 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
1847 printError(err1);
1848 goto error;
1852 // Setup callbacks
1853 if (inchannels > 0 && outchannels == 0) {
1854 AURenderCallbackStruct output;
1855 output.inputProc = Render;
1856 output.inputProcRefCon = this;
1857 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
1858 if (err1 != noErr) {
1859 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
1860 printError(err1);
1861 goto error;
1863 } else {
1864 AURenderCallbackStruct output;
1865 output.inputProc = Render;
1866 output.inputProcRefCon = this;
1867 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
1868 if (err1 != noErr) {
1869 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
1870 printError(err1);
1871 goto error;
1875 return 0;
1877 error:
1878 CloseAUHAL();
1879 return -1;
1882 int JackCoreAudioDriver::SetupBuffers(int inchannels)
1884 // Prepare buffers
1885 fJackInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
1886 fJackInputData->mNumberBuffers = inchannels;
1887 for (int i = 0; i < inchannels; i++) {
1888 fJackInputData->mBuffers[i].mNumberChannels = 1;
1889 fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(jack_default_audio_sample_t);
1891 return 0;
1894 void JackCoreAudioDriver::DisposeBuffers()
1896 if (fJackInputData) {
1897 free(fJackInputData);
1898 fJackInputData = 0;
1902 void JackCoreAudioDriver::CloseAUHAL()
1904 AudioOutputUnitStop(fAUHAL);
1905 AudioUnitUninitialize(fAUHAL);
1906 CloseComponent(fAUHAL);
1909 int JackCoreAudioDriver::AddListeners()
1911 OSStatus err = noErr;
1913 // Add listeners
1914 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
1915 if (err != noErr) {
1916 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
1917 printError(err);
1918 return -1;
1921 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback, this);
1922 if (err != noErr) {
1923 jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices");
1924 printError(err);
1925 return -1;
1928 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this);
1929 if (err != noErr) {
1930 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
1931 printError(err);
1932 return -1;
1935 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this);
1936 if (err != noErr) {
1937 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
1938 printError(err);
1939 return -1;
1942 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, DeviceNotificationCallback, this);
1943 if (err != noErr) {
1944 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsAlive");
1945 printError(err);
1946 return -1;
1949 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceHasChanged, DeviceNotificationCallback, this);
1950 if (err != noErr) {
1951 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceHasChanged");
1952 printError(err);
1953 return -1;
1956 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
1957 if (err != noErr) {
1958 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1959 printError(err);
1960 return -1;
1963 err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
1964 if (err != noErr) {
1965 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1966 printError(err);
1967 return -1;
1970 if (!fEngineControl->fSyncMode && fIOUsage != 1.f) {
1971 UInt32 outSize = sizeof(float);
1972 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyIOCycleUsage, outSize, &fIOUsage);
1973 if (err != noErr) {
1974 jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage");
1975 printError(err);
1979 return 0;
1982 void JackCoreAudioDriver::RemoveListeners()
1984 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback);
1985 AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback);
1986 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback);
1987 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback);
1988 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, DeviceNotificationCallback);
1989 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceHasChanged, DeviceNotificationCallback);
1990 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
1991 AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
1994 int JackCoreAudioDriver::Open(jack_nframes_t buffer_size,
1995 jack_nframes_t sample_rate,
1996 bool capturing,
1997 bool playing,
1998 int inchannels,
1999 int outchannels,
2000 const char* chan_in_list,
2001 const char* chan_out_list,
2002 bool monitor,
2003 const char* capture_driver_uid,
2004 const char* playback_driver_uid,
2005 jack_nframes_t capture_latency,
2006 jack_nframes_t playback_latency,
2007 int async_output_latency,
2008 int computation_grain,
2009 bool hogged,
2010 bool clock_drift,
2011 bool ac3_encoding,
2012 int ac3_bitrate,
2013 bool ac3_lfe)
2015 int in_maxChannels = 0;
2016 int out_maxChannels = 0;
2017 char capture_driver_name[256];
2018 char playback_driver_name[256];
2020 fCaptureLatency = capture_latency;
2021 fPlaybackLatency = playback_latency;
2022 fIOUsage = float(async_output_latency) / 100.f;
2023 fComputationGrain = float(computation_grain) / 100.f;
2024 fHogged = hogged;
2025 fClockDriftCompensate = clock_drift;
2027 SInt32 major;
2028 SInt32 minor;
2029 Gestalt(gestaltSystemVersionMajor, &major);
2030 Gestalt(gestaltSystemVersionMinor, &minor);
2032 vector<int> parsed_chan_in_list;
2033 vector<int> parsed_chan_out_list;
2035 // Starting with 10.6 systems, the HAL notification thread is created internally
2036 if (major == 10 && minor >= 6) {
2037 CFRunLoopRef theRunLoop = NULL;
2038 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
2039 OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
2040 if (osErr != noErr) {
2041 jack_error("Open kAudioHardwarePropertyRunLoop error");
2042 printError(osErr);
2046 if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name, sample_rate, ac3_encoding) < 0) {
2047 goto error;
2050 // Generic JackAudioDriver Open
2051 if (JackAudioDriver::Open(buffer_size, sample_rate,
2052 capturing, playing,
2053 inchannels, outchannels,
2054 monitor,
2055 capture_driver_name,
2056 playback_driver_name,
2057 capture_latency,
2058 playback_latency) != 0) {
2059 goto error;
2062 if (SetupChannels(capturing, playing, inchannels, outchannels, in_maxChannels, out_maxChannels, !ac3_encoding) < 0) {
2063 goto error;
2066 ParseChannelList(chan_in_list, parsed_chan_in_list, in_maxChannels);
2067 if (parsed_chan_in_list.size() > 0) {
2068 jack_info("Explicit input channel list size = %d", parsed_chan_in_list.size());
2069 inchannels = parsed_chan_in_list.size();
2072 ParseChannelList(chan_out_list, parsed_chan_out_list, out_maxChannels);
2073 if (parsed_chan_out_list.size() > 0) {
2074 jack_info("Explicit output channel list size = %d", parsed_chan_out_list.size());
2075 outchannels = parsed_chan_out_list.size();
2078 if (SetupBufferSize(buffer_size) < 0) {
2079 goto error;
2082 if (SetupSampleRate(sample_rate) < 0) {
2083 goto error;
2086 if (ac3_encoding) {
2088 if (!fDigitalPlayback) {
2089 jack_error("AC3 encoding can only be used with a digital device");
2090 goto error;
2093 JackAC3EncoderParams params;
2094 memset(&params, 0, sizeof(JackAC3EncoderParams));
2095 params.bitrate = ac3_bitrate;
2096 params.channels = outchannels;
2097 params.sample_rate = sample_rate;
2098 params.lfe = ac3_lfe;
2099 fAC3Encoder = new JackAC3Encoder(params);
2101 if (!fAC3Encoder || !fAC3Encoder->Init(sample_rate)) {
2102 jack_error("Cannot allocate or init AC3 encoder");
2103 goto error;
2106 // Setup AC3 channel number
2107 fPlaybackChannels = outchannels;
2108 if (ac3_lfe) {
2109 fPlaybackChannels++;
2112 if (fPlaybackChannels < 2 || fPlaybackChannels > 6) {
2113 jack_error("AC3 encoder channels must be between 2 and 6");
2114 goto error;
2117 // Force real output channel number to 2
2118 outchannels = out_maxChannels = 2;
2120 } else {
2121 fPlaybackChannels = outchannels;
2124 // Core driver may have changed the in/out values
2125 fCaptureChannels = inchannels;
2127 if (OpenAUHAL(capturing, playing, inchannels, outchannels, in_maxChannels, out_maxChannels, parsed_chan_in_list, parsed_chan_out_list, buffer_size, sample_rate) < 0) {
2128 goto error;
2131 if (capturing && inchannels > 0) {
2132 if (SetupBuffers(inchannels) < 0) {
2133 goto error;
2137 if (AddListeners() < 0) {
2138 goto error;
2141 return noErr;
2143 error:
2144 Close();
2145 return -1;
2148 int JackCoreAudioDriver::Close()
2150 jack_log("JackCoreAudioDriver::Close");
2152 // Generic audio driver close
2153 int res = JackAudioDriver::Close();
2155 RemoveListeners();
2156 DisposeBuffers();
2157 CloseAUHAL();
2158 DestroyAggregateDevice();
2159 return res;
2162 void JackCoreAudioDriver::UpdateLatencies()
2164 UInt32 size;
2165 OSStatus err;
2166 jack_latency_range_t input_range;
2167 jack_latency_range_t output_range;
2168 jack_latency_range_t monitor_range;
2170 // Get Input latency
2171 size = sizeof(UInt32);
2172 UInt32 value1 = 0;
2173 UInt32 value2 = 0;
2174 err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1);
2175 if (err != noErr) {
2176 jack_error("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
2178 err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2);
2179 if (err != noErr) {
2180 jack_error("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
2183 input_range.min = input_range.max = fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency;
2185 // Get input stream latencies
2186 vector<int> input_latencies;
2187 err = GetStreamLatencies(fDeviceID, true, input_latencies);
2189 for (int i = 0; i < fCaptureChannels; i++) {
2190 if (err != noErr) {
2191 input_range.min += input_latencies[i];
2192 input_range.max += input_latencies[i];
2194 fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &input_range);
2197 // Get Output latency
2198 size = sizeof(UInt32);
2199 value1 = 0;
2200 value2 = 0;
2201 err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyLatency, &size, &value1);
2202 if (err != noErr) {
2203 jack_error("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
2205 err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2);
2206 if (err != noErr) {
2207 jack_error("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
2210 // Get output stream latencies
2211 vector<int> output_latencies;
2212 err = GetStreamLatencies(fDeviceID, false, output_latencies);
2214 // Add more latency if "async" mode is used...
2215 output_range.min = output_range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode)
2216 ? 0 : fEngineControl->fBufferSize * fIOUsage) + value1 + value2 + fPlaybackLatency;
2218 for (int i = 0; i < fPlaybackChannels; i++) {
2219 if (err != noErr) {
2220 output_range.min += output_latencies[i];
2221 output_range.max += output_latencies[i];
2223 fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &output_range);
2225 // Monitor port
2226 if (fWithMonitorPorts) {
2227 monitor_range.min = monitor_range.max = fEngineControl->fBufferSize;
2228 fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &monitor_range);
2233 int JackCoreAudioDriver::Attach()
2235 OSStatus err;
2236 JackPort* port;
2237 jack_port_id_t port_index;
2238 UInt32 size;
2239 Boolean isWritable;
2240 char channel_name[64];
2241 char name[REAL_JACK_PORT_NAME_SIZE];
2242 char alias[REAL_JACK_PORT_NAME_SIZE];
2244 jack_log("JackCoreAudioDriver::Attach : fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
2246 for (int i = 0; i < fCaptureChannels; i++) {
2248 err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable);
2249 if (err != noErr) {
2250 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error");
2252 if (err == noErr && size > 0) {
2253 err = AudioDeviceGetProperty(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, channel_name);
2254 if (err != noErr) {
2255 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetProperty kAudioDevicePropertyChannelName error");
2257 snprintf(alias, sizeof(alias), "%s:%s:out_%s%u", fAliasName, fCaptureDriverName, channel_name, i + 1);
2258 } else {
2259 snprintf(alias, sizeof(alias), "%s:%s:out%u", fAliasName, fCaptureDriverName, i + 1);
2262 snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, i + 1);
2264 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
2265 jack_error("Cannot register port for %s", name);
2266 return -1;
2269 port = fGraphManager->GetPort(port_index);
2270 port->SetAlias(alias);
2271 fCapturePortList[i] = port_index;
2274 for (int i = 0; i < fPlaybackChannels; i++) {
2276 err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, &isWritable);
2277 if (err != noErr) {
2278 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error");
2280 if (err == noErr && size > 0) {
2281 err = AudioDeviceGetProperty(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, channel_name);
2282 if (err != noErr) {
2283 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetProperty kAudioDevicePropertyChannelName error");
2285 snprintf(alias, sizeof(alias), "%s:%s:in_%s%u", fAliasName, fPlaybackDriverName, channel_name, i + 1);
2286 } else {
2287 snprintf(alias, sizeof(alias), "%s:%s:in%u", fAliasName, fPlaybackDriverName, i + 1);
2290 snprintf(name, sizeof(name), "%s:playback_%d", fClientControl.fName, i + 1);
2292 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
2293 jack_error("Cannot register port for %s", name);
2294 return -1;
2297 port = fGraphManager->GetPort(port_index);
2298 port->SetAlias(alias);
2299 fPlaybackPortList[i] = port_index;
2301 // Monitor ports
2302 if (fWithMonitorPorts) {
2303 jack_log("JackCoreAudioDriver::Attach : create monitor port");
2304 snprintf(name, sizeof(name), "%s:monitor_%u", fClientControl.fName, i + 1);
2305 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
2306 jack_error("Cannot register monitor port for %s", name);
2307 return -1;
2308 } else {
2309 fMonitorPortList[i] = port_index;
2314 if (fAC3Encoder) {
2315 // Setup specific AC3 channels names
2316 for (int i = 0; i < fPlaybackChannels; i++) {
2317 fAC3Encoder->GetChannelName("coreaudio", "", alias, i);
2318 port = fGraphManager->GetPort(fPlaybackPortList[i]);
2319 port->SetAlias(alias);
2323 UpdateLatencies();
2325 // Input buffers do no change : prepare them only once
2326 for (int i = 0; i < fCaptureChannels; i++) {
2327 fJackInputData->mBuffers[i].mData = GetInputBuffer(i);
2330 return 0;
2333 int JackCoreAudioDriver::Start()
2335 jack_log("JackCoreAudioDriver::Start");
2336 if (JackAudioDriver::Start() == 0) {
2338 // Waiting for Render callback to be called (= driver has started)
2339 fState = false;
2340 int count = 0;
2342 OSStatus err = AudioOutputUnitStart(fAUHAL);
2343 if (err == noErr) {
2345 while (!fState && count++ < WAIT_COUNTER) {
2346 usleep(100000);
2347 jack_log("JackCoreAudioDriver::Start : wait count = %d", count);
2350 if (count < WAIT_COUNTER) {
2351 jack_info("CoreAudio driver is running...");
2352 return 0;
2355 jack_error("CoreAudio driver cannot start...");
2357 JackAudioDriver::Stop();
2359 return -1;
2362 int JackCoreAudioDriver::Stop()
2364 jack_log("JackCoreAudioDriver::Stop");
2365 int res = (AudioOutputUnitStop(fAUHAL) == noErr) ? 0 : -1;
2366 if (JackAudioDriver::Stop() < 0) {
2367 res = -1;
2369 return res;
2372 int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
2374 if (SetupBufferSize(buffer_size) < 0) {
2375 return -1;
2378 JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails
2380 // CoreAudio specific
2381 UpdateLatencies();
2383 // Input buffers do no change : prepare them only once
2384 for (int i = 0; i < fCaptureChannels; i++) {
2385 fJackInputData->mBuffers[i].mNumberChannels = 1;
2386 fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(jack_default_audio_sample_t);
2387 fJackInputData->mBuffers[i].mData = GetInputBuffer(i);
2390 return 0;
2393 bool JackCoreAudioDriver::TakeHogAux(AudioDeviceID deviceID, bool isInput)
2395 pid_t hog_pid;
2396 OSStatus err;
2398 UInt32 propSize = sizeof(hog_pid);
2399 err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyHogMode, &propSize, &hog_pid);
2400 if (err) {
2401 jack_error("Cannot read hog state...");
2402 printError(err);
2405 jack_log("JackCoreAudioDriver::TakeHogAux : deviceID = %d", deviceID);
2407 if (hog_pid != getpid()) {
2408 hog_pid = getpid();
2409 err = AudioDeviceSetProperty(deviceID, 0, 0, isInput, kAudioDevicePropertyHogMode, propSize, &hog_pid);
2410 if (err != noErr) {
2411 jack_error("Can't hog device = %d because it's being hogged by another program or cannot be hogged", deviceID);
2412 return false;
2416 return true;
2419 bool JackCoreAudioDriver::TakeHog()
2421 OSStatus err = noErr;
2422 AudioObjectID sub_device[32];
2423 UInt32 outSize = sizeof(sub_device);
2424 err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
2426 if (err != noErr) {
2427 jack_log("JackCoreAudioDriver::TakeHog : device does not have subdevices");
2428 return TakeHogAux(fDeviceID, true);
2429 } else {
2430 int num_devices = outSize / sizeof(AudioObjectID);
2431 jack_log("JackCoreAudioDriver::TakeHog : device does has %d subdevices", num_devices);
2432 for (int i = 0; i < num_devices; i++) {
2433 if (!TakeHogAux(sub_device[i], true)) {
2434 return false;
2437 return true;
2441 bool JackCoreAudioDriver::IsAggregateDevice(AudioDeviceID device)
2443 UInt32 deviceType, outSize = sizeof(UInt32);
2444 OSStatus err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyTransportType, &outSize, &deviceType);
2446 if (err != noErr) {
2447 jack_log("JackCoreAudioDriver::IsAggregateDevice kAudioDevicePropertyTransportType error");
2448 return false;
2449 } else {
2450 return (deviceType == kAudioDeviceTransportTypeAggregate);
2455 } // end of namespace
2458 #ifdef __cplusplus
2459 extern "C"
2461 #endif
2463 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
2465 jack_driver_desc_t * desc;
2466 jack_driver_desc_filler_t filler;
2467 jack_driver_param_value_t value;
2469 desc = jack_driver_descriptor_construct("coreaudio", JackDriverMaster, "Apple CoreAudio API based audio backend", &filler);
2471 value.i = -1;
2472 jack_driver_descriptor_add_parameter(desc, &filler, "channels", 'c', JackDriverParamInt, &value, NULL, "Maximum number of channels", "Maximum number of channels. If -1, max possible number of channels will be used");
2473 jack_driver_descriptor_add_parameter(desc, &filler, "in-channels", 'i', JackDriverParamInt, &value, NULL, "Maximum number of input channels", "Maximum number of input channels. If -1, max possible number of input channels will be used");
2474 jack_driver_descriptor_add_parameter(desc, &filler, "out-channels", 'o', JackDriverParamInt, &value, NULL, "Maximum number of output channels", "Maximum number of output channels. If -1, max possible number of output channels will be used");
2476 value.str[0] = 0;
2477 jack_driver_descriptor_add_parameter(desc, &filler, "input-list", 'n', JackDriverParamString, &value, NULL, "Input channel list for channel mapping", "List of input channel number to be opened (syntax like : \"0 3 2\")");
2478 jack_driver_descriptor_add_parameter(desc, &filler, "output-list", 'N', JackDriverParamString, &value, NULL, "Output channel list for channel mapping", "List of output channel number to be opened (syntax like : \"0 3 2\")");
2480 value.str[0] = 0;
2481 jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Input CoreAudio device name", NULL);
2482 jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Output CoreAudio device name", NULL);
2484 value.i = 0;
2485 jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL);
2487 #ifndef __ppc__
2488 value.i = 0;
2489 jack_driver_descriptor_add_parameter(desc, &filler, "AC3-encoding", 'a', JackDriverParamBool, &value, NULL, "AC3 multi-channels encoding", NULL);
2491 value.i = 448;
2492 jack_driver_descriptor_add_parameter(desc, &filler, "AC3-bitrate", 'b', JackDriverParamUInt, &value, NULL, "AC3 bitrate", NULL);
2494 value.i = 0;
2495 jack_driver_descriptor_add_parameter(desc, &filler, "AC3-LFE", 'f', JackDriverParamBool, &value, NULL, "AC3 LFE channel", NULL);
2496 #endif
2497 value.i = TRUE;
2498 jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL);
2500 value.ui = 44100U;
2501 jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
2503 value.ui = 256U;
2504 jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
2506 value.str[0] = 0;
2507 jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "CoreAudio device name", NULL);
2509 value.ui = 0;
2510 jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency (frames)", NULL);
2511 jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency (frames)", NULL);
2513 value.i = FALSE;
2514 jack_driver_descriptor_add_parameter(desc, &filler, "list-devices", 'l', JackDriverParamBool, &value, NULL, "Display available CoreAudio devices", NULL);
2516 value.i = FALSE;
2517 jack_driver_descriptor_add_parameter(desc, &filler, "hog", 'H', JackDriverParamBool, &value, NULL, "Take exclusive access of the audio device", NULL);
2519 value.ui = 100;
2520 jack_driver_descriptor_add_parameter(desc, &filler, "async-latency", 'L', JackDriverParamUInt, &value, NULL, "Extra output latency in asynchronous mode (percent)", NULL);
2522 value.ui = 100;
2523 jack_driver_descriptor_add_parameter(desc, &filler, "grain", 'G', JackDriverParamUInt, &value, NULL, "Computation grain in RT thread (percent)", NULL);
2525 value.i = FALSE;
2526 jack_driver_descriptor_add_parameter(desc, &filler, "clock-drift", 's', JackDriverParamBool, &value, NULL, "Clock drift compensation", "Whether to compensate clock drift in dynamically created aggregate device");
2528 return desc;
2531 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
2533 jack_nframes_t srate = 44100;
2534 jack_nframes_t frames_per_interrupt = 256;
2535 bool capture = false;
2536 bool playback = false;
2537 int chan_in = -1; // Default: if not explicitely set, then max possible will be used...
2538 int chan_out = -1; // Default: if not explicitely set, then max possible will be used...
2539 const char* chan_in_list = "";
2540 const char* chan_out_list = "";
2541 bool monitor = false;
2542 const char* capture_driver_uid = "";
2543 const char* playback_driver_uid = "";
2544 const JSList *node;
2545 const jack_driver_param_t *param;
2546 jack_nframes_t systemic_input_latency = 0;
2547 jack_nframes_t systemic_output_latency = 0;
2548 int async_output_latency = 100;
2549 int computation_grain = -1;
2550 bool hogged = false;
2551 bool clock_drift = false;
2552 bool ac3_encoding = false;
2553 int ac3_bitrate = 448;
2554 bool ac3_lfe = false;
2556 for (node = params; node; node = jack_slist_next(node)) {
2557 param = (const jack_driver_param_t *) node->data;
2559 switch (param->character) {
2561 case 'd':
2562 capture_driver_uid = param->value.str;
2563 playback_driver_uid = param->value.str;
2564 break;
2566 case 'D':
2567 capture = true;
2568 playback = true;
2569 break;
2571 case 'c':
2572 chan_in = chan_out = param->value.i;
2573 break;
2575 case 'i':
2576 chan_in = param->value.i;
2577 break;
2579 case 'o':
2580 chan_out = param->value.i;
2581 break;
2583 case 'n':
2584 chan_in_list = param->value.str;
2585 break;
2587 case 'N':
2588 chan_out_list = param->value.str;
2589 break;
2591 case 'C':
2592 capture = true;
2593 if (strcmp(param->value.str, "none") != 0) {
2594 capture_driver_uid = param->value.str;
2596 break;
2598 case 'P':
2599 playback = true;
2600 if (strcmp(param->value.str, "none") != 0) {
2601 playback_driver_uid = param->value.str;
2603 break;
2605 case 'm':
2606 monitor = param->value.i;
2607 break;
2609 #ifndef __ppc__
2610 case 'a':
2611 ac3_encoding = param->value.i;
2612 break;
2614 case 'b':
2615 ac3_bitrate = param->value.i;
2616 break;
2618 case 'f':
2619 ac3_lfe = param->value.i;
2620 break;
2621 #endif
2623 case 'r':
2624 srate = param->value.ui;
2625 break;
2627 case 'p':
2628 frames_per_interrupt = (unsigned int)param->value.ui;
2629 break;
2631 case 'I':
2632 systemic_input_latency = param->value.ui;
2633 break;
2635 case 'O':
2636 systemic_output_latency = param->value.ui;
2637 break;
2639 case 'l':
2640 Jack::DisplayDeviceNames();
2641 // Stops the server in this case
2642 return NULL;
2644 case 'H':
2645 hogged = true;
2646 break;
2648 case 'L':
2649 async_output_latency = param->value.ui;
2650 break;
2652 case 'G':
2653 computation_grain = param->value.ui;
2654 break;
2656 case 's':
2657 clock_drift = true;
2658 break;
2662 /* duplex is the default */
2663 if (!capture && !playback) {
2664 capture = true;
2665 playback = true;
2668 if (strcmp(chan_in_list, "") != 0 && chan_in >= 0) {
2669 printf("Input channel list and in channels are both specified, input channel list will take over...\n");
2672 if (strcmp(chan_out_list, "") != 0 && chan_out >= 0) {
2673 printf("Output channel list and out channels are both specified, output channel list will take over...\n");
2676 Jack::JackCoreAudioDriver* driver = new Jack::JackCoreAudioDriver("system", "coreaudio", engine, table);
2677 if (driver->Open(frames_per_interrupt,
2678 srate, capture,
2679 playback, chan_in,
2680 chan_out, chan_in_list,
2681 chan_out_list, monitor,
2682 capture_driver_uid,
2683 playback_driver_uid,
2684 systemic_input_latency,
2685 systemic_output_latency,
2686 async_output_latency,
2687 computation_grain,
2688 hogged, clock_drift,
2689 ac3_encoding, ac3_bitrate, ac3_lfe) == 0) {
2690 return driver;
2691 } else {
2692 delete driver;
2693 return NULL;
2697 #ifdef __cplusplus
2699 #endif