diff --git a/Alc/ALc.c b/Alc/ALc.c index 0cc36cad..7d4f4de3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -72,7 +72,7 @@ static struct BackendInfo BackendList[] = { { "alsa", ALCalsaBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_COREAUDIO - { "core", NULL, alc_ca_init, alc_ca_deinit, alc_ca_probe, EmptyFuncs }, + { "core", ALCcoreAudioBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_OSS { "oss", ALCossBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 4f398047..961a4d1a 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -137,6 +137,7 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \ ALCbackendFactory *ALCpulseBackendFactory_getFactory(void); ALCbackendFactory *ALCalsaBackendFactory_getFactory(void); +ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); ALCbackendFactory *ALCossBackendFactory_getFactory(void); ALCbackendFactory *ALCjackBackendFactory_getFactory(void); ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 5e0b03bd..435c0fae 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -33,6 +33,8 @@ #include #include +#include "backends/base.h" + typedef struct { AudioUnit audioUnit; @@ -51,17 +53,6 @@ typedef struct { static const ALCchar ca_device[] = "CoreAudio Default"; -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); - } -} - static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) { AudioBufferList *list; @@ -83,70 +74,85 @@ static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSiz return list; } -static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +static void destroy_buffer_list(AudioBufferList* list) { - ALCdevice *device = (ALCdevice*)inRefCon; - ca_data *data = (ca_data*)device->ExtraData; + if(list) + { + UInt32 i; + for(i = 0;i < list->mNumberBuffers;i++) + free(list->mBuffers[i].mData); + free(list); + } +} + + +typedef struct ALCcoreAudioPlayback { + DERIVE_FROM_TYPE(ALCbackend); + + AudioUnit audioUnit; + + ALuint frameSize; + AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD +} ALCcoreAudioPlayback; + +static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); +static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self); +static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name); +static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self); +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) + +DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback); + + +static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); + + self->frameSize = 0; + memset(&self->format, 0, sizeof(self->format)); +} + +static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) +{ + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +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; ALCdevice_Lock(device); aluMixData(device, ioData->mBuffers[0].mData, - ioData->mBuffers[0].mDataByteSize / data->frameSize); + ioData->mBuffers[0].mDataByteSize / self->frameSize); ALCdevice_Unlock(device); return noErr; } -static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, - AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData) -{ - ALCdevice *device = (ALCdevice*)inUserData; - ca_data *data = (ca_data*)device->ExtraData; - - // Read from the ring buffer and store temporarily in a large buffer - ll_ringbuffer_read(data->ring, data->resampleBuffer, *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; -} - -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; - } - - ll_ringbuffer_write(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames); - - return noErr; -} - -static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) + +static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; AudioComponentDescription desc; AudioComponent comp; - ca_data *data; 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 */ @@ -163,57 +169,47 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) return ALC_INVALID_VALUE; } - data = calloc(1, sizeof(*data)); - - err = AudioComponentInstanceNew(comp, &data->audioUnit); + err = AudioComponentInstanceNew(comp, &self->audioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); - free(data); 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"); - AudioComponentInstanceDispose(data->audioUnit); - free(data); + AudioComponentInstanceDispose(self->audioUnit); return ALC_INVALID_VALUE; } - alstr_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 void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self) { - ca_data *data = (ca_data*)device->ExtraData; - - AudioUnitUninitialize(data->audioUnit); - AudioComponentInstanceDispose(data->audioUnit); - - free(data); - device->ExtraData = NULL; + AudioUnitUninitialize(self->audioUnit); + AudioComponentInstanceDispose(self->audioUnit); } -static ALCboolean ca_reset_playback(ALCdevice *device) +static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) { - 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"); @@ -231,7 +227,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"); @@ -315,7 +311,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"); @@ -323,11 +319,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); + 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"); @@ -335,7 +331,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"); @@ -345,12 +341,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"); @@ -360,18 +353,107 @@ static ALCboolean ca_start_playback(ALCdevice *device) return ALC_TRUE; } -static void ca_stop_playback(ALCdevice *device) +static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) { - ca_data *data = (ca_data*)device->ExtraData; - OSStatus err; - - err = AudioOutputUnitStop(data->audioUnit); + OSStatus err = AudioOutputUnitStop(self->audioUnit); if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } -static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) + + + +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 void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self); +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 void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) { + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); + +} + +static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) +{ + 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)) +{ + ALCcoreAudioCapture *self = inRefCon; + AudioUnitRenderActionFlags flags = 0; + OSStatus err; + + // fill the bufferList with data from the input device + err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList); + if(err != noErr) + { + 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 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 @@ -383,12 +465,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) AudioObjectPropertyAddress propertyAddress; UInt32 enableIO; AudioComponent comp; - ca_data *data; 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; @@ -405,11 +486,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) return ALC_INVALID_VALUE; } - data = calloc(1, sizeof(*data)); - device->ExtraData = data; - // Open the component - err = AudioComponentInstanceNew(comp, &data->audioUnit); + err = AudioComponentInstanceNew(comp, &self->audioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -418,7 +496,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) // 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"); @@ -427,7 +505,7 @@ 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"); @@ -455,7 +533,7 @@ 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"); @@ -463,10 +541,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // 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"); @@ -474,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"); @@ -483,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"); @@ -545,8 +623,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); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later @@ -554,11 +632,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"); @@ -566,8 +644,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); @@ -575,7 +653,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); @@ -583,75 +661,71 @@ 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 = ll_ringbuffer_create( - device->UpdateSize*data->sampleRateRatio*device->NumUpdates + 1, - data->frameSize + self->ring = ll_ringbuffer_create( + device->UpdateSize*self->sampleRateRatio*device->NumUpdates + 1, + self->frameSize ); - if(!data->ring) goto error; + if(!self->ring) goto error; - alstr_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; error: - ll_ringbuffer_free(data->ring); - data->ring = NULL; - free(data->resampleBuffer); - destroy_buffer_list(data->bufferList); + ll_ringbuffer_free(self->ring); + self->ring = NULL; + free(self->resampleBuffer); + destroy_buffer_list(self->bufferList); - if(data->audioConverter) - AudioConverterDispose(data->audioConverter); - if(data->audioUnit) - AudioComponentInstanceDispose(data->audioUnit); - - free(data); - device->ExtraData = NULL; + if(self->audioConverter) + AudioConverterDispose(self->audioConverter); + if(self->audioUnit) + AudioComponentInstanceDispose(self->audioUnit); return ALC_INVALID_VALUE; } -static void ca_close_capture(ALCdevice *device) + +static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self) { - ca_data *data = (ca_data*)device->ExtraData; + ll_ringbuffer_free(self->ring); + self->ring = NULL; - ll_ringbuffer_free(data->ring); - data->ring = NULL; - free(data->resampleBuffer); - destroy_buffer_list(data->bufferList); + free(self->resampleBuffer); - AudioConverterDispose(data->audioConverter); - AudioComponentInstanceDispose(data->audioUnit); + destroy_buffer_list(self->bufferList); - free(data); - device->ExtraData = NULL; + AudioConverterDispose(self->audioConverter); + AudioComponentInstanceDispose(self->audioUnit); } -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; UInt32 frameCount; OSStatus err; @@ -665,14 +739,15 @@ static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint sa // 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].mNumberChannels = self->format.mChannelsPerFrame; + list->mBuffers[0].mDataByteSize = samples * self->frameSize; 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, list, NULL + ); if(err != noErr) { ERR("AudioConverterFillComplexBuffer error: %d\n", err); @@ -681,38 +756,47 @@ 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 ll_ringbuffer_read_space(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 -}; +typedef struct ALCcoreAudioBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCcoreAudioBackendFactory; +#define ALCCOREAUDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory) } } -ALCboolean alc_ca_init(BackendFuncs *func_list) +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); +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) { switch(type) { @@ -724,3 +808,23 @@ void alc_ca_probe(enum DevProbe type) 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; +} diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7add9310..1919a257 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -429,9 +429,6 @@ typedef struct { ALCuint (*AvailableSamples)(ALCdevice*); } BackendFuncs; -ALCboolean alc_ca_init(BackendFuncs *func_list); -void alc_ca_deinit(void); -void alc_ca_probe(enum DevProbe type); ALCboolean alc_qsa_init(BackendFuncs *func_list); void alc_qsa_deinit(void); void alc_qsa_probe(enum DevProbe type);