JackCoreAudioDriver.cpp 50.8 KB
Newer Older
sletz's avatar
sletz committed
1
/*
sletz's avatar
sletz committed
2
Copyright (C) 2004-2008 Grame
sletz's avatar
sletz committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

20
21
22
23
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif

sletz's avatar
sletz committed
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "JackCoreAudioDriver.h"
#include "JackEngineControl.h"
#include "JackMachThread.h"
#include "JackGraphManager.h"
#include "JackError.h"
#include "JackClientControl.h"
#include "JackDriverLoader.h"
#include "JackGlobals.h"
#include <iostream>

namespace Jack
{

static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
{
sletz's avatar
sletz committed
39
40
41
42
43
44
45
46
47
48
    jack_log("- - - - - - - - - - - - - - - - - - - -");
    jack_log("  Sample Rate:%f", inDesc->mSampleRate);
    jack_log("  Format ID:%.*s", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
    jack_log("  Format Flags:%lX", inDesc->mFormatFlags);
    jack_log("  Bytes per Packet:%ld", inDesc->mBytesPerPacket);
    jack_log("  Frames per Packet:%ld", inDesc->mFramesPerPacket);
    jack_log("  Bytes per Frame:%ld", inDesc->mBytesPerFrame);
    jack_log("  Channels per Frame:%ld", inDesc->mChannelsPerFrame);
    jack_log("  Bits per Channel:%ld", inDesc->mBitsPerChannel);
    jack_log("- - - - - - - - - - - - - - - - - - - -");
sletz's avatar
sletz committed
49
50
51
52
53
54
}

static void printError(OSStatus err)
{
    switch (err) {
        case kAudioHardwareNoError:
sletz's avatar
sletz committed
55
            jack_log("error code : kAudioHardwareNoError");
sletz's avatar
sletz committed
56
57
            break;
        case kAudioConverterErr_FormatNotSupported:
sletz's avatar
sletz committed
58
            jack_log("error code : kAudioConverterErr_FormatNotSupported");
sletz's avatar
sletz committed
59
60
            break;
        case kAudioConverterErr_OperationNotSupported:
sletz's avatar
sletz committed
61
            jack_log("error code : kAudioConverterErr_OperationNotSupported");
sletz's avatar
sletz committed
62
63
            break;
        case kAudioConverterErr_PropertyNotSupported:
sletz's avatar
sletz committed
64
            jack_log("error code : kAudioConverterErr_PropertyNotSupported");
sletz's avatar
sletz committed
65
66
            break;
        case kAudioConverterErr_InvalidInputSize:
sletz's avatar
sletz committed
67
            jack_log("error code : kAudioConverterErr_InvalidInputSize");
sletz's avatar
sletz committed
68
69
            break;
        case kAudioConverterErr_InvalidOutputSize:
sletz's avatar
sletz committed
70
            jack_log("error code : kAudioConverterErr_InvalidOutputSize");
sletz's avatar
sletz committed
71
72
            break;
        case kAudioConverterErr_UnspecifiedError:
sletz's avatar
sletz committed
73
            jack_log("error code : kAudioConverterErr_UnspecifiedError");
sletz's avatar
sletz committed
74
75
            break;
        case kAudioConverterErr_BadPropertySizeError:
sletz's avatar
sletz committed
76
            jack_log("error code : kAudioConverterErr_BadPropertySizeError");
sletz's avatar
sletz committed
77
78
            break;
        case kAudioConverterErr_RequiresPacketDescriptionsError:
sletz's avatar
sletz committed
79
            jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
sletz's avatar
sletz committed
80
81
            break;
        case kAudioConverterErr_InputSampleRateOutOfRange:
sletz's avatar
sletz committed
82
            jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
sletz's avatar
sletz committed
83
84
            break;
        case kAudioConverterErr_OutputSampleRateOutOfRange:
sletz's avatar
sletz committed
85
            jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
sletz's avatar
sletz committed
86
87
            break;
        case kAudioHardwareNotRunningError:
sletz's avatar
sletz committed
88
            jack_log("error code : kAudioHardwareNotRunningError");
sletz's avatar
sletz committed
89
90
            break;
        case kAudioHardwareUnknownPropertyError:
sletz's avatar
sletz committed
91
            jack_log("error code : kAudioHardwareUnknownPropertyError");
sletz's avatar
sletz committed
92
93
            break;
        case kAudioHardwareIllegalOperationError:
sletz's avatar
sletz committed
94
            jack_log("error code : kAudioHardwareIllegalOperationError");
sletz's avatar
sletz committed
95
96
            break;
        case kAudioHardwareBadDeviceError:
sletz's avatar
sletz committed
97
            jack_log("error code : kAudioHardwareBadDeviceError");
sletz's avatar
sletz committed
98
99
            break;
        case kAudioHardwareBadStreamError:
sletz's avatar
sletz committed
100
            jack_log("error code : kAudioHardwareBadStreamError");
sletz's avatar
sletz committed
101
102
            break;
        case kAudioDeviceUnsupportedFormatError:
sletz's avatar
sletz committed
103
            jack_log("error code : kAudioDeviceUnsupportedFormatError");
sletz's avatar
sletz committed
104
105
            break;
        case kAudioDevicePermissionsError:
sletz's avatar
sletz committed
106
            jack_log("error code : kAudioDevicePermissionsError");
107
            break;
sletz's avatar
sletz committed
108
        case kAudioHardwareBadObjectError:
sletz's avatar
sletz committed
109
            jack_log("error code : kAudioHardwareBadObjectError");
110
            break;
sletz's avatar
sletz committed
111
        case kAudioHardwareUnsupportedOperationError:
sletz's avatar
sletz committed
112
            jack_log("error code : kAudioHardwareUnsupportedOperationError");
sletz's avatar
sletz committed
113
114
            break;
        default:
sletz's avatar
sletz committed
115
            jack_log("error code : unknown");
sletz's avatar
sletz committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
            break;
    }
}

static OSStatus DisplayDeviceNames()
{
    UInt32 size;
    Boolean isWritable;
    int i, deviceNum;
    OSStatus err;
    CFStringRef UIname;

    err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
    if (err != noErr)
        return err;

    deviceNum = size / sizeof(AudioDeviceID);
    AudioDeviceID devices[deviceNum];

    err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
    if (err != noErr)
        return err;

    for (i = 0; i < deviceNum; i++) {
        char device_name[256];
        char internal_name[256];

        size = sizeof(CFStringRef);
        UIname = NULL;
        err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
        if (err == noErr) {
            CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
        } else {
            goto error;
        }

        size = 256;
        err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
        if (err != noErr)
            return err;

sletz's avatar
sletz committed
157
        jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name, internal_name);
sletz's avatar
sletz committed
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    }

    return noErr;

error:
    if (UIname != NULL)
        CFRelease(UIname);
    return err;
}

OSStatus JackCoreAudioDriver::Render(void *inRefCon,
                                     AudioUnitRenderActionFlags *ioActionFlags,
                                     const AudioTimeStamp *inTimeStamp,
                                     UInt32 inBusNumber,
                                     UInt32 inNumberFrames,
                                     AudioBufferList *ioData)
{
sletz's avatar
sletz committed
175
176
177
178
    JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inRefCon;
    driver->fActionFags = ioActionFlags;
    driver->fCurrentTime = (AudioTimeStamp *)inTimeStamp;
    driver->fDriverOutputData = ioData;
179
    driver->CycleTakeTime();
sletz's avatar
sletz committed
180
181
182
183
184
    return driver->Process();
}

int JackCoreAudioDriver::Read()
{
sletz's avatar
sletz committed
185
    AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData);
sletz's avatar
sletz committed
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
    return 0;
}

int JackCoreAudioDriver::Write()
{
    for (int i = 0; i < fPlaybackChannels; i++) {
        if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
            float* buffer = GetOutputBuffer(i);
            int size = sizeof(float) * fEngineControl->fBufferSize;
            memcpy((float*)fDriverOutputData->mBuffers[i].mData, buffer, size);
            // Monitor ports
            if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0)
                memcpy(GetMonitorBuffer(i), buffer, size);
        } else {
            memset((float*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(float) * fEngineControl->fBufferSize);
        }
    }
    return 0;
}

// Will run only once
OSStatus JackCoreAudioDriver::MeasureCallback(AudioDeviceID inDevice,
        const AudioTimeStamp* inNow,
        const AudioBufferList* inInputData,
        const AudioTimeStamp* inInputTime,
        AudioBufferList* outOutputData,
        const AudioTimeStamp* inOutputTime,
        void* inClientData)
{
    JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
    AudioDeviceStop(driver->fDeviceID, MeasureCallback);
    AudioDeviceRemoveIOProc(driver->fDeviceID, MeasureCallback);
sletz's avatar
sletz committed
218
    jack_log("JackCoreAudioDriver::MeasureCallback called");
sletz's avatar
sletz committed
219
    JackMachThread::GetParams(&driver->fEngineControl->fPeriod, &driver->fEngineControl->fComputation, &driver->fEngineControl->fConstraint);
sletz's avatar
sletz committed
220
221
    // Setup threadded based log function
    set_threaded_log_function();
sletz's avatar
sletz committed
222
223
224
    return noErr;
}

225
226
227
228
229
230
OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice,
        UInt32 inChannel,
        Boolean	isInput,
        AudioDevicePropertyID inPropertyID,
        void* inClientData)
{
sletz's avatar
sletz committed
231
232
233
234
235
    JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;

    switch (inPropertyID) {

        case kAudioDevicePropertyNominalSampleRate: {
sletz's avatar
sletz committed
236
            jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate ");
sletz's avatar
sletz committed
237
238
239
240
241
242
            driver->fState = true;
            break;
        }
    }

    return noErr;
243
244
}

245
246
// A better implementation would try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)

sletz's avatar
sletz committed
247
248
249
250
251
252
253
OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice,
        UInt32 inChannel,
        Boolean	isInput,
        AudioDevicePropertyID inPropertyID,
        void* inClientData)
{
    JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
sletz's avatar
sletz committed
254
         
sletz's avatar
sletz committed
255
256
257
    switch (inPropertyID) {

        case kAudioDeviceProcessorOverload:
sletz's avatar
sletz committed
258
            jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload");
259
260
            jack_time_t cur_time = GetMicroSeconds();
            driver->NotifyXRun(cur_time, float(cur_time - driver->fLastWaitUst));   // Better this value than nothing... 
sletz's avatar
sletz committed
261
262
263
264
265
266
267
268
269
270
271
            break;

        case kAudioDevicePropertyStreamConfiguration:
        case kAudioDevicePropertyNominalSampleRate: {

            UInt32 outSize = sizeof(Float64);
            Float64 sampleRate;
            int in_nChannels = 0;
            int out_nChannels = 0;
            char capture_driver_name[256];
            char playback_driver_name[256];
sletz's avatar
sletz committed
272
            CFStringRef ref;
sletz's avatar
sletz committed
273
274
275
276
277
278
279
280
281
282
283

            // Stop and restart
            driver->Stop();
            driver->RemoveListeners();
            driver->CloseAUHAL();

            OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
            if (err != noErr) {
                jack_error("Cannot get current sample rate");
                printError(err);
            }
sletz's avatar
sletz committed
284
            jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyNominalSampleRate %ld", long(sampleRate));
sletz's avatar
sletz committed
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312

            if (driver->SetupDevices(driver->fCaptureUID, driver->fPlaybackUID, capture_driver_name, playback_driver_name) < 0)
                return -1;

            if (driver->SetupChannels(driver->fCapturing, driver->fPlaying, driver->fInChannels, driver->fOutChannels, in_nChannels, out_nChannels, false) < 0)
                return -1;

            if (driver->SetupBufferSizeAndSampleRate(driver->fEngineControl->fBufferSize, sampleRate)  < 0)
                return -1;

            if (driver->OpenAUHAL(driver->fCapturing,
                                  driver->fPlaying,
                                  driver->fInChannels,
                                  driver->fOutChannels,
                                  in_nChannels,
                                  out_nChannels,
                                  driver->fEngineControl->fBufferSize,
                                  sampleRate,
                                  false) < 0)
                goto error;

            if (driver->AddListeners() < 0)
                goto error;

            driver->Start();

            // Send notification to be used in JackPilot or JackRouter plugin
            jack_error("Device restart...");
sletz's avatar
sletz committed
313
            ref = CFStringCreateWithCString(NULL, driver->fEngineControl->fServerName, kCFStringEncodingMacRoman);
sletz's avatar
sletz committed
314
315
316
317
318
319
320
321
322
323
324
325
            CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
                    CFSTR("com.grame.jackserver.restart"),
                    ref,
                    NULL,
                    kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
            CFRelease(ref);
            return noErr;
error:
            driver->CloseAUHAL();
            break;
        }
    }
sletz's avatar
sletz committed
326
327
328
329
330
331
332
333
334
335
336
337
338
339
    return noErr;
}

OSStatus JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id)
{
    UInt32 size = sizeof(AudioValueTranslation);
    CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
    AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };

    if (inIUD == NULL) {
        return kAudioHardwareUnspecifiedError;
    } else {
        OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
        CFRelease(inIUD);
sletz's avatar
sletz committed
340
        jack_log("get_device_id_from_uid %s %ld ", UID, *id);
sletz's avatar
sletz committed
341
342
343
344
345
346
347
348
349
350
351
        return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
    }
}

OSStatus JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID* id)
{
    OSStatus res;
    UInt32 theSize = sizeof(UInt32);
    AudioDeviceID inDefault;
    AudioDeviceID outDefault;

sletz's avatar
Cleanup    
sletz committed
352
    if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
sletz's avatar
sletz committed
353
354
        return res;

sletz's avatar
Cleanup    
sletz committed
355
    if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
sletz's avatar
sletz committed
356
357
        return res;

sletz's avatar
sletz committed
358
    jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);
sletz's avatar
sletz committed
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

    // Get the device only if default input and ouput are the same
    if (inDefault == outDefault) {
        *id = inDefault;
        return noErr;
    } else {
        jack_error("Default input and output devices are not the same !!");
        return kAudioHardwareBadDeviceError;
    }
}

OSStatus JackCoreAudioDriver::GetDefaultInputDevice(AudioDeviceID* id)
{
    OSStatus res;
    UInt32 theSize = sizeof(UInt32);
    AudioDeviceID inDefault;

sletz's avatar
Cleanup    
sletz committed
376
    if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
sletz's avatar
sletz committed
377
378
        return res;

sletz's avatar
sletz committed
379
    jack_log("GetDefaultInputDevice: input = %ld ", inDefault);
sletz's avatar
sletz committed
380
381
382
383
384
385
386
387
388
389
    *id = inDefault;
    return noErr;
}

OSStatus JackCoreAudioDriver::GetDefaultOutputDevice(AudioDeviceID* id)
{
    OSStatus res;
    UInt32 theSize = sizeof(UInt32);
    AudioDeviceID outDefault;

sletz's avatar
Cleanup    
sletz committed
390
    if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
sletz's avatar
sletz committed
391
392
        return res;

sletz's avatar
sletz committed
393
    jack_log("GetDefaultOutputDevice: output = %ld", outDefault);
sletz's avatar
sletz committed
394
395
396
397
398
399
400
401
402
403
    *id = outDefault;
    return noErr;
}

OSStatus JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id, char* name)
{
    UInt32 size = 256;
    return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
}

404
OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput)
sletz's avatar
sletz committed
405
{
406
    OSStatus err = noErr;
sletz's avatar
sletz committed
407
408
    UInt32	outSize;
    Boolean	outWritable;
409
    AudioBufferList* bufferList = 0;
sletz's avatar
sletz committed
410

sletz's avatar
sletz committed
411
412
413
414
415
416
    *channelCount = 0;
    err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
    if (err == noErr) {
        bufferList = (AudioBufferList*)malloc(outSize);
        err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
        if (err == noErr) {
417
            for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++)
sletz's avatar
sletz committed
418
419
                *channelCount += bufferList->mBuffers[i].mNumberChannels;
        }
sletz's avatar
sletz committed
420
421
422

        if (bufferList)
            free(bufferList);
sletz's avatar
sletz committed
423
424
425
426
427
    }

    return err;
}

428
JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, JackEngineInterface* engine, JackSynchro* table)
429
        : JackAudioDriver(name, alias, engine, table), fJackInputData(NULL), fDriverOutputData(NULL), fState(false), fIOUsage(1.f)
sletz's avatar
Cleanup    
sletz committed
430
{}
sletz's avatar
sletz committed
431
432

JackCoreAudioDriver::~JackCoreAudioDriver()
sletz's avatar
Cleanup    
sletz committed
433
{}
434

435
int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char* playback_driver_uid, char* capture_driver_name, char* playback_driver_name)
sletz's avatar
sletz committed
436
{
sletz's avatar
sletz committed
437
    capture_driver_name[0] = 0;
sletz's avatar
sletz committed
438
    playback_driver_name[0] = 0;
sletz's avatar
sletz committed
439
440

    // Duplex
441
    if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
sletz's avatar
sletz committed
442
        jack_log("JackCoreAudioDriver::Open duplex ");
sletz's avatar
sletz committed
443
444
445
446
447
448
449
450
451
452
453
        if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
            if (GetDefaultDevice(&fDeviceID) != noErr) {
                jack_error("Cannot open default device");
                return -1;
            }
        }
        if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
            jack_error("Cannot get device name from device ID");
            return -1;
        }

sletz's avatar
sletz committed
454
        // Capture only
455
    } else if (strcmp(capture_driver_uid, "") != 0) {
sletz's avatar
sletz committed
456
        jack_log("JackCoreAudioDriver::Open capture only ");
sletz's avatar
sletz committed
457
458
459
460
461
462
463
464
465
466
467
        if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
            if (GetDefaultInputDevice(&fDeviceID) != noErr) {
                jack_error("Cannot open default device");
                return -1;
            }
        }
        if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr) {
            jack_error("Cannot get device name from device ID");
            return -1;
        }

sletz's avatar
sletz committed
468
        // Playback only
469
    } else if (strcmp(playback_driver_uid, "") != 0) {
sletz's avatar
sletz committed
470
        jack_log("JackCoreAudioDriver::Open playback only ");
sletz's avatar
sletz committed
471
472
473
474
475
476
477
478
479
480
481
        if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
            if (GetDefaultOutputDevice(&fDeviceID) != noErr) {
                jack_error("Cannot open default device");
                return -1;
            }
        }
        if (GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
            jack_error("Cannot get device name from device ID");
            return -1;
        }

sletz's avatar
sletz committed
482
        // Use default driver in duplex mode
sletz's avatar
sletz committed
483
    } else {
sletz's avatar
sletz committed
484
        jack_log("JackCoreAudioDriver::Open default driver ");
sletz's avatar
sletz committed
485
486
487
488
489
490
491
492
493
        if (GetDefaultDevice(&fDeviceID) != noErr) {
            jack_error("Cannot open default device");
            return -1;
        }
        if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
            jack_error("Cannot get device name from device ID");
            return -1;
        }
    }
sletz's avatar
sletz committed
494
495

    return 0;
496
}
sletz's avatar
sletz committed
497

sletz's avatar
Cleanup    
sletz committed
498
int JackCoreAudioDriver::SetupChannels(bool capturing, bool playing, int& inchannels, int& outchannels, int& in_nChannels, int& out_nChannels, bool strict)
499
{
sletz's avatar
sletz committed
500
501
502
    OSStatus err = noErr;

    if (capturing) {
sletz's avatar
sletz committed
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
        err = GetTotalChannels(fDeviceID, &in_nChannels, true);
        if (err != noErr) {
            jack_error("Cannot get input channel number");
            printError(err);
            return -1;
        }
    }

    if (playing) {
        err = GetTotalChannels(fDeviceID, &out_nChannels, false);
        if (err != noErr) {
            jack_error("Cannot get output channel number");
            printError(err);
            return -1;
        }
    }

    if (inchannels > in_nChannels) {
        jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels);
sletz's avatar
sletz committed
522
523
524
        if (strict)
            return -1;
    }
sletz's avatar
sletz committed
525
526
527

    if (outchannels > out_nChannels) {
        jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels);
528
        if (strict)
sletz's avatar
sletz committed
529
            return -1;
sletz's avatar
sletz committed
530
531
532
    }

    if (inchannels == 0) {
sletz's avatar
sletz committed
533
        jack_log("Setup max in channels = %ld", in_nChannels);
sletz's avatar
sletz committed
534
535
536
537
        inchannels = in_nChannels;
    }

    if (outchannels == 0) {
sletz's avatar
sletz committed
538
        jack_log("Setup max out channels = %ld", out_nChannels);
sletz's avatar
sletz committed
539
540
        outchannels = out_nChannels;
    }
sletz's avatar
sletz committed
541
542

    return 0;
543
}
sletz's avatar
sletz committed
544

545
546
int JackCoreAudioDriver::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate)
{
sletz's avatar
sletz committed
547
    OSStatus err = noErr;
548
    UInt32 outSize;
sletz's avatar
sletz committed
549
550
551
    Float64 sampleRate;

    // Setting buffer size
sletz's avatar
sletz committed
552
    outSize = sizeof(UInt32);
sletz's avatar
sletz committed
553
    err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &nframes);
sletz's avatar
sletz committed
554
555
556
557
558
559
    if (err != noErr) {
        jack_error("Cannot set buffer size %ld", nframes);
        printError(err);
        return -1;
    }

560
    // Get sample rate
sletz's avatar
sletz committed
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
    outSize =  sizeof(Float64);
    err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
    if (err != noErr) {
        jack_error("Cannot get current sample rate");
        printError(err);
        return -1;
    }

    // If needed, set new sample rate
    if (samplerate != (jack_nframes_t)sampleRate) {
        sampleRate = (Float64)samplerate;

        // To get SR change notification
        err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
        if (err != noErr) {
            jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
            printError(err);
            return -1;
        }
        err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
        if (err != noErr) {
            jack_error("Cannot set sample rate = %ld", samplerate);
            printError(err);
            return -1;
        }

        // Waiting for SR change notification
        int count = 0;
        while (!fState && count++ < 100) {
            usleep(100000);
sletz's avatar
sletz committed
591
            jack_log("Wait count = %ld", count);
sletz's avatar
sletz committed
592
593
594
595
596
597
598
        }

        // Remove SR change notification
        AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
    }

    return 0;
599
}
600

sletz's avatar
sletz committed
601
602
603
604
605
606
607
608
609
int JackCoreAudioDriver::OpenAUHAL(bool capturing,
                                   bool playing,
                                   int inchannels,
                                   int outchannels,
                                   int in_nChannels,
                                   int out_nChannels,
                                   jack_nframes_t nframes,
                                   jack_nframes_t samplerate,
                                   bool strict)
610
{
sletz's avatar
sletz committed
611
    ComponentResult err1;
612
613
    UInt32 enableIO;
    AudioStreamBasicDescription srcFormat, dstFormat;
sletz's avatar
sletz committed
614

sletz's avatar
sletz committed
615
    jack_log("OpenAUHAL capturing = %ld playing = %ld playing = %ld outchannels = %ld in_nChannels = %ld out_nChannels = %ld ", capturing, playing, inchannels, inchannels, in_nChannels, out_nChannels);
sletz's avatar
sletz committed
616
617

    // AUHAL
sletz's avatar
sletz committed
618
619
620
621
622
623
624
    ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
    Component HALOutput = FindNextComponent(NULL, &cd);

    err1 = OpenAComponent(HALOutput, &fAUHAL);
    if (err1 != noErr) {
        jack_error("Error calling OpenAComponent");
        printError(err1);
625
        return -1;
sletz's avatar
sletz committed
626
627
628
629
630
631
    }

    err1 = AudioUnitInitialize(fAUHAL);
    if (err1 != noErr) {
        jack_error("Cannot initialize AUHAL unit");
        printError(err1);
632
        return -1;
sletz's avatar
sletz committed
633
634
635
636
637
    }

    // Start I/O
    enableIO = 1;
    if (capturing && inchannels > 0) {
sletz's avatar
sletz committed
638
        jack_log("Setup AUHAL input");
sletz's avatar
sletz committed
639
640
641
642
        err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
            printError(err1);
643
            if (strict)
sletz's avatar
sletz committed
644
                return -1;
sletz's avatar
sletz committed
645
646
647
648
        }
    }

    if (playing && outchannels > 0) {
sletz's avatar
sletz committed
649
        jack_log("Setup AUHAL output");
sletz's avatar
sletz committed
650
651
652
653
        err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
            printError(err1);
654
            if (strict)
sletz's avatar
sletz committed
655
                return -1;
sletz's avatar
sletz committed
656
657
658
659
660
661
662
663
        }
    }

    // Setup up choosen device, in both input and output cases
    err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
    if (err1 != noErr) {
        jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
        printError(err1);
664
        if (strict)
sletz's avatar
sletz committed
665
            return -1;
sletz's avatar
sletz committed
666
667
668
669
    }

    // Set buffer size
    if (capturing && inchannels > 0) {
sletz's avatar
sletz committed
670
        err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*) & nframes, sizeof(UInt32));
sletz's avatar
sletz committed
671
672
673
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
            printError(err1);
674
            if (strict)
sletz's avatar
sletz committed
675
                return -1;
sletz's avatar
sletz committed
676
677
678
679
        }
    }

    if (playing && outchannels > 0) {
sletz's avatar
sletz committed
680
        err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*) & nframes, sizeof(UInt32));
sletz's avatar
sletz committed
681
682
683
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
            printError(err1);
sletz's avatar
sletz committed
684
685
            if (strict)
                return -1;
sletz's avatar
sletz committed
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
        }
    }

    // Setup channel map
    if (capturing && inchannels > 0 && inchannels < in_nChannels) {
        SInt32 chanArr[in_nChannels];
        for (int i = 0; i < in_nChannels; i++) {
            chanArr[i] = -1;
        }
        for (int i = 0; i < inchannels; i++) {
            chanArr[i] = i;
        }
        AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
            printError(err1);
        }
    }

    if (playing && outchannels > 0 && outchannels < out_nChannels) {
        SInt32 chanArr[out_nChannels];
        for (int i = 0;	i < out_nChannels; i++) {
            chanArr[i] = -1;
        }
        for (int i = 0; i < outchannels; i++) {
            chanArr[i] = i;
        }
        err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
            printError(err1);
        }
    }

    // Setup stream converters
sletz's avatar
sletz committed
721
    jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
sletz's avatar
sletz committed
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
    srcFormat.mSampleRate = samplerate;
    srcFormat.mFormatID = kAudioFormatLinearPCM;
    srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
    srcFormat.mBytesPerPacket = sizeof(float);
    srcFormat.mFramesPerPacket = 1;
    srcFormat.mBytesPerFrame = sizeof(float);
    srcFormat.mChannelsPerFrame = outchannels;
    srcFormat.mBitsPerChannel = 32;

    err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription));
    if (err1 != noErr) {
        jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
        printError(err1);
    }

sletz's avatar
sletz committed
737
    jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
sletz's avatar
sletz committed
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
    dstFormat.mSampleRate = samplerate;
    dstFormat.mFormatID = kAudioFormatLinearPCM;
    dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
    dstFormat.mBytesPerPacket = sizeof(float);
    dstFormat.mFramesPerPacket = 1;
    dstFormat.mBytesPerFrame = sizeof(float);
    dstFormat.mChannelsPerFrame = inchannels;
    dstFormat.mBitsPerChannel = 32;

    err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription));
    if (err1 != noErr) {
        jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
        printError(err1);
    }

sletz's avatar
sletz committed
753
754
755
756
757
758
759
760
761
    // Setup callbacks
    if (inchannels > 0 && outchannels == 0) {
        AURenderCallbackStruct output;
        output.inputProc = Render;
        output.inputProcRefCon = this;
        err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
        if (err1 != noErr) {
            jack_error("Error calling  AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
            printError(err1);
762
            return -1;
sletz's avatar
sletz committed
763
764
765
766
767
768
769
770
771
        }
    } else {
        AURenderCallbackStruct output;
        output.inputProc = Render;
        output.inputProcRefCon = this;
        err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
            printError(err1);
772
            return -1;
sletz's avatar
sletz committed
773
774
775
        }
    }

sletz's avatar
sletz committed
776
    return 0;
777
778
779
780
}

int JackCoreAudioDriver::SetupBuffers(int inchannels, int outchannels)
{
sletz's avatar
sletz committed
781
782
783
784
785
786
787
788
789
790
791
792
    // Prepare buffers
    fJackInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
    if (fJackInputData == 0) {
        jack_error("Cannot allocate memory for input buffers");
        return -1;
    }
    fJackInputData->mNumberBuffers = inchannels;
    for (int i = 0; i < fCaptureChannels; i++) {
        fJackInputData->mBuffers[i].mNumberChannels = 1;
        fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float);
    }
    return 0;
793
794
795
796
}

void JackCoreAudioDriver::DisposeBuffers()
{
sletz's avatar
sletz committed
797
798
799
800
    if (fJackInputData) {
        free(fJackInputData);
        fJackInputData = 0;
    }
801
802
803
804
805
806
807
}

void JackCoreAudioDriver::CloseAUHAL()
{
    AudioUnitUninitialize(fAUHAL);
    CloseComponent(fAUHAL);
}
sletz's avatar
sletz committed
808

809
810
int JackCoreAudioDriver::AddListeners()
{
sletz's avatar
sletz committed
811
812
813
    OSStatus err = noErr;

    // Add listeners
sletz's avatar
sletz committed
814
815
816
    err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
817
818
        printError(err);
        return -1;
sletz's avatar
sletz committed
819
820
821
822
823
    }

    err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this);
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices");
824
825
        printError(err);
        return -1;
sletz's avatar
sletz committed
826
    }
sletz's avatar
sletz committed
827
828

    err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this);
829
830
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
831
832
        printError(err);
        return -1;
833
    }
sletz's avatar
sletz committed
834
835

    err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this);
836
837
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
838
839
        printError(err);
        return -1;
840
    }
sletz's avatar
sletz committed
841
842

    err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
843
844
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
845
846
        printError(err);
        return -1;
847
848
    }

sletz's avatar
sletz committed
849
    err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
850
851
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
852
853
        printError(err);
        return -1;
854
855
    }

856
    if (!fEngineControl->fSyncMode && fIOUsage != 1.f) {
sletz's avatar
sletz committed
857
        UInt32 outSize = sizeof(float);
858
        err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyIOCycleUsage, outSize, &fIOUsage);
sletz's avatar
sletz committed
859
860
861
862
863
        if (err != noErr) {
            jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage");
            printError(err);
        }
    }
sletz's avatar
Cleanup    
sletz committed
864

sletz's avatar
sletz committed
865
    return 0;
866
}
sletz's avatar
sletz committed
867

868
869
void JackCoreAudioDriver::RemoveListeners()
{
sletz's avatar
sletz committed
870
    AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback);
871
    AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback);
sletz's avatar
sletz committed
872
873
874
875
876
    AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback);
    AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback);
    AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback);
    AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
    AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
877
878
879
880
881
882
883
884
885
886
887
888
}

int JackCoreAudioDriver::Open(jack_nframes_t nframes,
                              jack_nframes_t samplerate,
                              bool capturing,
                              bool playing,
                              int inchannels,
                              int outchannels,
                              bool monitor,
                              const char* capture_driver_uid,
                              const char* playback_driver_uid,
                              jack_nframes_t capture_latency,
889
890
                              jack_nframes_t playback_latency,
                              int async_output_latency)
891
{
sletz's avatar
sletz committed
892
    int in_nChannels = 0;
893
894
895
    int out_nChannels = 0;
    char capture_driver_name[256];
    char playback_driver_name[256];
sletz's avatar
sletz committed
896
897
898
899
900
901
902
903
904
905
906

    // Keep initial state
    fCapturing = capturing;
    fPlaying = playing;
    fInChannels = inchannels;
    fOutChannels = outchannels;
    fMonitor = monitor;
    strcpy(fCaptureUID, capture_driver_uid);
    strcpy(fPlaybackUID, playback_driver_uid);
    fCaptureLatency = capture_latency;
    fPlaybackLatency = playback_latency;
907
    fIOUsage = float(async_output_latency)/ 100.f;
sletz's avatar
sletz committed
908
909
910
911

    if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name) < 0)
        return -1;

912
    // Generic JackAudioDriver Open
sletz's avatar
sletz committed
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
    if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
        return -1;

    if (SetupChannels(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, true) < 0)
        return -1;

    if (SetupBufferSizeAndSampleRate(nframes, samplerate)  < 0)
        return -1;

    if (OpenAUHAL(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, nframes, samplerate, true) < 0)
        goto error;

    if (capturing && inchannels > 0)
        if (SetupBuffers(inchannels, outchannels) < 0)
            goto error;

    if (AddListeners() < 0)
        goto error;

sletz's avatar
sletz committed
932
933
934
    // Core driver may have changed the in/out values
    fCaptureChannels = inchannels;
    fPlaybackChannels = outchannels;
935
    return noErr;
sletz's avatar
sletz committed
936
937

error:
sletz's avatar
sletz committed
938
    Close();
sletz's avatar
sletz committed
939
940
941
942
943
    return -1;
}

int JackCoreAudioDriver::Close()
{
sletz's avatar
sletz committed
944
    jack_log("JackCoreAudioDriver::Close");
sletz's avatar
sletz committed
945
    Stop();
sletz's avatar
sletz committed
946
    JackAudioDriver::Close();
947
    RemoveListeners();
sletz's avatar
sletz committed
948
949
    DisposeBuffers();
    CloseAUHAL();
950
    return 0;
sletz's avatar
sletz committed
951
952
953
954
955
956
957
958
959
960
}

int JackCoreAudioDriver::Attach()
{
    OSStatus err;
    JackPort* port;
    jack_port_id_t port_index;
    UInt32 size;
    Boolean isWritable;
    char channel_name[64];
961
    char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
sletz's avatar
sletz committed
962
    char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
sletz's avatar
sletz committed
963
964
    unsigned long port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;

sletz's avatar
sletz committed
965
    jack_log("JackCoreAudioDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
sletz's avatar
sletz committed
966
967
968
969
970

    for (int i = 0; i < fCaptureChannels; i++) {

        err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable);
        if (err != noErr)
sletz's avatar
sletz committed
971
            jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error ");
sletz's avatar
sletz committed
972
973
974
        if (err == noErr && size > 0) {
            err = AudioDeviceGetProperty(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, channel_name);
            if (err != noErr)
sletz's avatar
sletz committed
975
                jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error ");
976
            snprintf(alias, sizeof(alias) - 1, "%s:%s:out_%s%u", fAliasName, fCaptureDriverName, channel_name, i + 1);
sletz's avatar
sletz committed
977
        } else {
978
            snprintf(alias, sizeof(alias) - 1, "%s:%s:out%u", fAliasName, fCaptureDriverName, i + 1);
sletz's avatar
sletz committed
979
        }
sletz's avatar
sletz committed
980

981
        snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl->fName, i + 1);
sletz's avatar
sletz committed
982

983
984
        if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) {
            jack_error("Cannot register port for %s", name);
sletz's avatar
sletz committed
985
986
            return -1;
        }
sletz's avatar
sletz committed
987
988
989
990
991
992

        size = sizeof(UInt32);
        UInt32 value1 = 0;
        UInt32 value2 = 0;
        err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1);
        if (err != noErr)
sletz's avatar
sletz committed
993
            jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error ");
sletz's avatar
sletz committed
994
995
        err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2);
        if (err != noErr)
sletz's avatar
sletz committed
996
            jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error ");
sletz's avatar
sletz committed
997

sletz's avatar
sletz committed
998
        port = fGraphManager->GetPort(port_index);
sletz's avatar
sletz committed
999
        port->SetAlias(alias);
1000
        port->SetLatency(fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency);
For faster browsing, not all history is shown. View entire blame