JackCoreAudioDriver.cpp 50.6 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
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

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.

*/

#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
35
36
37
38
39
40
41
42
43
44
    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
45
46
47
48
49
50
}

static void printError(OSStatus err)
{
    switch (err) {
        case kAudioHardwareNoError:
sletz's avatar
sletz committed
51
            jack_log("error code : kAudioHardwareNoError");
sletz's avatar
sletz committed
52
53
            break;
        case kAudioConverterErr_FormatNotSupported:
sletz's avatar
sletz committed
54
            jack_log("error code : kAudioConverterErr_FormatNotSupported");
sletz's avatar
sletz committed
55
56
            break;
        case kAudioConverterErr_OperationNotSupported:
sletz's avatar
sletz committed
57
            jack_log("error code : kAudioConverterErr_OperationNotSupported");
sletz's avatar
sletz committed
58
59
            break;
        case kAudioConverterErr_PropertyNotSupported:
sletz's avatar
sletz committed
60
            jack_log("error code : kAudioConverterErr_PropertyNotSupported");
sletz's avatar
sletz committed
61
62
            break;
        case kAudioConverterErr_InvalidInputSize:
sletz's avatar
sletz committed
63
            jack_log("error code : kAudioConverterErr_InvalidInputSize");
sletz's avatar
sletz committed
64
65
            break;
        case kAudioConverterErr_InvalidOutputSize:
sletz's avatar
sletz committed
66
            jack_log("error code : kAudioConverterErr_InvalidOutputSize");
sletz's avatar
sletz committed
67
68
            break;
        case kAudioConverterErr_UnspecifiedError:
sletz's avatar
sletz committed
69
            jack_log("error code : kAudioConverterErr_UnspecifiedError");
sletz's avatar
sletz committed
70
71
            break;
        case kAudioConverterErr_BadPropertySizeError:
sletz's avatar
sletz committed
72
            jack_log("error code : kAudioConverterErr_BadPropertySizeError");
sletz's avatar
sletz committed
73
74
            break;
        case kAudioConverterErr_RequiresPacketDescriptionsError:
sletz's avatar
sletz committed
75
            jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
sletz's avatar
sletz committed
76
77
            break;
        case kAudioConverterErr_InputSampleRateOutOfRange:
sletz's avatar
sletz committed
78
            jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
sletz's avatar
sletz committed
79
80
            break;
        case kAudioConverterErr_OutputSampleRateOutOfRange:
sletz's avatar
sletz committed
81
            jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
sletz's avatar
sletz committed
82
83
            break;
        case kAudioHardwareNotRunningError:
sletz's avatar
sletz committed
84
            jack_log("error code : kAudioHardwareNotRunningError");
sletz's avatar
sletz committed
85
86
            break;
        case kAudioHardwareUnknownPropertyError:
sletz's avatar
sletz committed
87
            jack_log("error code : kAudioHardwareUnknownPropertyError");
sletz's avatar
sletz committed
88
89
            break;
        case kAudioHardwareIllegalOperationError:
sletz's avatar
sletz committed
90
            jack_log("error code : kAudioHardwareIllegalOperationError");
sletz's avatar
sletz committed
91
92
            break;
        case kAudioHardwareBadDeviceError:
sletz's avatar
sletz committed
93
            jack_log("error code : kAudioHardwareBadDeviceError");
sletz's avatar
sletz committed
94
95
            break;
        case kAudioHardwareBadStreamError:
sletz's avatar
sletz committed
96
            jack_log("error code : kAudioHardwareBadStreamError");
sletz's avatar
sletz committed
97
98
            break;
        case kAudioDeviceUnsupportedFormatError:
sletz's avatar
sletz committed
99
            jack_log("error code : kAudioDeviceUnsupportedFormatError");
sletz's avatar
sletz committed
100
101
            break;
        case kAudioDevicePermissionsError:
sletz's avatar
sletz committed
102
            jack_log("error code : kAudioDevicePermissionsError");
103
            break;
sletz's avatar
sletz committed
104
        case kAudioHardwareBadObjectError:
sletz's avatar
sletz committed
105
            jack_log("error code : kAudioHardwareBadObjectError");
106
            break;
sletz's avatar
sletz committed
107
        case kAudioHardwareUnsupportedOperationError:
sletz's avatar
sletz committed
108
            jack_log("error code : kAudioHardwareUnsupportedOperationError");
sletz's avatar
sletz committed
109
110
            break;
        default:
sletz's avatar
sletz committed
111
            jack_log("error code : unknown");
sletz's avatar
sletz committed
112
113
114
115
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
            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
153
        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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
    }

    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
171
    JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inRefCon;
sletz's avatar
sletz committed
172
    driver->fLastWaitUst = GetMicroSeconds(); // Take callback date here
sletz's avatar
sletz committed
173
174
175
    driver->fActionFags = ioActionFlags;
    driver->fCurrentTime = (AudioTimeStamp *)inTimeStamp;
    driver->fDriverOutputData = ioData;
sletz's avatar
sletz committed
176
177
178
179
180
    return driver->Process();
}

