src/audio/SDL_audio.c
author Sam Lantinga
Sun, 03 Nov 2013 11:13:06 -0800
changeset 7904 915b9b6c9fa0
parent 7719 31b5f9ff36ca
child 7981 6d538bc1b395
permissions -rw-r--r--
Fixed bug 2205 - SDL_GetAudioDeviceName returns default-device name on invalid index for default-device only drivers

norfanin

The audio_enumerateAndNameAudioDevicesNegativeTests test in testautomation_audio.c reports a failure for SDL_GetAudioDeviceName when called on a driver that has only the default device. SDL_GetNumAudioDevices reports 1, but SDL_GetAudioDeviceName does not check if the index passed by the caller is in that range in this case. For positive numbers anyway.

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