~ubuntu-branches/ubuntu/vivid/openal-soft/vivid

« back to all changes in this revision

Viewing changes to Alc/backends/coreaudio.c

  • Committer: Package Import Robot
  • Author(s): Andres Mejia
  • Date: 2012-04-01 16:19:00 UTC
  • mfrom: (0.2.9)
  • Revision ID: package-import@ubuntu.com-20120401161900-4dy81gsmc70tvon2
Tags: 1:1.14-1
* New upstream release.
* Add CPPFLAGS to CFLAGS. (Closes: #666095)
* Enable new sndio support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
8
 *
 
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.
 
13
 *
 
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
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
 
 
27
#include "alMain.h"
 
28
#include "AL/al.h"
 
29
#include "AL/alc.h"
 
30
 
 
31
#include <CoreServices/CoreServices.h>
 
32
#include <unistd.h>
 
33
#include <AudioUnit/AudioUnit.h>
 
34
#include <AudioToolbox/AudioToolbox.h>
 
35
 
 
36
 
 
37
typedef struct {
 
38
    AudioUnit audioUnit;
 
39
 
 
40
    ALuint frameSize;
 
41
    ALdouble sampleRateRatio;              // Ratio of hardware sample rate / requested sample rate
 
42
    AudioStreamBasicDescription format;    // This is the OpenAL format as a CoreAudio ASBD
 
43
 
 
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
 
47
 
 
48
    RingBuffer *ring;
 
49
} ca_data;
 
50
 
 
51
static const ALCchar ca_device[] = "CoreAudio Default";
 
52
 
 
53
 
 
54
static void destroy_buffer_list(AudioBufferList* list)
 
55
{
 
56
    if(list)
 
57
    {
 
58
        UInt32 i;
 
59
        for(i = 0;i < list->mNumberBuffers;i++)
 
60
            free(list->mBuffers[i].mData);
 
61
        free(list);
 
62
    }
 
63
}
 
64
 
 
65
static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize)
 
66
{
 
67
    AudioBufferList *list;
 
68
 
 
69
    list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer));
 
70
    if(list)
 
71
    {
 
72
        list->mNumberBuffers = 1;
 
73
 
 
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)
 
78
        {
 
79
            free(list);
 
80
            list = NULL;
 
81
        }
 
82
    }
 
83
    return list;
 
84
}
 
85
 
 
86
static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp,
 
87
                            UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
 
88
{
 
89
    ALCdevice *device = (ALCdevice*)inRefCon;
 
90
    ca_data *data = (ca_data*)device->ExtraData;
 
91
 
 
92
    aluMixData(device, ioData->mBuffers[0].mData,
 
93
               ioData->mBuffers[0].mDataByteSize / data->frameSize);
 
94
 
 
95
    return noErr;
 
96
}
 
97
 
 
98
static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
 
99
        AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData)
 
100
{
 
101
    ALCdevice *device = (ALCdevice*)inUserData;
 
102
    ca_data *data = (ca_data*)device->ExtraData;
 
103
 
 
104
    // Read from the ring buffer and store temporarily in a large buffer
 
105
    ReadRingBuffer(data->ring, data->resampleBuffer, (ALsizei)(*ioNumberDataPackets));
 
106
 
 
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;
 
112
 
 
113
    return noErr;
 
114
}
 
115
 
 
116
static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
 
117
                                    const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
 
118
                                    UInt32 inNumberFrames, AudioBufferList *ioData)
 
119
{
 
120
    ALCdevice *device = (ALCdevice*)inRefCon;
 
121
    ca_data *data = (ca_data*)device->ExtraData;
 
122
    AudioUnitRenderActionFlags flags = 0;
 
123
    OSStatus err;
 
124
 
 
125
    // fill the bufferList with data from the input device
 
126
    err = AudioUnitRender(data->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, data->bufferList);
 
127
    if(err != noErr)
 
128
    {
 
129
        ERR("AudioUnitRender error: %d\n", err);
 
130
        return err;
 
131
    }
 
132
 
 
133
    WriteRingBuffer(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames);
 
134
 
 
135
    return noErr;
 
136
}
 
137
 
 
138
static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName)
 