int JackCoreAudioDriver::Read()
{
sletz's avatar
sletz committed
181
    AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData);
sletz's avatar
sletz committed
182
183
184
185
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
    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
214
    jack_log("JackCoreAudioDriver::MeasureCallback called");
sletz's avatar
sletz committed
215
216
217
218
    JackMachThread::GetParams(&driver->fEngineControl->fPeriod, &driver->fEngineControl->fComputation, &driver->fEngineControl->fConstraint);
    return noErr;
}

219
220
221
222
223
224
OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice,
        UInt32 inChannel,
        Boolean	isInput,
        AudioDevicePropertyID inPropertyID,
        void* inClientData)
{
sletz's avatar
sletz committed
225
226
227
228
229
    JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;

    switch (inPropertyID) {

        case kAudioDevicePropertyNominalSampleRate: {
sletz's avatar
sletz committed
230
            jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate ");
sletz's avatar
sletz committed
231
232
233
234
235
236
            driver->fState = true;
            break;
        }
    }

    return noErr;
237
238
}

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

sletz's avatar
sletz committed
241
242
243
244
245
246
247
OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice,
        UInt32 inChannel,
        Boolean	isInput,
        AudioDevicePropertyID inPropertyID,
        void* inClientData)
{
    JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData;
sletz's avatar
sletz committed
248
249
250
251

    switch (inPropertyID) {

        case kAudioDeviceProcessorOverload:
sletz's avatar
sletz committed
252
            jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload");
sletz's avatar
sletz committed
253
254
255
256
257
258
259
260
261
262
263
264
            driver->NotifyXRun(GetMicroSeconds());
            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
265
            CFStringRef ref;
sletz's avatar
sletz committed
266
267
268
269
270
271
272
273
274
275
276

            // 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
277
            jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyNominalSampleRate %ld", long(sampleRate));
sletz's avatar
sletz committed
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305

            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
306
            ref = CFStringCreateWithCString(NULL, driver->fEngineControl->fServerName, kCFStringEncodingMacRoman);
sletz's avatar
sletz committed
307
308
309
310
311
312
313
314
315
316
317
318
            CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
                    CFSTR("com.grame.jackserver.restart"),
                    ref,
                    NULL,
                    kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
            CFRelease(ref);
            return noErr;
error:
            driver->CloseAUHAL();
            break;
        }
    }
sletz's avatar
sletz committed
319
320
321
322
323
324
325
326
327
328
329
330
331
332
    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
333
        jack_log("get_device_id_from_uid %s %ld ", UID, *id);
sletz's avatar
sletz committed
334
335
336
337
338
339
340
341
342
343
344
        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
345
    if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
sletz's avatar
sletz committed
346
347
        return res;

sletz's avatar
Cleanup    
sletz committed
348
    if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
sletz's avatar
sletz committed
349
350
        return res;

sletz's avatar
sletz committed
351
    jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);
sletz's avatar
sletz committed
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

    // 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
369
    if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
sletz's avatar
sletz committed
370
371
        return res;

sletz's avatar
sletz committed
372
    jack_log("GetDefaultInputDevice: input = %ld ", inDefault);
sletz's avatar
sletz committed
373
374
375
376
377
378
379
380
381
382
    *id = inDefault;
    return noErr;
}

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

sletz's avatar
Cleanup    
sletz committed
383
    if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
sletz's avatar
sletz committed
384
385
        return res;

sletz's avatar
sletz committed
386
    jack_log("GetDefaultOutputDevice: output = %ld", outDefault);
