src/audio/macosx/SDL_coreaudio.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
permissions -rw-r--r--
more tweaking indent options
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include <AudioUnit/AudioUnit.h>
    25 
    26 #include "SDL_audio.h"
    27 #include "../SDL_audio_c.h"
    28 #include "../SDL_sysaudio.h"
    29 #include "SDL_coreaudio.h"
    30 
    31 
    32 /* Audio driver functions */
    33 
    34 static int Core_OpenAudio(_THIS, SDL_AudioSpec * spec);
    35 static void Core_WaitAudio(_THIS);
    36 static void Core_PlayAudio(_THIS);
    37 static Uint8 *Core_GetAudioBuf(_THIS);
    38 static void Core_CloseAudio(_THIS);
    39 
    40 /* Audio driver bootstrap functions */
    41 
    42 static int
    43 Audio_Available(void)
    44 {
    45     return (1);
    46 }
    47 
    48 static void
    49 Audio_DeleteDevice(SDL_AudioDevice * device)
    50 {
    51     SDL_free(device->hidden);
    52     SDL_free(device);
    53 }
    54 
    55 static SDL_AudioDevice *
    56 Audio_CreateDevice(int devindex)
    57 {
    58     SDL_AudioDevice *this;
    59 
    60     /* Initialize all variables that we clean on shutdown */
    61     this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
    62     if (this) {
    63         SDL_memset(this, 0, (sizeof *this));
    64         this->hidden = (struct SDL_PrivateAudioData *)
    65             SDL_malloc((sizeof *this->hidden));
    66     }
    67     if ((this == NULL) || (this->hidden == NULL)) {
    68         SDL_OutOfMemory();
    69         if (this) {
    70             SDL_free(this);
    71         }
    72         return (0);
    73     }
    74     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
    75 
    76     /* Set the function pointers */
    77     this->OpenAudio = Core_OpenAudio;
    78     this->WaitAudio = Core_WaitAudio;
    79     this->PlayAudio = Core_PlayAudio;
    80     this->GetAudioBuf = Core_GetAudioBuf;
    81     this->CloseAudio = Core_CloseAudio;
    82 
    83     this->free = Audio_DeleteDevice;
    84 
    85     return this;
    86 }
    87 
    88 AudioBootStrap COREAUDIO_bootstrap = {
    89     "coreaudio", "Mac OS X CoreAudio",
    90     Audio_Available, Audio_CreateDevice
    91 };
    92 
    93 /* The CoreAudio callback */
    94 static OSStatus
    95 audioCallback(void *inRefCon,
    96               AudioUnitRenderActionFlags inActionFlags,
    97               const AudioTimeStamp * inTimeStamp,
    98               UInt32 inBusNumber, AudioBuffer * ioData)
    99 {
   100     SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
   101     UInt32 remaining, len;
   102     void *ptr;
   103 
   104     /* Only do anything if audio is enabled and not paused */
   105     if (!this->enabled || this->paused) {
   106         SDL_memset(ioData->mData, this->spec.silence, ioData->mDataByteSize);
   107         return 0;
   108     }
   109 
   110     /* No SDL conversion should be needed here, ever, since we accept
   111        any input format in OpenAudio, and leave the conversion to CoreAudio.
   112      */
   113     /*
   114        assert(!this->convert.needed);
   115        assert(this->spec.channels == ioData->mNumberChannels);
   116      */
   117 
   118     remaining = ioData->mDataByteSize;
   119     ptr = ioData->mData;
   120     while (remaining > 0) {
   121         if (bufferOffset >= bufferSize) {
   122             /* Generate the data */
   123             SDL_memset(buffer, this->spec.silence, bufferSize);
   124             SDL_mutexP(this->mixer_lock);
   125             (*this->spec.callback) (this->spec.userdata, buffer, bufferSize);
   126             SDL_mutexV(this->mixer_lock);
   127             bufferOffset = 0;
   128         }
   129 
   130         len = bufferSize - bufferOffset;
   131         if (len > remaining)
   132             len = remaining;
   133         SDL_memcpy(ptr, (char *) buffer + bufferOffset, len);
   134         ptr = (char *) ptr + len;
   135         remaining -= len;
   136         bufferOffset += len;
   137     }
   138 
   139     return 0;
   140 }
   141 
   142 /* Dummy functions -- we don't use thread-based audio */
   143 void
   144 Core_WaitAudio(_THIS)
   145 {
   146     return;
   147 }
   148 
   149 void
   150 Core_PlayAudio(_THIS)
   151 {
   152     return;
   153 }
   154 
   155 Uint8 *
   156 Core_GetAudioBuf(_THIS)
   157 {
   158     return (NULL);
   159 }
   160 
   161 void
   162 Core_CloseAudio(_THIS)
   163 {
   164     OSStatus result;
   165     struct AudioUnitInputCallback callback;
   166 
   167     /* stop processing the audio unit */
   168     result = AudioOutputUnitStop(outputAudioUnit);
   169     if (result != noErr) {
   170         SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
   171         return;
   172     }
   173 
   174     /* Remove the input callback */
   175     callback.inputProc = 0;
   176     callback.inputProcRefCon = 0;
   177     result = AudioUnitSetProperty(outputAudioUnit,
   178                                   kAudioUnitProperty_SetInputCallback,
   179                                   kAudioUnitScope_Input,
   180                                   0, &callback, sizeof(callback));
   181     if (result != noErr) {
   182         SDL_SetError
   183             ("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
   184         return;
   185     }
   186 
   187     result = CloseComponent(outputAudioUnit);
   188     if (result != noErr) {
   189         SDL_SetError("Core_CloseAudio: CloseComponent");
   190         return;
   191     }
   192 
   193     SDL_free(buffer);
   194 }
   195 
   196 #define CHECK_RESULT(msg) \
   197     if (result != noErr) { \
   198         SDL_SetError("Failed to start CoreAudio: " msg); \
   199         return -1; \
   200     }
   201 
   202 
   203 int
   204 Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
   205 {
   206     OSStatus result = noErr;
   207     Component comp;
   208     ComponentDescription desc;
   209     struct AudioUnitInputCallback callback;
   210     AudioStreamBasicDescription requestedDesc;
   211 
   212     /* Setup a AudioStreamBasicDescription with the requested format */
   213     requestedDesc.mFormatID = kAudioFormatLinearPCM;
   214     requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
   215     requestedDesc.mChannelsPerFrame = spec->channels;
   216     requestedDesc.mSampleRate = spec->freq;
   217 
   218     requestedDesc.mBitsPerChannel = spec->format & 0xFF;
   219     if (spec->format & 0x8000)
   220         requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
   221     if (spec->format & 0x1000)
   222         requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
   223 
   224     requestedDesc.mFramesPerPacket = 1;
   225     requestedDesc.mBytesPerFrame =
   226         requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
   227     requestedDesc.mBytesPerPacket =
   228         requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
   229 
   230 
   231     /* Locate the default output audio unit */
   232     desc.componentType = kAudioUnitComponentType;
   233     desc.componentSubType = kAudioUnitSubType_Output;
   234     desc.componentManufacturer = kAudioUnitID_DefaultOutput;
   235     desc.componentFlags = 0;
   236     desc.componentFlagsMask = 0;
   237 
   238     comp = FindNextComponent(NULL, &desc);
   239     if (comp == NULL) {
   240         SDL_SetError
   241             ("Failed to start CoreAudio: FindNextComponent returned NULL");
   242         return -1;
   243     }
   244 
   245     /* Open & initialize the default output audio unit */
   246     result = OpenAComponent(comp, &outputAudioUnit);
   247     CHECK_RESULT("OpenAComponent")
   248         result = AudioUnitInitialize(outputAudioUnit);
   249     CHECK_RESULT("AudioUnitInitialize")
   250         /* Set the input format of the audio unit. */
   251         result = AudioUnitSetProperty(outputAudioUnit,
   252                                       kAudioUnitProperty_StreamFormat,
   253                                       kAudioUnitScope_Input,
   254                                       0,
   255                                       &requestedDesc, sizeof(requestedDesc));
   256     CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
   257         /* Set the audio callback */
   258         callback.inputProc = audioCallback;
   259     callback.inputProcRefCon = this;
   260     result = AudioUnitSetProperty(outputAudioUnit,
   261                                   kAudioUnitProperty_SetInputCallback,
   262                                   kAudioUnitScope_Input,
   263                                   0, &callback, sizeof(callback));
   264     CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
   265         /* Calculate the final parameters for this audio specification */
   266         SDL_CalculateAudioSpec(spec);
   267 
   268     /* Allocate a sample buffer */
   269     bufferOffset = bufferSize = this->spec.size;
   270     buffer = SDL_malloc(bufferSize);
   271 
   272     /* Finally, start processing of the audio unit */
   273     result = AudioOutputUnitStart(outputAudioUnit);
   274     CHECK_RESULT("AudioOutputUnitStart")
   275         /* We're running! */
   276         return (1);
   277 }
   278 
   279 /* vi: set ts=4 sw=4 expandtab: */