2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
23 #include "backends/coreaudio.h"
31 #include "ringbuffer.h"
34 #include <AudioUnit/AudioUnit.h>
35 #include <AudioToolbox/AudioToolbox.h>
38 static const ALCchar ca_device
[] = "CoreAudio Default";
41 struct ALCcoreAudioPlayback final
: public ALCbackend
{
45 AudioStreamBasicDescription Format
; // This is the OpenAL format as a CoreAudio ASBD
48 static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback
*self
, ALCdevice
*device
);
49 static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback
*self
);
50 static ALCenum
ALCcoreAudioPlayback_open(ALCcoreAudioPlayback
*self
, const ALCchar
*name
);
51 static ALCboolean
ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback
*self
);
52 static ALCboolean
ALCcoreAudioPlayback_start(ALCcoreAudioPlayback
*self
);
53 static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback
*self
);
54 static DECLARE_FORWARD2(ALCcoreAudioPlayback
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
55 static DECLARE_FORWARD(ALCcoreAudioPlayback
, ALCbackend
, ALCuint
, availableSamples
)
56 static DECLARE_FORWARD(ALCcoreAudioPlayback
, ALCbackend
, ClockLatency
, getClockLatency
)
57 static DECLARE_FORWARD(ALCcoreAudioPlayback
, ALCbackend
, void, lock
)
58 static DECLARE_FORWARD(ALCcoreAudioPlayback
, ALCbackend
, void, unlock
)
59 DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback
)
61 DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback
);
64 static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback
*self
, ALCdevice
*device
)
66 new (self
) ALCcoreAudioPlayback
{};
67 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
68 SET_VTABLE2(ALCcoreAudioPlayback
, ALCbackend
, self
);
71 memset(&self
->Format
, 0, sizeof(self
->Format
));
74 static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback
*self
)
76 AudioUnitUninitialize(self
->AudioUnit
);
77 AudioComponentInstanceDispose(self
->AudioUnit
);
79 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
80 self
->~ALCcoreAudioPlayback();
84 static OSStatus
ALCcoreAudioPlayback_MixerProc(void *inRefCon
,
85 AudioUnitRenderActionFlags
* UNUSED(ioActionFlags
), const AudioTimeStamp
* UNUSED(inTimeStamp
),
86 UInt32
UNUSED(inBusNumber
), UInt32
UNUSED(inNumberFrames
), AudioBufferList
*ioData
)
88 ALCcoreAudioPlayback
*self
= static_cast<ALCcoreAudioPlayback
*>(inRefCon
);
89 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
91 ALCcoreAudioPlayback_lock(self
);
92 aluMixData(device
, ioData
->mBuffers
[0].mData
,
93 ioData
->mBuffers
[0].mDataByteSize
/ self
->FrameSize
);
94 ALCcoreAudioPlayback_unlock(self
);
100 static ALCenum
ALCcoreAudioPlayback_open(ALCcoreAudioPlayback
*self
, const ALCchar
*name
)
102 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
103 AudioComponentDescription desc
;
109 else if(strcmp(name
, ca_device
) != 0)
110 return ALC_INVALID_VALUE
;
112 /* open the default output unit */
113 desc
.componentType
= kAudioUnitType_Output
;
115 desc
.componentSubType
= kAudioUnitSubType_RemoteIO
;
117 desc
.componentSubType
= kAudioUnitSubType_DefaultOutput
;
119 desc
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
120 desc
.componentFlags
= 0;
121 desc
.componentFlagsMask
= 0;
123 comp
= AudioComponentFindNext(NULL
, &desc
);
126 ERR("AudioComponentFindNext failed\n");
127 return ALC_INVALID_VALUE
;
130 err
= AudioComponentInstanceNew(comp
, &self
->AudioUnit
);
133 ERR("AudioComponentInstanceNew failed\n");
134 return ALC_INVALID_VALUE
;
137 /* init and start the default audio unit... */
138 err
= AudioUnitInitialize(self
->AudioUnit
);
141 ERR("AudioUnitInitialize failed\n");
142 AudioComponentInstanceDispose(self
->AudioUnit
);
143 return ALC_INVALID_VALUE
;
146 device
->DeviceName
= name
;
150 static ALCboolean
ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback
*self
)
152 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
153 AudioStreamBasicDescription streamFormat
;
154 AURenderCallbackStruct input
;
158 err
= AudioUnitUninitialize(self
->AudioUnit
);
160 ERR("-- AudioUnitUninitialize failed.\n");
162 /* retrieve default output unit's properties (output side) */
163 size
= sizeof(AudioStreamBasicDescription
);
164 err
= AudioUnitGetProperty(self
->AudioUnit
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 0, &streamFormat
, &size
);
165 if(err
!= noErr
|| size
!= sizeof(AudioStreamBasicDescription
))
167 ERR("AudioUnitGetProperty failed\n");
172 TRACE("Output streamFormat of default output unit -\n");
173 TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat
.mFramesPerPacket
);
174 TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat
.mChannelsPerFrame
);
175 TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat
.mBitsPerChannel
);
176 TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat
.mBytesPerPacket
);
177 TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat
.mBytesPerFrame
);
178 TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat
.mSampleRate
);
181 /* set default output unit's input side to match output side */
182 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &streamFormat
, size
);
185 ERR("AudioUnitSetProperty failed\n");
189 if(device
->Frequency
!= streamFormat
.mSampleRate
)
191 device
->NumUpdates
= (ALuint
)((ALuint64
)device
->NumUpdates
*
192 streamFormat
.mSampleRate
/
194 device
->Frequency
= streamFormat
.mSampleRate
;
197 /* FIXME: How to tell what channels are what in the output device, and how
198 * to specify what we're giving? eg, 6.0 vs 5.1 */
199 switch(streamFormat
.mChannelsPerFrame
)
202 device
->FmtChans
= DevFmtMono
;
205 device
->FmtChans
= DevFmtStereo
;
208 device
->FmtChans
= DevFmtQuad
;
211 device
->FmtChans
= DevFmtX51
;
214 device
->FmtChans
= DevFmtX61
;
217 device
->FmtChans
= DevFmtX71
;
220 ERR("Unhandled channel count (%d), using Stereo\n", streamFormat
.mChannelsPerFrame
);
221 device
->FmtChans
= DevFmtStereo
;
222 streamFormat
.mChannelsPerFrame
= 2;
225 SetDefaultWFXChannelOrder(device
);
227 /* use channel count and sample rate from the default output unit's current
228 * parameters, but reset everything else */
229 streamFormat
.mFramesPerPacket
= 1;
230 streamFormat
.mFormatFlags
= 0;
231 switch(device
->FmtType
)
234 device
->FmtType
= DevFmtByte
;
237 streamFormat
.mFormatFlags
= kLinearPCMFormatFlagIsSignedInteger
;
238 streamFormat
.mBitsPerChannel
= 8;
241 device
->FmtType
= DevFmtShort
;
244 streamFormat
.mFormatFlags
= kLinearPCMFormatFlagIsSignedInteger
;
245 streamFormat
.mBitsPerChannel
= 16;
248 device
->FmtType
= DevFmtInt
;
251 streamFormat
.mFormatFlags
= kLinearPCMFormatFlagIsSignedInteger
;
252 streamFormat
.mBitsPerChannel
= 32;
255 streamFormat
.mFormatFlags
= kLinearPCMFormatFlagIsFloat
;
256 streamFormat
.mBitsPerChannel
= 32;
259 streamFormat
.mBytesPerFrame
= streamFormat
.mChannelsPerFrame
*
260 streamFormat
.mBitsPerChannel
/ 8;
261 streamFormat
.mBytesPerPacket
= streamFormat
.mBytesPerFrame
;
262 streamFormat
.mFormatID
= kAudioFormatLinearPCM
;
263 streamFormat
.mFormatFlags
|= kAudioFormatFlagsNativeEndian
|
264 kLinearPCMFormatFlagIsPacked
;
266 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &streamFormat
, sizeof(AudioStreamBasicDescription
));
269 ERR("AudioUnitSetProperty failed\n");
274 self
->FrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->mAmbiOrder
);
275 input
.inputProc
= ALCcoreAudioPlayback_MixerProc
;
276 input
.inputProcRefCon
= self
;
278 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioUnitProperty_SetRenderCallback
, kAudioUnitScope_Input
, 0, &input
, sizeof(AURenderCallbackStruct
));
281 ERR("AudioUnitSetProperty failed\n");
285 /* init the default audio unit... */
286 err
= AudioUnitInitialize(self
->AudioUnit
);
289 ERR("AudioUnitInitialize failed\n");
296 static ALCboolean
ALCcoreAudioPlayback_start(ALCcoreAudioPlayback
*self
)
298 OSStatus err
= AudioOutputUnitStart(self
->AudioUnit
);
301 ERR("AudioOutputUnitStart failed\n");
308 static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback
*self
)
310 OSStatus err
= AudioOutputUnitStop(self
->AudioUnit
);
312 ERR("AudioOutputUnitStop failed\n");
316 struct ALCcoreAudioCapture final
: public ALCbackend
{
320 ALdouble SampleRateRatio
; // Ratio of hardware sample rate / requested sample rate
321 AudioStreamBasicDescription Format
; // This is the OpenAL format as a CoreAudio ASBD
323 AudioConverterRef AudioConverter
; // Sample rate converter if needed
324 AudioBufferList
*BufferList
; // Buffer for data coming from the input device
325 ALCvoid
*ResampleBuffer
; // Buffer for returned RingBuffer data when resampling
327 ll_ringbuffer_t
*Ring
;
330 static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture
*self
, ALCdevice
*device
);
331 static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture
*self
);
332 static ALCenum
ALCcoreAudioCapture_open(ALCcoreAudioCapture
*self
, const ALCchar
*name
);
333 static DECLARE_FORWARD(ALCcoreAudioCapture
, ALCbackend
, ALCboolean
, reset
)
334 static ALCboolean
ALCcoreAudioCapture_start(ALCcoreAudioCapture
*self
);
335 static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture
*self
);
336 static ALCenum
ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
337 static ALCuint
ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture
*self
);
338 static DECLARE_FORWARD(ALCcoreAudioCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
339 static DECLARE_FORWARD(ALCcoreAudioCapture
, ALCbackend
, void, lock
)
340 static DECLARE_FORWARD(ALCcoreAudioCapture
, ALCbackend
, void, unlock
)
341 DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture
)
343 DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture
);
346 static AudioBufferList
*allocate_buffer_list(UInt32 channelCount
, UInt32 byteSize
)
348 AudioBufferList
*list
;
350 list
= static_cast<AudioBufferList
*>(calloc(1,
351 FAM_SIZE(AudioBufferList
, mBuffers
, 1) + byteSize
));
354 list
->mNumberBuffers
= 1;
356 list
->mBuffers
[0].mNumberChannels
= channelCount
;
357 list
->mBuffers
[0].mDataByteSize
= byteSize
;
358 list
->mBuffers
[0].mData
= &list
->mBuffers
[1];
363 static void destroy_buffer_list(AudioBufferList
*list
)
369 static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture
*self
, ALCdevice
*device
)
371 new (self
) ALCcoreAudioCapture
{};
372 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
373 SET_VTABLE2(ALCcoreAudioCapture
, ALCbackend
, self
);
376 self
->AudioConverter
= NULL
;
377 self
->BufferList
= NULL
;
378 self
->ResampleBuffer
= NULL
;
382 static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture
*self
)
384 ll_ringbuffer_free(self
->Ring
);
387 free(self
->ResampleBuffer
);
388 self
->ResampleBuffer
= NULL
;
390 destroy_buffer_list(self
->BufferList
);
391 self
->BufferList
= NULL
;
393 if(self
->AudioConverter
)
394 AudioConverterDispose(self
->AudioConverter
);
395 self
->AudioConverter
= NULL
;
398 AudioComponentInstanceDispose(self
->AudioUnit
);
401 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
402 self
->~ALCcoreAudioCapture();
406 static OSStatus
ALCcoreAudioCapture_RecordProc(void *inRefCon
,
407 AudioUnitRenderActionFlags
* UNUSED(ioActionFlags
),
408 const AudioTimeStamp
*inTimeStamp
, UInt32
UNUSED(inBusNumber
),
409 UInt32 inNumberFrames
, AudioBufferList
* UNUSED(ioData
))
411 ALCcoreAudioCapture
*self
= static_cast<ALCcoreAudioCapture
*>(inRefCon
);
412 AudioUnitRenderActionFlags flags
= 0;
415 // fill the BufferList with data from the input device
416 err
= AudioUnitRender(self
->AudioUnit
, &flags
, inTimeStamp
, 1, inNumberFrames
, self
->BufferList
);
419 ERR("AudioUnitRender error: %d\n", err
);
423 ll_ringbuffer_write(self
->Ring
, self
->BufferList
->mBuffers
[0].mData
, inNumberFrames
);
427 static OSStatus
ALCcoreAudioCapture_ConvertCallback(AudioConverterRef
UNUSED(inAudioConverter
),
428 UInt32
*ioNumberDataPackets
, AudioBufferList
*ioData
,
429 AudioStreamPacketDescription
** UNUSED(outDataPacketDescription
),
432 ALCcoreAudioCapture
*self
= reinterpret_cast<ALCcoreAudioCapture
*>(inUserData
);
434 // Read from the ring buffer and store temporarily in a large buffer
435 ll_ringbuffer_read(self
->Ring
, self
->ResampleBuffer
, *ioNumberDataPackets
);
437 // Set the input data
438 ioData
->mNumberBuffers
= 1;
439 ioData
->mBuffers
[0].mNumberChannels
= self
->Format
.mChannelsPerFrame
;
440 ioData
->mBuffers
[0].mData
= self
->ResampleBuffer
;
441 ioData
->mBuffers
[0].mDataByteSize
= (*ioNumberDataPackets
) * self
->Format
.mBytesPerFrame
;
447 static ALCenum
ALCcoreAudioCapture_open(ALCcoreAudioCapture
*self
, const ALCchar
*name
)
449 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
450 AudioStreamBasicDescription requestedFormat
; // The application requested format
451 AudioStreamBasicDescription hardwareFormat
; // The hardware format
452 AudioStreamBasicDescription outputFormat
; // The AudioUnit output format
453 AURenderCallbackStruct input
;
454 AudioComponentDescription desc
;
455 UInt32 outputFrameCount
;
457 AudioObjectPropertyAddress propertyAddress
;
464 else if(strcmp(name
, ca_device
) != 0)
465 return ALC_INVALID_VALUE
;
467 desc
.componentType
= kAudioUnitType_Output
;
469 desc
.componentSubType
= kAudioUnitSubType_RemoteIO
;
471 desc
.componentSubType
= kAudioUnitSubType_HALOutput
;
473 desc
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
474 desc
.componentFlags
= 0;
475 desc
.componentFlagsMask
= 0;
477 // Search for component with given description
478 comp
= AudioComponentFindNext(NULL
, &desc
);
481 ERR("AudioComponentFindNext failed\n");
482 return ALC_INVALID_VALUE
;
485 // Open the component
486 err
= AudioComponentInstanceNew(comp
, &self
->AudioUnit
);
489 ERR("AudioComponentInstanceNew failed\n");
493 // Turn off AudioUnit output
495 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Output
, 0, &enableIO
, sizeof(ALuint
));
498 ERR("AudioUnitSetProperty failed\n");
502 // Turn on AudioUnit input
504 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Input
, 1, &enableIO
, sizeof(ALuint
));
507 ERR("AudioUnitSetProperty failed\n");
513 // Get the default input device
514 AudioDeviceID inputDevice
= kAudioDeviceUnknown
;
516 propertySize
= sizeof(AudioDeviceID
);
517 propertyAddress
.mSelector
= kAudioHardwarePropertyDefaultInputDevice
;
518 propertyAddress
.mScope
= kAudioObjectPropertyScopeGlobal
;
519 propertyAddress
.mElement
= kAudioObjectPropertyElementMaster
;
521 err
= AudioObjectGetPropertyData(kAudioObjectSystemObject
, &propertyAddress
, 0, NULL
, &propertySize
, &inputDevice
);
524 ERR("AudioObjectGetPropertyData failed\n");
527 if(inputDevice
== kAudioDeviceUnknown
)
529 ERR("No input device found\n");
533 // Track the input device
534 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &inputDevice
, sizeof(AudioDeviceID
));
537 ERR("AudioUnitSetProperty failed\n");
543 // set capture callback
544 input
.inputProc
= ALCcoreAudioCapture_RecordProc
;
545 input
.inputProcRefCon
= self
;
547 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioOutputUnitProperty_SetInputCallback
, kAudioUnitScope_Global
, 0, &input
, sizeof(AURenderCallbackStruct
));
550 ERR("AudioUnitSetProperty failed\n");
554 // Initialize the device
555 err
= AudioUnitInitialize(self
->AudioUnit
);
558 ERR("AudioUnitInitialize failed\n");
562 // Get the hardware format
563 propertySize
= sizeof(AudioStreamBasicDescription
);
564 err
= AudioUnitGetProperty(self
->AudioUnit
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 1, &hardwareFormat
, &propertySize
);
565 if(err
!= noErr
|| propertySize
!= sizeof(AudioStreamBasicDescription
))
567 ERR("AudioUnitGetProperty failed\n");
571 // Set up the requested format description
572 switch(device
->FmtType
)
575 requestedFormat
.mBitsPerChannel
= 8;
576 requestedFormat
.mFormatFlags
= kAudioFormatFlagIsPacked
;
579 requestedFormat
.mBitsPerChannel
= 16;
580 requestedFormat
.mFormatFlags
= kAudioFormatFlagIsSignedInteger
| kAudioFormatFlagsNativeEndian
| kAudioFormatFlagIsPacked
;
583 requestedFormat
.mBitsPerChannel
= 32;
584 requestedFormat
.mFormatFlags
= kAudioFormatFlagIsSignedInteger
| kAudioFormatFlagsNativeEndian
| kAudioFormatFlagIsPacked
;
587 requestedFormat
.mBitsPerChannel
= 32;
588 requestedFormat
.mFormatFlags
= kAudioFormatFlagIsPacked
;
593 ERR("%s samples not supported\n", DevFmtTypeString(device
->FmtType
));
597 switch(device
->FmtChans
)
600 requestedFormat
.mChannelsPerFrame
= 1;
603 requestedFormat
.mChannelsPerFrame
= 2;
612 ERR("%s not supported\n", DevFmtChannelsString(device
->FmtChans
));
616 requestedFormat
.mBytesPerFrame
= requestedFormat
.mChannelsPerFrame
* requestedFormat
.mBitsPerChannel
/ 8;
617 requestedFormat
.mBytesPerPacket
= requestedFormat
.mBytesPerFrame
;
618 requestedFormat
.mSampleRate
= device
->Frequency
;
619 requestedFormat
.mFormatID
= kAudioFormatLinearPCM
;
620 requestedFormat
.mReserved
= 0;
621 requestedFormat
.mFramesPerPacket
= 1;
623 // save requested format description for later use
624 self
->Format
= requestedFormat
;
625 self
->FrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->mAmbiOrder
);
627 // Use intermediate format for sample rate conversion (outputFormat)
628 // Set sample rate to the same as hardware for resampling later
629 outputFormat
= requestedFormat
;
630 outputFormat
.mSampleRate
= hardwareFormat
.mSampleRate
;
632 // Determine sample rate ratio for resampling
633 self
->SampleRateRatio
= outputFormat
.mSampleRate
/ device
->Frequency
;
635 // The output format should be the requested format, but using the hardware sample rate
636 // This is because the AudioUnit will automatically scale other properties, except for sample rate
637 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, (void *)&outputFormat
, sizeof(outputFormat
));
640 ERR("AudioUnitSetProperty failed\n");
644 // Set the AudioUnit output format frame count
645 outputFrameCount
= device
->UpdateSize
* self
->SampleRateRatio
;
646 err
= AudioUnitSetProperty(self
->AudioUnit
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Output
, 0, &outputFrameCount
, sizeof(outputFrameCount
));
649 ERR("AudioUnitSetProperty failed: %d\n", err
);
653 // Set up sample converter
654 err
= AudioConverterNew(&outputFormat
, &requestedFormat
, &self
->AudioConverter
);
657 ERR("AudioConverterNew failed: %d\n", err
);
661 // Create a buffer for use in the resample callback
662 self
->ResampleBuffer
= malloc(device
->UpdateSize
* self
->FrameSize
* self
->SampleRateRatio
);
664 // Allocate buffer for the AudioUnit output
665 self
->BufferList
= allocate_buffer_list(outputFormat
.mChannelsPerFrame
, device
->UpdateSize
* self
->FrameSize
* self
->SampleRateRatio
);
666 if(self
->BufferList
== NULL
)
669 self
->Ring
= ll_ringbuffer_create(
670 (size_t)ceil(device
->UpdateSize
*self
->SampleRateRatio
*device
->NumUpdates
),
671 self
->FrameSize
, false
673 if(!self
->Ring
) goto error
;
675 device
->DeviceName
= name
;
679 ll_ringbuffer_free(self
->Ring
);
681 free(self
->ResampleBuffer
);
682 self
->ResampleBuffer
= NULL
;
683 destroy_buffer_list(self
->BufferList
);
684 self
->BufferList
= NULL
;
686 if(self
->AudioConverter
)
687 AudioConverterDispose(self
->AudioConverter
);
688 self
->AudioConverter
= NULL
;
690 AudioComponentInstanceDispose(self
->AudioUnit
);
693 return ALC_INVALID_VALUE
;
697 static ALCboolean
ALCcoreAudioCapture_start(ALCcoreAudioCapture
*self
)
699 OSStatus err
= AudioOutputUnitStart(self
->AudioUnit
);
702 ERR("AudioOutputUnitStart failed\n");
708 static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture
*self
)
710 OSStatus err
= AudioOutputUnitStop(self
->AudioUnit
);
712 ERR("AudioOutputUnitStop failed\n");
715 static ALCenum
ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
718 ALbyte _
[sizeof(AudioBufferList
) + sizeof(AudioBuffer
)];
719 AudioBufferList list
;
720 } audiobuf
= { { 0 } };
724 // If no samples are requested, just return
725 if(samples
== 0) return ALC_NO_ERROR
;
727 // Point the resampling buffer to the capture buffer
728 audiobuf
.list
.mNumberBuffers
= 1;
729 audiobuf
.list
.mBuffers
[0].mNumberChannels
= self
->Format
.mChannelsPerFrame
;
730 audiobuf
.list
.mBuffers
[0].mDataByteSize
= samples
* self
->FrameSize
;
731 audiobuf
.list
.mBuffers
[0].mData
= buffer
;
733 // Resample into another AudioBufferList
734 frameCount
= samples
;
735 err
= AudioConverterFillComplexBuffer(self
->AudioConverter
,
736 ALCcoreAudioCapture_ConvertCallback
, self
, &frameCount
, &audiobuf
.list
, NULL
740 ERR("AudioConverterFillComplexBuffer error: %d\n", err
);
741 return ALC_INVALID_VALUE
;
746 static ALCuint
ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture
*self
)
748 return ll_ringbuffer_read_space(self
->Ring
) / self
->SampleRateRatio
;
752 BackendFactory
&CoreAudioBackendFactory::getFactory()
754 static CoreAudioBackendFactory factory
{};
758 bool CoreAudioBackendFactory::init() { return true; }
760 bool CoreAudioBackendFactory::querySupport(ALCbackend_Type type
)
761 { return (type
== ALCbackend_Playback
|| ALCbackend_Capture
); }
763 void CoreAudioBackendFactory::probe(enum DevProbe type
, std::string
*outnames
)
767 case ALL_DEVICE_PROBE
:
768 case CAPTURE_DEVICE_PROBE
:
769 /* Includes null char. */
770 outnames
->append(ca_device
, sizeof(ca_device
));
775 ALCbackend
*CoreAudioBackendFactory::createBackend(ALCdevice
*device
, ALCbackend_Type type
)
777 if(type
== ALCbackend_Playback
)
779 ALCcoreAudioPlayback
*backend
;
780 NEW_OBJ(backend
, ALCcoreAudioPlayback
)(device
);
781 if(!backend
) return nullptr;
782 return STATIC_CAST(ALCbackend
, backend
);
784 if(type
== ALCbackend_Capture
)
786 ALCcoreAudioCapture
*backend
;
787 NEW_OBJ(backend
, ALCcoreAudioCapture
)(device
);
788 if(!backend
) return nullptr;
789 return STATIC_CAST(ALCbackend
, backend
);