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