src/audio/macosx/SDL_coreaudio.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 09 Mar 2006 06:33:21 +0000
changeset 1487 dc6b59e925a2
parent 1402 d910939febfa
child 1662 782fd950bd46
child 1895 c121d94672cb
child 4103 9df8136abec0
permissions -rw-r--r--
Cleaning up warnings on MacOS X
     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 Audio_Available(void)
    43 {
    44     return(1);
    45 }
    46 
    47 static void Audio_DeleteDevice(SDL_AudioDevice *device)
    48 {
    49     SDL_free(device->hidden);
    50     SDL_free(device);
    51 }
    52 
    53 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
    54 {
    55     SDL_AudioDevice *this;
    56 
    57     /* Initialize all variables that we clean on shutdown */
    58     this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
    59     if ( this ) {
    60         SDL_memset(this, 0, (sizeof *this));
    61         this->hidden = (struct SDL_PrivateAudioData *)
    62                 SDL_malloc((sizeof *this->hidden));
    63     }
    64     if ( (this == NULL) || (this->hidden == NULL) ) {
    65         SDL_OutOfMemory();
    66         if ( this ) {
    67             SDL_free(this);
    68         }
    69         return(0);
    70     }
    71     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
    72 
    73     /* Set the function pointers */
    74     this->OpenAudio = Core_OpenAudio;
    75     this->WaitAudio = Core_WaitAudio;
    76     this->PlayAudio = Core_PlayAudio;
    77     this->GetAudioBuf = Core_GetAudioBuf;
    78     this->CloseAudio = Core_CloseAudio;
    79 
    80     this->free = Audio_DeleteDevice;
    81 
    82     return this;
    83 }
    84 
    85 AudioBootStrap COREAUDIO_bootstrap = {
    86     "coreaudio", "Mac OS X CoreAudio",
    87     Audio_Available, Audio_CreateDevice
    88 };
    89 
    90 /* The CoreAudio callback */
    91 static OSStatus     audioCallback (void                             *inRefCon, 
    92                                     AudioUnitRenderActionFlags      inActionFlags,
    93                                     const AudioTimeStamp            *inTimeStamp, 
    94                                     UInt32                          inBusNumber, 
    95                                     AudioBuffer                     *ioData)
    96 {
    97     SDL_AudioDevice *this = (SDL_AudioDevice *)inRefCon;
    98     UInt32 remaining, len;
    99     void *ptr;
   100 
   101     /* Only do anything if audio is enabled and not paused */
   102     if ( ! this->enabled || this->paused ) {
   103         SDL_memset(ioData->mData, this->spec.silence, ioData->mDataByteSize);
   104         return 0;
   105     }
   106     
   107     /* No SDL conversion should be needed here, ever, since we accept
   108        any input format in OpenAudio, and leave the conversion to CoreAudio.
   109      */
   110     /*
   111     assert(!this->convert.needed);
   112     assert(this->spec.channels == ioData->mNumberChannels);
   113      */
   114     
   115     remaining = ioData->mDataByteSize;
   116     ptr = ioData->mData;
   117     while (remaining > 0) {
   118         if (bufferOffset >= bufferSize) {
   119             /* Generate the data */
   120             SDL_memset(buffer, this->spec.silence, bufferSize);
   121             SDL_mutexP(this->mixer_lock);
   122             (*this->spec.callback)(this->spec.userdata,
   123                         buffer, bufferSize);
   124             SDL_mutexV(this->mixer_lock);
   125             bufferOffset = 0;
   126         }
   127         
   128         len = bufferSize - bufferOffset;
   129         if (len > remaining)
   130             len = remaining;
   131         SDL_memcpy(ptr, (char *)buffer + bufferOffset, len);
   132         ptr = (char *)ptr + len;
   133         remaining -= len;
   134         bufferOffset += len;
   135     }
   136     
   137     return 0;
   138 }
   139 
   140 /* Dummy functions -- we don't use thread-based audio */
   141 void Core_WaitAudio(_THIS)
   142 {
   143     return;
   144 }
   145 
   146 void Core_PlayAudio(_THIS)
   147 {
   148     return;
   149 }
   150 
   151 Uint8 *Core_GetAudioBuf(_THIS)
   152 {
   153     return(NULL);
   154 }
   155 
   156 void Core_CloseAudio(_THIS)
   157 {
   158     OSStatus result;
   159     struct AudioUnitInputCallback callback;
   160 
   161     /* stop processing the audio unit */
   162     result = AudioOutputUnitStop (outputAudioUnit);
   163     if (result != noErr) {
   164         SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
   165         return;
   166     }
   167 
   168     /* Remove the input callback */
   169     callback.inputProc = 0;
   170     callback.inputProcRefCon = 0;
   171     result = AudioUnitSetProperty (outputAudioUnit, 
   172                         kAudioUnitProperty_SetInputCallback, 
   173                         kAudioUnitScope_Input, 
   174                         0,
   175                         &callback, 
   176                         sizeof(callback));
   177     if (result != noErr) {
   178         SDL_SetError("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
   179         return;
   180     }
   181 
   182     result = CloseComponent(outputAudioUnit);
   183     if (result != noErr) {
   184         SDL_SetError("Core_CloseAudio: CloseComponent");
   185         return;
   186     }
   187     
   188     SDL_free(buffer);
   189 }
   190 
   191 #define CHECK_RESULT(msg) \
   192     if (result != noErr) { \
   193         SDL_SetError("Failed to start CoreAudio: " msg); \
   194         return -1; \
   195     }
   196 
   197 
   198 int Core_OpenAudio(_THIS, SDL_AudioSpec *spec)
   199 {
   200     OSStatus result = noErr;
   201     Component comp;
   202     ComponentDescription desc;
   203     struct AudioUnitInputCallback callback;
   204     AudioStreamBasicDescription requestedDesc;
   205 
   206     /* Setup a AudioStreamBasicDescription with the requested format */
   207     requestedDesc.mFormatID = kAudioFormatLinearPCM;
   208     requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
   209     requestedDesc.mChannelsPerFrame = spec->channels;
   210     requestedDesc.mSampleRate = spec->freq;
   211     
   212     requestedDesc.mBitsPerChannel = spec->format & 0xFF;
   213     if (spec->format & 0x8000)
   214         requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
   215     if (spec->format & 0x1000)
   216         requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
   217 
   218     requestedDesc.mFramesPerPacket = 1;
   219     requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
   220     requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
   221 
   222 
   223     /* Locate the default output audio unit */
   224     desc.componentType = kAudioUnitComponentType;
   225     desc.componentSubType = kAudioUnitSubType_Output;
   226     desc.componentManufacturer = kAudioUnitID_DefaultOutput;
   227     desc.componentFlags = 0;
   228     desc.componentFlagsMask = 0;
   229     
   230     comp = FindNextComponent (NULL, &desc);
   231     if (comp == NULL) {
   232         SDL_SetError ("Failed to start CoreAudio: FindNextComponent returned NULL");
   233         return -1;
   234     }
   235     
   236     /* Open & initialize the default output audio unit */
   237     result = OpenAComponent (comp, &outputAudioUnit);
   238     CHECK_RESULT("OpenAComponent")
   239 
   240     result = AudioUnitInitialize (outputAudioUnit);
   241     CHECK_RESULT("AudioUnitInitialize")
   242                 
   243     /* Set the input format of the audio unit. */
   244     result = AudioUnitSetProperty (outputAudioUnit,
   245                                kAudioUnitProperty_StreamFormat,
   246                                kAudioUnitScope_Input,
   247                                0,
   248                                &requestedDesc,
   249                                sizeof (requestedDesc));
   250     CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
   251 
   252     /* Set the audio callback */
   253     callback.inputProc = audioCallback;
   254     callback.inputProcRefCon = this;
   255     result = AudioUnitSetProperty (outputAudioUnit, 
   256                         kAudioUnitProperty_SetInputCallback, 
   257                         kAudioUnitScope_Input, 
   258                         0,
   259                         &callback, 
   260                         sizeof(callback));
   261     CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
   262 
   263     /* Calculate the final parameters for this audio specification */
   264     SDL_CalculateAudioSpec(spec);
   265     
   266     /* Allocate a sample buffer */
   267     bufferOffset = bufferSize = this->spec.size;
   268     buffer = SDL_malloc(bufferSize);
   269 
   270     /* Finally, start processing of the audio unit */
   271     result = AudioOutputUnitStart (outputAudioUnit);
   272     CHECK_RESULT("AudioOutputUnitStart")    
   273     
   274 
   275     /* We're running! */
   276     return(1);
   277 }