I guess -1 isn't allowed for the output
[openal-soft.git] / Alc / backends / coreaudio.c
blobec926d3d93bd50bf82077c82d5baaa3b953ce2b4
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>
26 #include <alloca.h>
28 #include "alMain.h"
29 #include "alu.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 typedef struct {
40 AudioUnit audioUnit;
42 ALuint frameSize;
43 ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate
44 AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
46 AudioConverterRef audioConverter; // Sample rate converter if needed
47 AudioBufferList *bufferList; // Buffer for data coming from the input device
48 ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling
50 ll_ringbuffer_t *ring;
51 } ca_data;
53 static const ALCchar ca_device[] = "CoreAudio Default";
56 static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize)
58 AudioBufferList *list;
60 list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer));
61 if(list)
63 list->mNumberBuffers = 1;
65 list->mBuffers[0].mNumberChannels = channelCount;
66 list->mBuffers[0].mDataByteSize = byteSize;
67 list->mBuffers[0].mData = malloc(byteSize);
68 if(list->mBuffers[0].mData == NULL)
70 free(list);
71 list = NULL;
74 return list;
77 static void destroy_buffer_list(AudioBufferList* list)
79 if(list)
81 UInt32 i;
82 for(i = 0;i < list->mNumberBuffers;i++)
83 free(list->mBuffers[i].mData);
84 free(list);
89 typedef struct ALCcoreAudioPlayback {
90 DERIVE_FROM_TYPE(ALCbackend);
92 AudioUnit audioUnit;
94 ALuint frameSize;
95 AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
96 } ALCcoreAudioPlayback;
98 static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device);
99 static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self);
100 static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name);
101 static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self);
102 static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self);
103 static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self);
104 static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self);
105 static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
106 static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples)
107 static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency)
108 static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock)
109 static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock)
110 DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback)
112 DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback);
115 static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device)
117 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
118 SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self);
120 self->frameSize = 0;
121 memset(&self->format, 0, sizeof(self->format));
124 static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self)
126 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
130 static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon,
131 AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp),
132 UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData)
134 ALCcoreAudioPlayback *self = inRefCon;
135 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
137 ALCdevice_Lock(device);
138 aluMixData(device, ioData->mBuffers[0].mData,
139 ioData->mBuffers[0].mDataByteSize / self->frameSize);
140 ALCdevice_Unlock(device);
142 return noErr;
146 static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name)
148 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
149 AudioComponentDescription desc;
150 AudioComponent comp;
151 OSStatus err;
153 if(!name)
154 name = ca_device;
155 else if(strcmp(name, ca_device) != 0)
156 return ALC_INVALID_VALUE;
158 /* open the default output unit */
159 desc.componentType = kAudioUnitType_Output;
160 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
161 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
162 desc.componentFlags = 0;
163 desc.componentFlagsMask = 0;
165 comp = AudioComponentFindNext(NULL, &desc);
166 if(comp == NULL)
168 ERR("AudioComponentFindNext failed\n");
169 return ALC_INVALID_VALUE;
172 err = AudioComponentInstanceNew(comp, &self->audioUnit);
173 if(err != noErr)
175 ERR("AudioComponentInstanceNew failed\n");
176 return ALC_INVALID_VALUE;
179 /* init and start the default audio unit... */
180 err = AudioUnitInitialize(self->audioUnit);
181 if(err != noErr)
183 ERR("AudioUnitInitialize failed\n");
184 AudioComponentInstanceDispose(self->audioUnit);
185 return ALC_INVALID_VALUE;
188 alstr_copy_cstr(&device->DeviceName, name);
189 return ALC_NO_ERROR;
192 static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self)
194 AudioUnitUninitialize(self->audioUnit);
195 AudioComponentInstanceDispose(self->audioUnit);
198 static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self)
200 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
201 AudioStreamBasicDescription streamFormat;
202 AURenderCallbackStruct input;
203 OSStatus err;
204 UInt32 size;
206 err = AudioUnitUninitialize(self->audioUnit);
207 if(err != noErr)
208 ERR("-- AudioUnitUninitialize failed.\n");
210 /* retrieve default output unit's properties (output side) */
211 size = sizeof(AudioStreamBasicDescription);
212 err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
213 if(err != noErr || size != sizeof(AudioStreamBasicDescription))
215 ERR("AudioUnitGetProperty failed\n");
216 return ALC_FALSE;
219 #if 0
220 TRACE("Output streamFormat of default output unit -\n");
221 TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket);
222 TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame);
223 TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel);
224 TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket);
225 TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame);
226 TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate);
227 #endif
229 /* set default output unit's input side to match output side */
230 err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size);
231 if(err != noErr)
233 ERR("AudioUnitSetProperty failed\n");
234 return ALC_FALSE;
237 if(device->Frequency != streamFormat.mSampleRate)
239 device->NumUpdates = (ALuint)((ALuint64)device->NumUpdates *
240 streamFormat.mSampleRate /
241 device->Frequency);
242 device->Frequency = streamFormat.mSampleRate;
245 /* FIXME: How to tell what channels are what in the output device, and how
246 * to specify what we're giving? eg, 6.0 vs 5.1 */
247 switch(streamFormat.mChannelsPerFrame)
249 case 1:
250 device->FmtChans = DevFmtMono;
251 break;
252 case 2:
253 device->FmtChans = DevFmtStereo;
254 break;
255 case 4:
256 device->FmtChans = DevFmtQuad;
257 break;
258 case 6:
259 device->FmtChans = DevFmtX51;
260 break;
261 case 7:
262 device->FmtChans = DevFmtX61;
263 break;
264 case 8:
265 device->FmtChans = DevFmtX71;
266 break;
267 default:
268 ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame);
269 device->FmtChans = DevFmtStereo;
270 streamFormat.mChannelsPerFrame = 2;
271 break;
273 SetDefaultWFXChannelOrder(device);
275 /* use channel count and sample rate from the default output unit's current
276 * parameters, but reset everything else */
277 streamFormat.mFramesPerPacket = 1;
278 streamFormat.mFormatFlags = 0;
279 switch(device->FmtType)
281 case DevFmtUByte:
282 device->FmtType = DevFmtByte;
283 /* fall-through */
284 case DevFmtByte:
285 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
286 streamFormat.mBitsPerChannel = 8;
287 break;
288 case DevFmtUShort:
289 device->FmtType = DevFmtShort;
290 /* fall-through */
291 case DevFmtShort:
292 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
293 streamFormat.mBitsPerChannel = 16;
294 break;
295 case DevFmtUInt:
296 device->FmtType = DevFmtInt;
297 /* fall-through */
298 case DevFmtInt:
299 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
300 streamFormat.mBitsPerChannel = 32;
301 break;
302 case DevFmtFloat:
303 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
304 streamFormat.mBitsPerChannel = 32;
305 break;
307 streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame *
308 streamFormat.mBitsPerChannel / 8;
309 streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame;
310 streamFormat.mFormatID = kAudioFormatLinearPCM;
311 streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian |
312 kLinearPCMFormatFlagIsPacked;
314 err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription));
315 if(err != noErr)
317 ERR("AudioUnitSetProperty failed\n");
318 return ALC_FALSE;
321 /* setup callback */
322 self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
323 input.inputProc = ALCcoreAudioPlayback_MixerProc;
324 input.inputProcRefCon = self;
326 err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
327 if(err != noErr)
329 ERR("AudioUnitSetProperty failed\n");
330 return ALC_FALSE;
333 /* init the default audio unit... */
334 err = AudioUnitInitialize(self->audioUnit);
335 if(err != noErr)
337 ERR("AudioUnitInitialize failed\n");
338 return ALC_FALSE;
341 return ALC_TRUE;
344 static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self)
346 OSStatus err = AudioOutputUnitStart(self->audioUnit);
347 if(err != noErr)
349 ERR("AudioOutputUnitStart failed\n");
350 return ALC_FALSE;
353 return ALC_TRUE;
356 static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self)
358 OSStatus err = AudioOutputUnitStop(self->audioUnit);
359 if(err != noErr)
360 ERR("AudioOutputUnitStop failed\n");
366 typedef struct ALCcoreAudioCapture {
367 DERIVE_FROM_TYPE(ALCbackend);
369 AudioUnit audioUnit;
371 ALuint frameSize;
372 ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate
373 AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
375 AudioConverterRef audioConverter; // Sample rate converter if needed
376 AudioBufferList *bufferList; // Buffer for data coming from the input device
377 ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling
379 ll_ringbuffer_t *ring;
380 } ALCcoreAudioCapture;
382 static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device);
383 static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self);
384 static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name);
385 static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self);
386 static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset)
387 static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self);
388 static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self);
389 static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples);
390 static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self);
391 static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency)
392 static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock)
393 static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock)
394 DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture)
396 DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture);
399 static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device)
401 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
402 SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self);
406 static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self)
408 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
412 static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon,
413 AudioUnitRenderActionFlags* UNUSED(ioActionFlags),
414 const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber),
415 UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData))
417 ALCcoreAudioCapture *self = inRefCon;
418 AudioUnitRenderActionFlags flags = 0;
419 OSStatus err;
421 // fill the bufferList with data from the input device
422 err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList);
423 if(err != noErr)
425 ERR("AudioUnitRender error: %d\n", err);
426 return err;
429 ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames);
431 return noErr;
434 static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter),
435 UInt32 *ioNumberDataPackets, AudioBufferList *ioData,
436 AudioStreamPacketDescription** UNUSED(outDataPacketDescription),
437 void *inUserData)
439 ALCcoreAudioCapture *self = inUserData;
441 // Read from the ring buffer and store temporarily in a large buffer
442 ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets);
444 // Set the input data
445 ioData->mNumberBuffers = 1;
446 ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame;
447 ioData->mBuffers[0].mData = self->resampleBuffer;
448 ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame;
450 return noErr;
454 static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name)
456 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
457 AudioStreamBasicDescription requestedFormat; // The application requested format
458 AudioStreamBasicDescription hardwareFormat; // The hardware format
459 AudioStreamBasicDescription outputFormat; // The AudioUnit output format
460 AURenderCallbackStruct input;
461 AudioComponentDescription desc;
462 AudioDeviceID inputDevice;
463 UInt32 outputFrameCount;
464 UInt32 propertySize;
465 AudioObjectPropertyAddress propertyAddress;
466 UInt32 enableIO;
467 AudioComponent comp;
468 OSStatus err;
470 if(!name)
471 name = ca_device;
472 else if(strcmp(name, ca_device) != 0)
473 return ALC_INVALID_VALUE;
475 desc.componentType = kAudioUnitType_Output;
476 desc.componentSubType = kAudioUnitSubType_HALOutput;
477 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
478 desc.componentFlags = 0;
479 desc.componentFlagsMask = 0;
481 // Search for component with given description
482 comp = AudioComponentFindNext(NULL, &desc);
483 if(comp == NULL)
485 ERR("AudioComponentFindNext failed\n");
486 return ALC_INVALID_VALUE;
489 // Open the component
490 err = AudioComponentInstanceNew(comp, &self->audioUnit);
491 if(err != noErr)
493 ERR("AudioComponentInstanceNew failed\n");
494 goto error;
497 // Turn off AudioUnit output
498 enableIO = 0;
499 err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
500 if(err != noErr)
502 ERR("AudioUnitSetProperty failed\n");
503 goto error;
506 // Turn on AudioUnit input
507 enableIO = 1;
508 err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
509 if(err != noErr)
511 ERR("AudioUnitSetProperty failed\n");
512 goto error;
515 // Get the default input device
517 propertySize = sizeof(AudioDeviceID);
518 propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
519 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
520 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
522 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice);
523 if(err != noErr)
525 ERR("AudioObjectGetPropertyData failed\n");
526 goto error;
529 if(inputDevice == kAudioDeviceUnknown)
531 ERR("No input device found\n");
532 goto error;
535 // Track the input device
536 err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
537 if(err != noErr)
539 ERR("AudioUnitSetProperty failed\n");
540 goto error;
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));
548 if(err != noErr)
550 ERR("AudioUnitSetProperty failed\n");
551 goto error;
554 // Initialize the device
555 err = AudioUnitInitialize(self->audioUnit);
556 if(err != noErr)
558 ERR("AudioUnitInitialize failed\n");
559 goto error;
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");
568 goto error;
571 // Set up the requested format description
572 switch(device->FmtType)
574 case DevFmtUByte:
575 requestedFormat.mBitsPerChannel = 8;
576 requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
577 break;
578 case DevFmtShort:
579 requestedFormat.mBitsPerChannel = 16;
580 requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
581 break;
582 case DevFmtInt:
583 requestedFormat.mBitsPerChannel = 32;
584 requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
585 break;
586 case DevFmtFloat:
587 requestedFormat.mBitsPerChannel = 32;
588 requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
589 break;
590 case DevFmtByte:
591 case DevFmtUShort:
592 case DevFmtUInt:
593 ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
594 goto error;
597 switch(device->FmtChans)
599 case DevFmtMono:
600 requestedFormat.mChannelsPerFrame = 1;
601 break;
602 case DevFmtStereo:
603 requestedFormat.mChannelsPerFrame = 2;
604 break;
606 case DevFmtQuad:
607 case DevFmtX51:
608 case DevFmtX51Rear:
609 case DevFmtX61:
610 case DevFmtX71:
611 case DevFmtAmbi3D:
612 ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
613 goto error;
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->AmbiOrder);
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));
638 if(err != noErr)
640 ERR("AudioUnitSetProperty failed\n");
641 goto error;
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));
647 if(err != noErr)
649 ERR("AudioUnitSetProperty failed: %d\n", err);
650 goto error;
653 // Set up sample converter
654 err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter);
655 if(err != noErr)
657 ERR("AudioConverterNew failed: %d\n", err);
658 goto error;
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)
667 goto error;
669 self->ring = ll_ringbuffer_create(
670 device->UpdateSize*self->sampleRateRatio*device->NumUpdates + 1,
671 self->frameSize
673 if(!self->ring) goto error;
675 alstr_copy_cstr(&device->DeviceName, name);
677 return ALC_NO_ERROR;
679 error:
680 ll_ringbuffer_free(self->ring);
681 self->ring = NULL;
682 free(self->resampleBuffer);
683 destroy_buffer_list(self->bufferList);
685 if(self->audioConverter)
686 AudioConverterDispose(self->audioConverter);
687 if(self->audioUnit)
688 AudioComponentInstanceDispose(self->audioUnit);
690 return ALC_INVALID_VALUE;
694 static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self)
696 ll_ringbuffer_free(self->ring);
697 self->ring = NULL;
699 free(self->resampleBuffer);
701 destroy_buffer_list(self->bufferList);
703 AudioConverterDispose(self->audioConverter);
704 AudioComponentInstanceDispose(self->audioUnit);
707 static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self)
709 OSStatus err = AudioOutputUnitStart(self->audioUnit);
710 if(err != noErr)
712 ERR("AudioOutputUnitStart failed\n");
713 return ALC_FALSE;
715 return ALC_TRUE;
718 static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self)
720 OSStatus err = AudioOutputUnitStop(self->audioUnit);
721 if(err != noErr)
722 ERR("AudioOutputUnitStop failed\n");
725 static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples)
727 AudioBufferList *list;
728 UInt32 frameCount;
729 OSStatus err;
731 // If no samples are requested, just return
732 if(samples == 0)
733 return ALC_NO_ERROR;
735 // Allocate a temporary AudioBufferList to use as the return resamples data
736 list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer));
738 // Point the resampling buffer to the capture buffer
739 list->mNumberBuffers = 1;
740 list->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame;
741 list->mBuffers[0].mDataByteSize = samples * self->frameSize;
742 list->mBuffers[0].mData = buffer;
744 // Resample into another AudioBufferList
745 frameCount = samples;
746 err = AudioConverterFillComplexBuffer(self->audioConverter,
747 ALCcoreAudioCapture_ConvertCallback, self, &frameCount, list, NULL
749 if(err != noErr)
751 ERR("AudioConverterFillComplexBuffer error: %d\n", err);
752 return ALC_INVALID_VALUE;
754 return ALC_NO_ERROR;
757 static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self)
759 return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio;
763 typedef struct ALCcoreAudioBackendFactory {
764 DERIVE_FROM_TYPE(ALCbackendFactory);
765 } ALCcoreAudioBackendFactory;
766 #define ALCCOREAUDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory) } }
768 ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void);
770 static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self);
771 static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit)
772 static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type);
773 static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type);
774 static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
775 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory);
778 ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void)
780 static ALCcoreAudioBackendFactory factory = ALCCOREAUDIOBACKENDFACTORY_INITIALIZER;
781 return STATIC_CAST(ALCbackendFactory, &factory);
785 static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self))
787 return ALC_TRUE;
790 static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type)
792 if(type == ALCbackend_Playback || ALCbackend_Capture)
793 return ALC_TRUE;
794 return ALC_FALSE;
797 static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type)
799 switch(type)
801 case ALL_DEVICE_PROBE:
802 AppendAllDevicesList(ca_device);
803 break;
804 case CAPTURE_DEVICE_PROBE:
805 AppendCaptureDeviceList(ca_device);
806 break;
810 static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
812 if(type == ALCbackend_Playback)
814 ALCcoreAudioPlayback *backend;
815 NEW_OBJ(backend, ALCcoreAudioPlayback)(device);
816 if(!backend) return NULL;
817 return STATIC_CAST(ALCbackend, backend);
819 if(type == ALCbackend_Capture)
821 ALCcoreAudioCapture *backend;
822 NEW_OBJ(backend, ALCcoreAudioCapture)(device);
823 if(!backend) return NULL;
824 return STATIC_CAST(ALCbackend, backend);
827 return NULL;