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., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
18
* Or go to http://www.gnu.org/copyleft/lgpl.html
31
#include <CoreServices/CoreServices.h>
33
#include <AudioUnit/AudioUnit.h>
34
#include <AudioToolbox/AudioToolbox.h>
41
ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate
42
AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
44
AudioConverterRef audioConverter; // Sample rate converter if needed
45
AudioBufferList *bufferList; // Buffer for data coming from the input device
46
ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling
51
static const ALCchar ca_device[] = "CoreAudio Default";
54
static void destroy_buffer_list(AudioBufferList* list)
59
for(i = 0;i < list->mNumberBuffers;i++)
60
free(list->mBuffers[i].mData);
65
static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize)
67
AudioBufferList *list;
69
list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer));
72
list->mNumberBuffers = 1;
74
list->mBuffers[0].mNumberChannels = channelCount;
75
list->mBuffers[0].mDataByteSize = byteSize;
76
list->mBuffers[0].mData = malloc(byteSize);
77
if(list->mBuffers[0].mData == NULL)
86
static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp,
87
UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
89
ALCdevice *device = (ALCdevice*)inRefCon;
90
ca_data *data = (ca_data*)device->ExtraData;
92
aluMixData(device, ioData->mBuffers[0].mData,
93
ioData->mBuffers[0].mDataByteSize / data->frameSize);
98
static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
99
AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData)
101
ALCdevice *device = (ALCdevice*)inUserData;
102
ca_data *data = (ca_data*)device->ExtraData;
104
// Read from the ring buffer and store temporarily in a large buffer
105
ReadRingBuffer(data->ring, data->resampleBuffer, (ALsizei)(*ioNumberDataPackets));
107
// Set the input data
108
ioData->mNumberBuffers = 1;
109
ioData->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame;
110
ioData->mBuffers[0].mData = data->resampleBuffer;
111
ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * data->format.mBytesPerFrame;
116
static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
117
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
118
UInt32 inNumberFrames, AudioBufferList *ioData)
120
ALCdevice *device = (ALCdevice*)inRefCon;
121
ca_data *data = (ca_data*)device->ExtraData;
122
AudioUnitRenderActionFlags flags = 0;
125
// fill the bufferList with data from the input device
126
err = AudioUnitRender(data->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, data->bufferList);
129
ERR("AudioUnitRender error: %d\n", err);
133
WriteRingBuffer(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames);
138
static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName)
140
ComponentDescription desc;
146
deviceName = ca_device;
147
else if(strcmp(deviceName, ca_device) != 0)
148
return ALC_INVALID_VALUE;
150
/* open the default output unit */
151
desc.componentType = kAudioUnitType_Output;
152
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
153
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
154
desc.componentFlags = 0;
155
desc.componentFlagsMask = 0;
157
comp = FindNextComponent(NULL, &desc);
160
ERR("FindNextComponent failed\n");
161
return ALC_INVALID_VALUE;
164
data = calloc(1, sizeof(*data));
166
err = OpenAComponent(comp, &data->audioUnit);
169
ERR("OpenAComponent failed\n");
171
return ALC_INVALID_VALUE;
174
/* init and start the default audio unit... */
175
err = AudioUnitInitialize(data->audioUnit);
178
ERR("AudioUnitInitialize failed\n");
179
CloseComponent(data->audioUnit);
181
return ALC_INVALID_VALUE;
184
device->szDeviceName = strdup(deviceName);
185
device->ExtraData = data;
189
static void ca_close_playback(ALCdevice *device)
191
ca_data *data = (ca_data*)device->ExtraData;
193
AudioUnitUninitialize(data->audioUnit);
194
CloseComponent(data->audioUnit);
197
device->ExtraData = NULL;
200
static ALCboolean ca_reset_playback(ALCdevice *device)
202
ca_data *data = (ca_data*)device->ExtraData;
203
AudioStreamBasicDescription streamFormat;
204
AURenderCallbackStruct input;
208
err = AudioUnitUninitialize(data->audioUnit);
210
ERR("-- AudioUnitUninitialize failed.\n");
212
/* retrieve default output unit's properties (output side) */
213
size = sizeof(AudioStreamBasicDescription);
214
err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
215
if(err != noErr || size != sizeof(AudioStreamBasicDescription))
217
ERR("AudioUnitGetProperty failed\n");
222
TRACE("Output streamFormat of default output unit -\n");
223
TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket);
224
TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame);
225
TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel);
226
TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket);
227
TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame);
228
TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate);
231
/* set default output unit's input side to match output side */
232
err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size);
235
ERR("AudioUnitSetProperty failed\n");
239
if(device->Frequency != streamFormat.mSampleRate)
241
device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
242
streamFormat.mSampleRate /
244
device->Frequency = streamFormat.mSampleRate;
247
/* FIXME: How to tell what channels are what in the output device, and how
248
* to specify what we're giving? eg, 6.0 vs 5.1 */
249
switch(streamFormat.mChannelsPerFrame)
252
device->FmtChans = DevFmtMono;
255
device->FmtChans = DevFmtStereo;
258
device->FmtChans = DevFmtQuad;
261
device->FmtChans = DevFmtX51;
264
device->FmtChans = DevFmtX61;
267
device->FmtChans = DevFmtX71;
270
ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame);
271
device->FmtChans = DevFmtStereo;
272
streamFormat.mChannelsPerFrame = 2;
275
SetDefaultWFXChannelOrder(device);
277
/* use channel count and sample rate from the default output unit's current
278
* parameters, but reset everything else */
279
streamFormat.mFramesPerPacket = 1;
280
switch(device->FmtType)
283
device->FmtType = DevFmtByte;
286
streamFormat.mBitsPerChannel = 8;
287
streamFormat.mBytesPerPacket = streamFormat.mChannelsPerFrame;
288
streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame;
292
device->FmtType = DevFmtShort;
295
streamFormat.mBitsPerChannel = 16;
296
streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
297
streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
300
device->FmtType = DevFmtInt;
303
streamFormat.mBitsPerChannel = 32;
304
streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
305
streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
308
streamFormat.mFormatID = kAudioFormatLinearPCM;
309
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
310
kAudioFormatFlagsNativeEndian |
311
kLinearPCMFormatFlagIsPacked;
313
err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription));
316
ERR("AudioUnitSetProperty failed\n");
321
data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
322
input.inputProc = ca_callback;
323
input.inputProcRefCon = device;
325
err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
328
ERR("AudioUnitSetProperty failed\n");
332
/* init the default audio unit... */
333
err = AudioUnitInitialize(data->audioUnit);
336
ERR("AudioUnitInitialize failed\n");
343
static ALCboolean ca_start_playback(ALCdevice *device)
345
ca_data *data = (ca_data*)device->ExtraData;
348
err = AudioOutputUnitStart(data->audioUnit);
351
ERR("AudioOutputUnitStart failed\n");
358
static void ca_stop_playback(ALCdevice *device)
360
ca_data *data = (ca_data*)device->ExtraData;
363
err = AudioOutputUnitStop(data->audioUnit);
365
ERR("AudioOutputUnitStop failed\n");
368
static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
370
AudioStreamBasicDescription requestedFormat; // The application requested format
371
AudioStreamBasicDescription hardwareFormat; // The hardware format
372
AudioStreamBasicDescription outputFormat; // The AudioUnit output format
373
AURenderCallbackStruct input;
374
ComponentDescription desc;
375
AudioDeviceID inputDevice;
376
UInt32 outputFrameCount;
383
desc.componentType = kAudioUnitType_Output;
384
desc.componentSubType = kAudioUnitSubType_HALOutput;
385
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
386
desc.componentFlags = 0;
387
desc.componentFlagsMask = 0;
389
// Search for component with given description
390
comp = FindNextComponent(NULL, &desc);
393
ERR("FindNextComponent failed\n");
394
return ALC_INVALID_VALUE;
397
data = calloc(1, sizeof(*data));
398
device->ExtraData = data;
400
// Open the component
401
err = OpenAComponent(comp, &data->audioUnit);
404
ERR("OpenAComponent failed\n");
408
// Turn off AudioUnit output
410
err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
413
ERR("AudioUnitSetProperty failed\n");
417
// Turn on AudioUnit input
419
err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
422
ERR("AudioUnitSetProperty failed\n");
426
// Get the default input device
427
propertySize = sizeof(AudioDeviceID);
428
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice);
431
ERR("AudioHardwareGetProperty failed\n");
435
if(inputDevice == kAudioDeviceUnknown)
437
ERR("No input device found\n");
441
// Track the input device
442
err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
445
ERR("AudioUnitSetProperty failed\n");
449
// set capture callback
450
input.inputProc = ca_capture_callback;
451
input.inputProcRefCon = device;
453
err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
456
ERR("AudioUnitSetProperty failed\n");
460
// Initialize the device
461
err = AudioUnitInitialize(data->audioUnit);
464
ERR("AudioUnitInitialize failed\n");
468
// Get the hardware format
469
propertySize = sizeof(AudioStreamBasicDescription);
470
err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize);
471
if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription))
473
ERR("AudioUnitGetProperty failed\n");
477
// Set up the requested format description
478
switch(device->FmtType)
481
requestedFormat.mBitsPerChannel = 8;
482
requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
485
requestedFormat.mBitsPerChannel = 16;
486
requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
489
requestedFormat.mBitsPerChannel = 32;
490
requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
493
requestedFormat.mBitsPerChannel = 32;
494
requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
499
ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
503
switch(device->FmtChans)
506
requestedFormat.mChannelsPerFrame = 1;
509
requestedFormat.mChannelsPerFrame = 2;
517
ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
521
requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8;
522
requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame;
523
requestedFormat.mSampleRate = device->Frequency;
524
requestedFormat.mFormatID = kAudioFormatLinearPCM;
525
requestedFormat.mReserved = 0;
526
requestedFormat.mFramesPerPacket = 1;
528
// save requested format description for later use
529
data->format = requestedFormat;
530
data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
532
// Use intermediate format for sample rate conversion (outputFormat)
533
// Set sample rate to the same as hardware for resampling later
534
outputFormat = requestedFormat;
535
outputFormat.mSampleRate = hardwareFormat.mSampleRate;
537
// Determine sample rate ratio for resampling
538
data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency;
540
// The output format should be the requested format, but using the hardware sample rate
541
// This is because the AudioUnit will automatically scale other properties, except for sample rate
542
err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat));
545
ERR("AudioUnitSetProperty failed\n");
549
// Set the AudioUnit output format frame count
550
outputFrameCount = device->UpdateSize * data->sampleRateRatio;
551
err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount));
554
ERR("AudioUnitSetProperty failed: %d\n", err);
558
// Set up sample converter
559
err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter);
562
ERR("AudioConverterNew failed: %d\n", err);
566
// Create a buffer for use in the resample callback
567
data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio);
569
// Allocate buffer for the AudioUnit output
570
data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio);
571
if(data->bufferList == NULL)
574
data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates);
575
if(data->ring == NULL)
581
DestroyRingBuffer(data->ring);
582
free(data->resampleBuffer);
583
destroy_buffer_list(data->bufferList);
585
if(data->audioConverter)
586
AudioConverterDispose(data->audioConverter);
588
CloseComponent(data->audioUnit);
591
device->ExtraData = NULL;
593
return ALC_INVALID_VALUE;
596
static void ca_close_capture(ALCdevice *device)
598
ca_data *data = (ca_data*)device->ExtraData;
600
DestroyRingBuffer(data->ring);
601
free(data->resampleBuffer);
602
destroy_buffer_list(data->bufferList);
604
AudioConverterDispose(data->audioConverter);
605
CloseComponent(data->audioUnit);
608
device->ExtraData = NULL;
611
static void ca_start_capture(ALCdevice *device)
613
ca_data *data = (ca_data*)device->ExtraData;
614
OSStatus err = AudioOutputUnitStart(data->audioUnit);
616
ERR("AudioOutputUnitStart failed\n");
619
static void ca_stop_capture(ALCdevice *device)
621
ca_data *data = (ca_data*)device->ExtraData;
622
OSStatus err = AudioOutputUnitStop(data->audioUnit);
624
ERR("AudioOutputUnitStop failed\n");
627
static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
629
ca_data *data = (ca_data*)device->ExtraData;
630
AudioBufferList *list;
634
// If no samples are requested, just return
638
// Allocate a temporary AudioBufferList to use as the return resamples data
639
list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer));
641
// Point the resampling buffer to the capture buffer
642
list->mNumberBuffers = 1;
643
list->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame;
644
list->mBuffers[0].mDataByteSize = samples * data->frameSize;
645
list->mBuffers[0].mData = buffer;
647
// Resample into another AudioBufferList
648
frameCount = samples;
649
err = AudioConverterFillComplexBuffer(data->audioConverter, ca_capture_conversion_callback,
650
device, &frameCount, list, NULL);
653
ERR("AudioConverterFillComplexBuffer error: %d\n", err);
654
return ALC_INVALID_VALUE;
659
static ALCuint ca_available_samples(ALCdevice *device)
661
ca_data *data = device->ExtraData;
662
return RingBufferSize(data->ring) / data->sampleRateRatio;
666
static const BackendFuncs ca_funcs = {
680
ALCboolean alc_ca_init(BackendFuncs *func_list)
682
*func_list = ca_funcs;
686
void alc_ca_deinit(void)
690
void alc_ca_probe(enum DevProbe type)
694
case ALL_DEVICE_PROBE:
695
AppendAllDeviceList(ca_device);
697
case CAPTURE_DEVICE_PROBE:
698
AppendCaptureDeviceList(ca_device);