[WINEALSA] direct sound fallback patch

Robert Reif reif at earthlink.net
Mon Mar 21 10:30:55 CST 2005


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.
-------------- next part --------------
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 16:16:49 -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,21 @@ 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)
+                    format = SND_PCM_FORMAT_S16_LE;
+                else
+                    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 +1878,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");


More information about the wine-patches mailing list