sletz's avatar
sletz committed
387
388
389
390
391
392
393
394
395
396
    *id = outDefault;
    return noErr;
}

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

397
OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput)
sletz's avatar
sletz committed
398
{
399
    OSStatus err = noErr;
sletz's avatar
sletz committed
400
401
    UInt32	outSize;
    Boolean	outWritable;
402
    AudioBufferList* bufferList = 0;
sletz's avatar
sletz committed
403

sletz's avatar
sletz committed
404
405
406
407
408
409
    *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) {
410
            for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++)
sletz's avatar
sletz committed
411
412
                *channelCount += bufferList->mBuffers[i].mNumberChannels;
        }
sletz's avatar
sletz committed
413
414
415

        if (bufferList)
            free(bufferList);
sletz's avatar
sletz committed
416
417
418
419
420
421
    }

    return err;
}

JackCoreAudioDriver::JackCoreAudioDriver(const char* name, JackEngine* engine, JackSynchro** table)
422
        : JackAudioDriver(name, engine, table), fJackInputData(NULL), fDriverOutputData(NULL), fState(false), fIOUsage(1.f)
sletz's avatar
Cleanup    
sletz committed
423
{}
sletz's avatar
sletz committed
424
425

JackCoreAudioDriver::~JackCoreAudioDriver()
sletz's avatar
Cleanup    
sletz committed
426
{}
427

428
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
429
{
sletz's avatar
sletz committed
430
    capture_driver_name[0] = 0;
sletz's avatar
sletz committed
431
    playback_driver_name[0] = 0;
sletz's avatar
sletz committed
432
433

    // Duplex
434
    if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
sletz's avatar
sletz committed
435
        jack_log("JackCoreAudioDriver::Open duplex ");
sletz's avatar
sletz committed
436
437
438
439
440
441
442
443
444
445
446
        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
447
        // Capture only
448
    } else if (strcmp(capture_driver_uid, "") != 0) {
sletz's avatar
sletz committed
449
        jack_log("JackCoreAudioDriver::Open capture only ");
sletz's avatar
sletz committed
450
451
452
453
454
455
456
457
458
459
460
        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
461
        // Playback only
462
    } else if (strcmp(playback_driver_uid, "") != 0) {
sletz's avatar
sletz committed
463
        jack_log("JackCoreAudioDriver::Open playback only ");
sletz's avatar
sletz committed
464
465
466
467
468
469
470
471
472
473
474
        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
475
        // Use default driver in duplex mode
sletz's avatar
sletz committed
476
    } else {
sletz's avatar
sletz committed
477
        jack_log("JackCoreAudioDriver::Open default driver ");
sletz's avatar
sletz committed
478
479
480
481
482
483
484
485
486
        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
487
488

    return 0;
489
}
sletz's avatar
sletz committed
490

sletz's avatar
Cleanup    
sletz committed
491
int JackCoreAudioDriver::SetupChannels(bool capturing, bool playing, int& inchannels, int& outchannels, int& in_nChannels, int& out_nChannels, bool strict)
492
{
sletz's avatar
sletz committed
493
494
495
    OSStatus err = noErr;

    if (capturing) {
sletz's avatar
sletz committed
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
        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
515
516
517
        if (strict)
            return -1;
    }
sletz's avatar
sletz committed
518
519
520

    if (outchannels > out_nChannels) {
        jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels);
521
        if (strict)
sletz's avatar
sletz committed
522
            return -1;
sletz's avatar
sletz committed
523
524
525
    }

    if (inchannels == 0) {
sletz's avatar
sletz committed
526
        jack_log("Setup max in channels = %ld", in_nChannels);
sletz's avatar
sletz committed
527
528
529
530
        inchannels = in_nChannels;
    }

    if (outchannels == 0) {
sletz's avatar
sletz committed
531
        jack_log("Setup max out channels = %ld", out_nChannels);
sletz's avatar
sletz committed
532
533
        outchannels = out_nChannels;
    }
sletz's avatar
sletz committed
534
535

    return 0;
536
}
sletz's avatar
sletz committed
537

538
539
int JackCoreAudioDriver::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate)
{
sletz's avatar
sletz committed
540
    OSStatus err = noErr;
541
    UInt32 outSize;
sletz's avatar
sletz committed
542
543
544
    Float64 sampleRate;

    // Setting buffer size
sletz's avatar
sletz committed
545
    outSize = sizeof(UInt32);
sletz's avatar
sletz committed
546
    err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &nframes);