139
{
 
140
    ComponentDescription desc;
 
141
    Component comp;
 
142
    ca_data *data;
 
143
    OSStatus err;
 
144
 
 
145
    if(!deviceName)
 
146
        deviceName = ca_device;
 
147
    else if(strcmp(deviceName, ca_device) != 0)
 
148
        return ALC_INVALID_VALUE;
 
149
 
 
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;
 
156
 
 
157
    comp = FindNextComponent(NULL, &desc);
 
158
    if(comp == NULL)
 
159
    {
 
160
        ERR("FindNextComponent failed\n");
 
161
        return ALC_INVALID_VALUE;
 
162
    }
 
163
 
 
164
    data = calloc(1, sizeof(*data));
 
165
 
 
166
    err = OpenAComponent(comp, &data->audioUnit);
 
167
    if(err != noErr)
 
168
    {
 
169
        ERR("OpenAComponent failed\n");
 
170
        free(data);
 
171
        return ALC_INVALID_VALUE;
 
172
    }
 
173
 
 
174
    /* init and start the default audio unit... */
 
175
    err = AudioUnitInitialize(data->audioUnit);
 
176
    if(err != noErr)
 
177
    {
 
178
        ERR("AudioUnitInitialize failed\n");
 
179
        CloseComponent(data->audioUnit);
 
180
        free(data);
 
181
        return ALC_INVALID_VALUE;
 
182
    }
 
183
 
 
184
    device->szDeviceName = strdup(deviceName);
 
185
    device->ExtraData = data;
 
186
    return ALC_NO_ERROR;
 
187
}
 
188
 
 
189
static void ca_close_playback(ALCdevice *device)
 
190
{
 
191
    ca_data *data = (ca_data*)device->ExtraData;
 
192
 
 
193
    AudioUnitUninitialize(data->audioUnit);
 
194
    CloseComponent(data->audioUnit);
 
195
 
 
196
    free(data);
 
197
    device->ExtraData = NULL;
 
198
}
 
199
 
 
200
static ALCboolean ca_reset_playback(ALCdevice *device)
 
201
{
 
202
    ca_data *data = (ca_data*)device->ExtraData;
 
203
    AudioStreamBasicDescription streamFormat;
 
204
    AURenderCallbackStruct input;
 
205
    OSStatus err;
 
206
    UInt32 size;
 
207
 
 
208
    err = AudioUnitUninitialize(data->audioUnit);
 
209
    if(err != noErr)
 
210
        ERR("-- AudioUnitUninitialize failed.\n");
 
211
 
 
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))
 
216
    {
 
217
        ERR("AudioUnitGetProperty failed\n");
 
218
        return ALC_FALSE;
 
219
    }
 
220
 
 
221
#if 0
 
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);
 
229
#endif
 
230
 
 
231
    /* set default output unit's input side to match output side */
 
232
    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size);
 
233
    if(err != noErr)
 
234
    {
 
235
        ERR("AudioUnitSetProperty failed\n");
 
236
        return ALC_FALSE;
 
237
    }
 
238
 
 
239
    if(device->Frequency != streamFormat.mSampleRate)
 
240
    {
 
241
        device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
 
242
                                      streamFormat.mSampleRate /
 
243
                                      device->Frequency);
 
244
        device->Frequency = streamFormat.mSampleRate;
 
245
    }
 
246
 
 
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)
 
250
    {
 
251
        case 1:
 
252
            device->FmtChans = DevFmtMono;
 
253
            break;
 
254
        case 2:
 
255
            device->FmtChans = DevFmtStereo;
 
256
            break;
 
257
        case 4:
 
258
            device->FmtChans = DevFmtQuad;
 
259
            break;
 
260
        case 6:
 
261
            device->FmtChans = DevFmtX51;
 
262
            break;
 
263
        case 7:
 
264
            device->FmtChans = DevFmtX61;
 
265
            break;
 
266
        case 8:
 
267
            device->FmtChans = DevFmtX71;
 
268
            break;
 
269
        default:
 
270
            ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame);
 
271
            device->FmtChans = DevFmtStereo;
 
272
            streamFormat.mChannelsPerFrame = 2;
 
273
            break;
 
274
    }
 
275
    SetDefaultWFXChannelOrder(device);
 
276
 
 
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)
 
