Jack2
1.9.7
|
00001 /* 00002 Copyright (C) 2004-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 "JackCoreAudioDriver.h" 00021 #include "JackEngineControl.h" 00022 #include "JackMachThread.h" 00023 #include "JackGraphManager.h" 00024 #include "JackError.h" 00025 #include "JackClientControl.h" 00026 #include "JackDriverLoader.h" 00027 #include "JackGlobals.h" 00028 #include "JackTools.h" 00029 #include "JackCompilerDeps.h" 00030 00031 #include <iostream> 00032 #include <CoreServices/CoreServices.h> 00033 #include <CoreFoundation/CFNumber.h> 00034 00035 namespace Jack 00036 { 00037 00038 static void Print4CharCode(const char* msg, long c) 00039 { 00040 UInt32 __4CC_number = (c); 00041 char __4CC_string[5]; 00042 *((SInt32*)__4CC_string) = EndianU32_NtoB(__4CC_number); 00043 __4CC_string[4] = 0; 00044 jack_log("%s'%s'", (msg), __4CC_string); 00045 } 00046 00047 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc) 00048 { 00049 jack_log("- - - - - - - - - - - - - - - - - - - -"); 00050 jack_log(" Sample Rate:%f", inDesc->mSampleRate); 00051 jack_log(" Format ID:%.*s", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID); 00052 jack_log(" Format Flags:%lX", inDesc->mFormatFlags); 00053 jack_log(" Bytes per Packet:%ld", inDesc->mBytesPerPacket); 00054 jack_log(" Frames per Packet:%ld", inDesc->mFramesPerPacket); 00055 jack_log(" Bytes per Frame:%ld", inDesc->mBytesPerFrame); 00056 jack_log(" Channels per Frame:%ld", inDesc->mChannelsPerFrame); 00057 jack_log(" Bits per Channel:%ld", inDesc->mBitsPerChannel); 00058 jack_log("- - - - - - - - - - - - - - - - - - - -"); 00059 } 00060 00061 static void printError(OSStatus err) 00062 { 00063 switch (err) { 00064 case kAudioHardwareNoError: 00065 jack_log("error code : kAudioHardwareNoError"); 00066 break; 00067 case kAudioConverterErr_FormatNotSupported: 00068 jack_log("error code : kAudioConverterErr_FormatNotSupported"); 00069 break; 00070 case kAudioConverterErr_OperationNotSupported: 00071 jack_log("error code : kAudioConverterErr_OperationNotSupported"); 00072 break; 00073 case kAudioConverterErr_PropertyNotSupported: 00074 jack_log("error code : kAudioConverterErr_PropertyNotSupported"); 00075 break; 00076 case kAudioConverterErr_InvalidInputSize: 00077 jack_log("error code : kAudioConverterErr_InvalidInputSize"); 00078 break; 00079 case kAudioConverterErr_InvalidOutputSize: 00080 jack_log("error code : kAudioConverterErr_InvalidOutputSize"); 00081 break; 00082 case kAudioConverterErr_UnspecifiedError: 00083 jack_log("error code : kAudioConverterErr_UnspecifiedError"); 00084 break; 00085 case kAudioConverterErr_BadPropertySizeError: 00086 jack_log("error code : kAudioConverterErr_BadPropertySizeError"); 00087 break; 00088 case kAudioConverterErr_RequiresPacketDescriptionsError: 00089 jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError"); 00090 break; 00091 case kAudioConverterErr_InputSampleRateOutOfRange: 00092 jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange"); 00093 break; 00094 case kAudioConverterErr_OutputSampleRateOutOfRange: 00095 jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange"); 00096 break; 00097 case kAudioHardwareNotRunningError: 00098 jack_log("error code : kAudioHardwareNotRunningError"); 00099 break; 00100 case kAudioHardwareUnknownPropertyError: 00101 jack_log("error code : kAudioHardwareUnknownPropertyError"); 00102 break; 00103 case kAudioHardwareIllegalOperationError: 00104 jack_log("error code : kAudioHardwareIllegalOperationError"); 00105 break; 00106 case kAudioHardwareBadDeviceError: 00107 jack_log("error code : kAudioHardwareBadDeviceError"); 00108 break; 00109 case kAudioHardwareBadStreamError: 00110 jack_log("error code : kAudioHardwareBadStreamError"); 00111 break; 00112 case kAudioDeviceUnsupportedFormatError: 00113 jack_log("error code : kAudioDeviceUnsupportedFormatError"); 00114 break; 00115 case kAudioDevicePermissionsError: 00116 jack_log("error code : kAudioDevicePermissionsError"); 00117 break; 00118 case kAudioHardwareBadObjectError: 00119 jack_log("error code : kAudioHardwareBadObjectError"); 00120 break; 00121 case kAudioHardwareUnsupportedOperationError: 00122 jack_log("error code : kAudioHardwareUnsupportedOperationError"); 00123 break; 00124 default: 00125 Print4CharCode("error code : unknown", err); 00126 break; 00127 } 00128 } 00129 00130 static OSStatus DisplayDeviceNames() 00131 { 00132 UInt32 size; 00133 Boolean isWritable; 00134 int i, deviceNum; 00135 OSStatus err; 00136 CFStringRef UIname; 00137 00138 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable); 00139 if (err != noErr) 00140 return err; 00141 00142 deviceNum = size / sizeof(AudioDeviceID); 00143 AudioDeviceID devices[deviceNum]; 00144 00145 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices); 00146 if (err != noErr) 00147 return err; 00148 00149 for (i = 0; i < deviceNum; i++) { 00150 char device_name[256]; 00151 char internal_name[256]; 00152 00153 size = sizeof(CFStringRef); 00154 UIname = NULL; 00155 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname); 00156 if (err == noErr) { 00157 CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding()); 00158 } else { 00159 goto error; 00160 } 00161 00162 size = 256; 00163 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name); 00164 if (err != noErr) 00165 return err; 00166 00167 jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name, internal_name); 00168 } 00169 00170 return noErr; 00171 00172 error: 00173 if (UIname != NULL) 00174 CFRelease(UIname); 00175 return err; 00176 } 00177 00178 static CFStringRef GetDeviceName(AudioDeviceID id) 00179 { 00180 UInt32 size = sizeof(CFStringRef); 00181 CFStringRef UIname; 00182 OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname); 00183 return (err == noErr) ? UIname : NULL; 00184 } 00185 00186 OSStatus JackCoreAudioDriver::Render(void *inRefCon, 00187 AudioUnitRenderActionFlags *ioActionFlags, 00188 const AudioTimeStamp *inTimeStamp, 00189 UInt32 inBusNumber, 00190 UInt32 inNumberFrames, 00191 AudioBufferList *ioData) 00192 { 00193 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inRefCon; 00194 driver->fActionFags = ioActionFlags; 00195 driver->fCurrentTime = (AudioTimeStamp *)inTimeStamp; 00196 driver->fDriverOutputData = ioData; 00197 00198 // Setup threadded based log function once... 00199 if (set_threaded_log_function()) { 00200 00201 jack_log("set_threaded_log_function"); 00202 JackMachThread::GetParams(pthread_self(), &driver->fEngineControl->fPeriod, &driver->fEngineControl->fComputation, &driver->fEngineControl->fConstraint); 00203 00204 if (driver->fComputationGrain > 0) { 00205 jack_log("JackCoreAudioDriver::Render : RT thread computation setup to %d percent of period", int(driver->fComputationGrain * 100)); 00206 driver->fEngineControl->fComputation = driver->fEngineControl->fPeriod * driver->fComputationGrain; 00207 } 00208 00209 // Signal waiting start function... 00210 driver->fState = true; 00211 } 00212 00213 driver->CycleTakeBeginTime(); 00214 return driver->Process(); 00215 } 00216 00217 int JackCoreAudioDriver::Read() 00218 { 00219 OSStatus err = AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData); 00220 return (err == noErr) ? 0 : -1; 00221 } 00222 00223 int JackCoreAudioDriver::Write() 00224 { 00225 for (int i = 0; i < fPlaybackChannels; i++) { 00226 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { 00227 jack_default_audio_sample_t* buffer = GetOutputBuffer(i); 00228 int size = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize; 00229 memcpy((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, buffer, size); 00230 // Monitor ports 00231 if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) 00232 memcpy(GetMonitorBuffer(i), buffer, size); 00233 } else { 00234 memset((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); 00235 } 00236 } 00237 return 0; 00238 } 00239 00240 OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice, 00241 UInt32 inChannel, 00242 Boolean isInput, 00243 AudioDevicePropertyID inPropertyID, 00244 void* inClientData) 00245 { 00246 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData; 00247 00248 switch (inPropertyID) { 00249 00250 case kAudioDevicePropertyNominalSampleRate: { 00251 jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate"); 00252 driver->fState = true; 00253 // Check new sample rate 00254 Float64 sampleRate; 00255 UInt32 outSize = sizeof(Float64); 00256 OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); 00257 if (err != noErr) { 00258 jack_error("Cannot get current sample rate"); 00259 printError(err); 00260 } else { 00261 jack_log("SRNotificationCallback : checked sample rate = %f", sampleRate); 00262 } 00263 break; 00264 } 00265 } 00266 00267 return noErr; 00268 } 00269 00270 // A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code) 00271 OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, 00272 UInt32 inChannel, 00273 Boolean isInput, 00274 AudioDevicePropertyID inPropertyID, 00275 void* inClientData) 00276 { 00277 JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData; 00278 00279 switch (inPropertyID) { 00280 00281 case kAudioDevicePropertyDeviceIsRunning: { 00282 UInt32 isrunning = 0; 00283 UInt32 outsize = sizeof(UInt32); 00284 if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceIsRunning, &outsize, &isrunning) == noErr) { 00285 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsRunning = %d", isrunning); 00286 } 00287 break; 00288 } 00289 00290 case kAudioDeviceProcessorOverload: { 00291 jack_error("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload"); 00292 jack_time_t cur_time = GetMicroSeconds(); 00293 driver->NotifyXRun(cur_time, float(cur_time - driver->fBeginDateUst)); // Better this value than nothing... 00294 break; 00295 } 00296 00297 case kAudioDevicePropertyStreamConfiguration: { 00298 jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration : server will quit..."); 00299 driver->NotifyFailure(JackBackendError, "Another application has changed the device configuration."); // Message length limited to JACK_MESSAGE_SIZE 00300 driver->CloseAUHAL(); 00301 kill(JackTools::GetPID(), SIGINT); 00302 return kAudioHardwareUnsupportedOperationError; 00303 } 00304 00305 case kAudioDevicePropertyNominalSampleRate: { 00306 Float64 sampleRate = 0; 00307 UInt32 outsize = sizeof(Float64); 00308 OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outsize, &sampleRate); 00309 if (err != noErr) 00310 return kAudioHardwareUnsupportedOperationError; 00311 00312 char device_name[256]; 00313 const char* digidesign_name = "Digidesign"; 00314 driver->GetDeviceNameFromID(driver->fDeviceID, device_name); 00315 00316 if (sampleRate != driver->fEngineControl->fSampleRate) { 00317 00318 // Digidesign hardware, so "special" code : change the SR again here 00319 if (strncmp(device_name, digidesign_name, sizeof(digidesign_name)) == 0) { 00320 00321 jack_log("Digidesign HW = %s", device_name); 00322 00323 // Set sample rate again... 00324 sampleRate = driver->fEngineControl->fSampleRate; 00325 err = AudioDeviceSetProperty(driver->fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outsize, &sampleRate); 00326 if (err != noErr) { 00327 jack_error("Cannot set sample rate = %f", sampleRate); 00328 printError(err); 00329 } else { 00330 jack_log("Set sample rate = %f", sampleRate); 00331 } 00332 00333 // Check new sample rate again... 00334 outsize = sizeof(Float64); 00335 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outsize, &sampleRate); 00336 if (err != noErr) { 00337 jack_error("Cannot get current sample rate"); 00338 printError(err); 00339 } else { 00340 jack_log("Checked sample rate = %f", sampleRate); 00341 } 00342 return noErr; 00343 00344 } else { 00345 driver->NotifyFailure(JackBackendError, "Another application has changed the sample rate."); // Message length limited to JACK_MESSAGE_SIZE 00346 driver->CloseAUHAL(); 00347 kill(JackTools::GetPID(), SIGINT); 00348 return kAudioHardwareUnsupportedOperationError; 00349 } 00350 } 00351 } 00352 00353 } 00354 return noErr; 00355 } 00356 00357 OSStatus JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id) 00358 { 00359 UInt32 size = sizeof(AudioValueTranslation); 00360 CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding()); 00361 AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) }; 00362 00363 if (inIUD == NULL) { 00364 return kAudioHardwareUnspecifiedError; 00365 } else { 00366 OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value); 00367 CFRelease(inIUD); 00368 jack_log("GetDeviceIDFromUID %s %ld", UID, *id); 00369 return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res; 00370 } 00371 } 00372 00373 OSStatus JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID* id) 00374 { 00375 OSStatus res; 00376 UInt32 theSize = sizeof(UInt32); 00377 AudioDeviceID inDefault; 00378 AudioDeviceID outDefault; 00379 00380 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) 00381 return res; 00382 00383 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) 00384 return res; 00385 00386 jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault); 00387 00388 // Get the device only if default input and output are the same 00389 if (inDefault == outDefault) { 00390 *id = inDefault; 00391 return noErr; 00392 } else { 00393 jack_error("Default input and output devices are not the same !!"); 00394 return kAudioHardwareBadDeviceError; 00395 } 00396 } 00397 00398 OSStatus JackCoreAudioDriver::GetDefaultInputDevice(AudioDeviceID* id) 00399 { 00400 OSStatus res; 00401 UInt32 theSize = sizeof(UInt32); 00402 AudioDeviceID inDefault; 00403 00404 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) 00405 return res; 00406 00407 if (inDefault == 0) { 00408 jack_error("Error : input device is 0, please select a correct one !!"); 00409 return -1; 00410 } 00411 jack_log("GetDefaultInputDevice: input = %ld ", inDefault); 00412 *id = inDefault; 00413 return noErr; 00414 } 00415 00416 OSStatus JackCoreAudioDriver::GetDefaultOutputDevice(AudioDeviceID* id) 00417 { 00418 OSStatus res; 00419 UInt32 theSize = sizeof(UInt32); 00420 AudioDeviceID outDefault; 00421 00422 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) 00423 return res; 00424 00425 if (outDefault == 0) { 00426 jack_error("Error : output device is 0, please select a correct one !!"); 00427 return -1; 00428 } 00429 jack_log("GetDefaultOutputDevice: output = %ld", outDefault); 00430 *id = outDefault; 00431 return noErr; 00432 } 00433 00434 OSStatus JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id, char* name) 00435 { 00436 UInt32 size = 256; 00437 return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name); 00438 } 00439 00440 OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput) 00441 { 00442 OSStatus err = noErr; 00443 UInt32 outSize; 00444 Boolean outWritable; 00445 00446 channelCount = 0; 00447 err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable); 00448 if (err == noErr) { 00449 AudioBufferList bufferList[outSize]; 00450 err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList); 00451 if (err == noErr) { 00452 for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++) 00453 channelCount += bufferList->mBuffers[i].mNumberChannels; 00454 } 00455 } 00456 return err; 00457 } 00458 00459 JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) 00460 : JackAudioDriver(name, alias, engine, table), 00461 fJackInputData(NULL), 00462 fDriverOutputData(NULL), 00463 fPluginID(0), 00464 fState(false), 00465 fHogged(false), 00466 fIOUsage(1.f), 00467 fComputationGrain(-1.f), 00468 fClockDriftCompensate(false) 00469 {} 00470 00471 JackCoreAudioDriver::~JackCoreAudioDriver() 00472 {} 00473 00474 OSStatus JackCoreAudioDriver::DestroyAggregateDevice() 00475 { 00476 OSStatus osErr = noErr; 00477 AudioObjectPropertyAddress pluginAOPA; 00478 pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice; 00479 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; 00480 pluginAOPA.mElement = kAudioObjectPropertyElementMaster; 00481 UInt32 outDataSize; 00482 00483 if (fPluginID > 0) { 00484 00485 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); 00486 if (osErr != noErr) { 00487 jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); 00488 printError(osErr); 00489 return osErr; 00490 } 00491 00492 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); 00493 if (osErr != noErr) { 00494 jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); 00495 printError(osErr); 00496 return osErr; 00497 } 00498 00499 } 00500 00501 return noErr; 00502 } 00503 00504 OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) 00505 { 00506 OSStatus err = noErr; 00507 AudioObjectID sub_device[32]; 00508 UInt32 outSize = sizeof(sub_device); 00509 00510 err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); 00511 vector<AudioDeviceID> captureDeviceIDArray; 00512 00513 if (err != noErr) { 00514 jack_log("Input device does not have subdevices"); 00515 captureDeviceIDArray.push_back(captureDeviceID); 00516 } else { 00517 int num_devices = outSize / sizeof(AudioObjectID); 00518 jack_log("Input device has %d subdevices", num_devices); 00519 for (int i = 0; i < num_devices; i++) { 00520 captureDeviceIDArray.push_back(sub_device[i]); 00521 } 00522 } 00523 00524 err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); 00525 vector<AudioDeviceID> playbackDeviceIDArray; 00526 00527 if (err != noErr) { 00528 jack_log("Output device does not have subdevices"); 00529 playbackDeviceIDArray.push_back(playbackDeviceID); 00530 } else { 00531 int num_devices = outSize / sizeof(AudioObjectID); 00532 jack_log("Output device has %d subdevices", num_devices); 00533 for (int i = 0; i < num_devices; i++) { 00534 playbackDeviceIDArray.push_back(sub_device[i]); 00535 } 00536 } 00537 00538 return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice); 00539 } 00540 00541 OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) 00542 { 00543 OSStatus osErr = noErr; 00544 UInt32 outSize; 00545 Boolean outWritable; 00546 00547 // Prepare sub-devices for clock drift compensation 00548 // Workaround for bug in the HAL : until 10.6.2 00549 AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; 00550 AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; 00551 UInt32 theQualifierDataSize = sizeof(AudioObjectID); 00552 AudioClassID inClass = kAudioSubDeviceClassID; 00553 void* theQualifierData = &inClass; 00554 UInt32 subDevicesNum = 0; 00555 00556 //--------------------------------------------------------------------------- 00557 // Setup SR of both devices otherwise creating AD may fail... 00558 //--------------------------------------------------------------------------- 00559 UInt32 keptclockdomain = 0; 00560 UInt32 clockdomain = 0; 00561 outSize = sizeof(UInt32); 00562 bool need_clock_drift_compensation = false; 00563 00564 for (UInt32 i = 0; i < captureDeviceID.size(); i++) { 00565 if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { 00566 jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); 00567 } else { 00568 // Check clock domain 00569 osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); 00570 if (osErr != 0) { 00571 jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); 00572 printError(osErr); 00573 } else { 00574 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; 00575 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); 00576 if (clockdomain != 0 && clockdomain != keptclockdomain) { 00577 jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); 00578 need_clock_drift_compensation = true; 00579 } 00580 } 00581 } 00582 } 00583 00584 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { 00585 if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { 00586 jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); 00587 } else { 00588 // Check clock domain 00589 osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); 00590 if (osErr != 0) { 00591 jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); 00592 printError(osErr); 00593 } else { 00594 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; 00595 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); 00596 if (clockdomain != 0 && clockdomain != keptclockdomain) { 00597 jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); 00598 need_clock_drift_compensation = true; 00599 } 00600 } 00601 } 00602 } 00603 00604 // If no valid clock domain was found, then assume we have to compensate... 00605 if (keptclockdomain == 0) { 00606 need_clock_drift_compensation = true; 00607 } 00608 00609 //--------------------------------------------------------------------------- 00610 // Start to create a new aggregate by getting the base audio hardware plugin 00611 //--------------------------------------------------------------------------- 00612 00613 char device_name[256]; 00614 for (UInt32 i = 0; i < captureDeviceID.size(); i++) { 00615 GetDeviceNameFromID(captureDeviceID[i], device_name); 00616 jack_info("Separated input = '%s' ", device_name); 00617 } 00618 00619 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { 00620 GetDeviceNameFromID(playbackDeviceID[i], device_name); 00621 jack_info("Separated output = '%s' ", device_name); 00622 } 00623 00624 osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); 00625 if (osErr != noErr) { 00626 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); 00627 printError(osErr); 00628 return osErr; 00629 } 00630 00631 AudioValueTranslation pluginAVT; 00632 00633 CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio"); 00634 00635 pluginAVT.mInputData = &inBundleRef; 00636 pluginAVT.mInputDataSize = sizeof(inBundleRef); 00637 pluginAVT.mOutputData = &fPluginID; 00638 pluginAVT.mOutputDataSize = sizeof(fPluginID); 00639 00640 osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); 00641 if (osErr != noErr) { 00642 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); 00643 printError(osErr); 00644 return osErr; 00645 } 00646 00647 //------------------------------------------------- 00648 // Create a CFDictionary for our aggregate device 00649 //------------------------------------------------- 00650 00651 CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 00652 00653 CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex"); 00654 CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex"); 00655 00656 // add the name of the device to the dictionary 00657 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef); 00658 00659 // add our choice of UID for the aggregate device to the dictionary 00660 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); 00661 00662 // add a "private aggregate key" to the dictionary 00663 int value = 1; 00664 CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); 00665 00666 SInt32 system; 00667 Gestalt(gestaltSystemVersion, &system); 00668 00669 jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); 00670 00671 // Starting with 10.5.4 systems, the AD can be internal... (better) 00672 if (system < 0x00001054) { 00673 jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); 00674 } else { 00675 jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); 00676 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); 00677 } 00678 00679 // Prepare sub-devices for clock drift compensation 00680 CFMutableArrayRef subDevicesArrayClock = NULL; 00681 00682 /* 00683 if (fClockDriftCompensate) { 00684 if (need_clock_drift_compensation) { 00685 jack_info("Clock drift compensation activated..."); 00686 subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 00687 00688 for (UInt32 i = 0; i < captureDeviceID.size(); i++) { 00689 CFStringRef UID = GetDeviceName(captureDeviceID[i]); 00690 if (UID) { 00691 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 00692 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID); 00693 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef); 00694 //CFRelease(UID); 00695 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); 00696 } 00697 } 00698 00699 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { 00700 CFStringRef UID = GetDeviceName(playbackDeviceID[i]); 00701 if (UID) { 00702 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 00703 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID); 00704 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef); 00705 //CFRelease(UID); 00706 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); 00707 } 00708 } 00709 00710 // add sub-device clock array for the aggregate device to the dictionary 00711 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock); 00712 } else { 00713 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)"); 00714 } 00715 } 00716 */ 00717 00718 //------------------------------------------------- 00719 // Create a CFMutableArray for our sub-device list 00720 //------------------------------------------------- 00721 00722 // we need to append the UID for each device to a CFMutableArray, so create one here 00723 CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 00724 00725 vector<CFStringRef> captureDeviceUID; 00726 for (UInt32 i = 0; i < captureDeviceID.size(); i++) { 00727 CFStringRef ref = GetDeviceName(captureDeviceID[i]); 00728 if (ref == NULL) 00729 return -1; 00730 captureDeviceUID.push_back(ref); 00731 // input sub-devices in this example, so append the sub-device's UID to the CFArray 00732 CFArrayAppendValue(subDevicesArray, ref); 00733 } 00734 00735 vector<CFStringRef> playbackDeviceUID; 00736 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { 00737 CFStringRef ref = GetDeviceName(playbackDeviceID[i]); 00738 if (ref == NULL) 00739 return -1; 00740 playbackDeviceUID.push_back(ref); 00741 // output sub-devices in this example, so append the sub-device's UID to the CFArray 00742 CFArrayAppendValue(subDevicesArray, ref); 00743 } 00744 00745 //----------------------------------------------------------------------- 00746 // Feed the dictionary to the plugin, to create a blank aggregate device 00747 //----------------------------------------------------------------------- 00748 00749 AudioObjectPropertyAddress pluginAOPA; 00750 pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice; 00751 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; 00752 pluginAOPA.mElement = kAudioObjectPropertyElementMaster; 00753 UInt32 outDataSize; 00754 00755 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); 00756 if (osErr != noErr) { 00757 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); 00758 printError(osErr); 00759 goto error; 00760 } 00761 00762 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); 00763 if (osErr != noErr) { 00764 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); 00765 printError(osErr); 00766 goto error; 00767 } 00768 00769 // pause for a bit to make sure that everything completed correctly 00770 // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created 00771 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 00772 00773 //------------------------- 00774 // Set the sub-device list 00775 //------------------------- 00776 00777 pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList; 00778 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; 00779 pluginAOPA.mElement = kAudioObjectPropertyElementMaster; 00780 outDataSize = sizeof(CFMutableArrayRef); 00781 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray); 00782 if (osErr != noErr) { 00783 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error"); 00784 printError(osErr); 00785 goto error; 00786 } 00787 00788 // pause again to give the changes time to take effect 00789 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 00790 00791 //----------------------- 00792 // Set the master device 00793 //----------------------- 00794 00795 // set the master device manually (this is the device which will act as the master clock for the aggregate device) 00796 // pass in the UID of the device you want to use 00797 pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice; 00798 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; 00799 pluginAOPA.mElement = kAudioObjectPropertyElementMaster; 00800 outDataSize = sizeof(CFStringRef); 00801 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]); // First apture is master... 00802 if (osErr != noErr) { 00803 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for master device error"); 00804 printError(osErr); 00805 goto error; 00806 } 00807 00808 // pause again to give the changes time to take effect 00809 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 00810 00811 // Prepare sub-devices for clock drift compensation 00812 // Workaround for bug in the HAL : until 10.6.2 00813 00814 if (fClockDriftCompensate) { 00815 if (need_clock_drift_compensation) { 00816 jack_info("Clock drift compensation activated..."); 00817 00818 // Get the property data size 00819 osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); 00820 if (osErr != noErr) { 00821 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); 00822 printError(osErr); 00823 } 00824 00825 // Calculate the number of object IDs 00826 subDevicesNum = outSize / sizeof(AudioObjectID); 00827 jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); 00828 AudioObjectID subDevices[subDevicesNum]; 00829 outSize = sizeof(subDevices); 00830 00831 osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); 00832 if (osErr != noErr) { 00833 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); 00834 printError(osErr); 00835 } 00836 00837 // Set kAudioSubDevicePropertyDriftCompensation property... 00838 for (UInt32 index = 0; index < subDevicesNum; ++index) { 00839 UInt32 theDriftCompensationValue = 1; 00840 osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue); 00841 if (osErr != noErr) { 00842 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error"); 00843 printError(osErr); 00844 } 00845 } 00846 } else { 00847 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)"); 00848 } 00849 } 00850 00851 // pause again to give the changes time to take effect 00852 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 00853 00854 //---------- 00855 // Clean up 00856 //---------- 00857 00858 // release the private AD key 00859 CFRelease(AggregateDeviceNumberRef); 00860 00861 // release the CF objects we have created - we don't need them any more 00862 CFRelease(aggDeviceDict); 00863 CFRelease(subDevicesArray); 00864 00865 if (subDevicesArrayClock) 00866 CFRelease(subDevicesArrayClock); 00867 00868 // release the device UID 00869 for (UInt32 i = 0; i < captureDeviceUID.size(); i++) { 00870 CFRelease(captureDeviceUID[i]); 00871 } 00872 00873 for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) { 00874 CFRelease(playbackDeviceUID[i]); 00875 } 00876 00877 jack_log("New aggregate device %ld", *outAggregateDevice); 00878 return noErr; 00879 00880 error: 00881 DestroyAggregateDevice(); 00882 return -1; 00883 } 00884 00885 int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, 00886 const char* playback_driver_uid, 00887 char* capture_driver_name, 00888 char* playback_driver_name, 00889 jack_nframes_t samplerate) 00890 { 00891 capture_driver_name[0] = 0; 00892 playback_driver_name[0] = 0; 00893 00894 // Duplex 00895 if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { 00896 jack_log("JackCoreAudioDriver::Open duplex"); 00897 00898 // Same device for capture and playback... 00899 if (strcmp(capture_driver_uid, playback_driver_uid) == 0) { 00900 00901 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { 00902 jack_log("Will take default in/out"); 00903 if (GetDefaultDevice(&fDeviceID) != noErr) { 00904 jack_error("Cannot open default device"); 00905 return -1; 00906 } 00907 } 00908 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) { 00909 jack_error("Cannot get device name from device ID"); 00910 return -1; 00911 } 00912 00913 } else { 00914 00915 // Creates aggregate device 00916 AudioDeviceID captureID, playbackID; 00917 00918 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { 00919 jack_log("Will take default input"); 00920 if (GetDefaultInputDevice(&captureID) != noErr) { 00921 jack_error("Cannot open default input device"); 00922 return -1; 00923 } 00924 } 00925 00926 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { 00927 jack_log("Will take default output"); 00928 if (GetDefaultOutputDevice(&playbackID) != noErr) { 00929 jack_error("Cannot open default output device"); 00930 return -1; 00931 } 00932 } 00933 00934 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) 00935 return -1; 00936 } 00937 00938 // Capture only 00939 } else if (strcmp(capture_driver_uid, "") != 0) { 00940 jack_log("JackCoreAudioDriver::Open capture only"); 00941 if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) { 00942 jack_log("Will take default input"); 00943 if (GetDefaultInputDevice(&fDeviceID) != noErr) { 00944 jack_error("Cannot open default input device"); 00945 return -1; 00946 } 00947 } 00948 if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) { 00949 jack_error("Cannot get device name from device ID"); 00950 return -1; 00951 } 00952 00953 // Playback only 00954 } else if (strcmp(playback_driver_uid, "") != 0) { 00955 jack_log("JackCoreAudioDriver::Open playback only"); 00956 if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { 00957 jack_log("Will take default output"); 00958 if (GetDefaultOutputDevice(&fDeviceID) != noErr) { 00959 jack_error("Cannot open default output device"); 00960 return -1; 00961 } 00962 } 00963 if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) { 00964 jack_error("Cannot get device name from device ID"); 00965 return -1; 00966 } 00967 00968 // Use default driver in duplex mode 00969 } else { 00970 jack_log("JackCoreAudioDriver::Open default driver"); 00971 if (GetDefaultDevice(&fDeviceID) != noErr) { 00972 jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); 00973 00974 // Creates aggregate device 00975 AudioDeviceID captureID, playbackID; 00976 00977 if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { 00978 jack_log("Will take default input"); 00979 if (GetDefaultInputDevice(&captureID) != noErr) { 00980 jack_error("Cannot open default input device"); 00981 return -1; 00982 } 00983 } 00984 00985 if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { 00986 jack_log("Will take default output"); 00987 if (GetDefaultOutputDevice(&playbackID) != noErr) { 00988 jack_error("Cannot open default output device"); 00989 return -1; 00990 } 00991 } 00992 00993 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) 00994 return -1; 00995 } 00996 } 00997 00998 if (fHogged) { 00999 if (TakeHog()) { 01000 jack_info("Device = %ld has been hogged", fDeviceID); 01001 } 01002 } 01003 01004 return 0; 01005 } 01006 01007 /* 01008 Return the max possible input channels in in_nChannels and output channels in out_nChannels. 01009 */ 01010 int JackCoreAudioDriver::SetupChannels(bool capturing, bool playing, int& inchannels, int& outchannels, int& in_nChannels, int& out_nChannels, bool strict) 01011 { 01012 OSStatus err = noErr; 01013 01014 if (capturing) { 01015 err = GetTotalChannels(fDeviceID, in_nChannels, true); 01016 if (err != noErr) { 01017 jack_error("Cannot get input channel number"); 01018 printError(err); 01019 return -1; 01020 } else { 01021 jack_log("Max input channels : %d", in_nChannels); 01022 } 01023 } 01024 01025 if (playing) { 01026 err = GetTotalChannels(fDeviceID, out_nChannels, false); 01027 if (err != noErr) { 01028 jack_error("Cannot get output channel number"); 01029 printError(err); 01030 return -1; 01031 } else { 01032 jack_log("Max output channels : %d", out_nChannels); 01033 } 01034 } 01035 01036 if (inchannels > in_nChannels) { 01037 jack_error("This device hasn't required input channels inchannels = %d in_nChannels = %d", inchannels, in_nChannels); 01038 if (strict) 01039 return -1; 01040 } 01041 01042 if (outchannels > out_nChannels) { 01043 jack_error("This device hasn't required output channels outchannels = %d out_nChannels = %d", outchannels, out_nChannels); 01044 if (strict) 01045 return -1; 01046 } 01047 01048 if (inchannels == -1) { 01049 jack_log("Setup max in channels = %d", in_nChannels); 01050 inchannels = in_nChannels; 01051 } 01052 01053 if (outchannels == -1) { 01054 jack_log("Setup max out channels = %d", out_nChannels); 01055 outchannels = out_nChannels; 01056 } 01057 01058 return 0; 01059 } 01060 01061 int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size) 01062 { 01063 // Setting buffer size 01064 UInt32 outSize = sizeof(UInt32); 01065 OSStatus err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size); 01066 if (err != noErr) { 01067 jack_error("Cannot set buffer size %ld", buffer_size); 01068 printError(err); 01069 return -1; 01070 } 01071 01072 return 0; 01073 } 01074 01075 int JackCoreAudioDriver::SetupSampleRate(jack_nframes_t samplerate) 01076 { 01077 return SetupSampleRateAux(fDeviceID, samplerate); 01078 } 01079 01080 int JackCoreAudioDriver::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframes_t samplerate) 01081 { 01082 OSStatus err = noErr; 01083 UInt32 outSize; 01084 Float64 sampleRate; 01085 01086 // Get sample rate 01087 outSize = sizeof(Float64); 01088 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); 01089 if (err != noErr) { 01090 jack_error("Cannot get current sample rate"); 01091 printError(err); 01092 return -1; 01093 } else { 01094 jack_log("Current sample rate = %f", sampleRate); 01095 } 01096 01097 // If needed, set new sample rate 01098 if (samplerate != (jack_nframes_t)sampleRate) { 01099 sampleRate = (Float64)samplerate; 01100 01101 // To get SR change notification 01102 err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this); 01103 if (err != noErr) { 01104 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate"); 01105 printError(err); 01106 return -1; 01107 } 01108 err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate); 01109 if (err != noErr) { 01110 jack_error("Cannot set sample rate = %ld", samplerate); 01111 printError(err); 01112 return -1; 01113 } 01114 01115 // Waiting for SR change notification 01116 int count = 0; 01117 while (!fState && count++ < WAIT_COUNTER) { 01118 usleep(100000); 01119 jack_log("Wait count = %d", count); 01120 } 01121 01122 // Check new sample rate 01123 outSize = sizeof(Float64); 01124 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); 01125 if (err != noErr) { 01126 jack_error("Cannot get current sample rate"); 01127 printError(err); 01128 } else { 01129 jack_log("Checked sample rate = %f", sampleRate); 01130 } 01131 01132 // Remove SR change notification 01133 AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); 01134 } 01135 01136 return 0; 01137 } 01138 01139 int JackCoreAudioDriver::OpenAUHAL(bool capturing, 01140 bool playing, 01141 int inchannels, 01142 int outchannels, 01143 int in_nChannels, 01144 int out_nChannels, 01145 jack_nframes_t buffer_size, 01146 jack_nframes_t samplerate) 01147 { 01148 ComponentResult err1; 01149 UInt32 enableIO; 01150 AudioStreamBasicDescription srcFormat, dstFormat; 01151 AudioDeviceID currAudioDeviceID; 01152 UInt32 size; 01153 01154 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); 01155 01156 if (inchannels == 0 && outchannels == 0) { 01157 jack_error("No input and output channels..."); 01158 return -1; 01159 } 01160 01161 // AUHAL 01162 ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; 01163 Component HALOutput = FindNextComponent(NULL, &cd); 01164 01165 err1 = OpenAComponent(HALOutput, &fAUHAL); 01166 if (err1 != noErr) { 01167 jack_error("Error calling OpenAComponent"); 01168 printError(err1); 01169 goto error; 01170 } 01171 01172 err1 = AudioUnitInitialize(fAUHAL); 01173 if (err1 != noErr) { 01174 jack_error("Cannot initialize AUHAL unit"); 01175 printError(err1); 01176 goto error; 01177 } 01178 01179 // Start I/O 01180 if (capturing && inchannels > 0) { 01181 enableIO = 1; 01182 jack_log("Setup AUHAL input on"); 01183 } else { 01184 enableIO = 0; 01185 jack_log("Setup AUHAL input off"); 01186 } 01187 01188 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); 01189 if (err1 != noErr) { 01190 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); 01191 printError(err1); 01192 goto error; 01193 } 01194 01195 if (playing && outchannels > 0) { 01196 enableIO = 1; 01197 jack_log("Setup AUHAL output on"); 01198 } else { 01199 enableIO = 0; 01200 jack_log("Setup AUHAL output off"); 01201 } 01202 01203 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); 01204 if (err1 != noErr) { 01205 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); 01206 printError(err1); 01207 goto error; 01208 } 01209 01210 size = sizeof(AudioDeviceID); 01211 err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size); 01212 if (err1 != noErr) { 01213 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice"); 01214 printError(err1); 01215 goto error; 01216 } else { 01217 jack_log("AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID); 01218 } 01219 01220 // Setup up choosen device, in both input and output cases 01221 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID)); 01222 if (err1 != noErr) { 01223 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice"); 01224 printError(err1); 01225 goto error; 01226 } 01227 01228 // Set buffer size 01229 if (capturing && inchannels > 0) { 01230 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32)); 01231 if (err1 != noErr) { 01232 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); 01233 printError(err1); 01234 goto error; 01235 } 01236 } 01237 01238 if (playing && outchannels > 0) { 01239 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&buffer_size, sizeof(UInt32)); 01240 if (err1 != noErr) { 01241 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice"); 01242 printError(err1); 01243 goto error; 01244 } 01245 } 01246 01247 // Setup channel map 01248 if (capturing && inchannels > 0 && inchannels < in_nChannels) { 01249 SInt32 chanArr[in_nChannels]; 01250 for (int i = 0; i < in_nChannels; i++) { 01251 chanArr[i] = -1; 01252 } 01253 for (int i = 0; i < inchannels; i++) { 01254 chanArr[i] = i; 01255 } 01256 AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels); 01257 if (err1 != noErr) { 01258 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1"); 01259 printError(err1); 01260 goto error; 01261 } 01262 } 01263 01264 if (playing && outchannels > 0 && outchannels < out_nChannels) { 01265 SInt32 chanArr[out_nChannels]; 01266 for (int i = 0; i < out_nChannels; i++) { 01267 chanArr[i] = -1; 01268 } 01269 for (int i = 0; i < outchannels; i++) { 01270 chanArr[i] = i; 01271 } 01272 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels); 01273 if (err1 != noErr) { 01274 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0"); 01275 printError(err1); 01276 goto error; 01277 } 01278 } 01279 01280 // Setup stream converters 01281 if (capturing && inchannels > 0) { 01282 01283 size = sizeof(AudioStreamBasicDescription); 01284 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &size); 01285 if (err1 != noErr) { 01286 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); 01287 printError(err1); 01288 goto error; 01289 } 01290 PrintStreamDesc(&srcFormat); 01291 01292 jack_log("Setup AUHAL input stream converter SR = %ld", samplerate); 01293 srcFormat.mSampleRate = samplerate; 01294 srcFormat.mFormatID = kAudioFormatLinearPCM; 01295 srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; 01296 srcFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t); 01297 srcFormat.mFramesPerPacket = 1; 01298 srcFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t); 01299 srcFormat.mChannelsPerFrame = inchannels; 01300 srcFormat.mBitsPerChannel = 32; 01301 PrintStreamDesc(&srcFormat); 01302 01303 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription)); 01304 if (err1 != noErr) { 01305 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); 01306 printError(err1); 01307 goto error; 01308 } 01309 } 01310 01311 if (playing && outchannels > 0) { 01312 01313 size = sizeof(AudioStreamBasicDescription); 01314 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &size); 01315 if (err1 != noErr) { 01316 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); 01317 printError(err1); 01318 goto error; 01319 } 01320 PrintStreamDesc(&dstFormat); 01321 01322 jack_log("Setup AUHAL output stream converter SR = %ld", samplerate); 01323 dstFormat.mSampleRate = samplerate; 01324 dstFormat.mFormatID = kAudioFormatLinearPCM; 01325 dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; 01326 dstFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t); 01327 dstFormat.mFramesPerPacket = 1; 01328 dstFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t); 01329 dstFormat.mChannelsPerFrame = outchannels; 01330 dstFormat.mBitsPerChannel = 32; 01331 PrintStreamDesc(&dstFormat); 01332 01333 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription)); 01334 if (err1 != noErr) { 01335 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); 01336 printError(err1); 01337 goto error; 01338 } 01339 } 01340 01341 // Setup callbacks 01342 if (inchannels > 0 && outchannels == 0) { 01343 AURenderCallbackStruct output; 01344 output.inputProc = Render; 01345 output.inputProcRefCon = this; 01346 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output)); 01347 if (err1 != noErr) { 01348 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1"); 01349 printError(err1); 01350 goto error; 01351 } 01352 } else { 01353 AURenderCallbackStruct output; 01354 output.inputProc = Render; 01355 output.inputProcRefCon = this; 01356 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output)); 01357 if (err1 != noErr) { 01358 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0"); 01359 printError(err1); 01360 goto error; 01361 } 01362 } 01363 01364 return 0; 01365 01366 error: 01367 CloseAUHAL(); 01368 return -1; 01369 } 01370 01371 int JackCoreAudioDriver::SetupBuffers(int inchannels) 01372 { 01373 // Prepare buffers 01374 fJackInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer)); 01375 fJackInputData->mNumberBuffers = inchannels; 01376 for (int i = 0; i < inchannels; i++) { 01377 fJackInputData->mBuffers[i].mNumberChannels = 1; 01378 fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(jack_default_audio_sample_t); 01379 } 01380 return 0; 01381 } 01382 01383 void JackCoreAudioDriver::DisposeBuffers() 01384 { 01385 if (fJackInputData) { 01386 free(fJackInputData); 01387 fJackInputData = 0; 01388 } 01389 } 01390 01391 void JackCoreAudioDriver::CloseAUHAL() 01392 { 01393 AudioUnitUninitialize(fAUHAL); 01394 CloseComponent(fAUHAL); 01395 } 01396 01397 int JackCoreAudioDriver::AddListeners() 01398 { 01399 OSStatus err = noErr; 01400 01401 // Add listeners 01402 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this); 01403 if (err != noErr) { 01404 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload"); 01405 printError(err); 01406 return -1; 01407 } 01408 01409 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); 01410 if (err != noErr) { 01411 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); 01412 printError(err); 01413 return -1; 01414 } 01415 01416 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this); 01417 if (err != noErr) { 01418 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate"); 01419 printError(err); 01420 return -1; 01421 } 01422 01423 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this); 01424 if (err != noErr) { 01425 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning"); 01426 printError(err); 01427 return -1; 01428 } 01429 01430 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this); 01431 if (err != noErr) { 01432 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration"); 01433 printError(err); 01434 return -1; 01435 } 01436 01437 err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this); 01438 if (err != noErr) { 01439 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration"); 01440 printError(err); 01441 return -1; 01442 } 01443 01444 if (!fEngineControl->fSyncMode && fIOUsage != 1.f) { 01445 UInt32 outSize = sizeof(float); 01446 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyIOCycleUsage, outSize, &fIOUsage); 01447 if (err != noErr) { 01448 jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage"); 01449 printError(err); 01450 } 01451 } 01452 01453 return 0; 01454 } 01455 01456 void JackCoreAudioDriver::RemoveListeners() 01457 { 01458 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback); 01459 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback); 01460 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback); 01461 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback); 01462 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); 01463 AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); 01464 } 01465 01466 int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, 01467 jack_nframes_t samplerate, 01468 bool capturing, 01469 bool playing, 01470 int inchannels, 01471 int outchannels, 01472 bool monitor, 01473 const char* capture_driver_uid, 01474 const char* playback_driver_uid, 01475 jack_nframes_t capture_latency, 01476 jack_nframes_t playback_latency, 01477 int async_output_latency, 01478 int computation_grain, 01479 bool hogged, 01480 bool clock_drift) 01481 { 01482 int in_nChannels = 0; 01483 int out_nChannels = 0; 01484 char capture_driver_name[256]; 01485 char playback_driver_name[256]; 01486 01487 // Keep initial state 01488 strcpy(fCaptureUID, capture_driver_uid); 01489 strcpy(fPlaybackUID, playback_driver_uid); 01490 fCaptureLatency = capture_latency; 01491 fPlaybackLatency = playback_latency; 01492 fIOUsage = float(async_output_latency) / 100.f; 01493 fComputationGrain = float(computation_grain) / 100.f; 01494 fHogged = hogged; 01495 fClockDriftCompensate = clock_drift; 01496 01497 SInt32 major; 01498 SInt32 minor; 01499 Gestalt(gestaltSystemVersionMajor, &major); 01500 Gestalt(gestaltSystemVersionMinor, &minor); 01501 01502 // Starting with 10.6 systems, the HAL notification thread is created internally 01503 if (major == 10 && minor >= 6) { 01504 CFRunLoopRef theRunLoop = NULL; 01505 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; 01506 OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); 01507 if (osErr != noErr) { 01508 jack_error("JackCoreAudioDriver::Open kAudioHardwarePropertyRunLoop error"); 01509 printError(osErr); 01510 } 01511 } 01512 01513 if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name, samplerate) < 0) 01514 goto error; 01515 01516 // Generic JackAudioDriver Open 01517 if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) 01518 goto error; 01519 01520 if (SetupChannels(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, true) < 0) 01521 goto error; 01522 01523 if (SetupBufferSize(buffer_size) < 0) 01524 goto error; 01525 01526 if (SetupSampleRate(samplerate) < 0) 01527 goto error; 01528 01529 if (OpenAUHAL(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, buffer_size, samplerate) < 0) 01530 goto error; 01531 01532 if (capturing && inchannels > 0) 01533 if (SetupBuffers(inchannels) < 0) 01534 goto error; 01535 01536 if (AddListeners() < 0) 01537 goto error; 01538 01539 // Core driver may have changed the in/out values 01540 fCaptureChannels = inchannels; 01541 fPlaybackChannels = outchannels; 01542 return noErr; 01543 01544 error: 01545 Close(); 01546 return -1; 01547 } 01548 01549 int JackCoreAudioDriver::Close() 01550 { 01551 jack_log("JackCoreAudioDriver::Close"); 01552 Stop(); 01553 01554 // Generic audio driver close 01555 int res = JackAudioDriver::Close(); 01556 01557 RemoveListeners(); 01558 DisposeBuffers(); 01559 CloseAUHAL(); 01560 DestroyAggregateDevice(); 01561 return res; 01562 } 01563 01564 int JackCoreAudioDriver::Attach() 01565 { 01566 OSStatus err; 01567 JackPort* port; 01568 jack_port_id_t port_index; 01569 UInt32 size; 01570 Boolean isWritable; 01571 char channel_name[64]; 01572 char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; 01573 char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; 01574 jack_latency_range_t range; 01575 01576 jack_log("JackCoreAudioDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); 01577 01578 for (int i = 0; i < fCaptureChannels; i++) { 01579 01580 err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable); 01581 if (err != noErr) 01582 jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error"); 01583 if (err == noErr && size > 0) { 01584 err = AudioDeviceGetProperty(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, channel_name); 01585 if (err != noErr) 01586 jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error"); 01587 snprintf(alias, sizeof(alias) - 1, "%s:%s:out_%s%u", fAliasName, fCaptureDriverName, channel_name, i + 1); 01588 } else { 01589 snprintf(alias, sizeof(alias) - 1, "%s:%s:out%u", fAliasName, fCaptureDriverName, i + 1); 01590 } 01591 01592 snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1); 01593 01594 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { 01595 jack_error("Cannot register port for %s", name); 01596 return -1; 01597 } 01598 01599 size = sizeof(UInt32); 01600 UInt32 value1 = 0; 01601 UInt32 value2 = 0; 01602 err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1); 01603 if (err != noErr) 01604 jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error"); 01605 err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2); 01606 if (err != noErr) 01607 jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error"); 01608 01609 port = fGraphManager->GetPort(port_index); 01610 port->SetAlias(alias); 01611 range.min = range.max = fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency; 01612 port->SetLatencyRange(JackCaptureLatency, &range); 01613 fCapturePortList[i] = port_index; 01614 } 01615 01616 for (int i = 0; i < fPlaybackChannels; i++) { 01617 01618 err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, &isWritable); 01619 if (err != noErr) 01620 jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error"); 01621 if (err == noErr && size > 0) { 01622 err = AudioDeviceGetProperty(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, channel_name); 01623 if (err != noErr) 01624 jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error"); 01625 snprintf(alias, sizeof(alias) - 1, "%s:%s:in_%s%u", fAliasName, fPlaybackDriverName, channel_name, i + 1); 01626 } else { 01627 snprintf(alias, sizeof(alias) - 1, "%s:%s:in%u", fAliasName, fPlaybackDriverName, i + 1); 01628 } 01629 01630 snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1); 01631 01632 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { 01633 jack_error("Cannot register port for %s", name); 01634 return -1; 01635 } 01636 01637 size = sizeof(UInt32); 01638 UInt32 value1 = 0; 01639 UInt32 value2 = 0; 01640 err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyLatency, &size, &value1); 01641 if (err != noErr) 01642 jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error"); 01643 err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2); 01644 if (err != noErr) 01645 jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error"); 01646 01647 port = fGraphManager->GetPort(port_index); 01648 port->SetAlias(alias); 01649 // Add more latency if "async" mode is used... 01650 range.min = range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize * fIOUsage) + value1 + value2 + fPlaybackLatency; 01651 port->SetLatencyRange(JackPlaybackLatency, &range); 01652 fPlaybackPortList[i] = port_index; 01653 01654 // Monitor ports 01655 if (fWithMonitorPorts) { 01656 jack_log("Create monitor port"); 01657 snprintf(name, sizeof(name) - 1, "%s:monitor_%u", fClientControl.fName, i + 1); 01658 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { 01659 jack_error("Cannot register monitor port for %s", name); 01660 return -1; 01661 } else { 01662 port = fGraphManager->GetPort(port_index); 01663 range.min = range.max = fEngineControl->fBufferSize; 01664 port->SetLatencyRange(JackCaptureLatency, &range); 01665 fMonitorPortList[i] = port_index; 01666 } 01667 } 01668 } 01669 01670 // Input buffers do no change : prepare them only once 01671 for (int i = 0; i < fCaptureChannels; i++) { 01672 fJackInputData->mBuffers[i].mData = GetInputBuffer(i); 01673 } 01674 01675 return 0; 01676 } 01677 01678 int JackCoreAudioDriver::Start() 01679 { 01680 jack_log("JackCoreAudioDriver::Start"); 01681 if (JackAudioDriver::Start() >= 0) { 01682 OSStatus err = AudioOutputUnitStart(fAUHAL); 01683 if (err == noErr) { 01684 01685 // Waiting for Measure callback to be called (= driver has started) 01686 fState = false; 01687 int count = 0; 01688 while (!fState && count++ < WAIT_COUNTER) { 01689 usleep(100000); 01690 jack_log("JackCoreAudioDriver::Start wait count = %d", count); 01691 } 01692 01693 if (count < WAIT_COUNTER) { 01694 jack_info("CoreAudio driver is running..."); 01695 return 0; 01696 } 01697 01698 jack_error("CoreAudio driver cannot start..."); 01699 } 01700 JackAudioDriver::Stop(); 01701 } 01702 return -1; 01703 } 01704 01705 int JackCoreAudioDriver::Stop() 01706 { 01707 jack_log("JackCoreAudioDriver::Stop"); 01708 int res = (AudioOutputUnitStop(fAUHAL) == noErr) ? 0 : -1; 01709 if (JackAudioDriver::Stop() < 0) { 01710 res = -1; 01711 } 01712 return res; 01713 } 01714 01715 int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size) 01716 { 01717 OSStatus err; 01718 UInt32 outSize = sizeof(UInt32); 01719 01720 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size); 01721 if (err != noErr) { 01722 jack_error("Cannot set buffer size %ld", buffer_size); 01723 printError(err); 01724 return -1; 01725 } 01726 01727 JackAudioDriver::SetBufferSize(buffer_size); // never fails 01728 01729 // Input buffers do no change : prepare them only once 01730 for (int i = 0; i < fCaptureChannels; i++) { 01731 fJackInputData->mBuffers[i].mNumberChannels = 1; 01732 fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(jack_default_audio_sample_t); 01733 fJackInputData->mBuffers[i].mData = GetInputBuffer(i); 01734 } 01735 01736 return 0; 01737 } 01738 01739 bool JackCoreAudioDriver::TakeHogAux(AudioDeviceID deviceID, bool isInput) 01740 { 01741 pid_t hog_pid; 01742 OSStatus err; 01743 01744 UInt32 propSize = sizeof(hog_pid); 01745 err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyHogMode, &propSize, &hog_pid); 01746 if (err) { 01747 jack_error("Cannot read hog state..."); 01748 printError(err); 01749 } 01750 01751 if (hog_pid != getpid()) { 01752 hog_pid = getpid(); 01753 err = AudioDeviceSetProperty(deviceID, 0, 0, isInput, kAudioDevicePropertyHogMode, propSize, &hog_pid); 01754 if (err != noErr) { 01755 jack_error("Can't hog device = %d because it's being hogged by another program or cannot be hogged", deviceID); 01756 return false; 01757 } 01758 } 01759 01760 return true; 01761 } 01762 01763 bool JackCoreAudioDriver::TakeHog() 01764 { 01765 OSStatus err = noErr; 01766 AudioObjectID sub_device[32]; 01767 UInt32 outSize = sizeof(sub_device); 01768 err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); 01769 01770 if (err != noErr) { 01771 jack_log("Device does not have subdevices"); 01772 return TakeHogAux(fDeviceID, true); 01773 } else { 01774 int num_devices = outSize / sizeof(AudioObjectID); 01775 jack_log("Device does has %d subdevices", num_devices); 01776 for (int i = 0; i < num_devices; i++) { 01777 if (!TakeHogAux(sub_device[i], true)) { 01778 return false; 01779 } 01780 } 01781 return true; 01782 } 01783 } 01784 01785 bool JackCoreAudioDriver::IsAggregateDevice(AudioDeviceID device) 01786 { 01787 UInt32 deviceType, outSize = sizeof(UInt32); 01788 OSStatus err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyTransportType, &outSize, &deviceType); 01789 01790 if (err != noErr) { 01791 jack_log("JackCoreAudioDriver::IsAggregateDevice kAudioDevicePropertyTransportType error"); 01792 return false; 01793 } else { 01794 return (deviceType == kAudioDeviceTransportTypeAggregate); 01795 } 01796 } 01797 01798 01799 } // end of namespace 01800 01801 01802 #ifdef __cplusplus 01803 extern "C" 01804 { 01805 #endif 01806 01807 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() 01808 { 01809 jack_driver_desc_t *desc; 01810 unsigned int i; 01811 desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t)); 01812 01813 strcpy(desc->name, "coreaudio"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 01814 strcpy(desc->desc, "Apple CoreAudio API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 01815 01816 desc->nparams = 17; 01817 desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); 01818 01819 i = 0; 01820 strcpy(desc->params[i].name, "channels"); 01821 desc->params[i].character = 'c'; 01822 desc->params[i].type = JackDriverParamInt; 01823 desc->params[i].value.ui = -1; 01824 strcpy(desc->params[i].short_desc, "Maximum number of channels"); 01825 strcpy(desc->params[i].long_desc, "Maximum number of channels. If -1, max possible number of channels will be used"); 01826 01827 i++; 01828 strcpy(desc->params[i].name, "inchannels"); 01829 desc->params[i].character = 'i'; 01830 desc->params[i].type = JackDriverParamInt; 01831 desc->params[i].value.ui = -1; 01832 strcpy(desc->params[i].short_desc, "Maximum number of input channels"); 01833 strcpy(desc->params[i].long_desc, "Maximum number of input channels. If -1, max possible number of input channels will be used"); 01834 01835 i++; 01836 strcpy(desc->params[i].name, "outchannels"); 01837 desc->params[i].character = 'o'; 01838 desc->params[i].type = JackDriverParamInt; 01839 desc->params[i].value.ui = -1; 01840 strcpy(desc->params[i].short_desc, "Maximum number of output channels"); 01841 strcpy(desc->params[i].long_desc, "Maximum number of output channels. If -1, max possible number of output channels will be used"); 01842 01843 i++; 01844 strcpy(desc->params[i].name, "capture"); 01845 desc->params[i].character = 'C'; 01846 desc->params[i].type = JackDriverParamString; 01847 strcpy(desc->params[i].short_desc, "Input CoreAudio device name"); 01848 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01849 01850 i++; 01851 strcpy(desc->params[i].name, "playback"); 01852 desc->params[i].character = 'P'; 01853 desc->params[i].type = JackDriverParamString; 01854 strcpy(desc->params[i].short_desc, "Output CoreAudio device name"); 01855 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01856 01857 i++; 01858 strcpy (desc->params[i].name, "monitor"); 01859 desc->params[i].character = 'm'; 01860 desc->params[i].type = JackDriverParamBool; 01861 desc->params[i].value.i = 0; 01862 strcpy(desc->params[i].short_desc, "Provide monitor ports for the output"); 01863 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01864 01865 i++; 01866 strcpy(desc->params[i].name, "duplex"); 01867 desc->params[i].character = 'D'; 01868 desc->params[i].type = JackDriverParamBool; 01869 desc->params[i].value.i = TRUE; 01870 strcpy(desc->params[i].short_desc, "Provide both capture and playback ports"); 01871 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01872 01873 i++; 01874 strcpy(desc->params[i].name, "rate"); 01875 desc->params[i].character = 'r'; 01876 desc->params[i].type = JackDriverParamUInt; 01877 desc->params[i].value.ui = 44100U; 01878 strcpy(desc->params[i].short_desc, "Sample rate"); 01879 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01880 01881 i++; 01882 strcpy(desc->params[i].name, "period"); 01883 desc->params[i].character = 'p'; 01884 desc->params[i].type = JackDriverParamUInt; 01885 desc->params[i].value.ui = 128U; 01886 strcpy(desc->params[i].short_desc, "Frames per period"); 01887 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01888 01889 i++; 01890 strcpy(desc->params[i].name, "device"); 01891 desc->params[i].character = 'd'; 01892 desc->params[i].type = JackDriverParamString; 01893 strcpy(desc->params[i].short_desc, "CoreAudio device name"); 01894 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01895 01896 i++; 01897 strcpy(desc->params[i].name, "input-latency"); 01898 desc->params[i].character = 'I'; 01899 desc->params[i].type = JackDriverParamUInt; 01900 desc->params[i].value.i = 0; 01901 strcpy(desc->params[i].short_desc, "Extra input latency (frames)"); 01902 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01903 01904 i++; 01905 strcpy(desc->params[i].name, "output-latency"); 01906 desc->params[i].character = 'O'; 01907 desc->params[i].type = JackDriverParamUInt; 01908 desc->params[i].value.i = 0; 01909 strcpy(desc->params[i].short_desc, "Extra output latency (frames)"); 01910 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01911 01912 i++; 01913 strcpy(desc->params[i].name, "list-devices"); 01914 desc->params[i].character = 'l'; 01915 desc->params[i].type = JackDriverParamBool; 01916 desc->params[i].value.i = FALSE; 01917 strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); 01918 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01919 01920 i++; 01921 strcpy(desc->params[i].name, "hog"); 01922 desc->params[i].character = 'H'; 01923 desc->params[i].type = JackDriverParamBool; 01924 desc->params[i].value.i = FALSE; 01925 strcpy(desc->params[i].short_desc, "Take exclusive access of the audio device"); 01926 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01927 01928 i++; 01929 strcpy(desc->params[i].name, "async-latency"); 01930 desc->params[i].character = 'L'; 01931 desc->params[i].type = JackDriverParamUInt; 01932 desc->params[i].value.i = 100; 01933 strcpy(desc->params[i].short_desc, "Extra output latency in asynchronous mode (percent)"); 01934 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01935 01936 i++; 01937 strcpy(desc->params[i].name, "grain"); 01938 desc->params[i].character = 'G'; 01939 desc->params[i].type = JackDriverParamUInt; 01940 desc->params[i].value.i = 100; 01941 strcpy(desc->params[i].short_desc, "Computation grain in RT thread (percent)"); 01942 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 01943 01944 i++; 01945 strcpy(desc->params[i].name, "clock-drift"); 01946 desc->params[i].character = 's'; 01947 desc->params[i].type = JackDriverParamBool; 01948 desc->params[i].value.i = FALSE; 01949 strcpy(desc->params[i].short_desc, "Clock drift compensation"); 01950 strcpy(desc->params[i].long_desc, "Whether to compensate clock drift in dynamically created aggregate device"); 01951 01952 return desc; 01953 } 01954 01955 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) 01956 { 01957 jack_nframes_t srate = 44100; 01958 jack_nframes_t frames_per_interrupt = 128; 01959 bool capture = false; 01960 bool playback = false; 01961 int chan_in = -1; // Default: if not explicitely set, then max possible will be used... 01962 int chan_out = -1; // Default: if not explicitely set, then max possible will be used... 01963 bool monitor = false; 01964 const char* capture_driver_uid = ""; 01965 const char* playback_driver_uid = ""; 01966 const JSList *node; 01967 const jack_driver_param_t *param; 01968 jack_nframes_t systemic_input_latency = 0; 01969 jack_nframes_t systemic_output_latency = 0; 01970 int async_output_latency = 100; 01971 int computation_grain = -1; 01972 bool hogged = false; 01973 bool clock_drift = false; 01974 01975 for (node = params; node; node = jack_slist_next(node)) { 01976 param = (const jack_driver_param_t *) node->data; 01977 01978 switch (param->character) { 01979 01980 case 'd': 01981 capture_driver_uid = param->value.str; 01982 playback_driver_uid = param->value.str; 01983 break; 01984 01985 case 'D': 01986 capture = true; 01987 playback = true; 01988 break; 01989 01990 case 'c': 01991 chan_in = chan_out = (int)param->value.ui; 01992 break; 01993 01994 case 'i': 01995 chan_in = (int)param->value.ui; 01996 break; 01997 01998 case 'o': 01999 chan_out = (int)param->value.ui; 02000 break; 02001 02002 case 'C': 02003 capture = true; 02004 if (strcmp(param->value.str, "none") != 0) { 02005 capture_driver_uid = param->value.str; 02006 } 02007 break; 02008 02009 case 'P': 02010 playback = true; 02011 if (strcmp(param->value.str, "none") != 0) { 02012 playback_driver_uid = param->value.str; 02013 } 02014 break; 02015 02016 case 'm': 02017 monitor = param->value.i; 02018 break; 02019 02020 case 'r': 02021 srate = param->value.ui; 02022 break; 02023 02024 case 'p': 02025 frames_per_interrupt = (unsigned int)param->value.ui; 02026 break; 02027 02028 case 'I': 02029 systemic_input_latency = param->value.ui; 02030 break; 02031 02032 case 'O': 02033 systemic_output_latency = param->value.ui; 02034 break; 02035 02036 case 'l': 02037 Jack::DisplayDeviceNames(); 02038 break; 02039 02040 case 'H': 02041 hogged = true; 02042 break; 02043 02044 case 'L': 02045 async_output_latency = param->value.ui; 02046 break; 02047 02048 case 'G': 02049 computation_grain = param->value.ui; 02050 break; 02051 02052 case 's': 02053 clock_drift = true; 02054 break; 02055 } 02056 } 02057 02058 /* duplex is the default */ 02059 if (!capture && !playback) { 02060 capture = true; 02061 playback = true; 02062 } 02063 02064 Jack::JackCoreAudioDriver* driver = new Jack::JackCoreAudioDriver("system", "coreaudio", engine, table); 02065 if (driver->Open(frames_per_interrupt, srate, capture, playback, chan_in, chan_out, monitor, capture_driver_uid, 02066 playback_driver_uid, systemic_input_latency, systemic_output_latency, async_output_latency, computation_grain, hogged, clock_drift) == 0) { 02067 return driver; 02068 } else { 02069 delete driver; 02070 return NULL; 02071 } 02072 } 02073 02074 #ifdef __cplusplus 02075 } 02076 #endif 02077 02078