src/audio/directsound/SDL_directsound.c
author Sam Lantinga
Mon, 09 Jan 2017 11:58:01 -0800
changeset 10802 6afc9b833867
parent 10780 4ea5472ed455
child 11811 5d94cb6b24d3
permissions -rw-r--r--
We only need the first few keymaps corresponding to the following constants:
K_NORMTAB, K_SHIFTTAB, K_ALTTAB, K_ALTSHIFTTAB

In the normal case we'll load all the keymaps from the kernel, but this reduces the size of the SDL library for the fallback case when we can't get to the tty.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@0
    22
slouken@6044
    23
#if SDL_AUDIO_DRIVER_DSOUND
slouken@6044
    24
slouken@0
    25
/* Allow access to a raw mixing buffer */
slouken@0
    26
icculus@10279
    27
#include "SDL_assert.h"
slouken@0
    28
#include "SDL_timer.h"
slouken@5090
    29
#include "SDL_loadso.h"
slouken@0
    30
#include "SDL_audio.h"
slouken@1361
    31
#include "../SDL_audio_c.h"
icculus@5587
    32
#include "SDL_directsound.h"
slouken@0
    33
icculus@7449
    34
#ifndef WAVE_FORMAT_IEEE_FLOAT
icculus@7449
    35
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
icculus@7449
    36
#endif
icculus@7449
    37
slouken@0
    38
/* DirectX function pointers for audio */
slouken@5090
    39
static void* DSoundDLL = NULL;
icculus@10279
    40
