src/audio/SDL_audio.c
author Ryan C. Gordon
Thu, 11 Jul 2013 23:59:09 -0400
changeset 7407 db8a19d767d7
parent 7406 fb02213c11d3
child 7446 6cbb6aaedc20
permissions -rw-r--r--
Whoops, missed a part of that last commit.

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