Make winmm and directsound audio targets robust against unsupported formats.
It now tries to make sure the hardware can support a given format, and if it
can't, it carries on to the next best format instead of failing completely.
--- a/src/audio/directsound/SDL_directsound.c Sun Jul 14 15:55:34 2013 -0700
+++ b/src/audio/directsound/SDL_directsound.c Sun Jul 14 21:30:16 2013 -0400
@@ -346,7 +346,7 @@
number of audio chunks available in the created buffer.
*/
static int
-CreateSecondary(_THIS, HWND focus, WAVEFORMATEX * wavefmt)
+CreateSecondary(_THIS, HWND focus)
{
LPDIRECTSOUND sndObj = this->hidden->sound;
LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
@@ -356,6 +356,24 @@
DSBUFFERDESC format;
LPVOID pvAudioPtr1, pvAudioPtr2;
DWORD dwAudioBytes1, dwAudioBytes2;
+ WAVEFORMATEX wfmt;
+
+ SDL_zero(wfmt);
+
+ if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
+ wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ } else {
+ wfmt.wFormatTag = WAVE_FORMAT_PCM;
+ }
+
+ wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
+ wfmt.nChannels = this->spec.channels;
+ wfmt.nSamplesPerSec = this->spec.freq;
+ wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
+ wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(&this->spec);
/* Try to set primary mixing privileges */
if (focus) {
@@ -371,7 +389,7 @@
}
/* Try to create the secondary buffer */
- SDL_memset(&format, 0, sizeof(format));
+ SDL_zero(format);
format.dwSize = sizeof(format);
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
if (!focus) {
@@ -386,12 +404,12 @@
DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
}
format.dwReserved = 0;
- format.lpwfxFormat = wavefmt;
+ format.lpwfxFormat = &wfmt;
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
if (result != DS_OK) {
return SetDSerror("DirectSound CreateSoundBuffer", result);
}
- IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
+ IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt);
/* Silence the initial audio buffer */
result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
@@ -437,8 +455,8 @@
DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
{
HRESULT result;
- WAVEFORMATEX waveformat;
- int valid_format = 0;
+ SDL_bool valid_format = SDL_FALSE;
+ SDL_bool tried_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
FindDevGUIDData devguid;
LPGUID guid = NULL;
@@ -465,14 +483,25 @@
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ /* Open the audio device */
+ result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
+ if (result != DS_OK) {
+ DSOUND_CloseDevice(this);
+ return SetDSerror("DirectSoundCreate", result);
+ }
+
while ((!valid_format) && (test_format)) {
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
case AUDIO_F32:
+ tried_format = SDL_TRUE;
this->spec.format = test_format;
- valid_format = 1;
+ this->hidden->num_buffers = CreateSecondary(this, NULL);
+ if (this->hidden->num_buffers > 0) {
+ valid_format = SDL_TRUE;
+ }
break;
}
test_format = SDL_NextAudioFormat();
@@ -480,41 +509,12 @@
if (!valid_format) {
DSOUND_CloseDevice(this);
+ if (tried_format) {
+ return -1; // CreateSecondary() should have called SDL_SetError().
+ }
return SDL_SetError("DirectSound: Unsupported audio format");
}
- SDL_memset(&waveformat, 0, sizeof(waveformat));
-
- if (SDL_AUDIO_ISFLOAT(this->spec.format))
- waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- else
- waveformat.wFormatTag = WAVE_FORMAT_PCM;
-
- waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
- waveformat.nChannels = this->spec.channels;
- waveformat.nSamplesPerSec = this->spec.freq;
- waveformat.nBlockAlign =
- waveformat.nChannels * (waveformat.wBitsPerSample / 8);
- waveformat.nAvgBytesPerSec =
- waveformat.nSamplesPerSec * waveformat.nBlockAlign;
-
- /* Update the fragment size as size in bytes */
- SDL_CalculateAudioSpec(&this->spec);
-
- /* Open the audio device */
- result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
- if (result != DS_OK) {
- DSOUND_CloseDevice(this);
- return SetDSerror("DirectSoundCreate", result);
- }
-
- /* Create the audio buffer to which we write */
- this->hidden->num_buffers = CreateSecondary(this, NULL, &waveformat);
- if (this->hidden->num_buffers < 0) {
- DSOUND_CloseDevice(this);
- return -1;
- }
-
/* The buffer will auto-start playing in DSOUND_WaitDevice() */
this->hidden->mixlen = this->spec.size;
--- a/src/audio/winmm/SDL_winmm.c Sun Jul 14 15:55:34 2013 -0700
+++ b/src/audio/winmm/SDL_winmm.c Sun Jul 14 21:30:16 2013 -0400
@@ -197,6 +197,30 @@
}
}
+static SDL_bool
+PrepWaveFormat(_THIS, UINT_PTR devId, WAVEFORMATEX *pfmt, const int iscapture)
+{
+ SDL_zerop(pfmt);
+
+ if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
+ pfmt->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ } else {
+ pfmt->wFormatTag = WAVE_FORMAT_PCM;
+ }
+ pfmt->wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
+
+ pfmt->nChannels = this->spec.channels;
+ pfmt->nSamplesPerSec = this->spec.freq;
+ pfmt->nBlockAlign = pfmt->nChannels * (pfmt->wBitsPerSample / 8);
+ pfmt->nAvgBytesPerSec = pfmt->nSamplesPerSec * pfmt->nBlockAlign;
+
+ if (iscapture) {
+ return (waveInOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
+ } else {
+ return (waveOutOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
+ }
+}
+
static int
WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
{
@@ -254,18 +278,28 @@
for (i = 0; i < NUM_BUFFERS; ++i)
this->hidden->wavebuf[i].dwUser = 0xFFFF;
+ if (this->spec.channels > 2)
+ this->spec.channels = 2; /* !!! FIXME: is this right? */
+
+ /* Check the buffer size -- minimum of 1/4 second (word aligned) */
+ if (this->spec.samples < (this->spec.freq / 4))
+ this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
+
while ((!valid_datatype) && (test_format)) {
- valid_datatype = 1;
- this->spec.format = test_format;
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
case AUDIO_F32:
- break; /* valid. */
+ this->spec.format = test_format;
+ if (PrepWaveFormat(this, devId, &waveformat, iscapture)) {
+ valid_datatype = 1;
+ } else {
+ test_format = SDL_NextAudioFormat();
+ }
+ break;
default:
- valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
}
@@ -276,30 +310,6 @@
return SDL_SetError("Unsupported audio format");
}
- /* Set basic WAVE format parameters */
- SDL_memset(&waveformat, '\0', sizeof(waveformat));
-
- if (SDL_AUDIO_ISFLOAT(this->spec.format))
- waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- else
- waveformat.wFormatTag = WAVE_FORMAT_PCM;
-
- waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
-
- if (this->spec.channels > 2)
- this->spec.channels = 2; /* !!! FIXME: is this right? */
-
- waveformat.nChannels = this->spec.channels;
- waveformat.nSamplesPerSec = this->spec.freq;
- waveformat.nBlockAlign =
- waveformat.nChannels * (waveformat.wBitsPerSample / 8);
- waveformat.nAvgBytesPerSec =
- waveformat.nSamplesPerSec * waveformat.nBlockAlign;
-
- /* Check the buffer size -- minimum of 1/4 second (word aligned) */
- if (this->spec.samples < (this->spec.freq / 4))
- this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
-
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);