Jack2 1.9.8

JackCoreAudioAdapter.cpp

00001 /*
00002 Copyright (C) 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 "JackCoreAudioAdapter.h"
00021 #include "JackError.h"
00022 #include <unistd.h>
00023 
00024 #include <CoreServices/CoreServices.h>
00025 
00026 namespace Jack
00027 {
00028 
00029 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
00030 {
00031     jack_log("- - - - - - - - - - - - - - - - - - - -");
00032     jack_log("  Sample Rate:%f", inDesc->mSampleRate);
00033     jack_log("  Format ID:%.*s", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
00034     jack_log("  Format Flags:%lX", inDesc->mFormatFlags);
00035     jack_log("  Bytes per Packet:%ld", inDesc->mBytesPerPacket);
00036     jack_log("  Frames per Packet:%ld", inDesc->mFramesPerPacket);
00037     jack_log("  Bytes per Frame:%ld", inDesc->mBytesPerFrame);
00038     jack_log("  Channels per Frame:%ld", inDesc->mChannelsPerFrame);
00039     jack_log("  Bits per Channel:%ld", inDesc->mBitsPerChannel);
00040     jack_log("- - - - - - - - - - - - - - - - - - - -");
00041 }
00042 
00043 static OSStatus DisplayDeviceNames()
00044 {
00045     UInt32 size;
00046     Boolean isWritable;
00047     int i, deviceNum;
00048     OSStatus err;
00049     CFStringRef UIname;
00050 
00051     err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
00052     if (err != noErr) {
00053         return err;
00054     }
00055 
00056     deviceNum = size / sizeof(AudioDeviceID);
00057     AudioDeviceID devices[deviceNum];
00058 
00059     err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
00060     if (err != noErr) {
00061         return err;
00062     }
00063 
00064     for (i = 0; i < deviceNum; i++) {
00065         char device_name[256];
00066         char internal_name[256];
00067 
00068         size = sizeof(CFStringRef);
00069         UIname = NULL;
00070         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
00071         if (err == noErr) {
00072             CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
00073         } else {
00074             goto error;
00075         }
00076 
00077         size = 256;
00078         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
00079         if (err != noErr) {
00080             return err;
00081         }
00082 
00083         jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name, internal_name);
00084     }
00085 
00086     return noErr;
00087 
00088 error:
00089     if (UIname != NULL) {
00090         CFRelease(UIname);
00091     }
00092     return err;
00093 }
00094 
00095 static void printError(OSStatus err)
00096 {
00097     switch (err) {
00098         case kAudioHardwareNoError:
00099             jack_log("error code : kAudioHardwareNoError");
00100             break;
00101         case kAudioConverterErr_FormatNotSupported:
00102             jack_log("error code : kAudioConverterErr_FormatNotSupported");
00103             break;
00104         case kAudioConverterErr_OperationNotSupported:
00105             jack_log("error code : kAudioConverterErr_OperationNotSupported");
00106             break;
00107         case kAudioConverterErr_PropertyNotSupported:
00108             jack_log("error code : kAudioConverterErr_PropertyNotSupported");
00109             break;
00110         case kAudioConverterErr_InvalidInputSize:
00111             jack_log("error code : kAudioConverterErr_InvalidInputSize");
00112             break;
00113         case kAudioConverterErr_InvalidOutputSize:
00114             jack_log("error code : kAudioConverterErr_InvalidOutputSize");
00115             break;
00116         case kAudioConverterErr_UnspecifiedError:
00117             jack_log("error code : kAudioConverterErr_UnspecifiedError");
00118             break;
00119         case kAudioConverterErr_BadPropertySizeError:
00120             jack_log("error code : kAudioConverterErr_BadPropertySizeError");
00121             break;
00122         case kAudioConverterErr_RequiresPacketDescriptionsError:
00123             jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
00124             break;
00125         case kAudioConverterErr_InputSampleRateOutOfRange:
00126             jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
00127             break;
00128         case kAudioConverterErr_OutputSampleRateOutOfRange:
00129             jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
00130             break;
00131         case kAudioHardwareNotRunningError:
00132             jack_log("error code : kAudioHardwareNotRunningError");
00133             break;
00134         case kAudioHardwareUnknownPropertyError:
00135             jack_log("error code : kAudioHardwareUnknownPropertyError");
00136             break;
00137         case kAudioHardwareIllegalOperationError:
00138             jack_log("error code : kAudioHardwareIllegalOperationError");
00139             break;
00140         case kAudioHardwareBadDeviceError:
00141             jack_log("error code : kAudioHardwareBadDeviceError");
00142             break;
00143         case kAudioHardwareBadStreamError:
00144             jack_log("error code : kAudioHardwareBadStreamError");
00145             break;
00146         case kAudioDeviceUnsupportedFormatError:
00147             jack_log("error code : kAudioDeviceUnsupportedFormatError");
00148             break;
00149         case kAudioDevicePermissionsError:
00150             jack_log("error code : kAudioDevicePermissionsError");
00151             break;
00152         case kAudioHardwareBadObjectError:
00153             jack_log("error code : kAudioHardwareBadObjectError");
00154             break;
00155         case kAudioHardwareUnsupportedOperationError:
00156             jack_log("error code : kAudioHardwareUnsupportedOperationError");
00157             break;
00158         default:
00159             jack_log("error code : unknown");
00160             break;
00161     }
00162 }
00163 
00164 OSStatus JackCoreAudioAdapter::AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID, void* inClientData)
00165 {
00166     JackCoreAudioAdapter* driver = (JackCoreAudioAdapter*)inClientData;
00167 
00168     switch (inPropertyID) {
00169 
00170             case kAudioHardwarePropertyDevices: {
00171                 jack_log("JackCoreAudioAdapter::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices");
00172                 DisplayDeviceNames();
00173                 break;
00174             }
00175     }
00176 
00177     return noErr;
00178 }
00179 
00180 OSStatus JackCoreAudioAdapter::SRNotificationCallback(AudioDeviceID inDevice,
00181                                                         UInt32 inChannel,
00182                                                         Boolean isInput,
00183                                                         AudioDevicePropertyID inPropertyID,
00184                                                         void* inClientData)
00185 {
00186     JackCoreAudioAdapter* driver = static_cast<JackCoreAudioAdapter*>(inClientData);
00187 
00188     switch (inPropertyID) {
00189 
00190         case kAudioDevicePropertyNominalSampleRate: {
00191             jack_log("JackCoreAudioAdapter::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
00192             driver->fState = true;
00193             break;
00194         }
00195     }
00196 
00197     return noErr;
00198 }
00199 
00200 // A better implementation would try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
00201 OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice,
00202         UInt32 inChannel,
00203         Boolean isInput,
00204         AudioDevicePropertyID inPropertyID,
00205         void* inClientData)
00206 {
00207 
00208     switch (inPropertyID) {
00209 
00210         case kAudioDeviceProcessorOverload: {
00211             jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload");
00212             break;
00213                 }
00214 
00215         case kAudioDevicePropertyStreamConfiguration: {
00216             jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration");
00217             return kAudioHardwareUnsupportedOperationError;
00218         }
00219 
00220         case kAudioDevicePropertyNominalSampleRate: {
00221             jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate");
00222             return kAudioHardwareUnsupportedOperationError;
00223         }
00224 
00225     }
00226     return noErr;
00227 }
00228 
00229 int JackCoreAudioAdapter::AddListeners()
00230 {
00231     OSStatus err = noErr;
00232 
00233     // Add listeners
00234     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
00235     if (err != noErr) {
00236         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
00237         printError(err);
00238         return -1;
00239     }
00240 
00241     err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback, this);
00242     if (err != noErr) {
00243         jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices");
00244         printError(err);
00245         return -1;
00246     }
00247 
00248     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this);
00249     if (err != noErr) {
00250         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
00251         printError(err);
00252         return -1;
00253     }
00254 
00255     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this);
00256     if (err != noErr) {
00257         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
00258         printError(err);
00259         return -1;
00260     }
00261 
00262     err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
00263     if (err != noErr) {
00264         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
00265         printError(err);
00266         return -1;
00267     }
00268 
00269     err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
00270     if (err != noErr) {
00271         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
00272         printError(err);
00273         return -1;
00274     }
00275 
00276     return 0;
00277 }
00278 
00279 void JackCoreAudioAdapter::RemoveListeners()
00280 {
00281     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback);
00282     AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback);
00283     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback);
00284     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback);
00285     AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
00286     AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
00287 }
00288 
00289 OSStatus JackCoreAudioAdapter::Render(void *inRefCon,
00290                                     AudioUnitRenderActionFlags *ioActionFlags,
00291                                     const AudioTimeStamp *inTimeStamp,
00292                                     UInt32 inBusNumber,
00293                                     UInt32 inNumberFrames,
00294                                     AudioBufferList *ioData)
00295 {
00296     JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon);
00297     OSStatus err = AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData);
00298 
00299     if (err == noErr) {
00300         jack_default_audio_sample_t* inputBuffer[adapter->fCaptureChannels];
00301         jack_default_audio_sample_t* outputBuffer[adapter->fPlaybackChannels];
00302 
00303         for (int i = 0; i < adapter->fCaptureChannels; i++) {
00304             inputBuffer[i] = (jack_default_audio_sample_t*)adapter->fInputData->mBuffers[i].mData;
00305         }
00306         for (int i = 0; i < adapter->fPlaybackChannels; i++) {
00307             outputBuffer[i] = (jack_default_audio_sample_t*)ioData->mBuffers[i].mData;
00308         }
00309 
00310         adapter->PushAndPull((jack_default_audio_sample_t**)inputBuffer, (jack_default_audio_sample_t**)outputBuffer, inNumberFrames);
00311         return noErr;
00312     } else {
00313         return err;
00314     }
00315 }
00316 
00317 JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
00318                 :JackAudioAdapterInterface(buffer_size, sample_rate), fInputData(0), fCapturing(false), fPlaying(false), fState(false)
00319 {
00320     const JSList* node;
00321     const jack_driver_param_t* param;
00322     int in_nChannels = 0;
00323     int out_nChannels = 0;
00324     char captureName[256];
00325     char playbackName[256];
00326     fCaptureUID[0] = 0;
00327     fPlaybackUID[0] = 0;
00328     fClockDriftCompensate = false;
00329 
00330     // Default values
00331     fCaptureChannels = -1;
00332     fPlaybackChannels = -1;
00333 
00334     SInt32 major;
00335     SInt32 minor;
00336     Gestalt(gestaltSystemVersionMajor, &major);
00337     Gestalt(gestaltSystemVersionMinor, &minor);
00338 
00339     // Starting with 10.6 systems, the HAL notification thread is created internally
00340     if (major == 10 && minor >= 6) {
00341         CFRunLoopRef theRunLoop = NULL;
00342         AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
00343         OSStatus theError = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
00344         if (theError != noErr) {
00345             jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error");
00346         }
00347     }
00348 
00349     for (node = params; node; node = jack_slist_next(node)) {
00350         param = (const jack_driver_param_t*) node->data;
00351 
00352         switch (param->character) {
00353 
00354             case 'c' :
00355                 fCaptureChannels = fPlaybackChannels = param->value.ui;
00356                 break;
00357 
00358             case 'i':
00359                 fCaptureChannels = param->value.ui;
00360                 break;
00361 
00362             case 'o':
00363                 fPlaybackChannels = param->value.ui;
00364                 break;
00365 
00366             case 'C':
00367                 fCapturing = true;
00368                 strncpy(fCaptureUID, param->value.str, 256);
00369                 break;
00370 
00371             case 'P':
00372                 fPlaying = true;
00373                 strncpy(fPlaybackUID, param->value.str, 256);
00374                 break;
00375 
00376             case 'd':
00377                 strncpy(fCaptureUID, param->value.str, 256);
00378                 strncpy(fPlaybackUID, param->value.str, 256);
00379                 break;
00380 
00381             case 'D':
00382                 fCapturing = fPlaying = true;
00383                 break;
00384 
00385             case 'r':
00386                 SetAdaptedSampleRate(param->value.ui);
00387                 break;
00388 
00389             case 'p':
00390                 SetAdaptedBufferSize(param->value.ui);
00391                 break;
00392 
00393             case 'l':
00394                 DisplayDeviceNames();
00395                 break;
00396 
00397             case 'q':
00398                 fQuality = param->value.ui;
00399                 break;
00400 
00401             case 'g':
00402                 fRingbufferCurSize = param->value.ui;
00403                 fAdaptative = false;
00404                 break;
00405 
00406             case 's':
00407                 fClockDriftCompensate = true;
00408                 break;
00409         }
00410     }
00411 
00412     /* duplex is the default */
00413     if (!fCapturing && !fPlaying) {
00414         fCapturing = true;
00415         fPlaying = true;
00416     }
00417 
00418     if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName, fAdaptedSampleRate) < 0) {
00419        throw std::bad_alloc();
00420     }
00421 
00422     if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0) {
00423         throw std::bad_alloc();
00424     }
00425 
00426     if (SetupBufferSize(fAdaptedBufferSize) < 0) {
00427         throw std::bad_alloc();
00428     }
00429 
00430     if (SetupSampleRate(fAdaptedSampleRate) < 0) {
00431         throw std::bad_alloc();
00432     }
00433 
00434     if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate) < 0) {
00435         throw std::bad_alloc();
00436     }
00437 
00438     if (fCapturing && fCaptureChannels > 0) {
00439         if (SetupBuffers(fCaptureChannels) < 0) {
00440             throw std::bad_alloc();
00441         }
00442     }
00443 
00444     if (AddListeners() < 0) {
00445         throw std::bad_alloc();
00446     }
00447 
00448     GetStreamLatencies(fDeviceID, true, fInputLatencies);
00449     GetStreamLatencies(fDeviceID, false, fOutputLatencies);
00450 }
00451 
00452 OSStatus JackCoreAudioAdapter::GetDefaultDevice(AudioDeviceID* id)
00453 {
00454     OSStatus res;
00455     UInt32 theSize = sizeof(UInt32);
00456     AudioDeviceID inDefault;
00457     AudioDeviceID outDefault;
00458 
00459     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) {
00460         return res;
00461     }
00462 
00463     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) {
00464         return res;
00465     }
00466 
00467     jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);
00468 
00469     // Get the device only if default input and output are the same
00470     if (inDefault != outDefault) {
00471         jack_error("Default input and output devices are not the same !!");
00472         return kAudioHardwareBadDeviceError;
00473     } else if (inDefault == 0) {
00474         jack_error("Default input and output devices are null !!");
00475         return kAudioHardwareBadDeviceError;
00476     } else {
00477         *id = inDefault;
00478         return noErr;
00479     }
00480 }
00481 
00482 OSStatus JackCoreAudioAdapter::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput)
00483 {
00484     OSStatus err = noErr;
00485     UInt32      outSize;
00486     Boolean     outWritable;
00487 
00488     channelCount = 0;
00489     err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
00490     if (err == noErr) {
00491         AudioBufferList bufferList[outSize];
00492         err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
00493         if (err == noErr) {
00494             for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++) {
00495                 channelCount += bufferList->mBuffers[i].mNumberChannels;
00496             }
00497         }
00498     }
00499 
00500     return err;
00501 }
00502 
00503 OSStatus JackCoreAudioAdapter::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id)
00504 {
00505     UInt32 size = sizeof(AudioValueTranslation);
00506     CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
00507     AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
00508 
00509     if (inIUD == NULL) {
00510         return kAudioHardwareUnspecifiedError;
00511     } else {
00512         OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
00513         CFRelease(inIUD);
00514         jack_log("GetDeviceIDFromUID %s %ld", UID, *id);
00515         return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
00516     }
00517 }
00518 
00519 OSStatus JackCoreAudioAdapter::GetDefaultInputDevice(AudioDeviceID* id)
00520 {
00521     OSStatus res;
00522     UInt32 theSize = sizeof(UInt32);
00523     AudioDeviceID inDefault;
00524 
00525     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) {
00526         return res;
00527     }
00528 
00529     if (inDefault == 0) {
00530         jack_error("Error: default input device is 0, please select a correct one !!");
00531         return -1;
00532     }
00533     jack_log("GetDefaultInputDevice: input = %ld ", inDefault);
00534     *id = inDefault;
00535     return noErr;
00536 }
00537 
00538 OSStatus JackCoreAudioAdapter::GetDefaultOutputDevice(AudioDeviceID* id)
00539 {
00540     OSStatus res;
00541     UInt32 theSize = sizeof(UInt32);
00542     AudioDeviceID outDefault;
00543 
00544     if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) {
00545         return res;
00546     }
00547 
00548     if (outDefault == 0) {
00549         jack_error("Error: default output device is 0, please select a correct one !!");
00550         return -1;
00551     }
00552     jack_log("GetDefaultOutputDevice: output = %ld", outDefault);
00553     *id = outDefault;
00554     return noErr;
00555 }
00556 
00557 OSStatus JackCoreAudioAdapter::GetDeviceNameFromID(AudioDeviceID id, char* name)
00558 {
00559     UInt32 size = 256;
00560     return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
00561 }
00562 
00563 AudioDeviceID JackCoreAudioAdapter::GetDeviceIDFromName(const char* name)
00564 {
00565     UInt32 size;
00566     Boolean isWritable;
00567     int i, deviceNum;
00568 
00569     OSStatus err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
00570     if (err != noErr) {
00571         return -1;
00572     }
00573 
00574     deviceNum = size / sizeof(AudioDeviceID);
00575     AudioDeviceID devices[deviceNum];
00576 
00577     err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
00578     if (err != noErr) {
00579         return err;
00580     }
00581 
00582     for (i = 0; i < deviceNum; i++) {
00583         char device_name[256];
00584         size = 256;
00585         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
00586         if (err != noErr) {
00587             return -1;
00588         } else if (strcmp(device_name, name) == 0) {
00589             return devices[i];
00590         }
00591     }
00592 
00593     return -1;
00594 }
00595 
00596 // Setup
00597 int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
00598                                         const char* playback_driver_uid,
00599                                         char* capture_driver_name,
00600                                         char* playback_driver_name,
00601                                         jack_nframes_t samplerate)
00602 {
00603     capture_driver_name[0] = 0;
00604     playback_driver_name[0] = 0;
00605 
00606     // Duplex
00607     if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
00608         jack_log("JackCoreAudioDriver::Open duplex");
00609 
00610         // Same device for capture and playback...
00611         if (strcmp(capture_driver_uid, playback_driver_uid) == 0)  {
00612 
00613             if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
00614                 jack_log("Will take default in/out");
00615                 if (GetDefaultDevice(&fDeviceID) != noErr) {
00616                     jack_error("Cannot open default device");
00617                     return -1;
00618                 }
00619             }
00620             if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
00621                 jack_error("Cannot get device name from device ID");
00622                 return -1;
00623             }
00624 
00625         } else {
00626 
00627             // Creates aggregate device
00628             AudioDeviceID captureID, playbackID;
00629 
00630             if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
00631                 jack_log("Will take default input");
00632                 if (GetDefaultInputDevice(&captureID) != noErr) {
00633                     jack_error("Cannot open default input device");
00634                     return -1;
00635                 }
00636             }
00637 
00638             if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
00639                 jack_log("Will take default output");
00640                 if (GetDefaultOutputDevice(&playbackID) != noErr) {
00641                     jack_error("Cannot open default output device");
00642                     return -1;
00643                 }
00644             }
00645 
00646             if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
00647                 return -1;
00648             }
00649         }
00650 
00651     // Capture only
00652     } else if (strcmp(capture_driver_uid, "") != 0) {
00653         jack_log("JackCoreAudioAdapter::Open capture only");
00654         if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
00655             if (GetDefaultInputDevice(&fDeviceID) != noErr) {
00656                 jack_error("Cannot open default input device");
00657                 return -1;
00658             }
00659         }
00660         if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) {
00661             jack_error("Cannot get device name from device ID");
00662             return -1;
00663         }
00664 
00665     // Playback only
00666     } else if (strcmp(playback_driver_uid, "") != 0) {
00667         jack_log("JackCoreAudioAdapter::Open playback only");
00668         if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
00669             if (GetDefaultOutputDevice(&fDeviceID) != noErr) {
00670                 jack_error("Cannot open default output device");
00671                 return -1;
00672             }
00673         }
00674         if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
00675             jack_error("Cannot get device name from device ID");
00676             return -1;
00677         }
00678 
00679     // Use default driver in duplex mode
00680     } else {
00681         jack_log("JackCoreAudioAdapter::Open default driver");
00682         if (GetDefaultDevice(&fDeviceID) != noErr) {
00683             jack_error("Cannot open default device in duplex mode, so aggregate default input and default output");
00684 
00685             // Creates aggregate device
00686             AudioDeviceID captureID = -1, playbackID = -1;
00687 
00688             if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
00689                 jack_log("Will take default input");
00690                 if (GetDefaultInputDevice(&captureID) != noErr) {
00691                     jack_error("Cannot open default input device");
00692                     goto built_in;
00693                 }
00694             }
00695 
00696             if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
00697                 jack_log("Will take default output");
00698                 if (GetDefaultOutputDevice(&playbackID) != noErr) {
00699                     jack_error("Cannot open default output device");
00700                     goto built_in;
00701                 }
00702             }
00703 
00704             if (captureID > 0 && playbackID > 0) {
00705                 if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
00706                     goto built_in;
00707                 }
00708             } else {
00709                 jack_error("Cannot use default input/output");
00710                 goto built_in;
00711             }
00712         }
00713     }
00714 
00715     return 0;
00716 
00717 built_in:
00718 
00719     // Aggregate built-in input and output
00720     AudioDeviceID captureID = GetDeviceIDFromName("Built-in Input");
00721     AudioDeviceID playbackID = GetDeviceIDFromName("Built-in Output");
00722 
00723     if (captureID > 0 && playbackID > 0) {
00724         if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) {
00725             return -1;
00726         }
00727     } else {
00728         jack_error("Cannot aggregate built-in input and output");
00729         return -1;
00730     }
00731 
00732     return 0;
00733 }
00734 
00735 int JackCoreAudioAdapter::SetupChannels(bool capturing,
00736                                         bool playing,
00737                                         int& inchannels,
00738                                         int& outchannels,
00739                                         int& in_nChannels,
00740                                         int& out_nChannels,
00741                                         bool strict)
00742 {
00743     OSStatus err = noErr;
00744 
00745     if (capturing) {
00746         err = GetTotalChannels(fDeviceID, in_nChannels, true);
00747         if (err != noErr) {
00748             jack_error("Cannot get input channel number");
00749             printError(err);
00750             return -1;
00751         } else {
00752             jack_log("Max input channels : %d", in_nChannels);
00753         }
00754     }
00755 
00756     if (playing) {
00757         err = GetTotalChannels(fDeviceID, out_nChannels, false);
00758         if (err != noErr) {
00759             jack_error("Cannot get output channel number");
00760             printError(err);
00761             return -1;
00762         } else {
00763             jack_log("Max output channels : %d", out_nChannels);
00764         }
00765     }
00766 
00767     if (inchannels > in_nChannels) {
00768         jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels);
00769         if (strict) {
00770             return -1;
00771         }
00772     }
00773 
00774     if (outchannels > out_nChannels) {
00775         jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels);
00776         if (strict) {
00777             return -1;
00778         }
00779     }
00780 
00781     if (inchannels == -1) {
00782         jack_log("Setup max in channels = %ld", in_nChannels);
00783         inchannels = in_nChannels;
00784     }
00785 
00786     if (outchannels == -1) {
00787         jack_log("Setup max out channels = %ld", out_nChannels);
00788         outchannels = out_nChannels;
00789     }
00790 
00791     return 0;
00792 }
00793 
00794 int JackCoreAudioAdapter::SetupBufferSize(jack_nframes_t buffer_size)
00795 {
00796     // Setting buffer size
00797     UInt32 outSize = sizeof(UInt32);
00798     OSStatus err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size);
00799     if (err != noErr) {
00800         jack_error("Cannot set buffer size %ld", buffer_size);
00801         printError(err);
00802         return -1;
00803     }
00804 
00805     return 0;
00806 }
00807 
00808 int JackCoreAudioAdapter::SetupSampleRate(jack_nframes_t samplerate)
00809 {
00810     return SetupSampleRateAux(fDeviceID, samplerate);
00811 }
00812 
00813 int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframes_t samplerate)
00814 {
00815     OSStatus err = noErr;
00816     UInt32 outSize;
00817     Float64 sampleRate;
00818 
00819     // Get sample rate
00820     outSize =  sizeof(Float64);
00821     err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
00822     if (err != noErr) {
00823         jack_error("Cannot get current sample rate");
00824         printError(err);
00825         return -1;
00826     } else {
00827         jack_log("Current sample rate = %f", sampleRate);
00828     }
00829 
00830     // If needed, set new sample rate
00831     if (samplerate != (jack_nframes_t)sampleRate) {
00832         sampleRate = (Float64)samplerate;
00833 
00834         // To get SR change notification
00835         err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
00836         if (err != noErr) {
00837             jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
00838             printError(err);
00839             return -1;
00840         }
00841         err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
00842         if (err != noErr) {
00843             jack_error("Cannot set sample rate = %ld", samplerate);
00844             printError(err);
00845             return -1;
00846         }
00847 
00848         // Waiting for SR change notification
00849         int count = 0;
00850         while (!fState && count++ < WAIT_COUNTER) {
00851             usleep(100000);
00852             jack_log("Wait count = %d", count);
00853         }
00854 
00855         // Remove SR change notification
00856         AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
00857     }
00858 
00859     return 0;
00860 }
00861 
00862 int JackCoreAudioAdapter::SetupBuffers(int inchannels)
00863 {
00864     jack_log("JackCoreAudioAdapter::SetupBuffers: input = %ld", inchannels);
00865 
00866     // Prepare buffers
00867     fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
00868     fInputData->mNumberBuffers = inchannels;
00869     for (int i = 0; i < fCaptureChannels; i++) {
00870         fInputData->mBuffers[i].mNumberChannels = 1;
00871         fInputData->mBuffers[i].mDataByteSize = fAdaptedBufferSize * sizeof(jack_default_audio_sample_t);
00872         fInputData->mBuffers[i].mData = malloc(fAdaptedBufferSize * sizeof(jack_default_audio_sample_t));
00873     }
00874     return 0;
00875 }
00876 
00877 void JackCoreAudioAdapter::DisposeBuffers()
00878 {
00879     if (fInputData) {
00880         for (int i = 0; i < fCaptureChannels; i++) {
00881             free(fInputData->mBuffers[i].mData);
00882         }
00883         free(fInputData);
00884         fInputData = 0;
00885     }
00886 }
00887 
00888 int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
00889                                    bool playing,
00890                                    int inchannels,
00891                                    int outchannels,
00892                                    int in_nChannels,
00893                                    int out_nChannels,
00894                                    jack_nframes_t buffer_size,
00895                                    jack_nframes_t samplerate)
00896 {
00897     ComponentResult err1;
00898     UInt32 enableIO;
00899     AudioStreamBasicDescription srcFormat, dstFormat;
00900     AudioDeviceID currAudioDeviceID;
00901     UInt32 size;
00902 
00903     jack_log("OpenAUHAL capturing = %d playing = %d inchannels = %d outchannels = %d in_nChannels = %d out_nChannels = %d", capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels);
00904 
00905     if (inchannels == 0 && outchannels == 0) {
00906         jack_error("No input and output channels...");
00907         return -1;
00908     }
00909 
00910     // AUHAL
00911     ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
00912     Component HALOutput = FindNextComponent(NULL, &cd);
00913 
00914     err1 = OpenAComponent(HALOutput, &fAUHAL);
00915     if (err1 != noErr) {
00916         jack_error("Error calling OpenAComponent");
00917         printError(err1);
00918         goto error;
00919     }
00920 
00921     err1 = AudioUnitInitialize(fAUHAL);
00922     if (err1 != noErr) {
00923         jack_error("Cannot initialize AUHAL unit");
00924         printError(err1);
00925         goto error;
00926     }
00927 
00928     // Start I/O
00929     if (capturing && inchannels > 0) {
00930         enableIO = 1;
00931         jack_log("Setup AUHAL input on");
00932     } else {
00933         enableIO = 0;
00934         jack_log("Setup AUHAL input off");
00935     }
00936 
00937     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
00938     if (err1 != noErr) {
00939         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
00940         printError(err1);
00941         goto error;
00942     }
00943 
00944     if (playing && outchannels > 0) {
00945         enableIO = 1;
00946         jack_log("Setup AUHAL output on");
00947     } else {
00948         enableIO = 0;
00949         jack_log("Setup AUHAL output off");
00950     }
00951 
00952     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
00953     if (err1 != noErr) {
00954         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
00955         printError(err1);
00956         goto error;
00957     }
00958 
00959     size = sizeof(AudioDeviceID);
00960     err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size);
00961     if (err1 != noErr) {
00962         jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
00963         printError(err1);
00964         goto error;
00965     } else {
00966         jack_log("AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID);
00967     }
00968 
00969     // Setup up choosen device, in both input and output cases
00970     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
00971     if (err1 != noErr) {
00972         jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
00973         printError(err1);
00974         goto error;
00975     }
00976 
00977     // Set buffer size
00978     if (capturing && inchannels > 0) {
00979         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32));
00980         if (err1 != noErr) {
00981             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
00982             printError(err1);
00983             goto error;
00984         }
00985     }
00986 
00987     if (playing && outchannels > 0) {
00988         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&buffer_size, sizeof(UInt32));
00989         if (err1 != noErr) {
00990             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
00991             printError(err1);
00992             goto error;
00993         }
00994     }
00995 
00996     // Setup channel map
00997     if (capturing && inchannels > 0 && inchannels <= in_nChannels) {
00998         SInt32 chanArr[in_nChannels];
00999         for (int i = 0; i < in_nChannels; i++) {
01000             chanArr[i] = -1;
01001         }
01002         for (int i = 0; i < inchannels; i++) {
01003             chanArr[i] = i;
01004         }
01005         AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
01006         if (err1 != noErr) {
01007             jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
01008             printError(err1);
01009             goto error;
01010         }
01011     }
01012 
01013     if (playing && outchannels > 0 && outchannels <= out_nChannels) {
01014         SInt32 chanArr[out_nChannels];
01015         for (int i = 0; i < out_nChannels; i++) {
01016             chanArr[i] = -1;
01017         }
01018         for (int i = 0; i < outchannels; i++) {
01019             chanArr[i] = i;
01020         }
01021         err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
01022         if (err1 != noErr) {
01023             jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
01024             printError(err1);
01025             goto error;
01026         }
01027     }
01028 
01029     // Setup stream converters
01030     if (capturing && inchannels > 0) {
01031 
01032         size = sizeof(AudioStreamBasicDescription);
01033         err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size);
01034         if (err1 != noErr) {
01035             jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
01036             printError(err1);
01037             goto error;
01038         }
01039         PrintStreamDesc(&srcFormat);
01040 
01041         jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
01042         srcFormat.mSampleRate = samplerate;
01043         srcFormat.mFormatID = kAudioFormatLinearPCM;
01044         srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
01045         srcFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t);
01046         srcFormat.mFramesPerPacket = 1;
01047         srcFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t);
01048         srcFormat.mChannelsPerFrame = inchannels;
01049         srcFormat.mBitsPerChannel = 32;
01050         PrintStreamDesc(&srcFormat);
01051 
01052         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
01053 
01054         if (err1 != noErr) {
01055             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
01056             printError(err1);
01057             goto error;
01058         }
01059     }
01060 
01061     if (playing && outchannels > 0) {
01062 
01063         size = sizeof(AudioStreamBasicDescription);
01064         err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size);
01065         if (err1 != noErr) {
01066             jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
01067             printError(err1);
01068             goto error;
01069         }
01070         PrintStreamDesc(&dstFormat);
01071 
01072         jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
01073         dstFormat.mSampleRate = samplerate;
01074         dstFormat.mFormatID = kAudioFormatLinearPCM;
01075         dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
01076         dstFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t);
01077         dstFormat.mFramesPerPacket = 1;
01078         dstFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t);
01079         dstFormat.mChannelsPerFrame = outchannels;
01080         dstFormat.mBitsPerChannel = 32;
01081         PrintStreamDesc(&dstFormat);
01082 
01083         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
01084 
01085         if (err1 != noErr) {
01086             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
01087             printError(err1);
01088             goto error;
01089         }
01090     }
01091 
01092     // Setup callbacks
01093     if (inchannels > 0 && outchannels == 0) {
01094         AURenderCallbackStruct output;
01095         output.inputProc = Render;
01096         output.inputProcRefCon = this;
01097         err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
01098         if (err1 != noErr) {
01099             jack_error("Error calling  AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
01100             printError(err1);
01101             goto error;
01102         }
01103     } else {
01104         AURenderCallbackStruct output;
01105         output.inputProc = Render;
01106         output.inputProcRefCon = this;
01107         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
01108         if (err1 != noErr) {
01109             jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
01110             printError(err1);
01111             goto error;
01112         }
01113     }
01114 
01115     return 0;
01116 
01117 error:
01118     CloseAUHAL();
01119     return -1;
01120 }
01121 
01122 OSStatus JackCoreAudioAdapter::DestroyAggregateDevice()
01123 {
01124     OSStatus osErr = noErr;
01125     AudioObjectPropertyAddress pluginAOPA;
01126     pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
01127     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01128     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01129     UInt32 outDataSize;
01130 
01131     osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
01132     if (osErr != noErr) {
01133         jack_error("JackCoreAudioAdapter::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
01134         printError(osErr);
01135         return osErr;
01136     }
01137 
01138     osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
01139     if (osErr != noErr) {
01140         jack_error("JackCoreAudioAdapter::DestroyAggregateDevice : AudioObjectGetPropertyData error");
01141         printError(osErr);
01142         return osErr;
01143     }
01144 
01145     return noErr;
01146 }
01147 
01148 static CFStringRef GetDeviceName(AudioDeviceID id)
01149 {
01150     UInt32 size = sizeof(CFStringRef);
01151     CFStringRef UIname;
01152     OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
01153     return (err == noErr) ? UIname : NULL;
01154 }
01155 
01156 OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
01157 {
01158     OSStatus err = noErr;
01159     AudioObjectID sub_device[32];
01160     UInt32 outSize = sizeof(sub_device);
01161 
01162     err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
01163     vector<AudioDeviceID> captureDeviceIDArray;
01164 
01165     if (err != noErr) {
01166         jack_log("Input device does not have subdevices");
01167         captureDeviceIDArray.push_back(captureDeviceID);
01168     } else {
01169         int num_devices = outSize / sizeof(AudioObjectID);
01170         jack_log("Input device has %d subdevices", num_devices);
01171         for (int i = 0; i < num_devices; i++) {
01172             captureDeviceIDArray.push_back(sub_device[i]);
01173         }
01174     }
01175 
01176     err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
01177     vector<AudioDeviceID> playbackDeviceIDArray;
01178 
01179     if (err != noErr) {
01180         jack_log("Output device does not have subdevices");
01181         playbackDeviceIDArray.push_back(playbackDeviceID);
01182     } else {
01183         int num_devices = outSize / sizeof(AudioObjectID);
01184         jack_log("Output device has %d subdevices", num_devices);
01185         for (int i = 0; i < num_devices; i++) {
01186             playbackDeviceIDArray.push_back(sub_device[i]);
01187         }
01188     }
01189 
01190     return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice);
01191 }
01192 
01193 OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
01194 {
01195     OSStatus osErr = noErr;
01196     UInt32 outSize;
01197     Boolean outWritable;
01198 
01199     // Prepare sub-devices for clock drift compensation
01200     // Workaround for bug in the HAL : until 10.6.2
01201     AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
01202     AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
01203     UInt32 theQualifierDataSize = sizeof(AudioObjectID);
01204     AudioClassID inClass = kAudioSubDeviceClassID;
01205     void* theQualifierData = &inClass;
01206     UInt32 subDevicesNum = 0;
01207 
01208     //---------------------------------------------------------------------------
01209     // Setup SR of both devices otherwise creating AD may fail...
01210     //---------------------------------------------------------------------------
01211     UInt32 keptclockdomain = 0;
01212     UInt32 clockdomain = 0;
01213     outSize = sizeof(UInt32);
01214     bool need_clock_drift_compensation = false;
01215 
01216     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01217         if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) {
01218             jack_error("JackCoreAudioAdapter::CreateAggregateDevice : cannot set SR of input device");
01219         } else  {
01220             // Check clock domain
01221             osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
01222             if (osErr != 0) {
01223                 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
01224                 printError(osErr);
01225             } else {
01226                 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
01227                 jack_log("JackCoreAudioAdapter::CreateAggregateDevice : input clockdomain = %d", clockdomain);
01228                 if (clockdomain != 0 && clockdomain != keptclockdomain) {
01229                     jack_error("JackCoreAudioAdapter::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
01230                     need_clock_drift_compensation = true;
01231                 }
01232             }
01233         }
01234     }
01235 
01236     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01237         if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) {
01238             jack_error("JackCoreAudioAdapter::CreateAggregateDevice : cannot set SR of output device");
01239         } else {
01240             // Check clock domain
01241             osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
01242             if (osErr != 0) {
01243                 jack_error("JackCoreAudioAdapter::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
01244                 printError(osErr);
01245             } else {
01246                 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
01247                 jack_log("JackCoreAudioAdapter::CreateAggregateDevice : output clockdomain = %d", clockdomain);
01248                 if (clockdomain != 0 && clockdomain != keptclockdomain) {
01249                     jack_error("JackCoreAudioAdapter::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
01250                     need_clock_drift_compensation = true;
01251                 }
01252             }
01253         }
01254     }
01255 
01256     // If no valid clock domain was found, then assume we have to compensate...
01257     if (keptclockdomain == 0) {
01258         need_clock_drift_compensation = true;
01259     }
01260 
01261     //---------------------------------------------------------------------------
01262     // Start to create a new aggregate by getting the base audio hardware plugin
01263     //---------------------------------------------------------------------------
01264 
01265     char device_name[256];
01266     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01267         GetDeviceNameFromID(captureDeviceID[i], device_name);
01268         jack_info("Separated input = '%s' ", device_name);
01269     }
01270 
01271     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01272         GetDeviceNameFromID(playbackDeviceID[i], device_name);
01273         jack_info("Separated output = '%s' ", device_name);
01274     }
01275 
01276     osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
01277     if (osErr != noErr) {
01278         jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
01279         printError(osErr);
01280         return osErr;
01281     }
01282 
01283     AudioValueTranslation pluginAVT;
01284 
01285     CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
01286 
01287     pluginAVT.mInputData = &inBundleRef;
01288     pluginAVT.mInputDataSize = sizeof(inBundleRef);
01289     pluginAVT.mOutputData = &fPluginID;
01290     pluginAVT.mOutputDataSize = sizeof(fPluginID);
01291 
01292     osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
01293     if (osErr != noErr) {
01294         jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
01295         printError(osErr);
01296         return osErr;
01297     }
01298 
01299     //-------------------------------------------------
01300     // Create a CFDictionary for our aggregate device
01301     //-------------------------------------------------
01302 
01303     CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
01304 
01305     CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
01306     CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
01307 
01308     // add the name of the device to the dictionary
01309     CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
01310 
01311     // add our choice of UID for the aggregate device to the dictionary
01312     CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
01313 
01314     // add a "private aggregate key" to the dictionary
01315     int value = 1;
01316     CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
01317 
01318     SInt32 system;
01319     Gestalt(gestaltSystemVersion, &system);
01320 
01321     jack_log("JackCoreAudioAdapter::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054);
01322 
01323     // Starting with 10.5.4 systems, the AD can be internal... (better)
01324     if (system < 0x00001054) {
01325         jack_log("JackCoreAudioAdapter::CreateAggregateDevice : public aggregate device....");
01326     } else {
01327         jack_log("JackCoreAudioAdapter::CreateAggregateDevice : private aggregate device....");
01328         CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
01329     }
01330 
01331     // Prepare sub-devices for clock drift compensation
01332     CFMutableArrayRef subDevicesArrayClock = NULL;
01333 
01334     /*
01335      if (fClockDriftCompensate) {
01336      if (need_clock_drift_compensation) {
01337      jack_info("Clock drift compensation activated...");
01338      subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
01339 
01340      for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01341      CFStringRef UID = GetDeviceName(captureDeviceID[i]);
01342      if (UID) {
01343      CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
01344      CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
01345      CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
01346      //CFRelease(UID);
01347      CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
01348      }
01349      }
01350 
01351      for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01352      CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
01353      if (UID) {
01354      CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
01355      CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
01356      CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
01357      //CFRelease(UID);
01358      CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
01359      }
01360      }
01361 
01362      // add sub-device clock array for the aggregate device to the dictionary
01363      CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
01364      } else {
01365      jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
01366      }
01367      }
01368      */
01369 
01370     //-------------------------------------------------
01371     // Create a CFMutableArray for our sub-device list
01372     //-------------------------------------------------
01373 
01374     // we need to append the UID for each device to a CFMutableArray, so create one here
01375     CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
01376 
01377     vector<CFStringRef> captureDeviceUID;
01378     for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
01379         CFStringRef ref = GetDeviceName(captureDeviceID[i]);
01380         if (ref == NULL) {
01381             return -1;
01382         }
01383         captureDeviceUID.push_back(ref);
01384         // input sub-devices in this example, so append the sub-device's UID to the CFArray
01385         CFArrayAppendValue(subDevicesArray, ref);
01386     }
01387 
01388     vector<CFStringRef> playbackDeviceUID;
01389     for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
01390         CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
01391         if (ref == NULL) {
01392             return -1;
01393         }
01394         playbackDeviceUID.push_back(ref);
01395         // output sub-devices in this example, so append the sub-device's UID to the CFArray
01396         CFArrayAppendValue(subDevicesArray, ref);
01397     }
01398 
01399     //-----------------------------------------------------------------------
01400     // Feed the dictionary to the plugin, to create a blank aggregate device
01401     //-----------------------------------------------------------------------
01402 
01403     AudioObjectPropertyAddress pluginAOPA;
01404     pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
01405     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01406     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01407     UInt32 outDataSize;
01408 
01409     osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
01410     if (osErr != noErr) {
01411         jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectGetPropertyDataSize error");
01412         printError(osErr);
01413         goto error;
01414     }
01415 
01416     osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
01417     if (osErr != noErr) {
01418         jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectGetPropertyData error");
01419         printError(osErr);
01420         goto error;
01421     }
01422 
01423     // pause for a bit to make sure that everything completed correctly
01424     // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
01425     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01426 
01427     //-------------------------
01428     // Set the sub-device list
01429     //-------------------------
01430 
01431     pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
01432     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01433     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01434     outDataSize = sizeof(CFMutableArrayRef);
01435     osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
01436     if (osErr != noErr) {
01437         jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error");
01438         printError(osErr);
01439         goto error;
01440     }
01441 
01442     // pause again to give the changes time to take effect
01443     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01444 
01445     //-----------------------
01446     // Set the master device
01447     //-----------------------
01448 
01449     // set the master device manually (this is the device which will act as the master clock for the aggregate device)
01450     // pass in the UID of the device you want to use
01451     pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
01452     pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
01453     pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
01454     outDataSize = sizeof(CFStringRef);
01455     osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]);  // First apture is master...
01456     if (osErr != noErr) {
01457         jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectSetPropertyData for master device error");
01458         printError(osErr);
01459         goto error;
01460     }
01461 
01462     // pause again to give the changes time to take effect
01463     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01464 
01465     // Prepare sub-devices for clock drift compensation
01466     // Workaround for bug in the HAL : until 10.6.2
01467 
01468     if (fClockDriftCompensate) {
01469         if (need_clock_drift_compensation) {
01470             jack_info("Clock drift compensation activated...");
01471 
01472             // Get the property data size
01473             osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
01474             if (osErr != noErr) {
01475                 jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
01476                 printError(osErr);
01477             }
01478 
01479             //  Calculate the number of object IDs
01480             subDevicesNum = outSize / sizeof(AudioObjectID);
01481             jack_info("JackCoreAudioAdapter::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum);
01482             AudioObjectID subDevices[subDevicesNum];
01483             outSize = sizeof(subDevices);
01484 
01485             osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
01486             if (osErr != noErr) {
01487                 jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
01488                 printError(osErr);
01489             }
01490 
01491             // Set kAudioSubDevicePropertyDriftCompensation property...
01492             for (UInt32 index = 0; index < subDevicesNum; ++index) {
01493                 UInt32 theDriftCompensationValue = 1;
01494                 osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue);
01495                 if (osErr != noErr) {
01496                     jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error");
01497                     printError(osErr);
01498                 }
01499             }
01500         } else {
01501             jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
01502         }
01503     }
01504 
01505     // pause again to give the changes time to take effect
01506     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
01507 
01508     //----------
01509     // Clean up
01510     //----------
01511 
01512     // release the private AD key
01513     CFRelease(AggregateDeviceNumberRef);
01514 
01515     // release the CF objects we have created - we don't need them any more
01516     CFRelease(aggDeviceDict);
01517     CFRelease(subDevicesArray);
01518 
01519     if (subDevicesArrayClock) {
01520         CFRelease(subDevicesArrayClock);
01521     }
01522 
01523     // release the device UID
01524     for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
01525         CFRelease(captureDeviceUID[i]);
01526     }
01527 
01528     for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
01529         CFRelease(playbackDeviceUID[i]);
01530     }
01531 
01532     jack_log("New aggregate device %ld", *outAggregateDevice);
01533     return noErr;
01534 
01535 error:
01536     DestroyAggregateDevice();
01537     return -1;
01538 }
01539 
01540 
01541 bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device)
01542 {
01543     OSStatus err = noErr;
01544     AudioObjectID sub_device[32];
01545     UInt32 outSize = sizeof(sub_device);
01546     err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
01547 
01548     if (err != noErr) {
01549         jack_log("Device does not have subdevices");
01550         return false;
01551     } else {
01552         int num_devices = outSize / sizeof(AudioObjectID);
01553         jack_log("Device does has %d subdevices", num_devices);
01554         return true;
01555     }
01556 }
01557 
01558 void JackCoreAudioAdapter::CloseAUHAL()
01559 {
01560     AudioUnitUninitialize(fAUHAL);
01561     CloseComponent(fAUHAL);
01562 }
01563 
01564 int JackCoreAudioAdapter::Open()
01565 {
01566     return (AudioOutputUnitStart(fAUHAL) != noErr)  ? -1 : 0;
01567 }
01568 
01569 int JackCoreAudioAdapter::Close()
01570 {
01571 #ifdef JACK_MONITOR
01572     fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
01573 #endif
01574     AudioOutputUnitStop(fAUHAL);
01575     DisposeBuffers();
01576     CloseAUHAL();
01577     RemoveListeners();
01578     if (fPluginID > 0) {
01579         DestroyAggregateDevice();
01580     }
01581     return 0;
01582 }
01583 
01584 int JackCoreAudioAdapter::SetSampleRate(jack_nframes_t sample_rate)
01585 {
01586     JackAudioAdapterInterface::SetHostSampleRate(sample_rate);
01587     Close();
01588     return Open();
01589 }
01590 
01591 int JackCoreAudioAdapter::SetBufferSize(jack_nframes_t buffer_size)
01592 {
01593     JackAudioAdapterInterface::SetHostBufferSize(buffer_size);
01594     Close();
01595     return Open();
01596 }
01597 
01598 OSStatus JackCoreAudioAdapter::GetStreamLatencies(AudioDeviceID device, bool isInput, vector<int>& latencies)
01599 {
01600     OSStatus err = noErr;
01601     UInt32 outSize1, outSize2, outSize3;
01602     Boolean     outWritable;
01603 
01604     err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, &outWritable);
01605     if (err == noErr) {
01606         int stream_count = outSize1 / sizeof(UInt32);
01607         AudioStreamID streamIDs[stream_count];
01608         AudioBufferList bufferList[stream_count];
01609         UInt32 streamLatency;
01610         outSize2 = sizeof(UInt32);
01611 
01612         err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, streamIDs);
01613         if (err != noErr) {
01614             jack_error("GetStreamLatencies kAudioDevicePropertyStreams err = %d", err);
01615             return err;
01616         }
01617 
01618         err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, &outWritable);
01619         if (err != noErr) {
01620             jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err);
01621             return err;
01622         }
01623 
01624         for (int i = 0; i < stream_count; i++) {
01625             err = AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &outSize2, &streamLatency);
01626             if (err != noErr) {
01627                 jack_error("GetStreamLatencies kAudioStreamPropertyLatency err = %d", err);
01628                 return err;
01629             }
01630             err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, bufferList);
01631             if (err != noErr) {
01632                 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err);
01633                 return err;
01634             }
01635             // Push 'channel' time the stream latency
01636             for (uint k = 0; k < bufferList->mBuffers[i].mNumberChannels; k++) {
01637                 latencies.push_back(streamLatency);
01638             }
01639         }
01640     }
01641     return err;
01642 }
01643 
01644 int JackCoreAudioAdapter::GetLatency(int port_index, bool input)
01645 {
01646     UInt32 size = sizeof(UInt32);
01647     UInt32 value1 = 0;
01648     UInt32 value2 = 0;
01649 
01650     OSStatus err = AudioDeviceGetProperty(fDeviceID, 0, input, kAudioDevicePropertyLatency, &size, &value1);
01651     if (err != noErr) {
01652         jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
01653     }
01654     err = AudioDeviceGetProperty(fDeviceID, 0, input, kAudioDevicePropertySafetyOffset, &size, &value2);
01655     if (err != noErr) {
01656         jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
01657     }
01658 
01659     // TODO : add stream latency
01660 
01661     return value1 + value2 + fAdaptedBufferSize;
01662 }
01663 
01664 int JackCoreAudioAdapter::GetInputLatency(int port_index)
01665 {
01666     if (port_index < int(fInputLatencies.size())) {
01667         return GetLatency(port_index, true) + fInputLatencies[port_index];
01668     } else {
01669         // No stream latency
01670         return GetLatency(port_index, true);
01671     }
01672 }
01673 
01674 int JackCoreAudioAdapter::GetOutputLatency(int port_index)
01675 {
01676     if (port_index < int(fOutputLatencies.size())) {
01677         return GetLatency(port_index, false) + fOutputLatencies[port_index];
01678     } else {
01679         // No stream latency
01680         return GetLatency(port_index, false);
01681     }
01682 }
01683 
01684 } // namespace
01685 
01686 #ifdef __cplusplus
01687 extern "C"
01688 {
01689 #endif
01690 
01691    SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
01692    {
01693         jack_driver_desc_t * desc;
01694         jack_driver_desc_filler_t filler;
01695         jack_driver_param_value_t value;
01696 
01697         desc = jack_driver_descriptor_construct("audioadapter", JackDriverNone, "netjack audio <==> net backend adapter", &filler);
01698 
01699         value.i = -1;
01700         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");
01701         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");
01702         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");
01703 
01704         value.str[0] = 0;
01705         jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Input CoreAudio device name", NULL);
01706         jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Output CoreAudio device name", NULL);
01707 
01708         value.ui = 44100U;
01709         jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
01710 
01711         value.ui = 512U;
01712         jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
01713 
01714         value.i = TRUE;
01715         jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL);
01716 
01717         value.str[0] = 0;
01718         jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "CoreAudio device name", NULL);
01719 
01720         value.i = TRUE;
01721         jack_driver_descriptor_add_parameter(desc, &filler, "list-devices", 'l', JackDriverParamBool, &value, NULL, "Display available CoreAudio devices", NULL);
01722 
01723         value.ui = 0;
01724         jack_driver_descriptor_add_parameter(desc, &filler, "quality", 'q', JackDriverParamInt, &value, NULL, "Resample algorithm quality (0 - 4)", NULL);
01725 
01726         value.ui = 32768;
01727         jack_driver_descriptor_add_parameter(desc, &filler, "ring-buffer", 'g', JackDriverParamInt, &value, NULL, "Fixed ringbuffer size", "Fixed ringbuffer size (if not set => automatic adaptative)");
01728 
01729         value.i = FALSE;
01730         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");
01731 
01732         return desc;
01733     }
01734 
01735 
01736 #ifdef __cplusplus
01737 }
01738 #endif
01739