src/audio/winmm/SDL_winmm.c
author Ryan C. Gordon
Sun, 07 Aug 2016 01:48:38 -0400
changeset 10268 a3faa23abdbb
parent 10267 0abfef2f7fc5
child 10278 1e7b4cfe8451
permissions -rw-r--r--
winmm: Try to get full device names from the Windows Registry.
icculus@5588
     1
/*
icculus@5588
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
icculus@5588
     4
icculus@5588
     5
  This software is provided 'as-is', without any express or implied
icculus@5588
     6
  warranty.  In no event will the authors be held liable for any damages
icculus@5588
     7
  arising from the use of this software.
icculus@5588
     8
icculus@5588
     9
  Permission is granted to anyone to use this software for any purpose,
icculus@5588
    10
  including commercial applications, and to alter it and redistribute it
icculus@5588
    11
  freely, subject to the following restrictions:
icculus@5588
    12
icculus@5588
    13
  1. The origin of this software must not be misrepresented; you must not
icculus@5588
    14
     claim that you wrote the original software. If you use this software
icculus@5588
    15
     in a product, an acknowledgment in the product documentation would be
icculus@5588
    16
     appreciated but is not required.
icculus@5588
    17
  2. Altered source versions must be plainly marked as such, and must not be
icculus@5588
    18
     misrepresented as being the original software.
icculus@5588
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@5588
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
icculus@5588
    22
slouken@6044
    23
#if SDL_AUDIO_DRIVER_WINMM
slouken@6044
    24
icculus@5588
    25
/* Allow access to a raw mixing buffer */
icculus@5588
    26
icculus@5588
    27
#include "../../core/windows/SDL_windows.h"
icculus@5588
    28
#include <mmsystem.h>
icculus@5588
    29
icculus@10266
    30
#include "SDL_assert.h"
icculus@5588
    31
#include "SDL_timer.h"
icculus@5588
    32
#include "SDL_audio.h"
icculus@5588
    33
#include "../SDL_audio_c.h"
icculus@5588
    34
#include "SDL_winmm.h"
icculus@5588
    35
icculus@7449
    36
#ifndef WAVE_FORMAT_IEEE_FLOAT
icculus@7449
    37
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
icculus@7449
    38
#endif
icculus@7449
    39
icculus@10268
    40
/*
icculus@10267
    41
WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's
icculus@10267
    42
longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which
icculus@10267
    43
will give you a name GUID. The full name is in the Windows Registry under
icculus@10267
    44
that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories
icculus@10267
    45
icculus@10267
    46
Note that drivers can report GUID_NULL for the name GUID, in which case,
icculus@10267
    47
Windows makes a best effort to fill in those 31 bytes in the usual place.
icculus@10267
    48
This info summarized from MSDN:
icculus@10267
    49
icculus@10267
    50
http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx
icculus@10267
    51
icculus@10268
    52
Always look this up in the registry if possible, because the strings are
icculus@10268
    53
different! At least on Win10, I see "Yeti Stereo Microphone" in the
icculus@10268
    54
Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh.
icculus@10267
    55
*/
icculus@10268
    56
static char *
icculus@10268
    57
LookupDeviceName(const WCHAR *name, const GUID *guid)
icculus@10268
    58
{
icculus@10268
    59
    static const GUID nullguid = { 0 };
icculus@10268
    60
    const unsigned char *ptr;
icculus@10268
    61
    char keystr[128];
icculus@10268
    62
    WCHAR *strw = NULL;
icculus@10268
    63
    SDL_bool rc;
icculus@10268
    64
    HKEY hkey;
icculus@10268
    65
    DWORD len = 0;
icculus@10268
    66
    char *retval = NULL;
icculus@10268
    67
icculus@10268
    68
    if (SDL_memcmp(guid, &nullguid, sizeof (*guid)) == 0) {
icculus@10268
    69
        return WIN_StringToUTF8(name);  /* No GUID, go with what we've got. */
icculus@10268
    70
    }
icculus@10268
    71
icculus@10268
    72
    ptr = (const char *) guid;
icculus@10268
    73
    SDL_snprintf(keystr, sizeof (keystr),
icculus@10268
    74
        "System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
icculus@10268
    75
        ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6],
icculus@10268
    76
        ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
icculus@10268
    77
icculus@10268
    78
    strw = WIN_UTF8ToString(keystr);
icculus@10268
    79
    rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS);