typedef HRESULT (WINAPI *fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
icculus@10279
    41
typedef HRESULT (WINAPI *fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
icculus@10279
    42
typedef HRESULT (WINAPI *fnDirectSoundCaptureCreate8)(LPCGUID,LPDIRECTSOUNDCAPTURE8 *,LPUNKNOWN);
icculus@10279
    43
typedef HRESULT (WINAPI *fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
icculus@5587
    44
static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL;
icculus@5587
    45
static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL;
icculus@10279
    46
static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL;
icculus@5587
    47
static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
slouken@0
    48
slouken@1895
    49
static void
icculus@2049
    50
DSOUND_Unload(void)
slouken@0
    51
{
icculus@5587
    52
    pDirectSoundCreate8 = NULL;
icculus@5587
    53
    pDirectSoundEnumerateW = NULL;
icculus@10279
    54
    pDirectSoundCaptureCreate8 = NULL;
icculus@5587
    55
    pDirectSoundCaptureEnumerateW = NULL;
slouken@5090
    56
slouken@1895
    57
    if (DSoundDLL != NULL) {
slouken@5090
    58
        SDL_UnloadObject(DSoundDLL);
slouken@5090
    59
        DSoundDLL = NULL;
slouken@1895
    60
    }
slouken@0
    61
}
slouken@0
    62
icculus@2049
    63
icculus@2049
    64
static int
icculus@2049
    65
DSOUND_Load(void)
slouken@0
    66
{
icculus@2049
    67
    int loaded = 0;
icculus@2049
    68
icculus@2049
    69
    DSOUND_Unload();
slouken@0
    70
slouken@5090
    71
    DSoundDLL = SDL_LoadObject("DSOUND.DLL");
icculus@2049
    72
    if (DSoundDLL == NULL) {
icculus@2049
    73
        SDL_SetError("DirectSound: failed to load DSOUND.DLL");
icculus@2049
    74
    } else {
icculus@5587
    75
        /* Now make sure we have DirectX 8 or better... */
icculus@5587
    76
        #define DSOUNDLOAD(f) { \
icculus@5587
    77
            p##f = (fn##f) SDL_LoadFunction(DSoundDLL, #f); \
icculus@5587
    78
            if (!p##f) loaded = 0; \
icculus@2049
    79
        }
icculus@5587
    80
        loaded = 1;  /* will reset if necessary. */
icculus@5587
    81
        DSOUNDLOAD(DirectSoundCreate8);
icculus@5587
    82
        DSOUNDLOAD(DirectSoundEnumerateW);
icculus@10279
    83
        DSOUNDLOAD(DirectSoundCaptureCreate8);
icculus@5587
    84
        DSOUNDLOAD(DirectSoundCaptureEnumerateW);
icculus@5587
    85
        #undef DSOUNDLOAD
icculus@2049
    86
icculus@5587
    87
        if (!loaded) {
icculus@5587
    88
            SDL_SetError("DirectSound: System doesn't appear to have DX8.");
icculus@2049
    89
        }
slouken@1895
    90
    }
slouken@0
    91
icculus@2049
    92
    if (!loaded) {
icculus@2049
    93
        DSOUND_Unload();
slouken@1895
    94
    }
slouken@0
    95
icculus@2049
    96
    return loaded;
slouken@0
    97
}
slouken@0
    98
icculus@7037
    99
static int
slouken@1895
   100
SetDSerror(const char *function, int code)
slouken@0
   101
{
slouken@1895
   102
    static const char *error;
slouken@1895
   103
    static char errbuf[1024];
slouken@0
   104
slouken@1895
   105
    errbuf[0] = 0;
slouken@1895
   106
    switch (code) {
slouken@1895
   107
    case E_NOINTERFACE:
icculus@5587
   108
        error = "Unsupported interface -- Is DirectX 8.0 or later installed?";
slouken@1895
   109
        break;
slouken@1895
   110
    case DSERR_ALLOCATED:
slouken@1895
   111
        error = "Audio device in use";
slouken@1895
   112
        break;
slouken@1895
   113
    case DSERR_BADFORMAT:
slouken@1895
   114
        error = "Unsupported audio format";
slouken@1895
   115
        break;
slouken@1895
   116
    case DSERR_BUFFERLOST:
slouken@1895
   117
        error = "Mixing buffer was lost";
slouken@1895
   118
        break;
slouken@1895
   119
    case DSERR_CONTROLUNAVAIL:
slouken@1895
   120
        error = "Control requested is not available";
slouken@1895
   121
        break;
slouken@1895
   122
    case DSERR_INVALIDCALL:
slouken@1895
   123
        error = "Invalid call for the current state";
slouken@1895
   124
        break;
slouken@1895
   125
    case DSERR_INVALIDPARAM:
slouken@1895
   126
        error = "Invalid parameter";
slouken@1895
   127
        break;
slouken@1895
   128
    case DSERR_NODRIVER:
slouken@1895
   129
        error = "No audio device found";
slouken@1895
   130
        break;
slouken@1895
   131
    case DSERR_OUTOFMEMORY:
slouken@1895
   132
        error = "Out of memory";
slouken@1895
   133
        break;
slouken@1895
   134
    case DSERR_PRIOLEVELNEEDED:
slouken@1895
   135
        error = "Caller doesn't have priority";
slouken@1895
   136
        break;
slouken@1895
   137
    case DSERR_UNSUPPORTED:
slouken@1895
   138
        error = "Function not supported";
slouken@1895
   139
        break;
slouken@1895
   140
    default:
slouken@1895
   141
        SDL_snprintf(errbuf, SDL_arraysize(errbuf),
slouken@1895
   142
                     "%s: Unknown DirectSound error: 0x%x", function, code);
slouken@1895
   143
        break;
slouken@1895
   144
    }
slouken@1895
   145
    if (!errbuf[0]) {
slouken@1895
   146
        SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
slouken@1895
   147
                     error);
slouken@1895
   148
    }
icculus@7037
   149
    return SDL_SetError("%s", errbuf);
slouken@0
   150
}
slouken@0
   151
icculus@9394
   152
static void
icculus@9394
   153
DSOUND_FreeDeviceHandle(void *handle)
icculus@9394
   154
{
icculus@9394
   155
    SDL_free(handle);
icculus@9394
   156
}
icculus@5587
   157
icculus@5593
   158
static BOOL CALLBACK
icculus@5593
   159
FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
slouken@0
   160
{
icculus@9394
   161
    const int iscapture = (int) ((size_t) data);
icculus@5593
   162
    if (guid != NULL) {  /* skip default device */
icculus@10278
   163
        char *str = WIN_LookupAudioDeviceName(desc, guid);
icculus@5593
   164
        if (str != NULL) {
icculus@9394
   165
            LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
icculus@9394
   166
            SDL_memcpy(cpyguid, guid, sizeof (GUID));
icculus@9394
   167
            SDL_AddAudioDevice(iscapture, str, cpyguid);
icculus@5593
   168
            SDL_free(str);  /* addfn() makes a copy of this string. */
icculus@5587
   169
        }
icculus@5587
   170
    }
icculus@5587
   171
    return TRUE;  /* keep enumerating. */
slouken@0
   172
}
slouken@0
   173
icculus@5593
   174
static void
icculus@9394
   175
DSOUND_DetectDevices(void)
icculus@5587
   176
{
icculus@9394
   177
    pDirectSoundCaptureEnumerateW(FindAllDevs, (void *) ((size_t) 1));
icculus@9394
   178
    pDirectSoundEnumerateW(FindAllDevs, (void *) ((size_t) 0));
icculus@5587
   179
}
icculus@5587
   180
icculus@5587
   181
slouken@1895
   182
static void
icculus@2049
   183
DSOUND_WaitDevice(_THIS)
slouken@0
   184
{
icculus@2049
   185
    DWORD status = 0;
icculus@2049
   186
    DWORD cursor = 0;
icculus@2049
   187
    DWORD junk = 0;
icculus@2049
   188
    HRESULT result = DS_OK;
slouken@0
   189
slouken@1895
   190
    /* Semi-busy wait, since we have no way of getting play notification
slouken@1895
   191
       on a primary mixing buffer located in hardware (DirectX 5.0)
slouken@1895
   192
     */
icculus@2049
   193
    result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
icculus@2049
   194
                                                   &junk, &cursor);
slouken@1895
   195
    if (result != DS_OK) {
slouken@1895
   196
        if (result == DSERR_BUFFERLOST) {
icculus@2049
   197
            IDirectSoundBuffer_Restore(this->hidden->mixbuf);
slouken@1895
   198
        }
slouken@0
   199
#ifdef DEBUG_SOUND
slouken@1895
   200
        SetDSerror("DirectSound GetCurrentPosition", result);
slouken@0
   201
#endif
slouken@1895
   202
        return;
slouken@1895
   203
    }
slouken@0
   204
icculus@10279
   205
    while ((cursor / this->spec.size) == this->hidden->lastchunk) {
slouken@1895
   206
        /* FIXME: find out how much time is left and sleep that long */
slouken@1895
   207
        SDL_Delay(1);
slouken@0
   208
slouken@1895
   209
        /* Try to restore a lost sound buffer */
icculus@2049
   210
        IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
slouken@1895
   211
        if ((status & DSBSTATUS_BUFFERLOST)) {
icculus@2049
   212
            IDirectSoundBuffer_Restore(this->hidden->mixbuf);
icculus@2049
   213
            IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
slouken@1895
   214
            if ((status & DSBSTATUS_BUFFERLOST)) {
slouken@1895
   215
                break;
slouken@1895
   216
            }
slouken@1895
   217
        }
slouken@1895
   218
        if (!(status & DSBSTATUS_PLAYING)) {
icculus@2049
   219
            result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
icculus@2049
   220
                                             DSBPLAY_LOOPING);
slouken@1895
   221
            if (result == DS_OK) {
slouken@1895
   222
                continue;
slouken@1895
   223
            }
slouken@0
   224
#ifdef DEBUG_SOUND
slouken@1895
   225
            SetDSerror("DirectSound Play", result);
slouken@0
   226
#endif
slouken@1895
   227
            return;
slouken@1895
   228
        }
slouken@0
   229
slouken@1895
   230
        /* Find out where we are playing */
icculus@2049
   231
        result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
slouken@1895
   232
                                                       &junk, &cursor);
slouken@1895
   233
        if (result != DS_OK) {
slouken@1895
   234
            SetDSerror("DirectSound GetCurrentPosition", result);
slouken@1895
   235
            return;
slouken@1895
   236
        }
slouken@1895
   237
    }
