Jack2  1.9.7
JackCoreAudioDriver.cpp
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