src/audio/SDL_audio.c
author Ryan C. Gordon
Sat, 15 Sep 2012 10:59:39 -0400
changeset 6430 48d519500f7e
parent 6389 43a190ad60a7
child 6885 700f1b25f77f
permissions -rwxr-xr-x
Removed Windows CE support from SDL 2.0.

It's a long-dead platform, and we don't have any way to build for, test, or
maintain it, so there's no sense in doing acrobatics to support it.

If you need Windows CE support, use SDL 1.2. If you need Windows Phone support,
send SDL 2.0 patches for the newer Windows Mobile platform.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 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;
icculus@2049
    69
icculus@1190
    70
slouken@0
    71
/* Available audio drivers */
slouken@3162
    72
static const AudioBootStrap *const bootstrap[] = {
icculus@2939
    73
#if SDL_AUDIO_DRIVER_PULSEAUDIO
icculus@2939
    74
    &PULSEAUDIO_bootstrap,
slouken@0
    75
#endif
slouken@1361
    76
#if SDL_AUDIO_DRIVER_ALSA
slouken@1895
    77
    &ALSA_bootstrap,
slouken@0
    78
#endif
slouken@4548
    79
#if SDL_AUDIO_DRIVER_BSD
slouken@4548
    80
    &BSD_AUDIO_bootstrap,
slouken@4548
    81
#endif
icculus@2939
    82
#if SDL_AUDIO_DRIVER_OSS
icculus@2939
    83
    &DSP_bootstrap,
icculus@2271
    84
#endif
slouken@3099
    85
#if SDL_AUDIO_DRIVER_QSA
slouken@3099
    86
    &QSAAUDIO_bootstrap,
slouken@663
    87
#endif
slouken@1361
    88
#if SDL_AUDIO_DRIVER_SUNAUDIO
slouken@1895
    89
    &SUNAUDIO_bootstrap,
slouken@148
    90
#endif
slouken@1361
    91
#if SDL_AUDIO_DRIVER_ARTS
slouken@1895
    92
    &ARTS_bootstrap,
slouken@0
    93
#endif
slouken@1361
    94
#if SDL_AUDIO_DRIVER_ESD
slouken@1895
    95
    &ESD_bootstrap,
slouken@0
    96
#endif
slouken@1361
    97
#if SDL_AUDIO_DRIVER_NAS
slouken@1895
    98
    &NAS_bootstrap,
slouken@0
    99
#endif
icculus@5592
   100
#if SDL_AUDIO_DRIVER_XAUDIO2
icculus@5592
   101
    &XAUDIO2_bootstrap,
icculus@5592
   102
#endif
slouken@1361
   103
#if SDL_AUDIO_DRIVER_DSOUND
slouken@1895
   104
    &DSOUND_bootstrap,
slouken@0
   105
#endif
icculus@5588
   106
#if SDL_AUDIO_DRIVER_WINMM
icculus@5588
   107
    &WINMM_bootstrap,
slouken@0
   108
#endif
icculus@2049
   109
#if SDL_AUDIO_DRIVER_PAUDIO
icculus@2049
   110
    &PAUDIO_bootstrap,
slouken@1361
   111
#endif
icculus@2049
   112
#if SDL_AUDIO_DRIVER_BEOSAUDIO
icculus@2049
   113
    &BEOSAUDIO_bootstrap,
slouken@0
   114
#endif
slouken@1361
   115
#if SDL_AUDIO_DRIVER_COREAUDIO
slouken@1895
   116
    &COREAUDIO_bootstrap,
slouken@935
   117
#endif
slouken@1361
   118
#if SDL_AUDIO_DRIVER_DISK
slouken@1895
   119
    &DISKAUD_bootstrap,
slouken@68
   120
#endif
icculus@1532
   121
#if SDL_AUDIO_DRIVER_DUMMY
slouken@1895
   122
    &DUMMYAUD_bootstrap,
icculus@1532
   123
#endif
slouken@2735
   124
#if SDL_AUDIO_DRIVER_NDS
slouken@2735
   125
    &NDSAUD_bootstrap,
slouken@2735
   126
#endif
slouken@2947
   127
#if SDL_AUDIO_DRIVER_FUSIONSOUND
slouken@2947
   128
    &FUSIONSOUND_bootstrap,
slouken@2947
   129
#endif
paul@4718
   130
#if SDL_AUDIO_DRIVER_ANDROID
paul@4718
   131
    &ANDROIDAUD_bootstrap,
paul@4718
   132
#endif
slouken@1895
   133
    NULL
slouken@0
   134
};
icculus@2049
   135
slouken@2060
   136
static SDL_AudioDevice *
slouken@2060
   137
get_audio_device(SDL_AudioDeviceID id)
icculus@2049
   138
{
icculus@2049
   139
    id--;
slouken@2060
   140
    if ((id >= SDL_arraysize(open_devices)) || (open_devices[id] == NULL)) {
icculus@2049
   141
        SDL_SetError("Invalid audio device ID");
icculus@2049
   142
        return NULL;
icculus@2049
   143
    }
icculus@2049
   144
icculus@2049
   145
    return open_devices[id];
icculus@2049
   146
}
icculus@2049
   147
icculus@2049
   148
icculus@2049
   149
/* stubs for audio drivers that don't need a specific entry point... */
icculus@5593
   150
static void
icculus@5593
   151
SDL_AudioDetectDevices_Default(int iscapture, SDL_AddAudioDevice addfn)
icculus@5593
   152
{                               /* no-op. */
slouken@2060
   153
}
slouken@2735
   154
slouken@2060
   155
static void
slouken@2060
   156
SDL_AudioThreadInit_Default(_THIS)
slouken@2060
   157
{                               /* no-op. */
slouken@2060
   158
}
slouken@2735
   159
slouken@2060
   160
static void
slouken@2060
   161
SDL_AudioWaitDevice_Default(_THIS)
slouken@2060
   162
{                               /* no-op. */
slouken@2060
   163
}
slouken@2735
   164
slouken@2060
   165
static void
slouken@2060
   166
SDL_AudioPlayDevice_Default(_THIS)
slouken@2060
   167
{                               /* no-op. */
slouken@2060
   168
}
slouken@2735
   169
slouken@2060
   170
static Uint8 *
slouken@2060
   171
SDL_AudioGetDeviceBuf_Default(_THIS)
slouken@2060
   172
{
slouken@2060
   173
    return NULL;
slouken@2060
   174
}
slouken@2735
   175
