src/audio/directsound/SDL_directsound.c
author Ryan C. Gordon
Tue, 24 Jan 2017 16:18:25 -0500
changeset 10850 c9dc0068b0e7
parent 10780 4ea5472ed455
child 11811 5d94cb6b24d3
permissions -rw-r--r--
configure: report libsamplerate support status.
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: */