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