[WINEALSA] direct sound fallback patch

Robert Reif reif at earthlink.net
Mon Mar 21 12:06:28 CST 2005


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.
-------------- 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 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");


More information about the wine-devel mailing list