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