Jack2 1.9.6

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