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