src/audio/SDL_audio.c
author Ryan C. Gordon
Thu, 20 Mar 2014 17:00:33 -0400
changeset 8658 7939f33e81ac
parent 8149 681eb46b8ac4
child 8660 6bd1f8bad873
permissions -rw-r--r--
#ifdef'd out the audio streamer code.

It's been hardcoded out forever now, but I've now forcibly removed it with
the preprocessor so static analysis doesn't complain about it for now.

Eventually I want to rewrite or remove this code.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../SDL_internal.h"
    22 
    23 /* Allow access to a raw mixing buffer */
    24 
    25 #include "SDL.h"
    26 #include "SDL_audio.h"
    27 #include "SDL_audio_c.h"
    28 #include "SDL_audiomem.h"
    29 #include "SDL_sysaudio.h"
    30 
    31 #define _THIS SDL_AudioDevice *_this
    32 
    33 static SDL_AudioDriver current_audio;
    34 static SDL_AudioDevice *open_devices[16];
    35 
    36 /* !!! FIXME: These are wordy and unlocalized... */
    37 #define DEFAULT_OUTPUT_DEVNAME "System audio output device"
    38 #define DEFAULT_INPUT_DEVNAME "System audio capture device"
    39 
    40 
    41 /*
    42  * Not all of these will be compiled and linked in, but it's convenient
    43  *  to have a complete list here and saves yet-another block of #ifdefs...
    44  *  Please see bootstrap[], below, for the actual #ifdef mess.
    45  */
    46 extern AudioBootStrap BSD_AUDIO_bootstrap;
    47 extern AudioBootStrap DSP_bootstrap;
    48 extern AudioBootStrap ALSA_bootstrap;
    49 extern AudioBootStrap PULSEAUDIO_bootstrap;
    50 extern AudioBootStrap QSAAUDIO_bootstrap;
    51 extern AudioBootStrap SUNAUDIO_bootstrap;
    52 extern AudioBootStrap ARTS_bootstrap;
    53 extern AudioBootStrap ESD_bootstrap;
    54 extern AudioBootStrap NAS_bootstrap;
    55 extern AudioBootStrap XAUDIO2_bootstrap;
    56 extern AudioBootStrap DSOUND_bootstrap;
    57 extern AudioBootStrap WINMM_bootstrap;
    58 extern AudioBootStrap PAUDIO_bootstrap;
    59 extern AudioBootStrap HAIKUAUDIO_bootstrap;
    60 extern AudioBootStrap COREAUDIO_bootstrap;
    61 extern AudioBootStrap SNDMGR_bootstrap;
    62 extern AudioBootStrap DISKAUD_bootstrap;
    63 extern AudioBootStrap DUMMYAUD_bootstrap;
    64 extern AudioBootStrap DCAUD_bootstrap;
    65 extern AudioBootStrap DART_bootstrap;
    66 extern AudioBootStrap NDSAUD_bootstrap;
    67 extern AudioBootStrap FUSIONSOUND_bootstrap;
    68 extern AudioBootStrap ANDROIDAUD_bootstrap;
    69 extern AudioBootStrap PSPAUD_bootstrap;
    70 extern AudioBootStrap SNDIO_bootstrap;
    71 
    72 /* Available audio drivers */
    73 static const AudioBootStrap *const bootstrap[] = {
    74 #if SDL_AUDIO_DRIVER_PULSEAUDIO
    75     &PULSEAUDIO_bootstrap,
    76 #endif
    77 #if SDL_AUDIO_DRIVER_ALSA
    78     &ALSA_bootstrap,
    79 #endif
    80 #if SDL_AUDIO_DRIVER_SNDIO
    81     &SNDIO_bootstrap,
    82 #endif
    83 #if SDL_AUDIO_DRIVER_BSD
    84     &BSD_AUDIO_bootstrap,
    85 #endif
    86 #if SDL_AUDIO_DRIVER_OSS
    87     &DSP_bootstrap,
    88 #endif
    89 #if SDL_AUDIO_DRIVER_QSA
    90     &QSAAUDIO_bootstrap,
    91 #endif
    92 #if SDL_AUDIO_DRIVER_SUNAUDIO
    93     &SUNAUDIO_bootstrap,
    94 #endif
    95 #if SDL_AUDIO_DRIVER_ARTS
    96     &ARTS_bootstrap,
    97 #endif
    98 #if SDL_AUDIO_DRIVER_ESD
    99     &ESD_bootstrap,
   100 #endif
   101 #if SDL_AUDIO_DRIVER_NAS
   102     &NAS_bootstrap,
   103 #endif
   104 #if SDL_AUDIO_DRIVER_XAUDIO2
   105     &XAUDIO2_bootstrap,
   106 #endif
   107 #if SDL_AUDIO_DRIVER_DSOUND
   108     &DSOUND_bootstrap,
   109 #endif
   110 #if SDL_AUDIO_DRIVER_WINMM
   111     &WINMM_bootstrap,
   112 #endif
   113 #if SDL_AUDIO_DRIVER_PAUDIO
   114     &PAUDIO_bootstrap,
   115 #endif
   116 #if SDL_AUDIO_DRIVER_HAIKU
   117     &HAIKUAUDIO_bootstrap,
   118 #endif
   119 #if SDL_AUDIO_DRIVER_COREAUDIO
   120     &COREAUDIO_bootstrap,
   121 #endif
   122 #if SDL_AUDIO_DRIVER_DISK
   123     &DISKAUD_bootstrap,
   124 #endif
   125 #if SDL_AUDIO_DRIVER_DUMMY
   126     &DUMMYAUD_bootstrap,
   127 #endif
   128 #if SDL_AUDIO_DRIVER_FUSIONSOUND
   129     &FUSIONSOUND_bootstrap,
   130 #endif
   131 #if SDL_AUDIO_DRIVER_ANDROID
   132     &ANDROIDAUD_bootstrap,
   133 #endif
   134 #if SDL_AUDIO_DRIVER_PSP
   135     &PSPAUD_bootstrap,
   136 #endif
   137     NULL
   138 };
   139 
   140 static SDL_AudioDevice *
   141 get_audio_device(SDL_AudioDeviceID id)
   142 {
   143     id--;
   144     if ((id >= SDL_arraysize(open_devices)) || (open_devices[id] == NULL)) {
   145         SDL_SetError("Invalid audio device ID");
   146         return NULL;
   147     }
   148 
   149     return open_devices[id];
   150 }
   151 
   152 
   153 /* stubs for audio drivers that don't need a specific entry point... */
   154 static void
   155 SDL_AudioDetectDevices_Default(int iscapture, SDL_AddAudioDevice addfn)
   156 {                               /* no-op. */
   157 }
   158 
   159 static void
   160 SDL_AudioThreadInit_Default(_THIS)
   161 {                               /* no-op. */
   162 }
   163 
   164 static void
   165 SDL_AudioWaitDevice_Default(_THIS)
   166 {                               /* no-op. */
   167 }
   168 
   169 static void
   170 SDL_AudioPlayDevice_Default(_THIS)
   171 {                               /* no-op. */
   172 }
   173 
   174 static Uint8 *
   175 SDL_AudioGetDeviceBuf_Default(_THIS)
   176 {
   177     return NULL;
   178 }
   179 
   180 static void
   181 SDL_AudioWaitDone_Default(_THIS)
   182 {                               /* no-op. */
   183 }
   184 
   185 static void
   186 SDL_AudioCloseDevice_Default(_THIS)
   187 {                               /* no-op. */
   188 }
   189 
   190 static void
   191 SDL_AudioDeinitialize_Default(void)
   192 {                               /* no-op. */
   193 }
   194 
   195 static int
   196 SDL_AudioOpenDevice_Default(_THIS, const char *devname, int iscapture)
   197 {
   198     return -1;
   199 }
   200 
   201 static void
   202 SDL_AudioLockDevice_Default(SDL_AudioDevice * device)
   203 {
   204     if (device->thread && (SDL_ThreadID() == device->threadid)) {
   205         return;
   206     }
   207     SDL_LockMutex(device->mixer_lock);
   208 }
   209 
   210 static void
   211 SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device)
   212 {
   213     if (device->thread && (SDL_ThreadID() == device->threadid)) {
   214         return;
   215     }
   216     SDL_UnlockMutex(device->mixer_lock);
   217 }
   218 
   219 
   220 static void
   221 finalize_audio_entry_points(void)
   222 {
   223     /*
   224      * Fill in stub functions for unused driver entry points. This lets us
   225      *  blindly call them without having to check for validity first.
   226      */
   227 
   228 #define FILL_STUB(x) \
   229         if (current_audio.impl.x == NULL) { \
   230             current_audio.impl.x = SDL_Audio##x##_Default; \
   231         }
   232     FILL_STUB(DetectDevices);
   233     FILL_STUB(OpenDevice);
   234     FILL_STUB(ThreadInit);
   235     FILL_STUB(WaitDevice);
   236     FILL_STUB(PlayDevice);
   237     FILL_STUB(GetDeviceBuf);
   238     FILL_STUB(WaitDone);
   239     FILL_STUB(CloseDevice);
   240     FILL_STUB(LockDevice);
   241     FILL_STUB(UnlockDevice);
   242     FILL_STUB(Deinitialize);
   243 #undef FILL_STUB
   244 }
   245 
   246 /* Streaming functions (for when the input and output buffer sizes are different) */
   247 /* Write [length] bytes from buf into the streamer */
   248 static void
   249 SDL_StreamWrite(SDL_AudioStreamer * stream, Uint8 * buf, int length)
   250 {
   251     int i;
   252 
   253     for (i = 0; i < length; ++i) {
   254         stream->buffer[stream->write_pos] = buf[i];
   255         ++stream->write_pos;
   256     }
   257 }
   258 
   259 /* Read [length] bytes out of the streamer into buf */
   260 static void
   261 SDL_StreamRead(SDL_AudioStreamer * stream, Uint8 * buf, int length)
   262 {
   263     int i;
   264 
   265     for (i = 0; i < length; ++i) {
   266         buf[i] = stream->buffer[stream->read_pos];
   267         ++stream->read_pos;
   268     }
   269 }
   270 
   271 static int
   272 SDL_StreamLength(SDL_AudioStreamer * stream)
   273 {
   274     return (stream->write_pos - stream->read_pos) % stream->max_len;
   275 }
   276 
   277 /* Initialize the stream by allocating the buffer and setting the read/write heads to the beginning */
   278 #if 0
   279 static int
   280 SDL_StreamInit(SDL_AudioStreamer * stream, int max_len, Uint8 silence)
   281 {
   282     /* First try to allocate the buffer */
   283     stream->buffer = (Uint8 *) SDL_malloc(max_len);
   284     if (stream->buffer == NULL) {
   285         return -1;
   286     }
   287 
   288     stream->max_len = max_len;
   289     stream->read_pos = 0;
   290     stream->write_pos = 0;
   291 
   292     /* Zero out the buffer */
   293     SDL_memset(stream->buffer, silence, max_len);
   294 
   295     return 0;
   296 }
   297 #endif
   298 
   299 /* Deinitialize the stream simply by freeing the buffer */
   300 static void
   301 SDL_StreamDeinit(SDL_AudioStreamer * stream)
   302 {
   303     SDL_free(stream->buffer);
   304 }
   305 
   306 #if defined(ANDROID)
   307 #include <android/log.h>
   308 #endif
   309 
   310 /* The general mixing thread function */
   311 int SDLCALL
   312 SDL_RunAudio(void *devicep)
   313 {
   314     SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
   315     Uint8 *stream;
   316     int stream_len;
   317     void *udata;
   318     void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
   319     Uint32 delay;
   320     /* For streaming when the buffer sizes don't match up */
   321     Uint8 *istream;
   322     int istream_len = 0;
   323 
   324     /* The audio mixing is always a high priority thread */
   325     SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
   326 
   327     /* Perform any thread setup */
   328     device->threadid = SDL_ThreadID();
   329     current_audio.impl.ThreadInit(device);
   330 
   331     /* Set up the mixing function */
   332     fill = device->spec.callback;
   333     udata = device->spec.userdata;
   334 
   335     /* By default do not stream */
   336     device->use_streamer = 0;
   337 
   338     if (device->convert.needed) {
   339 #if 0                           /* !!! FIXME: I took len_div out of the structure. Use rate_incr instead? */
   340         /* If the result of the conversion alters the length, i.e. resampling is being used, use the streamer */
   341         if (device->convert.len_mult != 1 || device->convert.len_div != 1) {
   342             /* The streamer's maximum length should be twice whichever is larger: spec.size or len_cvt */
   343             stream_max_len = 2 * device->spec.size;
   344             if (device->convert.len_mult > device->convert.len_div) {
   345                 stream_max_len *= device->convert.len_mult;
   346                 stream_max_len /= device->convert.len_div;
   347             }
   348             if (SDL_StreamInit(&device->streamer, stream_max_len, silence) <
   349                 0)
   350                 return -1;
   351             device->use_streamer = 1;
   352 
   353             /* istream_len should be the length of what we grab from the callback and feed to conversion,
   354                so that we get close to spec_size. I.e. we want device.spec_size = istream_len * u / d
   355              */
   356             istream_len =
   357                 device->spec.size * device->convert.len_div /
   358                 device->convert.len_mult;
   359         }
   360 #endif
   361         stream_len = device->convert.len;
   362     } else {
   363         stream_len = device->spec.size;
   364     }
   365 
   366     /* Calculate the delay while paused */
   367     delay = ((device->spec.samples * 1000) / device->spec.freq);
   368 
   369     /* Determine if the streamer is necessary here */
   370 #if 0  /* !!! FIXME: rewrite/remove this streamer code. */
   371     if (device->use_streamer == 1) {
   372         /* This code is almost the same as the old code. The difference is, instead of reading
   373            directly from the callback into "stream", then converting and sending the audio off,
   374            we go: callback -> "istream" -> (conversion) -> streamer -> stream -> device.
   375            However, reading and writing with streamer are done separately:
   376            - We only call the callback and write to the streamer when the streamer does not
   377            contain enough samples to output to the device.
   378            - We only read from the streamer and tell the device to play when the streamer
   379            does have enough samples to output.
   380            This allows us to perform resampling in the conversion step, where the output of the
   381            resampling process can be any number. We will have to see what a good size for the
   382            stream's maximum length is, but I suspect 2*max(len_cvt, stream_len) is a good figure.
   383          */
   384         while (device->enabled) {
   385 
   386             if (device->paused) {
   387                 SDL_Delay(delay);
   388                 continue;
   389             }
   390 
   391             /* Only read in audio if the streamer doesn't have enough already (if it does not have enough samples to output) */
   392             if (SDL_StreamLength(&device->streamer) < stream_len) {
   393                 /* Set up istream */
   394                 if (device->convert.needed) {
   395                     if (device->convert.buf) {
   396                         istream = device->convert.buf;
   397                     } else {
   398                         continue;
   399                     }
   400                 } else {
   401 /* FIXME: Ryan, this is probably wrong.  I imagine we don't want to get
   402  * a device buffer both here and below in the stream output.
   403  */
   404                     istream = current_audio.impl.GetDeviceBuf(device);
   405                     if (istream == NULL) {
   406                         istream = device->fake_stream;
   407                     }
   408                 }
   409 
   410                 /* Read from the callback into the _input_ stream */
   411                 SDL_LockMutex(device->mixer_lock);
   412                 (*fill) (udata, istream, istream_len);
   413                 SDL_UnlockMutex(device->mixer_lock);
   414 
   415                 /* Convert the audio if necessary and write to the streamer */
   416                 if (device->convert.needed) {
   417                     SDL_ConvertAudio(&device->convert);
   418                     if (istream == NULL) {
   419                         istream = device->fake_stream;
   420                     }
   421                     /* SDL_memcpy(istream, device->convert.buf, device->convert.len_cvt); */
   422                     SDL_StreamWrite(&device->streamer, device->convert.buf,
   423                                     device->convert.len_cvt);
   424                 } else {
   425                     SDL_StreamWrite(&device->streamer, istream, istream_len);
   426                 }
   427             }
   428 
   429             /* Only output audio if the streamer has enough to output */
   430             if (SDL_StreamLength(&device->streamer) >= stream_len) {
   431                 /* Set up the output stream */
   432                 if (device->convert.needed) {
   433                     if (device->convert.buf) {
   434                         stream = device->convert.buf;
   435                     } else {
   436                         continue;
   437                     }
   438                 } else {
   439                     stream = current_audio.impl.GetDeviceBuf(device);
   440                     if (stream == NULL) {
   441                         stream = device->fake_stream;
   442                     }
   443                 }
   444 
   445                 /* Now read from the streamer */
   446                 SDL_StreamRead(&device->streamer, stream, stream_len);
   447 
   448                 /* Ready current buffer for play and change current buffer */
   449                 if (stream != device->fake_stream) {
   450                     current_audio.impl.PlayDevice(device);
   451                     /* Wait for an audio buffer to become available */
   452                     current_audio.impl.WaitDevice(device);
   453                 } else {
   454                     SDL_Delay(delay);
   455                 }
   456             }
   457 
   458         }
   459     } else {
   460 #endif
   461         /* Otherwise, do not use the streamer. This is the old code. */
   462         const int silence = (int) device->spec.silence;
   463 
   464         /* Loop, filling the audio buffers */
   465         while (device->enabled) {
   466 
   467             /* Fill the current buffer with sound */
   468             if (device->convert.needed) {
   469                 if (device->convert.buf) {
   470                     stream = device->convert.buf;
   471                 } else {
   472                     continue;
   473                 }
   474             } else {
   475                 stream = current_audio.impl.GetDeviceBuf(device);
   476                 if (stream == NULL) {
   477                     stream = device->fake_stream;
   478                 }
   479             }
   480 
   481             SDL_LockMutex(device->mixer_lock);
   482             if (device->paused) {
   483                 SDL_memset(stream, silence, stream_len);
   484             } else {
   485                 (*fill) (udata, stream, stream_len);
   486             }
   487             SDL_UnlockMutex(device->mixer_lock);
   488 
   489             /* Convert the audio if necessary */
   490             if (device->convert.needed) {
   491                 SDL_ConvertAudio(&device->convert);
   492                 stream = current_audio.impl.GetDeviceBuf(device);
   493                 if (stream == NULL) {
   494                     stream = device->fake_stream;
   495                 }
   496                 SDL_memcpy(stream, device->convert.buf,
   497                            device->convert.len_cvt);
   498             }
   499 
   500             /* Ready current buffer for play and change current buffer */
   501             if (stream != device->fake_stream) {
   502                 current_audio.impl.PlayDevice(device);
   503                 /* Wait for an audio buffer to become available */
   504                 current_audio.impl.WaitDevice(device);
   505             } else {
   506                 SDL_Delay(delay);
   507             }
   508         }
   509 #if 0  /* !!! FIXME: rewrite/remove this streamer code. */
   510     }
   511 #endif
   512 
   513     /* Wait for the audio to drain.. */
   514     current_audio.impl.WaitDone(device);
   515 
   516     /* If necessary, deinit the streamer */
   517 #if 0  /* !!! FIXME: rewrite/remove this streamer code. */
   518     if (device->use_streamer == 1)
   519         SDL_StreamDeinit(&device->streamer);
   520 #endif
   521 
   522     return (0);
   523 }
   524 
   525 
   526 static SDL_AudioFormat
   527 SDL_ParseAudioFormat(const char *string)
   528 {
   529 #define CHECK_FMT_STRING(x) if (SDL_strcmp(string, #x) == 0) return AUDIO_##x
   530     CHECK_FMT_STRING(U8);
   531     CHECK_FMT_STRING(S8);
   532     CHECK_FMT_STRING(U16LSB);
   533     CHECK_FMT_STRING(S16LSB);
   534     CHECK_FMT_STRING(U16MSB);
   535     CHECK_FMT_STRING(S16MSB);
   536     CHECK_FMT_STRING(U16SYS);
   537     CHECK_FMT_STRING(S16SYS);
   538     CHECK_FMT_STRING(U16);
   539     CHECK_FMT_STRING(S16);
   540     CHECK_FMT_STRING(S32LSB);
   541     CHECK_FMT_STRING(S32MSB);
   542     CHECK_FMT_STRING(S32SYS);
   543     CHECK_FMT_STRING(S32);
   544     CHECK_FMT_STRING(F32LSB);
   545     CHECK_FMT_STRING(F32MSB);
   546     CHECK_FMT_STRING(F32SYS);
   547     CHECK_FMT_STRING(F32);
   548 #undef CHECK_FMT_STRING
   549     return 0;
   550 }
   551 
   552 int
   553 SDL_GetNumAudioDrivers(void)
   554 {
   555     return (SDL_arraysize(bootstrap) - 1);
   556 }
   557 
   558 const char *
   559 SDL_GetAudioDriver(int index)
   560 {
   561     if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
   562         return (bootstrap[index]->name);
   563     }
   564     return (NULL);
   565 }
   566 
   567 int
   568 SDL_AudioInit(const char *driver_name)
   569 {
   570     int i = 0;
   571     int initialized = 0;
   572     int tried_to_init = 0;
   573 
   574     if (SDL_WasInit(SDL_INIT_AUDIO)) {
   575         SDL_AudioQuit();        /* shutdown driver if already running. */
   576     }
   577 
   578     SDL_memset(&current_audio, '\0', sizeof(current_audio));
   579     SDL_memset(open_devices, '\0', sizeof(open_devices));
   580 
   581     /* Select the proper audio driver */
   582     if (driver_name == NULL) {
   583         driver_name = SDL_getenv("SDL_AUDIODRIVER");
   584     }
   585 
   586     for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
   587         /* make sure we should even try this driver before doing so... */
   588         const AudioBootStrap *backend = bootstrap[i];
   589         if ((driver_name && (SDL_strncasecmp(backend->name, driver_name, SDL_strlen(driver_name)) != 0)) ||
   590             (!driver_name && backend->demand_only)) {
   591             continue;
   592         }
   593 
   594         tried_to_init = 1;
   595         SDL_memset(&current_audio, 0, sizeof(current_audio));
   596         current_audio.name = backend->name;
   597         current_audio.desc = backend->desc;
   598         initialized = backend->init(&current_audio.impl);
   599     }
   600 
   601     if (!initialized) {
   602         /* specific drivers will set the error message if they fail... */
   603         if (!tried_to_init) {
   604             if (driver_name) {
   605                 SDL_SetError("Audio target '%s' not available", driver_name);
   606             } else {
   607                 SDL_SetError("No available audio device");
   608             }
   609         }
   610 
   611         SDL_memset(&current_audio, 0, sizeof(current_audio));
   612         return (-1);            /* No driver was available, so fail. */
   613     }
   614 
   615     finalize_audio_entry_points();
   616 
   617     return (0);
   618 }
   619 
   620 /*
   621  * Get the current audio driver name
   622  */
   623 const char *
   624 SDL_GetCurrentAudioDriver()
   625 {
   626     return current_audio.name;
   627 }
   628 
   629 static void
   630 free_device_list(char ***devices, int *devCount)
   631 {
   632     int i = *devCount;
   633     if ((i > 0) && (*devices != NULL)) {
   634         while (i--) {
   635             SDL_free((*devices)[i]);
   636         }
   637     }
   638 
   639     SDL_free(*devices);
   640 
   641     *devices = NULL;
   642     *devCount = 0;
   643 }
   644 
   645 static
   646 void SDL_AddCaptureAudioDevice(const char *_name)
   647 {
   648     char *name = NULL;
   649     void *ptr = SDL_realloc(current_audio.inputDevices,
   650                           (current_audio.inputDeviceCount+1) * sizeof(char*));
   651     if (ptr == NULL) {
   652         return;  /* oh well. */
   653     }
   654 
   655     current_audio.inputDevices = (char **) ptr;
   656     name = SDL_strdup(_name);  /* if this returns NULL, that's okay. */
   657     current_audio.inputDevices[current_audio.inputDeviceCount++] = name;
   658 }
   659 
   660 static
   661 void SDL_AddOutputAudioDevice(const char *_name)
   662 {
   663     char *name = NULL;
   664     void *ptr = SDL_realloc(current_audio.outputDevices,
   665                           (current_audio.outputDeviceCount+1) * sizeof(char*));
   666     if (ptr == NULL) {
   667         return;  /* oh well. */
   668     }
   669 
   670     current_audio.outputDevices = (char **) ptr;
   671     name = SDL_strdup(_name);  /* if this returns NULL, that's okay. */
   672     current_audio.outputDevices[current_audio.outputDeviceCount++] = name;
   673 }
   674 
   675 
   676 int
   677 SDL_GetNumAudioDevices(int iscapture)
   678 {
   679     int retval = 0;
   680 
   681     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   682         return -1;
   683     }
   684 
   685     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   686         return 0;
   687     }
   688 
   689     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   690         return 1;
   691     }
   692 
   693     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   694         return 1;
   695     }
   696 
   697     if (iscapture) {
   698         free_device_list(&current_audio.inputDevices,
   699                          &current_audio.inputDeviceCount);
   700         current_audio.impl.DetectDevices(iscapture, SDL_AddCaptureAudioDevice);
   701         retval = current_audio.inputDeviceCount;
   702     } else {
   703         free_device_list(&current_audio.outputDevices,
   704                          &current_audio.outputDeviceCount);
   705         current_audio.impl.DetectDevices(iscapture, SDL_AddOutputAudioDevice);
   706         retval = current_audio.outputDeviceCount;
   707     }
   708 
   709     return retval;
   710 }
   711 
   712 
   713 const char *
   714 SDL_GetAudioDeviceName(int index, int iscapture)
   715 {
   716     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   717         SDL_SetError("Audio subsystem is not initialized");
   718         return NULL;
   719     }
   720 
   721     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   722         SDL_SetError("No capture support");
   723         return NULL;
   724     }
   725 
   726     if (index < 0) {
   727         goto no_such_device;
   728     }
   729 
   730     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   731         if (index > 0) {
   732             goto no_such_device;
   733         }
   734         return DEFAULT_INPUT_DEVNAME;
   735     }
   736 
   737     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   738         if (index > 0) {
   739             goto no_such_device;
   740         }
   741         return DEFAULT_OUTPUT_DEVNAME;
   742     }
   743 
   744     if (iscapture) {
   745         if (index >= current_audio.inputDeviceCount) {
   746             goto no_such_device;
   747         }
   748         return current_audio.inputDevices[index];
   749     } else {
   750         if (index >= current_audio.outputDeviceCount) {
   751             goto no_such_device;
   752         }
   753         return current_audio.outputDevices[index];
   754     }
   755 
   756 no_such_device:
   757     SDL_SetError("No such device");
   758     return NULL;
   759 }
   760 
   761 
   762 static void
   763 close_audio_device(SDL_AudioDevice * device)
   764 {
   765     device->enabled = 0;
   766     if (device->thread != NULL) {
   767         SDL_WaitThread(device->thread, NULL);
   768     }
   769     if (device->mixer_lock != NULL) {
   770         SDL_DestroyMutex(device->mixer_lock);
   771     }
   772     SDL_FreeAudioMem(device->fake_stream);
   773     if (device->convert.needed) {
   774         SDL_FreeAudioMem(device->convert.buf);
   775     }
   776     if (device->opened) {
   777         current_audio.impl.CloseDevice(device);
   778         device->opened = 0;
   779     }
   780     SDL_FreeAudioMem(device);
   781 }
   782 
   783 
   784 /*
   785  * Sanity check desired AudioSpec for SDL_OpenAudio() in (orig).
   786  *  Fills in a sanitized copy in (prepared).
   787  *  Returns non-zero if okay, zero on fatal parameters in (orig).
   788  */
   789 static int
   790 prepare_audiospec(const SDL_AudioSpec * orig, SDL_AudioSpec * prepared)
   791 {
   792     SDL_memcpy(prepared, orig, sizeof(SDL_AudioSpec));
   793 
   794     if (orig->callback == NULL) {
   795         SDL_SetError("SDL_OpenAudio() passed a NULL callback");
   796         return 0;
   797     }
   798 
   799     if (orig->freq == 0) {
   800         const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY");
   801         if ((!env) || ((prepared->freq = SDL_atoi(env)) == 0)) {
   802             prepared->freq = 22050;     /* a reasonable default */
   803         }
   804     }
   805 
   806     if (orig->format == 0) {
   807         const char *env = SDL_getenv("SDL_AUDIO_FORMAT");
   808         if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) {
   809             prepared->format = AUDIO_S16;       /* a reasonable default */
   810         }
   811     }
   812 
   813     switch (orig->channels) {
   814     case 0:{
   815             const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
   816             if ((!env) || ((prepared->channels = (Uint8) SDL_atoi(env)) == 0)) {
   817                 prepared->channels = 2; /* a reasonable default */
   818             }
   819             break;
   820         }
   821     case 1:                    /* Mono */
   822     case 2:                    /* Stereo */
   823     case 4:                    /* surround */
   824     case 6:                    /* surround with center and lfe */
   825         break;
   826     default:
   827         SDL_SetError("Unsupported number of audio channels.");
   828         return 0;
   829     }
   830 
   831     if (orig->samples == 0) {
   832         const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
   833         if ((!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0)) {
   834             /* Pick a default of ~46 ms at desired frequency */
   835             /* !!! FIXME: remove this when the non-Po2 resampling is in. */
   836             const int samples = (prepared->freq / 1000) * 46;
   837             int power2 = 1;
   838             while (power2 < samples) {
   839                 power2 *= 2;
   840             }
   841             prepared->samples = power2;
   842         }
   843     }
   844 
   845     /* Calculate the silence and size of the audio specification */
   846     SDL_CalculateAudioSpec(prepared);
   847 
   848     return 1;
   849 }
   850 
   851 
   852 static SDL_AudioDeviceID
   853 open_audio_device(const char *devname, int iscapture,
   854                   const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
   855                   int allowed_changes, int min_id)
   856 {
   857     SDL_AudioDeviceID id = 0;
   858     SDL_AudioSpec _obtained;
   859     SDL_AudioDevice *device;
   860     SDL_bool build_cvt;
   861     int i = 0;
   862 
   863     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   864         SDL_SetError("Audio subsystem is not initialized");
   865         return 0;
   866     }
   867 
   868     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   869         SDL_SetError("No capture support");
   870         return 0;
   871     }
   872 
   873     if (!obtained) {
   874         obtained = &_obtained;
   875     }
   876     if (!prepare_audiospec(desired, obtained)) {
   877         return 0;
   878     }
   879 
   880     /* If app doesn't care about a specific device, let the user override. */
   881     if (devname == NULL) {
   882         devname = SDL_getenv("SDL_AUDIO_DEVICE_NAME");
   883     }
   884 
   885     /*
   886      * Catch device names at the high level for the simple case...
   887      * This lets us have a basic "device enumeration" for systems that
   888      *  don't have multiple devices, but makes sure the device name is
   889      *  always NULL when it hits the low level.
   890      *
   891      * Also make sure that the simple case prevents multiple simultaneous
   892      *  opens of the default system device.
   893      */
   894 
   895     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   896         if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
   897             SDL_SetError("No such device");
   898             return 0;
   899         }
   900         devname = NULL;
   901 
   902         for (i = 0; i < SDL_arraysize(open_devices); i++) {
   903             if ((open_devices[i]) && (open_devices[i]->iscapture)) {
   904                 SDL_SetError("Audio device already open");
   905                 return 0;
   906             }
   907         }
   908     }
   909 
   910     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   911         if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
   912             SDL_SetError("No such device");
   913             return 0;
   914         }
   915         devname = NULL;
   916 
   917         for (i = 0; i < SDL_arraysize(open_devices); i++) {
   918             if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
   919                 SDL_SetError("Audio device already open");
   920                 return 0;
   921             }
   922         }
   923     }
   924 
   925     device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice));
   926     if (device == NULL) {
   927         SDL_OutOfMemory();
   928         return 0;
   929     }
   930     SDL_memset(device, '\0', sizeof(SDL_AudioDevice));
   931     device->spec = *obtained;
   932     device->enabled = 1;
   933     device->paused = 1;
   934     device->iscapture = iscapture;
   935 
   936     /* Create a semaphore for locking the sound buffers */
   937     if (!current_audio.impl.SkipMixerLock) {
   938         device->mixer_lock = SDL_CreateMutex();
   939         if (device->mixer_lock == NULL) {
   940             close_audio_device(device);
   941             SDL_SetError("Couldn't create mixer lock");
   942             return 0;
   943         }
   944     }
   945 
   946     /* force a device detection if we haven't done one yet. */
   947     if ( ((iscapture) && (current_audio.inputDevices == NULL)) ||
   948          ((!iscapture) && (current_audio.outputDevices == NULL)) )
   949         SDL_GetNumAudioDevices(iscapture);
   950 
   951     if (current_audio.impl.OpenDevice(device, devname, iscapture) < 0) {
   952         close_audio_device(device);
   953         return 0;
   954     }
   955     device->opened = 1;
   956 
   957     /* Allocate a fake audio memory buffer */
   958     device->fake_stream = (Uint8 *)SDL_AllocAudioMem(device->spec.size);
   959     if (device->fake_stream == NULL) {
   960         close_audio_device(device);
   961         SDL_OutOfMemory();
   962         return 0;
   963     }
   964 
   965     /* See if we need to do any conversion */
   966     build_cvt = SDL_FALSE;
   967     if (obtained->freq != device->spec.freq) {
   968         if (allowed_changes & SDL_AUDIO_ALLOW_FREQUENCY_CHANGE) {
   969             obtained->freq = device->spec.freq;
   970         } else {
   971             build_cvt = SDL_TRUE;
   972         }
   973     }
   974     if (obtained->format != device->spec.format) {
   975         if (allowed_changes & SDL_AUDIO_ALLOW_FORMAT_CHANGE) {
   976             obtained->format = device->spec.format;
   977         } else {
   978             build_cvt = SDL_TRUE;
   979         }
   980     }
   981     if (obtained->channels != device->spec.channels) {
   982         if (allowed_changes & SDL_AUDIO_ALLOW_CHANNELS_CHANGE) {
   983             obtained->channels = device->spec.channels;
   984         } else {
   985             build_cvt = SDL_TRUE;
   986         }
   987     }
   988 
   989     /* If the audio driver changes the buffer size, accept it.
   990        This needs to be done after the format is modified above,
   991        otherwise it might not have the correct buffer size.
   992      */
   993     if (device->spec.samples != obtained->samples) {
   994         obtained->samples = device->spec.samples;
   995         SDL_CalculateAudioSpec(obtained);
   996     }
   997 
   998     if (build_cvt) {
   999         /* Build an audio conversion block */
  1000         if (SDL_BuildAudioCVT(&device->convert,
  1001                               obtained->format, obtained->channels,
  1002                               obtained->freq,
  1003                               device->spec.format, device->spec.channels,
  1004                               device->spec.freq) < 0) {
  1005             close_audio_device(device);
  1006             return 0;
  1007         }
  1008         if (device->convert.needed) {
  1009             device->convert.len = (int) (((double) device->spec.size) /
  1010                                          device->convert.len_ratio);
  1011 
  1012             device->convert.buf =
  1013                 (Uint8 *) SDL_AllocAudioMem(device->convert.len *
  1014                                             device->convert.len_mult);
  1015             if (device->convert.buf == NULL) {
  1016                 close_audio_device(device);
  1017                 SDL_OutOfMemory();
  1018                 return 0;
  1019             }
  1020         }
  1021     }
  1022 
  1023     /* Find an available device ID and store the structure... */
  1024     for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) {
  1025         if (open_devices[id] == NULL) {
  1026             open_devices[id] = device;
  1027             break;
  1028         }
  1029     }
  1030 
  1031     if (id == SDL_arraysize(open_devices)) {
  1032         SDL_SetError("Too many open audio devices");
  1033         close_audio_device(device);
  1034         return 0;
  1035     }
  1036 
  1037     /* Start the audio thread if necessary */
  1038     if (!current_audio.impl.ProvidesOwnCallbackThread) {
  1039         /* Start the audio thread */
  1040         char name[64];
  1041         SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) (id + 1));
  1042 /* !!! FIXME: this is nasty. */
  1043 #if defined(__WIN32__) && !defined(HAVE_LIBC)
  1044 #undef SDL_CreateThread
  1045 #if SDL_DYNAMIC_API
  1046         device->thread = SDL_CreateThread_REAL(SDL_RunAudio, name, device, NULL, NULL);
  1047 #else
  1048         device->thread = SDL_CreateThread(SDL_RunAudio, name, device, NULL, NULL);
  1049 #endif
  1050 #else
  1051         device->thread = SDL_CreateThread(SDL_RunAudio, name, device);
  1052 #endif
  1053         if (device->thread == NULL) {
  1054             SDL_CloseAudioDevice(id + 1);
  1055             SDL_SetError("Couldn't create audio thread");
  1056             return 0;
  1057         }
  1058     }
  1059 
  1060     return id + 1;
  1061 }
  1062 
  1063 
  1064 int
  1065 SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
  1066 {
  1067     SDL_AudioDeviceID id = 0;
  1068 
  1069     /* Start up the audio driver, if necessary. This is legacy behaviour! */
  1070     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
  1071         if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
  1072             return (-1);
  1073         }
  1074     }
  1075 
  1076     /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
  1077     if (open_devices[0] != NULL) {
  1078         SDL_SetError("Audio device is already opened");
  1079         return (-1);
  1080     }
  1081 
  1082     if (obtained) {
  1083         id = open_audio_device(NULL, 0, desired, obtained,
  1084                                SDL_AUDIO_ALLOW_ANY_CHANGE, 1);
  1085     } else {
  1086         id = open_audio_device(NULL, 0, desired, desired, 0, 1);
  1087     }
  1088 
  1089     SDL_assert((id == 0) || (id == 1));
  1090     return ((id == 0) ? -1 : 0);
  1091 }
  1092 
  1093 SDL_AudioDeviceID
  1094 SDL_OpenAudioDevice(const char *device, int iscapture,
  1095                     const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
  1096                     int allowed_changes)
  1097 {
  1098     return open_audio_device(device, iscapture, desired, obtained,
  1099                              allowed_changes, 2);
  1100 }
  1101 
  1102 SDL_AudioStatus
  1103 SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
  1104 {
  1105     SDL_AudioDevice *device = get_audio_device(devid);
  1106     SDL_AudioStatus status = SDL_AUDIO_STOPPED;
  1107     if (device && device->enabled) {
  1108         if (device->paused) {
  1109             status = SDL_AUDIO_PAUSED;
  1110         } else {
  1111             status = SDL_AUDIO_PLAYING;
  1112         }
  1113     }
  1114     return (status);
  1115 }
  1116 
  1117 
  1118 SDL_AudioStatus
  1119 SDL_GetAudioStatus(void)
  1120 {
  1121     return SDL_GetAudioDeviceStatus(1);
  1122 }
  1123 
  1124 void
  1125 SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
  1126 {
  1127     SDL_AudioDevice *device = get_audio_device(devid);
  1128     if (device) {
  1129         current_audio.impl.LockDevice(device);
  1130         device->paused = pause_on;
  1131         current_audio.impl.UnlockDevice(device);
  1132     }
  1133 }
  1134 
  1135 void
  1136 SDL_PauseAudio(int pause_on)
  1137 {
  1138     SDL_PauseAudioDevice(1, pause_on);
  1139 }
  1140 
  1141 
  1142 void
  1143 SDL_LockAudioDevice(SDL_AudioDeviceID devid)
  1144 {
  1145     /* Obtain a lock on the mixing buffers */
  1146     SDL_AudioDevice *device = get_audio_device(devid);
  1147     if (device) {
  1148         current_audio.impl.LockDevice(device);
  1149     }
  1150 }
  1151 
  1152 void
  1153 SDL_LockAudio(void)
  1154 {
  1155     SDL_LockAudioDevice(1);
  1156 }
  1157 
  1158 void
  1159 SDL_UnlockAudioDevice(SDL_AudioDeviceID devid)
  1160 {
  1161     /* Obtain a lock on the mixing buffers */
  1162     SDL_AudioDevice *device = get_audio_device(devid);
  1163     if (device) {
  1164         current_audio.impl.UnlockDevice(device);
  1165     }
  1166 }
  1167 
  1168 void
  1169 SDL_UnlockAudio(void)
  1170 {
  1171     SDL_UnlockAudioDevice(1);
  1172 }
  1173 
  1174 void
  1175 SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
  1176 {
  1177     SDL_AudioDevice *device = get_audio_device(devid);
  1178     if (device) {
  1179         close_audio_device(device);
  1180         open_devices[devid - 1] = NULL;
  1181     }
  1182 }
  1183 
  1184 void
  1185 SDL_CloseAudio(void)
  1186 {
  1187     SDL_CloseAudioDevice(1);
  1188 }
  1189 
  1190 void
  1191 SDL_AudioQuit(void)
  1192 {
  1193     SDL_AudioDeviceID i;
  1194 
  1195     if (!current_audio.name) {  /* not initialized?! */
  1196         return;
  1197     }
  1198 
  1199     for (i = 0; i < SDL_arraysize(open_devices); i++) {
  1200         if (open_devices[i] != NULL) {
  1201             SDL_CloseAudioDevice(i+1);
  1202         }
  1203     }
  1204 
  1205     /* Free the driver data */
  1206     current_audio.impl.Deinitialize();
  1207     free_device_list(&current_audio.outputDevices,
  1208                      &current_audio.outputDeviceCount);
  1209     free_device_list(&current_audio.inputDevices,
  1210                      &current_audio.inputDeviceCount);
  1211     SDL_memset(&current_audio, '\0', sizeof(current_audio));
  1212     SDL_memset(open_devices, '\0', sizeof(open_devices));
  1213 }
  1214 
  1215 #define NUM_FORMATS 10
  1216 static int format_idx;
  1217 static int format_idx_sub;
  1218 static SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS] = {
  1219     {AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
  1220      AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
  1221     {AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
  1222      AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
  1223     {AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S32LSB,
  1224      AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
  1225     {AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S32MSB,
  1226      AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
  1227     {AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S32LSB,
  1228      AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
  1229     {AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_S32MSB,
  1230      AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
  1231     {AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S16LSB,
  1232      AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
  1233     {AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S16MSB,
  1234      AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
  1235     {AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_S16LSB,
  1236      AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
  1237     {AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_S16MSB,
  1238      AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
  1239 };
  1240 
  1241 SDL_AudioFormat
  1242 SDL_FirstAudioFormat(SDL_AudioFormat format)
  1243 {
  1244     for (format_idx = 0; format_idx < NUM_FORMATS; ++format_idx) {
  1245         if (format_list[format_idx][0] == format) {
  1246             break;
  1247         }
  1248     }
  1249     format_idx_sub = 0;
  1250     return (SDL_NextAudioFormat());
  1251 }
  1252 
  1253 SDL_AudioFormat
  1254 SDL_NextAudioFormat(void)
  1255 {
  1256     if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) {
  1257         return (0);
  1258     }
  1259     return (format_list[format_idx][format_idx_sub++]);
  1260 }
  1261 
  1262 void
  1263 SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
  1264 {
  1265     switch (spec->format) {
  1266     case AUDIO_U8:
  1267         spec->silence = 0x80;
  1268         break;
  1269     default:
  1270         spec->silence = 0x00;
  1271         break;
  1272     }
  1273     spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
  1274     spec->size *= spec->channels;
  1275     spec->size *= spec->samples;
  1276 }
  1277 
  1278 
  1279 /*
  1280  * Moved here from SDL_mixer.c, since it relies on internals of an opened
  1281  *  audio device (and is deprecated, by the way!).
  1282  */
  1283 void
  1284 SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
  1285 {
  1286     /* Mix the user-level audio format */
  1287     SDL_AudioDevice *device = get_audio_device(1);
  1288     if (device != NULL) {
  1289         SDL_AudioFormat format;
  1290         if (device->convert.needed) {
  1291             format = device->convert.src_format;
  1292         } else {
  1293             format = device->spec.format;
  1294         }
  1295         SDL_MixAudioFormat(dst, src, format, len, volume);
  1296     }
  1297 }
  1298 
  1299 /* vi: set ts=4 sw=4 expandtab: */