2 Copyright (C) 2004-2008 Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "JackCoreAudioDriver.h"
21 #include "JackEngineControl.h"
22 #include "JackMachThread.h"
23 #include "JackGraphManager.h"
24 #include "JackError.h"
25 #include "JackClientControl.h"
26 #include "JackDriverLoader.h"
27 #include "JackGlobals.h"
28 #include "JackTools.h"
29 #include "JackLockedEngine.h"
30 #include "JackAC3Encoder.h"
34 #include <CoreServices/CoreServices.h>
35 #include <CoreFoundation/CFNumber.h>
40 static void Print4CharCode(const char* msg
, long c
)
42 UInt32 __4CC_number
= (c
);
44 *((SInt32
*)__4CC_string
) = EndianU32_NtoB(__4CC_number
);
46 jack_log("%s'%s'", (msg
), __4CC_string
);
49 static void PrintStreamDesc(AudioStreamBasicDescription
*inDesc
)
51 jack_log("- - - - - - - - - - - - - - - - - - - -");
52 jack_log(" Sample Rate:%f", inDesc
->mSampleRate
);
53 jack_log(" Format ID:%.*s", (int)sizeof(inDesc
->mFormatID
), (char*)&inDesc
->mFormatID
);
54 jack_log(" Format Flags:%lX", inDesc
->mFormatFlags
);
55 jack_log(" Bytes per Packet:%ld", inDesc
->mBytesPerPacket
);
56 jack_log(" Frames per Packet:%ld", inDesc
->mFramesPerPacket
);
57 jack_log(" Bytes per Frame:%ld", inDesc
->mBytesPerFrame
);
58 jack_log(" Channels per Frame:%ld", inDesc
->mChannelsPerFrame
);
59 jack_log(" Bits per Channel:%ld", inDesc
->mBitsPerChannel
);
60 jack_log("- - - - - - - - - - - - - - - - - - - -");
63 static void printError(OSStatus err
)
66 case kAudioHardwareNoError
:
67 jack_log("error code : kAudioHardwareNoError");
69 case kAudioConverterErr_FormatNotSupported
:
70 jack_log("error code : kAudioConverterErr_FormatNotSupported");
72 case kAudioConverterErr_OperationNotSupported
:
73 jack_log("error code : kAudioConverterErr_OperationNotSupported");
75 case kAudioConverterErr_PropertyNotSupported
:
76 jack_log("error code : kAudioConverterErr_PropertyNotSupported");
78 case kAudioConverterErr_InvalidInputSize
:
79 jack_log("error code : kAudioConverterErr_InvalidInputSize");
81 case kAudioConverterErr_InvalidOutputSize
:
82 jack_log("error code : kAudioConverterErr_InvalidOutputSize");
84 case kAudioConverterErr_UnspecifiedError
:
85 jack_log("error code : kAudioConverterErr_UnspecifiedError");
87 case kAudioConverterErr_BadPropertySizeError
:
88 jack_log("error code : kAudioConverterErr_BadPropertySizeError");
90 case kAudioConverterErr_RequiresPacketDescriptionsError
:
91 jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
93 case kAudioConverterErr_InputSampleRateOutOfRange
:
94 jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
96 case kAudioConverterErr_OutputSampleRateOutOfRange
:
97 jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
99 case kAudioHardwareNotRunningError
:
100 jack_log("error code : kAudioHardwareNotRunningError");
102 case kAudioHardwareUnknownPropertyError
:
103 jack_log("error code : kAudioHardwareUnknownPropertyError");
105 case kAudioHardwareIllegalOperationError
:
106 jack_log("error code : kAudioHardwareIllegalOperationError");
108 case kAudioHardwareBadDeviceError
:
109 jack_log("error code : kAudioHardwareBadDeviceError");
111 case kAudioHardwareBadStreamError
:
112 jack_log("error code : kAudioHardwareBadStreamError");
114 case kAudioDeviceUnsupportedFormatError
:
115 jack_log("error code : kAudioDeviceUnsupportedFormatError");
117 case kAudioDevicePermissionsError
:
118 jack_log("error code : kAudioDevicePermissionsError");
120 case kAudioHardwareBadObjectError
:
121 jack_log("error code : kAudioHardwareBadObjectError");
123 case kAudioHardwareUnsupportedOperationError
:
124 jack_log("error code : kAudioHardwareUnsupportedOperationError");
127 Print4CharCode("error code : unknown ", err
);
132 static bool CheckAvailableDeviceName(const char* device_name
, AudioDeviceID
* device_id
)
139 err
= AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices
, &size
, &isWritable
);
144 deviceNum
= size
/ sizeof(AudioDeviceID
);
145 AudioDeviceID devices
[deviceNum
];
147 err
= AudioHardwareGetProperty(kAudioHardwarePropertyDevices
, &size
, devices
);
152 for (i
= 0; i
< deviceNum
; i
++) {
153 char device_name_aux
[256];
156 err
= AudioDeviceGetProperty(devices
[i
], 0, false, kAudioDevicePropertyDeviceName
, &size
, device_name_aux
);
161 if (strcmp(device_name_aux
, device_name
) == 0) {
162 *device_id
= devices
[i
];
171 static bool CheckAvailableDevice(AudioDeviceID device_id
)
178 err
= AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices
, &size
, &isWritable
);
183 deviceNum
= size
/ sizeof(AudioDeviceID
);
184 AudioDeviceID devices
[deviceNum
];
186 err
= AudioHardwareGetProperty(kAudioHardwarePropertyDevices
, &size
, devices
);
191 for (i
= 0; i
< deviceNum
; i
++) {
192 if (device_id
== devices
[i
]) {
201 static OSStatus
DisplayDeviceNames()
209 err
= AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices
, &size
, &isWritable
);
214 deviceNum
= size
/ sizeof(AudioDeviceID
);
215 AudioDeviceID devices
[deviceNum
];
217 err
= AudioHardwareGetProperty(kAudioHardwarePropertyDevices
, &size
, devices
);
222 for (i
= 0; i
< deviceNum
; i
++) {
223 char device_name
[256];
224 char internal_name
[256];
226 size
= sizeof(CFStringRef
);
228 err
= AudioDeviceGetProperty(devices
[i
], 0, false, kAudioDevicePropertyDeviceUID
, &size
, &UIname
);
230 CFStringGetCString(UIname
, internal_name
, 256, CFStringGetSystemEncoding());
236 err
= AudioDeviceGetProperty(devices
[i
], 0, false, kAudioDevicePropertyDeviceName
, &size
, device_name
);
241 jack_info("Device ID = \'%d\' name = \'%s\', internal name = \'%s\' (to be used as -C, -P, or -d parameter)", devices
[i
], device_name
, internal_name
);
247 if (UIname
!= NULL
) {
253 static CFStringRef
GetDeviceName(AudioDeviceID id
)
255 UInt32 size
= sizeof(CFStringRef
);
257 OSStatus err
= AudioDeviceGetProperty(id
, 0, false, kAudioDevicePropertyDeviceUID
, &size
, &UIname
);
258 return (err
== noErr
) ? UIname
: NULL
;
261 static void ParseChannelList(const string
& list
, vector
<int>& result
)
263 stringstream
ss(list
);
267 while (ss
>> token
) {
271 result
.push_back(chan
);
275 OSStatus
JackCoreAudioDriver::Render(void* inRefCon
,
276 AudioUnitRenderActionFlags
* ioActionFlags
,
277 const AudioTimeStamp
* inTimeStamp
,
279 UInt32 inNumberFrames
,
280 AudioBufferList
* ioData
)
282 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inRefCon
;
283 driver
->fActionFags
= ioActionFlags
;
284 driver
->fCurrentTime
= inTimeStamp
;
285 driver
->fDriverOutputData
= ioData
;
287 // Setup threaded based log function et get RT thread parameters once...
288 if (set_threaded_log_function()) {
290 jack_log("JackCoreAudioDriver::Render : set_threaded_log_function");
291 JackMachThread::GetParams(pthread_self(), &driver
->fEngineControl
->fPeriod
, &driver
->fEngineControl
->fComputation
, &driver
->fEngineControl
->fConstraint
);
293 if (driver
->fComputationGrain
> 0) {
294 jack_log("JackCoreAudioDriver::Render : RT thread computation setup to %d percent of period", int(driver
->fComputationGrain
* 100));
295 driver
->fEngineControl
->fComputation
= driver
->fEngineControl
->fPeriod
* driver
->fComputationGrain
;
299 // Signal waiting start function...
300 driver
->fState
= true;
302 driver
->CycleTakeBeginTime();
304 if (driver
->Process() < 0) {
305 jack_error("Process error, stopping driver");
306 driver
->NotifyFailure(JackBackendError
, "Process error, stopping driver"); // Message length limited to JACK_MESSAGE_SIZE
308 kill(JackTools::GetPID(), SIGINT
);
309 return kAudioHardwareUnsupportedOperationError
;
315 int JackCoreAudioDriver::Read()
317 if (fCaptureChannels
> 0) { // Calling AudioUnitRender with no input returns a '????' error (callback setting issue ??), so hack to avoid it here...
318 return (AudioUnitRender(fAUHAL
, fActionFags
, fCurrentTime
, 1, fEngineControl
->fBufferSize
, fJackInputData
) == noErr
) ? 0 : -1;
324 int JackCoreAudioDriver::Write()
328 // AC3 encoding and SPDIF write
329 jack_default_audio_sample_t
* AC3_inputs
[MAX_AC3_CHANNELS
];
330 jack_default_audio_sample_t
* AC3_outputs
[2];
331 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
332 AC3_inputs
[i
] = GetOutputBuffer(i
);
333 // If not connected, clear the buffer
334 if (fGraphManager
->GetConnectionsNum(fPlaybackPortList
[i
]) == 0) {
335 memset(AC3_inputs
[i
], 0, sizeof(jack_default_audio_sample_t
) * fEngineControl
->fBufferSize
);
338 AC3_outputs
[0] = (jack_default_audio_sample_t
*)fDriverOutputData
->mBuffers
[0].mData
;
339 AC3_outputs
[1] = (jack_default_audio_sample_t
*)fDriverOutputData
->mBuffers
[1].mData
;
340 fAC3Encoder
->Process(AC3_inputs
, AC3_outputs
, fEngineControl
->fBufferSize
);
345 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
346 if (fGraphManager
->GetConnectionsNum(fPlaybackPortList
[i
]) > 0) {
347 jack_default_audio_sample_t
* buffer
= GetOutputBuffer(i
);
348 int size
= sizeof(jack_default_audio_sample_t
) * fEngineControl
->fBufferSize
;
349 memcpy((jack_default_audio_sample_t
*)fDriverOutputData
->mBuffers
[i
].mData
, buffer
, size
);
351 if (fWithMonitorPorts
&& fGraphManager
->GetConnectionsNum(fMonitorPortList
[i
]) > 0) {
352 memcpy(GetMonitorBuffer(i
), buffer
, size
);
355 memset((jack_default_audio_sample_t
*)fDriverOutputData
->mBuffers
[i
].mData
, 0, sizeof(jack_default_audio_sample_t
) * fEngineControl
->fBufferSize
);
362 OSStatus
JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice
,
365 AudioDevicePropertyID inPropertyID
,
368 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inClientData
;
370 switch (inPropertyID
) {
372 case kAudioDevicePropertyNominalSampleRate
: {
373 jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
374 // Check new sample rate
375 Float64 tmp_sample_rate
;
376 UInt32 outSize
= sizeof(Float64
);
377 OSStatus err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outSize
, &tmp_sample_rate
);
379 jack_error("Cannot get current sample rate");
382 jack_log("JackCoreAudioDriver::SRNotificationCallback : checked sample rate = %f", tmp_sample_rate
);
384 driver
->fState
= true;
392 OSStatus
JackCoreAudioDriver::BSNotificationCallback(AudioDeviceID inDevice
,
395 AudioDevicePropertyID inPropertyID
,
398 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inClientData
;
400 switch (inPropertyID
) {
402 case kAudioDevicePropertyBufferFrameSize
: {
403 jack_log("JackCoreAudioDriver::BSNotificationCallback kAudioDevicePropertyBufferFrameSize");
404 // Check new buffer size
405 UInt32 tmp_buffer_size
;
406 UInt32 outSize
= sizeof(UInt32
);
407 OSStatus err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyBufferFrameSize
, &outSize
, &tmp_buffer_size
);
409 jack_error("Cannot get current buffer size");
412 jack_log("JackCoreAudioDriver::BSNotificationCallback : checked buffer size = %d", tmp_buffer_size
);
414 driver
->fState
= true;
422 // A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
423 OSStatus
JackCoreAudioDriver::AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID
, void* inClientData
)
425 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inClientData
;
427 switch (inPropertyID
) {
429 case kAudioHardwarePropertyDevices
: {
430 jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices");
431 DisplayDeviceNames();
432 AudioDeviceID captureID
, playbackID
;
433 if (CheckAvailableDevice(driver
->fDeviceID
) ||
434 (CheckAvailableDeviceName(driver
->fCaptureUID
, &captureID
)
435 && CheckAvailableDeviceName(driver
->fPlaybackUID
, &playbackID
))) {
445 OSStatus
JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice
,
448 AudioDevicePropertyID inPropertyID
,
451 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inClientData
;
453 switch (inPropertyID
) {
455 case kAudioDevicePropertyDeviceIsRunning
: {
456 UInt32 isrunning
= 0;
457 UInt32 outsize
= sizeof(UInt32
);
458 if (AudioDeviceGetProperty(driver
->fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyDeviceIsRunning
, &outsize
, &isrunning
) == noErr
) {
459 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsRunning = %d", isrunning
);
464 case kAudioDevicePropertyDeviceIsAlive
: {
466 UInt32 outsize
= sizeof(UInt32
);
467 if (AudioDeviceGetProperty(driver
->fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyDeviceIsAlive
, &outsize
, &isalive
) == noErr
) {
468 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsAlive = %d", isalive
);
473 case kAudioDevicePropertyDeviceHasChanged
: {
474 UInt32 hachanged
= 0;
475 UInt32 outsize
= sizeof(UInt32
);
476 if (AudioDeviceGetProperty(driver
->fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyDeviceHasChanged
, &outsize
, &hachanged
) == noErr
) {
477 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceHasChanged = %d", hachanged
);
482 case kAudioDeviceProcessorOverload
: {
483 jack_error("DeviceNotificationCallback kAudioDeviceProcessorOverload");
484 jack_time_t cur_time
= GetMicroSeconds();
485 driver
->NotifyXRun(cur_time
, float(cur_time
- driver
->fBeginDateUst
)); // Better this value than nothing...
489 case kAudioDevicePropertyStreamConfiguration
: {
490 jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration : server will quit...");
491 driver
->NotifyFailure(JackBackendError
, "Another application has changed the device configuration"); // Message length limited to JACK_MESSAGE_SIZE
492 driver
->CloseAUHAL();
493 kill(JackTools::GetPID(), SIGINT
);
494 return kAudioHardwareUnsupportedOperationError
;
497 case kAudioDevicePropertyNominalSampleRate
: {
498 Float64 sample_rate
= 0;
499 UInt32 outsize
= sizeof(Float64
);
500 OSStatus err
= AudioDeviceGetProperty(driver
->fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outsize
, &sample_rate
);
502 return kAudioHardwareUnsupportedOperationError
;
505 char device_name
[256];
506 const char* digidesign_name
= "Digidesign";
507 driver
->GetDeviceNameFromID(driver
->fDeviceID
, device_name
);
509 if (sample_rate
!= driver
->fEngineControl
->fSampleRate
) {
511 // Digidesign hardware, so "special" code : change the SR again here
512 if (strncmp(device_name
, digidesign_name
, 10) == 0) {
514 jack_log("JackCoreAudioDriver::DeviceNotificationCallback Digidesign HW = %s", device_name
);
516 // Set sample rate again...
517 sample_rate
= driver
->fEngineControl
->fSampleRate
;
518 err
= AudioDeviceSetProperty(driver
->fDeviceID
, NULL
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, outsize
, &sample_rate
);
520 jack_error("Cannot set sample rate = %f", sample_rate
);
523 jack_log("JackCoreAudioDriver::DeviceNotificationCallback : set sample rate = %f", sample_rate
);
526 // Check new sample rate again...
527 outsize
= sizeof(Float64
);
528 err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outsize
, &sample_rate
);
530 jack_error("Cannot get current sample rate");
533 jack_log("JackCoreAudioDriver::DeviceNotificationCallback : checked sample rate = %f", sample_rate
);
538 driver
->NotifyFailure(JackBackendError
, "Another application has changed the sample rate"); // Message length limited to JACK_MESSAGE_SIZE
539 driver
->CloseAUHAL();
540 kill(JackTools::GetPID(), SIGINT
);
541 return kAudioHardwareUnsupportedOperationError
;
550 OSStatus
JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID
, AudioDeviceID
* id
)
552 UInt32 size
= sizeof(AudioValueTranslation
);
553 CFStringRef inIUD
= CFStringCreateWithCString(NULL
, UID
, CFStringGetSystemEncoding());
554 AudioValueTranslation value
= { &inIUD
, sizeof(CFStringRef
), id
, sizeof(AudioDeviceID
) };
557 return kAudioHardwareUnspecifiedError
;
559 OSStatus res
= AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID
, &size
, &value
);
561 jack_log("JackCoreAudioDriver::GetDeviceIDFromUID %s %ld", UID
, *id
);
562 return (*id
== kAudioDeviceUnknown
) ? kAudioHardwareBadDeviceError
: res
;
566 OSStatus
JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID
* id
)
569 UInt32 theSize
= sizeof(UInt32
);
570 AudioDeviceID inDefault
;
571 AudioDeviceID outDefault
;
573 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
, &theSize
, &inDefault
)) != noErr
) {
577 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
, &theSize
, &outDefault
)) != noErr
) {
581 jack_log("JackCoreAudioDriver::GetDefaultDevice : input = %ld output = %ld", inDefault
, outDefault
);
583 // Get the device only if default input and output are the same
584 if (inDefault
!= outDefault
) {
585 jack_error("Default input and output devices are not the same !!");
586 return kAudioHardwareBadDeviceError
;
587 } else if (inDefault
== 0) {
588 jack_error("Default input and output devices are null !!");
589 return kAudioHardwareBadDeviceError
;
596 OSStatus
JackCoreAudioDriver::GetDefaultInputDevice(AudioDeviceID
* id
)
599 UInt32 theSize
= sizeof(UInt32
);
600 AudioDeviceID inDefault
;
602 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
, &theSize
, &inDefault
)) != noErr
) {
606 if (inDefault
== 0) {
607 jack_error("Error default input device is 0, please select a correct one !!");
610 jack_log("JackCoreAudioDriver::GetDefaultInputDevice : input = %ld ", inDefault
);
615 OSStatus
JackCoreAudioDriver::GetDefaultOutputDevice(AudioDeviceID
* id
)
618 UInt32 theSize
= sizeof(UInt32
);
619 AudioDeviceID outDefault
;
621 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
, &theSize
, &outDefault
)) != noErr
) {
625 if (outDefault
== 0) {
626 jack_error("Error default output device is 0, please select a correct one !!");
629 jack_log("JackCoreAudioDriver::GetDefaultOutputDevice : output = %ld", outDefault
);
634 OSStatus
JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id
, char* name
)
637 return AudioDeviceGetProperty(id
, 0, false, kAudioDevicePropertyDeviceName
, &size
, name
);
640 OSStatus
JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device
, int& channelCount
, bool isInput
)
642 OSStatus err
= noErr
;
647 err
= AudioDeviceGetPropertyInfo(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize
, &outWritable
);
649 int stream_count
= outSize
/ sizeof(AudioBufferList
);
650 jack_log("JackCoreAudioDriver::GetTotalChannels stream_count = %d", stream_count
);
651 AudioBufferList bufferList
[stream_count
];
652 err
= AudioDeviceGetProperty(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize
, bufferList
);
654 for (uint i
= 0; i
< bufferList
->mNumberBuffers
; i
++) {
655 channelCount
+= bufferList
->mBuffers
[i
].mNumberChannels
;
656 jack_log("JackCoreAudioDriver::GetTotalChannels stream = %d channels = %d", i
, bufferList
->mBuffers
[i
].mNumberChannels
);
663 OSStatus
JackCoreAudioDriver::GetStreamLatencies(AudioDeviceID device
, bool isInput
, vector
<int>& latencies
)
665 OSStatus err
= noErr
;
666 UInt32 outSize1
, outSize2
, outSize3
;
669 err
= AudioDeviceGetPropertyInfo(device
, 0, isInput
, kAudioDevicePropertyStreams
, &outSize1
, &outWritable
);
671 int stream_count
= outSize1
/ sizeof(UInt32
);
672 AudioStreamID streamIDs
[stream_count
];
673 AudioBufferList bufferList
[stream_count
];
674 UInt32 streamLatency
;
675 outSize2
= sizeof(UInt32
);
677 err
= AudioDeviceGetProperty(device
, 0, isInput
, kAudioDevicePropertyStreams
, &outSize1
, streamIDs
);
679 jack_error("GetStreamLatencies kAudioDevicePropertyStreams err = %d", err
);
683 err
= AudioDeviceGetPropertyInfo(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize3
, &outWritable
);
685 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err
);
689 for (int i
= 0; i
< stream_count
; i
++) {
690 err
= AudioStreamGetProperty(streamIDs
[i
], 0, kAudioStreamPropertyLatency
, &outSize2
, &streamLatency
);
692 jack_error("GetStreamLatencies kAudioStreamPropertyLatency err = %d", err
);
695 err
= AudioDeviceGetProperty(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize3
, bufferList
);
697 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err
);
700 // Push 'channel' time the stream latency
701 for (uint k
= 0; k
< bufferList
->mBuffers
[i
].mNumberChannels
; k
++) {
702 latencies
.push_back(streamLatency
);
709 bool JackCoreAudioDriver::IsDigitalDevice(AudioDeviceID device
)
711 OSStatus err
= noErr
;
713 bool is_digital
= false;
715 /* Get a list of all the streams on this device */
716 AudioObjectPropertyAddress streamsAddress
= { kAudioDevicePropertyStreams
, kAudioDevicePropertyScopeOutput
, kAudioObjectPropertyElementMaster
};
717 err
= AudioObjectGetPropertyDataSize(device
, &streamsAddress
, 0, NULL
, &outSize1
);
719 jack_error("IsDigitalDevice kAudioDevicePropertyStreams err = %d", err
);
723 int stream_count
= outSize1
/ sizeof(AudioStreamID
);
724 AudioStreamID streamIDs
[stream_count
];
726 err
= AudioObjectGetPropertyData(device
, &streamsAddress
, 0, NULL
, &outSize1
, streamIDs
);
729 jack_error("IsDigitalDevice kAudioDevicePropertyStreams list err = %d", err
);
733 AudioObjectPropertyAddress physicalFormatsAddress
= { kAudioStreamPropertyAvailablePhysicalFormats
, kAudioObjectPropertyScopeGlobal
, 0 };
735 for (int i
= 0; i
< stream_count
; i
++) {
737 /* Find a stream with a cac3 stream */
740 /* Retrieve all the stream formats supported by each output stream */
741 err
= AudioObjectGetPropertyDataSize(streamIDs
[i
], &physicalFormatsAddress
, 0, NULL
, &outSize1
);
744 jack_error("IsDigitalDevice kAudioStreamPropertyAvailablePhysicalFormats err = %d", err
);
748 format_num
= outSize1
/ sizeof(AudioStreamRangedDescription
);
749 AudioStreamRangedDescription format_list
[format_num
];
751 err
= AudioObjectGetPropertyData(streamIDs
[i
], &physicalFormatsAddress
, 0, NULL
, &outSize1
, format_list
);
754 jack_error("IsDigitalDevice could not get the list of streamformats err = %d", err
);
758 /* Check if one of the supported formats is a digital format */
759 for (int j
= 0; j
< format_num
; j
++) {
761 PrintStreamDesc(&format_list
[j
].mFormat
);
763 if (format_list
[j
].mFormat
.mFormatID
== 'IAC3' ||
764 format_list
[j
].mFormat
.mFormatID
== 'iac3' ||
765 format_list
[j
].mFormat
.mFormatID
== kAudioFormat60958AC3
||
766 format_list
[j
].mFormat
.mFormatID
== kAudioFormatAC3
)
777 JackCoreAudioDriver::JackCoreAudioDriver(const char* name
, const char* alias
, JackLockedEngine
* engine
, JackSynchro
* table
)
778 : JackAudioDriver(name
, alias
, engine
, table
),
780 fJackInputData(NULL
),
781 fDriverOutputData(NULL
),
786 fComputationGrain(-1.f
),
787 fClockDriftCompensate(false),
788 fDigitalPlayback(false)
791 JackCoreAudioDriver::~JackCoreAudioDriver()
796 OSStatus
JackCoreAudioDriver::DestroyAggregateDevice()
798 OSStatus osErr
= noErr
;
799 AudioObjectPropertyAddress pluginAOPA
;
800 pluginAOPA
.mSelector
= kAudioPlugInDestroyAggregateDevice
;
801 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
802 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
807 osErr
= AudioObjectGetPropertyDataSize(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
);
808 if (osErr
!= noErr
) {
809 jack_error("DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
814 osErr
= AudioObjectGetPropertyData(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
, &fDeviceID
);
815 if (osErr
!= noErr
) {
816 jack_error("DestroyAggregateDevice : AudioObjectGetPropertyData error");
826 OSStatus
JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceID
, AudioDeviceID playbackDeviceID
, jack_nframes_t samplerate
, AudioDeviceID
* outAggregateDevice
)
828 OSStatus err
= noErr
;
829 AudioObjectID sub_device
[32];
830 UInt32 outSize
= sizeof(sub_device
);
832 err
= AudioDeviceGetProperty(captureDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
833 vector
<AudioDeviceID
> captureDeviceIDArray
;
836 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input device does not have subdevices");
837 captureDeviceIDArray
.push_back(captureDeviceID
);
839 int num_devices
= outSize
/ sizeof(AudioObjectID
);
840 jack_log("JackCoreAudioDriver::CreateAggregateDevice :Input device has %d subdevices", num_devices
);
841 for (int i
= 0; i
< num_devices
; i
++) {
842 captureDeviceIDArray
.push_back(sub_device
[i
]);
846 err
= AudioDeviceGetProperty(playbackDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
847 vector
<AudioDeviceID
> playbackDeviceIDArray
;
850 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device does not have subdevices");
851 playbackDeviceIDArray
.push_back(playbackDeviceID
);
853 int num_devices
= outSize
/ sizeof(AudioObjectID
);
854 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device has %d subdevices", num_devices
);
855 for (int i
= 0; i
< num_devices
; i
++) {
856 playbackDeviceIDArray
.push_back(sub_device
[i
]);
860 return CreateAggregateDeviceAux(captureDeviceIDArray
, playbackDeviceIDArray
, samplerate
, outAggregateDevice
);
863 OSStatus
JackCoreAudioDriver::CreateAggregateDeviceAux(vector
<AudioDeviceID
> captureDeviceID
, vector
<AudioDeviceID
> playbackDeviceID
, jack_nframes_t samplerate
, AudioDeviceID
* outAggregateDevice
)
865 OSStatus osErr
= noErr
;
869 // Prepare sub-devices for clock drift compensation
870 // Workaround for bug in the HAL : until 10.6.2
871 AudioObjectPropertyAddress theAddressOwned
= { kAudioObjectPropertyOwnedObjects
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
872 AudioObjectPropertyAddress theAddressDrift
= { kAudioSubDevicePropertyDriftCompensation
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
873 UInt32 theQualifierDataSize
= sizeof(AudioObjectID
);
874 AudioClassID inClass
= kAudioSubDeviceClassID
;
875 void* theQualifierData
= &inClass
;
876 UInt32 subDevicesNum
= 0;
878 //---------------------------------------------------------------------------
879 // Setup SR of both devices otherwise creating AD may fail...
880 //---------------------------------------------------------------------------
881 UInt32 keptclockdomain
= 0;
882 UInt32 clockdomain
= 0;
883 outSize
= sizeof(UInt32
);
884 bool need_clock_drift_compensation
= false;
886 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
887 if (SetupSampleRateAux(captureDeviceID
[i
], samplerate
) < 0) {
888 jack_error("CreateAggregateDevice : cannot set SR of input device");
890 // Check clock domain
891 osErr
= AudioDeviceGetProperty(captureDeviceID
[i
], 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyClockDomain
, &outSize
, &clockdomain
);
893 jack_error("CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
896 keptclockdomain
= (keptclockdomain
== 0) ? clockdomain
: keptclockdomain
;
897 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain
);
898 if (clockdomain
!= 0 && clockdomain
!= keptclockdomain
) {
899 jack_error("CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
900 need_clock_drift_compensation
= true;
906 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
907 if (SetupSampleRateAux(playbackDeviceID
[i
], samplerate
) < 0) {
908 jack_error("CreateAggregateDevice : cannot set SR of output device");
910 // Check clock domain
911 osErr
= AudioDeviceGetProperty(playbackDeviceID
[i
], 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyClockDomain
, &outSize
, &clockdomain
);
913 jack_error("CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
916 keptclockdomain
= (keptclockdomain
== 0) ? clockdomain
: keptclockdomain
;
917 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain
);
918 if (clockdomain
!= 0 && clockdomain
!= keptclockdomain
) {
919 jack_error("CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
920 need_clock_drift_compensation
= true;
926 // If no valid clock domain was found, then assume we have to compensate...
927 if (keptclockdomain
== 0) {
928 need_clock_drift_compensation
= true;
931 //---------------------------------------------------------------------------
932 // Start to create a new aggregate by getting the base audio hardware plugin
933 //---------------------------------------------------------------------------
935 char device_name
[256];
936 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
937 GetDeviceNameFromID(captureDeviceID
[i
], device_name
);
938 jack_info("Separated input = '%s' ", device_name
);
941 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
942 GetDeviceNameFromID(playbackDeviceID
[i
], device_name
);
943 jack_info("Separated output = '%s' ", device_name
);
946 osErr
= AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID
, &outSize
, &outWritable
);
947 if (osErr
!= noErr
) {
948 jack_error("CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
953 AudioValueTranslation pluginAVT
;
955 CFStringRef inBundleRef
= CFSTR("com.apple.audio.CoreAudio");
957 pluginAVT
.mInputData
= &inBundleRef
;
958 pluginAVT
.mInputDataSize
= sizeof(inBundleRef
);
959 pluginAVT
.mOutputData
= &fPluginID
;
960 pluginAVT
.mOutputDataSize
= sizeof(fPluginID
);
962 osErr
= AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID
, &outSize
, &pluginAVT
);
963 if (osErr
!= noErr
) {
964 jack_error("CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
969 //-------------------------------------------------
970 // Create a CFDictionary for our aggregate device
971 //-------------------------------------------------
973 CFMutableDictionaryRef aggDeviceDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
975 CFStringRef AggregateDeviceNameRef
= CFSTR("JackDuplex");
976 CFStringRef AggregateDeviceUIDRef
= CFSTR("com.grame.JackDuplex");
978 // add the name of the device to the dictionary
979 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceNameKey
), AggregateDeviceNameRef
);
981 // add our choice of UID for the aggregate device to the dictionary
982 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceUIDKey
), AggregateDeviceUIDRef
);
984 // add a "private aggregate key" to the dictionary
986 CFNumberRef AggregateDeviceNumberRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &value
);
989 Gestalt(gestaltSystemVersion
, &system
);
991 jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system
, 0x00001054);
993 // Starting with 10.5.4 systems, the AD can be internal... (better)
994 if (system
< 0x00001054) {
995 jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device....");
997 jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device....");
998 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceIsPrivateKey
), AggregateDeviceNumberRef
);
1001 // Prepare sub-devices for clock drift compensation
1002 CFMutableArrayRef subDevicesArrayClock
= NULL
;
1005 if (fClockDriftCompensate) {
1006 if (need_clock_drift_compensation) {
1007 jack_info("Clock drift compensation activated...");
1008 subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1010 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
1011 CFStringRef UID = GetDeviceName(captureDeviceID[i]);
1013 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1014 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
1015 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
1017 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
1021 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
1022 CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
1024 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1025 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
1026 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
1028 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
1032 // add sub-device clock array for the aggregate device to the dictionary
1033 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
1035 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
1040 //-------------------------------------------------
1041 // Create a CFMutableArray for our sub-device list
1042 //-------------------------------------------------
1044 // we need to append the UID for each device to a CFMutableArray, so create one here
1045 CFMutableArrayRef subDevicesArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1047 vector
<CFStringRef
> captureDeviceUID
;
1048 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
1049 CFStringRef ref
= GetDeviceName(captureDeviceID
[i
]);
1053 captureDeviceUID
.push_back(ref
);
1054 // input sub-devices in this example, so append the sub-device's UID to the CFArray
1055 CFArrayAppendValue(subDevicesArray
, ref
);
1058 vector
<CFStringRef
> playbackDeviceUID
;
1059 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
1060 CFStringRef ref
= GetDeviceName(playbackDeviceID
[i
]);
1064 playbackDeviceUID
.push_back(ref
);
1065 // output sub-devices in this example, so append the sub-device's UID to the CFArray
1066 CFArrayAppendValue(subDevicesArray
, ref
);
1069 //-----------------------------------------------------------------------
1070 // Feed the dictionary to the plugin, to create a blank aggregate device
1071 //-----------------------------------------------------------------------
1073 AudioObjectPropertyAddress pluginAOPA
;
1074 pluginAOPA
.mSelector
= kAudioPlugInCreateAggregateDevice
;
1075 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1076 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1079 osErr
= AudioObjectGetPropertyDataSize(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
);
1080 if (osErr
!= noErr
) {
1081 jack_error("CreateAggregateDevice : AudioObjectGetPropertyDataSize error");
1086 osErr
= AudioObjectGetPropertyData(fPluginID
, &pluginAOPA
, sizeof(aggDeviceDict
), &aggDeviceDict
, &outDataSize
, outAggregateDevice
);
1087 if (osErr
!= noErr
) {
1088 jack_error("CreateAggregateDevice : AudioObjectGetPropertyData error");
1093 // pause for a bit to make sure that everything completed correctly
1094 // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
1095 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1097 //-------------------------
1098 // Set the sub-device list
1099 //-------------------------
1101 pluginAOPA
.mSelector
= kAudioAggregateDevicePropertyFullSubDeviceList
;
1102 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1103 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1104 outDataSize
= sizeof(CFMutableArrayRef
);
1105 osErr
= AudioObjectSetPropertyData(*outAggregateDevice
, &pluginAOPA
, 0, NULL
, outDataSize
, &subDevicesArray
);
1106 if (osErr
!= noErr
) {
1107 jack_error("CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error");
1112 // pause again to give the changes time to take effect
1113 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1115 //-----------------------
1116 // Set the master device
1117 //-----------------------
1119 // set the master device manually (this is the device which will act as the master clock for the aggregate device)
1120 // pass in the UID of the device you want to use
1121 pluginAOPA
.mSelector
= kAudioAggregateDevicePropertyMasterSubDevice
;
1122 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1123 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1124 outDataSize
= sizeof(CFStringRef
);
1125 osErr
= AudioObjectSetPropertyData(*outAggregateDevice
, &pluginAOPA
, 0, NULL
, outDataSize
, &captureDeviceUID
[0]); // First apture is master...
1126 if (osErr
!= noErr
) {
1127 jack_error("CreateAggregateDevice : AudioObjectSetPropertyData for master device error");
1132 // pause again to give the changes time to take effect
1133 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1135 // Prepare sub-devices for clock drift compensation
1136 // Workaround for bug in the HAL : until 10.6.2
1138 if (fClockDriftCompensate
) {
1139 if (need_clock_drift_compensation
) {
1140 jack_info("Clock drift compensation activated...");
1142 // Get the property data size
1143 osErr
= AudioObjectGetPropertyDataSize(*outAggregateDevice
, &theAddressOwned
, theQualifierDataSize
, theQualifierData
, &outSize
);
1144 if (osErr
!= noErr
) {
1145 jack_error("CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
1149 // Calculate the number of object IDs
1150 subDevicesNum
= outSize
/ sizeof(AudioObjectID
);
1151 jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum
);
1152 AudioObjectID subDevices
[subDevicesNum
];
1153 outSize
= sizeof(subDevices
);
1155 osErr
= AudioObjectGetPropertyData(*outAggregateDevice
, &theAddressOwned
, theQualifierDataSize
, theQualifierData
, &outSize
, subDevices
);
1156 if (osErr
!= noErr
) {
1157 jack_error("CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
1161 // Set kAudioSubDevicePropertyDriftCompensation property...
1162 for (UInt32 index
= 0; index
< subDevicesNum
; ++index
) {
1163 UInt32 theDriftCompensationValue
= 1;
1164 osErr
= AudioObjectSetPropertyData(subDevices
[index
], &theAddressDrift
, 0, NULL
, sizeof(UInt32
), &theDriftCompensationValue
);
1165 if (osErr
!= noErr
) {
1166 jack_error("CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error");
1171 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
1175 // pause again to give the changes time to take effect
1176 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1182 // release the private AD key
1183 CFRelease(AggregateDeviceNumberRef
);
1185 // release the CF objects we have created - we don't need them any more
1186 CFRelease(aggDeviceDict
);
1187 CFRelease(subDevicesArray
);
1189 if (subDevicesArrayClock
) {
1190 CFRelease(subDevicesArrayClock
);
1193 // release the device UID
1194 for (UInt32 i
= 0; i
< captureDeviceUID
.size(); i
++) {
1195 CFRelease(captureDeviceUID
[i
]);
1198 for (UInt32 i
= 0; i
< playbackDeviceUID
.size(); i
++) {
1199 CFRelease(playbackDeviceUID
[i
]);
1202 jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : new aggregate device %ld", *outAggregateDevice
);
1206 DestroyAggregateDevice();
1210 int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid
,
1211 const char* playback_driver_uid
,
1212 char* capture_driver_name
,
1213 char* playback_driver_name
,
1214 jack_nframes_t samplerate
,
1217 capture_driver_name
[0] = 0;
1218 playback_driver_name
[0] = 0;
1221 if (strcmp(capture_driver_uid
, "") != 0 && strcmp(playback_driver_uid
, "") != 0) {
1222 jack_log("JackCoreAudioDriver::SetupDevices : duplex");
1224 // Same device for capture and playback...
1225 if (strcmp(capture_driver_uid
, playback_driver_uid
) == 0) {
1227 if (GetDeviceIDFromUID(playback_driver_uid
, &fDeviceID
) != noErr
) {
1228 jack_log("JackCoreAudioDriver::SetupDevices : will take default in/out");
1229 if (GetDefaultDevice(&fDeviceID
) != noErr
) {
1230 jack_error("Cannot open default device");
1234 if (GetDeviceNameFromID(fDeviceID
, capture_driver_name
) != noErr
|| GetDeviceNameFromID(fDeviceID
, playback_driver_name
) != noErr
) {
1235 jack_error("Cannot get device name from device ID");
1240 if (!TakeHogAux(fDeviceID
, false)) {
1241 jack_error("Cannot take hog mode");
1244 fDigitalPlayback
= IsDigitalDevice(fDeviceID
);
1250 // Creates aggregate device
1251 AudioDeviceID captureID
= -1;
1252 AudioDeviceID playbackID
= -1;
1254 if (GetDeviceIDFromUID(capture_driver_uid
, &captureID
) != noErr
) {
1255 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1256 if (GetDefaultInputDevice(&captureID
) != noErr
) {
1257 jack_error("Cannot open default input device");
1262 if (GetDeviceIDFromUID(playback_driver_uid
, &playbackID
) != noErr
) {
1263 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1264 if (GetDefaultOutputDevice(&playbackID
) != noErr
) {
1265 jack_error("Cannot open default output device");
1270 if (CreateAggregateDevice(captureID
, playbackID
, samplerate
, &fDeviceID
) != noErr
) {
1274 GetDeviceNameFromID(captureID
, fCaptureUID
);
1275 GetDeviceNameFromID(playbackID
, fPlaybackUID
);
1278 if (!TakeHogAux(captureID
, true)) {
1279 jack_error("Cannot take hog mode for capture device");
1281 if (!TakeHogAux(playbackID
, false)) {
1282 jack_error("Cannot take hog mode for playback device");
1285 fDigitalPlayback
= IsDigitalDevice(playbackID
);
1292 } else if (strcmp(capture_driver_uid
, "") != 0) {
1293 jack_log("JackCoreAudioDriver::SetupDevices : capture only");
1294 if (GetDeviceIDFromUID(capture_driver_uid
, &fDeviceID
) != noErr
) {
1295 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1296 if (GetDefaultInputDevice(&fDeviceID
) != noErr
) {
1297 jack_error("Cannot open default input device");
1301 if (GetDeviceNameFromID(fDeviceID
, capture_driver_name
) != noErr
) {
1302 jack_error("Cannot get device name from device ID");
1307 if (!TakeHogAux(fDeviceID
, true)) {
1308 jack_error("Cannot take hog mode for capture device");
1313 } else if (strcmp(playback_driver_uid
, "") != 0) {
1314 jack_log("JackCoreAudioDriver::SetupDevices : playback only");
1315 if (GetDeviceIDFromUID(playback_driver_uid
, &fDeviceID
) != noErr
) {
1316 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1317 if (GetDefaultOutputDevice(&fDeviceID
) != noErr
) {
1318 jack_error("Cannot open default output device");
1322 if (GetDeviceNameFromID(fDeviceID
, playback_driver_name
) != noErr
) {
1323 jack_error("Cannot get device name from device ID");
1328 if (!TakeHogAux(fDeviceID
, false)) {
1329 jack_error("Cannot take hog mode for playback device");
1332 fDigitalPlayback
= IsDigitalDevice(fDeviceID
);
1336 // Use default driver in duplex mode
1338 jack_log("JackCoreAudioDriver::SetupDevices : default driver");
1339 if (GetDefaultDevice(&fDeviceID
) != noErr
) {
1340 jack_error("Cannot open default device in duplex mode, so aggregate default input and default output");
1342 // Creates aggregate device
1343 AudioDeviceID captureID
= -1;
1344 AudioDeviceID playbackID
= -1;
1346 if (GetDeviceIDFromUID(capture_driver_uid
, &captureID
) != noErr
) {
1347 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1348 if (GetDefaultInputDevice(&captureID
) != noErr
) {
1349 jack_error("Cannot open default input device");
1354 if (GetDeviceIDFromUID(playback_driver_uid
, &playbackID
) != noErr
) {
1355 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1356 if (GetDefaultOutputDevice(&playbackID
) != noErr
) {
1357 jack_error("Cannot open default output device");
1362 if (CreateAggregateDevice(captureID
, playbackID
, samplerate
, &fDeviceID
) != noErr
) {
1366 GetDeviceNameFromID(captureID
, fCaptureUID
);
1367 GetDeviceNameFromID(playbackID
, fPlaybackUID
);
1370 if (!TakeHogAux(captureID
, true)) {
1371 jack_error("Cannot take hog mode for capture device");
1373 if (!TakeHogAux(playbackID
, false)) {
1374 jack_error("Cannot take hog mode for playback device");
1377 fDigitalPlayback
= IsDigitalDevice(playbackID
);
1387 Return the max possible input channels in in_nChannels and output channels in out_nChannels.
1389 int JackCoreAudioDriver::SetupChannels(bool capturing
, bool playing
, int& inchannels
, int& outchannels
, int& in_nChannels
, int& out_nChannels
, bool strict
)
1391 OSStatus err
= noErr
;
1394 err
= GetTotalChannels(fDeviceID
, in_nChannels
, true);
1396 jack_error("SetupChannels : cannot get input channel number");
1400 jack_log("JackCoreAudioDriver::SetupChannels : max input channels : %d", in_nChannels
);
1405 err
= GetTotalChannels(fDeviceID
, out_nChannels
, false);
1407 jack_error("Cannot get output channel number");
1411 jack_log("JackCoreAudioDriver::SetupChannels : max output channels : %d", out_nChannels
);
1415 if (inchannels
> in_nChannels
) {
1416 jack_error("This device hasn't required input channels inchannels = %d in_nChannels = %d", inchannels
, in_nChannels
);
1422 if (outchannels
> out_nChannels
) {
1423 jack_error("This device hasn't required output channels outchannels = %d out_nChannels = %d", outchannels
, out_nChannels
);
1429 if (inchannels
== -1) {
1430 jack_log("JackCoreAudioDriver::SetupChannels : setup max in channels = %d", in_nChannels
);
1431 inchannels
= in_nChannels
;
1434 if (outchannels
== -1) {
1435 jack_log("JackCoreAudioDriver::SetupChannels : setup max out channels = %d", out_nChannels
);
1436 outchannels
= out_nChannels
;
1442 int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size
)
1444 // Setting buffer size
1445 OSStatus err
= noErr
;
1446 UInt32 tmp_buffer_size
= buffer_size
;
1447 UInt32 outSize
= sizeof(UInt32
);
1449 err
= AudioDeviceGetProperty(fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyBufferFrameSize
, &outSize
, &tmp_buffer_size
);
1451 jack_error("Cannot get buffer size %ld", buffer_size
);
1455 jack_log("JackCoreAudioDriver::SetupBufferSize : current buffer size = %ld", tmp_buffer_size
);
1458 // If needed, set new buffer size
1459 if (buffer_size
!= tmp_buffer_size
) {
1460 tmp_buffer_size
= buffer_size
;
1462 // To get BS change notification
1463 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyBufferFrameSize
, BSNotificationCallback
, this);
1465 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyBufferFrameSize");
1470 // Waiting for BS change notification
1474 err
= AudioDeviceSetProperty(fDeviceID
, NULL
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyBufferFrameSize
, outSize
, &tmp_buffer_size
);
1476 jack_error("SetupBufferSize : cannot set buffer size = %ld", tmp_buffer_size
);
1481 while (!fState
&& count
++ < WAIT_NOTIFICATION_COUNTER
) {
1483 jack_log("JackCoreAudioDriver::SetupBufferSize : wait count = %d", count
);
1486 if (count
>= WAIT_NOTIFICATION_COUNTER
) {
1487 jack_error("Did not get buffer size notification...");
1491 // Check new buffer size
1492 outSize
= sizeof(UInt32
);
1493 err
= AudioDeviceGetProperty(fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyBufferFrameSize
, &outSize
, &tmp_buffer_size
);
1495 jack_error("Cannot get current buffer size");
1498 jack_log("JackCoreAudioDriver::SetupBufferSize : checked buffer size = %ld", tmp_buffer_size
);
1501 // Remove BS change notification
1502 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyBufferFrameSize
, BSNotificationCallback
);
1509 // Remove BS change notification
1510 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyBufferFrameSize
, BSNotificationCallback
);
1515 int JackCoreAudioDriver::SetupSampleRate(jack_nframes_t sample_rate
)
1517 return SetupSampleRateAux(fDeviceID
, sample_rate
);
1520 int JackCoreAudioDriver::SetupSampleRateAux(AudioDeviceID inDevice
, jack_nframes_t sample_rate
)
1522 OSStatus err
= noErr
;
1524 Float64 tmp_sample_rate
;
1527 outSize
= sizeof(Float64
);
1528 err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outSize
, &tmp_sample_rate
);
1530 jack_error("Cannot get current sample rate");
1534 jack_log("JackCoreAudioDriver::SetupSampleRateAux : current sample rate = %f", tmp_sample_rate
);
1537 // If needed, set new sample rate
1538 if (sample_rate
!= (jack_nframes_t
)tmp_sample_rate
) {
1539 tmp_sample_rate
= (Float64
)sample_rate
;
1541 // To get SR change notification
1542 err
= AudioDeviceAddPropertyListener(inDevice
, 0, true, kAudioDevicePropertyNominalSampleRate
, SRNotificationCallback
, this);
1544 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
1549 // Waiting for SR change notification
1553 err
= AudioDeviceSetProperty(inDevice
, NULL
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, outSize
, &tmp_sample_rate
);
1555 jack_error("Cannot set sample rate = %ld", sample_rate
);
1560 while (!fState
&& count
++ < WAIT_NOTIFICATION_COUNTER
) {
1562 jack_log("JackCoreAudioDriver::SetupSampleRateAux : wait count = %d", count
);
1565 if (count
>= WAIT_NOTIFICATION_COUNTER
) {
1566 jack_error("Did not get sample rate notification...");
1570 // Check new sample rate
1571 outSize
= sizeof(Float64
);
1572 err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outSize
, &tmp_sample_rate
);
1574 jack_error("Cannot get current sample rate");
1577 jack_log("JackCoreAudioDriver::SetupSampleRateAux : checked sample rate = %f", tmp_sample_rate
);
1580 // Remove SR change notification
1581 AudioDeviceRemovePropertyListener(inDevice
, 0, true, kAudioDevicePropertyNominalSampleRate
, SRNotificationCallback
);
1588 // Remove SR change notification
1589 AudioDeviceRemovePropertyListener(inDevice
, 0, true, kAudioDevicePropertyNominalSampleRate
, SRNotificationCallback
);
1593 int JackCoreAudioDriver::OpenAUHAL(bool capturing
,
1599 const vector
<int>& chan_in_list
,
1600 const vector
<int>& chan_out_list
,
1601 jack_nframes_t buffer_size
,
1602 jack_nframes_t sample_rate
)
1604 ComponentResult err1
;
1606 AudioStreamBasicDescription srcFormat
, dstFormat
;
1607 AudioDeviceID currAudioDeviceID
;
1610 jack_log("JackCoreAudioDriver::OpenAUHAL : capturing = %d playing = %d inchannels = %d outchannels = %d in_nChannels = %d out_nChannels = %d chan_in_list = %d chan_out_list = %d",
1611 capturing
, playing
, inchannels
, outchannels
, in_nChannels
, out_nChannels
, chan_in_list
.size(), chan_out_list
.size());
1613 if (inchannels
== 0 && outchannels
== 0) {
1614 jack_error("No input and output channels...");
1619 ComponentDescription cd
= {kAudioUnitType_Output
, kAudioUnitSubType_HALOutput
, kAudioUnitManufacturer_Apple
, 0, 0};
1620 Component HALOutput
= FindNextComponent(NULL
, &cd
);
1622 err1
= OpenAComponent(HALOutput
, &fAUHAL
);
1623 if (err1
!= noErr
) {
1624 jack_error("Error calling OpenAComponent");
1629 err1
= AudioUnitInitialize(fAUHAL
);
1630 if (err1
!= noErr
) {
1631 jack_error("Cannot initialize AUHAL unit");
1637 if (capturing
&& inchannels
> 0) {
1639 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input on");
1642 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input off");
1645 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Input
, 1, &enableIO
, sizeof(enableIO
));
1646 if (err1
!= noErr
) {
1647 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
1652 if (playing
&& outchannels
> 0) {
1654 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output on");
1657 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output off");
1660 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Output
, 0, &enableIO
, sizeof(enableIO
));
1661 if (err1
!= noErr
) {
1662 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
1667 size
= sizeof(AudioDeviceID
);
1668 err1
= AudioUnitGetProperty(fAUHAL
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &currAudioDeviceID
, &size
);
1669 if (err1
!= noErr
) {
1670 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
1674 jack_log("JackCoreAudioDriver::OpenAUHAL : AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID
);
1677 // Setup up choosen device, in both input and output cases
1678 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &fDeviceID
, sizeof(AudioDeviceID
));
1679 if (err1
!= noErr
) {
1680 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
1686 if (capturing
&& inchannels
> 0) {
1687 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Global
, 1, (UInt32
*)&buffer_size
, sizeof(UInt32
));
1688 if (err1
!= noErr
) {
1689 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
1695 if (playing
&& outchannels
> 0) {
1696 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Global
, 0, (UInt32
*)&buffer_size
, sizeof(UInt32
));
1697 if (err1
!= noErr
) {
1698 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
1704 // Setup input channel map
1705 if (capturing
&& inchannels
> 0 && inchannels
<= in_nChannels
) {
1706 SInt32 chanArr
[in_nChannels
];
1707 for (int i
= 0; i
< in_nChannels
; i
++) {
1711 if (chan_in_list
.size() > 0) {
1712 for (uint i
= 0; i
< chan_in_list
.size(); i
++) {
1713 int chan
= chan_in_list
[i
];
1714 if (chan
< out_nChannels
) {
1715 // The wanted JACK input index for the 'chan' channel value
1717 jack_info("Input channel = %d ==> JACK input port = %d", chan
, i
);
1719 jack_info("Error input channel number is incorrect : %d", chan
);
1724 for (int i
= 0; i
< inchannels
; i
++) {
1726 jack_info("Input channel = %d ==> JACK input port = %d", chanArr
[i
], i
);
1730 AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Input
, 1, chanArr
, sizeof(SInt32
) * in_nChannels
);
1731 if (err1
!= noErr
) {
1732 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap for input");
1738 // Setup output channel map
1739 if (playing
&& outchannels
> 0 && outchannels
<= out_nChannels
) {
1740 SInt32 chanArr
[out_nChannels
];
1741 for (int i
= 0; i
< out_nChannels
; i
++) {
1745 if (chan_out_list
.size() > 0) {
1746 for (uint i
= 0; i
< chan_out_list
.size(); i
++) {
1747 int chan
= chan_out_list
[i
];
1748 if (chan
< out_nChannels
) {
1749 // The wanted JACK output index for the 'chan' channel value
1751 jack_info("JACK output port = %d ==> output channel = %d", i
, chan
);
1753 jack_info("Error output channel number is incorrect : %d", chan
);
1758 for (int i
= 0; i
< outchannels
; i
++) {
1760 jack_info("JACK output port = %d ==> output channel = %d", i
, chanArr
[i
]);
1764 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Output
, 0, chanArr
, sizeof(SInt32
) * out_nChannels
);
1765 if (err1
!= noErr
) {
1766 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap for output");
1772 // Setup stream converters
1773 if (capturing
&& inchannels
> 0) {
1775 size
= sizeof(AudioStreamBasicDescription
);
1776 err1
= AudioUnitGetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &srcFormat
, &size
);
1777 if (err1
!= noErr
) {
1778 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
1782 PrintStreamDesc(&srcFormat
);
1784 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input stream converter SR = %ld", sample_rate
);
1785 srcFormat
.mSampleRate
= sample_rate
;
1786 srcFormat
.mFormatID
= kAudioFormatLinearPCM
;
1787 srcFormat
.mFormatFlags
= kAudioFormatFlagsNativeFloatPacked
| kLinearPCMFormatFlagIsNonInterleaved
;
1788 srcFormat
.mBytesPerPacket
= sizeof(jack_default_audio_sample_t
);
1789 srcFormat
.mFramesPerPacket
= 1;
1790 srcFormat
.mBytesPerFrame
= sizeof(jack_default_audio_sample_t
);
1791 srcFormat
.mChannelsPerFrame
= inchannels
;
1792 srcFormat
.mBitsPerChannel
= 32;
1793 PrintStreamDesc(&srcFormat
);
1795 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &srcFormat
, sizeof(AudioStreamBasicDescription
));
1796 if (err1
!= noErr
) {
1797 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
1803 if (playing
&& outchannels
> 0) {
1805 size
= sizeof(AudioStreamBasicDescription
);
1806 err1
= AudioUnitGetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &dstFormat
, &size
);
1807 if (err1
!= noErr
) {
1808 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
1812 PrintStreamDesc(&dstFormat
);
1814 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output stream converter SR = %ld", sample_rate
);
1815 dstFormat
.mSampleRate
= sample_rate
;
1816 dstFormat
.mFormatID
= kAudioFormatLinearPCM
;
1817 dstFormat
.mFormatFlags
= kAudioFormatFlagsNativeFloatPacked
| kLinearPCMFormatFlagIsNonInterleaved
;
1818 dstFormat
.mBytesPerPacket
= sizeof(jack_default_audio_sample_t
);
1819 dstFormat
.mFramesPerPacket
= 1;
1820 dstFormat
.mBytesPerFrame
= sizeof(jack_default_audio_sample_t
);
1821 dstFormat
.mChannelsPerFrame
= outchannels
;
1822 dstFormat
.mBitsPerChannel
= 32;
1823 PrintStreamDesc(&dstFormat
);
1825 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &dstFormat
, sizeof(AudioStreamBasicDescription
));
1826 if (err1
!= noErr
) {
1827 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
1834 if (inchannels
> 0 && outchannels
== 0) {
1835 AURenderCallbackStruct output
;
1836 output
.inputProc
= Render
;
1837 output
.inputProcRefCon
= this;
1838 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_SetInputCallback
, kAudioUnitScope_Global
, 0, &output
, sizeof(output
));
1839 if (err1
!= noErr
) {
1840 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
1845 AURenderCallbackStruct output
;
1846 output
.inputProc
= Render
;
1847 output
.inputProcRefCon
= this;
1848 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_SetRenderCallback
, kAudioUnitScope_Input
, 0, &output
, sizeof(output
));
1849 if (err1
!= noErr
) {
1850 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
1863 int JackCoreAudioDriver::SetupBuffers(int inchannels
)
1866 fJackInputData
= (AudioBufferList
*)malloc(sizeof(UInt32
) + inchannels
* sizeof(AudioBuffer
));
1867 fJackInputData
->mNumberBuffers
= inchannels
;
1868 for (int i
= 0; i
< inchannels
; i
++) {
1869 fJackInputData
->mBuffers
[i
].mNumberChannels
= 1;
1870 fJackInputData
->mBuffers
[i
].mDataByteSize
= fEngineControl
->fBufferSize
* sizeof(jack_default_audio_sample_t
);
1875 void JackCoreAudioDriver::DisposeBuffers()
1877 if (fJackInputData
) {
1878 free(fJackInputData
);
1883 void JackCoreAudioDriver::CloseAUHAL()
1885 AudioOutputUnitStop(fAUHAL
);
1886 AudioUnitUninitialize(fAUHAL
);
1887 CloseComponent(fAUHAL
);
1890 int JackCoreAudioDriver::AddListeners()
1892 OSStatus err
= noErr
;
1895 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDeviceProcessorOverload
, DeviceNotificationCallback
, this);
1897 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
1902 err
= AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices
, AudioHardwareNotificationCallback
, this);
1904 jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices");
1909 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyNominalSampleRate
, DeviceNotificationCallback
, this);
1911 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
1916 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsRunning
, DeviceNotificationCallback
, this);
1918 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
1923 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsAlive
, DeviceNotificationCallback
, this);
1925 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsAlive");
1930 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceHasChanged
, DeviceNotificationCallback
, this);
1932 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceHasChanged");
1937 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
, this);
1939 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1944 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, false, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
, this);
1946 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1951 if (!fEngineControl
->fSyncMode
&& fIOUsage
!= 1.f
) {
1952 UInt32 outSize
= sizeof(float);
1953 err
= AudioDeviceSetProperty(fDeviceID
, NULL
, 0, false, kAudioDevicePropertyIOCycleUsage
, outSize
, &fIOUsage
);
1955 jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage");
1963 void JackCoreAudioDriver::RemoveListeners()
1965 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDeviceProcessorOverload
, DeviceNotificationCallback
);
1966 AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices
, AudioHardwareNotificationCallback
);
1967 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyNominalSampleRate
, DeviceNotificationCallback
);
1968 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsRunning
, DeviceNotificationCallback
);
1969 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsAlive
, DeviceNotificationCallback
);
1970 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceHasChanged
, DeviceNotificationCallback
);
1971 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
);
1972 AudioDeviceRemovePropertyListener(fDeviceID
, 0, false, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
);
1975 int JackCoreAudioDriver::Open(jack_nframes_t buffer_size
,
1976 jack_nframes_t sample_rate
,
1981 const char* chan_in_list
,
1982 const char* chan_out_list
,
1984 const char* capture_driver_uid
,
1985 const char* playback_driver_uid
,
1986 jack_nframes_t capture_latency
,
1987 jack_nframes_t playback_latency
,
1988 int async_output_latency
,
1989 int computation_grain
,
1996 int in_nChannels
= 0;
1997 int out_nChannels
= 0;
1998 char capture_driver_name
[256];
1999 char playback_driver_name
[256];
2001 fCaptureLatency
= capture_latency
;
2002 fPlaybackLatency
= playback_latency
;
2003 fIOUsage
= float(async_output_latency
) / 100.f
;
2004 fComputationGrain
= float(computation_grain
) / 100.f
;
2006 fClockDriftCompensate
= clock_drift
;
2010 Gestalt(gestaltSystemVersionMajor
, &major
);
2011 Gestalt(gestaltSystemVersionMinor
, &minor
);
2013 vector
<int> parsed_chan_in_list
;
2014 vector
<int> parsed_chan_out_list
;
2016 ParseChannelList(chan_in_list
, parsed_chan_in_list
);
2017 if (parsed_chan_in_list
.size() > 0) {
2018 jack_info("Explicit input channel list size = %d", parsed_chan_in_list
.size());
2019 inchannels
= parsed_chan_in_list
.size();
2022 ParseChannelList(chan_out_list
, parsed_chan_out_list
);
2023 if (parsed_chan_out_list
.size() > 0) {
2024 jack_info("Explicit output channel list size = %d", parsed_chan_out_list
.size());
2025 outchannels
= parsed_chan_out_list
.size();
2028 // Starting with 10.6 systems, the HAL notification thread is created internally
2029 if (major
== 10 && minor
>= 6) {
2030 CFRunLoopRef theRunLoop
= NULL
;
2031 AudioObjectPropertyAddress theAddress
= { kAudioHardwarePropertyRunLoop
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
2032 OSStatus osErr
= AudioObjectSetPropertyData (kAudioObjectSystemObject
, &theAddress
, 0, NULL
, sizeof(CFRunLoopRef
), &theRunLoop
);
2033 if (osErr
!= noErr
) {
2034 jack_error("Open kAudioHardwarePropertyRunLoop error");
2039 if (SetupDevices(capture_driver_uid
, playback_driver_uid
, capture_driver_name
, playback_driver_name
, sample_rate
, ac3_encoding
) < 0) {
2043 // Generic JackAudioDriver Open
2044 if (JackAudioDriver::Open(buffer_size
, sample_rate
,
2046 inchannels
, outchannels
,
2048 capture_driver_name
,
2049 playback_driver_name
,
2051 playback_latency
) != 0) {
2055 if (SetupChannels(capturing
, playing
, inchannels
, outchannels
, in_nChannels
, out_nChannels
, !ac3_encoding
) < 0) {
2059 if (SetupBufferSize(buffer_size
) < 0) {
2063 if (SetupSampleRate(sample_rate
) < 0) {
2069 if (!fDigitalPlayback
) {
2070 jack_error("AC3 encoding can only be used with a digital device");
2074 JackAC3EncoderParams params
;
2075 memset(¶ms
, 0, sizeof(JackAC3EncoderParams
));
2076 params
.bitrate
= ac3_bitrate
;
2077 params
.channels
= outchannels
;
2078 params
.sample_rate
= sample_rate
;
2079 params
.lfe
= ac3_lfe
;
2080 fAC3Encoder
= new JackAC3Encoder(params
);
2082 if (!fAC3Encoder
|| !fAC3Encoder
->Init(sample_rate
)) {
2083 jack_error("Cannot allocate or init AC3 encoder");
2087 // Setup AC3 channel number
2088 fPlaybackChannels
= outchannels
;
2090 fPlaybackChannels
++;
2093 if (fPlaybackChannels
< 2 || fPlaybackChannels
> 6) {
2094 jack_error("AC3 encoder channels must be between 2 and 6");
2098 // Force real output channel number to 2
2099 outchannels
= out_nChannels
= 2;
2102 fPlaybackChannels
= outchannels
;
2105 // Core driver may have changed the in/out values
2106 fCaptureChannels
= inchannels
;
2108 if (OpenAUHAL(capturing
, playing
, inchannels
, outchannels
, in_nChannels
, out_nChannels
, parsed_chan_in_list
, parsed_chan_out_list
, buffer_size
, sample_rate
) < 0) {
2112 if (capturing
&& inchannels
> 0) {
2113 if (SetupBuffers(inchannels
) < 0) {
2118 if (AddListeners() < 0) {
2129 int JackCoreAudioDriver::Close()
2131 jack_log("JackCoreAudioDriver::Close");
2133 // Generic audio driver close
2134 int res
= JackAudioDriver::Close();
2139 DestroyAggregateDevice();
2143 void JackCoreAudioDriver::UpdateLatencies()
2147 jack_latency_range_t input_range
;
2148 jack_latency_range_t output_range
;
2149 jack_latency_range_t monitor_range
;
2151 // Get Input latency
2152 size
= sizeof(UInt32
);
2155 err
= AudioDeviceGetProperty(fDeviceID
, 0, true, kAudioDevicePropertyLatency
, &size
, &value1
);
2157 jack_error("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
2159 err
= AudioDeviceGetProperty(fDeviceID
, 0, true, kAudioDevicePropertySafetyOffset
, &size
, &value2
);
2161 jack_error("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
2164 input_range
.min
= input_range
.max
= fEngineControl
->fBufferSize
+ value1
+ value2
+ fCaptureLatency
;
2166 // Get input stream latencies
2167 vector
<int> input_latencies
;
2168 err
= GetStreamLatencies(fDeviceID
, true, input_latencies
);
2170 for (int i
= 0; i
< fCaptureChannels
; i
++) {
2172 input_range
.min
+= input_latencies
[i
];
2173 input_range
.max
+= input_latencies
[i
];
2175 fGraphManager
->GetPort(fCapturePortList
[i
])->SetLatencyRange(JackCaptureLatency
, &input_range
);
2178 // Get Output latency
2179 size
= sizeof(UInt32
);
2182 err
= AudioDeviceGetProperty(fDeviceID
, 0, false, kAudioDevicePropertyLatency
, &size
, &value1
);
2184 jack_error("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
2186 err
= AudioDeviceGetProperty(fDeviceID
, 0, false, kAudioDevicePropertySafetyOffset
, &size
, &value2
);
2188 jack_error("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
2191 // Get output stream latencies
2192 vector
<int> output_latencies
;
2193 err
= GetStreamLatencies(fDeviceID
, false, output_latencies
);
2195 // Add more latency if "async" mode is used...
2196 output_range
.min
= output_range
.max
= fEngineControl
->fBufferSize
+ ((fEngineControl
->fSyncMode
)
2197 ? 0 : fEngineControl
->fBufferSize
* fIOUsage
) + value1
+ value2
+ fPlaybackLatency
;
2199 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
2201 output_range
.min
+= output_latencies
[i
];
2202 output_range
.max
+= output_latencies
[i
];
2204 fGraphManager
->GetPort(fPlaybackPortList
[i
])->SetLatencyRange(JackPlaybackLatency
, &output_range
);
2207 if (fWithMonitorPorts
) {
2208 monitor_range
.min
= monitor_range
.max
= fEngineControl
->fBufferSize
;
2209 fGraphManager
->GetPort(fMonitorPortList
[i
])->SetLatencyRange(JackCaptureLatency
, &monitor_range
);
2214 int JackCoreAudioDriver::Attach()
2218 jack_port_id_t port_index
;
2221 char channel_name
[64];
2222 char name
[REAL_JACK_PORT_NAME_SIZE
];
2223 char alias
[REAL_JACK_PORT_NAME_SIZE
];
2225 jack_log("JackCoreAudioDriver::Attach : fBufferSize %ld fSampleRate %ld", fEngineControl
->fBufferSize
, fEngineControl
->fSampleRate
);
2227 for (int i
= 0; i
< fCaptureChannels
; i
++) {
2229 err
= AudioDeviceGetPropertyInfo(fDeviceID
, i
+ 1, true, kAudioDevicePropertyChannelName
, &size
, &isWritable
);
2231 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error");
2233 if (err
== noErr
&& size
> 0) {
2234 err
= AudioDeviceGetProperty(fDeviceID
, i
+ 1, true, kAudioDevicePropertyChannelName
, &size
, channel_name
);
2236 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetProperty kAudioDevicePropertyChannelName error");
2238 snprintf(alias
, sizeof(alias
), "%s:%s:out_%s%u", fAliasName
, fCaptureDriverName
, channel_name
, i
+ 1);
2240 snprintf(alias
, sizeof(alias
), "%s:%s:out%u", fAliasName
, fCaptureDriverName
, i
+ 1);
2243 snprintf(name
, sizeof(name
), "%s:capture_%d", fClientControl
.fName
, i
+ 1);
2245 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_AUDIO_TYPE
, CaptureDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
2246 jack_error("Cannot register port for %s", name
);
2250 port
= fGraphManager
->GetPort(port_index
);
2251 port
->SetAlias(alias
);
2252 fCapturePortList
[i
] = port_index
;
2255 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
2257 err
= AudioDeviceGetPropertyInfo(fDeviceID
, i
+ 1, false, kAudioDevicePropertyChannelName
, &size
, &isWritable
);
2259 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error");
2261 if (err
== noErr
&& size
> 0) {
2262 err
= AudioDeviceGetProperty(fDeviceID
, i
+ 1, false, kAudioDevicePropertyChannelName
, &size
, channel_name
);
2264 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetProperty kAudioDevicePropertyChannelName error");
2266 snprintf(alias
, sizeof(alias
), "%s:%s:in_%s%u", fAliasName
, fPlaybackDriverName
, channel_name
, i
+ 1);
2268 snprintf(alias
, sizeof(alias
), "%s:%s:in%u", fAliasName
, fPlaybackDriverName
, i
+ 1);
2271 snprintf(name
, sizeof(name
), "%s:playback_%d", fClientControl
.fName
, i
+ 1);
2273 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_AUDIO_TYPE
, PlaybackDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
2274 jack_error("Cannot register port for %s", name
);
2278 port
= fGraphManager
->GetPort(port_index
);
2279 port
->SetAlias(alias
);
2280 fPlaybackPortList
[i
] = port_index
;
2283 if (fWithMonitorPorts
) {
2284 jack_log("JackCoreAudioDriver::Attach : create monitor port");
2285 snprintf(name
, sizeof(name
), "%s:monitor_%u", fClientControl
.fName
, i
+ 1);
2286 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_AUDIO_TYPE
, MonitorDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
2287 jack_error("Cannot register monitor port for %s", name
);
2290 fMonitorPortList
[i
] = port_index
;
2296 // Setup specific AC3 channels names
2297 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
2298 fAC3Encoder
->GetChannelName("coreaudio", "", alias
, i
);
2299 port
= fGraphManager
->GetPort(fPlaybackPortList
[i
]);
2300 port
->SetAlias(alias
);
2306 // Input buffers do no change : prepare them only once
2307 for (int i
= 0; i
< fCaptureChannels
; i
++) {
2308 fJackInputData
->mBuffers
[i
].mData
= GetInputBuffer(i
);
2314 int JackCoreAudioDriver::Start()
2316 jack_log("JackCoreAudioDriver::Start");
2317 if (JackAudioDriver::Start() == 0) {
2319 // Waiting for Render callback to be called (= driver has started)
2323 OSStatus err
= AudioOutputUnitStart(fAUHAL
);
2326 while (!fState
&& count
++ < WAIT_COUNTER
) {
2328 jack_log("JackCoreAudioDriver::Start : wait count = %d", count
);
2331 if (count
< WAIT_COUNTER
) {
2332 jack_info("CoreAudio driver is running...");
2336 jack_error("CoreAudio driver cannot start...");
2338 JackAudioDriver::Stop();
2343 int JackCoreAudioDriver::Stop()
2345 jack_log("JackCoreAudioDriver::Stop");
2346 int res
= (AudioOutputUnitStop(fAUHAL
) == noErr
) ? 0 : -1;
2347 if (JackAudioDriver::Stop() < 0) {
2353 int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size
)
2355 if (SetupBufferSize(buffer_size
) < 0) {
2359 JackAudioDriver::SetBufferSize(buffer_size
); // Generic change, never fails
2361 // CoreAudio specific
2364 // Input buffers do no change : prepare them only once
2365 for (int i
= 0; i
< fCaptureChannels
; i
++) {
2366 fJackInputData
->mBuffers
[i
].mNumberChannels
= 1;
2367 fJackInputData
->mBuffers
[i
].mDataByteSize
= fEngineControl
->fBufferSize
* sizeof(jack_default_audio_sample_t
);
2368 fJackInputData
->mBuffers
[i
].mData
= GetInputBuffer(i
);
2374 bool JackCoreAudioDriver::TakeHogAux(AudioDeviceID deviceID
, bool isInput
)
2379 UInt32 propSize
= sizeof(hog_pid
);
2380 err
= AudioDeviceGetProperty(deviceID
, 0, isInput
, kAudioDevicePropertyHogMode
, &propSize
, &hog_pid
);
2382 jack_error("Cannot read hog state...");
2386 jack_log("JackCoreAudioDriver::TakeHogAux : deviceID = %d", deviceID
);
2388 if (hog_pid
!= getpid()) {
2390 err
= AudioDeviceSetProperty(deviceID
, 0, 0, isInput
, kAudioDevicePropertyHogMode
, propSize
, &hog_pid
);
2392 jack_error("Can't hog device = %d because it's being hogged by another program or cannot be hogged", deviceID
);
2400 bool JackCoreAudioDriver::TakeHog()
2402 OSStatus err
= noErr
;
2403 AudioObjectID sub_device
[32];
2404 UInt32 outSize
= sizeof(sub_device
);
2405 err
= AudioDeviceGetProperty(fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
2408 jack_log("JackCoreAudioDriver::TakeHog : device does not have subdevices");
2409 return TakeHogAux(fDeviceID
, true);
2411 int num_devices
= outSize
/ sizeof(AudioObjectID
);
2412 jack_log("JackCoreAudioDriver::TakeHog : device does has %d subdevices", num_devices
);
2413 for (int i
= 0; i
< num_devices
; i
++) {
2414 if (!TakeHogAux(sub_device
[i
], true)) {
2422 bool JackCoreAudioDriver::IsAggregateDevice(AudioDeviceID device
)
2424 UInt32 deviceType
, outSize
= sizeof(UInt32
);
2425 OSStatus err
= AudioDeviceGetProperty(device
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyTransportType
, &outSize
, &deviceType
);
2428 jack_log("JackCoreAudioDriver::IsAggregateDevice kAudioDevicePropertyTransportType error");
2431 return (deviceType
== kAudioDeviceTransportTypeAggregate
);
2436 } // end of namespace
2444 SERVER_EXPORT jack_driver_desc_t
* driver_get_descriptor()
2446 jack_driver_desc_t
* desc
;
2447 jack_driver_desc_filler_t filler
;
2448 jack_driver_param_value_t value
;
2450 desc
= jack_driver_descriptor_construct("coreaudio", JackDriverMaster
, "Apple CoreAudio API based audio backend", &filler
);
2453 jack_driver_descriptor_add_parameter(desc
, &filler
, "channels", 'c', JackDriverParamInt
, &value
, NULL
, "Maximum number of channels", "Maximum number of channels. If -1, max possible number of channels will be used");
2454 jack_driver_descriptor_add_parameter(desc
, &filler
, "in-channels", 'i', JackDriverParamInt
, &value
, NULL
, "Maximum number of input channels", "Maximum number of input channels. If -1, max possible number of input channels will be used");
2455 jack_driver_descriptor_add_parameter(desc
, &filler
, "out-channels", 'o', JackDriverParamInt
, &value
, NULL
, "Maximum number of output channels", "Maximum number of output channels. If -1, max possible number of output channels will be used");
2458 jack_driver_descriptor_add_parameter(desc
, &filler
, "input-list", 'n', JackDriverParamString
, &value
, NULL
, "Input channel list", "List of input channel number to be opened");
2459 jack_driver_descriptor_add_parameter(desc
, &filler
, "output-list", 'N', JackDriverParamString
, &value
, NULL
, "Output channel list", "List of output channel number to be opened");
2462 jack_driver_descriptor_add_parameter(desc
, &filler
, "capture", 'C', JackDriverParamString
, &value
, NULL
, "Input CoreAudio device name", NULL
);
2463 jack_driver_descriptor_add_parameter(desc
, &filler
, "playback", 'P', JackDriverParamString
, &value
, NULL
, "Output CoreAudio device name", NULL
);
2466 jack_driver_descriptor_add_parameter(desc
, &filler
, "monitor", 'm', JackDriverParamBool
, &value
, NULL
, "Provide monitor ports for the output", NULL
);
2470 jack_driver_descriptor_add_parameter(desc
, &filler
, "AC3-encoding", 'a', JackDriverParamBool
, &value
, NULL
, "AC3 multi-channels encoding", NULL
);
2473 jack_driver_descriptor_add_parameter(desc
, &filler
, "AC3-bitrate", 'b', JackDriverParamUInt
, &value
, NULL
, "AC3 bitrate", NULL
);
2476 jack_driver_descriptor_add_parameter(desc
, &filler
, "AC3-LFE", 'f', JackDriverParamBool
, &value
, NULL
, "AC3 LFE channel", NULL
);
2479 jack_driver_descriptor_add_parameter(desc
, &filler
, "duplex", 'D', JackDriverParamBool
, &value
, NULL
, "Provide both capture and playback ports", NULL
);
2482 jack_driver_descriptor_add_parameter(desc
, &filler
, "rate", 'r', JackDriverParamUInt
, &value
, NULL
, "Sample rate", NULL
);
2485 jack_driver_descriptor_add_parameter(desc
, &filler
, "period", 'p', JackDriverParamUInt
, &value
, NULL
, "Frames per period", NULL
);
2488 jack_driver_descriptor_add_parameter(desc
, &filler
, "device", 'd', JackDriverParamString
, &value
, NULL
, "CoreAudio device name", NULL
);
2491 jack_driver_descriptor_add_parameter(desc
, &filler
, "input-latency", 'I', JackDriverParamUInt
, &value
, NULL
, "Extra input latency (frames)", NULL
);
2492 jack_driver_descriptor_add_parameter(desc
, &filler
, "output-latency", 'O', JackDriverParamUInt
, &value
, NULL
, "Extra output latency (frames)", NULL
);
2495 jack_driver_descriptor_add_parameter(desc
, &filler
, "list-devices", 'l', JackDriverParamBool
, &value
, NULL
, "Display available CoreAudio devices", NULL
);
2498 jack_driver_descriptor_add_parameter(desc
, &filler
, "hog", 'H', JackDriverParamBool
, &value
, NULL
, "Take exclusive access of the audio device", NULL
);
2501 jack_driver_descriptor_add_parameter(desc
, &filler
, "async-latency", 'L', JackDriverParamUInt
, &value
, NULL
, "Extra output latency in asynchronous mode (percent)", NULL
);
2504 jack_driver_descriptor_add_parameter(desc
, &filler
, "grain", 'G', JackDriverParamUInt
, &value
, NULL
, "Computation grain in RT thread (percent)", NULL
);
2507 jack_driver_descriptor_add_parameter(desc
, &filler
, "clock-drift", 's', JackDriverParamBool
, &value
, NULL
, "Clock drift compensation", "Whether to compensate clock drift in dynamically created aggregate device");
2512 SERVER_EXPORT
Jack::JackDriverClientInterface
* driver_initialize(Jack::JackLockedEngine
* engine
, Jack::JackSynchro
* table
, const JSList
* params
)
2514 jack_nframes_t srate
= 44100;
2515 jack_nframes_t frames_per_interrupt
= 256;
2516 bool capture
= false;
2517 bool playback
= false;
2518 int chan_in
= -1; // Default: if not explicitely set, then max possible will be used...
2519 int chan_out
= -1; // Default: if not explicitely set, then max possible will be used...
2520 const char* chan_in_list
= "";
2521 const char* chan_out_list
= "";
2522 bool monitor
= false;
2523 const char* capture_driver_uid
= "";
2524 const char* playback_driver_uid
= "";
2526 const jack_driver_param_t
*param
;
2527 jack_nframes_t systemic_input_latency
= 0;
2528 jack_nframes_t systemic_output_latency
= 0;
2529 int async_output_latency
= 100;
2530 int computation_grain
= -1;
2531 bool hogged
= false;
2532 bool clock_drift
= false;
2533 bool ac3_encoding
= false;
2534 int ac3_bitrate
= 448;
2535 bool ac3_lfe
= false;
2537 for (node
= params
; node
; node
= jack_slist_next(node
)) {
2538 param
= (const jack_driver_param_t
*) node
->data
;
2540 switch (param
->character
) {
2543 capture_driver_uid
= param
->value
.str
;
2544 playback_driver_uid
= param
->value
.str
;
2553 chan_in
= chan_out
= param
->value
.i
;
2557 chan_in
= param
->value
.i
;
2561 chan_out
= param
->value
.i
;
2565 chan_in_list
= param
->value
.str
;
2569 chan_out_list
= param
->value
.str
;
2574 if (strcmp(param
->value
.str
, "none") != 0) {
2575 capture_driver_uid
= param
->value
.str
;
2581 if (strcmp(param
->value
.str
, "none") != 0) {
2582 playback_driver_uid
= param
->value
.str
;
2587 monitor
= param
->value
.i
;
2592 ac3_encoding
= param
->value
.i
;
2596 ac3_bitrate
= param
->value
.i
;
2600 ac3_lfe
= param
->value
.i
;
2605 srate
= param
->value
.ui
;
2609 frames_per_interrupt
= (unsigned int)param
->value
.ui
;
2613 systemic_input_latency
= param
->value
.ui
;
2617 systemic_output_latency
= param
->value
.ui
;
2621 Jack::DisplayDeviceNames();
2622 // Stops the server in this case
2630 async_output_latency
= param
->value
.ui
;
2634 computation_grain
= param
->value
.ui
;
2643 /* duplex is the default */
2644 if (!capture
&& !playback
) {
2649 if (strcmp(chan_in_list
, "") != 0 && chan_in
>= 0) {
2650 printf("Input channel list and in channels are both specified, input channel list will take over...\n");
2653 if (strcmp(chan_out_list
, "") != 0 && chan_out
>= 0) {
2654 printf("Output channel list and out channels are both specified, output channel list will take over...\n");
2657 Jack::JackCoreAudioDriver
* driver
= new Jack::JackCoreAudioDriver("system", "coreaudio", engine
, table
);
2658 if (driver
->Open(frames_per_interrupt
,
2661 chan_out
, chan_in_list
,
2662 chan_out_list
, monitor
,
2664 playback_driver_uid
,
2665 systemic_input_latency
,
2666 systemic_output_latency
,
2667 async_output_latency
,
2669 hogged
, clock_drift
,
2670 ac3_encoding
, ac3_bitrate
, ac3_lfe
) == 0) {