slouken@0
   238
}
slouken@0
   239
slouken@1895
   240
static void
icculus@2049
   241
DSOUND_PlayDevice(_THIS)
slouken@0
   242
{
slouken@1895
   243
    /* Unlock the buffer, allowing it to play */
icculus@2049
   244
    if (this->hidden->locked_buf) {
icculus@2049
   245
        IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
icculus@2049
   246
                                  this->hidden->locked_buf,
icculus@10279
   247
                                  this->spec.size, NULL, 0);
slouken@1895
   248
    }
slouken@0
   249
}
slouken@0
   250
slouken@1895
   251
static Uint8 *
icculus@2049
   252
DSOUND_GetDeviceBuf(_THIS)
slouken@0
   253
{
icculus@2049
   254
    DWORD cursor = 0;
icculus@2049
   255
    DWORD junk = 0;
icculus@2049
   256
    HRESULT result = DS_OK;
icculus@2049
   257
    DWORD rawlen = 0;
slouken@0
   258
slouken@1895
   259
    /* Figure out which blocks to fill next */
icculus@2049
   260
    this->hidden->locked_buf = NULL;
icculus@2049
   261
    result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
icculus@2049
   262
                                                   &junk, &cursor);
slouken@1895
   263
    if (result == DSERR_BUFFERLOST) {
icculus@2049
   264
        IDirectSoundBuffer_Restore(this->hidden->mixbuf);
icculus@2049
   265
        result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
slouken@1895
   266
                                                       &junk, &cursor);
