src/audio/SDL_audio.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 04 Aug 2011 00:31:11 -0400
changeset 5593 ab22ca13c47f
parent 5592 2e88d0742f4d
child 5596 d4b2f6543074
permissions -rw-r--r--
Cleaned up audio device detection. Cleared out a lot of cut-and-paste.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 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_config.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 BEOSAUDIO_bootstrap;
    60 extern AudioBootStrap COREAUDIO_bootstrap;
    61 extern AudioBootStrap COREAUDIOIPHONE_bootstrap;
    62 extern AudioBootStrap SNDMGR_bootstrap;
    63 extern AudioBootStrap DISKAUD_bootstrap;
    64 extern AudioBootStrap DUMMYAUD_bootstrap;
    65 extern AudioBootStrap DCAUD_bootstrap;
    66 extern AudioBootStrap DART_bootstrap;
    67 extern AudioBootStrap NDSAUD_bootstrap;
    68 extern AudioBootStrap FUSIONSOUND_bootstrap;
    69 extern AudioBootStrap ANDROIDAUD_bootstrap;
    70 
    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_BSD
    81     &BSD_AUDIO_bootstrap,
    82 #endif
    83 #if SDL_AUDIO_DRIVER_OSS
    84     &DSP_bootstrap,
    85 #endif
    86 #if SDL_AUDIO_DRIVER_QSA
    87     &QSAAUDIO_bootstrap,
    88 #endif
    89 #if SDL_AUDIO_DRIVER_SUNAUDIO
    90     &SUNAUDIO_bootstrap,
    91 #endif
    92 #if SDL_AUDIO_DRIVER_ARTS
    93     &ARTS_bootstrap,
    94 #endif
    95 #if SDL_AUDIO_DRIVER_ESD
    96     &ESD_bootstrap,
    97 #endif
    98 #if SDL_AUDIO_DRIVER_NAS
    99     &NAS_bootstrap,
   100 #endif
   101 #if SDL_AUDIO_DRIVER_XAUDIO2
   102     &XAUDIO2_bootstrap,
   103 #endif
   104 #if SDL_AUDIO_DRIVER_DSOUND
   105     &DSOUND_bootstrap,
   106 #endif
   107 #if SDL_AUDIO_DRIVER_WINMM
   108     &WINMM_bootstrap,
   109 #endif
   110 #if SDL_AUDIO_DRIVER_PAUDIO
   111     &PAUDIO_bootstrap,
   112 #endif
   113 #if SDL_AUDIO_DRIVER_BEOSAUDIO
   114     &BEOSAUDIO_bootstrap,
   115 #endif
   116 #if SDL_AUDIO_DRIVER_COREAUDIO
   117     &COREAUDIO_bootstrap,
   118 #endif
   119 #if SDL_AUDIO_DRIVER_COREAUDIOIPHONE
   120     &COREAUDIOIPHONE_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_NDS
   129     &NDSAUD_bootstrap,
   130 #endif
   131 #if SDL_AUDIO_DRIVER_FUSIONSOUND
   132     &FUSIONSOUND_bootstrap,
   133 #endif
   134 #if SDL_AUDIO_DRIVER_ANDROID
   135     &ANDROIDAUD_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 0;
   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_mutexP(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_mutexV(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     if (stream->buffer != NULL) {
   304         SDL_free(stream->buffer);
   305     }
   306 }
   307 
   308 #if defined(ANDROID)
   309 #include <android/log.h>
   310 #endif
   311 
   312 /* The general mixing thread function */
   313 int SDLCALL
   314 SDL_RunAudio(void *devicep)
   315 {
   316     SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
   317     Uint8 *stream;
   318     int stream_len;
   319     void *udata;
   320     void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
   321     int silence;
   322     Uint32 delay;
   323     /* For streaming when the buffer sizes don't match up */
   324     Uint8 *istream;
   325     int istream_len = 0;
   326 
   327     /* The audio mixing is always a high priority thread */
   328     SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
   329 
   330     /* Perform any thread setup */
   331     device->threadid = SDL_ThreadID();
   332     current_audio.impl.ThreadInit(device);
   333 
   334     /* Set up the mixing function */
   335     fill = device->spec.callback;
   336     udata = device->spec.userdata;
   337 
   338     /* By default do not stream */
   339     device->use_streamer = 0;
   340 
   341     if (device->convert.needed) {
   342         if (device->convert.src_format == AUDIO_U8) {
   343             silence = 0x80;
   344         } else {
   345             silence = 0;
   346         }
   347 
   348 #if 0                           /* !!! FIXME: I took len_div out of the structure. Use rate_incr instead? */
   349         /* If the result of the conversion alters the length, i.e. resampling is being used, use the streamer */
   350         if (device->convert.len_mult != 1 || device->convert.len_div != 1) {
   351             /* The streamer's maximum length should be twice whichever is larger: spec.size or len_cvt */
   352             stream_max_len = 2 * device->spec.size;
   353             if (device->convert.len_mult > device->convert.len_div) {
   354                 stream_max_len *= device->convert.len_mult;
   355                 stream_max_len /= device->convert.len_div;
   356             }
   357             if (SDL_StreamInit(&device->streamer, stream_max_len, silence) <
   358                 0)
   359                 return -1;
   360             device->use_streamer = 1;
   361 
   362             /* istream_len should be the length of what we grab from the callback and feed to conversion,
   363                so that we get close to spec_size. I.e. we want device.spec_size = istream_len * u / d
   364              */
   365             istream_len =
   366                 device->spec.size * device->convert.len_div /
   367                 device->convert.len_mult;
   368         }
   369 #endif
   370 
   371         /* stream_len = device->convert.len; */
   372         stream_len = device->spec.size;
   373     } else {
   374         silence = device->spec.silence;
   375         stream_len = device->spec.size;
   376     }
   377 
   378     /* Calculate the delay while paused */
   379     delay = ((device->spec.samples * 1000) / device->spec.freq);
   380 
   381     /* Determine if the streamer is necessary here */
   382     if (device->use_streamer == 1) {
   383         /* This code is almost the same as the old code. The difference is, instead of reading
   384            directly from the callback into "stream", then converting and sending the audio off,
   385            we go: callback -> "istream" -> (conversion) -> streamer -> stream -> device.
   386            However, reading and writing with streamer are done separately:
   387            - We only call the callback and write to the streamer when the streamer does not
   388            contain enough samples to output to the device.
   389            - We only read from the streamer and tell the device to play when the streamer
   390            does have enough samples to output.
   391            This allows us to perform resampling in the conversion step, where the output of the
   392            resampling process can be any number. We will have to see what a good size for the
   393            stream's maximum length is, but I suspect 2*max(len_cvt, stream_len) is a good figure.
   394          */
   395         while (device->enabled) {
   396 
   397             if (device->paused) {
   398                 SDL_Delay(delay);
   399                 continue;
   400             }
   401 
   402             /* Only read in audio if the streamer doesn't have enough already (if it does not have enough samples to output) */
   403             if (SDL_StreamLength(&device->streamer) < stream_len) {
   404                 /* Set up istream */
   405                 if (device->convert.needed) {
   406                     if (device->convert.buf) {
   407                         istream = device->convert.buf;
   408                     } else {
   409                         continue;
   410                     }
   411                 } else {
   412 /* FIXME: Ryan, this is probably wrong.  I imagine we don't want to get
   413  * a device buffer both here and below in the stream output.
   414  */
   415                     istream = current_audio.impl.GetDeviceBuf(device);
   416                     if (istream == NULL) {
   417                         istream = device->fake_stream;
   418                     }
   419                 }
   420 
   421                 /* Read from the callback into the _input_ stream */
   422                 SDL_mutexP(device->mixer_lock);
   423                 (*fill) (udata, istream, istream_len);
   424                 SDL_mutexV(device->mixer_lock);
   425 
   426                 /* Convert the audio if necessary and write to the streamer */
   427                 if (device->convert.needed) {
   428                     SDL_ConvertAudio(&device->convert);
   429                     if (istream == NULL) {
   430                         istream = device->fake_stream;
   431                     }
   432                     /*SDL_memcpy(istream, device->convert.buf, device->convert.len_cvt); */
   433                     SDL_StreamWrite(&device->streamer, device->convert.buf,
   434                                     device->convert.len_cvt);
   435                 } else {
   436                     SDL_StreamWrite(&device->streamer, istream, istream_len);
   437                 }
   438             }
   439 
   440             /* Only output audio if the streamer has enough to output */
   441             if (SDL_StreamLength(&device->streamer) >= stream_len) {
   442                 /* Set up the output stream */
   443                 if (device->convert.needed) {
   444                     if (device->convert.buf) {
   445                         stream = device->convert.buf;
   446                     } else {
   447                         continue;
   448                     }
   449                 } else {
   450                     stream = current_audio.impl.GetDeviceBuf(device);
   451                     if (stream == NULL) {
   452                         stream = device->fake_stream;
   453                     }
   454                 }
   455 
   456                 /* Now read from the streamer */
   457                 SDL_StreamRead(&device->streamer, stream, stream_len);
   458 
   459                 /* Ready current buffer for play and change current buffer */
   460                 if (stream != device->fake_stream) {
   461                     current_audio.impl.PlayDevice(device);
   462                     /* Wait for an audio buffer to become available */
   463                     current_audio.impl.WaitDevice(device);
   464                 } else {
   465                     SDL_Delay(delay);
   466                 }
   467             }
   468 
   469         }
   470     } else {
   471         /* Otherwise, do not use the streamer. This is the old code. */
   472 
   473         /* Loop, filling the audio buffers */
   474         while (device->enabled) {
   475 
   476             if (device->paused) {
   477                 SDL_Delay(delay);
   478                 continue;
   479             }
   480 
   481             /* Fill the current buffer with sound */
   482             if (device->convert.needed) {
   483                 if (device->convert.buf) {
   484                     stream = device->convert.buf;
   485                 } else {
   486                     continue;
   487                 }
   488             } else {
   489                 stream = current_audio.impl.GetDeviceBuf(device);
   490                 if (stream == NULL) {
   491                     stream = device->fake_stream;
   492                 }
   493             }
   494 
   495             SDL_mutexP(device->mixer_lock);
   496             (*fill) (udata, stream, stream_len);
   497             SDL_mutexV(device->mixer_lock);
   498 
   499             /* Convert the audio if necessary */
   500             if (device->convert.needed) {
   501                 SDL_ConvertAudio(&device->convert);
   502                 stream = current_audio.impl.GetDeviceBuf(device);
   503                 if (stream == NULL) {
   504                     stream = device->fake_stream;
   505                 }
   506                 SDL_memcpy(stream, device->convert.buf,
   507                            device->convert.len_cvt);
   508             }
   509 
   510             /* Ready current buffer for play and change current buffer */
   511             if (stream != device->fake_stream) {
   512                 current_audio.impl.PlayDevice(device);
   513                 /* Wait for an audio buffer to become available */
   514                 current_audio.impl.WaitDevice(device);
   515             } else {
   516                 SDL_Delay(delay);
   517             }
   518         }
   519     }
   520 
   521     /* Wait for the audio to drain.. */
   522     current_audio.impl.WaitDone(device);
   523 
   524     /* If necessary, deinit the streamer */
   525     if (device->use_streamer == 1)
   526         SDL_StreamDeinit(&device->streamer);
   527 
   528     return (0);
   529 }
   530 
   531 
   532 static SDL_AudioFormat
   533 SDL_ParseAudioFormat(const char *string)
   534 {
   535 #define CHECK_FMT_STRING(x) if (SDL_strcmp(string, #x) == 0) return AUDIO_##x
   536     CHECK_FMT_STRING(U8);
   537     CHECK_FMT_STRING(S8);
   538     CHECK_FMT_STRING(U16LSB);
   539     CHECK_FMT_STRING(S16LSB);
   540     CHECK_FMT_STRING(U16MSB);
   541     CHECK_FMT_STRING(S16MSB);
   542     CHECK_FMT_STRING(U16SYS);
   543     CHECK_FMT_STRING(S16SYS);
   544     CHECK_FMT_STRING(U16);
   545     CHECK_FMT_STRING(S16);
   546     CHECK_FMT_STRING(S32LSB);
   547     CHECK_FMT_STRING(S32MSB);
   548     CHECK_FMT_STRING(S32SYS);
   549     CHECK_FMT_STRING(S32);
   550     CHECK_FMT_STRING(F32LSB);
   551     CHECK_FMT_STRING(F32MSB);
   552     CHECK_FMT_STRING(F32SYS);
   553     CHECK_FMT_STRING(F32);
   554 #undef CHECK_FMT_STRING
   555     return 0;
   556 }
   557 
   558 int
   559 SDL_GetNumAudioDrivers(void)
   560 {
   561     return (SDL_arraysize(bootstrap) - 1);
   562 }
   563 
   564 const char *
   565 SDL_GetAudioDriver(int index)
   566 {
   567     if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
   568         return (bootstrap[index]->name);
   569     }
   570     return (NULL);
   571 }
   572 
   573 int
   574 SDL_AudioInit(const char *driver_name)
   575 {
   576     int i = 0;
   577     int initialized = 0;
   578     int tried_to_init = 0;
   579 
   580     if (SDL_WasInit(SDL_INIT_AUDIO)) {
   581         SDL_AudioQuit();        /* shutdown driver if already running. */
   582     }
   583 
   584     SDL_memset(&current_audio, '\0', sizeof(current_audio));
   585     SDL_memset(open_devices, '\0', sizeof(open_devices));
   586 
   587     /* Select the proper audio driver */
   588     if (driver_name == NULL) {
   589         driver_name = SDL_getenv("SDL_AUDIODRIVER");
   590     }
   591 
   592     for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
   593         /* make sure we should even try this driver before doing so... */
   594         const AudioBootStrap *backend = bootstrap[i];
   595         if (((driver_name) && (SDL_strcasecmp(backend->name, driver_name))) ||
   596             ((!driver_name) && (backend->demand_only))) {
   597             continue;
   598         }
   599 
   600         tried_to_init = 1;
   601         SDL_memset(&current_audio, 0, sizeof(current_audio));
   602         current_audio.name = backend->name;
   603         current_audio.desc = backend->desc;
   604         initialized = backend->init(&current_audio.impl);
   605     }
   606 
   607     if (!initialized) {
   608         /* specific drivers will set the error message if they fail... */
   609         if (!tried_to_init) {
   610             if (driver_name) {
   611                 SDL_SetError("Audio target '%s' not available", driver_name);
   612             } else {
   613                 SDL_SetError("No available audio device");
   614             }
   615         }
   616 
   617         SDL_memset(&current_audio, 0, sizeof(current_audio));
   618         return (-1);            /* No driver was available, so fail. */
   619     }
   620 
   621     finalize_audio_entry_points();
   622 
   623     return (0);
   624 }
   625 
   626 /*
   627  * Get the current audio driver name
   628  */
   629 const char *
   630 SDL_GetCurrentAudioDriver()
   631 {
   632     return current_audio.name;
   633 }
   634 
   635 static void
   636 free_device_list(char ***devices, int *devCount)
   637 {
   638     int i = *devCount;
   639     if ((i > 0) && (*devices != NULL)) {
   640         while (i--) {
   641             SDL_free((*devices)[i]);
   642         }
   643     }
   644 
   645     if (*devices != NULL) {
   646         SDL_free(*devices);
   647     }
   648 
   649     *devices = NULL;
   650     *devCount = 0;
   651 }
   652 
   653 static
   654 void SDL_AddCaptureAudioDevice(const char *_name)
   655 {
   656     char *name = NULL;
   657     void *ptr = SDL_realloc(current_audio.inputDevices,
   658                           (current_audio.inputDeviceCount+1) * sizeof(char*));
   659     if (ptr == NULL) {
   660         return;  /* oh well. */
   661     }
   662 
   663     current_audio.inputDevices = (char **) ptr;
   664     name = SDL_strdup(_name);  /* if this returns NULL, that's okay. */
   665     current_audio.inputDevices[current_audio.inputDeviceCount++] = name;
   666 }
   667 
   668 static
   669 void SDL_AddOutputAudioDevice(const char *_name)
   670 {
   671     char *name = NULL;
   672     void *ptr = SDL_realloc(current_audio.outputDevices,
   673                           (current_audio.outputDeviceCount+1) * sizeof(char*));
   674     if (ptr == NULL) {
   675         return;  /* oh well. */
   676     }
   677 
   678     current_audio.outputDevices = (char **) ptr;
   679     name = SDL_strdup(_name);  /* if this returns NULL, that's okay. */
   680     current_audio.outputDevices[current_audio.outputDeviceCount++] = name;
   681 }
   682 
   683 
   684 int
   685 SDL_GetNumAudioDevices(int iscapture)
   686 {
   687     int retval = 0;
   688 
   689     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   690         return -1;
   691     }
   692 
   693     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   694         return 0;
   695     }
   696 
   697     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   698         return 1;
   699     }
   700 
   701     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   702         return 1;
   703     }
   704 
   705     if (iscapture) {
   706         free_device_list(&current_audio.inputDevices,
   707                          &current_audio.inputDeviceCount);
   708         current_audio.impl.DetectDevices(iscapture, SDL_AddCaptureAudioDevice);
   709         retval = current_audio.inputDeviceCount;
   710     } else {
   711         free_device_list(&current_audio.outputDevices,
   712                          &current_audio.outputDeviceCount);
   713         current_audio.impl.DetectDevices(iscapture, SDL_AddOutputAudioDevice);
   714         retval = current_audio.outputDeviceCount;
   715     }
   716 
   717     return retval;
   718 }
   719 
   720 
   721 const char *
   722 SDL_GetAudioDeviceName(int index, int iscapture)
   723 {
   724     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   725         SDL_SetError("Audio subsystem is not initialized");
   726         return NULL;
   727     }
   728 
   729     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   730         SDL_SetError("No capture support");
   731         return NULL;
   732     }
   733 
   734     if (index < 0) {
   735         goto no_such_device;
   736     }
   737 
   738     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   739         return DEFAULT_INPUT_DEVNAME;
   740     }
   741 
   742     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   743         return DEFAULT_OUTPUT_DEVNAME;
   744     }
   745 
   746     if (iscapture) {
   747         if (index >= current_audio.inputDeviceCount) {
   748             goto no_such_device;
   749         }
   750         return current_audio.inputDevices[index];
   751     } else {
   752         if (index >= current_audio.outputDeviceCount) {
   753             goto no_such_device;
   754         }
   755         return current_audio.outputDevices[index];
   756     }
   757 
   758 no_such_device:
   759     SDL_SetError("No such device");
   760     return NULL;
   761 }
   762 
   763 
   764 static void
   765 close_audio_device(SDL_AudioDevice * device)
   766 {
   767     device->enabled = 0;
   768     if (device->thread != NULL) {
   769         SDL_WaitThread(device->thread, NULL);
   770     }
   771     if (device->mixer_lock != NULL) {
   772         SDL_DestroyMutex(device->mixer_lock);
   773     }
   774     if (device->fake_stream != NULL) {
   775         SDL_FreeAudioMem(device->fake_stream);
   776     }
   777     if (device->convert.needed) {
   778         SDL_FreeAudioMem(device->convert.buf);
   779     }
   780     if (device->opened) {
   781         current_audio.impl.CloseDevice(device);
   782         device->opened = 0;
   783     }
   784     SDL_FreeAudioMem(device);
   785 }
   786 
   787 
   788 /*
   789  * Sanity check desired AudioSpec for SDL_OpenAudio() in (orig).
   790  *  Fills in a sanitized copy in (prepared).
   791  *  Returns non-zero if okay, zero on fatal parameters in (orig).
   792  */
   793 static int
   794 prepare_audiospec(const SDL_AudioSpec * orig, SDL_AudioSpec * prepared)
   795 {
   796     SDL_memcpy(prepared, orig, sizeof(SDL_AudioSpec));
   797 
   798     if (orig->callback == NULL) {
   799         SDL_SetError("SDL_OpenAudio() passed a NULL callback");
   800         return 0;
   801     }
   802 
   803     if (orig->freq == 0) {
   804         const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY");
   805         if ((!env) || ((prepared->freq = SDL_atoi(env)) == 0)) {
   806             prepared->freq = 22050;     /* a reasonable default */
   807         }
   808     }
   809 
   810     if (orig->format == 0) {
   811         const char *env = SDL_getenv("SDL_AUDIO_FORMAT");
   812         if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) {
   813             prepared->format = AUDIO_S16;       /* a reasonable default */
   814         }
   815     }
   816 
   817     switch (orig->channels) {
   818     case 0:{
   819             const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
   820             if ((!env) || ((prepared->channels = (Uint8) SDL_atoi(env)) == 0)) {
   821                 prepared->channels = 2; /* a reasonable default */
   822             }
   823             break;
   824         }
   825     case 1:                    /* Mono */
   826     case 2:                    /* Stereo */
   827     case 4:                    /* surround */
   828     case 6:                    /* surround with center and lfe */
   829         break;
   830     default:
   831         SDL_SetError("Unsupported number of audio channels.");
   832         return 0;
   833     }
   834 
   835     if (orig->samples == 0) {
   836         const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
   837         if ((!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0)) {
   838             /* Pick a default of ~46 ms at desired frequency */
   839             /* !!! FIXME: remove this when the non-Po2 resampling is in. */
   840             const int samples = (prepared->freq / 1000) * 46;
   841             int power2 = 1;
   842             while (power2 < samples) {
   843                 power2 *= 2;
   844             }
   845             prepared->samples = power2;
   846         }
   847     }
   848 
   849     /* Calculate the silence and size of the audio specification */
   850     SDL_CalculateAudioSpec(prepared);
   851 
   852     return 1;
   853 }
   854 
   855 
   856 static SDL_AudioDeviceID
   857 open_audio_device(const char *devname, int iscapture,
   858                   const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
   859                   int allowed_changes, int min_id)
   860 {
   861     SDL_AudioDeviceID id = 0;
   862     SDL_AudioSpec _obtained;
   863     SDL_AudioDevice *device;
   864     SDL_bool build_cvt;
   865     int i = 0;
   866 
   867     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   868         SDL_SetError("Audio subsystem is not initialized");
   869         return 0;
   870     }
   871 
   872     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   873         SDL_SetError("No capture support");
   874         return 0;
   875     }
   876 
   877     if (!obtained) {
   878         obtained = &_obtained;
   879     }
   880     if (!prepare_audiospec(desired, obtained)) {
   881         return 0;
   882     }
   883 
   884     /* If app doesn't care about a specific device, let the user override. */
   885     if (devname == NULL) {
   886         devname = SDL_getenv("SDL_AUDIO_DEVICE_NAME");
   887     }
   888 
   889     /*
   890      * Catch device names at the high level for the simple case...
   891      * This lets us have a basic "device enumeration" for systems that
   892      *  don't have multiple devices, but makes sure the device name is
   893      *  always NULL when it hits the low level.
   894      *
   895      * Also make sure that the simple case prevents multiple simultaneous
   896      *  opens of the default system device.
   897      */
   898 
   899     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   900         if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
   901             SDL_SetError("No such device");
   902             return 0;
   903         }
   904         devname = NULL;
   905 
   906         for (i = 0; i < SDL_arraysize(open_devices); i++) {
   907             if ((open_devices[i]) && (open_devices[i]->iscapture)) {
   908                 SDL_SetError("Audio device already open");
   909                 return 0;
   910             }
   911         }
   912     }
   913 
   914     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   915         if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
   916             SDL_SetError("No such device");
   917             return 0;
   918         }
   919         devname = NULL;
   920 
   921         for (i = 0; i < SDL_arraysize(open_devices); i++) {
   922             if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
   923                 SDL_SetError("Audio device already open");
   924                 return 0;
   925             }
   926         }
   927     }
   928 
   929     device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice));
   930     if (device == NULL) {
   931         SDL_OutOfMemory();
   932         return 0;
   933     }
   934     SDL_memset(device, '\0', sizeof(SDL_AudioDevice));
   935     device->spec = *obtained;
   936     device->enabled = 1;
   937     device->paused = 1;
   938     device->iscapture = iscapture;
   939 
   940     /* Create a semaphore for locking the sound buffers */
   941     if (!current_audio.impl.SkipMixerLock) {
   942         device->mixer_lock = SDL_CreateMutex();
   943         if (device->mixer_lock == NULL) {
   944             close_audio_device(device);
   945             SDL_SetError("Couldn't create mixer lock");
   946             return 0;
   947         }
   948     }
   949 
   950     /* force a device detection if we haven't done one yet. */
   951     if ( ((iscapture) && (current_audio.inputDevices == NULL)) ||
   952          ((!iscapture) && (current_audio.outputDevices == NULL)) )
   953         SDL_GetNumAudioDevices(iscapture);
   954 
   955     if (!current_audio.impl.OpenDevice(device, devname, iscapture)) {
   956         close_audio_device(device);
   957         return 0;
   958     }
   959     device->opened = 1;
   960 
   961     /* Allocate a fake audio memory buffer */
   962     device->fake_stream = (Uint8 *)SDL_AllocAudioMem(device->spec.size);
   963     if (device->fake_stream == NULL) {
   964         close_audio_device(device);
   965         SDL_OutOfMemory();
   966         return 0;
   967     }
   968 
   969     /* If the audio driver changes the buffer size, accept it */
   970     if (device->spec.samples != obtained->samples) {
   971         obtained->samples = device->spec.samples;
   972         SDL_CalculateAudioSpec(obtained);
   973     }
   974 
   975     /* See if we need to do any conversion */
   976     build_cvt = SDL_FALSE;
   977     if (obtained->freq != device->spec.freq) {
   978         if (allowed_changes & SDL_AUDIO_ALLOW_FREQUENCY_CHANGE) {
   979             obtained->freq = device->spec.freq;
   980         } else {
   981             build_cvt = SDL_TRUE;
   982         }
   983     }
   984     if (obtained->format != device->spec.format) {
   985         if (allowed_changes & SDL_AUDIO_ALLOW_FORMAT_CHANGE) {
   986             obtained->format = device->spec.format;
   987         } else {
   988             build_cvt = SDL_TRUE;
   989         }
   990     }
   991     if (obtained->channels != device->spec.channels) {
   992         if (allowed_changes & SDL_AUDIO_ALLOW_CHANNELS_CHANGE) {
   993             obtained->channels = device->spec.channels;
   994         } else {
   995             build_cvt = SDL_TRUE;
   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) obtained->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 /* !!! FIXME: this is nasty. */
  1041 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
  1042 #undef SDL_CreateThread
  1043         device->thread = SDL_CreateThread(SDL_RunAudio, device, NULL, NULL);
  1044 #else
  1045         device->thread = SDL_CreateThread(SDL_RunAudio, device);
  1046 #endif
  1047         if (device->thread == NULL) {
  1048             SDL_CloseAudioDevice(id + 1);
  1049             SDL_SetError("Couldn't create audio thread");
  1050             return 0;
  1051         }
  1052     }
  1053 
  1054     return id + 1;
  1055 }
  1056 
  1057 
  1058 int
  1059 SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
  1060 {
  1061     SDL_AudioDeviceID id = 0;
  1062 
  1063     /* Start up the audio driver, if necessary. This is legacy behaviour! */
  1064     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
  1065         if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
  1066             return (-1);
  1067         }
  1068     }
  1069 
  1070     /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
  1071     if (open_devices[0] != NULL) {
  1072         SDL_SetError("Audio device is already opened");
  1073         return (-1);
  1074     }
  1075 
  1076     if (obtained) {
  1077         id = open_audio_device(NULL, 0, desired, obtained,
  1078                                SDL_AUDIO_ALLOW_ANY_CHANGE, 1);
  1079     } else {
  1080         id = open_audio_device(NULL, 0, desired, desired, 0, 1);
  1081     }
  1082     if (id > 1) {               /* this should never happen in theory... */
  1083         SDL_CloseAudioDevice(id);
  1084         SDL_SetError("Internal error"); /* MUST be Device ID #1! */
  1085         return (-1);
  1086     }
  1087 
  1088     return ((id == 0) ? -1 : 0);
  1089 }
  1090 
  1091 SDL_AudioDeviceID
  1092 SDL_OpenAudioDevice(const char *device, int iscapture,
  1093                     const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
  1094                     int allowed_changes)
  1095 {
  1096     return open_audio_device(device, iscapture, desired, obtained,
  1097                              allowed_changes, 2);
  1098 }
  1099 
  1100 SDL_AudioStatus
  1101 SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
  1102 {
  1103     SDL_AudioDevice *device = get_audio_device(devid);
  1104     SDL_AudioStatus status = SDL_AUDIO_STOPPED;
  1105     if (device && device->enabled) {
  1106         if (device->paused) {
  1107             status = SDL_AUDIO_PAUSED;
  1108         } else {
  1109             status = SDL_AUDIO_PLAYING;
  1110         }
  1111     }
  1112     return (status);
  1113 }
  1114 
  1115 
  1116 SDL_AudioStatus
  1117 SDL_GetAudioStatus(void)
  1118 {
  1119     return SDL_GetAudioDeviceStatus(1);
  1120 }
  1121 
  1122 void
  1123 SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
  1124 {
  1125     SDL_AudioDevice *device = get_audio_device(devid);
  1126     if (device) {
  1127         device->paused = pause_on;
  1128     }
  1129 }
  1130 
  1131 void
  1132 SDL_PauseAudio(int pause_on)
  1133 {
  1134     SDL_PauseAudioDevice(1, pause_on);
  1135 }
  1136 
  1137 
  1138 void
  1139 SDL_LockAudioDevice(SDL_AudioDeviceID devid)
  1140 {
  1141     /* Obtain a lock on the mixing buffers */
  1142     SDL_AudioDevice *device = get_audio_device(devid);
  1143     if (device) {
  1144         current_audio.impl.LockDevice(device);
  1145     }
  1146 }
  1147 
  1148 void
  1149 SDL_LockAudio(void)
  1150 {
  1151     SDL_LockAudioDevice(1);
  1152 }
  1153 
  1154 void
  1155 SDL_UnlockAudioDevice(SDL_AudioDeviceID devid)
  1156 {
  1157     /* Obtain a lock on the mixing buffers */
  1158     SDL_AudioDevice *device = get_audio_device(devid);
  1159     if (device) {
  1160         current_audio.impl.UnlockDevice(device);
  1161     }
  1162 }
  1163 
  1164 void
  1165 SDL_UnlockAudio(void)
  1166 {
  1167     SDL_UnlockAudioDevice(1);
  1168 }
  1169 
  1170 void
  1171 SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
  1172 {
  1173     SDL_AudioDevice *device = get_audio_device(devid);
  1174     if (device) {
  1175         close_audio_device(device);
  1176         open_devices[devid - 1] = NULL;
  1177     }
  1178 }
  1179 
  1180 void
  1181 SDL_CloseAudio(void)
  1182 {
  1183     SDL_CloseAudioDevice(1);
  1184 }
  1185 
  1186 void
  1187 SDL_AudioQuit(void)
  1188 {
  1189     SDL_AudioDeviceID i;
  1190     for (i = 0; i < SDL_arraysize(open_devices); i++) {
  1191         SDL_CloseAudioDevice(i);
  1192     }
  1193 
  1194     /* Free the driver data */
  1195     current_audio.impl.Deinitialize();
  1196     free_device_list(&current_audio.outputDevices,
  1197                      &current_audio.outputDeviceCount);
  1198     free_device_list(&current_audio.inputDevices,
  1199                      &current_audio.inputDeviceCount);
  1200     SDL_memset(&current_audio, '\0', sizeof(current_audio));
  1201     SDL_memset(open_devices, '\0', sizeof(open_devices));
  1202 }
  1203 
  1204 #define NUM_FORMATS 10
  1205 static int format_idx;
  1206 static int format_idx_sub;
  1207 static SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS] = {
  1208     {AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
  1209      AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
  1210     {AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
  1211      AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
  1212     {AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S32LSB,
  1213      AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
  1214     {AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S32MSB,
  1215      AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
  1216     {AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S32LSB,
  1217      AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
  1218     {AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_S32MSB,
  1219      AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
  1220     {AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S16LSB,
  1221      AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
  1222     {AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S16MSB,
  1223      AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
  1224     {AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_S16LSB,
  1225      AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
  1226     {AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_S16MSB,
  1227      AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
  1228 };
  1229 
  1230 SDL_AudioFormat
  1231 SDL_FirstAudioFormat(SDL_AudioFormat format)
  1232 {
  1233     for (format_idx = 0; format_idx < NUM_FORMATS; ++format_idx) {
  1234         if (format_list[format_idx][0] == format) {
  1235             break;
  1236         }
  1237     }
  1238     format_idx_sub = 0;
  1239     return (SDL_NextAudioFormat());
  1240 }
  1241 
  1242 SDL_AudioFormat
  1243 SDL_NextAudioFormat(void)
  1244 {
  1245     if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) {
  1246         return (0);
  1247     }
  1248     return (format_list[format_idx][format_idx_sub++]);
  1249 }
  1250 
  1251 void
  1252 SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
  1253 {
  1254     switch (spec->format) {
  1255     case AUDIO_U8:
  1256         spec->silence = 0x80;
  1257         break;
  1258     default:
  1259         spec->silence = 0x00;
  1260         break;
  1261     }
  1262     spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
  1263     spec->size *= spec->channels;
  1264     spec->size *= spec->samples;
  1265 }
  1266 
  1267 
  1268 /*
  1269  * Moved here from SDL_mixer.c, since it relies on internals of an opened
  1270  *  audio device (and is deprecated, by the way!).
  1271  */
  1272 void
  1273 SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
  1274 {
  1275     /* Mix the user-level audio format */
  1276     SDL_AudioDevice *device = get_audio_device(1);
  1277     if (device != NULL) {
  1278         SDL_AudioFormat format;
  1279         if (device->convert.needed) {
  1280             format = device->convert.src_format;
  1281         } else {
  1282             format = device->spec.format;
  1283         }
  1284         SDL_MixAudioFormat(dst, src, format, len, volume);
  1285     }
  1286 }
  1287 
  1288 /* vi: set ts=4 sw=4 expandtab: */