slouken@2060
   176
static void
slouken@2060
   177
SDL_AudioWaitDone_Default(_THIS)
slouken@2060
   178
{                               /* no-op. */
slouken@2060
   179
}
slouken@2735
   180
slouken@2060
   181
static void
slouken@2060
   182
SDL_AudioCloseDevice_Default(_THIS)
slouken@2060
   183
{                               /* no-op. */
slouken@2060
   184
}
slouken@2735
   185
slouken@2060
   186
static void
slouken@2060
   187
SDL_AudioDeinitialize_Default(void)
slouken@2060
   188
{                               /* no-op. */
slouken@2060
   189
}
icculus@2049
   190
icculus@2049
   191
static int
icculus@2049
   192
SDL_AudioOpenDevice_Default(_THIS, const char *devname, int iscapture)
icculus@2049
   193
{
icculus@2049
   194
    return 0;
icculus@2049
   195
}
icculus@2049
   196
icculus@2049
   197
static void
icculus@2049
   198
SDL_AudioLockDevice_Default(SDL_AudioDevice * device)
icculus@2049
   199
{
icculus@2049
   200
    if (device->thread && (SDL_ThreadID() == device->threadid)) {
icculus@2049
   201
        return;
icculus@2049
   202
    }
icculus@2049
   203
    SDL_mutexP(device->mixer_lock);
icculus@2049
   204
}
icculus@2049
   205
icculus@2049
   206
static void
icculus@2049
   207
SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device)
icculus@2049
   208
{
icculus@2049
   209
    if (device->thread && (SDL_ThreadID() == device->threadid)) {
icculus@2049
   210
        return;
icculus@2049
   211
    }
icculus@2049
   212
    SDL_mutexV(device->mixer_lock);
icculus@2049
   213
}
icculus@2049
   214
slouken@0
   215
slouken@2060
   216
static void
slouken@2060
   217
finalize_audio_entry_points(void)
icculus@2049
   218
{
icculus@2049
   219
    /*
icculus@2049
   220
     * Fill in stub functions for unused driver entry points. This lets us
icculus@2049
   221
     *  blindly call them without having to check for validity first.
icculus@2049
   222
     */
icculus@2049
   223
slouken@2060
   224
#define FILL_STUB(x) \
icculus@2049
   225
        if (current_audio.impl.x == NULL) { \
icculus@2049
   226
            current_audio.impl.x = SDL_Audio##x##_Default; \
icculus@2049
   227
        }
icculus@2049
   228
    FILL_STUB(DetectDevices);
icculus@2049
   229
    FILL_STUB(OpenDevice);
icculus@2049
   230
    FILL_STUB(ThreadInit);
icculus@2049
   231
    FILL_STUB(WaitDevice);
icculus@2049
   232
    FILL_STUB(PlayDevice);
icculus@2049
   233
    FILL_STUB(GetDeviceBuf);
icculus@2049
   234
    FILL_STUB(WaitDone);
icculus@2049
   235
    FILL_STUB(CloseDevice);
icculus@2049
   236
    FILL_STUB(LockDevice);
icculus@2049
   237
    FILL_STUB(UnlockDevice);
icculus@2049
   238
    FILL_STUB(Deinitialize);
slouken@2060
   239
#undef FILL_STUB
icculus@2049
   240
}
icculus@2049
   241
slouken@2716
   242
/* Streaming functions (for when the input and output buffer sizes are different) */
slouken@2716
   243
/* Write [length] bytes from buf into the streamer */
slouken@4472
   244
static void
slouken@2716
   245
SDL_StreamWrite(SDL_AudioStreamer * stream, Uint8 * buf, int length)
slouken@2716
   246
{
slouken@2716
   247
    int i;
slouken@2716
   248
slouken@2716
   249
    for (i = 0; i < length; ++i) {
slouken@2716
   250
        stream->buffer[stream->write_pos] = buf[i];
slouken@2716
   251
        ++stream->write_pos;
slouken@2716
   252
    }
slouken@2716
   253
}
slouken@2716
   254
slouken@2716
   255
/* Read [length] bytes out of the streamer into buf */
slouken@4472
   256
static void
slouken@2716
   257
SDL_StreamRead(SDL_AudioStreamer * stream, Uint8 * buf, int length)
slouken@2716
   258
{
slouken@2716
   259
    int i;
slouken@2716
   260
slouken@2716
   261
    for (i = 0; i < length; ++i) {
slouken@2716
   262
        buf[i] = stream->buffer[stream->read_pos];
slouken@2716
   263
        ++stream->read_pos;
slouken@2716
   264
    }
slouken@2716
   265
}
slouken@2716
   266
slouken@4472
   267
static int
slouken@2716
   268
SDL_StreamLength(SDL_AudioStreamer * stream)
slouken@2716
   269
{
slouken@2716
   270
    return (stream->write_pos - stream->read_pos) % stream->max_len;
slouken@2716
   271
}
slouken@2716
   272
slouken@2716
   273
/* Initialize the stream by allocating the buffer and setting the read/write heads to the beginning */
slouken@4507
   274
#if 0
slouken@4472
   275
static int
slouken@2716
   276
SDL_StreamInit(SDL_AudioStreamer * stream, int max_len, Uint8 silence)
slouken@2716
   277
{
slouken@2716
   278
    /* First try to allocate the buffer */
slouken@2728
   279
    stream->buffer = (Uint8 *) SDL_malloc(max_len);
slouken@2716
   280
    if (stream->buffer == NULL) {
slouken@2716
   281
        return -1;
slouken@2716
   282
    }
slouken@2716
   283
slouken@2716
   284
    stream->max_len = max_len;
slouken@2716
   285
    stream->read_pos = 0;
slouken@2716
   286
    stream->write_pos = 0;
slouken@2716
   287
slouken@2716
   288
    /* Zero out the buffer */
slouken@2728
   289
    SDL_memset(stream->buffer, silence, max_len);
slouken@2728
   290
slouken@2728
   291
    return 0;
slouken@2716
   292
}
slouken@4507
   293
#endif
slouken@2716
   294
slouken@2716
   295
/* Deinitialize the stream simply by freeing the buffer */
slouken@4472
   296
static void
slouken@2716
   297