281
    {
 
282
        case DevFmtUByte:
 
283
            device->FmtType = DevFmtByte;
 
284
            /* fall-through */
 
285
        case DevFmtByte:
 
286
            streamFormat.mBitsPerChannel = 8;
 
287
            streamFormat.mBytesPerPacket = streamFormat.mChannelsPerFrame;
 
288
            streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame;
 
289
            break;
 
290
        case DevFmtUShort:
 
291
        case DevFmtFloat:
 
292
            device->FmtType = DevFmtShort;
 
293
            /* fall-through */
 
294
        case DevFmtShort:
 
295
            streamFormat.mBitsPerChannel = 16;
 
296
            streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
 
297
            streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
 
298
            break;
 
299
        case DevFmtUInt:
 
300
            device->FmtType = DevFmtInt;
 
301
            /* fall-through */
 
302
        case DevFmtInt:
 
303
            streamFormat.mBitsPerChannel = 32;
 
304
            streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
 
305
            streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
 
306
            break;
 
307
    }
 
308
    streamFormat.mFormatID = kAudioFormatLinearPCM;
 
309
    streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
 
310
                                kAudioFormatFlagsNativeEndian |
 
311
                                kLinearPCMFormatFlagIsPacked;
 
312
 
 
313
    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription));
 
314
    if(err != noErr)
 
315
    {
 
316
        ERR("AudioUnitSetProperty failed\n");
 
317
        return ALC_FALSE;
 
318
    }
 
319
 
 
320
    /* setup callback */
 
321
    data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
 
322
    input.inputProc = ca_callback;
 
323
    input.inputProcRefCon = device;
 
324
 
 
325
    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
 
326
    if(err != noErr)
 
327
    {
 
328
        ERR("AudioUnitSetProperty failed\n");
 
329
        return ALC_FALSE;
 
330
    }
 
331
 
 
332
    /* init the default audio unit... */
 
333
    err = AudioUnitInitialize(data->audioUnit);
 
334
    if(err != noErr)
 
335
    {
 
336
        ERR("AudioUnitInitialize failed\n");
 
337
        return ALC_FALSE;
 
338
    }
 
339
 
 
340
    return ALC_TRUE;
 
341
}
 
342
 
 
343
static ALCboolean ca_start_playback(ALCdevice *device)
 
344
{
 
345
    ca_data *data = (ca_data*)device->ExtraData;
 
346
    OSStatus err;
 
347
 
 
348
    err = AudioOutputUnitStart(data->audioUnit);
 
349
    if(err != noErr)
 
350
    {
 
351
        ERR("AudioOutputUnitStart failed\n");
 
352
        return ALC_FALSE;
 
353
    }
 
354
 
 
355
    return ALC_TRUE;
 
356
}
 
357
 
 
358
static void ca_stop_playback(ALCdevice *device)
 
359
{
 
360
    ca_data *data = (ca_data*)device->ExtraData;
 
361
    OSStatus err;
 
362
 
 
363
    err = AudioOutputUnitStop(data->audioUnit);
 
364
    if(err != noErr)
 
365
        ERR("AudioOutputUnitStop failed\n");
 
366
}
 
367
 
 
368
static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
 
369
{
 
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;
 
377
    UInt32 propertySize;
 
378
    UInt32 enableIO;
 
379
    Component comp;
 
380
    ca_data *data;
 
381
    OSStatus err;
 
382
 
 
383
    desc.componentType = kAudioUnitType_Output;
 
384
    desc.componentSubType = kAudioUnitSubType_HALOutput;
 
385
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
 
386
    desc.componentFlags = 0;
 
387
    desc.componentFlagsMask = 0;
 
388
 
 
389
    // Search for component with given description
 
390
    comp = FindNextComponent(NULL, &desc);
 
391
    if(comp == NULL)
 
392
    {
 
393
        ERR("FindNextComponent failed\n");
 
394
        return ALC_INVALID_VALUE;
 
395
    }
 
396
 
 
397
    data = calloc(1, sizeof(*data));
 
398
    device->ExtraData = data;
 
399
 
 
400
    // Open the component
 
401
    err = OpenAComponent(comp, &data->audioUnit);
 
402
    if(err != noErr)
 
403
    {
 
404
        ERR("OpenAComponent failed\n");
 
405
        goto error;
 
406
    }
 
407
 
 
408
    // Turn off AudioUnit output
 
409
    enableIO = 0;
 
410
    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
 
411
    if(err != noErr)
 
412
    {
 
413
        ERR("AudioUnitSetProperty failed\n");
 
414
        goto error;
 
415
    }
 
416
 
 
417
    // Turn on AudioUnit input
 
418
    enableIO = 1;
 
419
    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
 
420
    if(err != noErr)
 
421
    {
 
422
        ERR("AudioUnitSetProperty failed\n");
 
423
        goto error;
 
424
    }
 
425
 
 
426
    // Get the default input device
 
427
    propertySize = sizeof(AudioDeviceID);
 
428
    err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice);
 