slouken@1895
   267
    }
slouken@1895
   268
    if (result != DS_OK) {
slouken@1895
   269
        SetDSerror("DirectSound GetCurrentPosition", result);
slouken@1895
   270
        return (NULL);
slouken@1895
   271
    }
icculus@10279
   272
    cursor /= this->spec.size;
slouken@1877
   273
#ifdef DEBUG_SOUND
slouken@1895
   274
    /* Detect audio dropouts */
slouken@1895
   275
    {
slouken@1895
   276
        DWORD spot = cursor;
icculus@2049
   277
        if (spot < this->hidden->lastchunk) {
icculus@2049
   278
            spot += this->hidden->num_buffers;
slouken@1895
   279
        }
icculus@2049
   280
        if (spot > this->hidden->lastchunk + 1) {
slouken@1895
   281
            fprintf(stderr, "Audio dropout, missed %d fragments\n",
icculus@2049
   282
                    (spot - (this->hidden->lastchunk + 1)));
slouken@1895
   283
        }
slouken@1895
   284
    }
slouken@1877
   285
#endif
icculus@2049
   286
    this->hidden->lastchunk = cursor;
icculus@2049
   287
    cursor = (cursor + 1) % this->hidden->num_buffers;
icculus@10279
   288
    cursor *= this->spec.size;
slouken@0
   289
slouken@1895
   290
    /* Lock the audio buffer */
icculus@2049
   291
    result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
icculus@10279
   292
                                     this->spec.size,
slouken@2060
   293
                                     (LPVOID *) & this->hidden->locked_buf,
icculus@2049
   294
                                     &rawlen, NULL, &junk, 0);
slouken@1895
   295
    if (result == DSERR_BUFFERLOST) {
icculus@2049
   296
        IDirectSoundBuffer_Restore(this->hidden->mixbuf);
icculus@2049
   297
        result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
icculus@10279
   298
                                         this->spec.size,
slouken@3013
   299
                                         (LPVOID *) & this->
slouken@3013
   300
                                         hidden->locked_buf, &rawlen, NULL,
slouken@3013
   301
                                         &junk, 0);
slouken@1895
   302
    }
slouken@1895
   303
    if (result != DS_OK) {
slouken@1895
   304
        SetDSerror("DirectSound Lock", result);
slouken@1895
   305
        return (NULL);
slouken@1895
   306
    }
