Mercurial > sdl-ios-xcode
diff src/audio/macosx/SDL_coreaudio.c @ 935:f8d5ddc7aef1
Audio improvements from Max Horn, including a new CoreAudio driver for MacOSX
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 21 Aug 2004 02:06:30 +0000 |
parents | |
children | 84f930aebaeb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audio/macosx/SDL_coreaudio.c Sat Aug 21 02:06:30 2004 +0000 @@ -0,0 +1,287 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2004 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +#include <AudioUnit/AudioUnit.h> + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "SDL_endian.h" +#include "SDL_audio.h" +#include "SDL_audio_c.h" +#include "SDL_audiomem.h" +#include "SDL_sysaudio.h" +#include "SDL_coreaudio.h" + + +/* Audio driver functions */ + +static int Core_OpenAudio(_THIS, SDL_AudioSpec *spec); +static void Core_WaitAudio(_THIS); +static void Core_PlayAudio(_THIS); +static Uint8 *Core_GetAudioBuf(_THIS); +static void Core_CloseAudio(_THIS); + +/* Audio driver bootstrap functions */ + +static int Audio_Available(void) +{ + return(1); +} + +static void Audio_DeleteDevice(SDL_AudioDevice *device) +{ + free(device->hidden); + free(device); +} + +static SDL_AudioDevice *Audio_CreateDevice(int devindex) +{ + SDL_AudioDevice *this; + + /* Initialize all variables that we clean on shutdown */ + this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); + if ( this ) { + memset(this, 0, (sizeof *this)); + this->hidden = (struct SDL_PrivateAudioData *) + malloc((sizeof *this->hidden)); + } + if ( (this == NULL) || (this->hidden == NULL) ) { + SDL_OutOfMemory(); + if ( this ) { + free(this); + } + return(0); + } + memset(this->hidden, 0, (sizeof *this->hidden)); + + /* Set the function pointers */ + this->OpenAudio = Core_OpenAudio; + this->WaitAudio = Core_WaitAudio; + this->PlayAudio = Core_PlayAudio; + this->GetAudioBuf = Core_GetAudioBuf; + this->CloseAudio = Core_CloseAudio; + + this->free = Audio_DeleteDevice; + + return this; +} + +AudioBootStrap COREAUDIO_bootstrap = { + "coreaudio", "Mac OS X CoreAudio", + Audio_Available, Audio_CreateDevice +}; + +/* The CoreAudio callback */ +static OSStatus audioCallback (void *inRefCon, + AudioUnitRenderActionFlags inActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + AudioBuffer *ioData) +{ + SDL_AudioDevice *this = (SDL_AudioDevice *)inRefCon; + UInt32 remaining, len; + void *ptr; + + /* Only do anything if audio is enabled and not paused */ + if ( ! this->enabled || this->paused ) { + memset(ioData->mData, this->spec.silence, ioData->mDataByteSize); + return 0; + } + + /* No SDL conversion should be needed here, ever, since we accept + any input format in OpenAudio, and leave the conversion to CoreAudio. + */ + assert(!this->convert.needed); + assert(this->spec.channels == ioData->mNumberChannels); + + remaining = ioData->mDataByteSize; + ptr = ioData->mData; + while (remaining > 0) { + if (bufferOffset >= bufferSize) { + /* Generate the data */ + memset(buffer, this->spec.silence, bufferSize); + SDL_mutexP(this->mixer_lock); + (*this->spec.callback)(this->spec.userdata, + buffer, bufferSize); + SDL_mutexV(this->mixer_lock); + bufferOffset = 0; + } + + len = bufferSize - bufferOffset; + if (len > remaining) + len = remaining; + memcpy(ptr, buffer + bufferOffset, len); + ptr += len; + remaining -= len; + bufferOffset += len; + } + + return 0; +} + +/* Dummy functions -- we don't use thread-based audio */ +void Core_WaitAudio(_THIS) +{ + return; +} + +void Core_PlayAudio(_THIS) +{ + return; +} + +Uint8 *Core_GetAudioBuf(_THIS) +{ + return(NULL); +} + +void Core_CloseAudio(_THIS) +{ + OSStatus result; + AudioUnitInputCallback callback; + + /* stop processing the audio unit */ + result = AudioOutputUnitStop (outputAudioUnit); + if (result != noErr) { + SDL_SetError("Core_CloseAudio: AudioOutputUnitStop"); + return; + } + + /* Remove the input callback */ + callback.inputProc = 0; + callback.inputProcRefCon = 0; + result = AudioUnitSetProperty (outputAudioUnit, + kAudioUnitProperty_SetInputCallback, + kAudioUnitScope_Input, + 0, + &callback, + sizeof(callback)); + if (result != noErr) { + SDL_SetError("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)"); + return; + } + + result = CloseComponent(outputAudioUnit); + if (result != noErr) { + SDL_SetError("Core_CloseAudio: CloseComponent"); + return; + } + + free(buffer); +} + +#define CHECK_RESULT(msg) \ + if (result != noErr) { \ + SDL_SetError("Failed to start CoreAudio: " msg); \ + return -1; \ + } + + +int Core_OpenAudio(_THIS, SDL_AudioSpec *spec) +{ + OSStatus result = noErr; + Component comp; + ComponentDescription desc; + AudioUnitInputCallback callback; + AudioStreamBasicDescription requestedDesc; + + /* Setup a AudioStreamBasicDescription with the requested format */ + requestedDesc.mFormatID = kAudioFormatLinearPCM; + requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked; + requestedDesc.mChannelsPerFrame = spec->channels; + requestedDesc.mSampleRate = spec->freq; + + requestedDesc.mBitsPerChannel = spec->format & 0xFF; + if (spec->format & 0x8000) + requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + if (spec->format & 0x1000) + requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; + + requestedDesc.mFramesPerPacket = 1; + requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8; + requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket; + + + /* Locate the default output audio unit */ + desc.componentType = kAudioUnitComponentType; + desc.componentSubType = kAudioUnitSubType_Output; + desc.componentManufacturer = kAudioUnitID_DefaultOutput; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + comp = FindNextComponent (NULL, &desc); + if (comp == NULL) { + SDL_SetError ("Failed to start CoreAudio: FindNextComponent returned NULL"); + return -1; + } + + /* Open & initialize the default output audio unit */ + result = OpenAComponent (comp, &outputAudioUnit); + CHECK_RESULT("OpenAComponent") + + result = AudioUnitInitialize (outputAudioUnit); + CHECK_RESULT("AudioUnitInitialize") + + /* Set the input format of the audio unit. */ + result = AudioUnitSetProperty (outputAudioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &requestedDesc, + sizeof (requestedDesc)); + CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)") + + /* Set the audio callback */ + callback.inputProc = audioCallback; + callback.inputProcRefCon = this; + result = AudioUnitSetProperty (outputAudioUnit, + kAudioUnitProperty_SetInputCallback, + kAudioUnitScope_Input, + 0, + &callback, + sizeof(callback)); + CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)") + + /* Calculate the final parameters for this audio specification */ + SDL_CalculateAudioSpec(spec); + + /* Allocate a sample buffer */ + bufferOffset = bufferSize = this->spec.size; + buffer = malloc(bufferSize); + assert(buffer); + + /* Finally, start processing of the audio unit */ + result = AudioOutputUnitStart (outputAudioUnit); + CHECK_RESULT("AudioOutputUnitStart") + + + /* We're running! */ + return(1); +}