icculus@10268
    80
    SDL_free(strw);
icculus@10268
    81
    if (!rc) {
icculus@10268
    82
        return WIN_StringToUTF8(name);  /* oh well. */
icculus@10268
    83
    }
icculus@10268
    84
icculus@10268
    85
    rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS);
icculus@10268
    86
    if (!rc) {
icculus@10268
    87
        RegCloseKey(hkey);
icculus@10268
    88
        return WIN_StringToUTF8(name);  /* oh well. */
icculus@10268
    89
    }
icculus@10268
    90
icculus@10268
    91
    strw = (WCHAR *) SDL_malloc(len + sizeof (WCHAR));
icculus@10268
    92
    if (!strw) {
icculus@10268
    93
        RegCloseKey(hkey);
icculus@10268
    94
        return WIN_StringToUTF8(name);  /* oh well. */
icculus@10268
    95
    }
icculus@10268
    96
icculus@10268
    97
    rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE) strw, &len) == ERROR_SUCCESS);
icculus@10268
    98
    RegCloseKey(hkey);
icculus@10268
    99
    if (!rc) {
icculus@10268
   100
        SDL_free(strw);
icculus@10268
   101
        return WIN_StringToUTF8(name);  /* oh well. */
icculus@10268
   102
    }
icculus@10268
   103
icculus@10268
   104
    strw[len / 2] = 0;  /* make sure it's null-terminated. */
icculus@10268
   105
icculus@10268
   106
    retval = WIN_StringToUTF8(strw);
icculus@10268
   107
    SDL_free(strw);
icculus@10268
   108
    return retval ? retval : WIN_StringToUTF8(name);
icculus@10268
   109
}
icculus@10267
   110
icculus@9394
   111
#define DETECT_DEV_IMPL(iscap, typ, capstyp) \
icculus@9394
   112
static void DetectWave##typ##Devs(void) { \
icculus@9394
   113
    const UINT iscapture = iscap ? 1 : 0; \
icculus@5593
   114
    const UINT devcount = wave##typ##GetNumDevs(); \
icculus@10268
   115
    capstyp##2W caps; \
icculus@5593
   116
    UINT i; \
icculus@5593
   117
    for (i = 0; i < devcount; i++) { \
icculus@10268
   118
	if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
icculus@10268
   119
            char *name = LookupDeviceName(caps.szPname,&caps.NameGuid); \
icculus@5593
   120
            if (name != NULL) { \
icculus@9410
   121
                SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \
icculus@5593
   122
                SDL_free(name); \
icculus@5593
   123
            } \
icculus@5593
   124
        } \
icculus@5593
   125
    } \
icculus@5588
   126
}
icculus@5588
   127
icculus@9394
   128
DETECT_DEV_IMPL(SDL_FALSE, Out, WAVEOUTCAPS)
icculus@9394
   129
DETECT_DEV_IMPL(SDL_TRUE, In, WAVEINCAPS)
icculus@5588
   130
icculus@5593
   131
static void
icculus@9404
   132
WINMM_DetectDevices(void)
icculus@5588
   133
{
icculus@9394
   134
    DetectWaveInDevs();
icculus@9394
   135
    DetectWaveOutDevs();
icculus@5588
   136
}
icculus@5588
   137
icculus@5588
   138
static void CALLBACK
icculus@5588
   139
CaptureSound(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
icculus@5588
   140
          DWORD_PTR dwParam1, DWORD_PTR dwParam2)
icculus@5588
   141
{
icculus@5588
   142
    SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
icculus@5588
   143
icculus@5588
   144
    /* Only service "buffer is filled" messages */
icculus@5588
   145
    if (uMsg != WIM_DATA)
icculus@5588
   146
        return;
icculus@5588
   147
icculus@5588
   148
    /* Signal that we have a new buffer of data */
icculus@5588
   149
    ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
icculus@5588
   150
}
icculus@5588
   151
