cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_audio.c (46242B)


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