SDL_StreamDeinit(SDL_AudioStreamer * stream)
slouken@2716
   298
{
slouken@2716
   299
    if (stream->buffer != NULL) {
slouken@2728
   300
        SDL_free(stream->buffer);
slouken@2716
   301
    }
slouken@2716
   302
}
slouken@2716
   303
aschiffler@4865
   304
#if defined(ANDROID)
paul@4722
   305
#include <android/log.h>
aschiffler@4865
   306
#endif
paul@4722
   307
slouken@0
   308
/* The general mixing thread function */
slouken@1895
   309
int SDLCALL
icculus@2049
   310
SDL_RunAudio(void *devicep)
slouken@0
   311
{
icculus@2049
   312
    SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
slouken@1895
   313
    Uint8 *stream;
slouken@1895
   314
    int stream_len;
slouken@1895
   315
    void *udata;
slouken@1895
   316
    void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
slouken@3336
   317
    Uint32 delay;
airlangga@5526
   318
    /* For streaming when the buffer sizes don't match up */
airlangga@5526
   319
    Uint8 *istream;
airlangga@5526
   320
    int istream_len = 0;
slouken@2716
   321
slouken@5509
   322
    /* The audio mixing is always a high priority thread */
slouken@5509
   323
    SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
slouken@5509
   324
slouken@1895
   325
    /* Perform any thread setup */
icculus@2049
   326
    device->threadid = SDL_ThreadID();
icculus@2049
   327
    current_audio.impl.ThreadInit(device);
slouken@0
   328
slouken@1895
   329
    /* Set up the mixing function */
icculus@2049
   330
    fill = device->spec.callback;
icculus@2049
   331
    udata = device->spec.userdata;
slouken@21
   332
slouken@2716
   333
    /* By default do not stream */
slouken@2716
   334
    device->use_streamer = 0;
slouken@2716
   335
icculus@2049
   336
    if (device->convert.needed) {
slouken@3040
   337
#if 0                           /* !!! FIXME: I took len_div out of the structure. Use rate_incr instead? */
slouken@2716
   338
        /* If the result of the conversion alters the length, i.e. resampling is being used, use the streamer */
slouken@2716
   339
        if (device->convert.len_mult != 1 || device->convert.len_div != 1) {
slouken@2716
   340
            /* The streamer's maximum length should be twice whichever is larger: spec.size or len_cvt */
slouken@2716
   341
            stream_max_len = 2 * device->spec.size;
slouken@2716
   342
            if (device->convert.len_mult > device->convert.len_div) {
slouken@2716
   343
                stream_max_len *= device->convert.len_mult;
slouken@2716
   344
                stream_max_len /= device->convert.len_div;
slouken@2716
   345
            }
slouken@2716
   346
            if (SDL_StreamInit(&device->streamer, stream_max_len, silence) <
slouken@2716
   347
                0)
slouken@2716
   348
                return -1;
slouken@2716
   349
            device->use_streamer = 1;
slouken@2716
   350
slouken@2716
   351
            /* istream_len should be the length of what we grab from the callback and feed to conversion,
slouken@2716
   352
               so that we get close to spec_size. I.e. we want device.spec_size = istream_len * u / d
slouken@2716
   353
             */
slouken@2716
   354
            istream_len =
slouken@2716
   355
                device->spec.size * device->convert.len_div /
slouken@2716
   356
                device->convert.len_mult;
slouken@2716
   357
        }
icculus@3021
   358
#endif
slouken@2716
   359
slouken@2716
   360
        /* stream_len = device->convert.len; */
slouken@2716
   361
        stream_len = device->spec.size;
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@3336
   410
                SDL_mutexP(device->mixer_lock);
slouken@3336
   411
                (*fill) (udata, istream, istream_len);
slouken@3336
   412
                SDL_mutexV(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
                    }
slouken@2716
   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. */
slouken@0
   460
slouken@2716
   461
        /* Loop, filling the audio buffers */
slouken@2716
   462
        while (device->enabled) {
slouken@2716
   463
slouken@3336
   464
            if (device->paused) {
slouken@3336
   465
                SDL_Delay(delay);
slouken@3336
   466
                continue;
slouken@3336
   467
            }
slouken@3336
   468
slouken@2716
   469
            /* Fill the current buffer with sound */
slouken@2716
   470
            if (device->convert.needed) {
slouken@2716
   471
                if (device->convert.buf) {
slouken@2716
   472
                    stream = device->convert.buf;
slouken@2716
   473
                } else {
slouken@2716
   474
                    continue;
slouken@2716
   475
                }
slouken@2716
   476
            } else {
slouken@2716
   477
                stream = current_audio.impl.GetDeviceBuf(device);
slouken@2716
   478
                if (stream == NULL) {
slouken@2716
   479
                    stream = device->fake_stream;
slouken@2716
   480
                }
slouken@1895
   481
            }
slouken@0
   482
slouken@3336
   483
            SDL_mutexP(device->mixer_lock);
slouken@3336
   484
            (*fill) (udata, stream, stream_len);
slouken@3336
   485
            SDL_mutexV(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@2060
   583
        if (((driver_name) && (SDL_strcasecmp(backend->name, driver_name))) ||
slouken@2060
   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
icculus@5593
   633
    if (*devices != NULL) {
icculus@5593
   634
        SDL_free(*devices);
icculus@5593
   635
    }
icculus@5593
   636
icculus@5593
   637
    *devices = NULL;
icculus@5593
   638
    *devCount = 0;
icculus@5593
   639
}
icculus@5593
   640
icculus@5593
   641
static
icculus@5593
   642
void SDL_AddCaptureAudioDevice(const char *_name)
icculus@5593
   643
{
icculus@5593
   644
    char *name = NULL;
icculus@5593
   645
    void *ptr = SDL_realloc(current_audio.inputDevices,
icculus@5593
   646
                          (current_audio.inputDeviceCount+1) * sizeof(char*));
icculus@5593
   647
    if (ptr == NULL) {
icculus@5593
   648
        return;  /* oh well. */
icculus@5593
   649
    }
icculus@5593
   650
icculus@5593
   651
    current_audio.inputDevices = (char **) ptr;
icculus@5593
   652
    name = SDL_strdup(_name);  /* if this returns NULL, that's okay. */
icculus@5593
   653
    current_audio.inputDevices[current_audio.inputDeviceCount++] = name;
icculus@5593
   654
}
icculus@5593
   655
icculus@5593
   656
static
icculus@5593
   657
void SDL_AddOutputAudioDevice(const char *_name)
icculus@5593
   658
{
icculus@5593
   659
    char *name = NULL;
icculus@5593
   660
    void *ptr = SDL_realloc(current_audio.outputDevices,
icculus@5593
   661
                          (current_audio.outputDeviceCount+1) * sizeof(char*));
icculus@5593
   662
    if (ptr == NULL) {
icculus@5593
   663
        return;  /* oh well. */
icculus@5593
   664
    }
icculus@5593
   665
icculus@5593
   666
    current_audio.outputDevices = (char **) ptr;
icculus@5593
   667
    name = SDL_strdup(_name);  /* if this returns NULL, that's okay. */
icculus@5593
   668
    current_audio.outputDevices[current_audio.outputDeviceCount++] = name;
icculus@5593
   669
}
icculus@5593
   670
icculus@2049
   671
slouken@1895
   672
int
icculus@2049
   673
SDL_GetNumAudioDevices(int iscapture)
slouken@0
   674
{
icculus@5593
   675
    int retval = 0;
icculus@5593
   676
icculus@2049
   677
    if (!SDL_WasInit(SDL_INIT_AUDIO)) {
icculus@2049
   678
        return -1;
icculus@2049
   679
    }
icculus@5593
   680
icculus@2049
   681
    if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
icculus@2049
   682
        return 0;
icculus@2049
   683
    }
icculus@2049
   684
icculus@2049
   685
    if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
icculus@2049
   686
        return 1;
icculus@2049
   687
    }
icculus@2049
   688
icculus@2049
   689
    if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
icculus@2049
   690
        return 1;
icculus@2049
   691
    }
icculus@2049
   692
icculus@5593
   693
    if (iscapture) {
icculus@5593
   694
        free_device_list(&current_audio.inputDevices,
icculus@5593
   695
                         &current_audio.inputDeviceCount);
icculus@5593
   696
        current_audio.impl.DetectDevices(iscapture, SDL_AddCaptureAudioDevice);
icculus@5593
   697
        retval = current_audio.inputDeviceCount;
icculus@5593
   698
    } else {
icculus@5593
   699
        free_device_list(&current_audio.outputDevices,
icculus@5593
   700
                         &current_audio.outputDeviceCount);
icculus@5593
   701
        current_audio.impl.DetectDevices(iscapture, SDL_AddOutputAudioDevice);
icculus@5593
   702
        retval = current_audio.outputDeviceCount;
icculus@5593
   703
    }
icculus@5593
   704
icculus@5593
   705
    return retval;
icculus@2049
   706
}
icculus@2049
   707
slouken@0
   708
icculus@2049
   709
const char *
icculus@2049
   710
SDL_GetAudioDeviceName(int index, int iscapture)
icculus@2049
   711
{
icculus@2049
   712
    if (!SDL_WasInit(SDL_INIT_AUDIO)) {
icculus@2049
   713
        SDL_SetError("Audio subsystem is not initialized");
icculus@2049
   714
        return NULL;
icculus@2049
   715
    }
icculus@2049
   716
icculus@2049
   717
    if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
icculus@2049
   718
        SDL_SetError("No capture support");
icculus@2049
   719
        return NULL;
slouken@1895
   720
    }
icculus@2049
   721
icculus@2049
   722
    if (index < 0) {
icculus@5593
   723
        goto no_such_device;
icculus@2049
   724
    }
slouken@0
   725
icculus@2049
   726
    if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
icculus@2049
   727
        return DEFAULT_INPUT_DEVNAME;
icculus@2049
   728
    }
