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
, int max_chan
)
263 stringstream
ss(list
);
267 while (ss
>> token
) {
271 if (chan
< 0 || chan
>= max_chan
) {
272 jack_error("Ignore incorrect channel mapping value = %d", chan
);
274 result
.push_back(chan
);
279 OSStatus
JackCoreAudioDriver::Render(void* inRefCon
,
280 AudioUnitRenderActionFlags
* ioActionFlags
,
281 const AudioTimeStamp
* inTimeStamp
,
283 UInt32 inNumberFrames
,
284 AudioBufferList
* ioData
)
286 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inRefCon
;
287 driver
->fActionFags
= ioActionFlags
;
288 driver
->fCurrentTime
= inTimeStamp
;
289 driver
->fDriverOutputData
= ioData
;
291 // Setup threaded based log function et get RT thread parameters once...
292 if (set_threaded_log_function()) {
294 jack_log("JackCoreAudioDriver::Render : set_threaded_log_function");
295 JackMachThread::GetParams(pthread_self(), &driver
->fEngineControl
->fPeriod
, &driver
->fEngineControl
->fComputation
, &driver
->fEngineControl
->fConstraint
);
297 if (driver
->fComputationGrain
> 0) {
298 jack_log("JackCoreAudioDriver::Render : RT thread computation setup to %d percent of period", int(driver
->fComputationGrain
* 100));
299 driver
->fEngineControl
->fComputation
= driver
->fEngineControl
->fPeriod
* driver
->fComputationGrain
;
303 // Signal waiting start function...
304 driver
->fState
= true;
306 driver
->CycleTakeBeginTime();
308 if (driver
->Process() < 0) {
309 jack_error("Process error, stopping driver");
310 driver
->NotifyFailure(JackBackendError
, "Process error, stopping driver"); // Message length limited to JACK_MESSAGE_SIZE
312 kill(JackTools::GetPID(), SIGINT
);
313 return kAudioHardwareUnsupportedOperationError
;
319 int JackCoreAudioDriver::Read()
321 if (fCaptureChannels
> 0) { // Calling AudioUnitRender with no input returns a '????' error (callback setting issue ??), so hack to avoid it here...
322 return (AudioUnitRender(fAUHAL
, fActionFags
, fCurrentTime
, 1, fEngineControl
->fBufferSize
, fJackInputData
) == noErr
) ? 0 : -1;
328 int JackCoreAudioDriver::Write()
332 // AC3 encoding and SPDIF write
333 jack_default_audio_sample_t
* AC3_inputs
[MAX_AC3_CHANNELS
];
334 jack_default_audio_sample_t
* AC3_outputs
[2];
335 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
336 AC3_inputs
[i
] = GetOutputBuffer(i
);
337 // If not connected, clear the buffer
338 if (fGraphManager
->GetConnectionsNum(fPlaybackPortList
[i
]) == 0) {
339 memset(AC3_inputs
[i
], 0, sizeof(jack_default_audio_sample_t
) * fEngineControl
->fBufferSize
);
342 AC3_outputs
[0] = (jack_default_audio_sample_t
*)fDriverOutputData
->mBuffers
[0].mData
;
343 AC3_outputs
[1] = (jack_default_audio_sample_t
*)fDriverOutputData
->mBuffers
[1].mData
;
344 fAC3Encoder
->Process(AC3_inputs
, AC3_outputs
, fEngineControl
->fBufferSize
);
349 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
350 if (fGraphManager
->GetConnectionsNum(fPlaybackPortList
[i
]) > 0) {
351 jack_default_audio_sample_t
* buffer
= GetOutputBuffer(i
);
352 int size
= sizeof(jack_default_audio_sample_t
) * fEngineControl
->fBufferSize
;
353 memcpy((jack_default_audio_sample_t
*)fDriverOutputData
->mBuffers
[i
].mData
, buffer
, size
);
355 if (fWithMonitorPorts
&& fGraphManager
->GetConnectionsNum(fMonitorPortList
[i
]) > 0) {
356 memcpy(GetMonitorBuffer(i
), buffer
, size
);
359 memset((jack_default_audio_sample_t
*)fDriverOutputData
->mBuffers
[i
].mData
, 0, sizeof(jack_default_audio_sample_t
) * fEngineControl
->fBufferSize
);
366 OSStatus
JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice
,
369 AudioDevicePropertyID inPropertyID
,
372 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inClientData
;
374 switch (inPropertyID
) {
376 case kAudioDevicePropertyNominalSampleRate
: {
377 jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
378 // Check new sample rate
379 Float64 tmp_sample_rate
;
380 UInt32 outSize
= sizeof(Float64
);
381 OSStatus err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outSize
, &tmp_sample_rate
);
383 jack_error("Cannot get current sample rate");
386 jack_log("JackCoreAudioDriver::SRNotificationCallback : checked sample rate = %f", tmp_sample_rate
);
388 driver
->fState
= true;
396 OSStatus
JackCoreAudioDriver::BSNotificationCallback(AudioDeviceID inDevice
,
399 AudioDevicePropertyID inPropertyID
,
402 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inClientData
;
404 switch (inPropertyID
) {
406 case kAudioDevicePropertyBufferFrameSize
: {
407 jack_log("JackCoreAudioDriver::BSNotificationCallback kAudioDevicePropertyBufferFrameSize");
408 // Check new buffer size
409 UInt32 tmp_buffer_size
;
410 UInt32 outSize
= sizeof(UInt32
);
411 OSStatus err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyBufferFrameSize
, &outSize
, &tmp_buffer_size
);
413 jack_error("Cannot get current buffer size");
416 jack_log("JackCoreAudioDriver::BSNotificationCallback : checked buffer size = %d", tmp_buffer_size
);
418 driver
->fState
= true;
426 // A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
427 OSStatus
JackCoreAudioDriver::AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID
, void* inClientData
)
429 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inClientData
;
431 switch (inPropertyID
) {
433 case kAudioHardwarePropertyDevices
: {
434 jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices");
435 DisplayDeviceNames();
436 AudioDeviceID captureID
, playbackID
;
437 if (CheckAvailableDevice(driver
->fDeviceID
) ||
438 (CheckAvailableDeviceName(driver
->fCaptureUID
, &captureID
)
439 && CheckAvailableDeviceName(driver
->fPlaybackUID
, &playbackID
))) {
449 OSStatus
JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice
,
452 AudioDevicePropertyID inPropertyID
,
455 JackCoreAudioDriver
* driver
= (JackCoreAudioDriver
*)inClientData
;
457 switch (inPropertyID
) {
459 case kAudioDevicePropertyDeviceIsRunning
: {
460 UInt32 isrunning
= 0;
461 UInt32 outsize
= sizeof(UInt32
);
462 if (AudioDeviceGetProperty(driver
->fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyDeviceIsRunning
, &outsize
, &isrunning
) == noErr
) {
463 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsRunning = %d", isrunning
);
468 case kAudioDevicePropertyDeviceIsAlive
: {
470 UInt32 outsize
= sizeof(UInt32
);
471 if (AudioDeviceGetProperty(driver
->fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyDeviceIsAlive
, &outsize
, &isalive
) == noErr
) {
472 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsAlive = %d", isalive
);
477 case kAudioDevicePropertyDeviceHasChanged
: {
478 UInt32 hachanged
= 0;
479 UInt32 outsize
= sizeof(UInt32
);
480 if (AudioDeviceGetProperty(driver
->fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyDeviceHasChanged
, &outsize
, &hachanged
) == noErr
) {
481 jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceHasChanged = %d", hachanged
);
486 case kAudioDeviceProcessorOverload
: {
487 jack_error("DeviceNotificationCallback kAudioDeviceProcessorOverload");
488 jack_time_t cur_time
= GetMicroSeconds();
489 driver
->NotifyXRun(cur_time
, float(cur_time
- driver
->fBeginDateUst
)); // Better this value than nothing...
493 case kAudioDevicePropertyStreamConfiguration
: {
494 jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration : server will quit...");
495 driver
->NotifyFailure(JackBackendError
, "Another application has changed the device configuration"); // Message length limited to JACK_MESSAGE_SIZE
496 driver
->CloseAUHAL();
497 kill(JackTools::GetPID(), SIGINT
);
498 return kAudioHardwareUnsupportedOperationError
;
501 case kAudioDevicePropertyNominalSampleRate
: {
502 Float64 sample_rate
= 0;
503 UInt32 outsize
= sizeof(Float64
);
504 OSStatus err
= AudioDeviceGetProperty(driver
->fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outsize
, &sample_rate
);
506 return kAudioHardwareUnsupportedOperationError
;
509 char device_name
[256];
510 const char* digidesign_name
= "Digidesign";
511 driver
->GetDeviceNameFromID(driver
->fDeviceID
, device_name
);
513 if (sample_rate
!= driver
->fEngineControl
->fSampleRate
) {
515 // Digidesign hardware, so "special" code : change the SR again here
516 if (strncmp(device_name
, digidesign_name
, 10) == 0) {
518 jack_log("JackCoreAudioDriver::DeviceNotificationCallback Digidesign HW = %s", device_name
);
520 // Set sample rate again...
521 sample_rate
= driver
->fEngineControl
->fSampleRate
;
522 err
= AudioDeviceSetProperty(driver
->fDeviceID
, NULL
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, outsize
, &sample_rate
);
524 jack_error("Cannot set sample rate = %f", sample_rate
);
527 jack_log("JackCoreAudioDriver::DeviceNotificationCallback : set sample rate = %f", sample_rate
);
530 // Check new sample rate again...
531 outsize
= sizeof(Float64
);
532 err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outsize
, &sample_rate
);
534 jack_error("Cannot get current sample rate");
537 jack_log("JackCoreAudioDriver::DeviceNotificationCallback : checked sample rate = %f", sample_rate
);
542 driver
->NotifyFailure(JackBackendError
, "Another application has changed the sample rate"); // Message length limited to JACK_MESSAGE_SIZE
543 driver
->CloseAUHAL();
544 kill(JackTools::GetPID(), SIGINT
);
545 return kAudioHardwareUnsupportedOperationError
;
554 OSStatus
JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID
, AudioDeviceID
* id
)
556 UInt32 size
= sizeof(AudioValueTranslation
);
557 CFStringRef inIUD
= CFStringCreateWithCString(NULL
, UID
, CFStringGetSystemEncoding());
558 AudioValueTranslation value
= { &inIUD
, sizeof(CFStringRef
), id
, sizeof(AudioDeviceID
) };
561 return kAudioHardwareUnspecifiedError
;
563 OSStatus res
= AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID
, &size
, &value
);
565 jack_log("JackCoreAudioDriver::GetDeviceIDFromUID %s %ld", UID
, *id
);
566 return (*id
== kAudioDeviceUnknown
) ? kAudioHardwareBadDeviceError
: res
;
570 OSStatus
JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID
* id
)
573 UInt32 theSize
= sizeof(UInt32
);
574 AudioDeviceID inDefault
;
575 AudioDeviceID outDefault
;
577 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
, &theSize
, &inDefault
)) != noErr
) {
581 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
, &theSize
, &outDefault
)) != noErr
) {
585 jack_log("JackCoreAudioDriver::GetDefaultDevice : input = %ld output = %ld", inDefault
, outDefault
);
587 // Get the device only if default input and output are the same
588 if (inDefault
!= outDefault
) {
589 jack_error("Default input and output devices are not the same !!");
590 return kAudioHardwareBadDeviceError
;
591 } else if (inDefault
== 0) {
592 jack_error("Default input and output devices are null !!");
593 return kAudioHardwareBadDeviceError
;
600 OSStatus
JackCoreAudioDriver::GetDefaultInputDevice(AudioDeviceID
* id
)
603 UInt32 theSize
= sizeof(UInt32
);
604 AudioDeviceID inDefault
;
606 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
, &theSize
, &inDefault
)) != noErr
) {
610 if (inDefault
== 0) {
611 jack_error("Error default input device is 0, please select a correct one !!");
614 jack_log("JackCoreAudioDriver::GetDefaultInputDevice : input = %ld ", inDefault
);
619 OSStatus
JackCoreAudioDriver::GetDefaultOutputDevice(AudioDeviceID
* id
)
622 UInt32 theSize
= sizeof(UInt32
);
623 AudioDeviceID outDefault
;
625 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
, &theSize
, &outDefault
)) != noErr
) {
629 if (outDefault
== 0) {
630 jack_error("Error default output device is 0, please select a correct one !!");
633 jack_log("JackCoreAudioDriver::GetDefaultOutputDevice : output = %ld", outDefault
);
638 OSStatus
JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id
, char* name
)
641 return AudioDeviceGetProperty(id
, 0, false, kAudioDevicePropertyDeviceName
, &size
, name
);
644 OSStatus
JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device
, int& channelCount
, bool isInput
)
646 OSStatus err
= noErr
;
651 err
= AudioDeviceGetPropertyInfo(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize
, &outWritable
);
653 int stream_count
= outSize
/ sizeof(AudioBufferList
);
654 jack_log("JackCoreAudioDriver::GetTotalChannels stream_count = %d", stream_count
);
655 AudioBufferList bufferList
[stream_count
];
656 err
= AudioDeviceGetProperty(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize
, bufferList
);
658 for (uint i
= 0; i
< bufferList
->mNumberBuffers
; i
++) {
659 channelCount
+= bufferList
->mBuffers
[i
].mNumberChannels
;
660 jack_log("JackCoreAudioDriver::GetTotalChannels stream = %d channels = %d", i
, bufferList
->mBuffers
[i
].mNumberChannels
);
667 OSStatus
JackCoreAudioDriver::GetStreamLatencies(AudioDeviceID device
, bool isInput
, vector
<int>& latencies
)
669 OSStatus err
= noErr
;
670 UInt32 outSize1
, outSize2
, outSize3
;
673 err
= AudioDeviceGetPropertyInfo(device
, 0, isInput
, kAudioDevicePropertyStreams
, &outSize1
, &outWritable
);
675 int stream_count
= outSize1
/ sizeof(UInt32
);
676 AudioStreamID streamIDs
[stream_count
];
677 AudioBufferList bufferList
[stream_count
];
678 UInt32 streamLatency
;
679 outSize2
= sizeof(UInt32
);
681 err
= AudioDeviceGetProperty(device
, 0, isInput
, kAudioDevicePropertyStreams
, &outSize1
, streamIDs
);
683 jack_error("GetStreamLatencies kAudioDevicePropertyStreams err = %d", err
);
687 err
= AudioDeviceGetPropertyInfo(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize3
, &outWritable
);
689 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err
);
693 for (int i
= 0; i
< stream_count
; i
++) {
694 err
= AudioStreamGetProperty(streamIDs
[i
], 0, kAudioStreamPropertyLatency
, &outSize2
, &streamLatency
);
696 jack_error("GetStreamLatencies kAudioStreamPropertyLatency err = %d", err
);
699 err
= AudioDeviceGetProperty(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize3
, bufferList
);
701 jack_error("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = %d", err
);
704 // Push 'channel' time the stream latency
705 for (uint k
= 0; k
< bufferList
->mBuffers
[i
].mNumberChannels
; k
++) {
706 latencies
.push_back(streamLatency
);
713 bool JackCoreAudioDriver::IsDigitalDevice(AudioDeviceID device
)
715 OSStatus err
= noErr
;
717 bool is_digital
= false;
719 /* Get a list of all the streams on this device */
720 AudioObjectPropertyAddress streamsAddress
= { kAudioDevicePropertyStreams
, kAudioDevicePropertyScopeOutput
, kAudioObjectPropertyElementMaster
};
721 err
= AudioObjectGetPropertyDataSize(device
, &streamsAddress
, 0, NULL
, &outSize1
);
723 jack_error("IsDigitalDevice kAudioDevicePropertyStreams err = %d", err
);
727 int stream_count
= outSize1
/ sizeof(AudioStreamID
);
728 AudioStreamID streamIDs
[stream_count
];
730 err
= AudioObjectGetPropertyData(device
, &streamsAddress
, 0, NULL
, &outSize1
, streamIDs
);
733 jack_error("IsDigitalDevice kAudioDevicePropertyStreams list err = %d", err
);
737 AudioObjectPropertyAddress physicalFormatsAddress
= { kAudioStreamPropertyAvailablePhysicalFormats
, kAudioObjectPropertyScopeGlobal
, 0 };
739 for (int i
= 0; i
< stream_count
; i
++) {
741 /* Find a stream with a cac3 stream */
744 /* Retrieve all the stream formats supported by each output stream */
745 err
= AudioObjectGetPropertyDataSize(streamIDs
[i
], &physicalFormatsAddress
, 0, NULL
, &outSize1
);
748 jack_error("IsDigitalDevice kAudioStreamPropertyAvailablePhysicalFormats err = %d", err
);
752 format_num
= outSize1
/ sizeof(AudioStreamRangedDescription
);
753 AudioStreamRangedDescription format_list
[format_num
];
755 err
= AudioObjectGetPropertyData(streamIDs
[i
], &physicalFormatsAddress
, 0, NULL
, &outSize1
, format_list
);
758 jack_error("IsDigitalDevice could not get the list of streamformats err = %d", err
);
762 /* Check if one of the supported formats is a digital format */
763 for (int j
= 0; j
< format_num
; j
++) {
765 PrintStreamDesc(&format_list
[j
].mFormat
);
767 if (format_list
[j
].mFormat
.mFormatID
== 'IAC3' ||
768 format_list
[j
].mFormat
.mFormatID
== 'iac3' ||
769 format_list
[j
].mFormat
.mFormatID
== kAudioFormat60958AC3
||
770 format_list
[j
].mFormat
.mFormatID
== kAudioFormatAC3
)
781 JackCoreAudioDriver::JackCoreAudioDriver(const char* name
, const char* alias
, JackLockedEngine
* engine
, JackSynchro
* table
)
782 : JackAudioDriver(name
, alias
, engine
, table
),
784 fJackInputData(NULL
),
785 fDriverOutputData(NULL
),
790 fComputationGrain(-1.f
),
791 fClockDriftCompensate(false),
792 fDigitalPlayback(false)
795 JackCoreAudioDriver::~JackCoreAudioDriver()
800 OSStatus
JackCoreAudioDriver::DestroyAggregateDevice()
802 OSStatus osErr
= noErr
;
803 AudioObjectPropertyAddress pluginAOPA
;
804 pluginAOPA
.mSelector
= kAudioPlugInDestroyAggregateDevice
;
805 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
806 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
811 osErr
= AudioObjectGetPropertyDataSize(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
);
812 if (osErr
!= noErr
) {
813 jack_error("DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
818 osErr
= AudioObjectGetPropertyData(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
, &fDeviceID
);
819 if (osErr
!= noErr
) {
820 jack_error("DestroyAggregateDevice : AudioObjectGetPropertyData error");
830 OSStatus
JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceID
, AudioDeviceID playbackDeviceID
, jack_nframes_t samplerate
, AudioDeviceID
* outAggregateDevice
)
832 OSStatus err
= noErr
;
833 AudioObjectID sub_device
[32];
834 UInt32 outSize
= sizeof(sub_device
);
836 err
= AudioDeviceGetProperty(captureDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
837 vector
<AudioDeviceID
> captureDeviceIDArray
;
840 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input device does not have subdevices");
841 captureDeviceIDArray
.push_back(captureDeviceID
);
843 int num_devices
= outSize
/ sizeof(AudioObjectID
);
844 jack_log("JackCoreAudioDriver::CreateAggregateDevice :Input device has %d subdevices", num_devices
);
845 for (int i
= 0; i
< num_devices
; i
++) {
846 captureDeviceIDArray
.push_back(sub_device
[i
]);
850 err
= AudioDeviceGetProperty(playbackDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
851 vector
<AudioDeviceID
> playbackDeviceIDArray
;
854 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device does not have subdevices");
855 playbackDeviceIDArray
.push_back(playbackDeviceID
);
857 int num_devices
= outSize
/ sizeof(AudioObjectID
);
858 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output device has %d subdevices", num_devices
);
859 for (int i
= 0; i
< num_devices
; i
++) {
860 playbackDeviceIDArray
.push_back(sub_device
[i
]);
864 return CreateAggregateDeviceAux(captureDeviceIDArray
, playbackDeviceIDArray
, samplerate
, outAggregateDevice
);
867 OSStatus
JackCoreAudioDriver::CreateAggregateDeviceAux(vector
<AudioDeviceID
> captureDeviceID
, vector
<AudioDeviceID
> playbackDeviceID
, jack_nframes_t samplerate
, AudioDeviceID
* outAggregateDevice
)
869 OSStatus osErr
= noErr
;
873 // Prepare sub-devices for clock drift compensation
874 // Workaround for bug in the HAL : until 10.6.2
875 AudioObjectPropertyAddress theAddressOwned
= { kAudioObjectPropertyOwnedObjects
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
876 AudioObjectPropertyAddress theAddressDrift
= { kAudioSubDevicePropertyDriftCompensation
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
877 UInt32 theQualifierDataSize
= sizeof(AudioObjectID
);
878 AudioClassID inClass
= kAudioSubDeviceClassID
;
879 void* theQualifierData
= &inClass
;
880 UInt32 subDevicesNum
= 0;
882 //---------------------------------------------------------------------------
883 // Setup SR of both devices otherwise creating AD may fail...
884 //---------------------------------------------------------------------------
885 UInt32 keptclockdomain
= 0;
886 UInt32 clockdomain
= 0;
887 outSize
= sizeof(UInt32
);
888 bool need_clock_drift_compensation
= false;
890 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
891 if (SetupSampleRateAux(captureDeviceID
[i
], samplerate
) < 0) {
892 jack_error("CreateAggregateDevice : cannot set SR of input device");
894 // Check clock domain
895 osErr
= AudioDeviceGetProperty(captureDeviceID
[i
], 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyClockDomain
, &outSize
, &clockdomain
);
897 jack_error("CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
900 keptclockdomain
= (keptclockdomain
== 0) ? clockdomain
: keptclockdomain
;
901 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain
);
902 if (clockdomain
!= 0 && clockdomain
!= keptclockdomain
) {
903 jack_error("CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
904 need_clock_drift_compensation
= true;
910 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
911 if (SetupSampleRateAux(playbackDeviceID
[i
], samplerate
) < 0) {
912 jack_error("CreateAggregateDevice : cannot set SR of output device");
914 // Check clock domain
915 osErr
= AudioDeviceGetProperty(playbackDeviceID
[i
], 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyClockDomain
, &outSize
, &clockdomain
);
917 jack_error("CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
920 keptclockdomain
= (keptclockdomain
== 0) ? clockdomain
: keptclockdomain
;
921 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain
);
922 if (clockdomain
!= 0 && clockdomain
!= keptclockdomain
) {
923 jack_error("CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
924 need_clock_drift_compensation
= true;
930 // If no valid clock domain was found, then assume we have to compensate...
931 if (keptclockdomain
== 0) {
932 need_clock_drift_compensation
= true;
935 //---------------------------------------------------------------------------
936 // Start to create a new aggregate by getting the base audio hardware plugin
937 //---------------------------------------------------------------------------
939 char device_name
[256];
940 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
941 GetDeviceNameFromID(captureDeviceID
[i
], device_name
);
942 jack_info("Separated input = '%s' ", device_name
);
945 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
946 GetDeviceNameFromID(playbackDeviceID
[i
], device_name
);
947 jack_info("Separated output = '%s' ", device_name
);
950 osErr
= AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID
, &outSize
, &outWritable
);
951 if (osErr
!= noErr
) {
952 jack_error("CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
957 AudioValueTranslation pluginAVT
;
959 CFStringRef inBundleRef
= CFSTR("com.apple.audio.CoreAudio");
961 pluginAVT
.mInputData
= &inBundleRef
;
962 pluginAVT
.mInputDataSize
= sizeof(inBundleRef
);
963 pluginAVT
.mOutputData
= &fPluginID
;
964 pluginAVT
.mOutputDataSize
= sizeof(fPluginID
);
966 osErr
= AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID
, &outSize
, &pluginAVT
);
967 if (osErr
!= noErr
) {
968 jack_error("CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
973 //-------------------------------------------------
974 // Create a CFDictionary for our aggregate device
975 //-------------------------------------------------
977 CFMutableDictionaryRef aggDeviceDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
979 CFStringRef AggregateDeviceNameRef
= CFSTR("JackDuplex");
980 CFStringRef AggregateDeviceUIDRef
= CFSTR("com.grame.JackDuplex");
982 // add the name of the device to the dictionary
983 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceNameKey
), AggregateDeviceNameRef
);
985 // add our choice of UID for the aggregate device to the dictionary
986 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceUIDKey
), AggregateDeviceUIDRef
);
988 // add a "private aggregate key" to the dictionary
990 CFNumberRef AggregateDeviceNumberRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &value
);
993 Gestalt(gestaltSystemVersion
, &system
);
995 jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system
, 0x00001054);
997 // Starting with 10.5.4 systems, the AD can be internal... (better)
998 if (system
< 0x00001054) {
999 jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device....");
1001 jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device....");
1002 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceIsPrivateKey
), AggregateDeviceNumberRef
);
1005 // Prepare sub-devices for clock drift compensation
1006 CFMutableArrayRef subDevicesArrayClock
= NULL
;
1009 if (fClockDriftCompensate) {
1010 if (need_clock_drift_compensation) {
1011 jack_info("Clock drift compensation activated...");
1012 subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1014 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
1015 CFStringRef UID = GetDeviceName(captureDeviceID[i]);
1017 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1018 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
1019 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
1021 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
1025 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
1026 CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
1028 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1029 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
1030 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
1032 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
1036 // add sub-device clock array for the aggregate device to the dictionary
1037 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
1039 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
1044 //-------------------------------------------------
1045 // Create a CFMutableArray for our sub-device list
1046 //-------------------------------------------------
1048 // we need to append the UID for each device to a CFMutableArray, so create one here
1049 CFMutableArrayRef subDevicesArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1051 vector
<CFStringRef
> captureDeviceUID
;
1052 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
1053 CFStringRef ref
= GetDeviceName(captureDeviceID
[i
]);
1057 captureDeviceUID
.push_back(ref
);
1058 // input sub-devices in this example, so append the sub-device's UID to the CFArray
1059 CFArrayAppendValue(subDevicesArray
, ref
);
1062 vector
<CFStringRef
> playbackDeviceUID
;
1063 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
1064 CFStringRef ref
= GetDeviceName(playbackDeviceID
[i
]);
1068 playbackDeviceUID
.push_back(ref
);
1069 // output sub-devices in this example, so append the sub-device's UID to the CFArray
1070 CFArrayAppendValue(subDevicesArray
, ref
);
1073 //-----------------------------------------------------------------------
1074 // Feed the dictionary to the plugin, to create a blank aggregate device
1075 //-----------------------------------------------------------------------
1077 AudioObjectPropertyAddress pluginAOPA
;
1078 pluginAOPA
.mSelector
= kAudioPlugInCreateAggregateDevice
;
1079 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1080 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1083 osErr
= AudioObjectGetPropertyDataSize(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
);
1084 if (osErr
!= noErr
) {
1085 jack_error("CreateAggregateDevice : AudioObjectGetPropertyDataSize error");
1090 osErr
= AudioObjectGetPropertyData(fPluginID
, &pluginAOPA
, sizeof(aggDeviceDict
), &aggDeviceDict
, &outDataSize
, outAggregateDevice
);
1091 if (osErr
!= noErr
) {
1092 jack_error("CreateAggregateDevice : AudioObjectGetPropertyData error");
1097 // pause for a bit to make sure that everything completed correctly
1098 // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
1099 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1101 //-------------------------
1102 // Set the sub-device list
1103 //-------------------------
1105 pluginAOPA
.mSelector
= kAudioAggregateDevicePropertyFullSubDeviceList
;
1106 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1107 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1108 outDataSize
= sizeof(CFMutableArrayRef
);
1109 osErr
= AudioObjectSetPropertyData(*outAggregateDevice
, &pluginAOPA
, 0, NULL
, outDataSize
, &subDevicesArray
);
1110 if (osErr
!= noErr
) {
1111 jack_error("CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error");
1116 // pause again to give the changes time to take effect
1117 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1119 //-----------------------
1120 // Set the master device
1121 //-----------------------
1123 // set the master device manually (this is the device which will act as the master clock for the aggregate device)
1124 // pass in the UID of the device you want to use
1125 pluginAOPA
.mSelector
= kAudioAggregateDevicePropertyMasterSubDevice
;
1126 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1127 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1128 outDataSize
= sizeof(CFStringRef
);
1129 osErr
= AudioObjectSetPropertyData(*outAggregateDevice
, &pluginAOPA
, 0, NULL
, outDataSize
, &captureDeviceUID
[0]); // First apture is master...
1130 if (osErr
!= noErr
) {
1131 jack_error("CreateAggregateDevice : AudioObjectSetPropertyData for master device error");
1136 // pause again to give the changes time to take effect
1137 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1139 // Prepare sub-devices for clock drift compensation
1140 // Workaround for bug in the HAL : until 10.6.2
1142 if (fClockDriftCompensate
) {
1143 if (need_clock_drift_compensation
) {
1144 jack_info("Clock drift compensation activated...");
1146 // Get the property data size
1147 osErr
= AudioObjectGetPropertyDataSize(*outAggregateDevice
, &theAddressOwned
, theQualifierDataSize
, theQualifierData
, &outSize
);
1148 if (osErr
!= noErr
) {
1149 jack_error("CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
1153 // Calculate the number of object IDs
1154 subDevicesNum
= outSize
/ sizeof(AudioObjectID
);
1155 jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum
);
1156 AudioObjectID subDevices
[subDevicesNum
];
1157 outSize
= sizeof(subDevices
);
1159 osErr
= AudioObjectGetPropertyData(*outAggregateDevice
, &theAddressOwned
, theQualifierDataSize
, theQualifierData
, &outSize
, subDevices
);
1160 if (osErr
!= noErr
) {
1161 jack_error("CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
1165 // Set kAudioSubDevicePropertyDriftCompensation property...
1166 for (UInt32 index
= 0; index
< subDevicesNum
; ++index
) {
1167 UInt32 theDriftCompensationValue
= 1;
1168 osErr
= AudioObjectSetPropertyData(subDevices
[index
], &theAddressDrift
, 0, NULL
, sizeof(UInt32
), &theDriftCompensationValue
);
1169 if (osErr
!= noErr
) {
1170 jack_error("CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error");
1175 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
1179 // pause again to give the changes time to take effect
1180 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1186 // release the private AD key
1187 CFRelease(AggregateDeviceNumberRef
);
1189 // release the CF objects we have created - we don't need them any more
1190 CFRelease(aggDeviceDict
);
1191 CFRelease(subDevicesArray
);
1193 if (subDevicesArrayClock
) {
1194 CFRelease(subDevicesArrayClock
);
1197 // release the device UID
1198 for (UInt32 i
= 0; i
< captureDeviceUID
.size(); i
++) {
1199 CFRelease(captureDeviceUID
[i
]);
1202 for (UInt32 i
= 0; i
< playbackDeviceUID
.size(); i
++) {
1203 CFRelease(playbackDeviceUID
[i
]);
1206 jack_log("JackCoreAudioDriver::CreateAggregateDeviceAux : new aggregate device %ld", *outAggregateDevice
);
1210 DestroyAggregateDevice();
1214 int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid
,
1215 const char* playback_driver_uid
,
1216 char* capture_driver_name
,
1217 char* playback_driver_name
,
1218 jack_nframes_t samplerate
,
1221 capture_driver_name
[0] = 0;
1222 playback_driver_name
[0] = 0;
1225 if (strcmp(capture_driver_uid
, "") != 0 && strcmp(playback_driver_uid
, "") != 0) {
1226 jack_log("JackCoreAudioDriver::SetupDevices : duplex");
1228 // Same device for capture and playback...
1229 if (strcmp(capture_driver_uid
, playback_driver_uid
) == 0) {
1231 if (GetDeviceIDFromUID(playback_driver_uid
, &fDeviceID
) != noErr
) {
1232 jack_log("JackCoreAudioDriver::SetupDevices : will take default in/out");
1233 if (GetDefaultDevice(&fDeviceID
) != noErr
) {
1234 jack_error("Cannot open default device");
1238 if (GetDeviceNameFromID(fDeviceID
, capture_driver_name
) != noErr
|| GetDeviceNameFromID(fDeviceID
, playback_driver_name
) != noErr
) {
1239 jack_error("Cannot get device name from device ID");
1244 if (!TakeHogAux(fDeviceID
, false)) {
1245 jack_error("Cannot take hog mode");
1248 fDigitalPlayback
= IsDigitalDevice(fDeviceID
);
1254 // Creates aggregate device
1255 AudioDeviceID captureID
= -1;
1256 AudioDeviceID playbackID
= -1;
1258 if (GetDeviceIDFromUID(capture_driver_uid
, &captureID
) != noErr
) {
1259 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1260 if (GetDefaultInputDevice(&captureID
) != noErr
) {
1261 jack_error("Cannot open default input device");
1266 if (GetDeviceIDFromUID(playback_driver_uid
, &playbackID
) != noErr
) {
1267 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1268 if (GetDefaultOutputDevice(&playbackID
) != noErr
) {
1269 jack_error("Cannot open default output device");
1274 if (CreateAggregateDevice(captureID
, playbackID
, samplerate
, &fDeviceID
) != noErr
) {
1278 GetDeviceNameFromID(captureID
, fCaptureUID
);
1279 GetDeviceNameFromID(playbackID
, fPlaybackUID
);
1282 if (!TakeHogAux(captureID
, true)) {
1283 jack_error("Cannot take hog mode for capture device");
1285 if (!TakeHogAux(playbackID
, false)) {
1286 jack_error("Cannot take hog mode for playback device");
1289 fDigitalPlayback
= IsDigitalDevice(playbackID
);
1296 } else if (strcmp(capture_driver_uid
, "") != 0) {
1297 jack_log("JackCoreAudioDriver::SetupDevices : capture only");
1298 if (GetDeviceIDFromUID(capture_driver_uid
, &fDeviceID
) != noErr
) {
1299 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1300 if (GetDefaultInputDevice(&fDeviceID
) != noErr
) {
1301 jack_error("Cannot open default input device");
1305 if (GetDeviceNameFromID(fDeviceID
, capture_driver_name
) != noErr
) {
1306 jack_error("Cannot get device name from device ID");
1311 if (!TakeHogAux(fDeviceID
, true)) {
1312 jack_error("Cannot take hog mode for capture device");
1317 } else if (strcmp(playback_driver_uid
, "") != 0) {
1318 jack_log("JackCoreAudioDriver::SetupDevices : playback only");
1319 if (GetDeviceIDFromUID(playback_driver_uid
, &fDeviceID
) != noErr
) {
1320 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1321 if (GetDefaultOutputDevice(&fDeviceID
) != noErr
) {
1322 jack_error("Cannot open default output device");
1326 if (GetDeviceNameFromID(fDeviceID
, playback_driver_name
) != noErr
) {
1327 jack_error("Cannot get device name from device ID");
1332 if (!TakeHogAux(fDeviceID
, false)) {
1333 jack_error("Cannot take hog mode for playback device");
1336 fDigitalPlayback
= IsDigitalDevice(fDeviceID
);
1340 // Use default driver in duplex mode
1342 jack_log("JackCoreAudioDriver::SetupDevices : default driver");
1343 if (GetDefaultDevice(&fDeviceID
) != noErr
) {
1344 jack_error("Cannot open default device in duplex mode, so aggregate default input and default output");
1346 // Creates aggregate device
1347 AudioDeviceID captureID
= -1;
1348 AudioDeviceID playbackID
= -1;
1350 if (GetDeviceIDFromUID(capture_driver_uid
, &captureID
) != noErr
) {
1351 jack_log("JackCoreAudioDriver::SetupDevices : will take default input");
1352 if (GetDefaultInputDevice(&captureID
) != noErr
) {
1353 jack_error("Cannot open default input device");
1358 if (GetDeviceIDFromUID(playback_driver_uid
, &playbackID
) != noErr
) {
1359 jack_log("JackCoreAudioDriver::SetupDevices : will take default output");
1360 if (GetDefaultOutputDevice(&playbackID
) != noErr
) {
1361 jack_error("Cannot open default output device");
1366 if (CreateAggregateDevice(captureID
, playbackID
, samplerate
, &fDeviceID
) != noErr
) {
1370 GetDeviceNameFromID(captureID
, fCaptureUID
);
1371 GetDeviceNameFromID(playbackID
, fPlaybackUID
);
1374 if (!TakeHogAux(captureID
, true)) {
1375 jack_error("Cannot take hog mode for capture device");
1377 if (!TakeHogAux(playbackID
, false)) {
1378 jack_error("Cannot take hog mode for playback device");
1381 fDigitalPlayback
= IsDigitalDevice(playbackID
);
1391 Return the max possible input channels in in_maxChannels and output channels in out_maxChannels.
1393 int JackCoreAudioDriver::SetupChannels(bool capturing
, bool playing
, int& inchannels
, int& outchannels
, int& in_maxChannels
, int& out_maxChannels
, bool strict
)
1395 OSStatus err
= noErr
;
1398 err
= GetTotalChannels(fDeviceID
, in_maxChannels
, true);
1400 jack_error("SetupChannels : cannot get input channel number");
1404 jack_log("JackCoreAudioDriver::SetupChannels : max input channels : %d", in_maxChannels
);
1409 err
= GetTotalChannels(fDeviceID
, out_maxChannels
, false);
1411 jack_error("Cannot get output channel number");
1415 jack_log("JackCoreAudioDriver::SetupChannels : max output channels : %d", out_maxChannels
);
1419 if (inchannels
> in_maxChannels
) {
1420 jack_error("This device hasn't required input channels inchannels = %d in_maxChannels = %d", inchannels
, in_maxChannels
);
1426 if (outchannels
> out_maxChannels
) {
1427 jack_error("This device hasn't required output channels outchannels = %d out_maxChannels = %d", outchannels
, out_maxChannels
);
1433 if (inchannels
== -1) {
1434 jack_log("JackCoreAudioDriver::SetupChannels : setup max in channels = %d", in_maxChannels
);
1435 inchannels
= in_maxChannels
;
1438 if (outchannels
== -1) {
1439 jack_log("JackCoreAudioDriver::SetupChannels : setup max out channels = %d", out_maxChannels
);
1440 outchannels
= out_maxChannels
;
1446 int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size
)
1448 // Setting buffer size
1449 OSStatus err
= noErr
;
1450 UInt32 tmp_buffer_size
= buffer_size
;
1451 UInt32 outSize
= sizeof(UInt32
);
1453 err
= AudioDeviceGetProperty(fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyBufferFrameSize
, &outSize
, &tmp_buffer_size
);
1455 jack_error("Cannot get buffer size %ld", buffer_size
);
1459 jack_log("JackCoreAudioDriver::SetupBufferSize : current buffer size = %ld", tmp_buffer_size
);
1462 // If needed, set new buffer size
1463 if (buffer_size
!= tmp_buffer_size
) {
1464 tmp_buffer_size
= buffer_size
;
1466 // To get BS change notification
1467 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyBufferFrameSize
, BSNotificationCallback
, this);
1469 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyBufferFrameSize");
1474 // Waiting for BS change notification
1478 err
= AudioDeviceSetProperty(fDeviceID
, NULL
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyBufferFrameSize
, outSize
, &tmp_buffer_size
);
1480 jack_error("SetupBufferSize : cannot set buffer size = %ld", tmp_buffer_size
);
1485 while (!fState
&& count
++ < WAIT_NOTIFICATION_COUNTER
) {
1487 jack_log("JackCoreAudioDriver::SetupBufferSize : wait count = %d", count
);
1490 if (count
>= WAIT_NOTIFICATION_COUNTER
) {
1491 jack_error("Did not get buffer size notification...");
1495 // Check new buffer size
1496 outSize
= sizeof(UInt32
);
1497 err
= AudioDeviceGetProperty(fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyBufferFrameSize
, &outSize
, &tmp_buffer_size
);
1499 jack_error("Cannot get current buffer size");
1502 jack_log("JackCoreAudioDriver::SetupBufferSize : checked buffer size = %ld", tmp_buffer_size
);
1505 // Remove BS change notification
1506 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyBufferFrameSize
, BSNotificationCallback
);
1513 // Remove BS change notification
1514 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyBufferFrameSize
, BSNotificationCallback
);
1519 int JackCoreAudioDriver::SetupSampleRate(jack_nframes_t sample_rate
)
1521 return SetupSampleRateAux(fDeviceID
, sample_rate
);
1524 int JackCoreAudioDriver::SetupSampleRateAux(AudioDeviceID inDevice
, jack_nframes_t sample_rate
)
1526 OSStatus err
= noErr
;
1528 Float64 tmp_sample_rate
;
1531 outSize
= sizeof(Float64
);
1532 err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outSize
, &tmp_sample_rate
);
1534 jack_error("Cannot get current sample rate");
1538 jack_log("JackCoreAudioDriver::SetupSampleRateAux : current sample rate = %f", tmp_sample_rate
);
1541 // If needed, set new sample rate
1542 if (sample_rate
!= (jack_nframes_t
)tmp_sample_rate
) {
1543 tmp_sample_rate
= (Float64
)sample_rate
;
1545 // To get SR change notification
1546 err
= AudioDeviceAddPropertyListener(inDevice
, 0, true, kAudioDevicePropertyNominalSampleRate
, SRNotificationCallback
, this);
1548 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
1553 // Waiting for SR change notification
1557 err
= AudioDeviceSetProperty(inDevice
, NULL
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, outSize
, &tmp_sample_rate
);
1559 jack_error("Cannot set sample rate = %ld", sample_rate
);
1564 while (!fState
&& count
++ < WAIT_NOTIFICATION_COUNTER
) {
1566 jack_log("JackCoreAudioDriver::SetupSampleRateAux : wait count = %d", count
);
1569 if (count
>= WAIT_NOTIFICATION_COUNTER
) {
1570 jack_error("Did not get sample rate notification...");
1574 // Check new sample rate
1575 outSize
= sizeof(Float64
);
1576 err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outSize
, &tmp_sample_rate
);
1578 jack_error("Cannot get current sample rate");
1581 jack_log("JackCoreAudioDriver::SetupSampleRateAux : checked sample rate = %f", tmp_sample_rate
);
1584 // Remove SR change notification
1585 AudioDeviceRemovePropertyListener(inDevice
, 0, true, kAudioDevicePropertyNominalSampleRate
, SRNotificationCallback
);
1592 // Remove SR change notification
1593 AudioDeviceRemovePropertyListener(inDevice
, 0, true, kAudioDevicePropertyNominalSampleRate
, SRNotificationCallback
);
1597 int JackCoreAudioDriver::OpenAUHAL(bool capturing
,
1602 int out_maxChannels
,
1603 const vector
<int>& chan_in_list
,
1604 const vector
<int>& chan_out_list
,
1605 jack_nframes_t buffer_size
,
1606 jack_nframes_t sample_rate
)
1608 ComponentResult err1
;
1610 AudioStreamBasicDescription srcFormat
, dstFormat
;
1611 AudioDeviceID currAudioDeviceID
;
1614 jack_log("JackCoreAudioDriver::OpenAUHAL : capturing = %d playing = %d inchannels = %d outchannels = %d in_maxChannels = %d out_maxChannels = %d chan_in_list = %d chan_out_list = %d",
1615 capturing
, playing
, inchannels
, outchannels
, in_maxChannels
, out_maxChannels
, chan_in_list
.size(), chan_out_list
.size());
1617 if (inchannels
== 0 && outchannels
== 0) {
1618 jack_error("No input and output channels...");
1625 Gestalt(gestaltSystemVersionMajor
, &major
);
1626 Gestalt(gestaltSystemVersionMinor
, &minor
);
1628 if (major
== 10 && minor
>= 6) {
1629 AudioComponentDescription cd
= {kAudioUnitType_Output
, kAudioUnitSubType_HALOutput
, kAudioUnitManufacturer_Apple
, 0, 0};
1630 AudioComponent HALOutput
= AudioComponentFindNext(NULL
, &cd
);
1631 err1
= AudioComponentInstanceNew(HALOutput
, &fAUHAL
);
1632 if (err1
!= noErr
) {
1633 jack_error("Error calling AudioComponentInstanceNew");
1638 ComponentDescription cd
= {kAudioUnitType_Output
, kAudioUnitSubType_HALOutput
, kAudioUnitManufacturer_Apple
, 0, 0};
1639 Component HALOutput
= FindNextComponent(NULL
, &cd
);
1640 err1
= OpenAComponent(HALOutput
, &fAUHAL
);
1641 if (err1
!= noErr
) {
1642 jack_error("Error calling OpenAComponent");
1648 err1
= AudioUnitInitialize(fAUHAL
);
1649 if (err1
!= noErr
) {
1650 jack_error("Cannot initialize AUHAL unit");
1656 if (capturing
&& inchannels
> 0) {
1658 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input on");
1661 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input off");
1664 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Input
, 1, &enableIO
, sizeof(enableIO
));
1665 if (err1
!= noErr
) {
1666 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
1671 if (playing
&& outchannels
> 0) {
1673 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output on");
1676 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output off");
1679 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Output
, 0, &enableIO
, sizeof(enableIO
));
1680 if (err1
!= noErr
) {
1681 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
1686 size
= sizeof(AudioDeviceID
);
1687 err1
= AudioUnitGetProperty(fAUHAL
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &currAudioDeviceID
, &size
);
1688 if (err1
!= noErr
) {
1689 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
1693 jack_log("JackCoreAudioDriver::OpenAUHAL : AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID
);
1696 // Setup up choosen device, in both input and output cases
1697 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &fDeviceID
, sizeof(AudioDeviceID
));
1698 if (err1
!= noErr
) {
1699 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
1705 if (capturing
&& inchannels
> 0) {
1706 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Global
, 1, (UInt32
*)&buffer_size
, sizeof(UInt32
));
1707 if (err1
!= noErr
) {
1708 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
1714 if (playing
&& outchannels
> 0) {
1715 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Global
, 0, (UInt32
*)&buffer_size
, sizeof(UInt32
));
1716 if (err1
!= noErr
) {
1717 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
1723 // Setup input channel map
1724 if (capturing
&& inchannels
> 0 && inchannels
<= in_maxChannels
) {
1725 SInt32 chanArr
[in_maxChannels
];
1726 for (int i
= 0; i
< in_maxChannels
; i
++) {
1730 if (chan_in_list
.size() > 0) {
1731 for (uint i
= 0; i
< chan_in_list
.size(); i
++) {
1732 int chan
= chan_in_list
[i
];
1733 if (chan
< out_maxChannels
) {
1734 // The wanted JACK input index for the 'chan' channel value
1736 jack_info("Input channel = %d ==> JACK input port = %d", chan
, i
);
1738 jack_info("Error input channel number is incorrect : %d", chan
);
1743 for (int i
= 0; i
< inchannels
; i
++) {
1745 jack_info("Input channel = %d ==> JACK input port = %d", chanArr
[i
], i
);
1749 AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Input
, 1, chanArr
, sizeof(SInt32
) * in_maxChannels
);
1750 if (err1
!= noErr
) {
1751 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap for input");
1757 // Setup output channel map
1758 if (playing
&& outchannels
> 0 && outchannels
<= out_maxChannels
) {
1759 SInt32 chanArr
[out_maxChannels
];
1760 for (int i
= 0; i
< out_maxChannels
; i
++) {
1764 if (chan_out_list
.size() > 0) {
1765 for (uint i
= 0; i
< chan_out_list
.size(); i
++) {
1766 int chan
= chan_out_list
[i
];
1767 if (chan
< out_maxChannels
) {
1768 // The wanted JACK output index for the 'chan' channel value
1770 jack_info("JACK output port = %d ==> output channel = %d", i
, chan
);
1772 jack_info("Error output channel number is incorrect : %d", chan
);
1777 for (int i
= 0; i
< outchannels
; i
++) {
1779 jack_info("JACK output port = %d ==> output channel = %d", i
, chanArr
[i
]);
1783 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Output
, 0, chanArr
, sizeof(SInt32
) * out_maxChannels
);
1784 if (err1
!= noErr
) {
1785 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap for output");
1791 // Setup stream converters
1792 if (capturing
&& inchannels
> 0) {
1794 size
= sizeof(AudioStreamBasicDescription
);
1795 err1
= AudioUnitGetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &srcFormat
, &size
);
1796 if (err1
!= noErr
) {
1797 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
1801 PrintStreamDesc(&srcFormat
);
1803 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL input stream converter SR = %ld", sample_rate
);
1804 srcFormat
.mSampleRate
= sample_rate
;
1805 srcFormat
.mFormatID
= kAudioFormatLinearPCM
;
1806 srcFormat
.mFormatFlags
= kAudioFormatFlagsNativeFloatPacked
| kLinearPCMFormatFlagIsNonInterleaved
;
1807 srcFormat
.mBytesPerPacket
= sizeof(jack_default_audio_sample_t
);
1808 srcFormat
.mFramesPerPacket
= 1;
1809 srcFormat
.mBytesPerFrame
= sizeof(jack_default_audio_sample_t
);
1810 srcFormat
.mChannelsPerFrame
= inchannels
;
1811 srcFormat
.mBitsPerChannel
= 32;
1812 PrintStreamDesc(&srcFormat
);
1814 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &srcFormat
, sizeof(AudioStreamBasicDescription
));
1815 if (err1
!= noErr
) {
1816 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
1822 if (playing
&& outchannels
> 0) {
1824 size
= sizeof(AudioStreamBasicDescription
);
1825 err1
= AudioUnitGetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &dstFormat
, &size
);
1826 if (err1
!= noErr
) {
1827 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
1831 PrintStreamDesc(&dstFormat
);
1833 jack_log("JackCoreAudioDriver::OpenAUHAL : setup AUHAL output stream converter SR = %ld", sample_rate
);
1834 dstFormat
.mSampleRate
= sample_rate
;
1835 dstFormat
.mFormatID
= kAudioFormatLinearPCM
;
1836 dstFormat
.mFormatFlags
= kAudioFormatFlagsNativeFloatPacked
| kLinearPCMFormatFlagIsNonInterleaved
;
1837 dstFormat
.mBytesPerPacket
= sizeof(jack_default_audio_sample_t
);
1838 dstFormat
.mFramesPerPacket
= 1;
1839 dstFormat
.mBytesPerFrame
= sizeof(jack_default_audio_sample_t
);
1840 dstFormat
.mChannelsPerFrame
= outchannels
;
1841 dstFormat
.mBitsPerChannel
= 32;
1842 PrintStreamDesc(&dstFormat
);
1844 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &dstFormat
, sizeof(AudioStreamBasicDescription
));
1845 if (err1
!= noErr
) {
1846 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
1853 if (inchannels
> 0 && outchannels
== 0) {
1854 AURenderCallbackStruct output
;
1855 output
.inputProc
= Render
;
1856 output
.inputProcRefCon
= this;
1857 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_SetInputCallback
, kAudioUnitScope_Global
, 0, &output
, sizeof(output
));
1858 if (err1
!= noErr
) {
1859 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
1864 AURenderCallbackStruct output
;
1865 output
.inputProc
= Render
;
1866 output
.inputProcRefCon
= this;
1867 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_SetRenderCallback
, kAudioUnitScope_Input
, 0, &output
, sizeof(output
));
1868 if (err1
!= noErr
) {
1869 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
1882 int JackCoreAudioDriver::SetupBuffers(int inchannels
)
1885 fJackInputData
= (AudioBufferList
*)malloc(sizeof(UInt32
) + inchannels
* sizeof(AudioBuffer
));
1886 fJackInputData
->mNumberBuffers
= inchannels
;
1887 for (int i
= 0; i
< inchannels
; i
++) {
1888 fJackInputData
->mBuffers
[i
].mNumberChannels
= 1;
1889 fJackInputData
->mBuffers
[i
].mDataByteSize
= fEngineControl
->fBufferSize
* sizeof(jack_default_audio_sample_t
);
1894 void JackCoreAudioDriver::DisposeBuffers()
1896 if (fJackInputData
) {
1897 free(fJackInputData
);
1902 void JackCoreAudioDriver::CloseAUHAL()
1904 AudioOutputUnitStop(fAUHAL
);
1905 AudioUnitUninitialize(fAUHAL
);
1906 CloseComponent(fAUHAL
);
1909 int JackCoreAudioDriver::AddListeners()
1911 OSStatus err
= noErr
;
1914 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDeviceProcessorOverload
, DeviceNotificationCallback
, this);
1916 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
1921 err
= AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices
, AudioHardwareNotificationCallback
, this);
1923 jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices");
1928 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyNominalSampleRate
, DeviceNotificationCallback
, this);
1930 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
1935 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsRunning
, DeviceNotificationCallback
, this);
1937 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
1942 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsAlive
, DeviceNotificationCallback
, this);
1944 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsAlive");
1949 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceHasChanged
, DeviceNotificationCallback
, this);
1951 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceHasChanged");
1956 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
, this);
1958 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1963 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, false, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
, this);
1965 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
1970 if (!fEngineControl
->fSyncMode
&& fIOUsage
!= 1.f
) {
1971 UInt32 outSize
= sizeof(float);
1972 err
= AudioDeviceSetProperty(fDeviceID
, NULL
, 0, false, kAudioDevicePropertyIOCycleUsage
, outSize
, &fIOUsage
);
1974 jack_error("Error calling AudioDeviceSetProperty kAudioDevicePropertyIOCycleUsage");
1982 void JackCoreAudioDriver::RemoveListeners()
1984 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDeviceProcessorOverload
, DeviceNotificationCallback
);
1985 AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices
, AudioHardwareNotificationCallback
);
1986 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyNominalSampleRate
, DeviceNotificationCallback
);
1987 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsRunning
, DeviceNotificationCallback
);
1988 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsAlive
, DeviceNotificationCallback
);
1989 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceHasChanged
, DeviceNotificationCallback
);
1990 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
);
1991 AudioDeviceRemovePropertyListener(fDeviceID
, 0, false, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
);
1994 int JackCoreAudioDriver::Open(jack_nframes_t buffer_size
,
1995 jack_nframes_t sample_rate
,
2000 const char* chan_in_list
,
2001 const char* chan_out_list
,
2003 const char* capture_driver_uid
,
2004 const char* playback_driver_uid
,
2005 jack_nframes_t capture_latency
,
2006 jack_nframes_t playback_latency
,
2007 int async_output_latency
,
2008 int computation_grain
,
2015 int in_maxChannels
= 0;
2016 int out_maxChannels
= 0;
2017 char capture_driver_name
[256];
2018 char playback_driver_name
[256];
2020 fCaptureLatency
= capture_latency
;
2021 fPlaybackLatency
= playback_latency
;
2022 fIOUsage
= float(async_output_latency
) / 100.f
;
2023 fComputationGrain
= float(computation_grain
) / 100.f
;
2025 fClockDriftCompensate
= clock_drift
;
2029 Gestalt(gestaltSystemVersionMajor
, &major
);
2030 Gestalt(gestaltSystemVersionMinor
, &minor
);
2032 vector
<int> parsed_chan_in_list
;
2033 vector
<int> parsed_chan_out_list
;
2035 // Starting with 10.6 systems, the HAL notification thread is created internally
2036 if (major
== 10 && minor
>= 6) {
2037 CFRunLoopRef theRunLoop
= NULL
;
2038 AudioObjectPropertyAddress theAddress
= { kAudioHardwarePropertyRunLoop
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
2039 OSStatus osErr
= AudioObjectSetPropertyData (kAudioObjectSystemObject
, &theAddress
, 0, NULL
, sizeof(CFRunLoopRef
), &theRunLoop
);
2040 if (osErr
!= noErr
) {
2041 jack_error("Open kAudioHardwarePropertyRunLoop error");
2046 if (SetupDevices(capture_driver_uid
, playback_driver_uid
, capture_driver_name
, playback_driver_name
, sample_rate
, ac3_encoding
) < 0) {
2050 // Generic JackAudioDriver Open
2051 if (JackAudioDriver::Open(buffer_size
, sample_rate
,
2053 inchannels
, outchannels
,
2055 capture_driver_name
,
2056 playback_driver_name
,
2058 playback_latency
) != 0) {
2062 if (SetupChannels(capturing
, playing
, inchannels
, outchannels
, in_maxChannels
, out_maxChannels
, !ac3_encoding
) < 0) {
2066 ParseChannelList(chan_in_list
, parsed_chan_in_list
, in_maxChannels
);
2067 if (parsed_chan_in_list
.size() > 0) {
2068 jack_info("Explicit input channel list size = %d", parsed_chan_in_list
.size());
2069 inchannels
= parsed_chan_in_list
.size();
2072 ParseChannelList(chan_out_list
, parsed_chan_out_list
, out_maxChannels
);
2073 if (parsed_chan_out_list
.size() > 0) {
2074 jack_info("Explicit output channel list size = %d", parsed_chan_out_list
.size());
2075 outchannels
= parsed_chan_out_list
.size();
2078 if (SetupBufferSize(buffer_size
) < 0) {
2082 if (SetupSampleRate(sample_rate
) < 0) {
2088 if (!fDigitalPlayback
) {
2089 jack_error("AC3 encoding can only be used with a digital device");
2093 JackAC3EncoderParams params
;
2094 memset(¶ms
, 0, sizeof(JackAC3EncoderParams
));
2095 params
.bitrate
= ac3_bitrate
;
2096 params
.channels
= outchannels
;
2097 params
.sample_rate
= sample_rate
;
2098 params
.lfe
= ac3_lfe
;
2099 fAC3Encoder
= new JackAC3Encoder(params
);
2101 if (!fAC3Encoder
|| !fAC3Encoder
->Init(sample_rate
)) {
2102 jack_error("Cannot allocate or init AC3 encoder");
2106 // Setup AC3 channel number
2107 fPlaybackChannels
= outchannels
;
2109 fPlaybackChannels
++;
2112 if (fPlaybackChannels
< 2 || fPlaybackChannels
> 6) {
2113 jack_error("AC3 encoder channels must be between 2 and 6");
2117 // Force real output channel number to 2
2118 outchannels
= out_maxChannels
= 2;
2121 fPlaybackChannels
= outchannels
;
2124 // Core driver may have changed the in/out values
2125 fCaptureChannels
= inchannels
;
2127 if (OpenAUHAL(capturing
, playing
, inchannels
, outchannels
, in_maxChannels
, out_maxChannels
, parsed_chan_in_list
, parsed_chan_out_list
, buffer_size
, sample_rate
) < 0) {
2131 if (capturing
&& inchannels
> 0) {
2132 if (SetupBuffers(inchannels
) < 0) {
2137 if (AddListeners() < 0) {
2148 int JackCoreAudioDriver::Close()
2150 jack_log("JackCoreAudioDriver::Close");
2152 // Generic audio driver close
2153 int res
= JackAudioDriver::Close();
2158 DestroyAggregateDevice();
2162 void JackCoreAudioDriver::UpdateLatencies()
2166 jack_latency_range_t input_range
;
2167 jack_latency_range_t output_range
;
2168 jack_latency_range_t monitor_range
;
2170 // Get Input latency
2171 size
= sizeof(UInt32
);
2174 err
= AudioDeviceGetProperty(fDeviceID
, 0, true, kAudioDevicePropertyLatency
, &size
, &value1
);
2176 jack_error("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
2178 err
= AudioDeviceGetProperty(fDeviceID
, 0, true, kAudioDevicePropertySafetyOffset
, &size
, &value2
);
2180 jack_error("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
2183 input_range
.min
= input_range
.max
= fEngineControl
->fBufferSize
+ value1
+ value2
+ fCaptureLatency
;
2185 // Get input stream latencies
2186 vector
<int> input_latencies
;
2187 err
= GetStreamLatencies(fDeviceID
, true, input_latencies
);
2189 for (int i
= 0; i
< fCaptureChannels
; i
++) {
2191 input_range
.min
+= input_latencies
[i
];
2192 input_range
.max
+= input_latencies
[i
];
2194 fGraphManager
->GetPort(fCapturePortList
[i
])->SetLatencyRange(JackCaptureLatency
, &input_range
);
2197 // Get Output latency
2198 size
= sizeof(UInt32
);
2201 err
= AudioDeviceGetProperty(fDeviceID
, 0, false, kAudioDevicePropertyLatency
, &size
, &value1
);
2203 jack_error("AudioDeviceGetProperty kAudioDevicePropertyLatency error");
2205 err
= AudioDeviceGetProperty(fDeviceID
, 0, false, kAudioDevicePropertySafetyOffset
, &size
, &value2
);
2207 jack_error("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error");
2210 // Get output stream latencies
2211 vector
<int> output_latencies
;
2212 err
= GetStreamLatencies(fDeviceID
, false, output_latencies
);
2214 // Add more latency if "async" mode is used...
2215 output_range
.min
= output_range
.max
= fEngineControl
->fBufferSize
+ ((fEngineControl
->fSyncMode
)
2216 ? 0 : fEngineControl
->fBufferSize
* fIOUsage
) + value1
+ value2
+ fPlaybackLatency
;
2218 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
2220 output_range
.min
+= output_latencies
[i
];
2221 output_range
.max
+= output_latencies
[i
];
2223 fGraphManager
->GetPort(fPlaybackPortList
[i
])->SetLatencyRange(JackPlaybackLatency
, &output_range
);
2226 if (fWithMonitorPorts
) {
2227 monitor_range
.min
= monitor_range
.max
= fEngineControl
->fBufferSize
;
2228 fGraphManager
->GetPort(fMonitorPortList
[i
])->SetLatencyRange(JackCaptureLatency
, &monitor_range
);
2233 int JackCoreAudioDriver::Attach()
2237 jack_port_id_t port_index
;
2240 char channel_name
[64];
2241 char name
[REAL_JACK_PORT_NAME_SIZE
];
2242 char alias
[REAL_JACK_PORT_NAME_SIZE
];
2244 jack_log("JackCoreAudioDriver::Attach : fBufferSize %ld fSampleRate %ld", fEngineControl
->fBufferSize
, fEngineControl
->fSampleRate
);
2246 for (int i
= 0; i
< fCaptureChannels
; i
++) {
2248 err
= AudioDeviceGetPropertyInfo(fDeviceID
, i
+ 1, true, kAudioDevicePropertyChannelName
, &size
, &isWritable
);
2250 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error");
2252 if (err
== noErr
&& size
> 0) {
2253 err
= AudioDeviceGetProperty(fDeviceID
, i
+ 1, true, kAudioDevicePropertyChannelName
, &size
, channel_name
);
2255 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetProperty kAudioDevicePropertyChannelName error");
2257 snprintf(alias
, sizeof(alias
), "%s:%s:out_%s%u", fAliasName
, fCaptureDriverName
, channel_name
, i
+ 1);
2259 snprintf(alias
, sizeof(alias
), "%s:%s:out%u", fAliasName
, fCaptureDriverName
, i
+ 1);
2262 snprintf(name
, sizeof(name
), "%s:capture_%d", fClientControl
.fName
, i
+ 1);
2264 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_AUDIO_TYPE
, CaptureDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
2265 jack_error("Cannot register port for %s", name
);
2269 port
= fGraphManager
->GetPort(port_index
);
2270 port
->SetAlias(alias
);
2271 fCapturePortList
[i
] = port_index
;
2274 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
2276 err
= AudioDeviceGetPropertyInfo(fDeviceID
, i
+ 1, false, kAudioDevicePropertyChannelName
, &size
, &isWritable
);
2278 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error");
2280 if (err
== noErr
&& size
> 0) {
2281 err
= AudioDeviceGetProperty(fDeviceID
, i
+ 1, false, kAudioDevicePropertyChannelName
, &size
, channel_name
);
2283 jack_log("JackCoreAudioDriver::Attach : AudioDeviceGetProperty kAudioDevicePropertyChannelName error");
2285 snprintf(alias
, sizeof(alias
), "%s:%s:in_%s%u", fAliasName
, fPlaybackDriverName
, channel_name
, i
+ 1);
2287 snprintf(alias
, sizeof(alias
), "%s:%s:in%u", fAliasName
, fPlaybackDriverName
, i
+ 1);
2290 snprintf(name
, sizeof(name
), "%s:playback_%d", fClientControl
.fName
, i
+ 1);
2292 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_AUDIO_TYPE
, PlaybackDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
2293 jack_error("Cannot register port for %s", name
);
2297 port
= fGraphManager
->GetPort(port_index
);
2298 port
->SetAlias(alias
);
2299 fPlaybackPortList
[i
] = port_index
;
2302 if (fWithMonitorPorts
) {
2303 jack_log("JackCoreAudioDriver::Attach : create monitor port");
2304 snprintf(name
, sizeof(name
), "%s:monitor_%u", fClientControl
.fName
, i
+ 1);
2305 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_AUDIO_TYPE
, MonitorDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
2306 jack_error("Cannot register monitor port for %s", name
);
2309 fMonitorPortList
[i
] = port_index
;
2315 // Setup specific AC3 channels names
2316 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
2317 fAC3Encoder
->GetChannelName("coreaudio", "", alias
, i
);
2318 port
= fGraphManager
->GetPort(fPlaybackPortList
[i
]);
2319 port
->SetAlias(alias
);
2325 // Input buffers do no change : prepare them only once
2326 for (int i
= 0; i
< fCaptureChannels
; i
++) {
2327 fJackInputData
->mBuffers
[i
].mData
= GetInputBuffer(i
);
2333 int JackCoreAudioDriver::Start()
2335 jack_log("JackCoreAudioDriver::Start");
2336 if (JackAudioDriver::Start() == 0) {
2338 // Waiting for Render callback to be called (= driver has started)
2342 OSStatus err
= AudioOutputUnitStart(fAUHAL
);
2345 while (!fState
&& count
++ < WAIT_COUNTER
) {
2347 jack_log("JackCoreAudioDriver::Start : wait count = %d", count
);
2350 if (count
< WAIT_COUNTER
) {
2351 jack_info("CoreAudio driver is running...");
2355 jack_error("CoreAudio driver cannot start...");
2357 JackAudioDriver::Stop();
2362 int JackCoreAudioDriver::Stop()
2364 jack_log("JackCoreAudioDriver::Stop");
2365 int res
= (AudioOutputUnitStop(fAUHAL
) == noErr
) ? 0 : -1;
2366 if (JackAudioDriver::Stop() < 0) {
2372 int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size
)
2374 if (SetupBufferSize(buffer_size
) < 0) {
2378 JackAudioDriver::SetBufferSize(buffer_size
); // Generic change, never fails
2380 // CoreAudio specific
2383 // Input buffers do no change : prepare them only once
2384 for (int i
= 0; i
< fCaptureChannels
; i
++) {
2385 fJackInputData
->mBuffers
[i
].mNumberChannels
= 1;
2386 fJackInputData
->mBuffers
[i
].mDataByteSize
= fEngineControl
->fBufferSize
* sizeof(jack_default_audio_sample_t
);
2387 fJackInputData
->mBuffers
[i
].mData
= GetInputBuffer(i
);
2393 bool JackCoreAudioDriver::TakeHogAux(AudioDeviceID deviceID
, bool isInput
)
2398 UInt32 propSize
= sizeof(hog_pid
);
2399 err
= AudioDeviceGetProperty(deviceID
, 0, isInput
, kAudioDevicePropertyHogMode
, &propSize
, &hog_pid
);
2401 jack_error("Cannot read hog state...");
2405 jack_log("JackCoreAudioDriver::TakeHogAux : deviceID = %d", deviceID
);
2407 if (hog_pid
!= getpid()) {
2409 err
= AudioDeviceSetProperty(deviceID
, 0, 0, isInput
, kAudioDevicePropertyHogMode
, propSize
, &hog_pid
);
2411 jack_error("Can't hog device = %d because it's being hogged by another program or cannot be hogged", deviceID
);
2419 bool JackCoreAudioDriver::TakeHog()
2421 OSStatus err
= noErr
;
2422 AudioObjectID sub_device
[32];
2423 UInt32 outSize
= sizeof(sub_device
);
2424 err
= AudioDeviceGetProperty(fDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
2427 jack_log("JackCoreAudioDriver::TakeHog : device does not have subdevices");
2428 return TakeHogAux(fDeviceID
, true);
2430 int num_devices
= outSize
/ sizeof(AudioObjectID
);
2431 jack_log("JackCoreAudioDriver::TakeHog : device does has %d subdevices", num_devices
);
2432 for (int i
= 0; i
< num_devices
; i
++) {
2433 if (!TakeHogAux(sub_device
[i
], true)) {
2441 bool JackCoreAudioDriver::IsAggregateDevice(AudioDeviceID device
)
2443 UInt32 deviceType
, outSize
= sizeof(UInt32
);
2444 OSStatus err
= AudioDeviceGetProperty(device
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyTransportType
, &outSize
, &deviceType
);
2447 jack_log("JackCoreAudioDriver::IsAggregateDevice kAudioDevicePropertyTransportType error");
2450 return (deviceType
== kAudioDeviceTransportTypeAggregate
);
2455 } // end of namespace
2463 SERVER_EXPORT jack_driver_desc_t
* driver_get_descriptor()
2465 jack_driver_desc_t
* desc
;
2466 jack_driver_desc_filler_t filler
;
2467 jack_driver_param_value_t value
;
2469 desc
= jack_driver_descriptor_construct("coreaudio", JackDriverMaster
, "Apple CoreAudio API based audio backend", &filler
);
2472 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");
2473 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");
2474 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");
2477 jack_driver_descriptor_add_parameter(desc
, &filler
, "input-list", 'n', JackDriverParamString
, &value
, NULL
, "Input channel list for channel mapping", "List of input channel number to be opened (syntax like : \"0 3 2\")");
2478 jack_driver_descriptor_add_parameter(desc
, &filler
, "output-list", 'N', JackDriverParamString
, &value
, NULL
, "Output channel list for channel mapping", "List of output channel number to be opened (syntax like : \"0 3 2\")");
2481 jack_driver_descriptor_add_parameter(desc
, &filler
, "capture", 'C', JackDriverParamString
, &value
, NULL
, "Input CoreAudio device name", NULL
);
2482 jack_driver_descriptor_add_parameter(desc
, &filler
, "playback", 'P', JackDriverParamString
, &value
, NULL
, "Output CoreAudio device name", NULL
);
2485 jack_driver_descriptor_add_parameter(desc
, &filler
, "monitor", 'm', JackDriverParamBool
, &value
, NULL
, "Provide monitor ports for the output", NULL
);
2489 jack_driver_descriptor_add_parameter(desc
, &filler
, "AC3-encoding", 'a', JackDriverParamBool
, &value
, NULL
, "AC3 multi-channels encoding", NULL
);
2492 jack_driver_descriptor_add_parameter(desc
, &filler
, "AC3-bitrate", 'b', JackDriverParamUInt
, &value
, NULL
, "AC3 bitrate", NULL
);
2495 jack_driver_descriptor_add_parameter(desc
, &filler
, "AC3-LFE", 'f', JackDriverParamBool
, &value
, NULL
, "AC3 LFE channel", NULL
);
2498 jack_driver_descriptor_add_parameter(desc
, &filler
, "duplex", 'D', JackDriverParamBool
, &value
, NULL
, "Provide both capture and playback ports", NULL
);
2501 jack_driver_descriptor_add_parameter(desc
, &filler
, "rate", 'r', JackDriverParamUInt
, &value
, NULL
, "Sample rate", NULL
);
2504 jack_driver_descriptor_add_parameter(desc
, &filler
, "period", 'p', JackDriverParamUInt
, &value
, NULL
, "Frames per period", NULL
);
2507 jack_driver_descriptor_add_parameter(desc
, &filler
, "device", 'd', JackDriverParamString
, &value
, NULL
, "CoreAudio device name", NULL
);
2510 jack_driver_descriptor_add_parameter(desc
, &filler
, "input-latency", 'I', JackDriverParamUInt
, &value
, NULL
, "Extra input latency (frames)", NULL
);
2511 jack_driver_descriptor_add_parameter(desc
, &filler
, "output-latency", 'O', JackDriverParamUInt
, &value
, NULL
, "Extra output latency (frames)", NULL
);
2514 jack_driver_descriptor_add_parameter(desc
, &filler
, "list-devices", 'l', JackDriverParamBool
, &value
, NULL
, "Display available CoreAudio devices", NULL
);
2517 jack_driver_descriptor_add_parameter(desc
, &filler
, "hog", 'H', JackDriverParamBool
, &value
, NULL
, "Take exclusive access of the audio device", NULL
);
2520 jack_driver_descriptor_add_parameter(desc
, &filler
, "async-latency", 'L', JackDriverParamUInt
, &value
, NULL
, "Extra output latency in asynchronous mode (percent)", NULL
);
2523 jack_driver_descriptor_add_parameter(desc
, &filler
, "grain", 'G', JackDriverParamUInt
, &value
, NULL
, "Computation grain in RT thread (percent)", NULL
);
2526 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");
2531 SERVER_EXPORT
Jack::JackDriverClientInterface
* driver_initialize(Jack::JackLockedEngine
* engine
, Jack::JackSynchro
* table
, const JSList
* params
)
2533 jack_nframes_t srate
= 44100;
2534 jack_nframes_t frames_per_interrupt
= 256;
2535 bool capture
= false;
2536 bool playback
= false;
2537 int chan_in
= -1; // Default: if not explicitely set, then max possible will be used...
2538 int chan_out
= -1; // Default: if not explicitely set, then max possible will be used...
2539 const char* chan_in_list
= "";
2540 const char* chan_out_list
= "";
2541 bool monitor
= false;
2542 const char* capture_driver_uid
= "";
2543 const char* playback_driver_uid
= "";
2545 const jack_driver_param_t
*param
;
2546 jack_nframes_t systemic_input_latency
= 0;
2547 jack_nframes_t systemic_output_latency
= 0;
2548 int async_output_latency
= 100;
2549 int computation_grain
= -1;
2550 bool hogged
= false;
2551 bool clock_drift
= false;
2552 bool ac3_encoding
= false;
2553 int ac3_bitrate
= 448;
2554 bool ac3_lfe
= false;
2556 for (node
= params
; node
; node
= jack_slist_next(node
)) {
2557 param
= (const jack_driver_param_t
*) node
->data
;
2559 switch (param
->character
) {
2562 capture_driver_uid
= param
->value
.str
;
2563 playback_driver_uid
= param
->value
.str
;
2572 chan_in
= chan_out
= param
->value
.i
;
2576 chan_in
= param
->value
.i
;
2580 chan_out
= param
->value
.i
;
2584 chan_in_list
= param
->value
.str
;
2588 chan_out_list
= param
->value
.str
;
2593 if (strcmp(param
->value
.str
, "none") != 0) {
2594 capture_driver_uid
= param
->value
.str
;
2600 if (strcmp(param
->value
.str
, "none") != 0) {
2601 playback_driver_uid
= param
->value
.str
;
2606 monitor
= param
->value
.i
;
2611 ac3_encoding
= param
->value
.i
;
2615 ac3_bitrate
= param
->value
.i
;
2619 ac3_lfe
= param
->value
.i
;
2624 srate
= param
->value
.ui
;
2628 frames_per_interrupt
= (unsigned int)param
->value
.ui
;
2632 systemic_input_latency
= param
->value
.ui
;
2636 systemic_output_latency
= param
->value
.ui
;
2640 Jack::DisplayDeviceNames();
2641 // Stops the server in this case
2649 async_output_latency
= param
->value
.ui
;
2653 computation_grain
= param
->value
.ui
;
2662 /* duplex is the default */
2663 if (!capture
&& !playback
) {
2668 if (strcmp(chan_in_list
, "") != 0 && chan_in
>= 0) {
2669 printf("Input channel list and in channels are both specified, input channel list will take over...\n");
2672 if (strcmp(chan_out_list
, "") != 0 && chan_out
>= 0) {
2673 printf("Output channel list and out channels are both specified, output channel list will take over...\n");
2676 Jack::JackCoreAudioDriver
* driver
= new Jack::JackCoreAudioDriver("system", "coreaudio", engine
, table
);
2677 if (driver
->Open(frames_per_interrupt
,
2680 chan_out
, chan_in_list
,
2681 chan_out_list
, monitor
,
2683 playback_driver_uid
,
2684 systemic_input_latency
,
2685 systemic_output_latency
,
2686 async_output_latency
,
2688 hogged
, clock_drift
,
2689 ac3_encoding
, ac3_bitrate
, ac3_lfe
) == 0) {