Jack2 1.9.6
|
00001 /* 00002 Copyright (C) 2008 Grame 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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 // A better implementation would try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code) 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 // Add listeners 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 // Default values 00307 fCaptureChannels = -1; 00308 fPlaybackChannels = -1; 00309 00310 SInt32 major; 00311 SInt32 minor; 00312 Gestalt(gestaltSystemVersionMajor, &major); 00313 Gestalt(gestaltSystemVersionMinor, &minor); 00314 00315 // Starting with 10.6 systems, the HAL notification thread is created internally 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 /* duplex is the default */ 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 // Get the device only if default input and output are the same 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 // Setup 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 // Duplex 00527 if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { 00528 00529 // Same device for capture and playback... 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 // Creates aggregate device 00547 AudioDeviceID captureID, playbackID; 00548 00549 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { 00550 jack_log("Will take default input"); 00551 if (GetDefaultInputDevice(&captureID) != noErr) { 00552 jack_error("Cannot open default input device"); 00553 return -1; 00554 } 00555 } 00556 00557 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { 00558 jack_log("Will take default output"); 00559 if (GetDefaultOutputDevice(&playbackID) != noErr) { 00560 jack_error("Cannot open default output device"); 00561 return -1; 00562 } 00563 } 00564 00565 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) 00566 return -1; 00567 } 00568 00569 // Capture only 00570 } else if (strcmp(capture_driver_uid, "") != 0) { 00571 jack_log("JackCoreAudioAdapter::Open capture only"); 00572 if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) { 00573 if (GetDefaultInputDevice(&fDeviceID) != noErr) { 00574 jack_error("Cannot open default input device"); 00575 return -1; 00576 } 00577 } 00578 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) { 00579 jack_error("Cannot get device name from device ID"); 00580 return -1; 00581 } 00582 00583 // Playback only 00584 } else if (strcmp(playback_driver_uid, "") != 0) { 00585 jack_log("JackCoreAudioAdapter::Open playback only"); 00586 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { 00587 if (GetDefaultOutputDevice(&fDeviceID) != noErr) { 00588 jack_error("Cannot open default output device"); 00589 return -1; 00590 } 00591 } 00592 if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) { 00593 jack_error("Cannot get device name from device ID"); 00594 return -1; 00595 } 00596 00597 // Use default driver in duplex mode 00598 } else { 00599 jack_log("JackCoreAudioDriver::Open default driver"); 00600 if (GetDefaultDevice(&fDeviceID) != noErr) { 00601 jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); 00602 00603 // Creates aggregate device 00604 AudioDeviceID captureID, playbackID; 00605 00606 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { 00607 jack_log("Will take default input"); 00608 if (GetDefaultInputDevice(&captureID) != noErr) { 00609 jack_error("Cannot open default input device"); 00610 return -1; 00611 } 00612 } 00613 00614 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { 00615 jack_log("Will take default output"); 00616 if (GetDefaultOutputDevice(&playbackID) != noErr) { 00617 jack_error("Cannot open default output device"); 00618 return -1; 00619 } 00620 } 00621 00622 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) 00623 return -1; 00624 } 00625 } 00626 00627 return 0; 00628 } 00629 00630 int JackCoreAudioAdapter::SetupChannels(bool capturing, 00631 bool playing, 00632 int& inchannels, 00633 int& outchannels, 00634 int& in_nChannels, 00635 int& out_nChannels, 00636 bool strict) 00637 { 00638 OSStatus err = noErr; 00639 00640 if (capturing) { 00641 err = GetTotalChannels(fDeviceID, in_nChannels, true); 00642 if (err != noErr) { 00643 jack_error("Cannot get input channel number"); 00644 printError(err); 00645 return -1; 00646 } else { 00647 jack_log("Max input channels : %d", in_nChannels); 00648 } 00649 } 00650 00651 if (playing) { 00652 err = GetTotalChannels(fDeviceID, out_nChannels, false); 00653 if (err != noErr) { 00654 jack_error("Cannot get output channel number"); 00655 printError(err); 00656 return -1; 00657 } else { 00658 jack_log("Max output channels : %d", out_nChannels); 00659 } 00660 } 00661 00662 if (inchannels > in_nChannels) { 00663 jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels); 00664 if (strict) 00665 return -1; 00666 } 00667 00668 if (outchannels > out_nChannels) { 00669 jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels); 00670 if (strict) 00671 return -1; 00672 } 00673 00674 if (inchannels == -1) { 00675 jack_log("Setup max in channels = %ld", in_nChannels); 00676 inchannels = in_nChannels; 00677 } 00678 00679 if (outchannels == -1) { 00680 jack_log("Setup max out channels = %ld", out_nChannels); 00681 outchannels = out_nChannels; 00682 } 00683 00684 return 0; 00685 } 00686 00687 int JackCoreAudioAdapter::SetupBufferSize(jack_nframes_t buffer_size) 00688 { 00689 // Setting buffer size 00690 UInt32 outSize = sizeof(UInt32); 00691 OSStatus err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size); 00692 if (err != noErr) { 00693 jack_error("Cannot set buffer size %ld", buffer_size); 00694 printError(err); 00695 return -1; 00696 } 00697 00698 return 0; 00699 } 00700 00701 int JackCoreAudioAdapter::SetupSampleRate(jack_nframes_t samplerate) 00702 { 00703 return SetupSampleRateAux(fDeviceID, samplerate); 00704 } 00705 00706 int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframes_t samplerate) 00707 { 00708 OSStatus err = noErr; 00709 UInt32 outSize; 00710 Float64 sampleRate; 00711 00712 // Get sample rate 00713 outSize = sizeof(Float64); 00714 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); 00715 if (err != noErr) { 00716 jack_error("Cannot get current sample rate"); 00717 printError(err); 00718 return -1; 00719 } 00720 00721 // If needed, set new sample rate 00722 if (samplerate != (jack_nframes_t)sampleRate) { 00723 sampleRate = (Float64)samplerate; 00724 00725 // To get SR change notification 00726 err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this); 00727 if (err != noErr) { 00728 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate"); 00729 printError(err); 00730 return -1; 00731 } 00732 err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate); 00733 if (err != noErr) { 00734 jack_error("Cannot set sample rate = %ld", samplerate); 00735 printError(err); 00736 return -1; 00737 } 00738 00739 // Waiting for SR change notification 00740 int count = 0; 00741 while (!fState && count++ < WAIT_COUNTER) { 00742 usleep(100000); 00743 jack_log("Wait count = %d", count); 00744 } 00745 00746 // Remove SR change notification 00747 AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); 00748 } 00749 00750 return 0; 00751 } 00752 00753 int JackCoreAudioAdapter::SetupBuffers(int inchannels) 00754 { 00755 jack_log("JackCoreAudioAdapter::SetupBuffers: input = %ld", inchannels); 00756 00757 // Prepare buffers 00758 fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer)); 00759 fInputData->mNumberBuffers = inchannels; 00760 for (int i = 0; i < fCaptureChannels; i++) { 00761 fInputData->mBuffers[i].mNumberChannels = 1; 00762 fInputData->mBuffers[i].mDataByteSize = fAdaptedBufferSize * sizeof(float); 00763 fInputData->mBuffers[i].mData = malloc(fAdaptedBufferSize * sizeof(float)); 00764 } 00765 return 0; 00766 } 00767 00768 void JackCoreAudioAdapter::DisposeBuffers() 00769 { 00770 if (fInputData) { 00771 for (int i = 0; i < fCaptureChannels; i++) 00772 free(fInputData->mBuffers[i].mData); 00773 free(fInputData); 00774 fInputData = 0; 00775 } 00776 } 00777 00778 int JackCoreAudioAdapter::OpenAUHAL(bool capturing, 00779 bool playing, 00780 int inchannels, 00781 int outchannels, 00782 int in_nChannels, 00783 int out_nChannels, 00784 jack_nframes_t buffer_size, 00785 jack_nframes_t samplerate) 00786 { 00787 ComponentResult err1; 00788 UInt32 enableIO; 00789 AudioStreamBasicDescription srcFormat, dstFormat; 00790 AudioDeviceID currAudioDeviceID; 00791 UInt32 size; 00792 00793 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); 00794 00795 if (inchannels == 0 && outchannels == 0) { 00796 jack_error("No input and output channels..."); 00797 return -1; 00798 } 00799 00800 // AUHAL 00801 ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; 00802 Component HALOutput = FindNextComponent(NULL, &cd); 00803 00804 err1 = OpenAComponent(HALOutput, &fAUHAL); 00805 if (err1 != noErr) { 00806 jack_error("Error calling OpenAComponent"); 00807 printError(err1); 00808 goto error; 00809 } 00810 00811 err1 = AudioUnitInitialize(fAUHAL); 00812 if (err1 != noErr) { 00813 jack_error("Cannot initialize AUHAL unit"); 00814 printError(err1); 00815 goto error; 00816 } 00817 00818 // Start I/O 00819 if (capturing && inchannels > 0) { 00820 enableIO = 1; 00821 jack_log("Setup AUHAL input on"); 00822 } else { 00823 enableIO = 0; 00824 jack_log("Setup AUHAL input off"); 00825 } 00826 00827 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); 00828 if (err1 != noErr) { 00829 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); 00830 printError(err1); 00831 goto error; 00832 } 00833 00834 if (playing && outchannels > 0) { 00835 enableIO = 1; 00836 jack_log("Setup AUHAL output on"); 00837 } else { 00838 enableIO = 0; 00839 jack_log("Setup AUHAL output off"); 00840 } 00841 00842 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); 00843 if (err1 != noErr) { 00844 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); 00845 printError(err1); 00846 goto error; 00847 } 00848 00849 size = sizeof(AudioDeviceID); 00850 err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size); 00851 if (err1 != noErr) { 00852 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice"); 00853 printError(err1); 00854 goto error; 00855 } else { 00856 jack_log("AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID); 00857 } 00858 00859 // Setup up choosen device, in both input and output cases 00860 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID)); 00861 if (err1 != noErr) { 00862 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice"); 00863 printError(err1); 00864 goto error; 00865 } 00866 00867 // Set buffer size 00868 if (capturing && inchannels > 0) { 00869 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32)); 00870 if (err1 != noErr) { 00871 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); 00872 printError(err1); 00873 goto error; 00874 } 00875 } 00876 00877 if (playing && outchannels > 0) { 00878 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&buffer_size, sizeof(UInt32)); 00879 if (err1 != noErr) { 00880 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); 00881 printError(err1); 00882 goto error; 00883 } 00884 } 00885 00886 // Setup channel map 00887 if (capturing && inchannels > 0 && inchannels < in_nChannels) { 00888 SInt32 chanArr[in_nChannels]; 00889 for (int i = 0; i < in_nChannels; i++) { 00890 chanArr[i] = -1; 00891 } 00892 for (int i = 0; i < inchannels; i++) { 00893 chanArr[i] = i; 00894 } 00895 AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels); 00896 if (err1 != noErr) { 00897 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1"); 00898 printError(err1); 00899 goto error; 00900 } 00901 } 00902 00903 if (playing && outchannels > 0 && outchannels < out_nChannels) { 00904 SInt32 chanArr[out_nChannels]; 00905 for (int i = 0; i < out_nChannels; i++) { 00906 chanArr[i] = -1; 00907 } 00908 for (int i = 0; i < outchannels; i++) { 00909 chanArr[i] = i; 00910 } 00911 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels); 00912 if (err1 != noErr) { 00913 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0"); 00914 printError(err1); 00915 goto error; 00916 } 00917 } 00918 00919 // Setup stream converters 00920 if (capturing && inchannels > 0) { 00921 00922 size = sizeof(AudioStreamBasicDescription); 00923 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size); 00924 if (err1 != noErr) { 00925 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); 00926 printError(err1); 00927 goto error; 00928 } 00929 PrintStreamDesc(&srcFormat); 00930 00931 jack_log("Setup AUHAL input stream converter SR = %ld", samplerate); 00932 srcFormat.mSampleRate = samplerate; 00933 srcFormat.mFormatID = kAudioFormatLinearPCM; 00934 srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; 00935 srcFormat.mBytesPerPacket = sizeof(float); 00936 srcFormat.mFramesPerPacket = 1; 00937 srcFormat.mBytesPerFrame = sizeof(float); 00938 srcFormat.mChannelsPerFrame = inchannels; 00939 srcFormat.mBitsPerChannel = 32; 00940 PrintStreamDesc(&srcFormat); 00941 00942 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription)); 00943 00944 if (err1 != noErr) { 00945 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); 00946 printError(err1); 00947 goto error; 00948 } 00949 } 00950 00951 if (playing && outchannels > 0) { 00952 00953 size = sizeof(AudioStreamBasicDescription); 00954 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size); 00955 if (err1 != noErr) { 00956 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); 00957 printError(err1); 00958 goto error; 00959 } 00960 PrintStreamDesc(&dstFormat); 00961 00962 jack_log("Setup AUHAL output stream converter SR = %ld", samplerate); 00963 dstFormat.mSampleRate = samplerate; 00964 dstFormat.mFormatID = kAudioFormatLinearPCM; 00965 dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; 00966 dstFormat.mBytesPerPacket = sizeof(float); 00967 dstFormat.mFramesPerPacket = 1; 00968 dstFormat.mBytesPerFrame = sizeof(float); 00969 dstFormat.mChannelsPerFrame = outchannels; 00970 dstFormat.mBitsPerChannel = 32; 00971 PrintStreamDesc(&dstFormat); 00972 00973 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription)); 00974 00975 if (err1 != noErr) { 00976 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); 00977 printError(err1); 00978 goto error; 00979 } 00980 } 00981 00982 // Setup callbacks 00983 if (inchannels > 0 && outchannels == 0) { 00984 AURenderCallbackStruct output; 00985 output.inputProc = Render; 00986 output.inputProcRefCon = this; 00987 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output)); 00988 if (err1 != noErr) { 00989 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1"); 00990 printError(err1); 00991 goto error; 00992 } 00993 } else { 00994 AURenderCallbackStruct output; 00995 output.inputProc = Render; 00996 output.inputProcRefCon = this; 00997 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output)); 00998 if (err1 != noErr) { 00999 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0"); 01000 printError(err1); 01001 goto error; 01002 } 01003 } 01004 01005 return 0; 01006 01007 error: 01008 CloseAUHAL(); 01009 return -1; 01010 } 01011 01012 OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() 01013 { 01014 OSStatus osErr = noErr; 01015 AudioObjectPropertyAddress pluginAOPA; 01016 pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice; 01017 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; 01018 pluginAOPA.mElement = kAudioObjectPropertyElementMaster; 01019 UInt32 outDataSize; 01020 01021 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); 01022 if (osErr != noErr) { 01023 jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); 01024 printError(osErr); 01025 return osErr; 01026 } 01027 01028 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); 01029 if (osErr != noErr) { 01030 jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); 01031 printError(osErr); 01032 return osErr; 01033 } 01034 01035 return noErr; 01036 } 01037 01038 static CFStringRef GetDeviceName(AudioDeviceID id) 01039 { 01040 UInt32 size = sizeof(CFStringRef); 01041 CFStringRef UIname; 01042 OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname); 01043 return (err == noErr) ? UIname : NULL; 01044 } 01045 01046 OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) 01047 { 01048 OSStatus err = noErr; 01049 AudioObjectID sub_device[32]; 01050 UInt32 outSize = sizeof(sub_device); 01051 01052 err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); 01053 vector<AudioDeviceID> captureDeviceIDArray; 01054 01055 if (err != noErr) { 01056 jack_log("Input device does not have subdevices"); 01057 captureDeviceIDArray.push_back(captureDeviceID); 01058 } else { 01059 int num_devices = outSize / sizeof(AudioObjectID); 01060 jack_log("Input device has %d subdevices", num_devices); 01061 for (int i = 0; i < num_devices; i++) { 01062 captureDeviceIDArray.push_back(sub_device[i]); 01063 } 01064 } 01065 01066 err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); 01067 vector<AudioDeviceID> playbackDeviceIDArray; 01068 01069 if (err != noErr) { 01070 jack_log("Output device does not have subdevices"); 01071 playbackDeviceIDArray.push_back(playbackDeviceID); 01072 } else { 01073 int num_devices = outSize / sizeof(AudioObjectID); 01074 jack_log("Output device has %d subdevices", num_devices); 01075 for (int i = 0; i < num_devices; i++) { 01076 playbackDeviceIDArray.push_back(sub_device[i]); 01077 } 01078 } 01079 01080 return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice); 01081 } 01082 01083 OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) 01084 { 01085 OSStatus osErr = noErr; 01086 UInt32 outSize; 01087 Boolean outWritable; 01088 01089 // Prepare sub-devices for clock drift compensation 01090 // Workaround for bug in the HAL : until 10.6.2 01091 AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; 01092 AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; 01093 UInt32 theQualifierDataSize = sizeof(AudioObjectID); 01094 AudioClassID inClass = kAudioSubDeviceClassID; 01095 void* theQualifierData = &inClass; 01096 UInt32 subDevicesNum = 0; 01097 01098 //--------------------------------------------------------------------------- 01099 // Setup SR of both devices otherwise creating AD may fail... 01100 //--------------------------------------------------------------------------- 01101 UInt32 keptclockdomain = 0; 01102 UInt32 clockdomain = 0; 01103 outSize = sizeof(UInt32); 01104 bool need_clock_drift_compensation = false; 01105 01106 for (UInt32 i = 0; i < captureDeviceID.size(); i++) { 01107 if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { 01108 jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); 01109 } else { 01110 // Check clock domain 01111 osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); 01112 if (osErr != 0) { 01113 jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); 01114 printError(osErr); 01115 } else { 01116 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; 01117 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); 01118 if (clockdomain != 0 && clockdomain != keptclockdomain) { 01119 jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); 01120 need_clock_drift_compensation = true; 01121 } 01122 } 01123 } 01124 } 01125 01126 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { 01127 if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { 01128 jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); 01129 } else { 01130 // Check clock domain 01131 osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); 01132 if (osErr != 0) { 01133 jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); 01134 printError(osErr); 01135 } else { 01136 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; 01137 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); 01138 if (clockdomain != 0 && clockdomain != keptclockdomain) { 01139 jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); 01140 need_clock_drift_compensation = true; 01141 } 01142 } 01143 } 01144 } 01145 01146 // If no valid clock domain was found, then assume we have to compensate... 01147 if (keptclockdomain == 0) { 01148 need_clock_drift_compensation = true; 01149 } 01150 01151 //--------------------------------------------------------------------------- 01152 // Start to create a new aggregate by getting the base audio hardware plugin 01153 //--------------------------------------------------------------------------- 01154 01155 char device_name[256]; 01156 for (UInt32 i = 0; i < captureDeviceID.size(); i++) { 01157 GetDeviceNameFromID(captureDeviceID[i], device_name); 01158 jack_info("Separated input = '%s' ", device_name); 01159 } 01160 01161 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { 01162 GetDeviceNameFromID(playbackDeviceID[i], device_name); 01163 jack_info("Separated output = '%s' ", device_name); 01164 } 01165 01166 osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); 01167 if (osErr != noErr) { 01168 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); 01169 printError(osErr); 01170 return osErr; 01171 } 01172 01173 AudioValueTranslation pluginAVT; 01174 01175 CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio"); 01176 01177 pluginAVT.mInputData = &inBundleRef; 01178 pluginAVT.mInputDataSize = sizeof(inBundleRef); 01179 pluginAVT.mOutputData = &fPluginID; 01180 pluginAVT.mOutputDataSize = sizeof(fPluginID); 01181 01182 osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); 01183 if (osErr != noErr) { 01184 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); 01185 printError(osErr); 01186 return osErr; 01187 } 01188 01189 //------------------------------------------------- 01190 // Create a CFDictionary for our aggregate device 01191 //------------------------------------------------- 01192 01193 CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 01194 01195 CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex"); 01196 CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex"); 01197 01198 // add the name of the device to the dictionary 01199 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef); 01200 01201 // add our choice of UID for the aggregate device to the dictionary 01202 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); 01203 01204 // add a "private aggregate key" to the dictionary 01205 int value = 1; 01206 CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); 01207 01208 SInt32 system; 01209 Gestalt(gestaltSystemVersion, &system); 01210 01211 jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); 01212 01213 // Starting with 10.5.4 systems, the AD can be internal... (better) 01214 if (system < 0x00001054) { 01215 jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); 01216 } else { 01217 jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); 01218 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); 01219 } 01220 01221 // Prepare sub-devices for clock drift compensation 01222 CFMutableArrayRef subDevicesArrayClock = NULL; 01223 01224 /* 01225 if (fClockDriftCompensate) { 01226 if (need_clock_drift_compensation) { 01227 jack_info("Clock drift compensation activated..."); 01228 subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 01229 01230 for (UInt32 i = 0; i < captureDeviceID.size(); i++) { 01231 CFStringRef UID = GetDeviceName(captureDeviceID[i]); 01232 if (UID) { 01233 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 01234 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID); 01235 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef); 01236 //CFRelease(UID); 01237 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); 01238 } 01239 } 01240 01241 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { 01242 CFStringRef UID = GetDeviceName(playbackDeviceID[i]); 01243 if (UID) { 01244 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 01245 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID); 01246 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef); 01247 //CFRelease(UID); 01248 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); 01249 } 01250 } 01251 01252 // add sub-device clock array for the aggregate device to the dictionary 01253 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock); 01254 } else { 01255 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)"); 01256 } 01257 } 01258 */ 01259 01260 //------------------------------------------------- 01261 // Create a CFMutableArray for our sub-device list 01262 //------------------------------------------------- 01263 01264 // we need to append the UID for each device to a CFMutableArray, so create one here 01265 CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 01266 01267 vector<CFStringRef> captureDeviceUID; 01268 for (UInt32 i = 0; i < captureDeviceID.size(); i++) { 01269 CFStringRef ref = GetDeviceName(captureDeviceID[i]); 01270 if (ref == NULL) 01271 return -1; 01272 captureDeviceUID.push_back(ref); 01273 // input sub-devices in this example, so append the sub-device's UID to the CFArray 01274 CFArrayAppendValue(subDevicesArray, ref); 01275 } 01276 01277 vector<CFStringRef> playbackDeviceUID; 01278 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { 01279 CFStringRef ref = GetDeviceName(playbackDeviceID[i]); 01280 if (ref == NULL) 01281 return -1; 01282 playbackDeviceUID.push_back(ref); 01283 // output sub-devices in this example, so append the sub-device's UID to the CFArray 01284 CFArrayAppendValue(subDevicesArray, ref); 01285 } 01286 01287 //----------------------------------------------------------------------- 01288 // Feed the dictionary to the plugin, to create a blank aggregate device 01289 //----------------------------------------------------------------------- 01290 01291 AudioObjectPropertyAddress pluginAOPA; 01292 pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice; 01293 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; 01294 pluginAOPA.mElement = kAudioObjectPropertyElementMaster; 01295 UInt32 outDataSize; 01296 01297 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); 01298 if (osErr != noErr) { 01299 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); 01300 printError(osErr); 01301 goto error; 01302 } 01303 01304 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); 01305 if (osErr != noErr) { 01306 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); 01307 printError(osErr); 01308 goto error; 01309 } 01310 01311 // pause for a bit to make sure that everything completed correctly 01312 // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created 01313 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 01314 01315 //------------------------- 01316 // Set the sub-device list 01317 //------------------------- 01318 01319 pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList; 01320 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; 01321 pluginAOPA.mElement = kAudioObjectPropertyElementMaster; 01322 outDataSize = sizeof(CFMutableArrayRef); 01323 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray); 01324 if (osErr != noErr) { 01325 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error"); 01326 printError(osErr); 01327 goto error; 01328 } 01329 01330 // pause again to give the changes time to take effect 01331 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 01332 01333 //----------------------- 01334 // Set the master device 01335 //----------------------- 01336 01337 // set the master device manually (this is the device which will act as the master clock for the aggregate device) 01338 // pass in the UID of the device you want to use 01339 pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice; 01340 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; 01341 pluginAOPA.mElement = kAudioObjectPropertyElementMaster; 01342 outDataSize = sizeof(CFStringRef); 01343 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]); // First apture is master... 01344 if (osErr != noErr) { 01345 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for master device error"); 01346 printError(osErr); 01347 goto error; 01348 } 01349 01350 // pause again to give the changes time to take effect 01351 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 01352 01353 // Prepare sub-devices for clock drift compensation 01354 // Workaround for bug in the HAL : until 10.6.2 01355 01356 if (fClockDriftCompensate) { 01357 if (need_clock_drift_compensation) { 01358 jack_info("Clock drift compensation activated..."); 01359 01360 // Get the property data size 01361 osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); 01362 if (osErr != noErr) { 01363 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); 01364 printError(osErr); 01365 } 01366 01367 // Calculate the number of object IDs 01368 subDevicesNum = outSize / sizeof(AudioObjectID); 01369 jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); 01370 AudioObjectID subDevices[subDevicesNum]; 01371 outSize = sizeof(subDevices); 01372 01373 osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); 01374 if (osErr != noErr) { 01375 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); 01376 printError(osErr); 01377 } 01378 01379 // Set kAudioSubDevicePropertyDriftCompensation property... 01380 for (UInt32 index = 0; index < subDevicesNum; ++index) { 01381 UInt32 theDriftCompensationValue = 1; 01382 osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue); 01383 if (osErr != noErr) { 01384 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error"); 01385 printError(osErr); 01386 } 01387 } 01388 } else { 01389 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)"); 01390 } 01391 } 01392 01393 // pause again to give the changes time to take effect 01394 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 01395 01396 //---------- 01397 // Clean up 01398 //---------- 01399 01400 // release the private AD key 01401 CFRelease(AggregateDeviceNumberRef); 01402 01403 // release the CF objects we have created - we don't need them any more 01404 CFRelease(aggDeviceDict); 01405 CFRelease(subDevicesArray); 01406 01407 if (subDevicesArrayClock) 01408 CFRelease(subDevicesArrayClock); 01409 01410 // release the device UID 01411 for (UInt32 i = 0; i < captureDeviceUID.size(); i++) { 01412 CFRelease(captureDeviceUID[i]); 01413 } 01414 01415 for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) { 01416 CFRelease(playbackDeviceUID[i]); 01417 } 01418 01419 jack_log("New aggregate device %ld", *outAggregateDevice); 01420 return noErr; 01421 01422 error: 01423 DestroyAggregateDevice(); 01424 return -1; 01425 } 01426 01427 01428 bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device) 01429 { 01430 OSStatus err = noErr; 01431 AudioObjectID sub_device[32]; 01432 UInt32 outSize = sizeof(sub_device); 01433 err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); 01434 01435 if (err != noErr) { 01436 jack_log("Device does not have subdevices"); 01437 return false; 01438 } else { 01439 int num_devices = outSize / sizeof(AudioObjectID); 01440 jack_log("Device does has %d subdevices", num_devices); 01441 return true; 01442 } 01443 } 01444 01445 void JackCoreAudioAdapter::CloseAUHAL() 01446 { 01447 AudioUnitUninitialize(fAUHAL); 01448 CloseComponent(fAUHAL); 01449 } 01450 01451 int JackCoreAudioAdapter::Open() 01452 { 01453 return (AudioOutputUnitStart(fAUHAL) != noErr) ? -1 : 0; 01454 } 01455 01456 int JackCoreAudioAdapter::Close() 01457 { 01458 #ifdef JACK_MONITOR 01459 fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize); 01460 #endif 01461 AudioOutputUnitStop(fAUHAL); 01462 DisposeBuffers(); 01463 CloseAUHAL(); 01464 RemoveListeners(); 01465 if (fPluginID > 0) 01466 DestroyAggregateDevice(); 01467 return 0; 01468 } 01469 01470 int JackCoreAudioAdapter::SetSampleRate ( jack_nframes_t sample_rate ) { 01471 JackAudioAdapterInterface::SetHostSampleRate ( sample_rate ); 01472 Close(); 01473 return Open(); 01474 } 01475 01476 int JackCoreAudioAdapter::SetBufferSize ( jack_nframes_t buffer_size ) { 01477 JackAudioAdapterInterface::SetHostBufferSize ( buffer_size ); 01478 Close(); 01479 return Open(); 01480 } 01481 01482 } // namespace 01483 01484 #ifdef __cplusplus 01485 extern "C" 01486 { 01487 #endif 01488 01489 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor() 01490 { 01491 jack_driver_desc_t *desc; 01492 unsigned int i; 01493 desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t)); 01494 01495 strcpy(desc->name, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 01496 strcpy(desc->desc, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 01497 01498 desc->nparams = 13; 01499 desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); 01500 01501 i = 0; 01502 strcpy(desc->params[i].name, "channels"); 01503 desc->params[i].character = 'c'; 01504 desc->params[i].type = JackDriverParamInt; 01505 desc->params[i].value.ui = -1; 01506 strcpy(desc->params[i].short_desc, "Maximum number of channels"); 01507 strcpy(desc->params[i].long_desc, "Maximum number of channels. If -1, max possible number of channels will be used"); 01508 01509 i++; 01510 strcpy(desc->params[i].name, "inchannels"); 01511 desc->params[i].character = 'i'; 01512 desc->params[i].type = JackDriverParamInt; 01513 desc->params[i].value.ui = -1; 01514 strcpy(desc->params[i].short_desc, "Maximum number of input channels"); 01515 strcpy(desc->params[i].long_desc, "Maximum number of input channels. If -1, max possible number of input channels will be used"); 01516 01517 i++; 01518 strcpy(desc->params[i].name, "outchannels"); 01519 desc->params[i].character = 'o'; 01520 desc->params[i].type = JackDriverParamInt; 01521 desc->params[i].value.ui = -1; 01522 strcpy(desc->params[i].short_desc, "Maximum number of output channels"); 01523 strcpy(desc->params[i].long_desc, "Maximum number of output channels. If -1, max possible number of output channels will be used"); 01524 01525 i++; 01526 strcpy(desc->params[i].name, "capture"); 01527 desc->params[i].character = 'C'; 01528 desc->params[i].type = JackDriverParamString; 01529 strcpy(desc->params[i].short_desc, "Input CoreAudio device name"); 01530 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01531 01532 i++; 01533 strcpy(desc->params[i].name, "playback"); 01534 desc->params[i].character = 'P'; 01535 desc->params[i].type = JackDriverParamString; 01536 strcpy(desc->params[i].short_desc, "Output CoreAudio device name"); 01537 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01538 01539 i++; 01540 strcpy(desc->params[i].name, "rate"); 01541 desc->params[i].character = 'r'; 01542 desc->params[i].type = JackDriverParamUInt; 01543 desc->params[i].value.ui = 44100U; 01544 strcpy(desc->params[i].short_desc, "Sample rate"); 01545 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01546 01547 i++; 01548 strcpy(desc->params[i].name, "period"); 01549 desc->params[i].character = 'p'; 01550 desc->params[i].type = JackDriverParamUInt; 01551 desc->params[i].value.ui = 512U; 01552 strcpy(desc->params[i].short_desc, "Frames per period"); 01553 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01554 01555 i++; 01556 strcpy(desc->params[i].name, "duplex"); 01557 desc->params[i].character = 'D'; 01558 desc->params[i].type = JackDriverParamBool; 01559 desc->params[i].value.i = TRUE; 01560 strcpy(desc->params[i].short_desc, "Provide both capture and playback ports"); 01561 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01562 01563 i++; 01564 strcpy(desc->params[i].name, "device"); 01565 desc->params[i].character = 'd'; 01566 desc->params[i].type = JackDriverParamString; 01567 strcpy(desc->params[i].short_desc, "CoreAudio device name"); 01568 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01569 01570 i++; 01571 strcpy(desc->params[i].name, "list-devices"); 01572 desc->params[i].character = 'l'; 01573 desc->params[i].type = JackDriverParamBool; 01574 desc->params[i].value.i = TRUE; 01575 strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); 01576 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01577 01578 i++; 01579 strcpy(desc->params[i].name, "quality"); 01580 desc->params[i].character = 'q'; 01581 desc->params[i].type = JackDriverParamInt; 01582 desc->params[i].value.ui = 0; 01583 strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); 01584 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01585 01586 i++; 01587 strcpy(desc->params[i].name, "ring-buffer"); 01588 desc->params[i].character = 'g'; 01589 desc->params[i].type = JackDriverParamInt; 01590 desc->params[i].value.ui = 32768; 01591 strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); 01592 strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)"); 01593 01594 i++; 01595 strcpy(desc->params[i].name, "clock-drift"); 01596 desc->params[i].character = 's'; 01597 desc->params[i].type = JackDriverParamBool; 01598 desc->params[i].value.i = FALSE; 01599 strcpy(desc->params[i].short_desc, "Clock drift compensation"); 01600 strcpy(desc->params[i].long_desc, "Whether to compensate clock drift in dynamically created aggregate device"); 01601 01602 return desc; 01603 } 01604 01605 01606 #ifdef __cplusplus 01607 } 01608 #endif 01609