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