[WINEALSA] direct sound fallback patch
Robert Reif
reif at earthlink.net
Tue Mar 22 08:05:27 CST 2005
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).
-------------- 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 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;
More information about the wine-devel
mailing list