icculus@5588
   152
icculus@5588
   153
/* The Win32 callback for filling the WAVE device */
icculus@5588
   154
static void CALLBACK
icculus@5588
   155
FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
icculus@5588
   156
          DWORD_PTR dwParam1, DWORD_PTR dwParam2)
icculus@5588
   157
{
icculus@5588
   158
    SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
icculus@5588
   159
icculus@5588
   160
    /* Only service "buffer done playing" messages */
icculus@5588
   161
    if (uMsg != WOM_DONE)
icculus@5588
   162
        return;
icculus@5588
   163
icculus@5588
   164
    /* Signal that we are done playing a buffer */
icculus@5588
   165
    ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
icculus@5588
   166
}
icculus@5588
   167
icculus@7038
   168
static int
icculus@5588
   169
SetMMerror(char *function, MMRESULT code)
icculus@5588
   170
{
slouken@8585
   171
    int len;
icculus@5588
   172
    char errbuf[MAXERRORLENGTH];
icculus@5588
   173
    wchar_t werrbuf[MAXERRORLENGTH];
icculus@5588
   174
icculus@5588
   175
    SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
slouken@8585
   176
    len = SDL_static_cast(int, SDL_strlen(errbuf));
icculus@5588
   177
icculus@5588
   178
    waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH - len);
icculus@5588
   179
    WideCharToMultiByte(CP_ACP, 0, werrbuf, -1, errbuf + len,
icculus@5588
   180
                        MAXERRORLENGTH - len, NULL, NULL);
icculus@5588
   181
icculus@7038
   182
    return SDL_SetError("%s", errbuf);
icculus@5588
   183
}
icculus@5588
   184
icculus@5588
   185
static void
icculus@5588
   186
WINMM_WaitDevice(_THIS)
icculus@5588
   187
{
icculus@5588
   188
    /* Wait for an audio chunk to finish */
icculus@5588
   189
    WaitForSingleObject(this->hidden->audio_sem, INFINITE);
icculus@5588
   190
}
icculus@5588
   191
icculus@5588
   192
static Uint8 *
icculus@5588
   193
WINMM_GetDeviceBuf(_THIS)
icculus@5588
   194
{
icculus@5588
   195
    return (Uint8 *) (this->hidden->
icculus@5588
   196
                      wavebuf[this->hidden->next_buffer].lpData);
icculus@5588
   197
}
icculus@5588
   198
icculus@5588
   199
static void
icculus@5588
   200
WINMM_PlayDevice(_THIS)
icculus@5588
   201
{
icculus@5588
   202
    /* Queue it up */
icculus@5588
   203
    waveOutWrite(this->hidden->hout,
icculus@5588
   204
                 &this->hidden->wavebuf[this->hidden->next_buffer],
icculus@5588
   205
                 sizeof(this->hidden->wavebuf[0]));
icculus@5588
   206
    this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
icculus@5588
   207
}
icculus@5588
   208
icculus@5588
   209
static void
icculus@5588
   210
WINMM_WaitDone(_THIS)
icculus@5588
   211
{
icculus@5588
   212
    int i, left;
icculus@5588
   213
icculus@5588
   214
    do {
icculus@5588
   215
        left = NUM_BUFFERS;
icculus@5588
   216
        for (i = 0; i < NUM_BUFFERS; ++i) {
icculus@5588
   217
            if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
icculus@5588
   218
                --left;
icculus@5588
   219
            }
icculus@5588
   220
        }
icculus@5588
   221
        if (left > 0) {
icculus@5588
   222
            SDL_Delay(100);
icculus@5588
   223
        }
icculus@5588
   224
    } while (left > 0);
icculus@5588
   225
}
icculus@5588
   226
icculus@10266
   227
static int
icculus@10266
   228