icculus@2049
   307
    return (this->hidden->locked_buf);
slouken@0
   308
}
slouken@0
   309
icculus@10279
   310
static int
icculus@10279
   311
DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen)
icculus@10279
   312
{
icculus@10279
   313
    struct SDL_PrivateAudioData *h = this->hidden;
icculus@10279
   314
    DWORD junk, cursor, ptr1len, ptr2len;
icculus@10279
   315
    VOID *ptr1, *ptr2;
icculus@10279
   316
icculus@10279
   317
    SDL_assert(buflen == this->spec.size);
icculus@10279
   318
icculus@10279
   319
    while (SDL_TRUE) {
icculus@10279
   320
        if (SDL_AtomicGet(&this->shutdown)) {  /* in case the buffer froze... */
icculus@10279
   321
            SDL_memset(buffer, this->spec.silence, buflen);
icculus@10279
   322
            return buflen;
icculus@10279
   323
        }
icculus@10279
   324
icculus@10279
   325
        if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
icculus@10279
   326
            return -1;
icculus@10279
   327
        }
icculus@10279
   328
        if ((cursor / this->spec.size) == h->lastchunk) {
icculus@10279
   329
            SDL_Delay(1);  /* FIXME: find out how much time is left and sleep that long */
icculus@10279
   330
        } else {
icculus@10279
   331
            break;
icculus@10279
   332
        }
icculus@10279
   333
    }
icculus@10279
   334
icculus@10279
   335
    if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) {
icculus@10279
   336
        return -1;
icculus@10279
   337
    }
icculus@10279
   338
icculus@10279
   339
    SDL_assert(ptr1len == this->spec.size);
icculus@10279
   340
    SDL_assert(ptr2 == NULL);
icculus@10279
   341
    SDL_assert(ptr2len == 0);
icculus@10279
   342
icculus@10279
   343
    SDL_memcpy(buffer, ptr1, ptr1len);
icculus@10279
   344
icculus@10279
   345
    if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) {
icculus@10279
   346
        return -1;
icculus@10279
   347
    }
icculus@10279
   348
icculus@10279
   349
    h->lastchunk = (h->lastchunk + 1) % h->num_buffers;
icculus@10279
   350
icculus@10279
   351
    return ptr1len;
icculus@10279
   352
}
icculus@10279
   353
icculus@10279
   354
static void
icculus@10279
   355
DSOUND_FlushCapture(_THIS)
icculus@10279
   356
{
icculus@10279
   357
    struct SDL_PrivateAudioData *h = this->hidden;
icculus@10279
   358
    DWORD junk, cursor;
icculus@10279
   359
    if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) {
icculus@10279
   360
        h->lastchunk = cursor / this->spec.size;
icculus@10279
   361
    }
icculus@10279
   362
}
icculus@10279
   363
icculus@2049
   364
static void
icculus@2049
   365
DSOUND_CloseDevice(_THIS)
slouken@0
   366
{
icculus@10255
   367
    if (this->hidden->mixbuf != NULL) {
icculus@10279
   368
        IDirectSoundBuffer_Stop(this->hidden->mixbuf);
icculus@10255
   369
        IDirectSoundBuffer_Release(this->hidden->mixbuf);
slouken@1895
   370
    }
icculus@10255
   371
    if (this->hidden->sound != NULL) {
icculus@10255
   372
        IDirectSound_Release(this->hidden->sound);
icculus@10255
   373
    }
icculus@10279
   374
    if (this->hidden->capturebuf != NULL) {
icculus@10279
   375
        IDirectSoundCaptureBuffer_Stop(this->hidden->capturebuf);
icculus@10279
   376
        IDirectSoundCaptureBuffer_Release(this->hidden->capturebuf);
icculus@10279
   377
    }
icculus@10279
   378
    if (this->hidden->capture != NULL) {
icculus@10279
   379
        IDirectSoundCapture_Release(this->hidden->capture);
icculus@10279
   380
    }
icculus@10255
   381
    SDL_free(this->hidden);
slouken@0
   382
}
slouken@0
   383
slouken@0
   384
