Implement capture support for SoundIO
[openal-soft.git] / Alc / backends / coreaudio.c
bloba8787f7b001d1ecfeaf50a3ff608f7bddccf5e66
1 /**
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
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "alMain.h"
28 #include "alu.h"
29 #include "ringbuffer.h"
31 #include <CoreServices/CoreServices.h>
32 #include <unistd.h>
33 #include <AudioUnit/AudioUnit.h>
34 #include <AudioToolbox/AudioToolbox.h>
36 #include "backends/base.h"
39 static const ALCchar ca_device[] = "CoreAudio Default";
42 typedef struct ALCcoreAudioPlayback {
43 DERIVE_FROM_TYPE(ALCbackend);
45 AudioUnit audioUnit;
47 ALuint frameSize;
48 AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
49 } ALCcoreAudioPlayback;
51 static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device);
52 static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self);
53 static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name);
54 static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self);
55 static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self);
56 static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self);
57 static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
58 static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples)
59 static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency)
60 static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock)
61 static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock)
62 DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback)
64 DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback);
67 static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device)
69 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
70 SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self);
72 self->frameSize = 0;
73 memset(&self->format, 0, sizeof(self->format));
76 static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self)
78 AudioUnitUninitialize(self->audioUnit);
79 AudioComponentInstanceDispose(self->audioUnit);
81 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
85 static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon,
86 AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp),
87 UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData)
89 ALCcoreAudioPlayback *self = inRefCon;
90 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
92 ALCcoreAudioPlayback_lock(self);
93 aluMixData(device, ioData->mBuffers[0].mData,
94 ioData->mBuffers[0].mDataByteSize / self->frameSize);
95 ALCcoreAudioPlayback_unlock(self);
97 return noErr;
101 static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name)
103 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
104 AudioComponentDescription desc;
105 AudioComponent comp;
106 OSStatus err;
108 if(!name)
109 name = ca_device;
110 else if(strcmp(name, ca_device) != 0)
111 return ALC_INVALID_VALUE;
113 /* open the default output unit */
114 desc.componentType = kAudioUnitType_Output;
115 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
116 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
117 desc.componentFlags = 0;
118 desc.componentFlagsMask = 0;
120 comp = AudioComponentFindNext(NULL, &desc);
121 if(comp == NULL)
123 ERR("AudioComponentFindNext failed\n");
124 return ALC_INVALID_VALUE;
127 err = AudioComponentInstanceNew(comp, &self->audioUnit);
128 if(err != noErr)
130 ERR("AudioComponentInstanceNew failed\n");
131 return ALC_INVALID_VALUE;
134 /* init and start the default audio unit... */
135 err = AudioUnitInitialize(self->audioUnit);
136 if(err != noErr)
138 ERR("AudioUnitInitialize failed\n");
139 AudioComponentInstanceDispose(self->audioUnit);
140 return ALC_INVALID_VALUE;
143 alstr_copy_cstr(&device->DeviceName, name);
144 return ALC_NO_ERROR;
147 static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self)
149 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
150 AudioStreamBasicDescription streamFormat;
151 AURenderCallbackStruct input;
152 OSStatus err;
153 UInt32 size;
155 err = AudioUnitUninitialize(self->audioUnit);
156 if(err != noErr)
157 ERR("-- AudioUnitUninitialize failed.\n");
159 /* retrieve default output unit's properties (output side) */
160 size = sizeof(AudioStreamBasicDescription);
161 err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
162 if(err != noErr || size != sizeof(AudioStreamBasicDescription))
164 ERR("AudioUnitGetProperty failed\n");
165 return ALC_FALSE;
168 #if 0
169 TRACE("Output streamFormat of default output unit -\n");
170 TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket);
171 TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame);
172 TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel);
173 TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket);
174 TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame);
175 TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate);
176 #endif
178 /* set default output unit's input side to match output side */
179 err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size);
180 if(err != noErr)
182 ERR("AudioUnitSetProperty failed\n");
183 return ALC_FALSE;
186 if(device->Frequency != streamFormat.mSampleRate)
188 device->NumUpdates = (ALuint)((ALuint64)device->NumUpdates *
189 streamFormat.mSampleRate /
190 device->Frequency);
191 device->Frequency = streamFormat.mSampleRate;
194 /* FIXME: How to tell what channels are what in the output device, and how
195 * to specify what we're giving? eg, 6.0 vs 5.1 */
196 switch(streamFormat.mChannelsPerFrame)
198 case 1:
199 device->FmtChans = DevFmtMono;
200 break;
201 case 2:
202 device->FmtChans = DevFmtStereo;
203 break;
204 case 4:
205 device->FmtChans = DevFmtQuad;
206 break;
207 case 6:
208 device->FmtChans = DevFmtX51;
209 break;
210 case 7:
211 device->FmtChans = DevFmtX61;
212 break;
213 case 8:
214 device->FmtChans = DevFmtX71;
215 break;
216 default:
217 ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame);
218 device->FmtChans = DevFmtStereo;
219 streamFormat.mChannelsPerFrame = 2;
220 break;
222 SetDefaultWFXChannelOrder(device);
224 /* use channel count and sample rate from the default output unit's current
225 * parameters, but reset everything else */
226 streamFormat.mFramesPerPacket = 1;
227 streamFormat.mFormatFlags = 0;
228 switch(device->FmtType)
230 case DevFmtUByte:
231 device->FmtType = DevFmtByte;
232 /* fall-through */
233 case DevFmtByte:
234 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
235 streamFormat.mBitsPerChannel = 8;
236 break;
237 case DevFmtUShort:
238 device->FmtType = DevFmtShort;
239 /* fall-through */
240 case DevFmtShort:
241 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
242 streamFormat.mBitsPerChannel = 16;
243 break;
244 case DevFmtUInt:
245 device->FmtType = DevFmtInt;
246 /* fall-through */
247 case DevFmtInt:
248 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
249 streamFormat.mBitsPerChannel = 32;
250 break;
251 case DevFmtFloat:
252 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
253 streamFormat.mBitsPerChannel = 32;
254 break;
256 streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame *
257 streamFormat.mBitsPerChannel / 8;
258 streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame;
259 streamFormat.mFormatID = kAudioFormatLinearPCM;
260 streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian |
261 kLinearPCMFormatFlagIsPacked;
263 err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription));
264 if(err != noErr)
266 ERR("AudioUnitSetProperty failed\n");
267 return ALC_FALSE;
270 /* setup callback */
271 self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
272 input.inputProc = ALCcoreAudioPlayback_MixerProc;
273 input.inputProcRefCon = self;
275 err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
276 if(err != noErr)
278 ERR("AudioUnitSetProperty failed\n");
279 return ALC_FALSE;
282 /* init the default audio unit... */
283 err = AudioUnitInitialize(self->audioUnit);
284 if(err != noErr)
286 ERR("AudioUnitInitialize failed\n");
287 return ALC_FALSE;
290 return ALC_TRUE;
293 static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self)
295 OSStatus err = AudioOutputUnitStart(self->audioUnit);
296 if(err != noErr)
298 ERR("AudioOutputUnitStart failed\n");
299 return ALC_FALSE;
302 return ALC_TRUE;
305 static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self)
307 OSStatus err = AudioOutputUnitStop(self->audioUnit);
308 if(err != noErr)
309 ERR("AudioOutputUnitStop failed\n");
315 typedef struct ALCcoreAudioCapture {
316 DERIVE_FROM_TYPE(ALCbackend);
318 AudioUnit audioUnit;
320 ALuint frameSize;
321 ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate
322 AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
324 AudioConverterRef audioConverter; // Sample rate converter if needed
325 AudioBufferList *bufferList; // Buffer for data coming from the input device
326 ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling
328 ll_ringbuffer_t *ring;
329 } ALCcoreAudioCapture;
331 static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device);
332 static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self);
333 static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name);
334 static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset)
335 static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self);
336 static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self);
337 static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples);
338 static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self);
339 static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency)
340 static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock)
341 static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock)
342 DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture)
344 DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture);
347 static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize)
349 AudioBufferList *list;
351 list = calloc(1, FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize);
352 if(list)
354 list->mNumberBuffers = 1;
356 list->mBuffers[0].mNumberChannels = channelCount;
357 list->mBuffers[0].mDataByteSize = byteSize;
358 list->mBuffers[0].mData = &list->mBuffers[1];
360 return list;
363 static void destroy_buffer_list(AudioBufferList *list)
365 free(list);
369 static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device)
371 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
372 SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self);
374 self->audioUnit = 0;
375 self->audioConverter = NULL;
376 self->bufferList = NULL;
377 self->resampleBuffer = NULL;
378 self->ring = NULL;
381 static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self)
383 ll_ringbuffer_free(self->ring);
384 self->ring = NULL;
386 free(self->resampleBuffer);
387 self->resampleBuffer = NULL;
389 destroy_buffer_list(self->bufferList);
390 self->bufferList = NULL;
392 if(self->audioConverter)
393 AudioConverterDispose(self->audioConverter);
394 self->audioConverter = NULL;
396 if(self->audioUnit)
397 AudioComponentInstanceDispose(self->audioUnit);
398 self->audioUnit = 0;
400 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
404 static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon,
405 AudioUnitRenderActionFlags* UNUSED(ioActionFlags),
406 const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber),
407 UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData))
409 ALCcoreAudioCapture *self = inRefCon;
410 AudioUnitRenderActionFlags flags = 0;
411 OSStatus err;
413 // fill the bufferList with data from the input device
414 err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList);
415 if(err != noErr)
417 ERR("AudioUnitRender error: %d\n", err);
418 return err;
421 ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames);
423 return noErr;
426 static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter),
427 UInt32 *ioNumberDataPackets, AudioBufferList *ioData,
428 AudioStreamPacketDescription** UNUSED(outDataPacketDescription),
429 void *inUserData)
431 ALCcoreAudioCapture *self = inUserData;
433 // Read from the ring buffer and store temporarily in a large buffer
434 ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets);
436 // Set the input data
437 ioData->mNumberBuffers = 1;
438 ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame;
439 ioData->mBuffers[0].mData = self->resampleBuffer;
440 ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame;
442 return noErr;
446 static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name)
448 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
449 AudioStreamBasicDescription requestedFormat; // The application requested format
450 AudioStreamBasicDescription hardwareFormat; // The hardware format
451 AudioStreamBasicDescription outputFormat; // The AudioUnit output format
452 AURenderCallbackStruct input;
453 AudioComponentDescription desc;
454 AudioDeviceID inputDevice;
455 UInt32 outputFrameCount;
456 UInt32 propertySize;
457 AudioObjectPropertyAddress propertyAddress;
458 UInt32 enableIO;
459 AudioComponent comp;
460 OSStatus err;
462 if(!name)
463 name = ca_device;
464 else if(strcmp(name, ca_device) != 0)
465 return ALC_INVALID_VALUE;
467 desc.componentType = kAudioUnitType_Output;
468 desc.componentSubType = kAudioUnitSubType_HALOutput;
469 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
470 desc.componentFlags = 0;
471 desc.componentFlagsMask = 0;
473 // Search for component with given description
474 comp = AudioComponentFindNext(NULL, &desc);
475 if(comp == NULL)
477 ERR("AudioComponentFindNext failed\n");
478 return ALC_INVALID_VALUE;
481 // Open the component
482 err = AudioComponentInstanceNew(comp, &self->audioUnit);
483 if(err != noErr)
485 ERR("AudioComponentInstanceNew failed\n");
486 goto error;
489 // Turn off AudioUnit output
490 enableIO = 0;
491 err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
492 if(err != noErr)
494 ERR("AudioUnitSetProperty failed\n");
495 goto error;
498 // Turn on AudioUnit input
499 enableIO = 1;
500 err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
501 if(err != noErr)
503 ERR("AudioUnitSetProperty failed\n");
504 goto error;
507 // Get the default input device
509 propertySize = sizeof(AudioDeviceID);
510 propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
511 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
512 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
514 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice);
515 if(err != noErr)
517 ERR("AudioObjectGetPropertyData failed\n");
518 goto error;
521 if(inputDevice == kAudioDeviceUnknown)
523 ERR("No input device found\n");
524 goto error;
527 // Track the input device
528 err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
529 if(err != noErr)
531 ERR("AudioUnitSetProperty failed\n");
532 goto error;
535 // set capture callback
536 input.inputProc = ALCcoreAudioCapture_RecordProc;
537 input.inputProcRefCon = self;
539 err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
540 if(err != noErr)
542 ERR("AudioUnitSetProperty failed\n");
543 goto error;
546 // Initialize the device
547 err = AudioUnitInitialize(self->audioUnit);
548 if(err != noErr)
550 ERR("AudioUnitInitialize failed\n");
551 goto error;
554 // Get the hardware format
555 propertySize = sizeof(AudioStreamBasicDescription);
556 err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize);
557 if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription))
559 ERR("AudioUnitGetProperty failed\n");
560 goto error;
563 // Set up the requested format description
564 switch(device->FmtType)
566 case DevFmtUByte:
567 requestedFormat.mBitsPerChannel = 8;
568 requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
569 break;
570 case DevFmtShort:
571 requestedFormat.mBitsPerChannel = 16;
572 requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
573 break;
574 case DevFmtInt:
575 requestedFormat.mBitsPerChannel = 32;
576 requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
577 break;
578 case DevFmtFloat:
579 requestedFormat.mBitsPerChannel = 32;
580 requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
581 break;
582 case DevFmtByte:
583 case DevFmtUShort:
584 case DevFmtUInt:
585 ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
586 goto error;
589 switch(device->FmtChans)
591 case DevFmtMono:
592 requestedFormat.mChannelsPerFrame = 1;
593 break;
594 case DevFmtStereo:
595 requestedFormat.mChannelsPerFrame = 2;
596 break;
598 case DevFmtQuad:
599 case DevFmtX51:
600 case DevFmtX51Rear:
601 case DevFmtX61:
602 case DevFmtX71:
603 case DevFmtAmbi3D:
604 ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
605 goto error;
608 requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8;
609 requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame;
610 requestedFormat.mSampleRate = device->Frequency;
611 requestedFormat.mFormatID = kAudioFormatLinearPCM;
612 requestedFormat.mReserved = 0;
613 requestedFormat.mFramesPerPacket = 1;
615 // save requested format description for later use
616 self->format = requestedFormat;
617 self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
619 // Use intermediate format for sample rate conversion (outputFormat)
620 // Set sample rate to the same as hardware for resampling later
621 outputFormat = requestedFormat;
622 outputFormat.mSampleRate = hardwareFormat.mSampleRate;
624 // Determine sample rate ratio for resampling
625 self->sampleRateRatio = outputFormat.mSampleRate / device->Frequency;
627 // The output format should be the requested format, but using the hardware sample rate
628 // This is because the AudioUnit will automatically scale other properties, except for sample rate
629 err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat));
630 if(err != noErr)
632 ERR("AudioUnitSetProperty failed\n");
633 goto error;
636 // Set the AudioUnit output format frame count
637 outputFrameCount = device->UpdateSize * self->sampleRateRatio;
638 err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount));
639 if(err != noErr)
641 ERR("AudioUnitSetProperty failed: %d\n", err);
642 goto error;
645 // Set up sample converter
646 err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter);
647 if(err != noErr)
649 ERR("AudioConverterNew failed: %d\n", err);
650 goto error;
653 // Create a buffer for use in the resample callback
654 self->resampleBuffer = malloc(device->UpdateSize * self->frameSize * self->sampleRateRatio);
656 // Allocate buffer for the AudioUnit output
657 self->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->frameSize * self->sampleRateRatio);
658 if(self->bufferList == NULL)
659 goto error;
661 self->ring = ll_ringbuffer_create(
662 (size_t)ceil(device->UpdateSize*self->sampleRateRatio*device->NumUpdates),
663 self->frameSize, false
665 if(!self->ring) goto error;
667 alstr_copy_cstr(&device->DeviceName, name);
669 return ALC_NO_ERROR;
671 error:
672 ll_ringbuffer_free(self->ring);
673 self->ring = NULL;
674 free(self->resampleBuffer);
675 self->resampleBuffer = NULL;
676 destroy_buffer_list(self->bufferList);
677 self->bufferList = NULL;
679 if(self->audioConverter)
680 AudioConverterDispose(self->audioConverter);
681 self->audioConverter = NULL;
682 if(self->audioUnit)
683 AudioComponentInstanceDispose(self->audioUnit);
684 self->audioUnit = 0;
686 return ALC_INVALID_VALUE;
690 static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self)
692 OSStatus err = AudioOutputUnitStart(self->audioUnit);
693 if(err != noErr)
695 ERR("AudioOutputUnitStart failed\n");
696 return ALC_FALSE;
698 return ALC_TRUE;
701 static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self)
703 OSStatus err = AudioOutputUnitStop(self->audioUnit);
704 if(err != noErr)
705 ERR("AudioOutputUnitStop failed\n");
708 static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples)
710 union {
711 ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)];
712 AudioBufferList list;
713 } audiobuf = { { 0 } };
714 UInt32 frameCount;
715 OSStatus err;
717 // If no samples are requested, just return
718 if(samples == 0) return ALC_NO_ERROR;
720 // Point the resampling buffer to the capture buffer
721 audiobuf.list.mNumberBuffers = 1;
722 audiobuf.list.mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame;
723 audiobuf.list.mBuffers[0].mDataByteSize = samples * self->frameSize;
724 audiobuf.list.mBuffers[0].mData = buffer;
726 // Resample into another AudioBufferList
727 frameCount = samples;
728 err = AudioConverterFillComplexBuffer(self->audioConverter,
729 ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL
731 if(err != noErr)
733 ERR("AudioConverterFillComplexBuffer error: %d\n", err);
734 return ALC_INVALID_VALUE;
736 return ALC_NO_ERROR;
739 static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self)
741 return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio;
745 typedef struct ALCcoreAudioBackendFactory {
746 DERIVE_FROM_TYPE(ALCbackendFactory);
747 } ALCcoreAudioBackendFactory;
748 #define ALCCOREAUDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory) } }
750 ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void);
752 static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self);
753 static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit)
754 static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type);
755 static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type);
756 static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
757 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory);
760 ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void)
762 static ALCcoreAudioBackendFactory factory = ALCCOREAUDIOBACKENDFACTORY_INITIALIZER;
763 return STATIC_CAST(ALCbackendFactory, &factory);
767 static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self))
769 return ALC_TRUE;
772 static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type)
774 if(type == ALCbackend_Playback || ALCbackend_Capture)
775 return ALC_TRUE;
776 return ALC_FALSE;
779 static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type)
781 switch(type)
783 case ALL_DEVICE_PROBE:
784 AppendAllDevicesList(ca_device);
785 break;
786 case CAPTURE_DEVICE_PROBE:
787 AppendCaptureDeviceList(ca_device);
788 break;
792 static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
794 if(type == ALCbackend_Playback)
796 ALCcoreAudioPlayback *backend;
797 NEW_OBJ(backend, ALCcoreAudioPlayback)(device);
798 if(!backend) return NULL;
799 return STATIC_CAST(ALCbackend, backend);
801 if(type == ALCbackend_Capture)
803 ALCcoreAudioCapture *backend;
804 NEW_OBJ(backend, ALCcoreAudioCapture)(device);
805 if(!backend) return NULL;
806 return STATIC_CAST(ALCbackend, backend);
809 return NULL;