Robert Reif wrote:

Robert Reif wrote:

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.


This should be the last version.  Recalculates format properly
when changed and gets it back to direct sound properly.

I lied. This time with the correct patch (I hope).
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 22 Mar 2005 13:51:33 -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,22 @@ 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;
+            /* recalculate block align and bytes per second */
+            wwo->format.Format.nBlockAlign = 
(wwo->format.Format.wBitsPerSample * wwo->format.Format.nChannels) / 8;
+            wwo->format.Format.nAvgBytesPerSec = 
wwo->format.Format.nSamplesPerSec * wwo->format.Format.nBlockAlign;
+            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 +1856,27 @@ 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;
+                }
+                /* recalculate block align and bytes per second */
+                wwo->format.Format.nBlockAlign = 
(wwo->format.Format.wBitsPerSample * wwo->format.Format.nChannels) / 8;
+                wwo->format.Format.nAvgBytesPerSec = 
wwo->format.Format.nSamplesPerSec * wwo->format.Format.nBlockAlign;
+                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,10 +1887,34 @@ 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;
+            /* recalculate bytes per second */
+            wwo->format.Format.nAvgBytesPerSec = 
wwo->format.Format.nSamplesPerSec * wwo->format.Format.nBlockAlign;
+        } 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;
+        }
     }
+
+    /* give the new format back to direct sound */
+    if (dwFlags & WAVE_DIRECTSOUND) {
+        lpDesc->lpFormat->wFormatTag = wwo->format.Format.wFormatTag;
+        lpDesc->lpFormat->nChannels = wwo->format.Format.nChannels;
+        lpDesc->lpFormat->nSamplesPerSec = wwo->format.Format.nSamplesPerSec;
+        lpDesc->lpFormat->wBitsPerSample = wwo->format.Format.wBitsPerSample;
+        lpDesc->lpFormat->nBlockAlign = wwo->format.Format.nBlockAlign;
+        lpDesc->lpFormat->nAvgBytesPerSec = wwo->format.Format.nAvgBytesPerSec;
+    }
+
+    TRACE("Got this format: %ldx%dx%d %s\n",
+          wwo->format.Format.nSamplesPerSec,
+          wwo->format.Format.wBitsPerSample,
+          wwo->format.Format.nChannels,
+          getFormat(wwo->format.Format.wFormatTag));
+
     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");
     dir=0; 

Reply via email to