/* This function tries to create a secondary audio buffer, and returns the
icculus@10279
   385
   number of audio chunks available in the created buffer. This is for
icculus@10279
   386
   playback devices, not capture.
slouken@0
   387
*/
slouken@1895
   388
static int
icculus@10279
   389
CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
slouken@0
   390
{
icculus@2049
   391
    LPDIRECTSOUND sndObj = this->hidden->sound;
icculus@2051
   392
    LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
icculus@2049
   393
    HRESULT result = DS_OK;
slouken@1895
   394
    DSBUFFERDESC format;
slouken@1895
   395
    LPVOID pvAudioPtr1, pvAudioPtr2;
slouken@1895
   396
    DWORD dwAudioBytes1, dwAudioBytes2;
slouken@0
   397
slouken@1895
   398
    /* Try to create the secondary buffer */
icculus@7461
   399
    SDL_zero(format);
slouken@1895
   400
    format.dwSize = sizeof(format);
slouken@1895
   401
    format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
icculus@10279
   402
    format.dwFlags |= DSBCAPS_GLOBALFOCUS;
icculus@10279
   403
    format.dwBufferBytes = bufsize;
icculus@10279
   404
    format.lpwfxFormat = wfmt;
slouken@1895
   405
    result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
slouken@1895
   406
    if (result != DS_OK) {
icculus@7037
   407
        return SetDSerror("DirectSound CreateSoundBuffer", result);
slouken@1895
   408
    }
icculus@10279
   409
    IDirectSoundBuffer_SetFormat(*sndbuf, wfmt);
slouken@0
   410
slouken@1895
   411
    /* Silence the initial audio buffer */
slouken@1895
   412
    result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
slouken@1895
   413
                                     (LPVOID *) & pvAudioPtr1, &dwAudioBytes1,
slouken@1895
   414
                                     (LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
slouken@1895
   415
                                     DSBLOCK_ENTIREBUFFER);
slouken@1895
   416
    if (result == DS_OK) {
icculus@2049
   417
        SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
slouken@1895
   418
        IDirectSoundBuffer_Unlock(*sndbuf,
slouken@1895
   419
                                  (LPVOID) pvAudioPtr1, dwAudioBytes1,
slouken@1895
   420
                                  (LPVOID) pvAudioPtr2, dwAudioBytes2);
slouken@1895
   421
    }
slouken@118
   422
slouken@1895
   423
    /* We're ready to go */
icculus@10279
   424
    return 0;
icculus@10279
   425
}
icculus@10279
   426
icculus@10279
   427
/* This function tries to create a capture buffer, and returns the
icculus@10279
   428
   number of audio chunks available in the created buffer. This is for
icculus@10279
   429
   capture devices, not playback.
icculus@10279
   430
*/
icculus@10279
   431
static int
icculus@10279
   432
CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
icculus@10279
   433
{
icculus@10279
   434
    LPDIRECTSOUNDCAPTURE capture = this->hidden->capture;
icculus@10279
   435
    LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf;
icculus@10279
   436
    DSCBUFFERDESC format;
icculus@10279
   437
    HRESULT result;
icculus@10279
   438
icculus@10279
   439
    SDL_zero(format);
icculus@10279
   440
    format.dwSize = sizeof (format);
icculus@10279
   441
    format.dwFlags = DSCBCAPS_WAVEMAPPED;
icculus@10279
   442
    format.dwBufferBytes = bufsize;
icculus@10279
   443
    format.lpwfxFormat = wfmt;
icculus@10279
   444
icculus@10279
   445
    result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL);
icculus@10279
   446
    if (result != DS_OK) {
icculus@10279
   447
        return SetDSerror("DirectSound CreateCaptureBuffer", result);
icculus@10279
   448
    }
icculus@10279
   449
icculus@10279
   450
    result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING);
icculus@10279
   451
    if (result != DS_OK) {
icculus@10279
   452
        IDirectSoundCaptureBuffer_Release(*capturebuf);
icculus@10279
   453
        return SetDSerror("DirectSound Start", result);
icculus@10279
   454
    }
