From e53a150e022cf09ab99a4d76e5beb2710024569f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 4 Aug 2011 01:24:22 -0400 Subject: [PATCH] Reworked Windows waveOut code. Implemented multi-device support, changed name to "winmm". --- VisualC/SDL/SDL_VS2005.vcproj | 4 +- VisualC/SDL/SDL_VS2008.vcproj | 4 +- VisualC/SDL/SDL_VS2010.vcxproj | 4 +- configure.in | 8 +- include/SDL_config.h.in | 2 +- include/SDL_config_windows.h | 2 +- src/audio/SDL_audio.c | 6 +- .../SDL_dibaudio.c => winmm/SDL_winmm.c} | 242 ++++++++++++++---- .../SDL_dibaudio.h => winmm/SDL_winmm.h} | 9 +- 9 files changed, 210 insertions(+), 71 deletions(-) rename src/audio/{windib/SDL_dibaudio.c => winmm/SDL_winmm.c} (56%) rename src/audio/{windib/SDL_dibaudio.h => winmm/SDL_winmm.h} (93%) diff --git a/VisualC/SDL/SDL_VS2005.vcproj b/VisualC/SDL/SDL_VS2005.vcproj index 02fe16db2..1de6dc174 100644 --- a/VisualC/SDL/SDL_VS2005.vcproj +++ b/VisualC/SDL/SDL_VS2005.vcproj @@ -796,11 +796,11 @@ > - + @@ -377,7 +377,7 @@ - + diff --git a/configure.in b/configure.in index 4bae56ace..dcd39e6b5 100644 --- a/configure.in +++ b/configure.in @@ -2057,8 +2057,8 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau fi # Set up files for the audio library if test x$enable_audio = xyes; then - AC_DEFINE(SDL_AUDIO_DRIVER_WINWAVEOUT, 1, [ ]) - SOURCES="$SOURCES $srcdir/src/audio/windib/*.c" + AC_DEFINE(SDL_AUDIO_DRIVER_WINMM, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/audio/winmm/*.c" if test x$have_dsound = xyes; then AC_DEFINE(SDL_AUDIO_DRIVER_DSOUND, 1, [ ]) SOURCES="$SOURCES $srcdir/src/audio/directsound/*.c" @@ -2144,8 +2144,8 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau fi # Set up files for the audio library if test x$enable_audio = xyes; then - AC_DEFINE(SDL_AUDIO_DRIVER_WINWAVEOUT, 1, [ ]) - SOURCES="$SOURCES $srcdir/src/audio/windib/*.c" + AC_DEFINE(SDL_AUDIO_DRIVER_WINMM, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/audio/winmm/*.c" if test x$have_dsound = xyes; then AC_DEFINE(SDL_AUDIO_DRIVER_DSOUND, 1, [ ]) SOURCES="$SOURCES $srcdir/src/audio/directsound/*.c" diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 6c5714c15..84d921006 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -195,7 +195,7 @@ #undef SDL_AUDIO_DRIVER_PAUDIO #undef SDL_AUDIO_DRIVER_QSA #undef SDL_AUDIO_DRIVER_SUNAUDIO -#undef SDL_AUDIO_DRIVER_WINWAVEOUT +#undef SDL_AUDIO_DRIVER_WINMM #undef SDL_AUDIO_DRIVER_FUSIONSOUND #undef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC diff --git a/include/SDL_config_windows.h b/include/SDL_config_windows.h index b844b2a8e..6b9295150 100644 --- a/include/SDL_config_windows.h +++ b/include/SDL_config_windows.h @@ -146,7 +146,7 @@ typedef unsigned int uintptr_t; #ifndef _WIN32_WCE #define SDL_AUDIO_DRIVER_DSOUND 1 #endif -#define SDL_AUDIO_DRIVER_WINWAVEOUT 1 +#define SDL_AUDIO_DRIVER_WINMM 1 #define SDL_AUDIO_DRIVER_DISK 1 #define SDL_AUDIO_DRIVER_DUMMY 1 diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 1aaa756c2..7f16a6549 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -53,7 +53,7 @@ extern AudioBootStrap ARTS_bootstrap; extern AudioBootStrap ESD_bootstrap; extern AudioBootStrap NAS_bootstrap; extern AudioBootStrap DSOUND_bootstrap; -extern AudioBootStrap WINWAVEOUT_bootstrap; +extern AudioBootStrap WINMM_bootstrap; extern AudioBootStrap PAUDIO_bootstrap; extern AudioBootStrap BEOSAUDIO_bootstrap; extern AudioBootStrap COREAUDIO_bootstrap; @@ -100,8 +100,8 @@ static const AudioBootStrap *const bootstrap[] = { #if SDL_AUDIO_DRIVER_DSOUND &DSOUND_bootstrap, #endif -#if SDL_AUDIO_DRIVER_WINWAVEOUT - &WINWAVEOUT_bootstrap, +#if SDL_AUDIO_DRIVER_WINMM + &WINMM_bootstrap, #endif #if SDL_AUDIO_DRIVER_PAUDIO &PAUDIO_bootstrap, diff --git a/src/audio/windib/SDL_dibaudio.c b/src/audio/winmm/SDL_winmm.c similarity index 56% rename from src/audio/windib/SDL_dibaudio.c rename to src/audio/winmm/SDL_winmm.c index f2650586d..4a2c30a4e 100644 --- a/src/audio/windib/SDL_dibaudio.c +++ b/src/audio/winmm/SDL_winmm.c @@ -28,23 +28,119 @@ #include "SDL_timer.h" #include "SDL_audio.h" #include "../SDL_audio_c.h" -#include "SDL_dibaudio.h" +#include "SDL_winmm.h" #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) #include "win_ce_semaphore.h" #endif -#if defined(_WIN32_WCE) -#define WINDOWS_OS_NAME "Windows CE/PocketPC" -#elif defined(WIN64) -#define WINDOWS_OS_NAME "Win64" + +/* !!! FIXME: this is a cut and paste of SDL_FreeUnixAudioDevices(), + * !!! FIXME: which is more proof this needs to be managed in SDL_audio.c + * !!! FIXME: and not in drivers. + */ +static void +FreeWaveOutAudioDevices(char ***devices, int *devCount) +{ + int i = *devCount; + if ((i > 0) && (*devices != NULL)) { + while (i--) { + SDL_free((*devices)[i]); + } + } + + if (*devices != NULL) { + SDL_free(*devices); + } + + *devices = NULL; + *devCount = 0; +} + +static char **outputDevices = NULL; +static int outputDeviceCount = 0; +static char **inputDevices = NULL; +static int inputDeviceCount = 0; + +static int +DetectWaveOutDevices(void) +{ + UINT i; + const UINT devcount = waveOutGetNumDevs(); + WAVEOUTCAPS caps; + FreeWaveOutAudioDevices(&outputDevices, &outputDeviceCount); + outputDevices = (const char **) SDL_malloc(sizeof (char *) * devcount); + for (i = 0; i < devcount; i++) { + if (waveOutGetDevCaps(i, &caps, sizeof (caps)) == MMSYSERR_NOERROR) { + outputDevices[outputDeviceCount] = WIN_StringToUTF8(caps.szPname); + if (outputDevices[outputDeviceCount] != NULL) { + outputDeviceCount++; + } + } + } + return outputDeviceCount; +} + +static int +DetectWaveInDevices(void) +{ + UINT i; + const UINT devcount = waveInGetNumDevs(); + WAVEINCAPS caps; + FreeWaveInAudioDevices(&inputDevices, &inputDeviceCount); + inputDevices = (const char **) SDL_malloc(sizeof (char *) * devcount); + for (i = 0; i < devcount; i++) { + if (waveInGetDevCaps(i, &caps, sizeof (caps)) == MMSYSERR_NOERROR) { + inputDevices[inputDeviceCount] = WIN_StringToUTF8(caps.szPname); + if (inputDevices[inputDeviceCount] != NULL) { + inputDeviceCount++; + } + } + } + return inputDeviceCount; +} + +static int +WINMM_DetectDevices(int iscapture) +{ + return (iscapture) ? DetectWaveInDevices() : DetectWaveOutDevices(); +} + +static const char * +WINMM_GetDeviceName(int index, int iscapture) +{ + if ((iscapture) && (index < inputDeviceCount)) { + return inputDevices[index]; + } else if ((!iscapture) && (index < outputDeviceCount)) { + return outputDevices[index]; + } + + SDL_SetError("No such device"); + return NULL; +} + +static void CALLBACK +CaptureSound(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance; + + /* Only service "buffer is filled" messages */ + if (uMsg != WIM_DATA) + return; + + /* Signal that we have a new buffer of data */ +#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) + ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL); #else -#define WINDOWS_OS_NAME "Win32" + ReleaseSemaphore(this->hidden->audio_sem, 1, NULL); #endif +} + /* The Win32 callback for filling the WAVE device */ static void CALLBACK FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, - DWORD dwParam1, DWORD dwParam2) + DWORD_PTR dwParam1, DWORD_PTR dwParam2) { SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance; @@ -77,15 +173,8 @@ SetMMerror(char *function, MMRESULT code) SDL_SetError("%s", errbuf); } -/* Set high priority for the audio thread */ static void -WINWAVEOUT_ThreadInit(_THIS) -{ - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); -} - -void -WINWAVEOUT_WaitDevice(_THIS) +WINMM_WaitDevice(_THIS) { /* Wait for an audio chunk to finish */ #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) @@ -95,25 +184,25 @@ WINWAVEOUT_WaitDevice(_THIS) #endif } -Uint8 * -WINWAVEOUT_GetDeviceBuf(_THIS) +static Uint8 * +WINMM_GetDeviceBuf(_THIS) { return (Uint8 *) (this->hidden-> wavebuf[this->hidden->next_buffer].lpData); } -void -WINWAVEOUT_PlayDevice(_THIS) +static void +WINMM_PlayDevice(_THIS) { /* Queue it up */ - waveOutWrite(this->hidden->sound, + waveOutWrite(this->hidden->hout, &this->hidden->wavebuf[this->hidden->next_buffer], sizeof(this->hidden->wavebuf[0])); this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS; } -void -WINWAVEOUT_WaitDone(_THIS) +static void +WINMM_WaitDone(_THIS) { int i, left; @@ -130,8 +219,8 @@ WINWAVEOUT_WaitDone(_THIS) } while (left > 0); } -void -WINWAVEOUT_CloseDevice(_THIS) +static void +WINMM_CloseDevice(_THIS) { /* Close up audio */ if (this->hidden != NULL) { @@ -146,15 +235,20 @@ WINWAVEOUT_CloseDevice(_THIS) this->hidden->audio_sem = 0; } - if (this->hidden->sound) { - waveOutClose(this->hidden->sound); - this->hidden->sound = 0; + if (this->hidden->hin) { + waveInClose(this->hidden->hin); + this->hidden->hin = 0; + } + + if (this->hidden->hout) { + waveOutClose(this->hidden->hout); + this->hidden->hout = 0; } /* Clean up mixing buffers */ for (i = 0; i < NUM_BUFFERS; ++i) { if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { - waveOutUnprepareHeader(this->hidden->sound, + waveOutUnprepareHeader(this->hidden->hout, &this->hidden->wavebuf[i], sizeof(this->hidden->wavebuf[i])); this->hidden->wavebuf[i].dwUser = 0xFFFF; @@ -172,15 +266,52 @@ WINWAVEOUT_CloseDevice(_THIS) } } -int -WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) +static int +WINMM_OpenDevice(_THIS, const char *devname, int iscapture) { SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); int valid_datatype = 0; MMRESULT result; WAVEFORMATEX waveformat; + UINT_PTR devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */ + char *utf8 = NULL; int i; + if (devname != NULL) { /* specific device requested? */ + if (iscapture) { + const int devcount = (int) waveInGetNumDevs(); + WAVEINCAPS caps; + for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) { + result = waveInGetDevCaps(i, &caps, sizeof (caps)); + if (result != MMSYSERR_NOERROR) + continue; + else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL) + continue; + else if (SDL_strcmp(devname, utf8) == 0) + devId = (UINT_PTR) i; + SDL_free(utf8); + } + } else { + const int devcount = (int) waveOutGetNumDevs(); + WAVEOUTCAPS caps; + for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) { + result = waveOutGetDevCaps(i, &caps, sizeof (caps)); + if (result != MMSYSERR_NOERROR) + continue; + else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL) + continue; + else if (SDL_strcmp(devname, utf8) == 0) + devId = (UINT_PTR) i; + SDL_free(utf8); + } + } + + if (devId == WAVE_MAPPER) { + SDL_SetError("Requested device not found"); + return 0; + } + } + /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); @@ -211,7 +342,7 @@ WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) } if (!valid_datatype) { - WINWAVEOUT_CloseDevice(this); + WINMM_CloseDevice(this); SDL_SetError("Unsupported audio format"); return 0; } @@ -239,11 +370,18 @@ WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Open the audio device */ - result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat, - (DWORD_PTR) FillSound, (DWORD_PTR) this, - CALLBACK_FUNCTION); + if (iscapture) { + result = waveInOpen(&this->hidden->hin, devId, &waveformat, + (DWORD_PTR) CaptureSound, (DWORD_PTR) this, + CALLBACK_FUNCTION); + } else { + result = waveOutOpen(&this->hidden->hout, devId, &waveformat, + (DWORD_PTR) FillSound, (DWORD_PTR) this, + CALLBACK_FUNCTION); + } + if (result != MMSYSERR_NOERROR) { - WINWAVEOUT_CloseDevice(this); + WINMM_CloseDevice(this); SetMMerror("waveOutOpen()", result); return 0; } @@ -252,10 +390,10 @@ WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) { WAVEOUTCAPS caps; - result = waveOutGetDevCaps((UINT) this->hidden->sound, + result = waveOutGetDevCaps((UINT) this->hidden->hout, &caps, sizeof(caps)); if (result != MMSYSERR_NOERROR) { - WINWAVEOUT_CloseDevice(this); + WINMM_CloseDevice(this); SetMMerror("waveOutGetDevCaps()", result); return 0; } @@ -271,7 +409,7 @@ WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); #endif if (this->hidden->audio_sem == NULL) { - WINWAVEOUT_CloseDevice(this); + WINMM_CloseDevice(this); SDL_SetError("Couldn't create semaphore"); return 0; } @@ -280,7 +418,7 @@ WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) this->hidden->mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size); if (this->hidden->mixbuf == NULL) { - WINWAVEOUT_CloseDevice(this); + WINMM_CloseDevice(this); SDL_OutOfMemory(); return 0; } @@ -291,11 +429,11 @@ WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) this->hidden->wavebuf[i].dwFlags = WHDR_DONE; this->hidden->wavebuf[i].lpData = (LPSTR) & this->hidden->mixbuf[i * this->spec.size]; - result = waveOutPrepareHeader(this->hidden->sound, + result = waveOutPrepareHeader(this->hidden->hout, &this->hidden->wavebuf[i], sizeof(this->hidden->wavebuf[i])); if (result != MMSYSERR_NOERROR) { - WINWAVEOUT_CloseDevice(this); + WINMM_CloseDevice(this); SetMMerror("waveOutPrepareHeader()", result); return 0; } @@ -306,23 +444,23 @@ WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) static int -WINWAVEOUT_Init(SDL_AudioDriverImpl * impl) +WINMM_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ - impl->OpenDevice = WINWAVEOUT_OpenDevice; - impl->ThreadInit = WINWAVEOUT_ThreadInit; - impl->PlayDevice = WINWAVEOUT_PlayDevice; - impl->WaitDevice = WINWAVEOUT_WaitDevice; - impl->WaitDone = WINWAVEOUT_WaitDone; - impl->GetDeviceBuf = WINWAVEOUT_GetDeviceBuf; - impl->CloseDevice = WINWAVEOUT_CloseDevice; - impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Is this true? */ + impl->DetectDevices = WINMM_DetectDevices; + impl->GetDeviceName = WINMM_GetDeviceName; + impl->OpenDevice = WINMM_OpenDevice; + impl->PlayDevice = WINMM_PlayDevice; + impl->WaitDevice = WINMM_WaitDevice; + impl->WaitDone = WINMM_WaitDone; + impl->GetDeviceBuf = WINMM_GetDeviceBuf; + impl->CloseDevice = WINMM_CloseDevice; return 1; /* this audio target is available. */ } -AudioBootStrap WINWAVEOUT_bootstrap = { - "waveout", WINDOWS_OS_NAME " WaveOut", WINWAVEOUT_Init, 0 +AudioBootStrap WINMM_bootstrap = { + "winmm", "Windows Waveform Audio", WINMM_Init, 0 }; /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/windib/SDL_dibaudio.h b/src/audio/winmm/SDL_winmm.h similarity index 93% rename from src/audio/windib/SDL_dibaudio.h rename to src/audio/winmm/SDL_winmm.h index 8a2fcc91d..f68ed28d7 100644 --- a/src/audio/windib/SDL_dibaudio.h +++ b/src/audio/winmm/SDL_winmm.h @@ -20,8 +20,8 @@ */ #include "SDL_config.h" -#ifndef _SDL_dibaudio_h -#define _SDL_dibaudio_h +#ifndef _SDL_winmm_h +#define _SDL_winmm_h #include "../SDL_sysaudio.h" @@ -32,13 +32,14 @@ struct SDL_PrivateAudioData { - HWAVEOUT sound; + HWAVEOUT hout; + HWAVEIN hin; HANDLE audio_sem; Uint8 *mixbuf; /* The raw allocated mixing buffer */ WAVEHDR wavebuf[NUM_BUFFERS]; /* Wave audio fragments */ int next_buffer; }; -#endif /* _SDL_dibaudio_h */ +#endif /* _SDL_winmm_h */ /* vi: set ts=4 sw=4 expandtab: */