2 Copyright (C) 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 "JackCoreAudioAdapter.h"
21 #include "JackError.h"
24 #include <CoreServices/CoreServices.h>
29 static void PrintStreamDesc(AudioStreamBasicDescription
*inDesc
)
31 jack_log("- - - - - - - - - - - - - - - - - - - -");
32 jack_log(" Sample Rate:%f", inDesc
->mSampleRate
);
33 jack_log(" Format ID:%.*s", (int) sizeof(inDesc
->mFormatID
), (char*)&inDesc
->mFormatID
);
34 jack_log(" Format Flags:%lX", inDesc
->mFormatFlags
);
35 jack_log(" Bytes per Packet:%ld", inDesc
->mBytesPerPacket
);
36 jack_log(" Frames per Packet:%ld", inDesc
->mFramesPerPacket
);
37 jack_log(" Bytes per Frame:%ld", inDesc
->mBytesPerFrame
);
38 jack_log(" Channels per Frame:%ld", inDesc
->mChannelsPerFrame
);
39 jack_log(" Bits per Channel:%ld", inDesc
->mBitsPerChannel
);
40 jack_log("- - - - - - - - - - - - - - - - - - - -");
43 static OSStatus
DisplayDeviceNames()
51 err
= AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices
, &size
, &isWritable
);
55 deviceNum
= size
/ sizeof(AudioDeviceID
);
56 AudioDeviceID devices
[deviceNum
];
58 err
= AudioHardwareGetProperty(kAudioHardwarePropertyDevices
, &size
, devices
);
62 for (i
= 0; i
< deviceNum
; i
++) {
63 char device_name
[256];
64 char internal_name
[256];
66 size
= sizeof(CFStringRef
);
68 err
= AudioDeviceGetProperty(devices
[i
], 0, false, kAudioDevicePropertyDeviceUID
, &size
, &UIname
);
70 CFStringGetCString(UIname
, internal_name
, 256, CFStringGetSystemEncoding());
76 err
= AudioDeviceGetProperty(devices
[i
], 0, false, kAudioDevicePropertyDeviceName
, &size
, device_name
);
80 jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name
, internal_name
);
91 static void printError(OSStatus err
)
94 case kAudioHardwareNoError
:
95 jack_log("error code : kAudioHardwareNoError");
97 case kAudioConverterErr_FormatNotSupported
:
98 jack_log("error code : kAudioConverterErr_FormatNotSupported");
100 case kAudioConverterErr_OperationNotSupported
:
101 jack_log("error code : kAudioConverterErr_OperationNotSupported");
103 case kAudioConverterErr_PropertyNotSupported
:
104 jack_log("error code : kAudioConverterErr_PropertyNotSupported");
106 case kAudioConverterErr_InvalidInputSize
:
107 jack_log("error code : kAudioConverterErr_InvalidInputSize");
109 case kAudioConverterErr_InvalidOutputSize
:
110 jack_log("error code : kAudioConverterErr_InvalidOutputSize");
112 case kAudioConverterErr_UnspecifiedError
:
113 jack_log("error code : kAudioConverterErr_UnspecifiedError");
115 case kAudioConverterErr_BadPropertySizeError
:
116 jack_log("error code : kAudioConverterErr_BadPropertySizeError");
118 case kAudioConverterErr_RequiresPacketDescriptionsError
:
119 jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
121 case kAudioConverterErr_InputSampleRateOutOfRange
:
122 jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
124 case kAudioConverterErr_OutputSampleRateOutOfRange
:
125 jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
127 case kAudioHardwareNotRunningError
:
128 jack_log("error code : kAudioHardwareNotRunningError");
130 case kAudioHardwareUnknownPropertyError
:
131 jack_log("error code : kAudioHardwareUnknownPropertyError");
133 case kAudioHardwareIllegalOperationError
:
134 jack_log("error code : kAudioHardwareIllegalOperationError");
136 case kAudioHardwareBadDeviceError
:
137 jack_log("error code : kAudioHardwareBadDeviceError");
139 case kAudioHardwareBadStreamError
:
140 jack_log("error code : kAudioHardwareBadStreamError");
142 case kAudioDeviceUnsupportedFormatError
:
143 jack_log("error code : kAudioDeviceUnsupportedFormatError");
145 case kAudioDevicePermissionsError
:
146 jack_log("error code : kAudioDevicePermissionsError");
148 case kAudioHardwareBadObjectError
:
149 jack_log("error code : kAudioHardwareBadObjectError");
151 case kAudioHardwareUnsupportedOperationError
:
152 jack_log("error code : kAudioHardwareUnsupportedOperationError");
155 jack_log("error code : unknown");
160 OSStatus
JackCoreAudioAdapter::SRNotificationCallback(AudioDeviceID inDevice
,
163 AudioDevicePropertyID inPropertyID
,
166 JackCoreAudioAdapter
* driver
= static_cast<JackCoreAudioAdapter
*>(inClientData
);
168 switch (inPropertyID
) {
170 case kAudioDevicePropertyNominalSampleRate
: {
171 jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
172 driver
->fState
= true;
180 // A better implementation would try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
181 OSStatus
JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice
,
184 AudioDevicePropertyID inPropertyID
,
188 switch (inPropertyID
) {
190 case kAudioDeviceProcessorOverload
: {
191 jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload");
195 case kAudioDevicePropertyStreamConfiguration
: {
196 jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration");
197 return kAudioHardwareUnsupportedOperationError
;
200 case kAudioDevicePropertyNominalSampleRate
: {
201 jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate");
202 return kAudioHardwareUnsupportedOperationError
;
209 int JackCoreAudioAdapter::AddListeners()
211 OSStatus err
= noErr
;
214 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDeviceProcessorOverload
, DeviceNotificationCallback
, this);
216 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
221 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioHardwarePropertyDevices
, DeviceNotificationCallback
, this);
223 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices");
228 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyNominalSampleRate
, DeviceNotificationCallback
, this);
230 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
235 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsRunning
, DeviceNotificationCallback
, this);
237 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
242 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
, this);
244 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
249 err
= AudioDeviceAddPropertyListener(fDeviceID
, 0, false, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
, this);
251 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
259 void JackCoreAudioAdapter::RemoveListeners()
261 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDeviceProcessorOverload
, DeviceNotificationCallback
);
262 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioHardwarePropertyDevices
, DeviceNotificationCallback
);
263 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyNominalSampleRate
, DeviceNotificationCallback
);
264 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyDeviceIsRunning
, DeviceNotificationCallback
);
265 AudioDeviceRemovePropertyListener(fDeviceID
, 0, true, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
);
266 AudioDeviceRemovePropertyListener(fDeviceID
, 0, false, kAudioDevicePropertyStreamConfiguration
, DeviceNotificationCallback
);
269 OSStatus
JackCoreAudioAdapter::Render(void *inRefCon
,
270 AudioUnitRenderActionFlags
*ioActionFlags
,
271 const AudioTimeStamp
*inTimeStamp
,
273 UInt32 inNumberFrames
,
274 AudioBufferList
*ioData
)
276 JackCoreAudioAdapter
* adapter
= static_cast<JackCoreAudioAdapter
*>(inRefCon
);
277 AudioUnitRender(adapter
->fAUHAL
, ioActionFlags
, inTimeStamp
, 1, inNumberFrames
, adapter
->fInputData
);
279 float* inputBuffer
[adapter
->fCaptureChannels
];
280 float* outputBuffer
[adapter
->fPlaybackChannels
];
282 for (int i
= 0; i
< adapter
->fCaptureChannels
; i
++) {
283 inputBuffer
[i
] = (float*)adapter
->fInputData
->mBuffers
[i
].mData
;
285 for (int i
= 0; i
< adapter
->fPlaybackChannels
; i
++) {
286 outputBuffer
[i
] = (float*)ioData
->mBuffers
[i
].mData
;
289 adapter
->PushAndPull((float**)inputBuffer
, (float**)outputBuffer
, inNumberFrames
);
293 JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size
, jack_nframes_t sample_rate
, const JSList
* params
)
294 :JackAudioAdapterInterface(buffer_size
, sample_rate
), fInputData(0), fCapturing(false), fPlaying(false), fState(false)
297 const jack_driver_param_t
* param
;
298 int in_nChannels
= 0;
299 int out_nChannels
= 0;
300 char captureName
[256];
301 char playbackName
[256];
304 fClockDriftCompensate
= false;
307 fCaptureChannels
= -1;
308 fPlaybackChannels
= -1;
312 Gestalt(gestaltSystemVersionMajor
, &major
);
313 Gestalt(gestaltSystemVersionMinor
, &minor
);
315 // Starting with 10.6 systems, the HAL notification thread is created internally
316 if (major
== 10 && minor
>= 6) {
317 CFRunLoopRef theRunLoop
= NULL
;
318 AudioObjectPropertyAddress theAddress
= { kAudioHardwarePropertyRunLoop
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
319 OSStatus theError
= AudioObjectSetPropertyData (kAudioObjectSystemObject
, &theAddress
, 0, NULL
, sizeof(CFRunLoopRef
), &theRunLoop
);
320 if (theError
!= noErr
) {
321 jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error");
325 for (node
= params
; node
; node
= jack_slist_next(node
)) {
326 param
= (const jack_driver_param_t
*) node
->data
;
328 switch (param
->character
) {
331 fCaptureChannels
= fPlaybackChannels
= param
->value
.ui
;
335 fCaptureChannels
= param
->value
.ui
;
339 fPlaybackChannels
= param
->value
.ui
;
344 strncpy(fCaptureUID
, param
->value
.str
, 256);
349 strncpy(fPlaybackUID
, param
->value
.str
, 256);
353 strncpy(fCaptureUID
, param
->value
.str
, 256);
354 strncpy(fPlaybackUID
, param
->value
.str
, 256);
358 fCapturing
= fPlaying
= true;
362 SetAdaptedSampleRate(param
->value
.ui
);
366 SetAdaptedBufferSize(param
->value
.ui
);
370 DisplayDeviceNames();
374 fQuality
= param
->value
.ui
;
378 fRingbufferCurSize
= param
->value
.ui
;
383 fClockDriftCompensate
= true;
388 /* duplex is the default */
389 if (!fCapturing
&& !fPlaying
) {
394 if (SetupDevices(fCaptureUID
, fPlaybackUID
, captureName
, playbackName
, fAdaptedSampleRate
) < 0)
397 if (SetupChannels(fCapturing
, fPlaying
, fCaptureChannels
, fPlaybackChannels
, in_nChannels
, out_nChannels
, true) < 0)
400 if (SetupBufferSize(fAdaptedBufferSize
) < 0)
403 if (SetupSampleRate(fAdaptedSampleRate
) < 0)
406 if (OpenAUHAL(fCapturing
, fPlaying
, fCaptureChannels
, fPlaybackChannels
, in_nChannels
, out_nChannels
, fAdaptedBufferSize
, fAdaptedSampleRate
) < 0)
409 if (fCapturing
&& fCaptureChannels
> 0)
410 if (SetupBuffers(fCaptureChannels
) < 0)
413 if (AddListeners() < 0)
417 OSStatus
JackCoreAudioAdapter::GetDefaultDevice(AudioDeviceID
* id
)
420 UInt32 theSize
= sizeof(UInt32
);
421 AudioDeviceID inDefault
;
422 AudioDeviceID outDefault
;
424 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
, &theSize
, &inDefault
)) != noErr
)
427 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
, &theSize
, &outDefault
)) != noErr
)
430 jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault
, outDefault
);
432 // Get the device only if default input and output are the same
433 if (inDefault
== outDefault
) {
437 jack_error("Default input and output devices are not the same !!");
438 return kAudioHardwareBadDeviceError
;
442 OSStatus
JackCoreAudioAdapter::GetTotalChannels(AudioDeviceID device
, int& channelCount
, bool isInput
)
444 OSStatus err
= noErr
;
447 AudioBufferList
* bufferList
= 0;
450 err
= AudioDeviceGetPropertyInfo(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize
, &outWritable
);
452 bufferList
= (AudioBufferList
*)malloc(outSize
);
453 err
= AudioDeviceGetProperty(device
, 0, isInput
, kAudioDevicePropertyStreamConfiguration
, &outSize
, bufferList
);
455 for (unsigned int i
= 0; i
< bufferList
->mNumberBuffers
; i
++)
456 channelCount
+= bufferList
->mBuffers
[i
].mNumberChannels
;
466 OSStatus
JackCoreAudioAdapter::GetDeviceIDFromUID(const char* UID
, AudioDeviceID
* id
)
468 UInt32 size
= sizeof(AudioValueTranslation
);
469 CFStringRef inIUD
= CFStringCreateWithCString(NULL
, UID
, CFStringGetSystemEncoding());
470 AudioValueTranslation value
= { &inIUD
, sizeof(CFStringRef
), id
, sizeof(AudioDeviceID
) };
473 return kAudioHardwareUnspecifiedError
;
475 OSStatus res
= AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID
, &size
, &value
);
477 jack_log("GetDeviceIDFromUID %s %ld", UID
, *id
);
478 return (*id
== kAudioDeviceUnknown
) ? kAudioHardwareBadDeviceError
: res
;
482 OSStatus
JackCoreAudioAdapter::GetDefaultInputDevice(AudioDeviceID
* id
)
485 UInt32 theSize
= sizeof(UInt32
);
486 AudioDeviceID inDefault
;
488 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
, &theSize
, &inDefault
)) != noErr
)
491 jack_log("GetDefaultInputDevice: input = %ld ", inDefault
);
496 OSStatus
JackCoreAudioAdapter::GetDefaultOutputDevice(AudioDeviceID
* id
)
499 UInt32 theSize
= sizeof(UInt32
);
500 AudioDeviceID outDefault
;
502 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
, &theSize
, &outDefault
)) != noErr
)
505 jack_log("GetDefaultOutputDevice: output = %ld", outDefault
);
510 OSStatus
JackCoreAudioAdapter::GetDeviceNameFromID(AudioDeviceID id
, char* name
)
513 return AudioDeviceGetProperty(id
, 0, false, kAudioDevicePropertyDeviceName
, &size
, name
);
517 int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid
,
518 const char* playback_driver_uid
,
519 char* capture_driver_name
,
520 char* playback_driver_name
,
521 jack_nframes_t samplerate
)
523 capture_driver_name
[0] = 0;
524 playback_driver_name
[0] = 0;
527 if (strcmp(capture_driver_uid
, "") != 0 && strcmp(playback_driver_uid
, "") != 0) {
529 // Same device for capture and playback...
530 if (strcmp(capture_driver_uid
, playback_driver_uid
) == 0) {
532 if (GetDeviceIDFromUID(playback_driver_uid
, &fDeviceID
) != noErr
) {
533 jack_log("Will take default in/out");
534 if (GetDefaultDevice(&fDeviceID
) != noErr
) {
535 jack_error("Cannot open default device");
539 if (GetDeviceNameFromID(fDeviceID
, capture_driver_name
) != noErr
|| GetDeviceNameFromID(fDeviceID
, playback_driver_name
) != noErr
) {
540 jack_error("Cannot get device name from device ID");
546 // Creates aggregate device
547 AudioDeviceID captureID
, playbackID
;
548 if (GetDeviceIDFromUID(capture_driver_uid
, &captureID
) != noErr
)
550 if (GetDeviceIDFromUID(playback_driver_uid
, &playbackID
) != noErr
)
552 if (CreateAggregateDevice(captureID
, playbackID
, samplerate
, &fDeviceID
) != noErr
)
557 } else if (strcmp(capture_driver_uid
, "") != 0) {
558 jack_log("JackCoreAudioAdapter::Open capture only");
559 if (GetDeviceIDFromUID(capture_driver_uid
, &fDeviceID
) != noErr
) {
560 if (GetDefaultInputDevice(&fDeviceID
) != noErr
) {
561 jack_error("Cannot open default device");
565 if (GetDeviceNameFromID(fDeviceID
, capture_driver_name
) != noErr
) {
566 jack_error("Cannot get device name from device ID");
571 } else if (strcmp(playback_driver_uid
, "") != 0) {
572 jack_log("JackCoreAudioAdapter::Open playback only");
573 if (GetDeviceIDFromUID(playback_driver_uid
, &fDeviceID
) != noErr
) {
574 if (GetDefaultOutputDevice(&fDeviceID
) != noErr
) {
575 jack_error("Cannot open default device");
579 if (GetDeviceNameFromID(fDeviceID
, playback_driver_name
) != noErr
) {
580 jack_error("Cannot get device name from device ID");
584 // Use default driver in duplex mode
586 jack_log("JackCoreAudioAdapter::Open default driver");
587 if (GetDefaultDevice(&fDeviceID
) != noErr
) {
588 jack_error("Cannot open default device");
591 if (GetDeviceNameFromID(fDeviceID
, capture_driver_name
) != noErr
|| GetDeviceNameFromID(fDeviceID
, playback_driver_name
) != noErr
) {
592 jack_error("Cannot get device name from device ID");
600 int JackCoreAudioAdapter::SetupChannels(bool capturing
,
608 OSStatus err
= noErr
;
611 err
= GetTotalChannels(fDeviceID
, in_nChannels
, true);
613 jack_error("Cannot get input channel number");
617 jack_log("Max input channels : %d", in_nChannels
);
622 err
= GetTotalChannels(fDeviceID
, out_nChannels
, false);
624 jack_error("Cannot get output channel number");
628 jack_log("Max output channels : %d", out_nChannels
);
632 if (inchannels
> in_nChannels
) {
633 jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels
, in_nChannels
);
638 if (outchannels
> out_nChannels
) {
639 jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels
, out_nChannels
);
644 if (inchannels
== -1) {
645 jack_log("Setup max in channels = %ld", in_nChannels
);
646 inchannels
= in_nChannels
;
649 if (outchannels
== -1) {
650 jack_log("Setup max out channels = %ld", out_nChannels
);
651 outchannels
= out_nChannels
;
657 int JackCoreAudioAdapter::SetupBufferSize(jack_nframes_t buffer_size
)
659 // Setting buffer size
660 UInt32 outSize
= sizeof(UInt32
);
661 OSStatus err
= AudioDeviceSetProperty(fDeviceID
, NULL
, 0, false, kAudioDevicePropertyBufferFrameSize
, outSize
, &buffer_size
);
663 jack_error("Cannot set buffer size %ld", buffer_size
);
671 int JackCoreAudioAdapter::SetupSampleRate(jack_nframes_t samplerate
)
673 return SetupSampleRateAux(fDeviceID
, samplerate
);
676 int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice
, jack_nframes_t samplerate
)
678 OSStatus err
= noErr
;
683 outSize
= sizeof(Float64
);
684 err
= AudioDeviceGetProperty(inDevice
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, &outSize
, &sampleRate
);
686 jack_error("Cannot get current sample rate");
691 // If needed, set new sample rate
692 if (samplerate
!= (jack_nframes_t
)sampleRate
) {
693 sampleRate
= (Float64
)samplerate
;
695 // To get SR change notification
696 err
= AudioDeviceAddPropertyListener(inDevice
, 0, true, kAudioDevicePropertyNominalSampleRate
, SRNotificationCallback
, this);
698 jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
702 err
= AudioDeviceSetProperty(inDevice
, NULL
, 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyNominalSampleRate
, outSize
, &sampleRate
);
704 jack_error("Cannot set sample rate = %ld", samplerate
);
709 // Waiting for SR change notification
711 while (!fState
&& count
++ < WAIT_COUNTER
) {
713 jack_log("Wait count = %d", count
);
716 // Remove SR change notification
717 AudioDeviceRemovePropertyListener(inDevice
, 0, true, kAudioDevicePropertyNominalSampleRate
, SRNotificationCallback
);
723 int JackCoreAudioAdapter::SetupBuffers(int inchannels
)
725 jack_log("JackCoreAudioAdapter::SetupBuffers: input = %ld", inchannels
);
728 fInputData
= (AudioBufferList
*)malloc(sizeof(UInt32
) + inchannels
* sizeof(AudioBuffer
));
729 fInputData
->mNumberBuffers
= inchannels
;
730 for (int i
= 0; i
< fCaptureChannels
; i
++) {
731 fInputData
->mBuffers
[i
].mNumberChannels
= 1;
732 fInputData
->mBuffers
[i
].mDataByteSize
= fAdaptedBufferSize
* sizeof(float);
733 fInputData
->mBuffers
[i
].mData
= malloc(fAdaptedBufferSize
* sizeof(float));
738 void JackCoreAudioAdapter::DisposeBuffers()
741 for (int i
= 0; i
< fCaptureChannels
; i
++)
742 free(fInputData
->mBuffers
[i
].mData
);
748 int JackCoreAudioAdapter::OpenAUHAL(bool capturing
,
754 jack_nframes_t buffer_size
,
755 jack_nframes_t samplerate
)
757 ComponentResult err1
;
759 AudioStreamBasicDescription srcFormat
, dstFormat
;
760 AudioDeviceID currAudioDeviceID
;
763 jack_log("OpenAUHAL capturing = %d playing = %d inchannels = %d outchannels = %d in_nChannels = %d out_nChannels = %d", capturing
, playing
, inchannels
, outchannels
, in_nChannels
, out_nChannels
);
765 if (inchannels
== 0 && outchannels
== 0) {
766 jack_error("No input and output channels...");
771 ComponentDescription cd
= {kAudioUnitType_Output
, kAudioUnitSubType_HALOutput
, kAudioUnitManufacturer_Apple
, 0, 0};
772 Component HALOutput
= FindNextComponent(NULL
, &cd
);
774 err1
= OpenAComponent(HALOutput
, &fAUHAL
);
776 jack_error("Error calling OpenAComponent");
781 err1
= AudioUnitInitialize(fAUHAL
);
783 jack_error("Cannot initialize AUHAL unit");
789 if (capturing
&& inchannels
> 0) {
791 jack_log("Setup AUHAL input on");
794 jack_log("Setup AUHAL input off");
797 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Input
, 1, &enableIO
, sizeof(enableIO
));
799 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
804 if (playing
&& outchannels
> 0) {
806 jack_log("Setup AUHAL output on");
809 jack_log("Setup AUHAL output off");
812 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Output
, 0, &enableIO
, sizeof(enableIO
));
814 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
819 size
= sizeof(AudioDeviceID
);
820 err1
= AudioUnitGetProperty(fAUHAL
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &currAudioDeviceID
, &size
);
822 jack_error("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice");
826 jack_log("AudioUnitGetPropertyCurrentDevice = %d", currAudioDeviceID
);
829 // Setup up choosen device, in both input and output cases
830 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &fDeviceID
, sizeof(AudioDeviceID
));
832 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
838 if (capturing
&& inchannels
> 0) {
839 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Global
, 1, (UInt32
*)&buffer_size
, sizeof(UInt32
));
841 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
847 if (playing
&& outchannels
> 0) {
848 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Global
, 0, (UInt32
*)&buffer_size
, sizeof(UInt32
));
850 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
857 if (capturing
&& inchannels
> 0 && inchannels
< in_nChannels
) {
858 SInt32 chanArr
[in_nChannels
];
859 for (int i
= 0; i
< in_nChannels
; i
++) {
862 for (int i
= 0; i
< inchannels
; i
++) {
865 AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Input
, 1, chanArr
, sizeof(SInt32
) * in_nChannels
);
867 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
873 if (playing
&& outchannels
> 0 && outchannels
< out_nChannels
) {
874 SInt32 chanArr
[out_nChannels
];
875 for (int i
= 0; i
< out_nChannels
; i
++) {
878 for (int i
= 0; i
< outchannels
; i
++) {
881 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Output
, 0, chanArr
, sizeof(SInt32
) * out_nChannels
);
883 jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
889 // Setup stream converters
890 if (capturing
&& inchannels
> 0) {
892 size
= sizeof(AudioStreamBasicDescription
);
893 err1
= AudioUnitGetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 0, &srcFormat
, &size
);
895 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
899 PrintStreamDesc(&srcFormat
);
901 jack_log("Setup AUHAL input stream converter SR = %ld", samplerate
);
902 srcFormat
.mSampleRate
= samplerate
;
903 srcFormat
.mFormatID
= kAudioFormatLinearPCM
;
904 srcFormat
.mFormatFlags
= kAudioFormatFlagsNativeFloatPacked
| kLinearPCMFormatFlagIsNonInterleaved
;
905 srcFormat
.mBytesPerPacket
= sizeof(float);
906 srcFormat
.mFramesPerPacket
= 1;
907 srcFormat
.mBytesPerFrame
= sizeof(float);
908 srcFormat
.mChannelsPerFrame
= inchannels
;
909 srcFormat
.mBitsPerChannel
= 32;
910 PrintStreamDesc(&srcFormat
);
912 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &srcFormat
, sizeof(AudioStreamBasicDescription
));
915 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
921 if (playing
&& outchannels
> 0) {
923 size
= sizeof(AudioStreamBasicDescription
);
924 err1
= AudioUnitGetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 1, &dstFormat
, &size
);
926 jack_error("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
930 PrintStreamDesc(&dstFormat
);
932 jack_log("Setup AUHAL output stream converter SR = %ld", samplerate
);
933 dstFormat
.mSampleRate
= samplerate
;
934 dstFormat
.mFormatID
= kAudioFormatLinearPCM
;
935 dstFormat
.mFormatFlags
= kAudioFormatFlagsNativeFloatPacked
| kLinearPCMFormatFlagIsNonInterleaved
;
936 dstFormat
.mBytesPerPacket
= sizeof(float);
937 dstFormat
.mFramesPerPacket
= 1;
938 dstFormat
.mBytesPerFrame
= sizeof(float);
939 dstFormat
.mChannelsPerFrame
= outchannels
;
940 dstFormat
.mBitsPerChannel
= 32;
941 PrintStreamDesc(&dstFormat
);
943 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &dstFormat
, sizeof(AudioStreamBasicDescription
));
946 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
953 if (inchannels
> 0 && outchannels
== 0) {
954 AURenderCallbackStruct output
;
955 output
.inputProc
= Render
;
956 output
.inputProcRefCon
= this;
957 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_SetInputCallback
, kAudioUnitScope_Global
, 0, &output
, sizeof(output
));
959 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
964 AURenderCallbackStruct output
;
965 output
.inputProc
= Render
;
966 output
.inputProcRefCon
= this;
967 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_SetRenderCallback
, kAudioUnitScope_Input
, 0, &output
, sizeof(output
));
969 jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
982 OSStatus
JackCoreAudioAdapter::DestroyAggregateDevice()
984 OSStatus osErr
= noErr
;
985 AudioObjectPropertyAddress pluginAOPA
;
986 pluginAOPA
.mSelector
= kAudioPlugInDestroyAggregateDevice
;
987 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
988 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
991 osErr
= AudioObjectGetPropertyDataSize(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
);
992 if (osErr
!= noErr
) {
993 jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
998 osErr
= AudioObjectGetPropertyData(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
, &fDeviceID
);
999 if (osErr
!= noErr
) {
1000 jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error");
1008 static CFStringRef
GetDeviceName(AudioDeviceID id
)
1010 UInt32 size
= sizeof(CFStringRef
);
1012 OSStatus err
= AudioDeviceGetProperty(id
, 0, false, kAudioDevicePropertyDeviceUID
, &size
, &UIname
);
1013 return (err
== noErr
) ? UIname
: NULL
;
1016 OSStatus
JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID
, AudioDeviceID playbackDeviceID
, jack_nframes_t samplerate
, AudioDeviceID
* outAggregateDevice
)
1018 OSStatus err
= noErr
;
1019 AudioObjectID sub_device
[32];
1020 UInt32 outSize
= sizeof(sub_device
);
1022 err
= AudioDeviceGetProperty(captureDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
1023 vector
<AudioDeviceID
> captureDeviceIDArray
;
1026 jack_log("Input device does not have subdevices");
1027 captureDeviceIDArray
.push_back(captureDeviceID
);
1029 int num_devices
= outSize
/ sizeof(AudioObjectID
);
1030 jack_log("Input device has %d subdevices", num_devices
);
1031 for (int i
= 0; i
< num_devices
; i
++) {
1032 captureDeviceIDArray
.push_back(sub_device
[i
]);
1036 err
= AudioDeviceGetProperty(playbackDeviceID
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
1037 vector
<AudioDeviceID
> playbackDeviceIDArray
;
1040 jack_log("Output device does not have subdevices");
1041 playbackDeviceIDArray
.push_back(playbackDeviceID
);
1043 int num_devices
= outSize
/ sizeof(AudioObjectID
);
1044 jack_log("Output device has %d subdevices", num_devices
);
1045 for (int i
= 0; i
< num_devices
; i
++) {
1046 playbackDeviceIDArray
.push_back(sub_device
[i
]);
1050 return CreateAggregateDeviceAux(captureDeviceIDArray
, playbackDeviceIDArray
, samplerate
, outAggregateDevice
);
1053 OSStatus
JackCoreAudioAdapter::CreateAggregateDeviceAux(vector
<AudioDeviceID
> captureDeviceID
, vector
<AudioDeviceID
> playbackDeviceID
, jack_nframes_t samplerate
, AudioDeviceID
* outAggregateDevice
)
1055 OSStatus osErr
= noErr
;
1057 Boolean outWritable
;
1059 // Prepare sub-devices for clock drift compensation
1060 // Workaround for bug in the HAL : until 10.6.2
1061 AudioObjectPropertyAddress theAddressOwned
= { kAudioObjectPropertyOwnedObjects
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
1062 AudioObjectPropertyAddress theAddressDrift
= { kAudioSubDevicePropertyDriftCompensation
, kAudioObjectPropertyScopeGlobal
, kAudioObjectPropertyElementMaster
};
1063 UInt32 theQualifierDataSize
= sizeof(AudioObjectID
);
1064 AudioClassID inClass
= kAudioSubDeviceClassID
;
1065 void* theQualifierData
= &inClass
;
1066 UInt32 subDevicesNum
= 0;
1068 //---------------------------------------------------------------------------
1069 // Setup SR of both devices otherwise creating AD may fail...
1070 //---------------------------------------------------------------------------
1071 UInt32 keptclockdomain
= 0;
1072 UInt32 clockdomain
= 0;
1073 outSize
= sizeof(UInt32
);
1074 bool need_clock_drift_compensation
= false;
1076 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
1077 if (SetupSampleRateAux(captureDeviceID
[i
], samplerate
) < 0) {
1078 jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device");
1080 // Check clock domain
1081 osErr
= AudioDeviceGetProperty(captureDeviceID
[i
], 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyClockDomain
, &outSize
, &clockdomain
);
1083 jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
1086 keptclockdomain
= (keptclockdomain
== 0) ? clockdomain
: keptclockdomain
;
1087 jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain
);
1088 if (clockdomain
!= 0 && clockdomain
!= keptclockdomain
) {
1089 jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
1090 need_clock_drift_compensation
= true;
1096 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
1097 if (SetupSampleRateAux(playbackDeviceID
[i
], samplerate
) < 0) {
1098 jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device");
1100 // Check clock domain
1101 osErr
= AudioDeviceGetProperty(playbackDeviceID
[i
], 0, kAudioDeviceSectionGlobal
, kAudioDevicePropertyClockDomain
, &outSize
, &clockdomain
);
1103 jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
1106 keptclockdomain
= (keptclockdomain
== 0) ? clockdomain
: keptclockdomain
;
1107 jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain
);
1108 if (clockdomain
!= 0 && clockdomain
!= keptclockdomain
) {
1109 jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
1110 need_clock_drift_compensation
= true;
1116 // If no valid clock domain was found, then assume we have to compensate...
1117 if (keptclockdomain
== 0) {
1118 need_clock_drift_compensation
= true;
1121 //---------------------------------------------------------------------------
1122 // Start to create a new aggregate by getting the base audio hardware plugin
1123 //---------------------------------------------------------------------------
1125 char device_name
[256];
1126 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
1127 GetDeviceNameFromID(captureDeviceID
[i
], device_name
);
1128 jack_info("Separated input = '%s' ", device_name
);
1131 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
1132 GetDeviceNameFromID(playbackDeviceID
[i
], device_name
);
1133 jack_info("Separated output = '%s' ", device_name
);
1136 osErr
= AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID
, &outSize
, &outWritable
);
1137 if (osErr
!= noErr
) {
1138 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
1143 AudioValueTranslation pluginAVT
;
1145 CFStringRef inBundleRef
= CFSTR("com.apple.audio.CoreAudio");
1147 pluginAVT
.mInputData
= &inBundleRef
;
1148 pluginAVT
.mInputDataSize
= sizeof(inBundleRef
);
1149 pluginAVT
.mOutputData
= &fPluginID
;
1150 pluginAVT
.mOutputDataSize
= sizeof(fPluginID
);
1152 osErr
= AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID
, &outSize
, &pluginAVT
);
1153 if (osErr
!= noErr
) {
1154 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
1159 //-------------------------------------------------
1160 // Create a CFDictionary for our aggregate device
1161 //-------------------------------------------------
1163 CFMutableDictionaryRef aggDeviceDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1165 CFStringRef AggregateDeviceNameRef
= CFSTR("JackDuplex");
1166 CFStringRef AggregateDeviceUIDRef
= CFSTR("com.grame.JackDuplex");
1168 // add the name of the device to the dictionary
1169 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceNameKey
), AggregateDeviceNameRef
);
1171 // add our choice of UID for the aggregate device to the dictionary
1172 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceUIDKey
), AggregateDeviceUIDRef
);
1174 // add a "private aggregate key" to the dictionary
1176 CFNumberRef AggregateDeviceNumberRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &value
);
1179 Gestalt(gestaltSystemVersion
, &system
);
1181 jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system
, 0x00001054);
1183 // Starting with 10.5.4 systems, the AD can be internal... (better)
1184 if (system
< 0x00001054) {
1185 jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device....");
1187 jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device....");
1188 CFDictionaryAddValue(aggDeviceDict
, CFSTR(kAudioAggregateDeviceIsPrivateKey
), AggregateDeviceNumberRef
);
1191 // Prepare sub-devices for clock drift compensation
1192 CFMutableArrayRef subDevicesArrayClock
= NULL
;
1195 if (fClockDriftCompensate) {
1196 if (need_clock_drift_compensation) {
1197 jack_info("Clock drift compensation activated...");
1198 subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1200 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
1201 CFStringRef UID = GetDeviceName(captureDeviceID[i]);
1203 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1204 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
1205 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
1207 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
1211 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
1212 CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
1214 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1215 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
1216 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
1218 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
1222 // add sub-device clock array for the aggregate device to the dictionary
1223 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
1225 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
1230 //-------------------------------------------------
1231 // Create a CFMutableArray for our sub-device list
1232 //-------------------------------------------------
1234 // we need to append the UID for each device to a CFMutableArray, so create one here
1235 CFMutableArrayRef subDevicesArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1237 vector
<CFStringRef
> captureDeviceUID
;
1238 for (UInt32 i
= 0; i
< captureDeviceID
.size(); i
++) {
1239 CFStringRef ref
= GetDeviceName(captureDeviceID
[i
]);
1242 captureDeviceUID
.push_back(ref
);
1243 // input sub-devices in this example, so append the sub-device's UID to the CFArray
1244 CFArrayAppendValue(subDevicesArray
, ref
);
1247 vector
<CFStringRef
> playbackDeviceUID
;
1248 for (UInt32 i
= 0; i
< playbackDeviceID
.size(); i
++) {
1249 CFStringRef ref
= GetDeviceName(playbackDeviceID
[i
]);
1252 playbackDeviceUID
.push_back(ref
);
1253 // output sub-devices in this example, so append the sub-device's UID to the CFArray
1254 CFArrayAppendValue(subDevicesArray
, ref
);
1257 //-----------------------------------------------------------------------
1258 // Feed the dictionary to the plugin, to create a blank aggregate device
1259 //-----------------------------------------------------------------------
1261 AudioObjectPropertyAddress pluginAOPA
;
1262 pluginAOPA
.mSelector
= kAudioPlugInCreateAggregateDevice
;
1263 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1264 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1267 osErr
= AudioObjectGetPropertyDataSize(fPluginID
, &pluginAOPA
, 0, NULL
, &outDataSize
);
1268 if (osErr
!= noErr
) {
1269 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error");
1274 osErr
= AudioObjectGetPropertyData(fPluginID
, &pluginAOPA
, sizeof(aggDeviceDict
), &aggDeviceDict
, &outDataSize
, outAggregateDevice
);
1275 if (osErr
!= noErr
) {
1276 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error");
1281 // pause for a bit to make sure that everything completed correctly
1282 // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
1283 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1285 //-------------------------
1286 // Set the sub-device list
1287 //-------------------------
1289 pluginAOPA
.mSelector
= kAudioAggregateDevicePropertyFullSubDeviceList
;
1290 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1291 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1292 outDataSize
= sizeof(CFMutableArrayRef
);
1293 osErr
= AudioObjectSetPropertyData(*outAggregateDevice
, &pluginAOPA
, 0, NULL
, outDataSize
, &subDevicesArray
);
1294 if (osErr
!= noErr
) {
1295 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error");
1300 // pause again to give the changes time to take effect
1301 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1303 //-----------------------
1304 // Set the master device
1305 //-----------------------
1307 // set the master device manually (this is the device which will act as the master clock for the aggregate device)
1308 // pass in the UID of the device you want to use
1309 pluginAOPA
.mSelector
= kAudioAggregateDevicePropertyMasterSubDevice
;
1310 pluginAOPA
.mScope
= kAudioObjectPropertyScopeGlobal
;
1311 pluginAOPA
.mElement
= kAudioObjectPropertyElementMaster
;
1312 outDataSize
= sizeof(CFStringRef
);
1313 osErr
= AudioObjectSetPropertyData(*outAggregateDevice
, &pluginAOPA
, 0, NULL
, outDataSize
, &captureDeviceUID
[0]); // First apture is master...
1314 if (osErr
!= noErr
) {
1315 jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for master device error");
1320 // pause again to give the changes time to take effect
1321 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1323 // Prepare sub-devices for clock drift compensation
1324 // Workaround for bug in the HAL : until 10.6.2
1326 if (fClockDriftCompensate
) {
1327 if (need_clock_drift_compensation
) {
1328 jack_info("Clock drift compensation activated...");
1330 // Get the property data size
1331 osErr
= AudioObjectGetPropertyDataSize(*outAggregateDevice
, &theAddressOwned
, theQualifierDataSize
, theQualifierData
, &outSize
);
1332 if (osErr
!= noErr
) {
1333 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
1337 // Calculate the number of object IDs
1338 subDevicesNum
= outSize
/ sizeof(AudioObjectID
);
1339 jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum
);
1340 AudioObjectID subDevices
[subDevicesNum
];
1341 outSize
= sizeof(subDevices
);
1343 osErr
= AudioObjectGetPropertyData(*outAggregateDevice
, &theAddressOwned
, theQualifierDataSize
, theQualifierData
, &outSize
, subDevices
);
1344 if (osErr
!= noErr
) {
1345 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
1349 // Set kAudioSubDevicePropertyDriftCompensation property...
1350 for (UInt32 index
= 0; index
< subDevicesNum
; ++index
) {
1351 UInt32 theDriftCompensationValue
= 1;
1352 osErr
= AudioObjectSetPropertyData(subDevices
[index
], &theAddressDrift
, 0, NULL
, sizeof(UInt32
), &theDriftCompensationValue
);
1353 if (osErr
!= noErr
) {
1354 jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error");
1359 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
1363 // pause again to give the changes time to take effect
1364 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.1, false);
1370 // release the private AD key
1371 CFRelease(AggregateDeviceNumberRef
);
1373 // release the CF objects we have created - we don't need them any more
1374 CFRelease(aggDeviceDict
);
1375 CFRelease(subDevicesArray
);
1377 if (subDevicesArrayClock
)
1378 CFRelease(subDevicesArrayClock
);
1380 // release the device UID
1381 for (UInt32 i
= 0; i
< captureDeviceUID
.size(); i
++) {
1382 CFRelease(captureDeviceUID
[i
]);
1385 for (UInt32 i
= 0; i
< playbackDeviceUID
.size(); i
++) {
1386 CFRelease(playbackDeviceUID
[i
]);
1389 jack_log("New aggregate device %ld", *outAggregateDevice
);
1393 DestroyAggregateDevice();
1398 bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device
)
1400 OSStatus err
= noErr
;
1401 AudioObjectID sub_device
[32];
1402 UInt32 outSize
= sizeof(sub_device
);
1403 err
= AudioDeviceGetProperty(device
, 0, kAudioDeviceSectionGlobal
, kAudioAggregateDevicePropertyActiveSubDeviceList
, &outSize
, sub_device
);
1406 jack_log("Device does not have subdevices");
1409 int num_devices
= outSize
/ sizeof(AudioObjectID
);
1410 jack_log("Device does has %d subdevices", num_devices
);
1415 void JackCoreAudioAdapter::CloseAUHAL()
1417 AudioUnitUninitialize(fAUHAL
);
1418 CloseComponent(fAUHAL
);
1421 int JackCoreAudioAdapter::Open()
1423 return (AudioOutputUnitStart(fAUHAL
) != noErr
) ? -1 : 0;
1426 int JackCoreAudioAdapter::Close()
1429 fTable
.Save(fHostBufferSize
, fHostSampleRate
, fAdaptedSampleRate
, fAdaptedBufferSize
);
1431 AudioOutputUnitStop(fAUHAL
);
1436 DestroyAggregateDevice();
1440 int JackCoreAudioAdapter::SetSampleRate ( jack_nframes_t sample_rate
) {
1441 JackAudioAdapterInterface::SetHostSampleRate ( sample_rate
);
1446 int JackCoreAudioAdapter::SetBufferSize ( jack_nframes_t buffer_size
) {
1447 JackAudioAdapterInterface::SetHostBufferSize ( buffer_size
);
1459 SERVER_EXPORT jack_driver_desc_t
* jack_get_descriptor()
1461 jack_driver_desc_t
*desc
;
1463 desc
= (jack_driver_desc_t
*)calloc(1, sizeof(jack_driver_desc_t
));
1465 strcpy(desc
->name
, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
1466 strcpy(desc
->desc
, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
1469 desc
->params
= (jack_driver_param_desc_t
*)calloc(desc
->nparams
, sizeof(jack_driver_param_desc_t
));
1472 strcpy(desc
->params
[i
].name
, "channels");
1473 desc
->params
[i
].character
= 'c';
1474 desc
->params
[i
].type
= JackDriverParamInt
;
1475 desc
->params
[i
].value
.ui
= -1;
1476 strcpy(desc
->params
[i
].short_desc
, "Maximum number of channels");
1477 strcpy(desc
->params
[i
].long_desc
, "Maximum number of channels. If -1, max possible number of channels will be used");
1480 strcpy(desc
->params
[i
].name
, "inchannels");
1481 desc
->params
[i
].character
= 'i';
1482 desc
->params
[i
].type
= JackDriverParamInt
;
1483 desc
->params
[i
].value
.ui
= -1;
1484 strcpy(desc
->params
[i
].short_desc
, "Maximum number of input channels");
1485 strcpy(desc
->params
[i
].long_desc
, "Maximum number of input channels. If -1, max possible number of input channels will be used");
1488 strcpy(desc
->params
[i
].name
, "outchannels");
1489 desc
->params
[i
].character
= 'o';
1490 desc
->params
[i
].type
= JackDriverParamInt
;
1491 desc
->params
[i
].value
.ui
= -1;
1492 strcpy(desc
->params
[i
].short_desc
, "Maximum number of output channels");
1493 strcpy(desc
->params
[i
].long_desc
, "Maximum number of output channels. If -1, max possible number of output channels will be used");
1496 strcpy(desc
->params
[i
].name
, "capture");
1497 desc
->params
[i
].character
= 'C';
1498 desc
->params
[i
].type
= JackDriverParamString
;
1499 strcpy(desc
->params
[i
].value
.str
, "will take default CoreAudio input device");
1500 strcpy(desc
->params
[i
].short_desc
, "Provide capture ports. Optionally set CoreAudio device name");
1501 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
1504 strcpy(desc
->params
[i
].name
, "playback");
1505 desc
->params
[i
].character
= 'P';
1506 desc
->params
[i
].type
= JackDriverParamString
;
1507 strcpy(desc
->params
[i
].value
.str
, "will take default CoreAudio output device");
1508 strcpy(desc
->params
[i
].short_desc
, "Provide playback ports. Optionally set CoreAudio device name");
1509 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
1512 strcpy(desc
->params
[i
].name
, "rate");
1513 desc
->params
[i
].character
= 'r';
1514 desc
->params
[i
].type
= JackDriverParamUInt
;
1515 desc
->params
[i
].value
.ui
= 44100U;
1516 strcpy(desc
->params
[i
].short_desc
, "Sample rate");
1517 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
1520 strcpy(desc
->params
[i
].name
, "periodsize");
1521 desc
->params
[i
].character
= 'p';
1522 desc
->params
[i
].type
= JackDriverParamUInt
;
1523 desc
->params
[i
].value
.ui
= 512U;
1524 strcpy(desc
->params
[i
].short_desc
, "Period size");
1525 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
1528 strcpy(desc
->params
[i
].name
, "duplex");
1529 desc
->params
[i
].character
= 'D';
1530 desc
->params
[i
].type
= JackDriverParamBool
;
1531 desc
->params
[i
].value
.i
= TRUE
;
1532 strcpy(desc
->params
[i
].short_desc
, "Provide both capture and playback ports");
1533 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
1536 strcpy(desc
->params
[i
].name
, "device");
1537 desc
->params
[i
].character
= 'd';
1538 desc
->params
[i
].type
= JackDriverParamString
;
1539 strcpy(desc
->params
[i
].value
.str
, "will take default CoreAudio device name");
1540 strcpy(desc
->params
[i
].short_desc
, "CoreAudio device name");
1541 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
1544 strcpy(desc
->params
[i
].name
, "list-devices");
1545 desc
->params
[i
].character
= 'l';
1546 desc
->params
[i
].type
= JackDriverParamBool
;
1547 desc
->params
[i
].value
.i
= TRUE
;
1548 strcpy(desc
->params
[i
].short_desc
, "Display available CoreAudio devices");
1549 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
1552 strcpy(desc
->params
[i
].name
, "quality");
1553 desc
->params
[i
].character
= 'q';
1554 desc
->params
[i
].type
= JackDriverParamInt
;
1555 desc
->params
[i
].value
.ui
= 0;
1556 strcpy(desc
->params
[i
].short_desc
, "Resample algorithm quality (0 - 4)");
1557 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
1560 strcpy(desc
->params
[i
].name
, "ring-buffer");
1561 desc
->params
[i
].character
= 'g';
1562 desc
->params
[i
].type
= JackDriverParamInt
;
1563 desc
->params
[i
].value
.ui
= 32768;
1564 strcpy(desc
->params
[i
].short_desc
, "Fixed ringbuffer size");
1565 strcpy(desc
->params
[i
].long_desc
, "Fixed ringbuffer size (if not set => automatic adaptative)");
1568 strcpy(desc
->params
[i
].name
, "clock-drift");
1569 desc
->params
[i
].character
= 's';
1570 desc
->params
[i
].type
= JackDriverParamBool
;
1571 desc
->params
[i
].value
.i
= FALSE
;
1572 strcpy(desc
->params
[i
].short_desc
, "Clock drift compensation");
1573 strcpy(desc
->params
[i
].long_desc
, "Whether to compensate clock drift in dynamically created aggregate device");