sletz's avatar
sletz committed
547
548
549
550
551
552
    if (err != noErr) {
        jack_error("Cannot set buffer size %ld", nframes);
        printError(err);
        return -1;
    }

553
    // Get sample rate
sletz's avatar
sletz committed
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
    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
584
            jack_log("Wait count = %ld", count);
sletz's avatar
sletz committed
585
586
587
588
589
590
591
        }

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

    return 0;
592
}
593

sletz's avatar
sletz committed
594
595
596
597
598
599
600
601
602
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)
603
{
sletz's avatar
sletz committed
604
    ComponentResult err1;
605
606
    UInt32 enableIO;
    AudioStreamBasicDescription srcFormat, dstFormat;
sletz's avatar
sletz committed
607

sletz's avatar
sletz committed
608
    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
609
610

    // AUHAL
sletz's avatar
sletz committed
611
612
613
614
615
616
617
    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);
618
        return -1;
sletz's avatar
sletz committed
619
620
621
622
623
624
    }

    err1 = AudioUnitInitialize(fAUHAL);
    if (err1 != noErr) {
        jack_error("Cannot initialize AUHAL unit");
        printError(err1);
625
        return -1;
sletz's avatar
sletz committed
626
627
628
629
630
    }

    // Start I/O
    enableIO = 1;
    if (capturing && inchannels > 0) {
sletz's avatar
sletz committed
631
        jack_log("Setup AUHAL input");
sletz's avatar
sletz committed
632
633
634
635
        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);
636
            if (strict)
sletz's avatar
sletz committed
637
                return -1;
sletz's avatar
sletz committed
638
639
640
641
        }
    }

    if (playing && outchannels > 0) {
sletz's avatar
sletz committed
642
        jack_log("Setup AUHAL output");
sletz's avatar
sletz committed
643
644
645
646
        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);
647
            if (strict)
sletz's avatar
sletz committed
648
                return -1;
sletz's avatar
sletz committed
649
650
651
652
653
654
655
656
        }
    }

    // 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);
657
        if (strict)
sletz's avatar
sletz committed
658
            return -1;
sletz's avatar
sletz committed
659
660
661
662
    }

    // Set buffer size
    if (capturing && inchannels > 0) {
sletz's avatar
sletz committed
663
        err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*) & nframes, sizeof(UInt32));
sletz's avatar
sletz committed
664
665
666
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
            printError(err1);
667
            if (strict)
sletz's avatar
sletz committed
668
                return -1;
sletz's avatar
sletz committed
669
670
671
672
        }
    }

    if (playing && outchannels > 0) {
sletz's avatar
sletz committed
673
        err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*) & nframes, sizeof(UInt32));
sletz's avatar
sletz committed
674
675
676
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
            printError(err1);
sletz's avatar
sletz committed
677
678
            if (strict)
                return -1;
sletz's avatar
sletz committed
679
680
681
682
683
684
685
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
        }
    }

    // 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
714
    jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
sletz's avatar
sletz committed
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
    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
730
    jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
sletz's avatar
sletz committed
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
    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
746
747
748
749
750
751
752
753
754
    // 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);
755
            return -1;
sletz's avatar
sletz committed
756
757
758
759
760
761
762
763
764
        }
    } 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);
765
            return -1;
sletz's avatar
sletz committed
766
767
768
        }
    }

sletz's avatar
sletz committed
769
    return 0;
770
771
772
773
}

int JackCoreAudioDriver::SetupBuffers(int inchannels, int outchannels)
{
sletz's avatar
sletz committed
774
775
776
777
778
779
780
781
782
783
784
785
    // 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;
786
787
788
789
}

void JackCoreAudioDriver::DisposeBuffers()
{
sletz's avatar
sletz committed
790
791
792
793
    if (fJackInputData) {
        free(fJackInputData);
        fJackInputData = 0;
    }
794
795
796
797
798
799
800
}

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

802
803
int JackCoreAudioDriver::AddListeners()
{
sletz's avatar
sletz committed
804
805
806
    OSStatus err = noErr;

    // Add listeners
sletz's avatar
sletz committed
807
808
809
    err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
810
811
        printError(err);
        return -1;
sletz's avatar
sletz committed
812
813
814
815
816
    }

    err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this);
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices");
817
818
        printError(err);
        return -1;
