Robert Reif wrote:
> Don't fail when opening a device in direct sound mode.
> Rather, try alternate formats first before failing.
>
> With the wave api, requesting a format that the
> hardware can't do should fail so the wave mapper can
> fix it up. However, the direct sound api does not
> expect a failure (within reason) if the format isn't
> supported in hardware but expects the closest
> format that the hardware does support.
>
> This gets the direct sound regression tests working
> better with the ALSA "hw" device and my lame Intel
> builtin sound card.
Use this patch instead. Fixes a format bug.
Index: dlls/winmm/winealsa/audio.c
===================================================================
RCS file: /home/wine/wine/dlls/winmm/winealsa/audio.c,v
retrieving revision 1.71
diff -u -p -r1.71 audio.c
--- dlls/winmm/winealsa/audio.c 21 Mar 2005 12:32:48 -0000 1.71
+++ dlls/winmm/winealsa/audio.c 21 Mar 2005 18:02:05 -0000
@@ -315,6 +315,22 @@ static const char * getMessage(UINT msg)
return unknown;
}
+static const char * getFormat(WORD wFormatTag)
+{
+ static char unknown[32];
+#define FMT_TO_STR(x) case x: return #x
+ switch(wFormatTag) {
+ FMT_TO_STR(WAVE_FORMAT_PCM);
+ FMT_TO_STR(WAVE_FORMAT_EXTENSIBLE);
+ FMT_TO_STR(WAVE_FORMAT_MULAW);
+ FMT_TO_STR(WAVE_FORMAT_ALAW);
+ FMT_TO_STR(WAVE_FORMAT_ADPCM);
+ }
+#undef FMT_TO_STR
+ sprintf(unknown, "UNKNOWN(0x%04x)", wFormatTag);
+ return unknown;
+}
+
static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
WAVEFORMATPCMEX* format)
{
@@ -1758,6 +1774,12 @@ static DWORD wodOpen(WORD wDevID, LPWAVE
memcpy(&wwo->waveDesc, lpDesc, sizeof(WAVEOPENDESC));
copy_format(lpDesc->lpFormat, &wwo->format);
+ TRACE("Requested this format: %ldx%dx%d %s\n",
+ wwo->format.Format.nSamplesPerSec,
+ wwo->format.Format.wBitsPerSample,
+ wwo->format.Format.nChannels,
+ getFormat(wwo->format.Format.wFormatTag));
+
if (wwo->format.Format.wBitsPerSample == 0) {
WARN("Resetting zeroed wBitsPerSample\n");
wwo->format.Format.wBitsPerSample = 8 *
@@ -1789,7 +1811,19 @@ static DWORD wodOpen(WORD wDevID, LPWAVE
else
wwo->write = snd_pcm_mmap_writei;
- EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels), MMSYSERR_INVALPARAM, "unable to set required channels");
+ if ((err = snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels)) < 0) {
+ WARN("unable to set required channels: %d\n", wwo->format.Format.nChannels);
+ if (dwFlags & WAVE_DIRECTSOUND) {
+ if (wwo->format.Format.nChannels > 2)
+ wwo->format.Format.nChannels = 2;
+ else if (wwo->format.Format.nChannels == 2)
+ wwo->format.Format.nChannels = 1;
+ else if (wwo->format.Format.nChannels == 1)
+ wwo->format.Format.nChannels = 2;
+ WARN("changed number of channels from %d to %d\n", lpDesc->lpFormat->nChannels, wwo->format.Format.nChannels);
+ }
+ EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels ), MMSYSERR_INVALPARAM, "unable to set required channels" );
+ }
if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_PCM) ||
((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
@@ -1819,7 +1853,24 @@ static DWORD wodOpen(WORD wDevID, LPWAVE
return WAVERR_BADFORMAT;
}
- EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), MMSYSERR_INVALPARAM, "unable to set required format");
+ if ((err = snd_pcm_hw_params_set_format(pcm, hw_params, format)) < 0) {
+ WARN("unable to set required format: %s\n", snd_pcm_format_name(format));
+ if (dwFlags & WAVE_DIRECTSOUND) {
+ if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_PCM) ||
+ ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
+ IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) {
+ if (wwo->format.Format.wBitsPerSample != 16) {
+ wwo->format.Format.wBitsPerSample = 16;
+ format = SND_PCM_FORMAT_S16_LE;
+ } else {
+ wwo->format.Format.wBitsPerSample = 8;
+ format = SND_PCM_FORMAT_U8;
+ }
+ WARN("changed bits per sample from %d to %d\n", lpDesc->lpFormat->wBitsPerSample, wwo->format.Format.wBitsPerSample);
+ }
+ }
+ EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), MMSYSERR_INVALPARAM, "unable to set required format" );
+ }
rate = wwo->format.Format.nSamplesPerSec;
dir=0;
@@ -1830,9 +1881,14 @@ static DWORD wodOpen(WORD wDevID, LPWAVE
return WAVERR_BADFORMAT;
}
if (rate != wwo->format.Format.nSamplesPerSec) {
- ERR("Rate doesn't match (requested %ld Hz, got %d Hz)\n", wwo->format.Format.nSamplesPerSec, rate);
- snd_pcm_close(pcm);
- return WAVERR_BADFORMAT;
+ if (dwFlags & WAVE_DIRECTSOUND) {
+ WARN("changed sample rate from %ld Hz to %d Hz\n", wwo->format.Format.nSamplesPerSec, rate);
+ wwo->format.Format.nSamplesPerSec = rate;
+ } else {
+ ERR("Rate doesn't match (requested %ld Hz, got %d Hz)\n", wwo->format.Format.nSamplesPerSec, rate);
+ snd_pcm_close(pcm);
+ return WAVERR_BADFORMAT;
+ }
}
dir=0;
EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, &dir), MMSYSERR_INVALPARAM, "unable to set buffer time");