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. --HG-- extra : rebase_source : 7b4e61c8030d1e1ce4c926bc0abc9b4d4af11dd9
This commit is contained in:
parent
901d874a2b
commit
8f4fb24e2d
2 changed files with 84 additions and 74 deletions
|
@ -346,7 +346,7 @@ DSOUND_CloseDevice(_THIS)
|
|||
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 @@ CreateSecondary(_THIS, HWND focus, WAVEFORMATEX * wavefmt)
|
|||
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 @@ CreateSecondary(_THIS, HWND focus, WAVEFORMATEX * wavefmt)
|
|||
}
|
||||
|
||||
/* 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 @@ CreateSecondary(_THIS, HWND focus, WAVEFORMATEX * wavefmt)
|
|||
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 @@ static int
|
|||
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,42 +483,6 @@ DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
|
|||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
while ((!valid_format) && (test_format)) {
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
case AUDIO_S16:
|
||||
case AUDIO_S32:
|
||||
case AUDIO_F32:
|
||||
this->spec.format = test_format;
|
||||
valid_format = 1;
|
||||
break;
|
||||
}
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
|
||||
if (!valid_format) {
|
||||
DSOUND_CloseDevice(this);
|
||||
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) {
|
||||
|
@ -508,11 +490,29 @@ DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
|
|||
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) {
|
||||
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;
|
||||
this->hidden->num_buffers = CreateSecondary(this, NULL);
|
||||
if (this->hidden->num_buffers > 0) {
|
||||
valid_format = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
|
||||
if (!valid_format) {
|
||||
DSOUND_CloseDevice(this);
|
||||
return -1;
|
||||
if (tried_format) {
|
||||
return -1; // CreateSecondary() should have called SDL_SetError().
|
||||
}
|
||||
return SDL_SetError("DirectSound: Unsupported audio format");
|
||||
}
|
||||
|
||||
/* The buffer will auto-start playing in DSOUND_WaitDevice() */
|
||||
|
|
|
@ -197,6 +197,30 @@ WINMM_CloseDevice(_THIS)
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
|
|||
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 @@ WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
|
|||
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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue