src/audio/SDL_audio.c
author Ryan C. Gordon
Wed, 30 Jul 2014 11:08:31 -0400
changeset 9031 e963a13a720c
parent 9012 aa058c87737b
child 9032 36c472422d64
permissions -rw-r--r--
Added a GetPendingBytes method to the audio backend.

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