icculus@2049
   729
icculus@2049
   730
    if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
icculus@2049
   731
        return DEFAULT_OUTPUT_DEVNAME;
slouken@1895
   732
    }
slouken@262
   733
icculus@5593
   734
    if (iscapture) {
icculus@5593
   735
        if (index >= current_audio.inputDeviceCount) {
icculus@5593
   736
            goto no_such_device;
icculus@5593
   737
        }
icculus@5593
   738
        return current_audio.inputDevices[index];
icculus@5593
   739
    } else {
icculus@5593
   740
        if (index >= current_audio.outputDeviceCount) {
icculus@5593
   741
            goto no_such_device;
icculus@5593
   742
        }
icculus@5593
   743
        return current_audio.outputDevices[index];
icculus@5593
   744
    }
icculus@5593
   745
icculus@5593
   746
no_such_device:
icculus@5593
   747
    SDL_SetError("No such device");
icculus@5593
   748
    return NULL;
icculus@2049
   749
}
icculus@2049
   750
icculus@2049
   751
icculus@2049
   752
static void
slouken@2060
   753
close_audio_device(SDL_AudioDevice * device)
icculus@2049
   754
{
icculus@2049
   755
    device->enabled = 0;
icculus@2049
   756
    if (device->thread != NULL) {
icculus@2049
   757
        SDL_WaitThread(device->thread, NULL);
icculus@2049
   758
    }
icculus@2049
   759
    if (device->mixer_lock != NULL) {
icculus@2049
   760
        SDL_DestroyMutex(device->mixer_lock);
icculus@2049
   761
    }
icculus@2049
   762
    if (device->fake_stream != NULL) {
icculus@2049
   763
        SDL_FreeAudioMem(device->fake_stream);
icculus@2049
   764
    }
icculus@2049
   765
    if (device->convert.needed) {
icculus@2049
   766
        SDL_FreeAudioMem(device->convert.buf);
icculus@2049
   767
    }
icculus@2049
   768
    if (device->opened) {
icculus@2049
   769
        current_audio.impl.CloseDevice(device);
icculus@2049
   770
        device->opened = 0;
icculus@2049
   771
    }
icculus@2049
   772
    SDL_FreeAudioMem(device);
icculus@2049
   773
}
icculus@2049
   774
icculus@2049
   775
icculus@2049
   776
/*
icculus@2049
   777
 * Sanity check desired AudioSpec for SDL_OpenAudio() in (orig).
icculus@2049
   778
 *  Fills in a sanitized copy in (prepared).
icculus@2049
   779
 *  Returns non-zero if okay, zero on fatal parameters in (orig).
icculus@2049
   780
 */
icculus@2049
   781
static int
slouken@2060
   782
