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