Jack2 1.9.10

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 "JackLockedEngine.h"
00030 #include "JackAC3Encoder.h"
00031 
00032 #include <sstream>
00033 #include <iostream>
00034 #include <CoreServices/CoreServices.h>
00035 #include <CoreFoundation/CFNumber.h>
00036 
00037 namespace Jack
00038 {
00039 
00040 static void Print4CharCode(const char* msg, long c)
00041 {
00042     UInt32 __4CC_number = (c);
00043     char __4CC_string[5];
00044     *((SInt32*)__4CC_string) = EndianU32_NtoB(__4CC_number);
00045     __4CC_string[4] = 0;
00046     jack_log("%s'%s'", (msg), __4CC_string);
00047 }
00048 
00049 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
00050 {
00051     jack_log("- - - - - - - - - - - - - - - - - - - -");
00052     jack_log("  Sample Rate:%f", inDesc->mSampleRate);
00053     jack_log("  Format ID:%.*s", (int)sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
00054     jack_log("  Format Flags:%lX", inDesc->mFormatFlags);
00055     jack_log("  Bytes per Packet:%ld", inDesc->mBytesPerPacket);
00056     jack_log("  Frames per Packet:%ld", inDesc->mFramesPerPacket);
00057     jack_log("  Bytes per Frame:%ld", inDesc->mBytesPerFrame);
00058     jack_log("  Channels per Frame:%ld", inDesc->mChannelsPerFrame);
00059     jack_log("  Bits per Channel:%ld", inDesc->mBitsPerChannel);
00060     jack_log("- - - - - - - - - - - - - - - - - - - -");
00061 }
00062 
00063 static void printError(OSStatus err)
00064 {
00065     switch (err) {
00066         case kAudioHardwareNoError:
00067             jack_log("error code : kAudioHardwareNoError");
00068             break;
00069         case kAudioConverterErr_FormatNotSupported:
00070             jack_log("error code : kAudioConverterErr_FormatNotSupported");
00071             break;
00072         case kAudioConverterErr_OperationNotSupported:
00073             jack_log("error code : kAudioConverterErr_OperationNotSupported");
00074             break;
00075         case kAudioConverterErr_PropertyNotSupported:
00076             jack_log("error code : kAudioConverterErr_PropertyNotSupported");
00077             break;
00078         case kAudioConverterErr_InvalidInputSize:
00079             jack_log("error code : kAudioConverterErr_InvalidInputSize");
00080             break;
00081         case kAudioConverterErr_InvalidOutputSize:
00082             jack_log("error code : kAudioConverterErr_InvalidOutputSize");
00083             break;
00084         case kAudioConverterErr_UnspecifiedError:
00085             jack_log("error code : kAudioConverterErr_UnspecifiedError");
00086             break;
00087         case kAudioConverterErr_BadPropertySizeError:
00088             jack_log("error code : kAudioConverterErr_BadPropertySizeError");
00089             break;
00090         case kAudioConverterErr_RequiresPacketDescriptionsError:
00091             jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
00092             break;
00093         case kAudioConverterErr_InputSampleRateOutOfRange:
00094             jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
00095             break;
00096         case kAudioConverterErr_OutputSampleRateOutOfRange:
00097             jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
00098             break;
00099         case kAudioHardwareNotRunningError:
00100             jack_log("error code : kAudioHardwareNotRunningError");
00101             break;
00102         case kAudioHardwareUnknownPropertyError:
00103             jack_log("error code : kAudioHardwareUnknownPropertyError");
00104             break;
00105         case kAudioHardwareIllegalOperationError:
00106             jack_log("error code : kAudioHardwareIllegalOperationError");
00107             break;
00108         case kAudioHardwareBadDeviceError:
00109             jack_log("error code : kAudioHardwareBadDeviceError");
00110             break;
00111         case kAudioHardwareBadStreamError:
00112             jack_log("error code : kAudioHardwareBadStreamError");
00113             break;
00114         case kAudioDeviceUnsupportedFormatError:
00115             jack_log("error code : kAudioDeviceUnsupportedFormatError");
00116             break;
00117         case kAudioDevicePermissionsError:
00118             jack_log("error code : kAudioDevicePermissionsError");
00119             break;
00120         case kAudioHardwareBadObjectError:
00121             jack_log("error code : kAudioHardwareBadObjectError");
00122             break;
00123         case kAudioHardwareUnsupportedOperationError:
00124             jack_log("error code : kAudioHardwareUnsupportedOperationError");
00125             break;
00126         default:
00127             Print4CharCode("error code : unknown ", err);
00128             break;
00129     }
00130 }
00131 
00132 static bool CheckAvailableDeviceName(const char* device_name, AudioDeviceID* device_id)
00133 {
00134     UInt32 size;
00135     Boolean isWritable;
00136     int i, deviceNum;
00137     OSStatus err;
00138 
00139     err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
00140     if (err != noErr) {
00141         return false;
00142     }
00143 
00144     deviceNum = size / sizeof(AudioDeviceID);
00145     AudioDeviceID devices[deviceNum];
00146 
00147     err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
00148     if (err != noErr) {
00149         return false;
00150     }
00151 
00152     for (i = 0; i < deviceNum; i++) {
00153         char device_name_aux[256];
00154 
00155         size = 256;
00156         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name_aux);
00157         if (err != noErr) {
00158             return false;
00159         }
00160 
00161         if (strncmp(device_name_aux, device_name, strlen(device_name)) == 0) {
00162             *device_id = devices[i];
00163             return true;
00164         }
00165     }
00166 
00167     return false;
00168 }
00169 
00170 static bool CheckAvailableDevice(AudioDeviceID device_id)
00171 {
00172     UInt32 size;
00173     Boolean isWritable;
00174     int i, deviceNum;
00175     OSStatus err;
00176 
00177     err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
00178     if (err != noErr) {
00179         return false;
00180     }
00181 
00182     deviceNum = size / sizeof(AudioDeviceID);
00183     AudioDeviceID devices[deviceNum];
00184 
00185     err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
00186     if (err != noErr) {
00187         return false;
00188     }
00189 
00190     for (i = 0; i < deviceNum; i++) {
00191         if (device_id == devices[i]) {
00192             return true;
00193         }
00194     }
00195 
00196     return false;
00197 }
00198 
00199 static OSStatus DisplayDeviceNames()
00200 {
00201     UInt32 size;
00202     Boolean isWritable;
00203     int i, deviceNum;
00204     OSStatus err;
00205     CFStringRef UIname;
00206 
00207     err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
00208     if (err != noErr) {
00209         return err;
00210     }
00211 
00212     deviceNum = size / sizeof(AudioDeviceID);
00213     AudioDeviceID devices[deviceNum];
00214 
00215     err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
00216     if (err != noErr) {
00217         return err;
00218     }
00219 
00220     for (i = 0; i < deviceNum; i++) {
00221         char device_name[256];
00222         char internal_name[256];
00223 
00224         size = sizeof(CFStringRef);
00225         UIname = NULL;
00226         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
00227         if (err == noErr) {
00228             CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
00229         } else {
00230             goto error;
00231         }
00232 
00233         size = 256;
00234         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
00235         if (err != noErr) {
00236             return err;
00237         }
00238 
00239         jack_info("Device ID = \'%d\' name = \'%s\', internal name = \'%s\' (to be used as -C, -P, or -d parameter)", devices[i], device_name, internal_name);
00240     }
00241 
00242     return noErr;
00243 
00244 error:
00245     if (UIname != NULL) {
00246         CFRelease(UIname);
00247     }
00248     return err;
00249 }
00250 
00251 static CFStringRef GetDeviceName(AudioDeviceID id)
00252 {
00253     UInt32 size = sizeof(CFStringRef);
00254     CFStringRef UIname;
00255     OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
00256     return (err == noErr) ? UIname : NULL;
00257 }
00258 
00259 static void ParseChannelList(const string& list, vector<int>& result, int max_chan)
00260 {
00261     stringstream ss(list);
00262     string token;
00263     int chan;
00264   
00265     while (ss >> token) {
00266         istringstream ins;
00267         ins.str(token);
00268         ins >> chan;
00269         if (chan < 0 || chan >= max_chan) {
00270             jack_error("Ignore incorrect channel mapping value = %d", chan);
00271         } else {
00272             result.push_back(chan);
00273         }
00274     }
00275 }
00276 
00277 OSStatus JackCoreAudioDriver::Render(void* inRefCon,
00278                                      AudioUnitRenderActionFlags* ioActionFlags,
00279                                      const AudioTimeStamp* inTimeStamp,
00280                                      UInt32 inBusNumber,
00281                                      UInt32 inNumberFrames,
00282                                      AudioBufferList* ioData)
00283 {
00284     return static_cast<JackCoreAudioDriver*>(inRefCon)->Render(ioActionFlags, inTimeStamp, ioData);
00285 }
00286 
00287 OSStatus JackCoreAudioDriver::Render(AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp,  AudioBufferList* ioData)
00288 {
00289     fActionFags = ioActionFlags;
00290     fCurrentTime = inTimeStamp;
00291     fDriverOutputData = ioData;
00292 
00293     // Setup threaded based log function et get RT thread parameters once...
00294     if (set_threaded_log_function()) {
00295 
00296         jack_log("JackCoreAudioDriver::Render : set_threaded_log_function");
00297         JackMachThread::GetParams(pthread_self(), &fEngineControl->fPeriod, &fEngineControl->fComputation, &fEngineControl->fConstraint);
00298 
00299         if (fComputationGrain > 0) {
00300             jack_log("JackCoreAudioDriver::Render : RT thread computation setup to %d percent of period", int(fComputationGrain * 100));
00301             fEngineControl->fComputation = fEngineControl->fPeriod * fComputationGrain;
00302         }
00303     }
00304 
00305     // Signal waiting start function...
00306     fState = true;
00307 
00308     CycleTakeBeginTime();
00309 
00310     if (Process() < 0) {
00311         jack_error("Process error, stopping driver");
00312         NotifyFailure(JackFailure | JackBackendError, "Process error, stopping driver");    // Message length limited to JACK_MESSAGE_SIZE
00313         Stop();
00314         kill(JackTools::GetPID(), SIGINT);
00315         return kAudioHardwareUnsupportedOperationError;
00316     } else {
00317         return noErr;
00318     }
00319 }
00320 
00321 int JackCoreAudioDriver::Read()
00322 {
00323     if (fCaptureChannels > 0)  { // Calling AudioUnitRender with no input returns a '????' error (callback setting issue ??), so hack to avoid it here...
00324         return (AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData) == noErr) ? 0 : -1;
00325     } else {
00326         return 0;
00327     }
00328 }
00329 
00330 int JackCoreAudioDriver::Write()
00331 {
00332     int size = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize;
00333     
00334     if (fAC3Encoder) {
00335     
00336         // AC3 encoding and SPDIF write
00337         jack_default_audio_sample_t* AC3_inputs[MAX_AC3_CHANNELS];
00338         jack_default_audio_sample_t* AC3_outputs[2];
00339         for (int i = 0; i < fPlaybackChannels; i++) {
00340             AC3_inputs[i] = GetOutputBuffer(i);
00341             // If not connected, clear the buffer
00342             if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) == 0) {
00343                 memset(AC3_inputs[i], 0, size);
00344             }
00345         }
00346         AC3_outputs[0] = (jack_default_audio_sample_t*)fDriverOutputData->mBuffers[0].mData;
00347         AC3_outputs[1] = (jack_default_audio_sample_t*)fDriverOutputData->mBuffers[1].mData;
00348         fAC3Encoder->Process(AC3_inputs, AC3_outputs, fEngineControl->fBufferSize);
00349         
00350     } else {
00351        
00352         // Standard write
00353         for (int i = 0; i < fPlaybackChannels; i++) {
00354             if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
00355                 jack_default_audio_sample_t* buffer = GetOutputBuffer(i);
00356                 memcpy((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, buffer, size);
00357                 // Monitor ports
00358                 if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) {
00359                     memcpy(GetMonitorBuffer(i), buffer, size);
00360                 }
00361             } else {
00362                 memset((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, 0, size);
00363             }
00364         }
00365     }
00366     return 0;
00367 }
00368 
00369 OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice,
00370                                                     UInt32 inChannel,
00371                                                     Boolean     isInput,
00372                                                     AudioDevicePropertyID inPropertyID,
00373                                                     void* inClientData)
00374 {
00375     JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
00376 
00377     switch (inPropertyID) {
00378 
00379         case kAudioDevicePropertyNominalSampleRate: {
00380             jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
00381             // Check new sample rate
00382             Float64 tmp_sample_rate;
00383             UInt32 outSize = sizeof(Float64);
00384             OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &tmp_sample_rate);
00385             if (err != noErr) {
00386                 jack_error("Cannot get current sample rate");
00387                 printError(err);
00388             } else {
00389                 jack_log("JackCoreAudioDriver::SRNotificationCallback : checked sample rate = %f", tmp_sample_rate);
00390             }
00391             driver->fState = true;
00392             break;
00393         }
00394     }
00395 
00396     return noErr;
00397 }
00398 
00399 OSStatus JackCoreAudioDriver::BSNotificationCallback(AudioDeviceID inDevice,
00400                                                      UInt32 inChannel,
00401                                                      Boolean isInput,
00402                                                      AudioDevicePropertyID inPropertyID,
00403                                                      void* inClientData)
00404 {
00405     JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
00406 
00407     switch (inPropertyID) {
00408 
00409         case kAudioDevicePropertyBufferFrameSize: {
00410             jack_log("JackCoreAudioDriver::BSNotificationCallback kAudioDevicePropertyBufferFrameSize");
00411             // Check new buffer size
00412             UInt32 tmp_buffer_size;
00413             UInt32 outSize = sizeof(UInt32);
00414             OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &tmp_buffer_size);
00415             if (err != noErr) {
00416                 jack_error("Cannot get current buffer size");
00417                 printError(err);
00418             } else {
00419                 jack_log("JackCoreAudioDriver::BSNotificationCallback : checked buffer size = %d", tmp_buffer_size);
00420             }
00421             driver->fState = true;
00422             break;
00423         }
00424     }
00425 
00426     return noErr;
00427 }
00428 
00429 // A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
00430 OSStatus JackCoreAudioDriver::AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID, void* inClientData)
00431 {
00432     JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
00433 
00434     switch (inPropertyID) {
00435 
00436         case kAudioHardwarePropertyDevices: {
00437             jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices");
00438             DisplayDeviceNames();
00439             AudioDeviceID captureID, playbackID;
00440             if (CheckAvailableDevice(driver->fDeviceID) ||
00441                 (CheckAvailableDeviceName(driver->fCaptureUID, &captureID)
00442                 && CheckAvailableDeviceName(driver->fPlaybackUID, &playbackID))) {
00443 
00444             }
00445             break;
00446         }
00447     }
00448 
00449     return noErr;
00450 }
00451 
00452 OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice,
00453                                                         UInt32 inChannel,
00454                                                         Boolean isInput,
00455                                                         AudioDevicePropertyID inPropertyID,
00456                                                         void* inClientData)
00457 {
00458     JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
00459 
00460     switch (inPropertyID) {
00461 
00462         case kAudioDevicePropertyDeviceIsRunning: {
00463             UInt32 isrunning = 0;
00464             UInt32 outsize = sizeof(UInt32);
00465             if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceIsRunning, &outsize, &isrunning) == noErr) {
00466                 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsRunning = %d", isrunning);
00467             }
00468             break;
00469         }
00470 
00471         case kAudioDevicePropertyDeviceIsAlive: {
00472             UInt32 isalive = 0;
00473             UInt32 outsize = sizeof(UInt32);
00474             if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceIsAlive, &outsize, &isalive) == noErr) {
00475                 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsAlive = %d", isalive);
00476             }
00477             break;
00478         }
00479 
00480         case kAudioDevicePropertyDeviceHasChanged: {
00481             UInt32 hachanged = 0;
00482             UInt32 outsize = sizeof(UInt32);
00483             if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceHasChanged, &outsize, &hachanged) == noErr) {
00484                 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceHasChanged = %d", hachanged);
00485             }
00486             break;
00487         }
00488 
00489         case kAudioDeviceProcessorOverload: {
00490             jack_error("DeviceNotificationCallback kAudioDeviceProcessorOverload");
00491             jack_time_t cur_time = GetMicroSeconds();
00492             driver->NotifyXRun(cur_time, float(cur_time - driver->fBeginDateUst));   // Better this value than nothing...
00493             break;
00494         }
00495 
00496         case kAudioDevicePropertyStreamConfiguration: {
00497             jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration : server will quit...");
00498             driver->NotifyFailure(JackFailure | JackBackendError, "Another application has changed the device configuration");   // Message length limited to JACK_MESSAGE_SIZE
00499             driver->CloseAUHAL();
00500             kill(JackTools::GetPID(), SIGINT);
00501             return kAudioHardwareUnsupportedOperationError;
00502         }
00503 
00504         case kAudioDevicePropertyNominalSampleRate: {
00505             Float64 sample_rate = 0;
00506             UInt32 outsize = sizeof(Float64);
00507             OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outsize, &sample_rate);
00508             if (err != noErr) {
00509                 return kAudioHardwareUnsupportedOperationError;
00510             }
00511 
00512             char device_name[256];
00513             const char* digidesign_name = "Digidesign";
00514             driver->GetDeviceNameFromID(driver->fDeviceID, device_name);
00515 
00516             if (sample_rate != driver->fEngineControl->fSampleRate) {
00517 
00518                // Digidesign hardware, so "special" code : change the SR again here
00519                if (strncmp(device_name, digidesign_name, 10) == 0) {
00520 
00521                     jack_log("JackCoreAudioDriver::DeviceNotificationCallback Digidesign HW = %s", device_name);
00522 
00523                     // Set sample rate again...
00524                     sample_rate = driver->fEngineControl->fSampleRate;
00525                     err = AudioDeviceSetProperty(driver->fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outsize, &sample_rate);
00526                     if (err != noErr) {
00527                         jack_error("Cannot set sample rate = %f", sample_rate);
00528                         printError(err);
00529                     } else {
00530                         jack_log("JackCoreAudioDriver::DeviceNotificationCallback : set sample rate = %f", sample_rate);
00531                     }
00532 
00533                     // Check new sample rate again...
00534                     outsize = sizeof(Float64);
00535                     err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outsize, &sample_rate);
00536                     if (err != noErr) {
00537                         jack_error("Cannot get current sample rate");
00538                         printError(err);
00539                     } else {
00540                         jack_log("JackCoreAudioDriver::DeviceNotificationCallback : checked sample rate = %f", sample_rate);
00541                     }
00542                     return noErr;
00543 
00544                 } else {
00545                     driver->NotifyFailure(JackFailure | JackBackendError, "Another application has changed the sample rate");    // Message length limited to JACK_MESSAGE_SIZE
00546                     driver->CloseAUHAL();
00547                     kill(JackTools::GetPID(), SIGINT);
00548                     return kAudioHardwareUnsupportedOperationError;
00549                 }
00550             }
00551         }
00552 
00553     }
00554     return noErr;
00555 }
00556 
00557 OSStatus JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id)
00558 {
00559     UInt32 size = sizeof(AudioValueTranslation);
00560     CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
00561     AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
00562 
00563     if (inIUD == NULL) {
00564         return kAudioHardwareUnspecifiedError;
00565     } else {
00566         OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
00567         CFRelease(inIUD);
00568         jack_log("JackCoreAudioDriver::GetDeviceIDFromUID %s %ld", UID, *id);
00569         return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
00570     }
00571 }
00572 
00573 OSStatus JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID* id)
00574 {
00575     OSStatus res;
00576     UInt32 theSize = sizeof(UInt32);
00577     AudioDeviceID inDefault;
00578     AudioDeviceID outDefault;
00579 
00580     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) {
00581         return res;
00582     }
00583 
00584     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) {
00585         return res;
00586     }
00587 
00588     jack_log("JackCoreAudioDriver::GetDefaultDevice : input = %ld output = %ld", inDefault, outDefault);
00589 
00590     // Get the device only if default input and output are the same
00591     if (inDefault != outDefault) {
00592         jack_error("Default input and output devices are not the same !!");
00593         return kAudioHardwareBadDeviceError;
00594     } else if (inDefault == 0) {
00595         jack_error("Default input and output devices are null !!");
00596         return kAudioHardwareBadDeviceError;
00597     } else {
00598         *id = inDefault;
00599         return noErr;
00600     }
00601 }
00602 
00603 OSStatus JackCoreAudioDriver::GetDefaultInputDevice(AudioDeviceID* id)
00604 {
00605     OSStatus res;
00606     UInt32 theSize = sizeof(UInt32);
00607     AudioDeviceID inDefault;
00608 
00609     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) {
00610         return res;
00611     }
00612 
00613     if (inDefault == 0) {
00614         jack_error("Error default input device is 0, will take 'Built-in'...");
00615         if (CheckAvailableDeviceName("Built-in Microphone", id) 
00616             || CheckAvailableDeviceName("Built-in Line", id)) {
00617              jack_log("JackCoreAudioDriver::GetDefaultInputDevice : output = %ld", *id);
00618             return noErr;
00619         } else {
00620             jack_error("Cannot find any input device to use...");
00621             return -1;
00622         }
00623     }
00624     jack_log("JackCoreAudioDriver::GetDefaultInputDevice : input = %ld ", inDefault);
00625     *id = inDefault;
00626     return noErr;
00627 }
00628 
00629 OSStatus JackCoreAudioDriver::GetDefaultOutputDevice(AudioDeviceID* id)
00630 {
00631     OSStatus res;
00632     UInt32 theSize = sizeof(UInt32);
00633     AudioDeviceID outDefault;
00634 
00635     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) {
00636         return res;
00637     }
00638 
00639     if (outDefault == 0) {
00640         jack_error("Error default ouput device is 0, will take 'Built-in'...");
00641         if (CheckAvailableDeviceName("Built-in Output", id)) {
00642             jack_log("JackCoreAudioDriver::GetDefaultOutputDevice : output = %ld", *id);
00643             return noErr;
00644         } else {
00645             jack_error("Cannot find any output device to use...");
00646             return -1;
00647         }
00648     }
00649     jack_log("JackCoreAudioDriver::GetDefaultOutputDevice : output = %ld", outDefault);
00650     *id = outDefault;
00651     return noErr;
00652 }
00653 
00654 OSStatus JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id, char* name)
00655 {
00656     UInt32 size = 256;
00657     return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
00658 }
00659 
00660 OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput)
00661 {
00662     OSStatus err = noErr;
00663     UInt32 outSize;
00664     Boolean     outWritable;
00665 
00666     channelCount = 0;
00667     err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
00668     if (err == noErr) {
00669         int stream_count = outSize / sizeof(AudioBufferList);
00670         jack_log("JackCoreAudioDriver::GetTotalChannels stream_count = %d", stream_count);
00671         AudioBufferList bufferList[stream_count];
00672         err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
00673         if (err == noErr) {
00674             for (uint i = 0; i < bufferList->mNumberBuffers; i++) {
00675                 channelCount += bufferList->mBuffers[i].mNumberChannels;
00676                 jack_log("JackCoreAudioDriver::GetTotalChannels stream = %d channels = %d", i, bufferList->mBuffers[i].mNumberChannels);
00677             }
00678         }
00679     }
00680     return err;
00681 }
00682 
00683 OSStatus JackCoreAudioDriver::GetStreamLatencies(AudioDeviceID device, bool isInput, vector<int>& latencies)
00684 {
00685     OSStatus err = noErr;
00686     UInt32 outSize1, outSize2, outSize3;
00687     Boolean     outWritable;
00688 
00689     err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, &outWritable);
00690     if (err == noErr) {
00691         int stream_count = outSize1 / sizeof(UInt32);
00692         AudioStreamID streamIDs[stream_count];
00693         AudioBufferList bufferList[stream_count];
00694         UInt32 streamLatency;
00695         outSize2 = sizeof(UInt32);
00696 
00697         err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, streamIDs);
00698         if (err != noErr) {
00699             jack_error("GetStreamLatencies kAudioDevicePropertyStreams err = %d", err);
00700             return err;
00701         }
00702 
00703         err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, &outWritable);
00704         if (err != noErr) {
00705             jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err);
00706             return err;
00707         }
00708 
00709         for (int i = 0; i < stream_count; i++) {
00710             err = AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &outSize2, &streamLatency);
00711             if (err != noErr) {
00712                 jack_error("GetStreamLatencies kAudioStreamPropertyLatency err = %d", err);
00713                 return err;
00714             }
00715             err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, bufferList);
00716             if (err != noErr) {
00717                 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err);
00718                 return err;
00719             }
00720             // Push 'channel' time the stream latency
00721             for (uint k = 0; k < bufferList->mBuffers[i].mNumberChannels; k++) {
00722                 latencies.push_back(streamLatency);
00723             }
00724         }
00725     }
00726     return err;
00727 }
00728 
00729 bool JackCoreAudioDriver::IsDigitalDevice(AudioDeviceID device)
00730 {
00731     OSStatus err = noErr;
00732     UInt32 outSize1;
00733     bool is_digital = false;
00734     
00735     /* Get a list of all the streams on this device */
00736     AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
00737     err = AudioObjectGetPropertyDataSize(device, &streamsAddress, 0, NULL, &outSize1);
00738     if (err != noErr) {
00739         jack_error("IsDigitalDevice kAudioDevicePropertyStreams err = %d", err);
00740         return false;
00741     }
00742     
00743     int stream_count = outSize1 / sizeof(AudioStreamID);
00744     AudioStreamID streamIDs[stream_count];
00745     
00746     err = AudioObjectGetPropertyData(device, &streamsAddress, 0, NULL, &outSize1, streamIDs);
00747 
00748     if (err != noErr) {
00749         jack_error("IsDigitalDevice kAudioDevicePropertyStreams list err = %d", err);
00750         return false;
00751     }
00752     
00753     AudioObjectPropertyAddress physicalFormatsAddress = { kAudioStreamPropertyAvailablePhysicalFormats, kAudioObjectPropertyScopeGlobal, 0 };
00754      
00755     for (int i = 0; i < stream_count ; i++) {
00756    
00757         /* Find a stream with a cac3 stream */
00758         int  format_num = 0;
00759     
00760         /* Retrieve all the stream formats supported by each output stream */
00761         err = AudioObjectGetPropertyDataSize(streamIDs[i], &physicalFormatsAddress, 0, NULL, &outSize1);
00762         
00763         if (err != noErr) {
00764             jack_error("IsDigitalDevice kAudioStreamPropertyAvailablePhysicalFormats err = %d", err);
00765             return false;
00766         }
00767 
00768         format_num = outSize1 / sizeof(AudioStreamRangedDescription);
00769         AudioStreamRangedDescription format_list[format_num];
00770       
00771         err = AudioObjectGetPropertyData(streamIDs[i], &physicalFormatsAddress, 0, NULL, &outSize1, format_list);
00772          
00773         if (err != noErr) {
00774             jack_error("IsDigitalDevice could not get the list of streamformats err = %d", err);
00775             return false;
00776         }
00777    
00778         /* Check if one of the supported formats is a digital format */
00779         for (int j = 0; j < format_num; j++) {
00780         
00781             PrintStreamDesc(&format_list[j].mFormat);
00782             
00783             if (format_list[j].mFormat.mFormatID == 'IAC3' ||
00784                 format_list[j].mFormat.mFormatID == 'iac3' ||
00785                 format_list[j].mFormat.mFormatID == kAudioFormat60958AC3 ||
00786                 format_list[j].mFormat.mFormatID == kAudioFormatAC3)
00787             {
00788                 is_digital = true;
00789                 break;
00790             }
00791         }
00792     }
00793        
00794     return is_digital;
00795 }
00796 
00797 JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
00798         : JackAudioDriver(name, alias, engine, table),
00799         fAC3Encoder(NULL),
00800         fJackInputData(NULL),
00801         fDriverOutputData(NULL),
00802         fPluginID(0),
00803         fState(false),
00804         fHogged(false),
00805         fIOUsage(1.f),
00806         fComputationGrain(-1.f),
00807         fClockDriftCompensate(false),
00808         fDigitalPlayback(false)
00809 {}
00810 
00811 JackCoreAudioDriver::~JackCoreAudioDriver()
00812 {
00813     delete fAC3Encoder;
00814 }
00815 
00816 OSStatus JackCoreAudioDriver::DestroyAggregateDevice()
00817 {
00818     OSStatus osErr = noErr;
00819     AudioObjectPropertyAddress pluginAOPA;
00820     pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
00821     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
00822     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
00823     UInt32 outDataSize;
00824 
00825     if (fPluginID > 0) {
00826 
00827         osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
00828         if (osErr != noErr) {
00829             jack_error("DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
00830             printError(osErr);
00831             return osErr;
00832         }
00833 
00834         osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
00835         if (osErr != noErr) {
00836             jack_error("DestroyAggregateDevice : AudioObjectGetPropertyData error");
00837             printError(osErr);
00838             return osErr;
00839         }
00840 
00841     }
00842 
00843     return noErr;
00844 }
00845 
00846 OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
00847 {
00848     OSStatus err = noErr;
00849     AudioObjectID sub_device[32];
00850     UInt32 outSize = sizeof(sub_device);
00851 
00852     err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
00853     vector<AudioDeviceID> captureDeviceIDArray;
00854     
00855     jack_log("JackCoreAudioDriver::CreateAggregateDevice : input device %d", captureDeviceID);
00856 
00857     if (err != noErr) {
00858         jack_log("JackCoreAudioDriver::CreateAggregateDevice : input device does not have subdevices");
00859         captureDeviceIDArray.push_back(captureDeviceID);
00860     } else {
00861         int num_devices = outSize / sizeof(AudioObjectID);
00862         jack_log("JackCoreAudioDriver::CreateAggregateDevice : input device has %d subdevices", num_devices);
00863         for (int i = 0; i < num_devices; i++) {
00864             jack_log("JackCoreAudioDriver::CreateAggregateDevice : input sub_device %d", sub_device[i]);
00865             captureDeviceIDArray.push_back(sub_device[i]);
00866         }
00867     }
00868 
00869     outSize = sizeof(sub_device);
00870     err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
00871     vector<AudioDeviceID> playbackDeviceIDArray;
00872     
00873     jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device %d", playbackDeviceID);
00874 
00875     if (err != noErr) {
00876         jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device does not have subdevices");
00877         playbackDeviceIDArray.push_back(playbackDeviceID);
00878     } else {
00879         int num_devices = outSize / sizeof(AudioObjectID);
00880         jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device has %d subdevices", num_devices);
00881         for (int i = 0; i < num_devices; i++) {
00882             jack_log("JackCoreAudioDriver::CreateAggregateDevice : output sub_device %d", sub_device[i]);
00883             playbackDeviceIDArray.push_back(sub_device[i]);
00884         }
00885     }
00886 
00887     return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice);
00888 }
00889 
00890 OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
00891 {
00892     OSStatus osErr = noErr;
00893     UInt32 outSize;
00894     Boolean outWritable;
00895 
00896     // Prepare sub-devices for clock drift compensation
00897     // Workaround for bug in the HAL : until 10.6.2
00898     AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
00899     AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
00900     UInt32 theQualifierDataSize = sizeof(AudioObjectID);
00901     AudioClassID inClass = kAudioSubDeviceClassID;
00902     void* theQualifierData = &inClass;
00903     UInt32 subDevicesNum = 0;
00904 
00905     //---------------------------------------------------------------------------
00906     // Setup SR of both devices otherwise creating AD may fail...
00907     //---------------------------------------------------------------------------
00908     UInt32 keptclockdomain = 0;
00909     UInt32 clockdomain = 0;
00910     outSize = sizeof(UInt32);
00911     bool need_clock_drift_compensation = false;
00912 
00913     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
00914         if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) {
00915             jack_error("CreateAggregateDeviceAux : cannot set SR of input device");
00916         } else  {
00917             // Check clock domain
00918             osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
00919             if (osErr != 0) {
00920                 jack_error("CreateAggregateDeviceAux : kAudioDevicePropertyClockDomain error");
00921                 printError(osErr);
00922             } else {
00923                 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
00924                 jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : input clockdomain = %d", clockdomain);
00925                 if (clockdomain != 0 && clockdomain != keptclockdomain) {
00926                     jack_error("CreateAggregateDeviceAux : devices do not share the same clock!! clock drift compensation would be needed...");
00927                     need_clock_drift_compensation = true;
00928                 }
00929             }
00930         }
00931     }
00932 
00933     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
00934         if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) {
00935             jack_error("CreateAggregateDeviceAux : cannot set SR of output device");
00936         } else {
00937             // Check clock domain
00938             osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
00939             if (osErr != 0) {
00940                 jack_error("CreateAggregateDeviceAux : kAudioDevicePropertyClockDomain error");
00941                 printError(osErr);
00942             } else {
00943                 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
00944                 jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : output clockdomain = %d", clockdomain);
00945                 if (clockdomain != 0 && clockdomain != keptclockdomain) {
00946                     jack_error("CreateAggregateDeviceAux : devices do not share the same clock!! clock drift compensation would be needed...");
00947                     need_clock_drift_compensation = true;
00948                 }
00949             }
00950         }
00951     }
00952 
00953     // If no valid clock domain was found, then assume we have to compensate...
00954     if (keptclockdomain == 0) {
00955         need_clock_drift_compensation = true;
00956     }
00957 
00958     //---------------------------------------------------------------------------
00959     // Start to create a new aggregate by getting the base audio hardware plugin
00960     //---------------------------------------------------------------------------
00961 
00962     char device_name[256];
00963     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
00964         GetDeviceNameFromID(captureDeviceID[i], device_name);
00965         jack_info("Separated input = '%s' ", device_name);
00966     }
00967 
00968     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
00969         GetDeviceNameFromID(playbackDeviceID[i], device_name);
00970         jack_info("Separated output = '%s' ", device_name);
00971     }
00972 
00973     osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
00974     if (osErr != noErr) {
00975         jack_error("CreateAggregateDeviceAux : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
00976         printError(osErr);
00977         return osErr;
00978     }
00979 
00980     AudioValueTranslation pluginAVT;
00981 
00982     CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
00983 
00984     pluginAVT.mInputData = &inBundleRef;
00985     pluginAVT.mInputDataSize = sizeof(inBundleRef);
00986     pluginAVT.mOutputData = &fPluginID;
00987     pluginAVT.mOutputDataSize = sizeof(fPluginID);
00988 
00989     osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
00990     if (osErr != noErr) {
00991         jack_error("CreateAggregateDeviceAux : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
00992         printError(osErr);
00993         return osErr;
00994     }
00995 
00996     //-------------------------------------------------
00997     // Create a CFDictionary for our aggregate device
00998     //-------------------------------------------------
00999 
01000     CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
01001 
01002     CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
01003     CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
01004 
01005     // add the name of the device to the dictionary
01006     CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
01007 
01008     // add our choice of UID for the aggregate device to the dictionary
01009     CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
01010 
01011     // add a "private aggregate key" to the dictionary
01012     int value = 1;
01013     CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
01014 
01015     SInt32 system;
01016     Gestalt(gestaltSystemVersion, &system);
01017 
01018     jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : system version = %x limit = %x", system, 0x00001054);
01019 
01020     // Starting with 10.5.4 systems, the AD can be internal... (better)
01021     if (system < 0x00001054) {
01022         jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : public aggregate device....");
01023     } else {
01024         jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : private aggregate device....");
01025         CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
01026     }
01027 
01028     // Prepare sub-devices for clock drift compensation
01029     CFMutableArrayRef subDevicesArrayClock = NULL;
01030 
01031     /*
01032     if (fClockDriftCompensate) {
01033         if (need_clock_drift_compensation) {
01034             jack_info("Clock drift compensation activated...");
01035             subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
01036 
01037             for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01038                 CFStringRef UID = GetDeviceName(captureDeviceID[i]);
01039                 if (UID) {
01040                     CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
01041                     CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
01042                     CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
01043                     //CFRelease(UID);
01044                     CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
01045                 }
01046             }
01047 
01048             for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01049                 CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
01050                 if (UID) {
01051                     CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
01052                     CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
01053                     CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
01054                     //CFRelease(UID);
01055                     CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
01056                 }
01057             }
01058 
01059             // add sub-device clock array for the aggregate device to the dictionary
01060             CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
01061         } else {
01062             jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
01063         }
01064     }
01065     */
01066 
01067     //-------------------------------------------------
01068     // Create a CFMutableArray for our sub-device list
01069     //-------------------------------------------------
01070 
01071     // we need to append the UID for each device to a CFMutableArray, so create one here
01072     CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
01073 
01074     vector<CFStringRef> captureDeviceUID;
01075     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01076         CFStringRef ref = GetDeviceName(captureDeviceID[i]);
01077         if (ref == NULL) {
01078             return -1;
01079         }
01080         captureDeviceUID.push_back(ref);
01081         // input sub-devices in this example, so append the sub-device's UID to the CFArray
01082         CFArrayAppendValue(subDevicesArray, ref);
01083    }
01084 
01085     vector<CFStringRef> playbackDeviceUID;
01086     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01087         CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
01088         if (ref == NULL) {
01089             return -1;
01090         }
01091         playbackDeviceUID.push_back(ref);
01092         // output sub-devices in this example, so append the sub-device's UID to the CFArray
01093         CFArrayAppendValue(subDevicesArray, ref);
01094     }
01095 
01096     //-----------------------------------------------------------------------
01097     // Feed the dictionary to the plugin, to create a blank aggregate device
01098     //-----------------------------------------------------------------------
01099 
01100     AudioObjectPropertyAddress pluginAOPA;
01101     pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
01102     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01103     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01104     UInt32 outDataSize;
01105 
01106     osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
01107     if (osErr != noErr) {
01108         jack_error("CreateAggregateDeviceAux : AudioObjectGetPropertyDataSize error");
01109         printError(osErr);
01110         goto error;
01111     }
01112 
01113     osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
01114     if (osErr != noErr) {
01115         jack_error("CreateAggregateDeviceAux : AudioObjectGetPropertyData error");
01116         printError(osErr);
01117         goto error;
01118     }
01119 
01120     // pause for a bit to make sure that everything completed correctly
01121     // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
01122     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01123 
01124     //-------------------------
01125     // Set the sub-device list
01126     //-------------------------
01127 
01128     pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
01129     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01130     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01131     outDataSize = sizeof(CFMutableArrayRef);
01132     osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
01133     if (osErr != noErr) {
01134         jack_error("CreateAggregateDeviceAux : AudioObjectSetPropertyData for sub-device list error");
01135         printError(osErr);
01136         goto error;
01137     }
01138 
01139     // pause again to give the changes time to take effect
01140     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01141 
01142     //-----------------------
01143     // Set the master device
01144     //-----------------------
01145 
01146     // set the master device manually (this is the device which will act as the master clock for the aggregate device)
01147     // pass in the UID of the device you want to use
01148     pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
01149     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01150     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01151     outDataSize = sizeof(CFStringRef);
01152     osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]);  // First capture is master...
01153     if (osErr != noErr) {
01154         jack_error("CreateAggregateDeviceAux : AudioObjectSetPropertyData for master device error");
01155         printError(osErr);
01156         goto error;
01157     }
01158 
01159     // pause again to give the changes time to take effect
01160     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01161 
01162     // Prepare sub-devices for clock drift compensation
01163     // Workaround for bug in the HAL : until 10.6.2
01164 
01165     if (fClockDriftCompensate) {
01166         if (need_clock_drift_compensation) {
01167             jack_info("Clock drift compensation activated...");
01168 
01169             // Get the property data size
01170             osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
01171             if (osErr != noErr) {
01172                 jack_error("CreateAggregateDeviceAux kAudioObjectPropertyOwnedObjects error");
01173                 printError(osErr);
01174             }
01175 
01176             //  Calculate the number of object IDs
01177             subDevicesNum = outSize / sizeof(AudioObjectID);
01178             jack_info("JackCoreAudioDriver::CreateAggregateDeviceAux clock drift compensation, number of sub-devices = %d", subDevicesNum);
01179             AudioObjectID subDevices[subDevicesNum];
01180             outSize = sizeof(subDevices);
01181 
01182             osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
01183             if (osErr != noErr) {
01184                 jack_error("CreateAggregateDeviceAux kAudioObjectPropertyOwnedObjects error");
01185                 printError(osErr);
01186             }
01187 
01188             // Set kAudioSubDevicePropertyDriftCompensation property...
01189             for (UInt32 index = 0; index < subDevicesNum; ++index) {
01190                 UInt32 theDriftCompensationValue = 1;
01191                 osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue);
01192                 if (osErr != noErr) {
01193                     jack_error("CreateAggregateDeviceAux kAudioSubDevicePropertyDriftCompensation error");
01194                     printError(osErr);
01195                 }
01196             }
01197         } else {
01198             jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
01199         }
01200     }
01201 
01202     // pause again to give the changes time to take effect
01203     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01204 
01205     //----------
01206     // Clean up
01207     //----------
01208 
01209     // release the private AD key
01210     CFRelease(AggregateDeviceNumberRef);
01211 
01212     // release the CF objects we have created - we don't need them any more
01213     CFRelease(aggDeviceDict);
01214     CFRelease(subDevicesArray);
01215 
01216     if (subDevicesArrayClock) {
01217         CFRelease(subDevicesArrayClock);
01218     }
01219 
01220     // release the device UID
01221     for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
01222         CFRelease(captureDeviceUID[i]);
01223     }
01224 
01225     for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
01226         CFRelease(playbackDeviceUID[i]);
01227     }
01228 
01229     jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : new aggregate device %ld", *outAggregateDevice);
01230     return noErr;
01231 
01232 error:
01233     DestroyAggregateDevice();
01234     return -1;
01235 }
01236 
01237 int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid,
01238                                       const char* playback_driver_uid,
01239                                       char* capture_driver_name,
01240                                       char* playback_driver_name,
01241                                       jack_nframes_t samplerate,
01242                                       bool ac3_encoding)
01243 {
01244     capture_driver_name[0] = 0;
01245     playback_driver_name[0] = 0;
01246 
01247     // Duplex
01248     if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
01249         jack_log("JackCoreAudioDriver::SetupDevices : duplex");
01250 
01251         // Same device for capture and playback...
01252         if (strcmp(capture_driver_uid, playback_driver_uid) == 0)  {
01253 
01254             if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
01255                 jack_log("JackCoreAudioDriver::SetupDevices : will take default in/out");
01256                 if (GetDefaultDevice(&fDeviceID) != noErr) {
01257                     jack_error("Cannot open default device");
01258                     return -1;
01259                 }
01260             }
01261             
01262             if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
01263                 jack_error("Cannot get device name from device ID");
01264                 return -1;
01265             }
01266             
01267             if (fHogged) {
01268                 if (!TakeHogAux(fDeviceID, false)) {
01269                     jack_error("Cannot take hog mode");
01270                 } 
01271                 if (ac3_encoding) {
01272                     fDigitalPlayback = IsDigitalDevice(fDeviceID);
01273                 }
01274             }
01275 
01276         } else {
01277 
01278             // Creates aggregate device
01279             AudioDeviceID captureID = -1;
01280             AudioDeviceID playbackID = -1;
01281     
01282             if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
01283                 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
01284                 if (GetDefaultInputDevice(&captureID) != noErr) {
01285                     jack_error("Cannot open default input device");
01286                     return -1;
01287                 }
01288             }
01289 
01290             if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
01291                 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
01292                 if (GetDefaultOutputDevice(&playbackID) != noErr) {
01293                     jack_error("Cannot open default output device");
01294                     return -1;
01295                 }
01296             }
01297 
01298             if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
01299                 return -1;
01300             }
01301 
01302             GetDeviceNameFromID(captureID, fCaptureUID);
01303             GetDeviceNameFromID(playbackID, fPlaybackUID);
01304             
01305             if (fHogged) {
01306                 if (!TakeHogAux(captureID, true)) {
01307                     jack_error("Cannot take hog mode for capture device");
01308                 }
01309                 if (!TakeHogAux(playbackID, false)) {
01310                     jack_error("Cannot take hog mode for playback device");
01311                 }
01312                 if (ac3_encoding) {
01313                     fDigitalPlayback = IsDigitalDevice(playbackID);
01314                 }
01315             }
01316             
01317         }
01318 
01319     // Capture only
01320     } else if (strcmp(capture_driver_uid, "") != 0) {
01321     
01322         jack_log("JackCoreAudioDriver::SetupDevices : capture only");
01323         if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
01324             jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
01325             if (GetDefaultInputDevice(&fDeviceID) != noErr) {
01326                 jack_error("Cannot open default input device");
01327                 return -1;
01328             }
01329         }
01330         
01331         if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) {
01332             jack_error("Cannot get device name from device ID");
01333             return -1;
01334         }
01335         
01336         if (fHogged) {
01337             if (!TakeHogAux(fDeviceID, true)) {
01338                 jack_error("Cannot take hog mode for capture device");
01339             }
01340         }
01341 
01342     // Playback only
01343     } else if (strcmp(playback_driver_uid, "") != 0) {
01344     
01345         jack_log("JackCoreAudioDriver::SetupDevices : playback only");
01346         if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
01347             jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
01348             if (GetDefaultOutputDevice(&fDeviceID) != noErr) {
01349                 jack_error("Cannot open default output device");
01350                 return -1;
01351             }
01352         }
01353         
01354         if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
01355             jack_error("Cannot get device name from device ID");
01356             return -1;
01357         }
01358         
01359         if (fHogged) {
01360             if (!TakeHogAux(fDeviceID, false)) {
01361                 jack_error("Cannot take hog mode for playback device");
01362             }
01363             if (ac3_encoding) {
01364                 fDigitalPlayback = IsDigitalDevice(fDeviceID);
01365             }
01366         }
01367 
01368     // Use default driver in duplex mode
01369     } else {
01370         jack_log("JackCoreAudioDriver::SetupDevices : default driver");
01371         if (GetDefaultDevice(&fDeviceID) != noErr) {
01372             jack_error("Cannot open default device in duplex mode, so aggregate default input and default output");
01373 
01374             // Creates aggregate device
01375             AudioDeviceID captureID = -1;
01376             AudioDeviceID playbackID = -1;
01377             
01378             if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
01379                 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
01380                 if (GetDefaultInputDevice(&captureID) != noErr) {
01381                     jack_error("Cannot open default input device");
01382                     return -1;
01383                 }
01384             }
01385 
01386             if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
01387                 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
01388                 if (GetDefaultOutputDevice(&playbackID) != noErr) {
01389                     jack_error("Cannot open default output device");
01390                     return -1;
01391                 }
01392             }
01393 
01394             if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
01395                 return -1;
01396             }
01397 
01398             GetDeviceNameFromID(captureID, fCaptureUID);
01399             GetDeviceNameFromID(playbackID, fPlaybackUID);
01400             
01401             if (fHogged) {
01402                 if (!TakeHogAux(captureID, true)) {
01403                     jack_error("Cannot take hog mode for capture device");
01404                 }
01405                 if (!TakeHogAux(playbackID, false)) {
01406                     jack_error("Cannot take hog mode for playback device");
01407                 }
01408                 if (ac3_encoding) {
01409                     fDigitalPlayback = IsDigitalDevice(playbackID);
01410                 }
01411             }
01412         }
01413     }
01414      
01415     return 0;
01416 }
01417 
01418 /*
01419 Return the max possible input channels in in_maxChannels and output channels in out_maxChannels.
01420 */
01421 int JackCoreAudioDriver::SetupChannels(bool capturing, bool playing, int& inchannels, int& outchannels, int& in_maxChannels, int& out_maxChannels, bool strict)
01422 {
01423     OSStatus err = noErr;
01424     
01425     jack_log("JackCoreAudioDriver::SetupChannels : fDeviceID = %d", fDeviceID);
01426 
01427     if (capturing) {
01428         err = GetTotalChannels(fDeviceID, in_maxChannels, true);
01429         if (err != noErr) {
01430             jack_error("SetupChannels : cannot get input channel number");
01431             printError(err);
01432             return -1;
01433         } else {
01434             jack_log("JackCoreAudioDriver::SetupChannels : max input channels : %d", in_maxChannels);
01435         }
01436     }
01437 
01438     if (playing) {
01439         err = GetTotalChannels(fDeviceID, out_maxChannels, false);
01440         if (err != noErr) {
01441             jack_error("Cannot get output channel number");
01442             printError(err);
01443             return -1;
01444         } else {
01445             jack_log("JackCoreAudioDriver::SetupChannels : max output channels : %d", out_maxChannels);
01446         }
01447     }
01448 
01449     if (inchannels > in_maxChannels) {
01450         jack_error("This device hasn't required input channels inchannels = %d in_maxChannels = %d", inchannels, in_maxChannels);
01451         if (strict) {
01452             return -1;
01453         }
01454     }
01455 
01456     if (outchannels > out_maxChannels) {
01457         jack_error("This device hasn't required output channels outchannels = %d out_maxChannels = %d", outchannels, out_maxChannels);
01458         if (strict) {
01459             return -1;
01460         }
01461     }
01462 
01463     if (inchannels == -1) {
01464         jack_log("JackCoreAudioDriver::SetupChannels : setup max in channels = %d", in_maxChannels);
01465         inchannels = in_maxChannels;
01466     }
01467 
01468     if (outchannels == -1) {
01469         jack_log("JackCoreAudioDriver::SetupChannels : setup max out channels = %d", out_maxChannels);
01470         outchannels = out_maxChannels;
01471     }
01472 
01473     return 0;
01474 }
01475 
01476 int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size)
01477 {
01478     // Setting buffer size
01479     OSStatus err = noErr;
01480     UInt32 tmp_buffer_size = buffer_size;
01481     UInt32 outSize = sizeof(UInt32);
01482  
01483     err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &tmp_buffer_size);
01484     if (err != noErr) {
01485         jack_error("Cannot get buffer size %ld", buffer_size);
01486         printError(err);
01487         return -1;
01488     } else {
01489         jack_log("JackCoreAudioDriver::SetupBufferSize : current buffer size = %ld", tmp_buffer_size);
01490     }
01491 
01492     // If needed, set new buffer size
01493     if (buffer_size != tmp_buffer_size) {
01494         tmp_buffer_size = buffer_size;
01495 
01496         // To get BS change notification
01497         err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback, this);
01498         if (err != noErr) {
01499             jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyBufferFrameSize");
01500             printError(err);
01501             return -1;
01502         }
01503 
01504         // Waiting for BS change notification
01505         int count = 0;
01506         fState = false;
01507 
01508         err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, outSize, &tmp_buffer_size);
01509         if (err != noErr) {
01510             jack_error("SetupBufferSize : cannot set buffer size = %ld", tmp_buffer_size);
01511             printError(err);
01512             goto error;
01513         }
01514 
01515         while (!fState && count++ < WAIT_NOTIFICATION_COUNTER) {
01516             usleep(100000);
01517             jack_log("JackCoreAudioDriver::SetupBufferSize : wait count = %d", count);
01518         }
01519 
01520         if (count >= WAIT_NOTIFICATION_COUNTER) {
01521             jack_error("Did not get buffer size notification...");
01522             goto error;
01523         }
01524 
01525         // Check new buffer size
01526         outSize = sizeof(UInt32);
01527         err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &tmp_buffer_size);
01528         if (err != noErr) {
01529             jack_error("Cannot get current buffer size");
01530             printError(err);
01531         } else {
01532             jack_log("JackCoreAudioDriver::SetupBufferSize : checked buffer size = %ld", tmp_buffer_size);
01533         }
01534 
01535         // Remove BS change notification
01536         AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback);
01537     }
01538 
01539     return 0;
01540 
01541 error:
01542 
01543     // Remove BS change notification
01544     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback);
01545     return -1;
01546 }
01547 
01548 int JackCoreAudioDriver::SetupSampleRate(jack_nframes_t sample_rate)
01549 {
01550     return SetupSampleRateAux(fDeviceID, sample_rate);
01551 }
01552 
01553 int JackCoreAudioDriver::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframes_t sample_rate)
01554 {
01555     OSStatus err = noErr;
01556     UInt32 outSize;
01557     Float64 tmp_sample_rate;
01558 
01559     // Get sample rate
01560     outSize =  sizeof(Float64);
01561     err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &tmp_sample_rate);
01562     if (err != noErr) {
01563         jack_error("Cannot get current sample rate");
01564         printError(err);
01565         return -1;
01566     } else {
01567         jack_log("JackCoreAudioDriver::SetupSampleRateAux : current sample rate = %f", tmp_sample_rate);
01568     }
01569 
01570     // If needed, set new sample rate
01571     if (sample_rate != (jack_nframes_t)tmp_sample_rate) {
01572         tmp_sample_rate = (Float64)sample_rate;
01573 
01574         // To get SR change notification
01575         err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
01576         if (err != noErr) {
01577             jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
01578             printError(err);
01579             return -1;
01580         }
01581 
01582         // Waiting for SR change notification
01583         int count = 0;
01584         fState = false;
01585 
01586         err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &tmp_sample_rate);
01587         if (err != noErr) {
01588             jack_error("Cannot set sample rate = %ld", sample_rate);
01589             printError(err);
01590             goto error;
01591         }
01592 
01593         while (!fState && count++ < WAIT_NOTIFICATION_COUNTER) {
01594             usleep(100000);
01595             jack_log("JackCoreAudioDriver::SetupSampleRateAux : wait count = %d", count);
01596         }
01597 
01598         if (count >= WAIT_NOTIFICATION_COUNTER) {
01599             jack_error("Did not get sample rate notification...");
01600             goto error;
01601         }
01602 
01603         // Check new sample rate
01604         outSize = sizeof(Float64);
01605         err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &tmp_sample_rate);
01606         if (err != noErr) {
01607             jack_error("Cannot get current sample rate");
01608             printError(err);
01609         } else {
01610             jack_log("JackCoreAudioDriver::SetupSampleRateAux : checked sample rate = %f", tmp_sample_rate);
01611         }
01612 
01613         // Remove SR change notification
01614         AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
01615     }
01616 
01617     return 0;
01618 
01619 error:
01620 
01621     // Remove SR change notification
01622     AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
01623     return -1;
01624 }
01625 
01626 int JackCoreAudioDriver::OpenAUHAL(bool capturing,
01627                                    bool playing,
01628                                    int inchannels,
01629                                    int outchannels,
01630                                    int in_maxChannels,
01631                                    int out_maxChannels,
01632                                    const vector<int>& chan_in_list,
01633                                    const vector<int>& chan_out_list,
01634                                    jack_nframes_t buffer_size,
01635                                    jack_nframes_t sample_rate)
01636 {
01637     ComponentResult err1;
01638     UInt32 enableIO;
01639     AudioStreamBasicDescription srcFormat, dstFormat;
01640     AudioDeviceID currAudioDeviceID;
01641     UInt32 size;
01642 
01643     jack_log("JackCoreAudioDriver::OpenAUHAL : capturing = %d playing = %d inchannels = %d outchannels = %d in_maxChannels = %d out_maxChannels = %d chan_in_list = %d chan_out_list = %d",
01644         capturing, playing, inchannels, outchannels, in_maxChannels, out_maxChannels, chan_in_list.size(), chan_out_list.size());
01645 
01646     if (inchannels == 0 && outchannels == 0) {
01647         jack_error("No input and output channels...");
01648         return -1;
01649     }
01650     
01651     // AUHAL
01652 #ifdef MAC_OS_X_VERSION_10_5
01653     ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
01654     Component HALOutput = FindNextComponent(NULL, &cd);
01655     err1 = OpenAComponent(HALOutput, &fAUHAL);
01656     if (err1 != noErr) {
01657         jack_error("Error calling OpenAComponent");
01658         printError(err1);
01659         goto error;
01660     }
01661 #else 
01662     AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
01663     AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
01664     err1 = AudioComponentInstanceNew(HALOutput, &fAUHAL);
01665     if (err1 != noErr) {
01666         jack_error("Error calling AudioComponentInstanceNew");
01667         printError(err1);
01668         goto error;
01669     }
01670 #endif
01671 
01672     err1 = AudioUnitInitialize(fAUHAL);
01673     if (err1 != noErr) {
01674         jack_error("Cannot initialize AUHAL unit");
01675         printError(err1);
01676         goto error;
01677     }
01678     
01679     // Start I/O
01680     if (capturing && inchannels > 0) {
01681         enableIO = 1;
01682         jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input on");
01683     } else {
01684         enableIO = 0;
01685         jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input off");
01686     }
01687 
01688     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
01689     if (err1 != noErr) {
01690         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
01691         printError(err1);
01692         goto error;
01693     }
01694 
01695     if (playing && outchannels > 0) {
01696         enableIO = 1;
01697         jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output on");
01698     } else {
01699         enableIO = 0;
01700         jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output off");
01701     }
01702 
01703     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
01704     if (err1 != noErr) {
01705         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output");
01706         printError(err1);
01707         goto error;
01708     }
01709 
01710     size = sizeof(AudioDeviceID);
01711     err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size);
01712     if (err1 != noErr) {
01713         jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
01714         printError(err1);
01715         goto error;
01716     } else {
01717         jack_log("JackCoreAudioDriver::OpenAUHAL : AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID);
01718     }
01719 
01720     // Setup up choosen device, in both input and output cases
01721     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
01722     if (err1 != noErr) {
01723         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
01724         printError(err1);
01725         goto error;
01726     }
01727 
01728     // Set buffer size
01729     if (capturing && inchannels > 0) {
01730         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32));
01731         if (err1 != noErr) {
01732             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
01733             printError(err1);
01734             goto error;
01735         }
01736     }
01737 
01738     if (playing && outchannels > 0) {
01739         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&buffer_size, sizeof(UInt32));
01740         if (err1 != noErr) {
01741             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
01742             printError(err1);
01743             goto error;
01744         }
01745     }
01746 
01747     // Setup input channel map
01748     if (capturing && inchannels > 0 && inchannels <= in_maxChannels) {
01749         SInt32 chanArr[in_maxChannels];
01750         for (int i = 0; i < in_maxChannels; i++) {
01751             chanArr[i] = -1;
01752         }
01753         // Explicit mapping
01754         if (chan_in_list.size() > 0) {
01755             for (uint i = 0; i < chan_in_list.size(); i++) {
01756                 int chan = chan_in_list[i];
01757                 if (chan < in_maxChannels) {
01758                     // The wanted JACK input index for the 'chan' channel value
01759                     chanArr[chan] = i;
01760                     jack_info("Input channel = %d ==> JACK input port = %d", chan, i);
01761                 } else {
01762                     jack_info("Error input channel number is incorrect : %d", chan);
01763                     goto error;
01764                 }
01765             }
01766         } else {
01767             for (int i = 0; i < inchannels; i++) {
01768                 chanArr[i] = i;
01769                 jack_info("Input channel = %d ==> JACK input port = %d", chanArr[i], i);
01770             }
01771         }
01772 
01773         AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_maxChannels);
01774         if (err1 != noErr) {
01775             jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap for input");
01776             printError(err1);
01777             goto error;
01778         }
01779     }
01780 
01781     // Setup output channel map
01782     if (playing && outchannels > 0 && outchannels <= out_maxChannels) {
01783         SInt32 chanArr[out_maxChannels];
01784         for (int i = 0; i < out_maxChannels; i++) {
01785             chanArr[i] = -1;
01786         }
01787         // Explicit mapping
01788         if (chan_out_list.size() > 0) {
01789             for (uint i = 0; i < chan_out_list.size(); i++) {
01790                 int chan = chan_out_list[i];
01791                 if (chan < out_maxChannels) {
01792                     // The wanted JACK output index for the 'chan' channel value
01793                     chanArr[chan] = i;
01794                     jack_info("JACK output port = %d ==> output channel = %d", i, chan);
01795                 } else {
01796                     jack_info("Error output channel number is incorrect : %d", chan);
01797                     goto error;
01798                 }
01799             }
01800         } else {
01801             for (int i = 0; i < outchannels; i++) {
01802                 chanArr[i] = i;
01803                 jack_info("JACK output port = %d ==> output channel = %d", i, chanArr[i]);
01804             }
01805         }
01806 
01807         err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_maxChannels);
01808         if (err1 != noErr) {
01809             jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap for output");
01810             printError(err1);
01811             goto error;
01812         }
01813     }
01814 
01815     // Setup stream converters
01816     if (capturing && inchannels > 0) {
01817 
01818         size = sizeof(AudioStreamBasicDescription);
01819         err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &size);
01820         if (err1 != noErr) {
01821             jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
01822             printError(err1);
01823             goto error;
01824         }
01825         PrintStreamDesc(&srcFormat);
01826 
01827         jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input stream converter SR = %ld", sample_rate);
01828         srcFormat.mSampleRate = sample_rate;
01829         srcFormat.mFormatID = kAudioFormatLinearPCM;
01830         srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
01831         srcFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t);
01832         srcFormat.mFramesPerPacket = 1;
01833         srcFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t);
01834         srcFormat.mChannelsPerFrame = inchannels;
01835         srcFormat.mBitsPerChannel = 32;
01836         PrintStreamDesc(&srcFormat);
01837 
01838         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
01839         if (err1 != noErr) {
01840             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
01841             printError(err1);
01842             goto error;
01843         }
01844     }
01845 
01846     if (playing && outchannels > 0) {
01847 
01848         size = sizeof(AudioStreamBasicDescription);
01849         err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &size);
01850         if (err1 != noErr) {
01851             jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
01852             printError(err1);
01853             goto error;
01854         }
01855         PrintStreamDesc(&dstFormat);
01856 
01857         jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output stream converter SR = %ld", sample_rate);
01858         dstFormat.mSampleRate = sample_rate;
01859         dstFormat.mFormatID = kAudioFormatLinearPCM;
01860         dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
01861         dstFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t);
01862         dstFormat.mFramesPerPacket = 1;
01863         dstFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t);
01864         dstFormat.mChannelsPerFrame = outchannels;
01865         dstFormat.mBitsPerChannel = 32;
01866         PrintStreamDesc(&dstFormat);
01867 
01868         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
01869         if (err1 != noErr) {
01870             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
01871             printError(err1);
01872             goto error;
01873         }
01874     }
01875 
01876     // Setup callbacks
01877     if (inchannels > 0 && outchannels == 0) {
01878         AURenderCallbackStruct output;
01879         output.inputProc = Render;
01880         output.inputProcRefCon = this;
01881         err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
01882         if (err1 != noErr) {
01883             jack_error("Error calling  AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
01884             printError(err1);
01885             goto error;
01886         }
01887     } else {
01888         AURenderCallbackStruct output;
01889         output.inputProc = Render;
01890         output.inputProcRefCon = this;
01891         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
01892         if (err1 != noErr) {
01893             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
01894             printError(err1);
01895             goto error;
01896         }
01897     }
01898 
01899     return 0;
01900 
01901 error:
01902     CloseAUHAL();
01903     return -1;
01904 }
01905 
01906 int JackCoreAudioDriver::SetupBuffers(int inchannels)
01907 {
01908     // Prepare buffers
01909     fJackInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
01910     fJackInputData->mNumberBuffers = inchannels;
01911     for (int i = 0; i < inchannels; i++) {
01912         fJackInputData->mBuffers[i].mNumberChannels = 1;
01913         fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(jack_default_audio_sample_t);
01914     }
01915     return 0;
01916 }
01917 
01918 void JackCoreAudioDriver::DisposeBuffers()
01919 {
01920     if (fJackInputData) {
01921         free(fJackInputData);
01922         fJackInputData = 0;
01923     }
01924 }
01925 
01926 void JackCoreAudioDriver::CloseAUHAL()
01927 {
01928     AudioOutputUnitStop(fAUHAL);
01929     AudioUnitUninitialize(fAUHAL);
01930     CloseComponent(fAUHAL);
01931 }
01932 
01933 int JackCoreAudioDriver::AddListeners()
01934 {
01935     OSStatus err = noErr;
01936 
01937     // Add listeners
01938     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
01939     if (err != noErr) {
01940         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
01941         printError(err);
01942         return -1;
01943     }
01944 
01945     err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback, this);
01946     if (err != noErr) {
01947         jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices");
01948         printError(err);
01949         return -1;
01950     }
01951 
01952     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this);
01953     if (err != noErr) {
01954         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
01955         printError(err);
01956         return -1;
01957     }
01958 
01959     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this);
01960     if (err != noErr) {
01961         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
01962         printError(err);
01963         return -1;
01964     }
01965 
01966     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, DeviceNotificationCallback, this);
01967     if (err != noErr) {
01968         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsAlive");
01969         printError(err);
01970         return -1;
01971     }
01972 
01973     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceHasChanged, DeviceNotificationCallback, this);
01974     if (err != noErr) {
01975         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceHasChanged");
01976         printError(err);
01977         return -1;
01978     }
01979 
01980     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
01981     if (err != noErr) {
01982         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
01983         printError(err);
01984         return -1;
01985     }
01986 
01987     err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
01988     if (err != noErr) {
01989         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
01990         printError(err);
01991         return -1;
01992     }
01993 
01994     if (!fEngineControl->fSyncMode && fIOUsage != 1.f) {
01995         UInt32 outSize = sizeof(float);
01996         err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyIOCycleUsage, outSize, &fIOUsage);
01997         if (err != noErr) {
01998             jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage");
01999             printError(err);
02000         }
02001     }
02002 
02003     return 0;
02004 }
02005 
02006 void JackCoreAudioDriver::RemoveListeners()
02007 {
02008     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback);
02009     AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback);
02010     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback);
02011     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback);
02012     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, DeviceNotificationCallback);
02013     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceHasChanged, DeviceNotificationCallback);
02014     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
02015     AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
02016 }
02017 
02018 int JackCoreAudioDriver::Open(jack_nframes_t buffer_size,
02019                               jack_nframes_t sample_rate,
02020                               bool capturing,
02021                               bool playing,
02022                               int inchannels,
02023                               int outchannels,
02024                               const char* chan_in_list,
02025                               const char* chan_out_list,
02026                               bool monitor,
02027                               const char* capture_driver_uid,
02028                               const char* playback_driver_uid,
02029                               jack_nframes_t capture_latency,
02030                               jack_nframes_t playback_latency,
02031                               int async_output_latency,
02032                               int computation_grain,
02033                               bool hogged,
02034                               bool clock_drift,
02035                               bool ac3_encoding,
02036                               int ac3_bitrate,
02037                               bool ac3_lfe)
02038 {
02039     int in_maxChannels = 0;
02040     int out_maxChannels = 0;
02041     char capture_driver_name[256];
02042     char playback_driver_name[256];
02043 
02044     fCaptureLatency = capture_latency;
02045     fPlaybackLatency = playback_latency;
02046     fIOUsage = float(async_output_latency) / 100.f;
02047     fComputationGrain = float(computation_grain) / 100.f;
02048     fHogged = hogged;
02049     fClockDriftCompensate = clock_drift;
02050 
02051     SInt32 major;
02052     SInt32 minor;
02053     Gestalt(gestaltSystemVersionMajor, &major);
02054     Gestalt(gestaltSystemVersionMinor, &minor);
02055 
02056     vector<int> parsed_chan_in_list;
02057     vector<int> parsed_chan_out_list;
02058    
02059     // Starting with 10.6 systems, the HAL notification thread is created internally
02060     if (major == 10 && minor >= 6) {
02061         CFRunLoopRef theRunLoop = NULL;
02062         AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
02063         OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
02064         if (osErr != noErr) {
02065             jack_error("Open kAudioHardwarePropertyRunLoop error");
02066             printError(osErr);
02067         }
02068     }
02069   
02070     if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name, sample_rate, ac3_encoding) < 0) {
02071         goto error;
02072     }
02073 
02074     // Generic JackAudioDriver Open
02075     if (JackAudioDriver::Open(buffer_size, sample_rate,
02076                             capturing, playing,
02077                             inchannels, outchannels,
02078                             monitor,
02079                             capture_driver_name,
02080                             playback_driver_name,
02081                             capture_latency,
02082                             playback_latency) != 0) {
02083         goto error;
02084     }
02085 
02086     if (SetupChannels(capturing, playing, inchannels, outchannels, in_maxChannels, out_maxChannels, !ac3_encoding) < 0) {
02087         goto error;
02088     }
02089     
02090     ParseChannelList(chan_in_list, parsed_chan_in_list, in_maxChannels);
02091     if (parsed_chan_in_list.size() > 0) {
02092         jack_info("Explicit input channel list size = %d", parsed_chan_in_list.size());
02093         inchannels = parsed_chan_in_list.size();
02094     }
02095 
02096     ParseChannelList(chan_out_list, parsed_chan_out_list, out_maxChannels);
02097     if (parsed_chan_out_list.size() > 0) {
02098         jack_info("Explicit output channel list size = %d", parsed_chan_out_list.size());
02099         outchannels = parsed_chan_out_list.size();
02100     }  
02101 
02102     if (SetupBufferSize(buffer_size) < 0) {
02103         goto error;
02104     }
02105 
02106     if (SetupSampleRate(sample_rate) < 0) {
02107         goto error;
02108     }
02109     
02110     if (ac3_encoding) {
02111           
02112         if (!fDigitalPlayback) {
02113             jack_error("AC3 encoding can only be used with a digital device");
02114             goto error;
02115         }
02116         
02117         JackAC3EncoderParams params;
02118         memset(&params, 0, sizeof(JackAC3EncoderParams));
02119         params.bitrate = ac3_bitrate;
02120         params.channels = outchannels;
02121         params.sample_rate = sample_rate;
02122         params.lfe = ac3_lfe;
02123         fAC3Encoder = new JackAC3Encoder(params);
02124         
02125         if (!fAC3Encoder || !fAC3Encoder->Init(sample_rate)) {
02126             jack_error("Cannot allocate or init AC3 encoder");
02127             goto error;
02128         }
02129         
02130         // Setup AC3 channel number
02131         fPlaybackChannels = outchannels;
02132         if (ac3_lfe) {
02133             fPlaybackChannels++;
02134         }
02135         
02136         if (fPlaybackChannels < 2 || fPlaybackChannels > 6) {
02137             jack_error("AC3 encoder channels must be between 2 and 6");
02138             goto error;
02139         }
02140         
02141         // Force real output channel number to 2
02142         outchannels = out_maxChannels = 2;
02143         
02144     } else {
02145         fPlaybackChannels = outchannels;
02146     }
02147     
02148     // Core driver may have changed the in/out values
02149     fCaptureChannels = inchannels;
02150 
02151     if (OpenAUHAL(capturing, playing, inchannels, outchannels, in_maxChannels, out_maxChannels, parsed_chan_in_list, parsed_chan_out_list, buffer_size, sample_rate) < 0) {
02152         goto error;
02153     }
02154 
02155     if (capturing && inchannels > 0) {
02156         if (SetupBuffers(inchannels) < 0) {
02157             goto error;
02158         }
02159     }
02160 
02161     if (AddListeners() < 0) {
02162         goto error;
02163     }
02164   
02165     return noErr;
02166 
02167 error:
02168     Close();
02169     return -1;
02170 }
02171 
02172 int JackCoreAudioDriver::Close()
02173 {
02174     jack_log("JackCoreAudioDriver::Close");
02175 
02176     // Generic audio driver close
02177     int res = JackAudioDriver::Close();
02178 
02179     RemoveListeners();
02180     DisposeBuffers();
02181     CloseAUHAL();
02182     DestroyAggregateDevice();
02183     return res;
02184 }
02185 
02186 void JackCoreAudioDriver::UpdateLatencies()
02187 {
02188     UInt32 size;
02189     OSStatus err;
02190     jack_latency_range_t input_range;
02191     jack_latency_range_t output_range;
02192     jack_latency_range_t monitor_range;
02193 
02194     // Get Input latency
02195     size = sizeof(UInt32);
02196     UInt32 value1 = 0;
02197     UInt32 value2 = 0;
02198     err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1);
02199     if (err != noErr) {
02200         jack_error("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
02201     }
02202     err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2);
02203     if (err != noErr) {
02204         jack_error("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
02205     }
02206 
02207     input_range.min = input_range.max = fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency;
02208 
02209     // Get input stream latencies
02210     vector<int> input_latencies;
02211     err = GetStreamLatencies(fDeviceID, true, input_latencies);
02212 
02213     for (int i = 0; i < fCaptureChannels; i++) {
02214         if (err != noErr) {
02215             input_range.min += input_latencies[i];
02216             input_range.max += input_latencies[i];
02217         }
02218         fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &input_range);
02219     }
02220 
02221     // Get Output latency
02222     size = sizeof(UInt32);
02223     value1 = 0;
02224     value2 = 0;
02225     err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyLatency, &size, &value1);
02226     if (err != noErr) {
02227         jack_error("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
02228     }
02229     err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2);
02230     if (err != noErr) {
02231         jack_error("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
02232     }
02233 
02234     // Get output stream latencies
02235     vector<int> output_latencies;
02236     err = GetStreamLatencies(fDeviceID, false, output_latencies);
02237 
02238     // Add more latency if "async" mode is used...
02239     output_range.min = output_range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode)
02240         ? 0 : fEngineControl->fBufferSize * fIOUsage) + value1 + value2 + fPlaybackLatency;
02241 
02242     for (int i = 0; i < fPlaybackChannels; i++) {
02243         if (err != noErr) {
02244             output_range.min += output_latencies[i];
02245             output_range.max += output_latencies[i];
02246         }
02247         fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &output_range);
02248 
02249         // Monitor port
02250         if (fWithMonitorPorts) {
02251             monitor_range.min = monitor_range.max = fEngineControl->fBufferSize;
02252             fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &monitor_range);
02253         }
02254     }
02255 }
02256 
02257 int JackCoreAudioDriver::Attach()
02258 {
02259     OSStatus err;
02260     JackPort* port;
02261     jack_port_id_t port_index;
02262     UInt32 size;
02263     Boolean isWritable;
02264     char channel_name[64];
02265     char name[REAL_JACK_PORT_NAME_SIZE];
02266     char alias[REAL_JACK_PORT_NAME_SIZE];
02267 
02268     jack_log("JackCoreAudioDriver::Attach : fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
02269 
02270     for (int i = 0; i < fCaptureChannels; i++) {
02271 
02272         err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable);
02273         if (err != noErr) {
02274             jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error");
02275         }
02276         if (err == noErr && size > 0) {
02277             err = AudioDeviceGetProperty(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, channel_name);
02278             if (err != noErr) {
02279                 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetProperty kAudioDevicePropertyChannelName error");
02280             }
02281             snprintf(alias, sizeof(alias), "%s:%s:out_%s%u", fAliasName, fCaptureDriverName, channel_name, i + 1);
02282         } else {
02283             snprintf(alias, sizeof(alias), "%s:%s:out%u", fAliasName, fCaptureDriverName, i + 1);
02284         }
02285 
02286         snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, i + 1);
02287 
02288         if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
02289             jack_error("Cannot register port for %s", name);
02290             return -1;
02291         }
02292 
02293         port = fGraphManager->GetPort(port_index);
02294         port->SetAlias(alias);
02295         fCapturePortList[i] = port_index;
02296     }
02297 
02298     for (int i = 0; i < fPlaybackChannels; i++) {
02299 
02300         err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, &isWritable);
02301         if (err != noErr) {
02302             jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error");
02303         }
02304         if (err == noErr && size > 0) {
02305             err = AudioDeviceGetProperty(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, channel_name);
02306             if (err != noErr) {
02307                 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetProperty kAudioDevicePropertyChannelName error");
02308             }
02309             snprintf(alias, sizeof(alias), "%s:%s:in_%s%u", fAliasName, fPlaybackDriverName, channel_name, i + 1);
02310         } else {
02311             snprintf(alias, sizeof(alias), "%s:%s:in%u", fAliasName, fPlaybackDriverName, i + 1);
02312         }
02313 
02314         snprintf(name, sizeof(name), "%s:playback_%d", fClientControl.fName, i + 1);
02315 
02316         if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
02317             jack_error("Cannot register port for %s", name);
02318             return -1;
02319         }
02320 
02321         port = fGraphManager->GetPort(port_index);
02322         port->SetAlias(alias);
02323         fPlaybackPortList[i] = port_index;
02324 
02325         // Monitor ports
02326         if (fWithMonitorPorts) {
02327             jack_log("JackCoreAudioDriver::Attach : create monitor port");
02328             snprintf(name, sizeof(name), "%s:monitor_%u", fClientControl.fName, i + 1);
02329             if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
02330                 jack_error("Cannot register monitor port for %s", name);
02331                 return -1;
02332             } else {
02333                 fMonitorPortList[i] = port_index;
02334             }
02335         }
02336     }
02337     
02338     if (fAC3Encoder) {
02339         // Setup specific AC3 channels names
02340         for (int i = 0; i < fPlaybackChannels; i++) {
02341             fAC3Encoder->GetChannelName("coreaudio", "", alias, i);
02342             port = fGraphManager->GetPort(fPlaybackPortList[i]);
02343             port->SetAlias(alias);
02344         }
02345     }
02346 
02347     UpdateLatencies();
02348 
02349     // Input buffers do no change : prepare them only once
02350     for (int i = 0; i < fCaptureChannels; i++) {
02351         fJackInputData->mBuffers[i].mData = GetInputBuffer(i);
02352     }
02353 
02354     return 0;
02355 }
02356 
02357 int JackCoreAudioDriver::Start()
02358 {
02359     jack_log("JackCoreAudioDriver::Start");
02360     if (JackAudioDriver::Start() == 0) {
02361 
02362         // Waiting for Render callback to be called (= driver has started)
02363         fState = false;
02364         int count = 0;
02365 
02366         if (AudioOutputUnitStart(fAUHAL) == noErr) {
02367 
02368             while (!fState && count++ < WAIT_COUNTER) {
02369                 usleep(100000);
02370                 jack_log("JackCoreAudioDriver::Start : wait count = %d", count);
02371             }
02372 
02373             if (count < WAIT_COUNTER) {
02374                 jack_info("CoreAudio driver is running...");
02375                 return 0;
02376             }
02377 
02378             jack_error("CoreAudio driver cannot start...");
02379         }
02380         JackAudioDriver::Stop();
02381     }
02382     return -1;
02383 }
02384 
02385 int JackCoreAudioDriver::Stop()
02386 {
02387     jack_log("JackCoreAudioDriver::Stop");
02388     int res = (AudioOutputUnitStop(fAUHAL) == noErr) ? 0 : -1;
02389     if (JackAudioDriver::Stop() < 0) {
02390         res = -1;
02391     }
02392     return res;
02393 }
02394 
02395 int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
02396 {
02397     if (SetupBufferSize(buffer_size) < 0) {
02398         return -1;
02399     }
02400 
02401     JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails
02402 
02403     // CoreAudio specific
02404     UpdateLatencies();
02405 
02406     // Input buffers do no change : prepare them only once
02407     for (int i = 0; i < fCaptureChannels; i++) {
02408         fJackInputData->mBuffers[i].mNumberChannels = 1;
02409         fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(jack_default_audio_sample_t);
02410         fJackInputData->mBuffers[i].mData = GetInputBuffer(i);
02411     }
02412 
02413     return 0;
02414 }
02415 
02416 bool JackCoreAudioDriver::TakeHogAux(AudioDeviceID deviceID, bool isInput)
02417 {
02418     pid_t hog_pid;
02419     UInt32 propSize = sizeof(hog_pid);
02420     
02421     OSStatus err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyHogMode, &propSize, &hog_pid);
02422     if (err) {
02423         jack_error("Cannot read hog state...");
02424         printError(err);
02425     }
02426     
02427     jack_log("JackCoreAudioDriver::TakeHogAux : deviceID = %d", deviceID);
02428 
02429     if (hog_pid != getpid()) {
02430         hog_pid = getpid();
02431         err = AudioDeviceSetProperty(deviceID, 0, 0, isInput, kAudioDevicePropertyHogMode, propSize, &hog_pid);
02432         if (err != noErr) {
02433             jack_error("Can't hog device = %d because it's being hogged by another program or cannot be hogged", deviceID);
02434             return false;
02435         }
02436     }
02437 
02438     return true;
02439 }
02440 
02441 bool JackCoreAudioDriver::TakeHog()
02442 {
02443     OSStatus err = noErr;
02444     AudioObjectID sub_device[32];
02445     UInt32 outSize = sizeof(sub_device);
02446     err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
02447 
02448     if (err != noErr) {
02449         jack_log("JackCoreAudioDriver::TakeHog : device does not have subdevices");
02450         return TakeHogAux(fDeviceID, true);
02451     } else {
02452         int num_devices = outSize / sizeof(AudioObjectID);
02453         jack_log("JackCoreAudioDriver::TakeHog : device does has %d subdevices", num_devices);
02454         for (int i = 0; i < num_devices; i++) {
02455             if (!TakeHogAux(sub_device[i], true)) {
02456                 return false;
02457             }
02458         }
02459         return true;
02460     }
02461 }
02462 
02463 bool JackCoreAudioDriver::IsAggregateDevice(AudioDeviceID device)
02464 {
02465     UInt32 deviceType, outSize = sizeof(UInt32);
02466     OSStatus err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyTransportType, &outSize, &deviceType);
02467 
02468     if (err != noErr) {
02469         jack_log("JackCoreAudioDriver::IsAggregateDevice kAudioDevicePropertyTransportType error");
02470         return false;
02471     } else {
02472         return (deviceType == kAudioDeviceTransportTypeAggregate);
02473     }
02474 }
02475 
02476 
02477 } // end of namespace
02478 
02479 
02480 #ifdef __cplusplus
02481 extern "C"
02482 {
02483 #endif
02484 
02485     SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
02486     {
02487         jack_driver_desc_t * desc;
02488         jack_driver_desc_filler_t filler;
02489         jack_driver_param_value_t value;
02490 
02491         desc = jack_driver_descriptor_construct("coreaudio", JackDriverMaster, "Apple CoreAudio API based audio backend", &filler);
02492 
02493         value.i = -1;
02494         jack_driver_descriptor_add_parameter(desc, &filler, "channels", 'c', JackDriverParamInt, &value, NULL, "Maximum number of channels", "Maximum number of channels. If -1, max possible number of channels will be used");
02495         jack_driver_descriptor_add_parameter(desc, &filler, "in-channels", 'i', JackDriverParamInt, &value, NULL, "Maximum number of input channels", "Maximum number of input channels. If -1, max possible number of input channels will be used");
02496         jack_driver_descriptor_add_parameter(desc, &filler, "out-channels", 'o', JackDriverParamInt, &value, NULL, "Maximum number of output channels", "Maximum number of output channels. If -1, max possible number of output channels will be used");
02497 
02498         value.str[0] = 0;
02499         jack_driver_descriptor_add_parameter(desc, &filler, "input-list", 'n', JackDriverParamString, &value, NULL, "Input channel list for channel mapping", "List of input channel number to be opened (syntax like : \"0 3 2\")");
02500         jack_driver_descriptor_add_parameter(desc, &filler, "output-list", 'N', JackDriverParamString, &value, NULL, "Output channel list for channel mapping", "List of output channel number to be opened (syntax like : \"0 3 2\")");
02501 
02502         value.str[0] = 0;
02503         jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Input CoreAudio device name", NULL);
02504         jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Output CoreAudio device name", NULL);
02505 
02506         value.i  = 0;
02507         jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL);
02508         
02509 #ifndef __ppc__
02510         value.i  = 0;
02511         jack_driver_descriptor_add_parameter(desc, &filler, "AC3-encoding", 'a', JackDriverParamBool, &value, NULL, "AC3 multi-channels encoding", NULL);
02512         
02513         value.i  = 448;
02514         jack_driver_descriptor_add_parameter(desc, &filler, "AC3-bitrate", 'b', JackDriverParamUInt, &value, NULL, "AC3 bitrate", NULL);
02515        
02516         value.i  = 0;
02517         jack_driver_descriptor_add_parameter(desc, &filler, "AC3-LFE", 'f', JackDriverParamBool, &value, NULL, "AC3 LFE channel", NULL);
02518 #endif
02519         value.i  = true;
02520         jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL);
02521 
02522         value.ui  = 44100U;
02523         jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
02524 
02525         value.ui  = 256U;
02526         jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
02527 
02528         value.str[0] = 0;
02529         jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "CoreAudio device name", NULL);
02530 
02531         value.ui  = 0;
02532         jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency (frames)", NULL);
02533         jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency (frames)", NULL);
02534 
02535         value.i  = false;
02536         jack_driver_descriptor_add_parameter(desc, &filler, "list-devices", 'l', JackDriverParamBool, &value, NULL, "Display available CoreAudio devices", NULL);
02537 
02538         value.i  = false;
02539         jack_driver_descriptor_add_parameter(desc, &filler, "hog", 'H', JackDriverParamBool, &value, NULL, "Take exclusive access of the audio device", NULL);
02540 
02541         value.ui  = 100;
02542         jack_driver_descriptor_add_parameter(desc, &filler, "async-latency", 'L', JackDriverParamUInt, &value, NULL, "Extra output latency in asynchronous mode (percent)", NULL);
02543 
02544         value.ui  = 100;
02545         jack_driver_descriptor_add_parameter(desc, &filler, "grain", 'G', JackDriverParamUInt, &value, NULL, "Computation grain in RT thread (percent)", NULL);
02546 
02547         value.i = false;
02548         jack_driver_descriptor_add_parameter(desc, &filler, "clock-drift", 's', JackDriverParamBool, &value, NULL, "Clock drift compensation", "Whether to compensate clock drift in dynamically created aggregate device");
02549 
02550         return desc;
02551     }
02552 
02553     SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
02554     {
02555         jack_nframes_t srate = 44100;
02556         jack_nframes_t frames_per_interrupt = 256;
02557         bool capture = false;
02558         bool playback = false;
02559         int chan_in = -1;   // Default: if not explicitely set, then max possible will be used...
02560         int chan_out = -1;  // Default: if not explicitely set, then max possible will be used...
02561         const char* chan_in_list = "";
02562         const char* chan_out_list = "";
02563         bool monitor = false;
02564         const char* capture_driver_uid = "";
02565         const char* playback_driver_uid = "";
02566         const JSList *node;
02567         const jack_driver_param_t *param;
02568         jack_nframes_t systemic_input_latency = 0;
02569         jack_nframes_t systemic_output_latency = 0;
02570         int async_output_latency = 100;
02571         int computation_grain = -1;
02572         bool hogged = false;
02573         bool clock_drift = false;
02574         bool ac3_encoding = false;
02575         int ac3_bitrate = 448;
02576         bool ac3_lfe = false;
02577 
02578         for (node = params; node; node = jack_slist_next(node)) {
02579             param = (const jack_driver_param_t *) node->data;
02580 
02581             switch (param->character) {
02582 
02583                 case 'd':
02584                     capture_driver_uid = param->value.str;
02585                     playback_driver_uid = param->value.str;
02586                     break;
02587 
02588                 case 'D':
02589                     capture = true;
02590                     playback = true;
02591                     break;
02592 
02593                 case 'c':
02594                     chan_in = chan_out = param->value.i;
02595                     break;
02596 
02597                 case 'i':
02598                     chan_in = param->value.i;
02599                     break;
02600 
02601                 case 'o':
02602                     chan_out = param->value.i;
02603                     break;
02604 
02605                 case 'n':
02606                     chan_in_list = param->value.str;
02607                     break;
02608 
02609                 case 'N':
02610                     chan_out_list = param->value.str;
02611                     break;
02612 
02613                 case 'C':
02614                     capture = true;
02615                     if (strcmp(param->value.str, "none") != 0) {
02616                         capture_driver_uid = param->value.str;
02617                     }
02618                     break;
02619 
02620                 case 'P':
02621                     playback = true;
02622                     if (strcmp(param->value.str, "none") != 0) {
02623                         playback_driver_uid = param->value.str;
02624                     }
02625                     break;
02626 
02627                 case 'm':
02628                     monitor = param->value.i;
02629                     break;
02630                     
02631             #ifndef __ppc__            
02632                 case 'a':
02633                     ac3_encoding = param->value.i;
02634                     break;
02635                      
02636                 case 'b':
02637                     ac3_bitrate = param->value.i;
02638                     break;
02639                     
02640                 case 'f':
02641                     ac3_lfe = param->value.i;
02642                     break;
02643             #endif
02644 
02645                 case 'r':
02646                     srate = param->value.ui;
02647                     break;
02648 
02649                 case 'p':
02650                     frames_per_interrupt = (unsigned int)param->value.ui;
02651                     break;
02652 
02653                 case 'I':
02654                     systemic_input_latency = param->value.ui;
02655                     break;
02656 
02657                 case 'O':
02658                     systemic_output_latency = param->value.ui;
02659                     break;
02660 
02661                 case 'l':
02662                     Jack::DisplayDeviceNames();
02663                     // Stops the server in this case
02664                     return NULL;
02665 
02666                 case 'H':
02667                     hogged = true;
02668                     break;
02669 
02670                 case 'L':
02671                     async_output_latency = param->value.ui;
02672                     break;
02673 
02674                 case 'G':
02675                     computation_grain = param->value.ui;
02676                     break;
02677 
02678                 case 's':
02679                     clock_drift = true;
02680                     break;
02681             }
02682         }
02683 
02684         /* duplex is the default */
02685         if (!capture && !playback) {
02686             capture = true;
02687             playback = true;
02688         }
02689 
02690         if (strcmp(chan_in_list, "") != 0 && chan_in >= 0) {
02691             printf("Input channel list and in channels are both specified, input channel list will take over...\n");
02692         }
02693 
02694         if (strcmp(chan_out_list, "") != 0 && chan_out >= 0) {
02695             printf("Output channel list and out channels are both specified, output channel list will take over...\n");
02696         }
02697 
02698         Jack::JackCoreAudioDriver* driver = new Jack::JackCoreAudioDriver("system", "coreaudio", engine, table);
02699         if (driver->Open(frames_per_interrupt,
02700                         srate, capture,
02701                         playback, chan_in,
02702                         chan_out, chan_in_list,
02703                         chan_out_list, monitor,
02704                         capture_driver_uid,
02705                         playback_driver_uid,
02706                         systemic_input_latency,
02707                         systemic_output_latency,
02708                         async_output_latency,
02709                         computation_grain,
02710                         hogged, clock_drift, 
02711                         ac3_encoding, ac3_bitrate, ac3_lfe) == 0) {
02712             return driver;
02713         } else {
02714             delete driver;
02715             return NULL;
02716         }
02717     }
02718 
02719 #ifdef __cplusplus
02720 }
02721 #endif
02722 
02723