prepare_audiospec(const SDL_AudioSpec * orig, SDL_AudioSpec * prepared)
icculus@2049
   783
{
slouken@2060
   784
    SDL_memcpy(prepared, orig, sizeof(SDL_AudioSpec));
icculus@2049
   785
icculus@2049
   786
    if (orig->callback == NULL) {
icculus@2049
   787
        SDL_SetError("SDL_OpenAudio() passed a NULL callback");
icculus@2049
   788
        return 0;
icculus@2049
   789
    }
icculus@2049
   790
icculus@2049
   791
    if (orig->freq == 0) {
icculus@2049
   792
        const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY");
slouken@2060
   793
        if ((!env) || ((prepared->freq = SDL_atoi(env)) == 0)) {
slouken@2060
   794
            prepared->freq = 22050;     /* a reasonable default */
slouken@1895
   795
        }
slouken@1895
   796
    }
icculus@2049
   797
icculus@2049
   798
    if (orig->format == 0) {
icculus@2049
   799
        const char *env = SDL_getenv("SDL_AUDIO_FORMAT");
icculus@2049
   800
        if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) {
slouken@2060
   801
            prepared->format = AUDIO_S16;       /* a reasonable default */
slouken@1895
   802
        }
slouken@1895
   803
    }
icculus@2049
   804
icculus@2049
   805
    switch (orig->channels) {
slouken@2060
   806
    case 0:{
slouken@2060
   807
            const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
slouken@2141
   808
            if ((!env) || ((prepared->channels = (Uint8) SDL_atoi(env)) == 0)) {
slouken@2060
   809
                prepared->channels = 2; /* a reasonable default */
slouken@2060
   810
            }
slouken@2060
   811
            break;
icculus@2049
   812
        }
slouken@1895
   813
    case 1:                    /* Mono */
slouken@1895
   814
    case 2:                    /* Stereo */
slouken@1895
   815
    case 4:                    /* surround */
slouken@1895
   816
    case 6:                    /* surround with center and lfe */
slouken@1895
   817
        break;
slouken@1895
   818
    default:
icculus@2049
   819
        SDL_SetError("Unsupported number of audio channels.");
icculus@2049
   820
        return 0;
slouken@1895
   821
    }
icculus@2049
   822
icculus@2049
   823
    if (orig->samples == 0) {
icculus@2049
   824
        const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
slouken@2060
   825
        if ((!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0)) {
icculus@2049
   826
            /* Pick a default of ~46 ms at desired frequency */
icculus@2049
   827
            /* !!! FIXME: remove this when the non-Po2 resampling is in. */
icculus@2049
   828
            const int samples = (prepared->freq / 1000) * 46;
icculus@2049
   829
            int power2 = 1;
icculus@2049
   830
            while (power2 < samples) {
icculus@2049
   831
                power2 *= 2;
icculus@2049
   832
            }
icculus@2049
   833
            prepared->samples = power2;
slouken@1895
   834
        }
slouken@1895
   835
    }
slouken@0
   836
slouken@1895
   837
    /* Calculate the silence and size of the audio specification */
icculus@2049
   838
    SDL_CalculateAudioSpec(prepared);
slouken@21
   839
icculus@2049
   840
    return 1;
icculus@2049
   841
}
slouken@1408
   842
slouken@21
   843
icculus@2049
   844
static SDL_AudioDeviceID
icculus@2049
   845
open_audio_device(const char *devname, int iscapture,
slouken@2866
   846
                  const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
slouken@2866
   847
                  int allowed_changes, int min_id)
icculus@2049
   848
{
icculus@2049
   849
    SDL_AudioDeviceID id = 0;
slouken@2866
   850
    SDL_AudioSpec _obtained;
icculus@2049
   851
    SDL_AudioDevice *device;
slouken@2866
   852
    SDL_bool build_cvt;
icculus@2049
   853
    int i = 0;
slouken@21
   854
icculus@2049
   855
    if (!SDL_WasInit(SDL_INIT_AUDIO)) {
icculus@2049
   856
        SDL_SetError("Audio subsystem is not initialized");
icculus@2049
   857
        return 0;
icculus@2049
   858
    }
icculus@2049
   859
icculus@2049
   860
    if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
icculus@2049
   861
        SDL_SetError("No capture support");
icculus@2049
   862
        return 0;
icculus@2049
   863
    }
icculus@2049
   864
slouken@2866
   865
    if (!obtained) {
slouken@2866
   866
        obtained = &_obtained;
slouken@2866
   867
    }
slouken@2866
   868
    if (!prepare_audiospec(desired, obtained)) {
icculus@2049
   869
        return 0;
icculus@2049
   870
    }
icculus@2049
   871
icculus@2049
   872
    /* If app doesn't care about a specific device, let the user override. */
icculus@2049
   873
    if (devname == NULL) {
icculus@2049
   874
        devname = SDL_getenv("SDL_AUDIO_DEVICE_NAME");
slouken@1895
   875
    }
slouken@21
   876
icculus@2049
   877
    /*
icculus@2049
   878
     * Catch device names at the high level for the simple case...
icculus@2049
   879
     * This lets us have a basic "device enumeration" for systems that
icculus@2049
   880
     *  don't have multiple devices, but makes sure the device name is
icculus@2049
   881
     *  always NULL when it hits the low level.
icculus@2049
   882
     *
icculus@2049
   883
     * Also make sure that the simple case prevents multiple simultaneous
icculus@2049
   884
     *  opens of the default system device.
icculus@2049
   885
     */
icculus@2049
   886
icculus@2049
   887
    if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
icculus@2049
   888
        if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
icculus@2049
   889
            SDL_SetError("No such device");
icculus@2049
   890
            return 0;
icculus@2049
   891
        }
icculus@2049
   892
        devname = NULL;
icculus@2049
   893
icculus@2049
   894
        for (i = 0; i < SDL_arraysize(open_devices); i++) {
icculus@2049
   895
            if ((open_devices[i]) && (open_devices[i]->iscapture)) {
icculus@2049
   896
                SDL_SetError("Audio device already open");
icculus@2049
   897
                return 0;
icculus@2049
   898
            }
icculus@2049
   899
        }
icculus@2049
   900
    }
icculus@2049
   901
icculus@2049
   902
    if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
icculus@2049
   903
        if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
icculus@2049
   904
            SDL_SetError("No such device");
icculus@2049
   905
            return 0;
icculus@2049
   906
        }
icculus@2049
   907
        devname = NULL;
icculus@2049
   908
