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