00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "JackCoreAudioAdapter.h"
00021 #include "JackError.h"
00022 #include <unistd.h>
00023
00024 #include <CoreServices/CoreServices.h>
00025
00026 namespace Jack
00027 {
00028
00029 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
00030 {
00031 jack_log("- - - - - - - - - - - - - - - - - - - -");
00032 jack_log(" Sample Rate:%f", inDesc->mSampleRate);
00033 jack_log(" Format ID:%.*s", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
00034 jack_log(" Format Flags:%lX", inDesc->mFormatFlags);
00035 jack_log(" Bytes per Packet:%ld", inDesc->mBytesPerPacket);
00036 jack_log(" Frames per Packet:%ld", inDesc->mFramesPerPacket);
00037 jack_log(" Bytes per Frame:%ld", inDesc->mBytesPerFrame);
00038 jack_log(" Channels per Frame:%ld", inDesc->mChannelsPerFrame);
00039 jack_log(" Bits per Channel:%ld", inDesc->mBitsPerChannel);
00040 jack_log("- - - - - - - - - - - - - - - - - - - -");
00041 }
00042
00043 static OSStatus DisplayDeviceNames()
00044 {
00045 UInt32 size;
00046 Boolean isWritable;
00047 int i, deviceNum;
00048 OSStatus err;
00049 CFStringRef UIname;
00050
00051 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
00052 if (err != noErr) {
00053 return err;
00054 }
00055
00056 deviceNum = size / sizeof(AudioDeviceID);
00057 AudioDeviceID devices[deviceNum];
00058
00059 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
00060 if (err != noErr) {
00061 return err;
00062 }
00063
00064 for (i = 0; i < deviceNum; i++) {
00065 char device_name[256];
00066 char internal_name[256];
00067
00068 size = sizeof(CFStringRef);
00069 UIname = NULL;
00070 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
00071 if (err == noErr) {
00072 CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
00073 } else {
00074 goto error;
00075 }
00076
00077 size = 256;
00078 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
00079 if (err != noErr) {
00080 return err;
00081 }
00082
00083 jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name, internal_name);
00084 }
00085
00086 return noErr;
00087
00088 error:
00089 if (UIname != NULL) {
00090 CFRelease(UIname);
00091 }
00092 return err;
00093 }
00094
00095 static void printError(OSStatus err)
00096 {
00097 switch (err) {
00098 case kAudioHardwareNoError:
00099 jack_log("error code : kAudioHardwareNoError");
00100 break;
00101 case kAudioConverterErr_FormatNotSupported:
00102 jack_log("error code : kAudioConverterErr_FormatNotSupported");
00103 break;
00104 case kAudioConverterErr_OperationNotSupported:
00105 jack_log("error code : kAudioConverterErr_OperationNotSupported");
00106 break;
00107 case kAudioConverterErr_PropertyNotSupported:
00108 jack_log("error code : kAudioConverterErr_PropertyNotSupported");
00109 break;
00110 case kAudioConverterErr_InvalidInputSize:
00111 jack_log("error code : kAudioConverterErr_InvalidInputSize");
00112 break;
00113 case kAudioConverterErr_InvalidOutputSize:
00114 jack_log("error code : kAudioConverterErr_InvalidOutputSize");
00115 break;
00116 case kAudioConverterErr_UnspecifiedError:
00117 jack_log("error code : kAudioConverterErr_UnspecifiedError");
00118 break;
00119 case kAudioConverterErr_BadPropertySizeError:
00120 jack_log("error code : kAudioConverterErr_BadPropertySizeError");
00121 break;
00122 case kAudioConverterErr_RequiresPacketDescriptionsError:
00123 jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
00124 break;
00125 case kAudioConverterErr_InputSampleRateOutOfRange:
00126 jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
00127 break;
00128 case kAudioConverterErr_OutputSampleRateOutOfRange:
00129 jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
00130 break;
00131 case kAudioHardwareNotRunningError:
00132 jack_log("error code : kAudioHardwareNotRunningError");
00133 break;
00134 case kAudioHardwareUnknownPropertyError:
00135 jack_log("error code : kAudioHardwareUnknownPropertyError");
00136 break;
00137 case kAudioHardwareIllegalOperationError:
00138 jack_log("error code : kAudioHardwareIllegalOperationError");
00139 break;
00140 case kAudioHardwareBadDeviceError:
00141 jack_log("error code : kAudioHardwareBadDeviceError");
00142 break;
00143 case kAudioHardwareBadStreamError:
00144 jack_log("error code : kAudioHardwareBadStreamError");
00145 break;
00146 case kAudioDeviceUnsupportedFormatError:
00147 jack_log("error code : kAudioDeviceUnsupportedFormatError");
00148 break;
00149 case kAudioDevicePermissionsError:
00150 jack_log("error code : kAudioDevicePermissionsError");
00151 break;
00152 case kAudioHardwareBadObjectError:
00153 jack_log("error code : kAudioHardwareBadObjectError");
00154 break;
00155 case kAudioHardwareUnsupportedOperationError:
00156 jack_log("error code : kAudioHardwareUnsupportedOperationError");
00157 break;
00158 default:
00159 jack_log("error code : unknown");
00160 break;
00161 }
00162 }
00163
00164 OSStatus JackCoreAudioAdapter::AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID, void* inClientData)
00165 {
00166 JackCoreAudioAdapter* driver = (JackCoreAudioAdapter*)inClientData;
00167
00168 switch (inPropertyID) {
00169
00170 case kAudioHardwarePropertyDevices: {
00171 jack_log("JackCoreAudioAdapter::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices");
00172 DisplayDeviceNames();
00173 break;
00174 }
00175 }
00176
00177 return noErr;
00178 }
00179
00180 OSStatus JackCoreAudioAdapter::SRNotificationCallback(AudioDeviceID inDevice,
00181 UInt32 inChannel,
00182 Boolean isInput,
00183 AudioDevicePropertyID inPropertyID,
00184 void* inClientData)
00185 {
00186 JackCoreAudioAdapter* driver = static_cast<JackCoreAudioAdapter*>(inClientData);
00187
00188 switch (inPropertyID) {
00189
00190 case kAudioDevicePropertyNominalSampleRate: {
00191 jack_log("JackCoreAudioAdapter::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
00192 driver->fState = true;
00193 break;
00194 }
00195 }
00196
00197 return noErr;
00198 }
00199
00200
00201 OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice,
00202 UInt32 inChannel,
00203 Boolean isInput,
00204 AudioDevicePropertyID inPropertyID,
00205 void* inClientData)
00206 {
00207
00208 switch (inPropertyID) {
00209
00210 case kAudioDeviceProcessorOverload: {
00211 jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload");
00212 break;
00213 }
00214
00215 case kAudioDevicePropertyStreamConfiguration: {
00216 jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration");
00217 return kAudioHardwareUnsupportedOperationError;
00218 }
00219
00220 case kAudioDevicePropertyNominalSampleRate: {
00221 jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate");
00222 return kAudioHardwareUnsupportedOperationError;
00223 }
00224
00225 }
00226 return noErr;
00227 }
00228
00229 int JackCoreAudioAdapter::AddListeners()
00230 {
00231 OSStatus err = noErr;
00232
00233
00234 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
00235 if (err != noErr) {
00236 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
00237 printError(err);
00238 return -1;
00239 }
00240
00241 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback, this);
00242 if (err != noErr) {
00243 jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices");
00244 printError(err);
00245 return -1;
00246 }
00247
00248 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this);
00249 if (err != noErr) {
00250 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
00251 printError(err);
00252 return -1;
00253 }
00254
00255 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this);
00256 if (err != noErr) {
00257 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
00258 printError(err);
00259 return -1;
00260 }
00261
00262 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
00263 if (err != noErr) {
00264 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
00265 printError(err);
00266 return -1;
00267 }
00268
00269 err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
00270 if (err != noErr) {
00271 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
00272 printError(err);
00273 return -1;
00274 }
00275
00276 return 0;
00277 }
00278
00279 void JackCoreAudioAdapter::RemoveListeners()
00280 {
00281 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback);
00282 AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback);
00283 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback);
00284 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback);
00285 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
00286 AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
00287 }
00288
00289 OSStatus JackCoreAudioAdapter::Render(void *inRefCon,
00290 AudioUnitRenderActionFlags *ioActionFlags,
00291 const AudioTimeStamp *inTimeStamp,
00292 UInt32 inBusNumber,
00293 UInt32 inNumberFrames,
00294 AudioBufferList *ioData)
00295 {
00296 JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon);
00297 OSStatus err = AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData);
00298
00299 if (err == noErr) {
00300 jack_default_audio_sample_t* inputBuffer[adapter->fCaptureChannels];
00301 jack_default_audio_sample_t* outputBuffer[adapter->fPlaybackChannels];
00302
00303 for (int i = 0; i < adapter->fCaptureChannels; i++) {
00304 inputBuffer[i] = (jack_default_audio_sample_t*)adapter->fInputData->mBuffers[i].mData;
00305 }
00306 for (int i = 0; i < adapter->fPlaybackChannels; i++) {
00307 outputBuffer[i] = (jack_default_audio_sample_t*)ioData->mBuffers[i].mData;
00308 }
00309
00310 adapter->PushAndPull((jack_default_audio_sample_t**)inputBuffer, (jack_default_audio_sample_t**)outputBuffer, inNumberFrames);
00311 return noErr;
00312 } else {
00313 return err;
00314 }
00315 }
00316
00317 JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
00318 :JackAudioAdapterInterface(buffer_size, sample_rate), fInputData(0), fCapturing(false), fPlaying(false), fState(false)
00319 {
00320 const JSList* node;
00321 const jack_driver_param_t* param;
00322 int in_nChannels = 0;
00323 int out_nChannels = 0;
00324 char captureName[256];
00325 char playbackName[256];
00326 fCaptureUID[0] = 0;
00327 fPlaybackUID[0] = 0;
00328 fClockDriftCompensate = false;
00329
00330
00331 fCaptureChannels = -1;
00332 fPlaybackChannels = -1;
00333
00334 SInt32 major;
00335 SInt32 minor;
00336 Gestalt(gestaltSystemVersionMajor, &major);
00337 Gestalt(gestaltSystemVersionMinor, &minor);
00338
00339
00340 if (major == 10 && minor >= 6) {
00341 CFRunLoopRef theRunLoop = NULL;
00342 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
00343 OSStatus theError = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
00344 if (theError != noErr) {
00345 jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error");
00346 }
00347 }
00348
00349 for (node = params; node; node = jack_slist_next(node)) {
00350 param = (const jack_driver_param_t*) node->data;
00351
00352 switch (param->character) {
00353
00354 case 'c' :
00355 fCaptureChannels = fPlaybackChannels = param->value.ui;
00356 break;
00357
00358 case 'i':
00359 fCaptureChannels = param->value.ui;
00360 break;
00361
00362 case 'o':
00363 fPlaybackChannels = param->value.ui;
00364 break;
00365
00366 case 'C':
00367 fCapturing = true;
00368 strncpy(fCaptureUID, param->value.str, 256);
00369 break;
00370
00371 case 'P':
00372 fPlaying = true;
00373 strncpy(fPlaybackUID, param->value.str, 256);
00374 break;
00375
00376 case 'd':
00377 strncpy(fCaptureUID, param->value.str, 256);
00378 strncpy(fPlaybackUID, param->value.str, 256);
00379 break;
00380
00381 case 'D':
00382 fCapturing = fPlaying = true;
00383 break;
00384
00385 case 'r':
00386 SetAdaptedSampleRate(param->value.ui);
00387 break;
00388
00389 case 'p':
00390 SetAdaptedBufferSize(param->value.ui);
00391 break;
00392
00393 case 'l':
00394 DisplayDeviceNames();
00395 break;
00396
00397 case 'q':
00398 fQuality = param->value.ui;
00399 break;
00400
00401 case 'g':
00402 fRingbufferCurSize = param->value.ui;
00403 fAdaptative = false;
00404 break;
00405
00406 case 's':
00407 fClockDriftCompensate = true;
00408 break;
00409 }
00410 }
00411
00412
00413 if (!fCapturing && !fPlaying) {
00414 fCapturing = true;
00415 fPlaying = true;
00416 }
00417
00418 if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName, fAdaptedSampleRate) < 0) {
00419 throw std::bad_alloc();
00420 }
00421
00422 if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0) {
00423 throw std::bad_alloc();
00424 }
00425
00426 if (SetupBufferSize(fAdaptedBufferSize) < 0) {
00427 throw std::bad_alloc();
00428 }
00429
00430 if (SetupSampleRate(fAdaptedSampleRate) < 0) {
00431 throw std::bad_alloc();
00432 }
00433
00434 if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate) < 0) {
00435 throw std::bad_alloc();
00436 }
00437
00438 if (fCapturing && fCaptureChannels > 0) {
00439 if (SetupBuffers(fCaptureChannels) < 0) {
00440 throw std::bad_alloc();
00441 }
00442 }
00443
00444 if (AddListeners() < 0) {
00445 throw std::bad_alloc();
00446 }
00447
00448 GetStreamLatencies(fDeviceID, true, fInputLatencies);
00449 GetStreamLatencies(fDeviceID, false, fOutputLatencies);
00450 }
00451
00452 OSStatus JackCoreAudioAdapter::GetDefaultDevice(AudioDeviceID* id)
00453 {
00454 OSStatus res;
00455 UInt32 theSize = sizeof(UInt32);
00456 AudioDeviceID inDefault;
00457 AudioDeviceID outDefault;
00458
00459 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) {
00460 return res;
00461 }
00462
00463 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) {
00464 return res;
00465 }
00466
00467 jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);
00468
00469
00470 if (inDefault != outDefault) {
00471 jack_error("Default input and output devices are not the same !!");
00472 return kAudioHardwareBadDeviceError;
00473 } else if (inDefault == 0) {
00474 jack_error("Default input and output devices are null !!");
00475 return kAudioHardwareBadDeviceError;
00476 } else {
00477 *id = inDefault;
00478 return noErr;
00479 }
00480 }
00481
00482 OSStatus JackCoreAudioAdapter::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput)
00483 {
00484 OSStatus err = noErr;
00485 UInt32 outSize;
00486 Boolean outWritable;
00487
00488 channelCount = 0;
00489 err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
00490 if (err == noErr) {
00491 AudioBufferList bufferList[outSize];
00492 err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
00493 if (err == noErr) {
00494 for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++) {
00495 channelCount += bufferList->mBuffers[i].mNumberChannels;
00496 }
00497 }
00498 }
00499
00500 return err;
00501 }
00502
00503 OSStatus JackCoreAudioAdapter::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id)
00504 {
00505 UInt32 size = sizeof(AudioValueTranslation);
00506 CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
00507 AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
00508
00509 if (inIUD == NULL) {
00510 return kAudioHardwareUnspecifiedError;
00511 } else {
00512 OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
00513 CFRelease(inIUD);
00514 jack_log("GetDeviceIDFromUID %s %ld", UID, *id);
00515 return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
00516 }
00517 }
00518
00519 OSStatus JackCoreAudioAdapter::GetDefaultInputDevice(AudioDeviceID* id)
00520 {
00521 OSStatus res;
00522 UInt32 theSize = sizeof(UInt32);
00523 AudioDeviceID inDefault;
00524
00525 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) {
00526 return res;
00527 }
00528
00529 if (inDefault == 0) {
00530 jack_error("Error: default input device is 0, please select a correct one !!");
00531 return -1;
00532 }
00533 jack_log("GetDefaultInputDevice: input = %ld ", inDefault);
00534 *id = inDefault;
00535 return noErr;
00536 }
00537
00538 OSStatus JackCoreAudioAdapter::GetDefaultOutputDevice(AudioDeviceID* id)
00539 {
00540 OSStatus res;
00541 UInt32 theSize = sizeof(UInt32);
00542 AudioDeviceID outDefault;
00543
00544 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) {
00545 return res;
00546 }
00547
00548 if (outDefault == 0) {
00549 jack_error("Error: default output device is 0, please select a correct one !!");
00550 return -1;
00551 }
00552 jack_log("GetDefaultOutputDevice: output = %ld", outDefault);
00553 *id = outDefault;
00554 return noErr;
00555 }
00556
00557 OSStatus JackCoreAudioAdapter::GetDeviceNameFromID(AudioDeviceID id, char* name)
00558 {
00559 UInt32 size = 256;
00560 return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
00561 }
00562
00563 AudioDeviceID JackCoreAudioAdapter::GetDeviceIDFromName(const char* name)
00564 {
00565 UInt32 size;
00566 Boolean isWritable;
00567 int i, deviceNum;
00568
00569 OSStatus err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
00570 if (err != noErr) {
00571 return -1;
00572 }
00573
00574 deviceNum = size / sizeof(AudioDeviceID);
00575 AudioDeviceID devices[deviceNum];
00576
00577 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
00578 if (err != noErr) {
00579 return err;
00580 }
00581
00582 for (i = 0; i < deviceNum; i++) {
00583 char device_name[256];
00584 size = 256;
00585 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
00586 if (err != noErr) {
00587 return -1;
00588 } else if (strcmp(device_name, name) == 0) {
00589 return devices[i];
00590 }
00591 }
00592
00593 return -1;
00594 }
00595
00596
00597 int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
00598 const char* playback_driver_uid,
00599 char* capture_driver_name,
00600 char* playback_driver_name,
00601 jack_nframes_t samplerate)
00602 {
00603 capture_driver_name[0] = 0;
00604 playback_driver_name[0] = 0;
00605
00606
00607 if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
00608 jack_log("JackCoreAudioDriver::Open duplex");
00609
00610
00611 if (strcmp(capture_driver_uid, playback_driver_uid) == 0) {
00612
00613 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
00614 jack_log("Will take default in/out");
00615 if (GetDefaultDevice(&fDeviceID) != noErr) {
00616 jack_error("Cannot open default device");
00617 return -1;
00618 }
00619 }
00620 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
00621 jack_error("Cannot get device name from device ID");
00622 return -1;
00623 }
00624
00625 } else {
00626
00627
00628 AudioDeviceID captureID, playbackID;
00629
00630 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
00631 jack_log("Will take default input");
00632 if (GetDefaultInputDevice(&captureID) != noErr) {
00633 jack_error("Cannot open default input device");
00634 return -1;
00635 }
00636 }
00637
00638 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
00639 jack_log("Will take default output");
00640 if (GetDefaultOutputDevice(&playbackID) != noErr) {
00641 jack_error("Cannot open default output device");
00642 return -1;
00643 }
00644 }
00645
00646 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
00647 return -1;
00648 }
00649 }
00650
00651
00652 } else if (strcmp(capture_driver_uid, "") != 0) {
00653 jack_log("JackCoreAudioAdapter::Open capture only");
00654 if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
00655 if (GetDefaultInputDevice(&fDeviceID) != noErr) {
00656 jack_error("Cannot open default input device");
00657 return -1;
00658 }
00659 }
00660 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) {
00661 jack_error("Cannot get device name from device ID");
00662 return -1;
00663 }
00664
00665
00666 } else if (strcmp(playback_driver_uid, "") != 0) {
00667 jack_log("JackCoreAudioAdapter::Open playback only");
00668 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
00669 if (GetDefaultOutputDevice(&fDeviceID) != noErr) {
00670 jack_error("Cannot open default output device");
00671 return -1;
00672 }
00673 }
00674 if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
00675 jack_error("Cannot get device name from device ID");
00676 return -1;
00677 }
00678
00679
00680 } else {
00681 jack_log("JackCoreAudioAdapter::Open default driver");
00682 if (GetDefaultDevice(&fDeviceID) != noErr) {
00683 jack_error("Cannot open default device in duplex mode, so aggregate default input and default output");
00684
00685
00686 AudioDeviceID captureID = -1, playbackID = -1;
00687
00688 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
00689 jack_log("Will take default input");
00690 if (GetDefaultInputDevice(&captureID) != noErr) {
00691 jack_error("Cannot open default input device");
00692 goto built_in;
00693 }
00694 }
00695
00696 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
00697 jack_log("Will take default output");
00698 if (GetDefaultOutputDevice(&playbackID) != noErr) {
00699 jack_error("Cannot open default output device");
00700 goto built_in;
00701 }
00702 }
00703
00704 if (captureID > 0 && playbackID > 0) {
00705 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
00706 goto built_in;
00707 }
00708 } else {
00709 jack_error("Cannot use default input/output");
00710 goto built_in;
00711 }
00712 }
00713 }
00714
00715 return 0;
00716
00717 built_in:
00718
00719
00720 AudioDeviceID captureID = GetDeviceIDFromName("Built-in Input");
00721 AudioDeviceID playbackID = GetDeviceIDFromName("Built-in Output");
00722
00723 if (captureID > 0 && playbackID > 0) {
00724 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
00725 return -1;
00726 }
00727 } else {
00728 jack_error("Cannot aggregate built-in input and output");
00729 return -1;
00730 }
00731
00732 return 0;
00733 }
00734
00735 int JackCoreAudioAdapter::SetupChannels(bool capturing,
00736 bool playing,
00737 int& inchannels,
00738 int& outchannels,
00739 int& in_nChannels,
00740 int& out_nChannels,
00741 bool strict)
00742 {
00743 OSStatus err = noErr;
00744
00745 if (capturing) {
00746 err = GetTotalChannels(fDeviceID, in_nChannels, true);
00747 if (err != noErr) {
00748 jack_error("Cannot get input channel number");
00749 printError(err);
00750 return -1;
00751 } else {
00752 jack_log("Max input channels : %d", in_nChannels);
00753 }
00754 }
00755
00756 if (playing) {
00757 err = GetTotalChannels(fDeviceID, out_nChannels, false);
00758 if (err != noErr) {
00759 jack_error("Cannot get output channel number");
00760 printError(err);
00761 return -1;
00762 } else {
00763 jack_log("Max output channels : %d", out_nChannels);
00764 }
00765 }
00766
00767 if (inchannels > in_nChannels) {
00768 jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels);
00769 if (strict) {
00770 return -1;
00771 }
00772 }
00773
00774 if (outchannels > out_nChannels) {
00775 jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels);
00776 if (strict) {
00777 return -1;
00778 }
00779 }
00780
00781 if (inchannels == -1) {
00782 jack_log("Setup max in channels = %ld", in_nChannels);
00783 inchannels = in_nChannels;
00784 }
00785
00786 if (outchannels == -1) {
00787 jack_log("Setup max out channels = %ld", out_nChannels);
00788 outchannels = out_nChannels;
00789 }
00790
00791 return 0;
00792 }
00793
00794 int JackCoreAudioAdapter::SetupBufferSize(jack_nframes_t buffer_size)
00795 {
00796
00797 UInt32 outSize = sizeof(UInt32);
00798 OSStatus err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size);
00799 if (err != noErr) {
00800 jack_error("Cannot set buffer size %ld", buffer_size);
00801 printError(err);
00802 return -1;
00803 }
00804
00805 return 0;
00806 }
00807
00808 int JackCoreAudioAdapter::SetupSampleRate(jack_nframes_t samplerate)
00809 {
00810 return SetupSampleRateAux(fDeviceID, samplerate);
00811 }
00812
00813 int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframes_t samplerate)
00814 {
00815 OSStatus err = noErr;
00816 UInt32 outSize;
00817 Float64 sampleRate;
00818
00819
00820 outSize = sizeof(Float64);
00821 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
00822 if (err != noErr) {
00823 jack_error("Cannot get current sample rate");
00824 printError(err);
00825 return -1;
00826 } else {
00827 jack_log("Current sample rate = %f", sampleRate);
00828 }
00829
00830
00831 if (samplerate != (jack_nframes_t)sampleRate) {
00832 sampleRate = (Float64)samplerate;
00833
00834
00835 err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
00836 if (err != noErr) {
00837 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
00838 printError(err);
00839 return -1;
00840 }
00841 err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
00842 if (err != noErr) {
00843 jack_error("Cannot set sample rate = %ld", samplerate);
00844 printError(err);
00845 return -1;
00846 }
00847
00848
00849 int count = 0;
00850 while (!fState && count++ < WAIT_COUNTER) {
00851 usleep(100000);
00852 jack_log("Wait count = %d", count);
00853 }
00854
00855
00856 AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
00857 }
00858
00859 return 0;
00860 }
00861
00862 int JackCoreAudioAdapter::SetupBuffers(int inchannels)
00863 {
00864 jack_log("JackCoreAudioAdapter::SetupBuffers: input = %ld", inchannels);
00865
00866
00867 fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
00868 fInputData->mNumberBuffers = inchannels;
00869 for (int i = 0; i < fCaptureChannels; i++) {
00870 fInputData->mBuffers[i].mNumberChannels = 1;
00871 fInputData->mBuffers[i].mDataByteSize = fAdaptedBufferSize * sizeof(jack_default_audio_sample_t);
00872 fInputData->mBuffers[i].mData = malloc(fAdaptedBufferSize * sizeof(jack_default_audio_sample_t));
00873 }
00874 return 0;
00875 }
00876
00877 void JackCoreAudioAdapter::DisposeBuffers()
00878 {
00879 if (fInputData) {
00880 for (int i = 0; i < fCaptureChannels; i++) {
00881 free(fInputData->mBuffers[i].mData);
00882 }
00883 free(fInputData);
00884 fInputData = 0;
00885 }
00886 }
00887
00888 int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
00889 bool playing,
00890 int inchannels,
00891 int outchannels,
00892 int in_nChannels,
00893 int out_nChannels,
00894 jack_nframes_t buffer_size,
00895 jack_nframes_t samplerate)
00896 {
00897 ComponentResult err1;
00898 UInt32 enableIO;
00899 AudioStreamBasicDescription srcFormat, dstFormat;
00900 AudioDeviceID currAudioDeviceID;
00901 UInt32 size;
00902
00903 jack_log("OpenAUHAL capturing = %d playing = %d inchannels = %d outchannels = %d in_nChannels = %d out_nChannels = %d", capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels);
00904
00905 if (inchannels == 0 && outchannels == 0) {
00906 jack_error("No input and output channels...");
00907 return -1;
00908 }
00909
00910
00911 ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
00912 Component HALOutput = FindNextComponent(NULL, &cd);
00913
00914 err1 = OpenAComponent(HALOutput, &fAUHAL);
00915 if (err1 != noErr) {
00916 jack_error("Error calling OpenAComponent");
00917 printError(err1);
00918 goto error;
00919 }
00920
00921 err1 = AudioUnitInitialize(fAUHAL);
00922 if (err1 != noErr) {
00923 jack_error("Cannot initialize AUHAL unit");
00924 printError(err1);
00925 goto error;
00926 }
00927
00928
00929 if (capturing && inchannels > 0) {
00930 enableIO = 1;
00931 jack_log("Setup AUHAL input on");
00932 } else {
00933 enableIO = 0;
00934 jack_log("Setup AUHAL input off");
00935 }
00936
00937 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
00938 if (err1 != noErr) {
00939 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
00940 printError(err1);
00941 goto error;
00942 }
00943
00944 if (playing && outchannels > 0) {
00945 enableIO = 1;
00946 jack_log("Setup AUHAL output on");
00947 } else {
00948 enableIO = 0;
00949 jack_log("Setup AUHAL output off");
00950 }
00951
00952 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
00953 if (err1 != noErr) {
00954 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
00955 printError(err1);
00956 goto error;
00957 }
00958
00959 size = sizeof(AudioDeviceID);
00960 err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size);
00961 if (err1 != noErr) {
00962 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
00963 printError(err1);
00964 goto error;
00965 } else {
00966 jack_log("AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID);
00967 }
00968
00969
00970 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
00971 if (err1 != noErr) {
00972 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
00973 printError(err1);
00974 goto error;
00975 }
00976
00977
00978 if (capturing && inchannels > 0) {
00979 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32));
00980 if (err1 != noErr) {
00981 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
00982 printError(err1);
00983 goto error;
00984 }
00985 }
00986
00987 if (playing && outchannels > 0) {
00988 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&buffer_size, sizeof(UInt32));
00989 if (err1 != noErr) {
00990 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
00991 printError(err1);
00992 goto error;
00993 }
00994 }
00995
00996
00997 if (capturing && inchannels > 0 && inchannels <= in_nChannels) {
00998 SInt32 chanArr[in_nChannels];
00999 for (int i = 0; i < in_nChannels; i++) {
01000 chanArr[i] = -1;
01001 }
01002 for (int i = 0; i < inchannels; i++) {
01003 chanArr[i] = i;
01004 }
01005 AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
01006 if (err1 != noErr) {
01007 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
01008 printError(err1);
01009 goto error;
01010 }
01011 }
01012
01013 if (playing && outchannels > 0 && outchannels <= out_nChannels) {
01014 SInt32 chanArr[out_nChannels];
01015 for (int i = 0; i < out_nChannels; i++) {
01016 chanArr[i] = -1;
01017 }
01018 for (int i = 0; i < outchannels; i++) {
01019 chanArr[i] = i;
01020 }
01021 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
01022 if (err1 != noErr) {
01023 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
01024 printError(err1);
01025 goto error;
01026 }
01027 }
01028
01029
01030 if (capturing && inchannels > 0) {
01031
01032 size = sizeof(AudioStreamBasicDescription);
01033 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size);
01034 if (err1 != noErr) {
01035 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
01036 printError(err1);
01037 goto error;
01038 }
01039 PrintStreamDesc(&srcFormat);
01040
01041 jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
01042 srcFormat.mSampleRate = samplerate;
01043 srcFormat.mFormatID = kAudioFormatLinearPCM;
01044 srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
01045 srcFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t);
01046 srcFormat.mFramesPerPacket = 1;
01047 srcFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t);
01048 srcFormat.mChannelsPerFrame = inchannels;
01049 srcFormat.mBitsPerChannel = 32;
01050 PrintStreamDesc(&srcFormat);
01051
01052 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
01053
01054 if (err1 != noErr) {
01055 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
01056 printError(err1);
01057 goto error;
01058 }
01059 }
01060
01061 if (playing && outchannels > 0) {
01062
01063 size = sizeof(AudioStreamBasicDescription);
01064 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size);
01065 if (err1 != noErr) {
01066 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
01067 printError(err1);
01068 goto error;
01069 }
01070 PrintStreamDesc(&dstFormat);
01071
01072 jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
01073 dstFormat.mSampleRate = samplerate;
01074 dstFormat.mFormatID = kAudioFormatLinearPCM;
01075 dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
01076 dstFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t);
01077 dstFormat.mFramesPerPacket = 1;
01078 dstFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t);
01079 dstFormat.mChannelsPerFrame = outchannels;
01080 dstFormat.mBitsPerChannel = 32;
01081 PrintStreamDesc(&dstFormat);
01082
01083 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
01084
01085 if (err1 != noErr) {
01086 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
01087 printError(err1);
01088 goto error;
01089 }
01090 }
01091
01092
01093 if (inchannels > 0 && outchannels == 0) {
01094 AURenderCallbackStruct output;
01095 output.inputProc = Render;
01096 output.inputProcRefCon = this;
01097 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
01098 if (err1 != noErr) {
01099 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
01100 printError(err1);
01101 goto error;
01102 }
01103 } else {
01104 AURenderCallbackStruct output;
01105 output.inputProc = Render;
01106 output.inputProcRefCon = this;
01107 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
01108 if (err1 != noErr) {
01109 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
01110 printError(err1);
01111 goto error;
01112 }
01113 }
01114
01115 return 0;
01116
01117 error:
01118 CloseAUHAL();
01119 return -1;
01120 }
01121
01122 OSStatus JackCoreAudioAdapter::DestroyAggregateDevice()
01123 {
01124 OSStatus osErr = noErr;
01125 AudioObjectPropertyAddress pluginAOPA;
01126 pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
01127 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01128 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01129 UInt32 outDataSize;
01130
01131 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
01132 if (osErr != noErr) {
01133 jack_error("JackCoreAudioAdapter::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
01134 printError(osErr);
01135 return osErr;
01136 }
01137
01138 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
01139 if (osErr != noErr) {
01140 jack_error("JackCoreAudioAdapter::DestroyAggregateDevice : AudioObjectGetPropertyData error");
01141 printError(osErr);
01142 return osErr;
01143 }
01144
01145 return noErr;
01146 }
01147
01148 static CFStringRef GetDeviceName(AudioDeviceID id)
01149 {
01150 UInt32 size = sizeof(CFStringRef);
01151 CFStringRef UIname;
01152 OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
01153 return (err == noErr) ? UIname : NULL;
01154 }
01155
01156 OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
01157 {
01158 OSStatus err = noErr;
01159 AudioObjectID sub_device[32];
01160 UInt32 outSize = sizeof(sub_device);
01161
01162 err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
01163 vector<AudioDeviceID> captureDeviceIDArray;
01164
01165 if (err != noErr) {
01166 jack_log("Input device does not have subdevices");
01167 captureDeviceIDArray.push_back(captureDeviceID);
01168 } else {
01169 int num_devices = outSize / sizeof(AudioObjectID);
01170 jack_log("Input device has %d subdevices", num_devices);
01171 for (int i = 0; i < num_devices; i++) {
01172 captureDeviceIDArray.push_back(sub_device[i]);
01173 }
01174 }
01175
01176 err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
01177 vector<AudioDeviceID> playbackDeviceIDArray;
01178
01179 if (err != noErr) {
01180 jack_log("Output device does not have subdevices");
01181 playbackDeviceIDArray.push_back(playbackDeviceID);
01182 } else {
01183 int num_devices = outSize / sizeof(AudioObjectID);
01184 jack_log("Output device has %d subdevices", num_devices);
01185 for (int i = 0; i < num_devices; i++) {
01186 playbackDeviceIDArray.push_back(sub_device[i]);
01187 }
01188 }
01189
01190 return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice);
01191 }
01192
01193 OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
01194 {
01195 OSStatus osErr = noErr;
01196 UInt32 outSize;
01197 Boolean outWritable;
01198
01199
01200
01201 AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
01202 AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
01203 UInt32 theQualifierDataSize = sizeof(AudioObjectID);
01204 AudioClassID inClass = kAudioSubDeviceClassID;
01205 void* theQualifierData = &inClass;
01206 UInt32 subDevicesNum = 0;
01207
01208
01209
01210
01211 UInt32 keptclockdomain = 0;
01212 UInt32 clockdomain = 0;
01213 outSize = sizeof(UInt32);
01214 bool need_clock_drift_compensation = false;
01215
01216 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01217 if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) {
01218 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : cannot set SR of input device");
01219 } else {
01220
01221 osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
01222 if (osErr != 0) {
01223 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
01224 printError(osErr);
01225 } else {
01226 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
01227 jack_log("JackCoreAudioAdapter::CreateAggregateDevice : input clockdomain = %d", clockdomain);
01228 if (clockdomain != 0 && clockdomain != keptclockdomain) {
01229 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
01230 need_clock_drift_compensation = true;
01231 }
01232 }
01233 }
01234 }
01235
01236 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01237 if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) {
01238 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : cannot set SR of output device");
01239 } else {
01240
01241 osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
01242 if (osErr != 0) {
01243 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
01244 printError(osErr);
01245 } else {
01246 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
01247 jack_log("JackCoreAudioAdapter::CreateAggregateDevice : output clockdomain = %d", clockdomain);
01248 if (clockdomain != 0 && clockdomain != keptclockdomain) {
01249 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
01250 need_clock_drift_compensation = true;
01251 }
01252 }
01253 }
01254 }
01255
01256
01257 if (keptclockdomain == 0) {
01258 need_clock_drift_compensation = true;
01259 }
01260
01261
01262
01263
01264
01265 char device_name[256];
01266 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01267 GetDeviceNameFromID(captureDeviceID[i], device_name);
01268 jack_info("Separated input = '%s' ", device_name);
01269 }
01270
01271 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01272 GetDeviceNameFromID(playbackDeviceID[i], device_name);
01273 jack_info("Separated output = '%s' ", device_name);
01274 }
01275
01276 osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
01277 if (osErr != noErr) {
01278 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
01279 printError(osErr);
01280 return osErr;
01281 }
01282
01283 AudioValueTranslation pluginAVT;
01284
01285 CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
01286
01287 pluginAVT.mInputData = &inBundleRef;
01288 pluginAVT.mInputDataSize = sizeof(inBundleRef);
01289 pluginAVT.mOutputData = &fPluginID;
01290 pluginAVT.mOutputDataSize = sizeof(fPluginID);
01291
01292 osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
01293 if (osErr != noErr) {
01294 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
01295 printError(osErr);
01296 return osErr;
01297 }
01298
01299
01300
01301
01302
01303 CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
01304
01305 CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
01306 CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
01307
01308
01309 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
01310
01311
01312 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
01313
01314
01315 int value = 1;
01316 CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
01317
01318 SInt32 system;
01319 Gestalt(gestaltSystemVersion, &system);
01320
01321 jack_log("JackCoreAudioAdapter::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054);
01322
01323
01324 if (system < 0x00001054) {
01325 jack_log("JackCoreAudioAdapter::CreateAggregateDevice : public aggregate device....");
01326 } else {
01327 jack_log("JackCoreAudioAdapter::CreateAggregateDevice : private aggregate device....");
01328 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
01329 }
01330
01331
01332 CFMutableArrayRef subDevicesArrayClock = NULL;
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375 CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
01376
01377 vector<CFStringRef> captureDeviceUID;
01378 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01379 CFStringRef ref = GetDeviceName(captureDeviceID[i]);
01380 if (ref == NULL) {
01381 return -1;
01382 }
01383 captureDeviceUID.push_back(ref);
01384
01385 CFArrayAppendValue(subDevicesArray, ref);
01386 }
01387
01388 vector<CFStringRef> playbackDeviceUID;
01389 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01390 CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
01391 if (ref == NULL) {
01392 return -1;
01393 }
01394 playbackDeviceUID.push_back(ref);
01395
01396 CFArrayAppendValue(subDevicesArray, ref);
01397 }
01398
01399
01400
01401
01402
01403 AudioObjectPropertyAddress pluginAOPA;
01404 pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
01405 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01406 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01407 UInt32 outDataSize;
01408
01409 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
01410 if (osErr != noErr) {
01411 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectGetPropertyDataSize error");
01412 printError(osErr);
01413 goto error;
01414 }
01415
01416 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
01417 if (osErr != noErr) {
01418 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectGetPropertyData error");
01419 printError(osErr);
01420 goto error;
01421 }
01422
01423
01424
01425 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01426
01427
01428
01429
01430
01431 pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
01432 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01433 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01434 outDataSize = sizeof(CFMutableArrayRef);
01435 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
01436 if (osErr != noErr) {
01437 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error");
01438 printError(osErr);
01439 goto error;
01440 }
01441
01442
01443 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01444
01445
01446
01447
01448
01449
01450
01451 pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
01452 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01453 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01454 outDataSize = sizeof(CFStringRef);
01455 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]);
01456 if (osErr != noErr) {
01457 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectSetPropertyData for master device error");
01458 printError(osErr);
01459 goto error;
01460 }
01461
01462
01463 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01464
01465
01466
01467
01468 if (fClockDriftCompensate) {
01469 if (need_clock_drift_compensation) {
01470 jack_info("Clock drift compensation activated...");
01471
01472
01473 osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
01474 if (osErr != noErr) {
01475 jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
01476 printError(osErr);
01477 }
01478
01479
01480 subDevicesNum = outSize / sizeof(AudioObjectID);
01481 jack_info("JackCoreAudioAdapter::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum);
01482 AudioObjectID subDevices[subDevicesNum];
01483 outSize = sizeof(subDevices);
01484
01485 osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
01486 if (osErr != noErr) {
01487 jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
01488 printError(osErr);
01489 }
01490
01491
01492 for (UInt32 index = 0; index < subDevicesNum; ++index) {
01493 UInt32 theDriftCompensationValue = 1;
01494 osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue);
01495 if (osErr != noErr) {
01496 jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error");
01497 printError(osErr);
01498 }
01499 }
01500 } else {
01501 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
01502 }
01503 }
01504
01505
01506 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01507
01508
01509
01510
01511
01512
01513 CFRelease(AggregateDeviceNumberRef);
01514
01515
01516 CFRelease(aggDeviceDict);
01517 CFRelease(subDevicesArray);
01518
01519 if (subDevicesArrayClock) {
01520 CFRelease(subDevicesArrayClock);
01521 }
01522
01523
01524 for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
01525 CFRelease(captureDeviceUID[i]);
01526 }
01527
01528 for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
01529 CFRelease(playbackDeviceUID[i]);
01530 }
01531
01532 jack_log("New aggregate device %ld", *outAggregateDevice);
01533 return noErr;
01534
01535 error:
01536 DestroyAggregateDevice();
01537 return -1;
01538 }
01539
01540
01541 bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device)
01542 {
01543 OSStatus err = noErr;
01544 AudioObjectID sub_device[32];
01545 UInt32 outSize = sizeof(sub_device);
01546 err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
01547
01548 if (err != noErr) {
01549 jack_log("Device does not have subdevices");
01550 return false;
01551 } else {
01552 int num_devices = outSize / sizeof(AudioObjectID);
01553 jack_log("Device does has %d subdevices", num_devices);
01554 return true;
01555 }
01556 }
01557
01558 void JackCoreAudioAdapter::CloseAUHAL()
01559 {
01560 AudioUnitUninitialize(fAUHAL);
01561 CloseComponent(fAUHAL);
01562 }
01563
01564 int JackCoreAudioAdapter::Open()
01565 {
01566 return (AudioOutputUnitStart(fAUHAL) != noErr) ? -1 : 0;
01567 }
01568
01569 int JackCoreAudioAdapter::Close()
01570 {
01571 #ifdef JACK_MONITOR
01572 fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
01573 #endif
01574 AudioOutputUnitStop(fAUHAL);
01575 DisposeBuffers();
01576 CloseAUHAL();
01577 RemoveListeners();
01578 if (fPluginID > 0) {
01579 DestroyAggregateDevice();
01580 }
01581 return 0;
01582 }
01583
01584 int JackCoreAudioAdapter::SetSampleRate(jack_nframes_t sample_rate)
01585 {
01586 JackAudioAdapterInterface::SetHostSampleRate(sample_rate);
01587 Close();
01588 return Open();
01589 }
01590
01591 int JackCoreAudioAdapter::SetBufferSize(jack_nframes_t buffer_size)
01592 {
01593 JackAudioAdapterInterface::SetHostBufferSize(buffer_size);
01594 Close();
01595 return Open();
01596 }
01597
01598 OSStatus JackCoreAudioAdapter::GetStreamLatencies(AudioDeviceID device, bool isInput, vector<int>& latencies)
01599 {
01600 OSStatus err = noErr;
01601 UInt32 outSize1, outSize2, outSize3;
01602 Boolean outWritable;
01603
01604 err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, &outWritable);
01605 if (err == noErr) {
01606 int stream_count = outSize1 / sizeof(UInt32);
01607 AudioStreamID streamIDs[stream_count];
01608 AudioBufferList bufferList[stream_count];
01609 UInt32 streamLatency;
01610 outSize2 = sizeof(UInt32);
01611
01612 err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, streamIDs);
01613 if (err != noErr) {
01614 jack_error("GetStreamLatencies kAudioDevicePropertyStreams err = %d", err);
01615 return err;
01616 }
01617
01618 err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, &outWritable);
01619 if (err != noErr) {
01620 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err);
01621 return err;
01622 }
01623
01624 for (int i = 0; i < stream_count; i++) {
01625 err = AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &outSize2, &streamLatency);
01626 if (err != noErr) {
01627 jack_error("GetStreamLatencies kAudioStreamPropertyLatency err = %d", err);
01628 return err;
01629 }
01630 err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, bufferList);
01631 if (err != noErr) {
01632 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err);
01633 return err;
01634 }
01635
01636 for (uint k = 0; k < bufferList->mBuffers[i].mNumberChannels; k++) {
01637 latencies.push_back(streamLatency);
01638 }
01639 }
01640 }
01641 return err;
01642 }
01643
01644 int JackCoreAudioAdapter::GetLatency(int port_index, bool input)
01645 {
01646 UInt32 size = sizeof(UInt32);
01647 UInt32 value1 = 0;
01648 UInt32 value2 = 0;
01649
01650 OSStatus err = AudioDeviceGetProperty(fDeviceID, 0, input, kAudioDevicePropertyLatency, &size, &value1);
01651 if (err != noErr) {
01652 jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
01653 }
01654 err = AudioDeviceGetProperty(fDeviceID, 0, input, kAudioDevicePropertySafetyOffset, &size, &value2);
01655 if (err != noErr) {
01656 jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
01657 }
01658
01659
01660
01661 return value1 + value2 + fAdaptedBufferSize;
01662 }
01663
01664 int JackCoreAudioAdapter::GetInputLatency(int port_index)
01665 {
01666 if (port_index < int(fInputLatencies.size())) {
01667 return GetLatency(port_index, true) + fInputLatencies[port_index];
01668 } else {
01669
01670 return GetLatency(port_index, true);
01671 }
01672 }
01673
01674 int JackCoreAudioAdapter::GetOutputLatency(int port_index)
01675 {
01676 if (port_index < int(fOutputLatencies.size())) {
01677 return GetLatency(port_index, false) + fOutputLatencies[port_index];
01678 } else {
01679
01680 return GetLatency(port_index, false);
01681 }
01682 }
01683
01684 }
01685
01686 #ifdef __cplusplus
01687 extern "C"
01688 {
01689 #endif
01690
01691 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
01692 {
01693 jack_driver_desc_t * desc;
01694 jack_driver_desc_filler_t filler;
01695 jack_driver_param_value_t value;
01696
01697 desc = jack_driver_descriptor_construct("audioadapter", JackDriverNone, "netjack audio <==> net backend adapter", &filler);
01698
01699 value.i = -1;
01700 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");
01701 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");
01702 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");
01703
01704 value.str[0] = 0;
01705 jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Input CoreAudio device name", NULL);
01706 jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Output CoreAudio device name", NULL);
01707
01708 value.ui = 44100U;
01709 jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
01710
01711 value.ui = 512U;
01712 jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
01713
01714 value.i = TRUE;
01715 jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL);
01716
01717 value.str[0] = 0;
01718 jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "CoreAudio device name", NULL);
01719
01720 value.i = TRUE;
01721 jack_driver_descriptor_add_parameter(desc, &filler, "list-devices", 'l', JackDriverParamBool, &value, NULL, "Display available CoreAudio devices", NULL);
01722
01723 value.ui = 0;
01724 jack_driver_descriptor_add_parameter(desc, &filler, "quality", 'q', JackDriverParamInt, &value, NULL, "Resample algorithm quality (0 - 4)", NULL);
01725
01726 value.ui = 32768;
01727 jack_driver_descriptor_add_parameter(desc, &filler, "ring-buffer", 'g', JackDriverParamInt, &value, NULL, "Fixed ringbuffer size", "Fixed ringbuffer size (if not set => automatic adaptative)");
01728
01729 value.i = FALSE;
01730 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");
01731
01732 return desc;
01733 }
01734
01735
01736 #ifdef __cplusplus
01737 }
01738 #endif
01739