sletz's avatar
sletz committed
819
    }
sletz's avatar
sletz committed
820
821

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

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

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

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

849
    if (!fEngineControl->fSyncMode && fIOUsage != 1.f) {
sletz's avatar
sletz committed
850
        UInt32 outSize = sizeof(float);
851
        err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyIOCycleUsage, outSize, &fIOUsage);
sletz's avatar
sletz committed
852
853
854
855
856
        if (err != noErr) {
            jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage");
            printError(err);
        }
    }
sletz's avatar
Cleanup    
sletz committed
857

sletz's avatar
sletz committed
858
    return 0;
859
}
sletz's avatar
sletz committed
860

861
862
void JackCoreAudioDriver::RemoveListeners()
{
sletz's avatar
sletz committed
863
    AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback);
864
    AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback);
sletz's avatar
sletz committed
865
866
867
868
869
    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);
870
871
872
873
874
875
876
877
878
879
880
881
}

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,
882
883
                              jack_nframes_t playback_latency,
                              int async_output_latency)
884
{
sletz's avatar
sletz committed
885
    int in_nChannels = 0;
886
887
888
    int out_nChannels = 0;
    char capture_driver_name[256];
    char playback_driver_name[256];
sletz's avatar
sletz committed
889
890
891
892
893
894
895
896
897
898
899

    // 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;
900
    fIOUsage = float(async_output_latency)/ 100.f;
sletz's avatar
sletz committed
901
902
903
904

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

905
    // Generic JackAudioDriver Open
sletz's avatar
sletz committed
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
    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
925
926
927
    // Core driver may have changed the in/out values
    fCaptureChannels = inchannels;
    fPlaybackChannels = outchannels;
928
    return noErr;
sletz's avatar
sletz committed
929
930

error:
sletz's avatar
sletz committed
931
    Close();
sletz's avatar
sletz committed
932
933
934
935
936
    return -1;
}

int JackCoreAudioDriver::Close()
{
sletz's avatar
sletz committed
937
    jack_log("JackCoreAudioDriver::Close");
sletz's avatar
sletz committed
938
    Stop();
sletz's avatar
sletz committed
939
    JackAudioDriver::Close();
940
    RemoveListeners();
sletz's avatar
sletz committed
941
942
    DisposeBuffers();
    CloseAUHAL();
943
    return 0;
sletz's avatar
sletz committed
944
945
946
947
948
949
950
951
952
953
}

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

sletz's avatar
sletz committed
958
    jack_log("JackCoreAudioDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
sletz's avatar
sletz committed
959
960
961
962
963

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

        err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable);
        if (err != noErr)
sletz's avatar
sletz committed
964
            jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error ");
sletz's avatar
sletz committed
965
966
967
        if (err == noErr && size > 0) {
            err = AudioDeviceGetProperty(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, channel_name);
            if (err != noErr)
sletz's avatar
sletz committed
968
                jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error ");
969
            snprintf(alias, sizeof(alias) - 1, "%s:%s:out_%s%u", fClientControl->fName, fCaptureDriverName, channel_name, i + 1);
sletz's avatar
sletz committed
970
        } else {
971
            snprintf(alias, sizeof(alias) - 1, "%s:%s:out%u", fClientControl->fName, fCaptureDriverName, i + 1);
sletz's avatar
sletz committed
972
        }
sletz's avatar
sletz committed
973
974
975

        snprintf(name, sizeof(name) - 1, "system:capture_%d", i + 1);

976
977
        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
978
979
            return -1;
        }
sletz's avatar
sletz committed
980
981
982
983
984
985

        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
986
            jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error ");
sletz's avatar
sletz committed
987
988
        err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2);
        if (err != noErr)
sletz's avatar
sletz committed
989
            jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error ");
sletz's avatar
sletz committed
990

sletz's avatar
sletz committed
991
        port = fGraphManager->GetPort(port_index);
sletz's avatar
sletz committed
992
        port->SetAlias(alias);
993
        port->SetLatency(fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency);
sletz's avatar
sletz committed
994
995
996
997
998
999
1000
        fCapturePortList[i] = port_index;
    }

    port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;

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

For faster browsing, not all history is shown. View entire blame