Jack2 1.9.10

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