WINMM_CaptureFromDevice(_THIS, void *buffer, int buflen)
icculus@10266
   229
{
icculus@10266
   230
    const int nextbuf = this->hidden->next_buffer;
icculus@10266
   231
    MMRESULT result;
icculus@10266
   232
icculus@10266
   233
    SDL_assert(buflen == this->spec.size);
icculus@10266
   234
icculus@10266
   235
    /* Wait for an audio chunk to finish */
icculus@10266
   236
    WaitForSingleObject(this->hidden->audio_sem, INFINITE);
icculus@10266
   237
icculus@10266
   238
    /* Copy it to caller's buffer... */
icculus@10266
   239
    SDL_memcpy(buffer, this->hidden->wavebuf[nextbuf].lpData, this->spec.size);
icculus@10266
   240
icculus@10266
   241
    /* requeue the buffer that just finished. */
icculus@10266
   242
    result = waveInAddBuffer(this->hidden->hin,
icculus@10266
   243
                             &this->hidden->wavebuf[nextbuf],
icculus@10266
   244
                             sizeof (this->hidden->wavebuf[nextbuf]));
icculus@10266
   245
    if (result != MMSYSERR_NOERROR) {
icculus@10266
   246
        return -1;  /* uhoh! Disable the device. */
icculus@10266
   247
    }
icculus@10266
   248
icculus@10266
   249
    /* queue the next buffer in sequence, next time. */
icculus@10266
   250
    this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
icculus@10266
   251
    return this->spec.size;
icculus@10266
   252
}
icculus@10266
   253
icculus@10266
   254
static void
icculus@10266
   255
WINMM_FlushCapture(_THIS)
icculus@10266
   256
{
icculus@10266
   257
    /* Wait for an audio chunk to finish */
icculus@10266
   258
    if (WaitForSingleObject(this->hidden->audio_sem, 0) == WAIT_OBJECT_0) {
icculus@10266
   259
        const int nextbuf = this->hidden->next_buffer;
icculus@10266
   260
        /* requeue the buffer that just finished without reading from it. */
icculus@10266
   261
        waveInAddBuffer(this->hidden->hin,
icculus@10266
   262
                        &this->hidden->wavebuf[nextbuf],
icculus@10266
   263
                        sizeof (this->hidden->wavebuf[nextbuf]));
icculus@10266
   264
        this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
icculus@10266
   265
    }
icculus@10266
   266
}
icculus@10266
   267
icculus@5588
   268
static void
icculus@5588
   269
WINMM_CloseDevice(_THIS)
icculus@5588
   270
{
icculus@10255
   271
    int i;
icculus@5588
   272
icculus@10266
   273
    if (this->hidden->hout) {
icculus@10266
   274
        waveOutReset(this->hidden->hout);
icculus@5588
   275
icculus@10266
   276
        /* Clean up mixing buffers */
icculus@10266
   277
        for (i = 0; i < NUM_BUFFERS; ++i) {
icculus@10266
   278
            if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
icculus@10266
   279
                waveOutUnprepareHeader(this->hidden->hout,
icculus@10266
   280
                                       &this->hidden->wavebuf[i],
icculus@10266
   281
                                       sizeof (this->hidden->wavebuf[i]));
icculus@10266
   282
            }
icculus@5588
   283
        }
icculus@10266
   284
icculus@10266
   285
        waveOutClose(this->hidden->hout);
icculus@10255
   286
    }
icculus@5588
   287
icculus@10255
   288
    if (this->hidden->hin) {
icculus@10266
   289
        waveInReset(this->hidden->hin);
icculus@10266
   290
icculus@10266
   291
        /* Clean up mixing buffers */
icculus@10266
   292
        for (i = 0; i < NUM_BUFFERS; ++i) {
icculus@10266
   293
            if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
icculus@10266
   294
                waveInUnprepareHeader(this->hidden->hin,
icculus@10266
   295
                                       &this->hidden->wavebuf[i],
icculus@10266
   296
                                       sizeof (this->hidden->wavebuf[i]));
icculus@10266
   297
            }
icculus@10266
   298
        }
icculus@10255
   299
        waveInClose(this->hidden->hin);
icculus@10255
   300
    }
icculus@5588
   301
