diff options
Diffstat (limited to 'Alc/backends/coreaudio.c')
-rw-r--r-- | Alc/backends/coreaudio.c | 586 |
1 files changed, 345 insertions, 241 deletions
diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 43e881da..adb01fa6 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -23,195 +23,145 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <alloca.h> #include "alMain.h" #include "alu.h" +#include "ringbuffer.h" -#include <CoreServices/CoreServices.h> #include <unistd.h> #include <AudioUnit/AudioUnit.h> #include <AudioToolbox/AudioToolbox.h> +#include "backends/base.h" -typedef struct { - AudioUnit audioUnit; - - ALuint frameSize; - ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate - AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD - AudioConverterRef audioConverter; // Sample rate converter if needed - AudioBufferList *bufferList; // Buffer for data coming from the input device - ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling +static const ALCchar ca_device[] = "CoreAudio Default"; - RingBuffer *ring; -} ca_data; -static const ALCchar ca_device[] = "CoreAudio Default"; +typedef struct ALCcoreAudioPlayback { + DERIVE_FROM_TYPE(ALCbackend); + AudioUnit audioUnit; -static void destroy_buffer_list(AudioBufferList* list) -{ - if(list) - { - UInt32 i; - for(i = 0;i < list->mNumberBuffers;i++) - free(list->mBuffers[i].mData); - free(list); - } -} + ALuint frameSize; + AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD +} ALCcoreAudioPlayback; -static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) -{ - AudioBufferList *list; +static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); +static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self); +static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name); +static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self); +static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self); +static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self); +static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback) - list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer)); - if(list) - { - list->mNumberBuffers = 1; +DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback); - list->mBuffers[0].mNumberChannels = channelCount; - list->mBuffers[0].mDataByteSize = byteSize; - list->mBuffers[0].mData = malloc(byteSize); - if(list->mBuffers[0].mData == NULL) - { - free(list); - list = NULL; - } - } - return list; -} -static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device) { - ALCdevice *device = (ALCdevice*)inRefCon; - ca_data *data = (ca_data*)device->ExtraData; - - aluMixData(device, ioData->mBuffers[0].mData, - ioData->mBuffers[0].mDataByteSize / data->frameSize); + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); - return noErr; + self->frameSize = 0; + memset(&self->format, 0, sizeof(self->format)); } -static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, - AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData) +static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) { - ALCdevice *device = (ALCdevice*)inUserData; - ca_data *data = (ca_data*)device->ExtraData; + AudioUnitUninitialize(self->audioUnit); + AudioComponentInstanceDispose(self->audioUnit); - // Read from the ring buffer and store temporarily in a large buffer - ReadRingBuffer(data->ring, data->resampleBuffer, (ALsizei)(*ioNumberDataPackets)); - - // Set the input data - ioData->mNumberBuffers = 1; - ioData->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame; - ioData->mBuffers[0].mData = data->resampleBuffer; - ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * data->format.mBytesPerFrame; - - return noErr; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } -static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, - UInt32 inNumberFrames, AudioBufferList *ioData) -{ - ALCdevice *device = (ALCdevice*)inRefCon; - ca_data *data = (ca_data*)device->ExtraData; - AudioUnitRenderActionFlags flags = 0; - OSStatus err; - // fill the bufferList with data from the input device - err = AudioUnitRender(data->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, data->bufferList); - if(err != noErr) - { - ERR("AudioUnitRender error: %d\n", err); - return err; - } +static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, + AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp), + UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) +{ + ALCcoreAudioPlayback *self = inRefCon; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - WriteRingBuffer(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames); + ALCcoreAudioPlayback_lock(self); + aluMixData(device, ioData->mBuffers[0].mData, + ioData->mBuffers[0].mDataByteSize / self->frameSize); + ALCcoreAudioPlayback_unlock(self); return noErr; } -static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) + +static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) { - ComponentDescription desc; - Component comp; - ca_data *data; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + AudioComponentDescription desc; + AudioComponent comp; OSStatus err; - if(!deviceName) - deviceName = ca_device; - else if(strcmp(deviceName, ca_device) != 0) + if(!name) + name = ca_device; + else if(strcmp(name, ca_device) != 0) return ALC_INVALID_VALUE; /* open the default output unit */ desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else desc.componentSubType = kAudioUnitSubType_DefaultOutput; +#endif desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; - comp = FindNextComponent(NULL, &desc); + comp = AudioComponentFindNext(NULL, &desc); if(comp == NULL) { - ERR("FindNextComponent failed\n"); + ERR("AudioComponentFindNext failed\n"); return ALC_INVALID_VALUE; } - data = calloc(1, sizeof(*data)); - - err = OpenAComponent(comp, &data->audioUnit); + err = AudioComponentInstanceNew(comp, &self->audioUnit); if(err != noErr) { - ERR("OpenAComponent failed\n"); - free(data); + ERR("AudioComponentInstanceNew failed\n"); return ALC_INVALID_VALUE; } /* init and start the default audio unit... */ - err = AudioUnitInitialize(data->audioUnit); + err = AudioUnitInitialize(self->audioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - CloseComponent(data->audioUnit); - free(data); + AudioComponentInstanceDispose(self->audioUnit); return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, deviceName); - device->ExtraData = data; + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } -static void ca_close_playback(ALCdevice *device) +static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) { - ca_data *data = (ca_data*)device->ExtraData; - - AudioUnitUninitialize(data->audioUnit); - CloseComponent(data->audioUnit); - - free(data); - device->ExtraData = NULL; -} - -static ALCboolean ca_reset_playback(ALCdevice *device) -{ - ca_data *data = (ca_data*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; AudioStreamBasicDescription streamFormat; AURenderCallbackStruct input; OSStatus err; UInt32 size; - err = AudioUnitUninitialize(data->audioUnit); + err = AudioUnitUninitialize(self->audioUnit); if(err != noErr) ERR("-- AudioUnitUninitialize failed.\n"); /* retrieve default output unit's properties (output side) */ size = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); + err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); if(err != noErr || size != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -229,7 +179,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device) #endif /* set default output unit's input side to match output side */ - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -238,7 +188,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device) if(device->Frequency != streamFormat.mSampleRate) { - device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * + device->NumUpdates = (ALuint)((ALuint64)device->NumUpdates * streamFormat.mSampleRate / device->Frequency); device->Frequency = streamFormat.mSampleRate; @@ -313,7 +263,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device) streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked; - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -321,11 +271,11 @@ static ALCboolean ca_reset_playback(ALCdevice *device) } /* setup callback */ - data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - input.inputProc = ca_callback; - input.inputProcRefCon = device; + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + input.inputProc = ALCcoreAudioPlayback_MixerProc; + input.inputProcRefCon = self; - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -333,7 +283,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device) } /* init the default audio unit... */ - err = AudioUnitInitialize(data->audioUnit); + err = AudioUnitInitialize(self->audioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -343,12 +293,9 @@ static ALCboolean ca_reset_playback(ALCdevice *device) return ALC_TRUE; } -static ALCboolean ca_start_playback(ALCdevice *device) +static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) { - ca_data *data = (ca_data*)device->ExtraData; - OSStatus err; - - err = AudioOutputUnitStart(data->audioUnit); + OSStatus err = AudioOutputUnitStart(self->audioUnit); if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -358,64 +305,196 @@ static ALCboolean ca_start_playback(ALCdevice *device) return ALC_TRUE; } -static void ca_stop_playback(ALCdevice *device) +static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) +{ + OSStatus err = AudioOutputUnitStop(self->audioUnit); + if(err != noErr) + ERR("AudioOutputUnitStop failed\n"); +} + + + + +typedef struct ALCcoreAudioCapture { + DERIVE_FROM_TYPE(ALCbackend); + + AudioUnit audioUnit; + + ALuint frameSize; + ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate + AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD + + AudioConverterRef audioConverter; // Sample rate converter if needed + AudioBufferList *bufferList; // Buffer for data coming from the input device + ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling + + ll_ringbuffer_t *ring; +} ALCcoreAudioCapture; + +static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); +static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self); +static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name); +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self); +static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self); +static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self); +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture) + +DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); + + +static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) +{ + AudioBufferList *list; + + list = calloc(1, FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize); + if(list) + { + list->mNumberBuffers = 1; + + list->mBuffers[0].mNumberChannels = channelCount; + list->mBuffers[0].mDataByteSize = byteSize; + list->mBuffers[0].mData = &list->mBuffers[1]; + } + return list; +} + +static void destroy_buffer_list(AudioBufferList *list) +{ + free(list); +} + + +static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); + + self->audioUnit = 0; + self->audioConverter = NULL; + self->bufferList = NULL; + self->resampleBuffer = NULL; + self->ring = NULL; +} + +static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) +{ + ll_ringbuffer_free(self->ring); + self->ring = NULL; + + free(self->resampleBuffer); + self->resampleBuffer = NULL; + + destroy_buffer_list(self->bufferList); + self->bufferList = NULL; + + if(self->audioConverter) + AudioConverterDispose(self->audioConverter); + self->audioConverter = NULL; + + if(self->audioUnit) + AudioComponentInstanceDispose(self->audioUnit); + self->audioUnit = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, + AudioUnitRenderActionFlags* UNUSED(ioActionFlags), + const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), + UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData)) { - ca_data *data = (ca_data*)device->ExtraData; + ALCcoreAudioCapture *self = inRefCon; + AudioUnitRenderActionFlags flags = 0; OSStatus err; - err = AudioOutputUnitStop(data->audioUnit); + // fill the bufferList with data from the input device + err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList); if(err != noErr) - ERR("AudioOutputUnitStop failed\n"); + { + ERR("AudioUnitRender error: %d\n", err); + return err; + } + + ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames); + + return noErr; +} + +static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter), + UInt32 *ioNumberDataPackets, AudioBufferList *ioData, + AudioStreamPacketDescription** UNUSED(outDataPacketDescription), + void *inUserData) +{ + ALCcoreAudioCapture *self = inUserData; + + // Read from the ring buffer and store temporarily in a large buffer + ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets); + + // Set the input data + ioData->mNumberBuffers = 1; + ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; + ioData->mBuffers[0].mData = self->resampleBuffer; + ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame; + + return noErr; } -static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) + +static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name) { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; AudioStreamBasicDescription requestedFormat; // The application requested format AudioStreamBasicDescription hardwareFormat; // The hardware format AudioStreamBasicDescription outputFormat; // The AudioUnit output format AURenderCallbackStruct input; - ComponentDescription desc; - AudioDeviceID inputDevice; + AudioComponentDescription desc; UInt32 outputFrameCount; UInt32 propertySize; + AudioObjectPropertyAddress propertyAddress; UInt32 enableIO; - Component comp; - ca_data *data; + AudioComponent comp; OSStatus err; - if(!deviceName) - deviceName = ca_device; - else if(strcmp(deviceName, ca_device) != 0) + if(!name) + name = ca_device; + else if(strcmp(name, ca_device) != 0) return ALC_INVALID_VALUE; desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else desc.componentSubType = kAudioUnitSubType_HALOutput; +#endif desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; // Search for component with given description - comp = FindNextComponent(NULL, &desc); + comp = AudioComponentFindNext(NULL, &desc); if(comp == NULL) { - ERR("FindNextComponent failed\n"); + ERR("AudioComponentFindNext failed\n"); return ALC_INVALID_VALUE; } - data = calloc(1, sizeof(*data)); - device->ExtraData = data; - // Open the component - err = OpenAComponent(comp, &data->audioUnit); + err = AudioComponentInstanceNew(comp, &self->audioUnit); if(err != noErr) { - ERR("OpenAComponent failed\n"); + ERR("AudioComponentInstanceNew failed\n"); goto error; } // Turn off AudioUnit output enableIO = 0; - err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -424,22 +503,28 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) // Turn on AudioUnit input enableIO = 1; - err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } +#if !TARGET_OS_IOS // Get the default input device + AudioDeviceID inputDevice = kAudioDeviceUnknown; + propertySize = sizeof(AudioDeviceID); - err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + + err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice); if(err != noErr) { - ERR("AudioHardwareGetProperty failed\n"); + ERR("AudioObjectGetPropertyData failed\n"); goto error; } - if(inputDevice == kAudioDeviceUnknown) { ERR("No input device found\n"); @@ -447,18 +532,19 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Track the input device - err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } +#endif // set capture callback - input.inputProc = ca_capture_callback; - input.inputProcRefCon = device; + input.inputProc = ALCcoreAudioCapture_RecordProc; + input.inputProcRefCon = self; - err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -466,7 +552,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Initialize the device - err = AudioUnitInitialize(data->audioUnit); + err = AudioUnitInitialize(self->audioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -475,7 +561,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); + err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -522,7 +608,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: - case DevFmtBFormat3D: + case DevFmtAmbi3D: ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); goto error; } @@ -535,8 +621,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) requestedFormat.mFramesPerPacket = 1; // save requested format description for later use - data->format = requestedFormat; - data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->format = requestedFormat; + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later @@ -544,11 +630,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) outputFormat.mSampleRate = hardwareFormat.mSampleRate; // Determine sample rate ratio for resampling - data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; + self->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -556,8 +642,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Set the AudioUnit output format frame count - outputFrameCount = device->UpdateSize * data->sampleRateRatio; - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); + outputFrameCount = device->UpdateSize * self->sampleRateRatio; + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) { ERR("AudioUnitSetProperty failed: %d\n", err); @@ -565,7 +651,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Set up sample converter - err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter); + err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter); if(err != noErr) { ERR("AudioConverterNew failed: %d\n", err); @@ -573,92 +659,83 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Create a buffer for use in the resample callback - data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio); + self->resampleBuffer = malloc(device->UpdateSize * self->frameSize * self->sampleRateRatio); // Allocate buffer for the AudioUnit output - data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio); - if(data->bufferList == NULL) + self->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->frameSize * self->sampleRateRatio); + if(self->bufferList == NULL) goto error; - data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates); - if(data->ring == NULL) - goto error; + self->ring = ll_ringbuffer_create( + (size_t)ceil(device->UpdateSize*self->sampleRateRatio*device->NumUpdates), + self->frameSize, false + ); + if(!self->ring) goto error; - al_string_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; error: - DestroyRingBuffer(data->ring); - free(data->resampleBuffer); - destroy_buffer_list(data->bufferList); - - if(data->audioConverter) - AudioConverterDispose(data->audioConverter); - if(data->audioUnit) - CloseComponent(data->audioUnit); - - free(data); - device->ExtraData = NULL; + ll_ringbuffer_free(self->ring); + self->ring = NULL; + free(self->resampleBuffer); + self->resampleBuffer = NULL; + destroy_buffer_list(self->bufferList); + self->bufferList = NULL; + + if(self->audioConverter) + AudioConverterDispose(self->audioConverter); + self->audioConverter = NULL; + if(self->audioUnit) + AudioComponentInstanceDispose(self->audioUnit); + self->audioUnit = 0; return ALC_INVALID_VALUE; } -static void ca_close_capture(ALCdevice *device) -{ - ca_data *data = (ca_data*)device->ExtraData; - - DestroyRingBuffer(data->ring); - free(data->resampleBuffer); - destroy_buffer_list(data->bufferList); - AudioConverterDispose(data->audioConverter); - CloseComponent(data->audioUnit); - - free(data); - device->ExtraData = NULL; -} - -static void ca_start_capture(ALCdevice *device) +static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) { - ca_data *data = (ca_data*)device->ExtraData; - OSStatus err = AudioOutputUnitStart(data->audioUnit); + OSStatus err = AudioOutputUnitStart(self->audioUnit); if(err != noErr) + { ERR("AudioOutputUnitStart failed\n"); + return ALC_FALSE; + } + return ALC_TRUE; } -static void ca_stop_capture(ALCdevice *device) +static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) { - ca_data *data = (ca_data*)device->ExtraData; - OSStatus err = AudioOutputUnitStop(data->audioUnit); + OSStatus err = AudioOutputUnitStop(self->audioUnit); if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } -static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) +static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples) { - ca_data *data = (ca_data*)device->ExtraData; - AudioBufferList *list; + union { + ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)]; + AudioBufferList list; + } audiobuf = { { 0 } }; UInt32 frameCount; OSStatus err; // If no samples are requested, just return - if(samples == 0) - return ALC_NO_ERROR; - - // Allocate a temporary AudioBufferList to use as the return resamples data - list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer)); + if(samples == 0) return ALC_NO_ERROR; // Point the resampling buffer to the capture buffer - list->mNumberBuffers = 1; - list->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame; - list->mBuffers[0].mDataByteSize = samples * data->frameSize; - list->mBuffers[0].mData = buffer; + audiobuf.list.mNumberBuffers = 1; + audiobuf.list.mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mDataByteSize = samples * self->frameSize; + audiobuf.list.mBuffers[0].mData = buffer; // Resample into another AudioBufferList frameCount = samples; - err = AudioConverterFillComplexBuffer(data->audioConverter, ca_capture_conversion_callback, - device, &frameCount, list, NULL); + err = AudioConverterFillComplexBuffer(self->audioConverter, + ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL + ); if(err != noErr) { ERR("AudioConverterFillComplexBuffer error: %d\n", err); @@ -667,46 +744,73 @@ static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint sa return ALC_NO_ERROR; } -static ALCuint ca_available_samples(ALCdevice *device) +static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) { - ca_data *data = device->ExtraData; - return RingBufferSize(data->ring) / data->sampleRateRatio; + return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio; } -static const BackendFuncs ca_funcs = { - ca_open_playback, - ca_close_playback, - ca_reset_playback, - ca_start_playback, - ca_stop_playback, - ca_open_capture, - ca_close_capture, - ca_start_capture, - ca_stop_capture, - ca_capture_samples, - ca_available_samples -}; - -ALCboolean alc_ca_init(BackendFuncs *func_list) +typedef struct ALCcoreAudioBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCcoreAudioBackendFactory; +#define ALCCOREAUDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory) } } + +ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); + +static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self); +static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type); +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory); + + +ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void) +{ + static ALCcoreAudioBackendFactory factory = ALCCOREAUDIOBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self)) { - *func_list = ca_funcs; return ALC_TRUE; } -void alc_ca_deinit(void) +static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type) { + if(type == ALCbackend_Playback || ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; } -void alc_ca_probe(enum DevProbe type) +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - AppendAllDevicesList(ca_device); - break; case CAPTURE_DEVICE_PROBE: - AppendCaptureDeviceList(ca_device); + alstr_append_range(outnames, ca_device, ca_device+sizeof(ca_device)); break; } } + +static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCcoreAudioPlayback *backend; + NEW_OBJ(backend, ALCcoreAudioPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCcoreAudioCapture *backend; + NEW_OBJ(backend, ALCcoreAudioCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} |