icculus@2049
   909
        for (i = 0; i < SDL_arraysize(open_devices); i++) {
icculus@2049
   910
            if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
icculus@2049
   911
                SDL_SetError("Audio device already open");
icculus@2049
   912
                return 0;
icculus@2049
   913
            }
icculus@2049
   914
        }
icculus@2049
   915
    }
icculus@2049
   916
slouken@2060
   917
    device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice));
icculus@2049
   918
    if (device == NULL) {
icculus@2049
   919
        SDL_OutOfMemory();
icculus@2049
   920
        return 0;
icculus@2049
   921
    }
slouken@2060
   922
    SDL_memset(device, '\0', sizeof(SDL_AudioDevice));
slouken@2866
   923
    device->spec = *obtained;
icculus@2049
   924
    device->enabled = 1;
icculus@2049
   925
    device->paused = 1;
icculus@2049
   926
    device->iscapture = iscapture;
icculus@2049
   927
icculus@2049
   928
    /* Create a semaphore for locking the sound buffers */
icculus@2049
   929
    if (!current_audio.impl.SkipMixerLock) {
icculus@2049
   930
        device->mixer_lock = SDL_CreateMutex();
icculus@2049
   931
        if (device->mixer_lock == NULL) {
icculus@2049
   932
            close_audio_device(device);
icculus@2049
   933
            SDL_SetError("Couldn't create mixer lock");
icculus@2049
   934
            return 0;
icculus@2049
   935
        }
icculus@2049
   936
    }
icculus@2049
   937
icculus@5593
   938
    /* force a device detection if we haven't done one yet. */
icculus@5593
   939
    if ( ((iscapture) && (current_audio.inputDevices == NULL)) ||
icculus@5593
   940
         ((!iscapture) && (current_audio.outputDevices == NULL)) )
icculus@5593
   941
        SDL_GetNumAudioDevices(iscapture);
icculus@5593
   942
icculus@2049
   943
    if (!current_audio.impl.OpenDevice(device, devname, iscapture)) {
icculus@2049
   944
        close_audio_device(device);
icculus@2049
   945
        return 0;
icculus@2049
   946
    }
icculus@2049
   947
    device->opened = 1;
slouken@0
   948
slouken@1895
   949
    /* Allocate a fake audio memory buffer */
aschiffler@4865
   950
    device->fake_stream = (Uint8 *)SDL_AllocAudioMem(device->spec.size);
icculus@2049
   951
    if (device->fake_stream == NULL) {
icculus@2049
   952
        close_audio_device(device);
slouken@1895
   953
        SDL_OutOfMemory();
icculus@2049
   954
        return 0;
slouken@1895
   955
    }
slouken@0
   956
slouken@2866
   957
    /* If the audio driver changes the buffer size, accept it */
slouken@2866
   958
    if (device->spec.samples != obtained->samples) {
slouken@2866
   959
        obtained->samples = device->spec.samples;
slouken@2866
   960
        SDL_CalculateAudioSpec(obtained);
slouken@2866
   961
    }
slouken@2866
   962
slouken@1895
   963
    /* See if we need to do any conversion */
slouken@2866
   964
    build_cvt = SDL_FALSE;
slouken@2866
   965
    if (obtained->freq != device->spec.freq) {
slouken@2866
   966
        if (allowed_changes & SDL_AUDIO_ALLOW_FREQUENCY_CHANGE) {
slouken@2866
   967
            obtained->freq = device->spec.freq;
slouken@2866
   968
        } else {
slouken@2866
   969
            build_cvt = SDL_TRUE;
slouken@2866
   970
        }
slouken@2866
   971
    }
slouken@2866
   972
    if (obtained->format != device->spec.format) {
slouken@2866
   973
        if (allowed_changes & SDL_AUDIO_ALLOW_FORMAT_CHANGE) {
slouken@2866
   974
            obtained->format = device->spec.format;
slouken@2866
   975
        } else {
slouken@2866
   976
            build_cvt = SDL_TRUE;
slouken@2866
   977
        }
slouken@2866
   978
    }
slouken@2866
   979
    if (obtained->channels != device->spec.channels) {
slouken@2866
   980
        if (allowed_changes & SDL_AUDIO_ALLOW_CHANNELS_CHANGE) {
slouken@2866
   981
            obtained->channels = device->spec.channels;
slouken@2866
   982
        } else {
slouken@2866
   983
            build_cvt = SDL_TRUE;
slouken@2866
   984
        }
slouken@2866
   985
    }
slouken@2866
   986
    if (build_cvt) {
slouken@1895
   987
        /* Build an audio conversion block */
icculus@2049
   988
        if (SDL_BuildAudioCVT(&device->convert,
slouken@2866
   989
                              obtained->format, obtained->channels,
slouken@2866
   990
                              obtained->freq,
icculus@2049
   991
                              device->spec.format, device->spec.channels,
icculus@2049
   992
                              device->spec.freq) < 0) {
icculus@2049
   993
            close_audio_device(device);
icculus@2049
   994
            return 0;
slouken@1895
   995
        }
icculus@2049
   996
        if (device->convert.needed) {
slouken@2866
   997
            device->convert.len = (int) (((double) obtained->size) /
slouken@2060
   998
                                         device->convert.len_ratio);
icculus@2053
   999
icculus@2049
  1000
            device->convert.buf =
icculus@2049
  1001
                (Uint8 *) SDL_AllocAudioMem(device->convert.len *
icculus@2049
  1002
                                            device->convert.len_mult);
icculus@2049
  1003
            if (device->convert.buf == NULL) {
icculus@2049
  1004
                close_audio_device(device);
slouken@1895
  1005
                SDL_OutOfMemory();
icculus@2049
  1006
                return 0;
slouken@1895
  1007
            }
slouken@1895
  1008
        }
slouken@1895
  1009
    }
icculus@2049
  1010
icculus@2049
  1011
    /* Find an available device ID and store the structure... */
slouken@2060
  1012
    for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) {
icculus@2049
  1013
        if (open_devices[id] == NULL) {
icculus@2049
  1014
            open_devices[id] = device;
icculus@2049
  1015
            break;
icculus@2049
  1016
        }
icculus@2049
  1017
    }
icculus@2049
  1018
icculus@2049
  1019
    if (id == SDL_arraysize(open_devices)) {
icculus@2049
  1020
        SDL_SetError("Too many open audio devices");
icculus@2049
  1021
        close_audio_device(device);
icculus@2049
  1022
        return 0;
icculus@2049
  1023
    }