icculus@10279
   455
icculus@10279
   456
#if 0
icculus@10279
   457
    /* presumably this starts at zero, but just in case... */
icculus@10279
   458
    result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor);
icculus@10279
   459
    if (result != DS_OK) {
icculus@10279
   460
        IDirectSoundCaptureBuffer_Stop(*capturebuf);
icculus@10279
   461
        IDirectSoundCaptureBuffer_Release(*capturebuf);
icculus@10279
   462
        return SetDSerror("DirectSound GetCurrentPosition", result);
icculus@10279
   463
    }
icculus@10279
   464
icculus@10279
   465
    this->hidden->lastchunk = cursor / this->spec.size;
icculus@10279
   466
#endif
icculus@10279
   467
icculus@10279
   468
    return 0;
slouken@0
   469
}
slouken@0
   470
slouken@1895
   471
static int
icculus@9394
   472
DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
slouken@0
   473
{
icculus@10279
   474
    const DWORD numchunks = 8;
slouken@1895
   475
    HRESULT result;
icculus@7461
   476
    SDL_bool valid_format = SDL_FALSE;
icculus@7461
   477
    SDL_bool tried_format = SDL_FALSE;
icculus@2049
   478
    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
icculus@9394
   479
    LPGUID guid = (LPGUID) handle;
icculus@10279
   480
	DWORD bufsize;
icculus@10279
   481
	
icculus@2049
   482
    /* Initialize all variables that we clean on shutdown */
icculus@2049
   483
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@2060
   484
        SDL_malloc((sizeof *this->hidden));
icculus@2049
   485
    if (this->hidden == NULL) {
icculus@7038
   486
        return SDL_OutOfMemory();
icculus@2049
   487
    }
icculus@10257
   488
    SDL_zerop(this->hidden);
icculus@2049
   489
icculus@7461
   490
    /* Open the audio device */
icculus@10279
   491
    if (iscapture) {
icculus@10279
   492
        result = pDirectSoundCaptureCreate8(guid, &this->hidden->capture, NULL);
icculus@10279
   493
        if (result != DS_OK) {
icculus@10279
   494
            return SetDSerror("DirectSoundCaptureCreate8", result);
icculus@10279
   495
        }
icculus@10279
   496
    } else {
icculus@10279
   497
        result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
icculus@10279
   498
        if (result != DS_OK) {
icculus@10279
   499
            return SetDSerror("DirectSoundCreate8", result);
icculus@10279
   500
        }
icculus@10279
   501
        result = IDirectSound_SetCooperativeLevel(this->hidden->sound,
icculus@10279
   502
                                                  GetDesktopWindow(),
icculus@10279
   503
                                                  DSSCL_NORMAL);
icculus@10279
   504
        if (result != DS_OK) {
icculus@10279
   505
            return SetDSerror("DirectSound SetCooperativeLevel", result);
icculus@10279
   506
        }
icculus@7461
   507
    }
icculus@7461
   508
icculus@2049
   509
    while ((!valid_format) && (test_format)) {
icculus@2049
   510
        switch (test_format) {
slouken@2060
   511
        case AUDIO_U8:
slouken@2060
   512
        case AUDIO_S16:
slouken@2060
   513
        case AUDIO_S32:
icculus@7449
   514
        case AUDIO_F32:
icculus@7461
   515
            tried_format = SDL_TRUE;
icculus@10279
   516
slouken@2060
   517
            this->spec.format = test_format;
icculus@10279
   518
icculus@10275
   519
            /* Update the fragment size as size in bytes */
icculus@10275
   520
            SDL_CalculateAudioSpec(&this->spec);
icculus@10279
   521
icculus@10279
   522
            bufsize = numchunks * this->spec.size;
icculus@10279
   523
            if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
icculus@10279
   524
                SDL_SetError("Sound buffer size must be between %d and %d",
icculus@10642
   525
                             (int) ((DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks),
icculus@10642
   526
                             (int) (DSBSIZE_MAX / numchunks));
icculus@10279
   527
            } else {
icculus@10279
   528
                int rc;
icculus@10279
   529
				WAVEFORMATEX wfmt;
icculus@10279
   530
                SDL_zero(wfmt);
icculus@10279
   531
                if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
icculus@10279
   532
                    wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
icculus@10279
   533
                } else {
icculus@10279
   534
                    wfmt.wFormatTag = WAVE_FORMAT_PCM;
icculus@10279
   535
                }
icculus@10279
   536
icculus@10279
   537
                wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
icculus@10279
   538
                wfmt.nChannels = this->spec.channels;
icculus@10279
   539
                wfmt.nSamplesPerSec = this->spec.freq;
icculus@10279
   540
                wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
icculus@10279
   541
                wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
icculus@10279
   542
icculus@10279
   543
                rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt);
icculus@10279
   544
                if (rc == 0) {
icculus@10279
   545
                    this->hidden->num_buffers = numchunks;
icculus@10279
   546
                    valid_format = SDL_TRUE;
icculus@10279
   547
                }
icculus@7461
   548
            }
slouken@2060
   549
            break;
icculus@2049
   550
        }
