src/audio/SDL_audio.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 27 Oct 2006 20:19:48 +0000
changeset 2053 716cf90f24a0
parent 2049 5f6550e5184f
child 2060 866052b01ee5
permissions -rw-r--r--
1.3 branch version of revision 2878.

Fixes Bugzilla #298.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* Allow access to a raw mixing buffer */
    25 
    26 #include "SDL.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 DMA_bootstrap;
    49 extern AudioBootStrap ALSA_bootstrap;
    50 extern AudioBootStrap QNXNTOAUDIO_bootstrap;
    51 extern AudioBootStrap SUNAUDIO_bootstrap;
    52 extern AudioBootStrap DMEDIA_bootstrap;
    53 extern AudioBootStrap ARTS_bootstrap;
    54 extern AudioBootStrap ESD_bootstrap;
    55 extern AudioBootStrap NAS_bootstrap;
    56 extern AudioBootStrap DSOUND_bootstrap;
    57 extern AudioBootStrap WAVEOUT_bootstrap;
    58 extern AudioBootStrap PAUDIO_bootstrap;
    59 extern AudioBootStrap BEOSAUDIO_bootstrap;
    60 extern AudioBootStrap COREAUDIO_bootstrap;
    61 extern AudioBootStrap SNDMGR_bootstrap;
    62 extern AudioBootStrap MINTAUDIO_GSXB_bootstrap;
    63 extern AudioBootStrap MINTAUDIO_MCSN_bootstrap;
    64 extern AudioBootStrap MINTAUDIO_STFA_bootstrap;
    65 extern AudioBootStrap MINTAUDIO_XBIOS_bootstrap;
    66 extern AudioBootStrap MINTAUDIO_DMA8_bootstrap;
    67 extern AudioBootStrap DISKAUD_bootstrap;
    68 extern AudioBootStrap DUMMYAUD_bootstrap;
    69 extern AudioBootStrap DCAUD_bootstrap;
    70 extern AudioBootStrap MMEAUDIO_bootstrap;
    71 extern AudioBootStrap DART_bootstrap;
    72 
    73 
    74 /* Available audio drivers */
    75 static AudioBootStrap *bootstrap[] = {
    76 #if SDL_AUDIO_DRIVER_BSD
    77     &BSD_AUDIO_bootstrap,
    78 #endif
    79 #if SDL_AUDIO_DRIVER_OSS
    80     &DSP_bootstrap,
    81     &DMA_bootstrap,
    82 #endif
    83 #if SDL_AUDIO_DRIVER_ALSA
    84     &ALSA_bootstrap,
    85 #endif
    86 #if SDL_AUDIO_DRIVER_QNXNTO
    87     &QNXNTOAUDIO_bootstrap,
    88 #endif
    89 #if SDL_AUDIO_DRIVER_SUNAUDIO
    90     &SUNAUDIO_bootstrap,
    91 #endif
    92 #if SDL_AUDIO_DRIVER_DMEDIA
    93     &DMEDIA_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_DSOUND
   105     &DSOUND_bootstrap,
   106 #endif
   107 #if SDL_AUDIO_DRIVER_WAVEOUT
   108     &WAVEOUT_bootstrap,
   109 #endif
   110 #if SDL_AUDIO_DRIVER_PAUDIO
   111     &PAUDIO_bootstrap,
   112 #endif
   113 #if SDL_AUDIO_DRIVER_BEOSAUDIO
   114     &BEOSAUDIO_bootstrap,
   115 #endif
   116 #if SDL_AUDIO_DRIVER_COREAUDIO
   117     &COREAUDIO_bootstrap,
   118 #endif
   119 #if SDL_AUDIO_DRIVER_SNDMGR
   120     &SNDMGR_bootstrap,
   121 #endif
   122 #if SDL_AUDIO_DRIVER_MINT
   123     &MINTAUDIO_GSXB_bootstrap,
   124     &MINTAUDIO_MCSN_bootstrap,
   125     &MINTAUDIO_STFA_bootstrap,
   126     &MINTAUDIO_XBIOS_bootstrap,
   127     &MINTAUDIO_DMA8_bootstrap,
   128 #endif
   129 #if SDL_AUDIO_DRIVER_DISK
   130     &DISKAUD_bootstrap,
   131 #endif
   132 #if SDL_AUDIO_DRIVER_DUMMY
   133     &DUMMYAUD_bootstrap,
   134 #endif
   135 #if SDL_AUDIO_DRIVER_DC
   136     &DCAUD_bootstrap,
   137 #endif
   138 #if SDL_AUDIO_DRIVER_MMEAUDIO
   139     &MMEAUDIO_bootstrap,
   140 #endif
   141 #if SDL_AUDIO_DRIVER_DART
   142     &DART_bootstrap,
   143 #endif
   144     NULL
   145 };
   146 
   147 static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id)
   148 {
   149     id--;
   150     if ( (id >= SDL_arraysize(open_devices)) || (open_devices[id] == NULL) ) {
   151         SDL_SetError("Invalid audio device ID");
   152         return NULL;
   153     }
   154 
   155     return open_devices[id];
   156 }
   157 
   158 
   159 /* stubs for audio drivers that don't need a specific entry point... */
   160 static int SDL_AudioDetectDevices_Default(int iscapture) { return -1; }
   161 static void SDL_AudioThreadInit_Default(_THIS) { /* no-op. */ }
   162 static void SDL_AudioWaitDevice_Default(_THIS) { /* no-op. */ }
   163 static void SDL_AudioPlayDevice_Default(_THIS) { /* no-op. */ }
   164 static Uint8 *SDL_AudioGetDeviceBuf_Default(_THIS) { return NULL; }
   165 static void SDL_AudioWaitDone_Default(_THIS) { /* no-op. */ }
   166 static void SDL_AudioCloseDevice_Default(_THIS) { /* no-op. */ }
   167 static void SDL_AudioDeinitialize_Default(void) { /* no-op. */ }
   168 
   169 static int
   170 SDL_AudioOpenDevice_Default(_THIS, const char *devname, int iscapture)
   171 {
   172     return 0;
   173 }
   174 
   175 static const char *SDL_AudioGetDeviceName_Default(int index, int iscapture)
   176 {
   177     SDL_SetError("No such device");
   178     return NULL;
   179 }
   180 
   181 static void
   182 SDL_AudioLockDevice_Default(SDL_AudioDevice * device)
   183 {
   184     if (device->thread && (SDL_ThreadID() == device->threadid)) {
   185         return;
   186     }
   187     SDL_mutexP(device->mixer_lock);
   188 }
   189 
   190 static void
   191 SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device)
   192 {
   193     if (device->thread && (SDL_ThreadID() == device->threadid)) {
   194         return;
   195     }
   196     SDL_mutexV(device->mixer_lock);
   197 }
   198 
   199 
   200 static void finalize_audio_entry_points(void)
   201 {
   202     /*
   203      * Fill in stub functions for unused driver entry points. This lets us
   204      *  blindly call them without having to check for validity first.
   205      */
   206 
   207     #define FILL_STUB(x) \
   208         if (current_audio.impl.x == NULL) { \
   209             current_audio.impl.x = SDL_Audio##x##_Default; \
   210         }
   211     FILL_STUB(DetectDevices);
   212     FILL_STUB(GetDeviceName);
   213     FILL_STUB(OpenDevice);
   214     FILL_STUB(ThreadInit);
   215     FILL_STUB(WaitDevice);
   216     FILL_STUB(PlayDevice);
   217     FILL_STUB(GetDeviceBuf);
   218     FILL_STUB(WaitDone);
   219     FILL_STUB(CloseDevice);
   220     FILL_STUB(LockDevice);
   221     FILL_STUB(UnlockDevice);
   222     FILL_STUB(Deinitialize);
   223     #undef FILL_STUB
   224 }
   225 
   226 
   227 /* The general mixing thread function */
   228 int SDLCALL
   229 SDL_RunAudio(void *devicep)
   230 {
   231     SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
   232     const int legacy_device = (device == open_devices[0]);
   233     Uint8 *stream;
   234     int stream_len;
   235     void *udata;
   236     void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
   237     int silence;
   238 
   239     /* Perform any thread setup */
   240     device->threadid = SDL_ThreadID();
   241     current_audio.impl.ThreadInit(device);
   242 
   243     /* Set up the mixing function */
   244     fill = device->spec.callback;
   245     udata = device->spec.userdata;
   246 
   247     if (device->convert.needed) {
   248         if (device->convert.src_format == AUDIO_U8) {
   249             silence = 0x80;
   250         } else {
   251             silence = 0;
   252         }
   253         stream_len = device->convert.len;
   254     } else {
   255         silence = device->spec.silence;
   256         stream_len = device->spec.size;
   257     }
   258 
   259     /* Loop, filling the audio buffers */
   260     while (device->enabled) {
   261 
   262         /* Fill the current buffer with sound */
   263         if (device->convert.needed) {
   264             if (device->convert.buf) {
   265                 stream = device->convert.buf;
   266             } else {
   267                 continue;
   268             }
   269         } else {
   270             stream = current_audio.impl.GetDeviceBuf(device);
   271             if (stream == NULL) {
   272                 stream = device->fake_stream;
   273             }
   274         }
   275 
   276         /* New code should fill buffer or set it to silence themselves. */
   277         if (legacy_device) {
   278             SDL_memset(stream, silence, stream_len);
   279         }
   280 
   281         if (!device->paused) {
   282             SDL_mutexP(device->mixer_lock);
   283             (*fill) (udata, stream, stream_len);
   284             SDL_mutexV(device->mixer_lock);
   285         }
   286 
   287         /* Convert the audio if necessary */
   288         if (device->convert.needed) {
   289             SDL_ConvertAudio(&device->convert);
   290             stream = current_audio.impl.GetDeviceBuf(device);
   291             if (stream == NULL) {
   292                 stream = device->fake_stream;
   293             }
   294             SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt);
   295         }
   296 
   297         /* Ready current buffer for play and change current buffer */
   298         if (stream != device->fake_stream) {
   299             current_audio.impl.PlayDevice(device);
   300         }
   301 
   302         /* Wait for an audio buffer to become available */
   303         if (stream == device->fake_stream) {
   304             SDL_Delay((device->spec.samples * 1000) / device->spec.freq);
   305         } else {
   306             current_audio.impl.WaitDevice(device);
   307         }
   308     }
   309 
   310     /* Wait for the audio to drain.. */
   311     current_audio.impl.WaitDone(device);
   312 
   313     return (0);
   314 }
   315 
   316 
   317 static SDL_AudioFormat
   318 SDL_ParseAudioFormat(const char *string)
   319 {
   320     #define CHECK_FMT_STRING(x) if (strcmp(string, #x) == 0) return AUDIO_##x
   321     CHECK_FMT_STRING(U8);
   322     CHECK_FMT_STRING(S8);
   323     CHECK_FMT_STRING(U16LSB);
   324     CHECK_FMT_STRING(S16LSB);
   325     CHECK_FMT_STRING(U16MSB);
   326     CHECK_FMT_STRING(S16MSB);
   327     CHECK_FMT_STRING(U16SYS);
   328     CHECK_FMT_STRING(S16SYS);
   329     CHECK_FMT_STRING(U16);
   330     CHECK_FMT_STRING(S16);
   331     CHECK_FMT_STRING(S32LSB);
   332     CHECK_FMT_STRING(S32MSB);
   333     CHECK_FMT_STRING(S32SYS);
   334     CHECK_FMT_STRING(S32);
   335     CHECK_FMT_STRING(F32LSB);
   336     CHECK_FMT_STRING(F32MSB);
   337     CHECK_FMT_STRING(F32SYS);
   338     CHECK_FMT_STRING(F32);
   339     #undef CHECK_FMT_STRING
   340     return 0;
   341 }
   342 
   343 int
   344 SDL_GetNumAudioDrivers(void)
   345 {
   346     return (SDL_arraysize(bootstrap) - 1);
   347 }
   348 
   349 const char *
   350 SDL_GetAudioDriver(int index)
   351 {
   352     if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
   353         return (bootstrap[index]->name);
   354     }
   355     return (NULL);
   356 }
   357 
   358 int
   359 SDL_AudioInit(const char *driver_name)
   360 {
   361     int i = 0;
   362     int initialized = 0;
   363     int tried_to_init = 0;
   364 
   365     if (SDL_WasInit(SDL_INIT_AUDIO)) {
   366         SDL_AudioQuit();  /* shutdown driver if already running. */
   367     }
   368 
   369     SDL_memset(&current_audio, '\0', sizeof (current_audio));
   370     SDL_memset(open_devices, '\0', sizeof (open_devices));
   371 
   372     /* Select the proper audio driver */
   373     if (driver_name == NULL) {
   374         driver_name = SDL_getenv("SDL_AUDIODRIVER");
   375     }
   376 
   377     for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
   378         /* make sure we should even try this driver before doing so... */
   379         const AudioBootStrap *backend = bootstrap[i];
   380         if ( ((driver_name) && (SDL_strcasecmp(backend->name, driver_name))) ||
   381              ((!driver_name) && (backend->demand_only)) ) {
   382             continue;
   383         }
   384 
   385         tried_to_init = 1;
   386         SDL_memset(&current_audio, 0, sizeof (current_audio));
   387         current_audio.name = backend->name;
   388         current_audio.desc = backend->desc;
   389         initialized = backend->init(&current_audio.impl);
   390     }
   391 
   392     if (!initialized) {
   393         /* specific drivers will set the error message if they fail... */
   394         if (!tried_to_init) {
   395             if (driver_name) {
   396                 SDL_SetError("%s not available", driver_name);
   397             } else {
   398                 SDL_SetError("No available audio device");
   399             }
   400         }
   401 
   402         SDL_memset(&current_audio, 0, sizeof (current_audio));
   403         return (-1);  /* No driver was available, so fail. */
   404     }
   405 
   406     finalize_audio_entry_points();
   407 
   408     return (0);
   409 }
   410 
   411 /*
   412  * Get the current audio driver name
   413  */
   414 const char *
   415 SDL_GetCurrentAudioDriver()
   416 {
   417     return current_audio.name;
   418 }
   419 
   420 
   421 int
   422 SDL_GetNumAudioDevices(int iscapture)
   423 {
   424     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   425         return -1;
   426     }
   427     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   428         return 0;
   429     }
   430 
   431     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   432         return 1;
   433     }
   434 
   435     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   436         return 1;
   437     }
   438 
   439     return current_audio.impl.DetectDevices(iscapture);
   440 }
   441 
   442 
   443 const char *
   444 SDL_GetAudioDeviceName(int index, int iscapture)
   445 {
   446     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   447         SDL_SetError("Audio subsystem is not initialized");
   448         return NULL;
   449     }
   450 
   451     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   452         SDL_SetError("No capture support");
   453         return NULL;
   454     }
   455 
   456     if (index < 0) {
   457         SDL_SetError("No such device");
   458         return NULL;
   459     }
   460 
   461     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   462         return DEFAULT_INPUT_DEVNAME;
   463     }
   464 
   465     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   466         return DEFAULT_OUTPUT_DEVNAME;
   467     }
   468 
   469     return current_audio.impl.GetDeviceName(index, iscapture);
   470 }
   471 
   472 
   473 static void
   474 close_audio_device(SDL_AudioDevice *device)
   475 {
   476     device->enabled = 0;
   477     if (device->thread != NULL) {
   478         SDL_WaitThread(device->thread, NULL);
   479     }
   480     if (device->mixer_lock != NULL) {
   481         SDL_DestroyMutex(device->mixer_lock);
   482     }
   483     if (device->fake_stream != NULL) {
   484         SDL_FreeAudioMem(device->fake_stream);
   485     }
   486     if (device->convert.needed) {
   487         SDL_FreeAudioMem(device->convert.buf);
   488     }
   489     if (device->opened) {
   490         current_audio.impl.CloseDevice(device);
   491         device->opened = 0;
   492     }
   493     SDL_FreeAudioMem(device);
   494 }
   495 
   496 
   497 /*
   498  * Sanity check desired AudioSpec for SDL_OpenAudio() in (orig).
   499  *  Fills in a sanitized copy in (prepared).
   500  *  Returns non-zero if okay, zero on fatal parameters in (orig).
   501  */
   502 static int
   503 prepare_audiospec(const SDL_AudioSpec *orig, SDL_AudioSpec *prepared)
   504 {
   505     SDL_memcpy(prepared, orig, sizeof (SDL_AudioSpec));
   506 
   507     if (orig->callback == NULL) {
   508         SDL_SetError("SDL_OpenAudio() passed a NULL callback");
   509         return 0;
   510     }
   511 
   512     if (orig->freq == 0) {
   513         const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY");
   514         if ( (!env) || ((prepared->freq = SDL_atoi(env)) == 0) ) {
   515             prepared->freq = 22050;  /* a reasonable default */
   516         }
   517     }
   518 
   519     if (orig->format == 0) {
   520         const char *env = SDL_getenv("SDL_AUDIO_FORMAT");
   521         if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) {
   522             prepared->format = AUDIO_S16;  /* a reasonable default */
   523         }
   524     }
   525 
   526     switch (orig->channels) {
   527     case 0: {
   528         const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
   529         if ( (!env) || ((prepared->channels = SDL_atoi(env)) == 0) ) {
   530             prepared->channels = 2;  /* a reasonable default */
   531         }
   532         break;
   533     }
   534     case 1:                    /* Mono */
   535     case 2:                    /* Stereo */
   536     case 4:                    /* surround */
   537     case 6:                    /* surround with center and lfe */
   538         break;
   539     default:
   540         SDL_SetError("Unsupported number of audio channels.");
   541         return 0;
   542     }
   543 
   544     if (orig->samples == 0) {
   545         const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
   546         if ( (!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0) ) {
   547             /* Pick a default of ~46 ms at desired frequency */
   548             /* !!! FIXME: remove this when the non-Po2 resampling is in. */
   549             const int samples = (prepared->freq / 1000) * 46;
   550             int power2 = 1;
   551             while (power2 < samples) {
   552                 power2 *= 2;
   553             }
   554             prepared->samples = power2;
   555         }
   556     }
   557 
   558     /* Calculate the silence and size of the audio specification */
   559     SDL_CalculateAudioSpec(prepared);
   560 
   561     return 1;
   562 }
   563 
   564 
   565 static SDL_AudioDeviceID
   566 open_audio_device(const char *devname, int iscapture,
   567                     const SDL_AudioSpec *_desired, SDL_AudioSpec *obtained,
   568                     int min_id)
   569 {
   570     SDL_AudioDeviceID id = 0;
   571     SDL_AudioSpec desired;
   572     SDL_AudioDevice *device;
   573     int i = 0;
   574 
   575     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   576         SDL_SetError("Audio subsystem is not initialized");
   577         return 0;
   578     }
   579 
   580     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
   581         SDL_SetError("No capture support");
   582         return 0;
   583     }
   584 
   585     if (!prepare_audiospec(_desired, &desired)) {
   586         return 0;
   587     }
   588 
   589     /* If app doesn't care about a specific device, let the user override. */
   590     if (devname == NULL) {
   591         devname = SDL_getenv("SDL_AUDIO_DEVICE_NAME");
   592     }
   593 
   594     /*
   595      * Catch device names at the high level for the simple case...
   596      * This lets us have a basic "device enumeration" for systems that
   597      *  don't have multiple devices, but makes sure the device name is
   598      *  always NULL when it hits the low level.
   599      *
   600      * Also make sure that the simple case prevents multiple simultaneous
   601      *  opens of the default system device.
   602      */
   603 
   604     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
   605         if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
   606             SDL_SetError("No such device");
   607             return 0;
   608         }
   609         devname = NULL;
   610 
   611         for (i = 0; i < SDL_arraysize(open_devices); i++) {
   612             if ((open_devices[i]) && (open_devices[i]->iscapture)) {
   613                 SDL_SetError("Audio device already open");
   614                 return 0;
   615             }
   616         }
   617     }
   618 
   619     if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
   620         if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
   621             SDL_SetError("No such device");
   622             return 0;
   623         }
   624         devname = NULL;
   625 
   626         for (i = 0; i < SDL_arraysize(open_devices); i++) {
   627             if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
   628                 SDL_SetError("Audio device already open");
   629                 return 0;
   630             }
   631         }
   632     }
   633 
   634     device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof (SDL_AudioDevice));
   635     if (device == NULL) {
   636         SDL_OutOfMemory();
   637         return 0;
   638     }
   639     SDL_memset(device, '\0', sizeof (SDL_AudioDevice));
   640     SDL_memcpy(&device->spec, &desired, sizeof (SDL_AudioSpec));
   641     device->enabled = 1;
   642     device->paused = 1;
   643     device->iscapture = iscapture;
   644 
   645     /* Create a semaphore for locking the sound buffers */
   646     if (!current_audio.impl.SkipMixerLock) {
   647         device->mixer_lock = SDL_CreateMutex();
   648         if (device->mixer_lock == NULL) {
   649             close_audio_device(device);
   650             SDL_SetError("Couldn't create mixer lock");
   651             return 0;
   652         }
   653     }
   654 
   655     if (!current_audio.impl.OpenDevice(device, devname, iscapture)) {
   656         close_audio_device(device);
   657         return 0;
   658     }
   659     device->opened = 1;
   660 
   661     /* If the audio driver changes the buffer size, accept it */
   662     if (device->spec.samples != desired.samples) {
   663         desired.samples = device->spec.samples;
   664         SDL_CalculateAudioSpec(&device->spec);
   665     }
   666 
   667     /* Allocate a fake audio memory buffer */
   668     device->fake_stream = SDL_AllocAudioMem(device->spec.size);
   669     if (device->fake_stream == NULL) {
   670         close_audio_device(device);
   671         SDL_OutOfMemory();
   672         return 0;
   673     }
   674 
   675     /* See if we need to do any conversion */
   676     if (obtained != NULL) {
   677         SDL_memcpy(obtained, &device->spec, sizeof(SDL_AudioSpec));
   678     } else if (desired.freq != device->spec.freq ||
   679                desired.format != device->spec.format ||
   680                desired.channels != device->spec.channels) {
   681         /* Build an audio conversion block */
   682         if (SDL_BuildAudioCVT(&device->convert,
   683                               desired.format, desired.channels,
   684                               desired.freq,
   685                               device->spec.format, device->spec.channels,
   686                               device->spec.freq) < 0) {
   687             close_audio_device(device);
   688             return 0;
   689         }
   690         if (device->convert.needed) {
   691             device->convert.len = (int) ( ((double) desired.size) /
   692                                           device->convert.len_ratio );
   693 
   694             device->convert.buf =
   695                 (Uint8 *) SDL_AllocAudioMem(device->convert.len *
   696                                             device->convert.len_mult);
   697             if (device->convert.buf == NULL) {
   698                 close_audio_device(device);
   699                 SDL_OutOfMemory();
   700                 return 0;
   701             }
   702         }
   703     }
   704 
   705     /* Find an available device ID and store the structure... */
   706     for (id = min_id-1; id < SDL_arraysize(open_devices); id++) {
   707         if (open_devices[id] == NULL) {
   708             open_devices[id] = device;
   709             break;
   710         }
   711     }
   712 
   713     if (id == SDL_arraysize(open_devices)) {
   714         SDL_SetError("Too many open audio devices");
   715         close_audio_device(device);
   716         return 0;
   717     }
   718 
   719     /* Start the audio thread if necessary */
   720     if (!current_audio.impl.ProvidesOwnCallbackThread) {
   721         /* Start the audio thread */
   722 /* !!! FIXME: this is nasty. */
   723 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
   724 #undef SDL_CreateThread
   725         device->thread = SDL_CreateThread(SDL_RunAudio, device, NULL, NULL);
   726 #else
   727         device->thread = SDL_CreateThread(SDL_RunAudio, device);
   728 #endif
   729         if (device->thread == NULL) {
   730             SDL_CloseAudioDevice(id+1);
   731             SDL_SetError("Couldn't create audio thread");
   732             return 0;
   733         }
   734     }
   735 
   736     return id+1;
   737 }
   738 
   739 
   740 int
   741 SDL_OpenAudio(const SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
   742 {
   743     SDL_AudioDeviceID id = 0;
   744 
   745     /* Start up the audio driver, if necessary. This is legacy behaviour! */
   746     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
   747         if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
   748             return (-1);
   749         }
   750     }
   751 
   752     /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
   753     if (open_devices[0] != NULL) {
   754         SDL_SetError("Audio device is already opened");
   755         return (-1);
   756     }
   757 
   758     id = open_audio_device(NULL, 0, desired, obtained, 1);
   759     if (id > 1) {  /* this should never happen in theory... */
   760         SDL_CloseAudioDevice(id);
   761         SDL_SetError("Internal error");  /* MUST be Device ID #1! */
   762         return (-1);
   763     }
   764 
   765     return ((id == 0) ? -1 : 0);
   766 }
   767 
   768 SDL_AudioDeviceID
   769 SDL_OpenAudioDevice(const char *device, int iscapture,
   770                     const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
   771 {
   772     return open_audio_device(device, iscapture, desired, obtained, 2);
   773 }
   774 
   775 SDL_audiostatus
   776 SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
   777 {
   778     SDL_AudioDevice *device = get_audio_device(devid);
   779     SDL_audiostatus status = SDL_AUDIO_STOPPED;
   780     if (device && device->enabled) {
   781         if (device->paused) {
   782             status = SDL_AUDIO_PAUSED;
   783         } else {
   784             status = SDL_AUDIO_PLAYING;
   785         }
   786     }
   787     return (status);
   788 }
   789 
   790 
   791 SDL_audiostatus
   792 SDL_GetAudioStatus(void)
   793 {
   794     return SDL_GetAudioDeviceStatus(1);
   795 }
   796 
   797 void
   798 SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
   799 {
   800     SDL_AudioDevice *device = get_audio_device(devid);
   801     if (device) {
   802         device->paused = pause_on;
   803     }
   804 }
   805 
   806 void
   807 SDL_PauseAudio(int pause_on)
   808 {
   809     SDL_PauseAudioDevice(1, pause_on);
   810 }
   811 
   812 
   813 void
   814 SDL_LockAudioDevice(SDL_AudioDeviceID devid)
   815 {
   816     /* Obtain a lock on the mixing buffers */
   817     SDL_AudioDevice *device = get_audio_device(devid);
   818     if (device) {
   819         current_audio.impl.LockDevice(device);
   820     }
   821 }
   822 
   823 void
   824 SDL_LockAudio(void)
   825 {
   826     SDL_LockAudioDevice(1);
   827 }
   828 
   829 void
   830 SDL_UnlockAudioDevice(SDL_AudioDeviceID devid)
   831 {
   832     /* Obtain a lock on the mixing buffers */
   833     SDL_AudioDevice *device = get_audio_device(devid);
   834     if (device) {
   835         current_audio.impl.UnlockDevice(device);
   836     }
   837 }
   838 
   839 void
   840 SDL_UnlockAudio(void)
   841 {
   842     SDL_UnlockAudioDevice(1);
   843 }
   844 
   845 void
   846 SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
   847 {
   848     SDL_AudioDevice *device = get_audio_device(devid);
   849     if (device) {
   850         close_audio_device(device);
   851         open_devices[devid-1] = NULL;
   852     }
   853 }
   854 
   855 void
   856 SDL_CloseAudio(void)
   857 {
   858     SDL_CloseAudioDevice(1);
   859 }
   860 
   861 void
   862 SDL_AudioQuit(void)
   863 {
   864     SDL_AudioDeviceID i;
   865     for (i = 0; i < SDL_arraysize(open_devices); i++) {
   866         SDL_CloseAudioDevice(i);
   867     }
   868 
   869     /* Free the driver data */
   870     current_audio.impl.Deinitialize();
   871     SDL_memset(&current_audio, '\0', sizeof (current_audio));
   872     SDL_memset(open_devices, '\0', sizeof (open_devices));
   873 }
   874 
   875 #define NUM_FORMATS 10
   876 static int format_idx;
   877 static int format_idx_sub;
   878 static SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS] = {
   879     {AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
   880      AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
   881     {AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
   882      AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
   883     {AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S32LSB,
   884      AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
   885     {AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S32MSB,
   886      AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
   887     {AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S32LSB,
   888      AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
   889     {AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_S32MSB,
   890      AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
   891     {AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S16LSB,
   892      AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
   893     {AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S16MSB,
   894      AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
   895     {AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_S16LSB,
   896      AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
   897     {AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_S16MSB,
   898      AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
   899 };
   900 
   901 SDL_AudioFormat
   902 SDL_FirstAudioFormat(SDL_AudioFormat format)
   903 {
   904     for (format_idx = 0; format_idx < NUM_FORMATS; ++format_idx) {
   905         if (format_list[format_idx][0] == format) {
   906             break;
   907         }
   908     }
   909     format_idx_sub = 0;
   910     return (SDL_NextAudioFormat());
   911 }
   912 
   913 SDL_AudioFormat
   914 SDL_NextAudioFormat(void)
   915 {
   916     if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) {
   917         return (0);
   918     }
   919     return (format_list[format_idx][format_idx_sub++]);
   920 }
   921 
   922 void
   923 SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
   924 {
   925     switch (spec->format) {
   926     case AUDIO_U8:
   927         spec->silence = 0x80;
   928         break;
   929     default:
   930         spec->silence = 0x00;
   931         break;
   932     }
   933     spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
   934     spec->size *= spec->channels;
   935     spec->size *= spec->samples;
   936 }
   937 
   938 
   939 /*
   940  * Moved here from SDL_mixer.c, since it relies on internals of an opened
   941  *  audio device (and is deprecated, by the way!).
   942  */
   943 void
   944 SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
   945 {
   946     /* Mix the user-level audio format */
   947     SDL_AudioDevice *device = get_audio_device(1);
   948     if (device != NULL) {
   949         SDL_AudioFormat format;
   950         if (device->convert.needed) {
   951             format = device->convert.src_format;
   952         } else {
   953             format = device->spec.format;
   954         }
   955         SDL_MixAudioFormat(dst, src, format, len, volume);
   956     }
   957 }
   958 
   959 /* vi: set ts=4 sw=4 expandtab: */