icculus@10266
   302
    if (this->hidden->audio_sem) {
icculus@10266
   303
        CloseHandle(this->hidden->audio_sem);
icculus@10255
   304
    }
slouken@7332
   305
icculus@10255
   306
    SDL_free(this->hidden->mixbuf);
icculus@10255
   307
    SDL_free(this->hidden);
icculus@5588
   308
}
icculus@5588
   309
icculus@7461
   310
static SDL_bool
slouken@8585
   311
PrepWaveFormat(_THIS, UINT devId, WAVEFORMATEX *pfmt, const int iscapture)
icculus@7461
   312
{
icculus@7461
   313
    SDL_zerop(pfmt);
icculus@7461
   314
icculus@7461
   315
    if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
icculus@7461
   316
        pfmt->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
icculus@7461
   317
    } else {
icculus@7461
   318
        pfmt->wFormatTag = WAVE_FORMAT_PCM;
icculus@7461
   319
    }
icculus@7461
   320
    pfmt->wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
icculus@7461
   321
icculus@7461
   322
    pfmt->nChannels = this->spec.channels;
icculus@7461
   323
    pfmt->nSamplesPerSec = this->spec.freq;
icculus@7461
   324
    pfmt->nBlockAlign = pfmt->nChannels * (pfmt->wBitsPerSample / 8);
icculus@7461
   325
    pfmt->nAvgBytesPerSec = pfmt->nSamplesPerSec * pfmt->nBlockAlign;
icculus@7461
   326