icculus@2049
   551
        test_format = SDL_NextAudioFormat();
icculus@2049
   552
    }
icculus@2049
   553
icculus@2049
   554
    if (!valid_format) {
icculus@7461
   555
        if (tried_format) {
gabomdq@7663
   556
            return -1;  /* CreateSecondary() should have called SDL_SetError(). */
icculus@7461
   557
        }
icculus@7038
   558
        return SDL_SetError("DirectSound: Unsupported audio format");
icculus@2049
   559
    }
icculus@2049
   560
icculus@10279
   561
    /* Playback buffers will auto-start playing in DSOUND_WaitDevice() */
slouken@0
   562
icculus@7038
   563
    return 0;                   /* good to go. */
icculus@2049
   564
}
icculus@2049
   565
icculus@2049
   566
icculus@2049
   567
static void
icculus@2049
   568
DSOUND_Deinitialize(void)
icculus@2049
   569
{
icculus@2049
   570
    DSOUND_Unload();
slouken@0
   571
}
slouken@0
   572
icculus@2049
   573
icculus@2049
   574
static int
slouken@2060
   575
DSOUND_Init(SDL_AudioDriverImpl * impl)
icculus@2049
   576
{
icculus@2049
   577
    if (!DSOUND_Load()) {
icculus@2049
   578
        return 0;
icculus@2049
   579
    }
icculus@2049
   580
icculus@2049
   581
    /* Set the function pointers */
icculus@5587
   582
    impl->DetectDevices = DSOUND_DetectDevices;
icculus@2049
   583
    impl->OpenDevice = DSOUND_OpenDevice;
icculus@2049
   584
    impl->PlayDevice = DSOUND_PlayDevice;
icculus@2049
   585
    impl->WaitDevice = DSOUND_WaitDevice;
icculus@2049
   586
    impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
icculus@10279
   587
    impl->CaptureFromDevice = DSOUND_CaptureFromDevice;
icculus@10279
   588
    impl->FlushCapture = DSOUND_FlushCapture;
icculus@2049
   589
    impl->CloseDevice = DSOUND_CloseDevice;
icculus@9394
   590
    impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
icculus@10279
   591
    impl->Deinitialize = DSOUND_Deinitialize;
icculus@9394
   592
icculus@10279
   593
    impl->HasCaptureSupport = SDL_TRUE;
icculus@2049
   594
icculus@3699
   595
    return 1;   /* this audio target is available. */
icculus@2049
   596
}
icculus@2049
   597
icculus@2049
   598
AudioBootStrap DSOUND_bootstrap = {
icculus@5587
   599
    "directsound", "DirectSound", DSOUND_Init, 0
icculus@2049
   600
};
icculus@2049
   601
slouken@6044
   602
#endif /* SDL_AUDIO_DRIVER_DSOUND */
slouken@6044
   603
slouken@1895
   604
/* vi: set ts=4 sw=4 expandtab: */