icculus@2049
  1024
slouken@1895
  1025
    /* Start the audio thread if necessary */
icculus@2049
  1026
    if (!current_audio.impl.ProvidesOwnCallbackThread) {
slouken@1895
  1027
        /* Start the audio thread */
icculus@5969
  1028
        char name[64];
icculus@5969
  1029
        SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) (id + 1));
icculus@2049
  1030
/* !!! FIXME: this is nasty. */
icculus@6430
  1031
#if defined(__WIN32__) && !defined(HAVE_LIBC)
slouken@1330
  1032
#undef SDL_CreateThread
icculus@5969
  1033
        device->thread = SDL_CreateThread(SDL_RunAudio, name, device, NULL, NULL);
slouken@1330
  1034
#else
icculus@5969
  1035
        device->thread = SDL_CreateThread(SDL_RunAudio, name, device);
slouken@1330
  1036
#endif
icculus@2049
  1037
        if (device->thread == NULL) {
slouken@2060
  1038
            SDL_CloseAudioDevice(id + 1);
slouken@1895
  1039
            SDL_SetError("Couldn't create audio thread");
icculus@2049
  1040
            return 0;
icculus@2049
  1041
        }
icculus@2049
  1042
    }
icculus@2049
  1043
slouken@2060
  1044
    return id + 1;
icculus@2049
  1045
}
icculus@2049
  1046
icculus@2049
  1047
icculus@2049
  1048
int
slouken@2866
  1049
SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
icculus@2049
  1050
{
icculus@2049
  1051
    SDL_AudioDeviceID id = 0;
icculus@2049
  1052
icculus@2049
  1053
    /* Start up the audio driver, if necessary. This is legacy behaviour! */
icculus@2049
  1054
    if (!SDL_WasInit(SDL_INIT_AUDIO)) {
icculus@2049
  1055
        if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
slouken@1895
  1056
            return (-1);
slouken@1895
  1057
        }
icculus@2049
  1058
    }
slouken@0
  1059
icculus@2049
  1060
    /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
icculus@2049
  1061
    if (open_devices[0] != NULL) {
icculus@2049
  1062
        SDL_SetError("Audio device is already opened");
icculus@2049
  1063
        return (-1);
slouken@1895
  1064
    }
icculus@2049
  1065
slouken@2866
  1066
    if (obtained) {
slouken@2866
  1067
        id = open_audio_device(NULL, 0, desired, obtained,
slouken@2866
  1068
                               SDL_AUDIO_ALLOW_ANY_CHANGE, 1);
slouken@2866
  1069
    } else {
slouken@2866
  1070
        id = open_audio_device(NULL, 0, desired, desired, 0, 1);
slouken@2866
  1071
    }
slouken@21
  1072
icculus@5964
  1073
    SDL_assert((id == 0) || (id == 1));
icculus@2049
  1074
    return ((id == 0) ? -1 : 0);
icculus@2049
  1075
}
slouken@21
  1076
icculus@2049
  1077
SDL_AudioDeviceID
icculus@2049
  1078
SDL_OpenAudioDevice(const char *device, int iscapture,
slouken@2866
  1079
                    const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
slouken@2866
  1080
                    int allowed_changes)
icculus@2049
  1081
{
slouken@2866
  1082
    return open_audio_device(device, iscapture, desired, obtained,
slouken@2866
  1083
                             allowed_changes, 2);
slouken@1895
  1084
}
slouken@1895
  1085
slouken@3537
  1086
SDL_AudioStatus
icculus@2049
  1087
SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
slouken@1895
  1088
{
icculus@2049
  1089
    SDL_AudioDevice *device = get_audio_device(devid);
slouken@3537
  1090
    SDL_AudioStatus status = SDL_AUDIO_STOPPED;
icculus@2049
  1091
    if (device && device->enabled) {
icculus@2049
  1092
        if (device->paused) {
slouken@1895
  1093
            status = SDL_AUDIO_PAUSED;
slouken@1895
  1094
        } else {
slouken@1895
  1095
            status = SDL_AUDIO_PLAYING;
slouken@1895
  1096
        }
slouken@1895
  1097
    }
slouken@1895
  1098
    return (status);
slouken@0
  1099
}
slouken@0
  1100
icculus@2049
  1101
slouken@3537
  1102
SDL_AudioStatus
icculus@2049
  1103
SDL_GetAudioStatus(void)
icculus@2049
  1104
{
icculus@2049
  1105
    return SDL_GetAudioDeviceStatus(1);
icculus@2049
  1106
}
icculus@2049
  1107
icculus@2049
  1108
void
icculus@2049
  1109
SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
icculus@2049
  1110
{
icculus@2049
  1111
    SDL_AudioDevice *device = get_audio_device(devid);
icculus@2049
  1112
    if (device) {
icculus@2049
  1113
        device->paused = pause_on;
icculus@2049
  1114
    }
icculus@2049
  1115
}
icculus@2049
  1116
slouken@1895
  1117
void
slouken@1895
  1118
SDL_PauseAudio(int pause_on)
slouken@0
  1119
{
icculus@2049
  1120
    SDL_PauseAudioDevice(1, pause_on);
icculus@2049
  1121
}
icculus@2049
  1122
slouken@0
  1123
icculus@2049
  1124
void
icculus@2049
  1125
SDL_LockAudioDevice(SDL_AudioDeviceID devid)
icculus@2049
  1126
{
icculus@2049
  1127
    /* Obtain a lock on the mixing buffers */
icculus@2049
  1128
    SDL_AudioDevice *device = get_audio_device(devid);
icculus@2049
  1129
    if (device) {
icculus@2049
  1130
        current_audio.impl.LockDevice(device);
slouken@1895
  1131
    }
slouken@0
  1132
}
slouken@0
  1133
slouken@1895
  1134
void
slouken@1895
  1135
SDL_LockAudio(void)
slouken@0
  1136
{
icculus@2049
  1137
    SDL_LockAudioDevice(1);
icculus@2049
  1138
}
slouken@0
  1139
icculus@2049
  1140
void
icculus@2049
  1141
SDL_UnlockAudioDevice(SDL_AudioDeviceID devid)
icculus@2049
  1142
{
slouken@1895
  1143
    /* Obtain a lock on the mixing buffers */
icculus@2049
  1144
    SDL_AudioDevice *device = get_audio_device(devid);
icculus@2049
  1145
    if (device) {
icculus@2049
  1146
        current_audio.impl.UnlockDevice(device);
slouken@1895
  1147
    }
slouken@0
  1148
}
slouken@0
  1149