icculus@7461
   327
    if (iscapture) {
icculus@7461
   328
        return (waveInOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
icculus@7461
   329
    } else {
icculus@7461
   330
        return (waveOutOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
icculus@7461
   331
    }
icculus@7461
   332
}
icculus@7461
   333
icculus@5588
   334
static int
icculus@9394
   335
WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
icculus@5588
   336
{
icculus@5588
   337
    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
icculus@5588
   338
    int valid_datatype = 0;
icculus@5588
   339
    MMRESULT result;
icculus@5588
   340
    WAVEFORMATEX waveformat;
slouken@8585
   341
    UINT devId = WAVE_MAPPER;  /* WAVE_MAPPER == choose system's default */
slouken@8585
   342
    UINT i;
icculus@5588
   343
icculus@9394
   344
    if (handle != NULL) {  /* specific device requested? */
icculus@9410
   345
        /* -1 because we increment the original value to avoid NULL. */
icculus@9410
   346
        const size_t val = ((size_t) handle) - 1;
icculus@9394
   347
        devId = (UINT) val;
icculus@5588
   348
    }
icculus@5588
   349
icculus@5588
   350
    /* Initialize all variables that we clean on shutdown */
icculus@5588
   351
    this->hidden = (struct SDL_PrivateAudioData *)
icculus@5588
   352
        SDL_malloc((sizeof *this->hidden));
icculus@5588
   353
    if (this->hidden == NULL) {
icculus@7038
   354
        return SDL_OutOfMemory();
icculus@5588
   355
    }
icculus@10257
   356
    SDL_zerop(this->hidden);
icculus@5588
   357
icculus@5588
   358
    /* Initialize the wavebuf structures for closing */
icculus@5588
   359
    for (i = 0; i < NUM_BUFFERS; ++i)
icculus@5588
   360
        this->hidden->wavebuf[i].dwUser = 0xFFFF;
icculus@5588
   361
icculus@7461
   362
    if (this->spec.channels > 2)
icculus@7461
   363
        this->spec.channels = 2;        /* !!! FIXME: is this right? */
icculus@7461
   364
icculus@5588
   365
    while ((!valid_datatype) && (test_format)) {
icculus@5588
   366
        switch (test_format) {
icculus@5588
   367
        case AUDIO_U8:
icculus@5588
   368
        case AUDIO_S16:
icculus@5588
   369
        case AUDIO_S32:
icculus@7449
   370
        case AUDIO_F32:
icculus@7461
   371
            this->spec.format = test_format;
icculus@7461
   372
            if (PrepWaveFormat(this, devId, &waveformat, iscapture)) {
icculus@7461
   373
                valid_datatype = 1;
icculus@7461
   374
            } else {
icculus@7461
   375
                test_format = SDL_NextAudioFormat();
icculus@7461
   376
            }
icculus@7461
   377
            break;
icculus@5588
   378
icculus@5588
   379
        default:
icculus@5588
   380
            test_format = SDL_NextAudioFormat();
icculus@5588
   381
            break;
icculus@5588
   382
        }
icculus@5588
   383
    }
icculus@5588
   384
icculus@5588
   385
    if (!valid_datatype) {
icculus@7038
   386
        return SDL_SetError("Unsupported audio format");
icculus@5588
   387
    }
icculus@5588
   388
icculus@5588
   389
    /* Update the fragment size as size in bytes */
icculus@5588
   390
    SDL_CalculateAudioSpec(&this->spec);
icculus@5588
   391
icculus@5588
   392
    /* Open the audio device */
icculus@5588
   393
    if (iscapture) {
icculus@5588
   394
        result = waveInOpen(&this->hidden->hin, devId, &waveformat,
icculus@5588
   395
                             (DWORD_PTR) CaptureSound, (DWORD_PTR) this,
icculus@5588
   396
                             CALLBACK_FUNCTION);
icculus@10266
   397
        if (result != MMSYSERR_NOERROR) {
icculus@10266
   398
            return SetMMerror("waveInOpen()", result);
icculus@10266
   399
        }
icculus@5588
   400
    } else {
icculus@5588
   401
        result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
icculus@5588
   402
                             (DWORD_PTR) FillSound, (DWORD_PTR) this,
icculus@5588
   403
                             CALLBACK_FUNCTION);
icculus@10266
   404
        if (result != MMSYSERR_NOERROR) {
icculus@10266
   405
            return SetMMerror("waveOutOpen()", result);
icculus@10266
   406
        }
icculus@5588
   407
    }
icculus@5588
   408
icculus@5588
   409
#ifdef SOUND_DEBUG
icculus@5588
   410
    /* Check the sound device we retrieved */
icculus@5588
   411
    {
icculus@10266
   412
        if (iscapture) {
icculus@10266
   413
            WAVEINCAPS caps;
icculus@10266
   414
            result = waveInGetDevCaps((UINT) this->hidden->hout,
icculus@10266
   415
                                      &caps, sizeof (caps));
icculus@10266
   416
            if (result != MMSYSERR_NOERROR) {
icculus@10266
   417
                return SetMMerror("waveInGetDevCaps()", result);
icculus@10266
   418
            }
icculus@10266
   419
            printf("Audio device: %s\n", caps.szPname);
icculus@10266
   420
        } else {
icculus@10266
   421
            WAVEOUTCAPS caps;
icculus@10266
   422
            result = waveOutGetDevCaps((UINT) this->hidden->hout,
icculus@10266
   423
                                       &caps, sizeof(caps));
icculus@10266
   424
            if (result != MMSYSERR_NOERROR) {
icculus@10266
   425
                return SetMMerror("waveOutGetDevCaps()", result);
icculus@10266
   426
            }
icculus@10266
   427
            printf("Audio device: %s\n", caps.szPname);
icculus@5588
   428
        }
icculus@5588
   429
    }
icculus@5588
   430
#endif
icculus@5588
   431
icculus@5588
   432
    /* Create the audio buffer semaphore */
icculus@5588
   433
    this->hidden->audio_sem =
icculus@10266
   434
		CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
icculus@5588
   435
    if (this->hidden->audio_sem == NULL) {
icculus@7038
   436
        return SDL_SetError("Couldn't create semaphore");
icculus@5588
   437
    }
icculus@5588
   438
icculus@5588
   439
    /* Create the sound buffers */
icculus@5588
   440
    this->hidden->mixbuf =
icculus@5588
   441
        (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
icculus@5588
   442
    if (this->hidden->mixbuf == NULL) {
icculus@7038
   443
        return SDL_OutOfMemory();
icculus@5588
   444
    }
icculus@10257
   445
icculus@10257
   446
    SDL_zero(this->hidden->wavebuf);
icculus@5588
   447
    for (i = 0; i < NUM_BUFFERS; ++i) {
icculus@5588
   448
        this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
icculus@5588
   449
        this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
icculus@5588
   450
        this->hidden->wavebuf[i].lpData =
icculus@5588
   451
            (LPSTR) & this->hidden->mixbuf[i * this->spec.size];
icculus@10266
   452
icculus@10266
   453
        if (iscapture) {
icculus@10266
   454
            result = waveInPrepareHeader(this->hidden->hin,
icculus@10266
   455
                                          &this->hidden->wavebuf[i],
icculus@10266
   456
                                          sizeof(this->hidden->wavebuf[i]));
icculus@10266
   457
            if (result != MMSYSERR_NOERROR) {
icculus@10266
   458
                return SetMMerror("waveInPrepareHeader()", result);
icculus@10266
   459
            }
icculus@10266
   460
icculus@10266
   461
            result = waveInAddBuffer(this->hidden->hin,
icculus@10266
   462
                                     &this->hidden->wavebuf[i],
icculus@10266
   463
                                     sizeof(this->hidden->wavebuf[i]));
icculus@10266
   464
            if (result != MMSYSERR_NOERROR) {
icculus@10266
   465
                return SetMMerror("waveInAddBuffer()", result);
icculus@10266
   466
            }
icculus@10266
   467
        } else {
icculus@10266
   468
            result = waveOutPrepareHeader(this->hidden->hout,
icculus@10266
   469
                                          &this->hidden->wavebuf[i],
icculus@10266
   470
                                          sizeof(this->hidden->wavebuf[i]));
icculus@10266
   471
            if (result != MMSYSERR_NOERROR) {
icculus@10266
   472
                return SetMMerror("waveOutPrepareHeader()", result);
icculus@10266
   473
            }
icculus@10266
   474
        }
icculus@10266
   475
    }
icculus@10266
   476
icculus@10266
   477
    if (iscapture) {
icculus@10266
   478
        result = waveInStart(this->hidden->hin);
icculus@5588
   479
        if (result != MMSYSERR_NOERROR) {
icculus@10266
   480
            return SetMMerror("waveInStart()", result);
icculus@5588
   481
        }
icculus@5588
   482
    }
icculus@5588
   483
icculus@7038
   484
    return 0;                   /* Ready to go! */
icculus@5588
   485
}
icculus@5588
   486
icculus@5588
   487
icculus@5588
   488
static int
icculus@5588
   489
WINMM_Init(SDL_AudioDriverImpl * impl)
icculus@5588
   490
{
icculus@5588
   491
    /* Set the function pointers */
icculus@5588
   492
    impl->DetectDevices = WINMM_DetectDevices;
icculus@5588
   493
    impl->OpenDevice = WINMM_OpenDevice;
icculus@5588
   494
    impl->PlayDevice = WINMM_PlayDevice;
icculus@5588
   495
    impl->WaitDevice = WINMM_WaitDevice;
icculus@5588
   496
    impl->WaitDone = WINMM_WaitDone;
icculus@5588
   497
    impl->GetDeviceBuf = WINMM_GetDeviceBuf;
icculus@10266
   498
    impl->CaptureFromDevice = WINMM_CaptureFromDevice;
icculus@10266
   499
    impl->FlushCapture = WINMM_FlushCapture;
icculus@5588
   500
    impl->CloseDevice = WINMM_CloseDevice;
icculus@5588
   501
icculus@10266
   502
    impl->HasCaptureSupport = SDL_TRUE;
icculus@10266
   503
icculus@5588
   504
    return 1;   /* this audio target is available. */
icculus@5588
   505
}
icculus@5588
   506
icculus@5588
   507
AudioBootStrap WINMM_bootstrap = {
icculus@5588
   508
    "winmm", "Windows Waveform Audio", WINMM_Init, 0
icculus@5588
   509
};
icculus@5588
   510
slouken@6044
   511
#endif /* SDL_AUDIO_DRIVER_WINMM */
slouken@6044
   512
icculus@5588
   513
/* vi: set ts=4 sw=4 expandtab: */