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