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.
1.1 --- a/src/audio/directsound/SDL_directsound.c Sun Jul 14 15:55:34 2013 -0700
1.2 +++ b/src/audio/directsound/SDL_directsound.c Sun Jul 14 21:30:16 2013 -0400
1.3 @@ -346,7 +346,7 @@
1.4 number of audio chunks available in the created buffer.
1.5 */
1.6 static int
1.7 -CreateSecondary(_THIS, HWND focus, WAVEFORMATEX * wavefmt)
1.8 +CreateSecondary(_THIS, HWND focus)
1.9 {
1.10 LPDIRECTSOUND sndObj = this->hidden->sound;
1.11 LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
1.12 @@ -356,6 +356,24 @@
1.13 DSBUFFERDESC format;
1.14 LPVOID pvAudioPtr1, pvAudioPtr2;
1.15 DWORD dwAudioBytes1, dwAudioBytes2;
1.16 + WAVEFORMATEX wfmt;
1.17 +
1.18 + SDL_zero(wfmt);
1.19 +
1.20 + if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
1.21 + wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
1.22 + } else {
1.23 + wfmt.wFormatTag = WAVE_FORMAT_PCM;
1.24 + }
1.25 +
1.26 + wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
1.27 + wfmt.nChannels = this->spec.channels;
1.28 + wfmt.nSamplesPerSec = this->spec.freq;
1.29 + wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
1.30 + wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
1.31 +
1.32 + /* Update the fragment size as size in bytes */
1.33 + SDL_CalculateAudioSpec(&this->spec);
1.34
1.35 /* Try to set primary mixing privileges */
1.36 if (focus) {
1.37 @@ -371,7 +389,7 @@
1.38 }
1.39
1.40 /* Try to create the secondary buffer */
1.41 - SDL_memset(&format, 0, sizeof(format));
1.42 + SDL_zero(format);
1.43 format.dwSize = sizeof(format);
1.44 format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
1.45 if (!focus) {
1.46 @@ -386,12 +404,12 @@
1.47 DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
1.48 }
1.49 format.dwReserved = 0;
1.50 - format.lpwfxFormat = wavefmt;
1.51 + format.lpwfxFormat = &wfmt;
1.52 result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
1.53 if (result != DS_OK) {
1.54 return SetDSerror("DirectSound CreateSoundBuffer", result);
1.55 }
1.56 - IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
1.57 + IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt);
1.58
1.59 /* Silence the initial audio buffer */
1.60 result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
1.61 @@ -437,8 +455,8 @@
1.62 DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
1.63 {
1.64 HRESULT result;
1.65 - WAVEFORMATEX waveformat;
1.66 - int valid_format = 0;
1.67 + SDL_bool valid_format = SDL_FALSE;
1.68 + SDL_bool tried_format = SDL_FALSE;
1.69 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
1.70 FindDevGUIDData devguid;
1.71 LPGUID guid = NULL;
1.72 @@ -465,14 +483,25 @@
1.73 }
1.74 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
1.75
1.76 + /* Open the audio device */
1.77 + result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
1.78 + if (result != DS_OK) {
1.79 + DSOUND_CloseDevice(this);
1.80 + return SetDSerror("DirectSoundCreate", result);
1.81 + }
1.82 +
1.83 while ((!valid_format) && (test_format)) {
1.84 switch (test_format) {
1.85 case AUDIO_U8:
1.86 case AUDIO_S16:
1.87 case AUDIO_S32:
1.88 case AUDIO_F32:
1.89 + tried_format = SDL_TRUE;
1.90 this->spec.format = test_format;
1.91 - valid_format = 1;
1.92 + this->hidden->num_buffers = CreateSecondary(this, NULL);
1.93 + if (this->hidden->num_buffers > 0) {
1.94 + valid_format = SDL_TRUE;
1.95 + }
1.96 break;
1.97 }
1.98 test_format = SDL_NextAudioFormat();
1.99 @@ -480,41 +509,12 @@
1.100
1.101 if (!valid_format) {
1.102 DSOUND_CloseDevice(this);
1.103 + if (tried_format) {
1.104 + return -1; // CreateSecondary() should have called SDL_SetError().
1.105 + }
1.106 return SDL_SetError("DirectSound: Unsupported audio format");
1.107 }
1.108
1.109 - SDL_memset(&waveformat, 0, sizeof(waveformat));
1.110 -
1.111 - if (SDL_AUDIO_ISFLOAT(this->spec.format))
1.112 - waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
1.113 - else
1.114 - waveformat.wFormatTag = WAVE_FORMAT_PCM;
1.115 -
1.116 - waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
1.117 - waveformat.nChannels = this->spec.channels;
1.118 - waveformat.nSamplesPerSec = this->spec.freq;
1.119 - waveformat.nBlockAlign =
1.120 - waveformat.nChannels * (waveformat.wBitsPerSample / 8);
1.121 - waveformat.nAvgBytesPerSec =
1.122 - waveformat.nSamplesPerSec * waveformat.nBlockAlign;
1.123 -
1.124 - /* Update the fragment size as size in bytes */
1.125 - SDL_CalculateAudioSpec(&this->spec);
1.126 -
1.127 - /* Open the audio device */
1.128 - result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
1.129 - if (result != DS_OK) {
1.130 - DSOUND_CloseDevice(this);
1.131 - return SetDSerror("DirectSoundCreate", result);
1.132 - }
1.133 -
1.134 - /* Create the audio buffer to which we write */
1.135 - this->hidden->num_buffers = CreateSecondary(this, NULL, &waveformat);
1.136 - if (this->hidden->num_buffers < 0) {
1.137 - DSOUND_CloseDevice(this);
1.138 - return -1;
1.139 - }
1.140 -
1.141 /* The buffer will auto-start playing in DSOUND_WaitDevice() */
1.142 this->hidden->mixlen = this->spec.size;
1.143
2.1 --- a/src/audio/winmm/SDL_winmm.c Sun Jul 14 15:55:34 2013 -0700
2.2 +++ b/src/audio/winmm/SDL_winmm.c Sun Jul 14 21:30:16 2013 -0400
2.3 @@ -197,6 +197,30 @@
2.4 }
2.5 }
2.6
2.7 +static SDL_bool
2.8 +PrepWaveFormat(_THIS, UINT_PTR devId, WAVEFORMATEX *pfmt, const int iscapture)
2.9 +{
2.10 + SDL_zerop(pfmt);
2.11 +
2.12 + if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
2.13 + pfmt->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
2.14 + } else {
2.15 + pfmt->wFormatTag = WAVE_FORMAT_PCM;
2.16 + }
2.17 + pfmt->wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
2.18 +
2.19 + pfmt->nChannels = this->spec.channels;
2.20 + pfmt->nSamplesPerSec = this->spec.freq;
2.21 + pfmt->nBlockAlign = pfmt->nChannels * (pfmt->wBitsPerSample / 8);
2.22 + pfmt->nAvgBytesPerSec = pfmt->nSamplesPerSec * pfmt->nBlockAlign;
2.23 +
2.24 + if (iscapture) {
2.25 + return (waveInOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
2.26 + } else {
2.27 + return (waveOutOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
2.28 + }
2.29 +}
2.30 +
2.31 static int
2.32 WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
2.33 {
2.34 @@ -254,18 +278,28 @@
2.35 for (i = 0; i < NUM_BUFFERS; ++i)
2.36 this->hidden->wavebuf[i].dwUser = 0xFFFF;
2.37
2.38 + if (this->spec.channels > 2)
2.39 + this->spec.channels = 2; /* !!! FIXME: is this right? */
2.40 +
2.41 + /* Check the buffer size -- minimum of 1/4 second (word aligned) */
2.42 + if (this->spec.samples < (this->spec.freq / 4))
2.43 + this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
2.44 +
2.45 while ((!valid_datatype) && (test_format)) {
2.46 - valid_datatype = 1;
2.47 - this->spec.format = test_format;
2.48 switch (test_format) {
2.49 case AUDIO_U8:
2.50 case AUDIO_S16:
2.51 case AUDIO_S32:
2.52 case AUDIO_F32:
2.53 - break; /* valid. */
2.54 + this->spec.format = test_format;
2.55 + if (PrepWaveFormat(this, devId, &waveformat, iscapture)) {
2.56 + valid_datatype = 1;
2.57 + } else {
2.58 + test_format = SDL_NextAudioFormat();
2.59 + }
2.60 + break;
2.61
2.62 default:
2.63 - valid_datatype = 0;
2.64 test_format = SDL_NextAudioFormat();
2.65 break;
2.66 }
2.67 @@ -276,30 +310,6 @@
2.68 return SDL_SetError("Unsupported audio format");
2.69 }
2.70
2.71 - /* Set basic WAVE format parameters */
2.72 - SDL_memset(&waveformat, '\0', sizeof(waveformat));
2.73 -
2.74 - if (SDL_AUDIO_ISFLOAT(this->spec.format))
2.75 - waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
2.76 - else
2.77 - waveformat.wFormatTag = WAVE_FORMAT_PCM;
2.78 -
2.79 - waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
2.80 -
2.81 - if (this->spec.channels > 2)
2.82 - this->spec.channels = 2; /* !!! FIXME: is this right? */
2.83 -
2.84 - waveformat.nChannels = this->spec.channels;
2.85 - waveformat.nSamplesPerSec = this->spec.freq;
2.86 - waveformat.nBlockAlign =
2.87 - waveformat.nChannels * (waveformat.wBitsPerSample / 8);
2.88 - waveformat.nAvgBytesPerSec =
2.89 - waveformat.nSamplesPerSec * waveformat.nBlockAlign;
2.90 -
2.91 - /* Check the buffer size -- minimum of 1/4 second (word aligned) */
2.92 - if (this->spec.samples < (this->spec.freq / 4))
2.93 - this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
2.94 -
2.95 /* Update the fragment size as size in bytes */
2.96 SDL_CalculateAudioSpec(&this->spec);
2.97