429
    if(err != noErr)
 
430
    {
 
431
        ERR("AudioHardwareGetProperty failed\n");
 
432
        goto error;
 
433
    }
 
434
 
 
435
    if(inputDevice == kAudioDeviceUnknown)
 
436
    {
 
437
        ERR("No input device found\n");
 
438
        goto error;
 
439
    }
 
440
 
 
441
    // Track the input device
 
442
    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
 
443
    if(err != noErr)
 
444
    {
 
445
        ERR("AudioUnitSetProperty failed\n");
 
446
        goto error;
 
447
    }
 
448
 
 
449
    // set capture callback
 
450
    input.inputProc = ca_capture_callback;
 
451
    input.inputProcRefCon = device;
 
452
 
 
453
    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
 
454
    if(err != noErr)
 
455
    {
 
456
        ERR("AudioUnitSetProperty failed\n");
 
457
        goto error;
 
458
    }
 
459
 
 
460
    // Initialize the device
 
461
    err = AudioUnitInitialize(data->audioUnit);
 
462
    if(err != noErr)
 
463
    {
 
464
        ERR("AudioUnitInitialize failed\n");
 
465
        goto error;
 
466
    }
 
467
 
 
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))
 
472
    {
 
473
        ERR("AudioUnitGetProperty failed\n");
 
474
        goto error;
 
475
    }
 
476
 
 
477
    // Set up the requested format description
 
478
    switch(device->FmtType)
 
479
    {
 
480
        case DevFmtUByte:
 
481
            requestedFormat.mBitsPerChannel = 8;
 
482
            requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
 
483
            break;
 
484
        case DevFmtShort:
 
485
            requestedFormat.mBitsPerChannel = 16;
 
486
            requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
 
487
            break;
 
488
        case DevFmtInt:
 
489
            requestedFormat.mBitsPerChannel = 32;
 
490
            requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
 
491
            break;
 
492
        case DevFmtFloat:
 
493
            requestedFormat.mBitsPerChannel = 32;
 
494
            requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
 
495
            break;
 
496
        case DevFmtByte:
 
497
        case DevFmtUShort:
 
498
        case DevFmtUInt:
 
499
            ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
 
500
            goto error;
 
501
    }
 
502
 
 
503
    switch(device->FmtChans)
 
504
    {
 
505
        case DevFmtMono:
 
506
            requestedFormat.mChannelsPerFrame = 1;
 
507
            break;
 
508
        case DevFmtStereo:
 
509
            requestedFormat.mChannelsPerFrame = 2;
 
510
            break;
 
511
 
 
512
        case DevFmtQuad:
 
513
        case DevFmtX51:
 
514
        case DevFmtX51Side:
 
515
        case DevFmtX61:
 
516
        case DevFmtX71:
 
517
            ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
 
518
            goto error;
 
519
    }
 
520
 
 
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;
 
527
 
 
528
    // save requested format description for later use
 
529
    data->format = requestedFormat;
 
530
    data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
 
531
 
 
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;
 
536
 
 
537
    // Determine sample rate ratio for resampling
 
538
    data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency;
 
539
 
 
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));
 
543
    if(err != noErr)
 
544
    {
 
545
        ERR("AudioUnitSetProperty failed\n");
 
546
        goto error;
 
547
    }
 
548
 
 
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));
 
552
    if(err != noErr)
 
553
    {
 
554
        ERR("AudioUnitSetProperty failed: %d\n", err);
 
555
        goto error;
 
556
    }
 
557
 
 
558
    // Set up sample converter
 
559
    err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter);
 
560
    if(err != noErr)
 
561
    {
 
562
        ERR("AudioConverterNew failed: %d\n", err);
 
563
        goto error;
 
564
    }
 
565
 
 
566
    // Create a buffer for use in the resample callback
 
567
    data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio);
 
568
 
 
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)
 
572
        goto error;
 
573
 
 
574
    data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates);
 
575
    if(data->ring == NULL)
 
576
        goto error;
 
577
 
 
578
    return ALC_NO_ERROR;
 