slouken@1895
  1150
void
slouken@1895
  1151
SDL_UnlockAudio(void)
slouken@0
  1152
{
icculus@2049
  1153
    SDL_UnlockAudioDevice(1);
icculus@2049
  1154
}
slouken@0
  1155
icculus@2049
  1156
void
icculus@2049
  1157
SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
icculus@2049
  1158
{
icculus@2049
  1159
    SDL_AudioDevice *device = get_audio_device(devid);
icculus@2049
  1160
    if (device) {
icculus@2049
  1161
        close_audio_device(device);
slouken@2060
  1162
        open_devices[devid - 1] = NULL;
slouken@1895
  1163
    }
slouken@0
  1164
}
slouken@0
  1165
slouken@1895
  1166
void
slouken@1895
  1167
SDL_CloseAudio(void)
slouken@0
  1168
{
icculus@2049
  1169
    SDL_CloseAudioDevice(1);
slouken@0
  1170
}
slouken@0
  1171
slouken@1895
  1172
void
slouken@1895
  1173
SDL_AudioQuit(void)
slouken@0
  1174
{
icculus@2049
  1175
    SDL_AudioDeviceID i;
icculus@2049
  1176
    for (i = 0; i < SDL_arraysize(open_devices); i++) {
icculus@2049
  1177
        SDL_CloseAudioDevice(i);
icculus@2049
  1178
    }
slouken@0
  1179
icculus@2049
  1180
    /* Free the driver data */
icculus@2049
  1181
    current_audio.impl.Deinitialize();
icculus@5593
  1182
    free_device_list(&current_audio.outputDevices,
icculus@5593
  1183
                     &current_audio.outputDeviceCount);
icculus@5593
  1184
    free_device_list(&current_audio.inputDevices,
icculus@5593
  1185
                     &current_audio.inputDeviceCount);
slouken@2060
  1186
    SDL_memset(&current_audio, '\0', sizeof(current_audio));
slouken@2060
  1187
    SDL_memset(open_devices, '\0', sizeof(open_devices));
slouken@0
  1188
}
slouken@0
  1189
icculus@1982
  1190
#define NUM_FORMATS 10
slouken@0
  1191
static int format_idx;
slouken@0
  1192
static int format_idx_sub;
icculus@1982
  1193
static SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS] = {
slouken@1895
  1194
    {AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
icculus@1982
  1195
     AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
slouken@1895
  1196
    {AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
icculus@1982
  1197
     AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
icculus@1982
  1198
    {AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S32LSB,
icculus@1982
  1199
     AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
icculus@1982
  1200
    {AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S32MSB,
icculus@1982
  1201
     AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
icculus@1982
  1202
    {AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S32LSB,
icculus@1982
  1203
     AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
icculus@1982
  1204
    {AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_S32MSB,
icculus@1982
  1205
     AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
icculus@1993
  1206
    {AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S16LSB,
icculus@1993
  1207
     AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
icculus@1993
  1208
    {AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S16MSB,
icculus@1993
  1209
     AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
icculus@1993
  1210
    {AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_S16LSB,
icculus@1993
  1211
     AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
icculus@1993
  1212
    {AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_S16MSB,
icculus@1993
  1213
     AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
slouken@0
  1214
};
slouken@0
  1215
icculus@1982
  1216
SDL_AudioFormat
icculus@1982
  1217
SDL_FirstAudioFormat(SDL_AudioFormat format)
slouken@0
  1218
{
slouken@1895
  1219
    for (format_idx = 0; format_idx < NUM_FORMATS; ++format_idx) {
slouken@1895
  1220
        if (format_list[format_idx][0] == format) {
slouken@1895
  1221
            break;
slouken@1895
  1222
        }
slouken@1895
  1223
    }
slouken@1895
  1224
    format_idx_sub = 0;
slouken@1895
  1225
    return (SDL_NextAudioFormat());
slouken@0
  1226
}
slouken@0
  1227
icculus@1982
  1228
SDL_AudioFormat
slouken@1895
  1229
SDL_NextAudioFormat(void)
slouken@0
  1230
{
slouken@1895
  1231
    if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) {
slouken@1895
  1232
        return (0);
slouken@1895
  1233
    }
slouken@1895
  1234
    return (format_list[format_idx][format_idx_sub++]);
slouken@0
  1235
}
slouken@0
  1236
slouken@1895
  1237
void
slouken@1895
  1238
SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
slouken@0
  1239
{
slouken@1895
  1240
    switch (spec->format) {
slouken@1895
  1241
    case AUDIO_U8:
slouken@1895
  1242
        spec->silence = 0x80;
slouken@1895
  1243
        break;
slouken@1895
  1244
    default:
slouken@1895
  1245
        spec->silence = 0x00;
slouken@1895
  1246
        break;
slouken@1895
  1247
    }
icculus@2049
  1248
    spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
slouken@1895
  1249
    spec->size *= spec->channels;
slouken@1895
  1250
    spec->size *= spec->samples;
slouken@0
  1251
}
slouken@1895
  1252
icculus@2049
  1253
icculus@2049
  1254
/*
icculus@2049
  1255
 * Moved here from SDL_mixer.c, since it relies on internals of an opened
icculus@2049
  1256
 *  audio device (and is deprecated, by the way!).
icculus@2049
  1257
 */
icculus@2049
  1258
void
icculus@2049
  1259
SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
icculus@2049
  1260
{
icculus@2049
  1261
    /* Mix the user-level audio format */
icculus@2049
  1262
    SDL_AudioDevice *device = get_audio_device(1);
icculus@2049
  1263
    if (device != NULL) {
icculus@2049
  1264
        SDL_AudioFormat format;
icculus@2049
  1265
        if (device->convert.needed) {
icculus@2049
  1266
            format = device->convert.src_format;
icculus@2049
  1267
        } else {
icculus@2049
  1268
            format = device->spec.format;
icculus@2049
  1269
        }
icculus@2049
  1270
        SDL_MixAudioFormat(dst, src, format, len, volume);
icculus@2049
  1271
    }
icculus@2049
  1272
}
icculus@2049
  1273
slouken@1895
  1274
/* vi: set ts=4 sw=4 expandtab: */