src/audio/SDL_audio.c
author Sam Lantinga
Sat, 13 Dec 2008 06:36:47 +0000
changeset 2866 e532417a6977
parent 2859 99210400e8b9
child 2938 2929ed239d2a
permissions -rw-r--r--
Fixed SDL 1.2 compatibility problem.

The API specifies that SDL_OpenAudio() will fill out the 'desired' audio spec
with the correct samples and size set by the driver. This value is important
since it may be used by applications that size audio buffers, etc.

However, we want to allow advanced applications to call SDL_OpenAudioDevice()
which gets passed a const 'desired' parameter, and have the correct data filled
into the 'obtained' parameter, possibly allowing or not allowing format changes.

So... 'obtained' becomes the audio format the user callback is expected to use,
and we add flags to allow the application to specify which format changes are
allowed.

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