579
 
 
580
error:
 
581
    DestroyRingBuffer(data->ring);
 
582
    free(data->resampleBuffer);
 
583
    destroy_buffer_list(data->bufferList);
 
584
 
 
585
    if(data->audioConverter)
 
586
        AudioConverterDispose(data->audioConverter);
 
587
    if(data->audioUnit)
 
588
        CloseComponent(data->audioUnit);
 
589
 
 
590
    free(data);
 
591
    device->ExtraData = NULL;
 
592
 
 
593
    return ALC_INVALID_VALUE;
 
594
}
 
595
 
 
596
static void ca_close_capture(ALCdevice *device)
 
597
{
 
598
    ca_data *data = (ca_data*)device->ExtraData;
 
599
 
 
600
    DestroyRingBuffer(data->ring);
 
601
    free(data->resampleBuffer);
 
602
    destroy_buffer_list(data->bufferList);
 
603
 
 
604
    AudioConverterDispose(data->audioConverter);
 
605
    CloseComponent(data->audioUnit);
 
606
 
 
607
    free(data);
 
608
    device->ExtraData = NULL;
 
609
}
 
610
 
 
611
static void ca_start_capture(ALCdevice *device)
 
612
{
 
613
    ca_data *data = (ca_data*)device->ExtraData;
 
614
    OSStatus err = AudioOutputUnitStart(data->audioUnit);
 
615
    if(err != noErr)
 
616
        ERR("AudioOutputUnitStart failed\n");
 
617
}
 
618
 
 
619
static void ca_stop_capture(ALCdevice *device)
 
620
{
 
621
    ca_data *data = (ca_data*)device->ExtraData;
 
622
    OSStatus err = AudioOutputUnitStop(data->audioUnit);
 
623
    if(err != noErr)
 
624
        ERR("AudioOutputUnitStop failed\n");
 
625
}
 
626
 
 
627
static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
 
628
{
 
629
    ca_data *data = (ca_data*)device->ExtraData;
 
630
    AudioBufferList *list;
 
631
    UInt32 frameCount;
 
632
    OSStatus err;
 
633
 
 
634
    // If no samples are requested, just return
 
635
    if(samples == 0)
 
636
        return ALC_NO_ERROR;
 
637
 
 
638
    // Allocate a temporary AudioBufferList to use as the return resamples data
 
639
    list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer));
 
640
 
 
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;
 
646
 
 
647
    // Resample into another AudioBufferList
 
648
    frameCount = samples;
 
649
    err = AudioConverterFillComplexBuffer(data->audioConverter, ca_capture_conversion_callback,
 
650
                                          device, &frameCount, list, NULL);
 
651
    if(err != noErr)
 
652
    {
 
653
        ERR("AudioConverterFillComplexBuffer error: %d\n", err);
 
654
        return ALC_INVALID_VALUE;
 
655
    }
 
656
    return ALC_NO_ERROR;
 
657
}
 
658
 
 
659
static ALCuint ca_available_samples(ALCdevice *device)
 
660
{
 
661
    ca_data *data = device->ExtraData;
 
662
    return RingBufferSize(data->ring) / data->sampleRateRatio;
 
663
}
 
664
 
 
665
 
 
666
static const BackendFuncs ca_funcs = {
 
667
    ca_open_playback,
 
668
    ca_close_playback,
 
669
    ca_reset_playback,
 
670
    ca_start_playback,
 
671
    ca_stop_playback,
 
672
    ca_open_capture,
 
673
    ca_close_capture,
 
674
    ca_start_capture,
 
675
    ca_stop_capture,
 
676
    ca_capture_samples,
 
677
    ca_available_samples
 
678
};
 
679
 
 
680
ALCboolean alc_ca_init(BackendFuncs *func_list)
 
681
{
 
682
    *func_list = ca_funcs;
 
683
    return ALC_TRUE;
 
684
}
 
685
 
 
686
void alc_ca_deinit(void)
 
687
{
 
688
}
 
689
 
 
690
void alc_ca_probe(enum DevProbe type)
 
691
{
 
692
    switch(type)
 
693
    {
 
694
        case ALL_DEVICE_PROBE:
 
695
            AppendAllDeviceList(ca_device);
 
696
            break;
 
697
        case CAPTURE_DEVICE_PROBE:
 
698
            AppendCaptureDeviceList(ca_device);
 
699
            break;
 
700
    }
 
701
}