dsound: Add detection of output format and allow a maximum of 8 channels

Donny Yang xiao.tai.lang.de.email at gmail.com
Fri Jul 13 02:57:48 CDT 2012


This patch makes dsound automatically get the output format when a
output device is initialised and also allows up to 8 output channels
to be used for ALSA and PulseAudio. Using ALSA with over 2 channels
outputs the channels in the wrong speakers with my testing but I don't
know why so I can't fix that.
This was tested under wine 1.5.8 with Ubuntu 12.04 using both winealsa
and winepulse with 2.0, 5.1 and 7.1 output channels and 1.0, 2.0, 5.1
and 7.1 file input channels using foobar2000.
-------------- next part --------------
From f8d0850caf875d20cef15074b9f188a1320ee201 Mon Sep 17 00:00:00 2001
From: Donny Yang <xiao.tai.lang.de.email at gmail.com>
Date: Fri, 13 Jul 2012 15:24:59 +1000
Subject: dsound: Add detection of output format and allow a maximum of 8 channels

---
 dlls/dsound/dsound.c          |   19 +++++++++++++++++++
 dlls/dsound/dsound_convert.c  |    8 +++++---
 dlls/dsound/dsound_main.c     |    4 ++--
 dlls/dsound/dsound_private.h  |    6 +++---
 dlls/dsound/mixer.c           |    7 +++----
 dlls/dsound/primary.c         |   28 ++++++++++++++++++++++++++++
 dlls/winealsa.drv/mmdevdrv.c  |    6 +++---
 dlls/winepulse.drv/mmdevdrv.c |    4 ++--
 8 files changed, 65 insertions(+), 17 deletions(-)

diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
index e401725..7d75760 100644
--- a/dlls/dsound/dsound.c
+++ b/dlls/dsound/dsound.c
@@ -1382,6 +1382,7 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
     GUID devGUID;
     DirectSoundDevice *device;
     IMMDevice *mmdevice;
+    WAVEFORMATEX *pwfx;
 
     TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
 
@@ -1492,6 +1493,24 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
     } else
         WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
 
+    hr = IAudioClient_GetMixFormat(device->client, &pwfx);
+    if(FAILED(hr)){
+        WARN("IAudioClient_GetMixFormat failed: %08x; Falling back to default output format\n", hr);
+    }else{
+        DWORD oldPriolevel = device->priolevel;
+        device->priolevel = DSSCL_WRITEPRIMARY;
+        hr = primarybuffer_SetFormat(device, pwfx);
+        device->priolevel = oldPriolevel;
+        CoTaskMemFree(pwfx);
+        if(FAILED(hr)){
+            HeapFree(GetProcessHeap(), 0, device);
+            LeaveCriticalSection(&DSOUND_renderers_lock);
+            IMMDevice_Release(mmdevice);
+            WARN("primarybuffer_SetFormat failed: %08x\n", hr);
+            return hr;
+        }
+    }
+
     *ppDevice = device;
     list_add_tail(&DSOUND_renderers, &device->entry);
 
diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c
index d3d686a..a8c929c 100644
--- a/dlls/dsound/dsound_convert.c
+++ b/dlls/dsound/dsound_convert.c
@@ -159,10 +159,12 @@ void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, floa
     *fbuf = value;
 }
 
-void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
+void put_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
 {
-    dsb->put_aux(dsb, pos, 0, value);
-    dsb->put_aux(dsb, pos, 1, value);
+    /* XXX: Is this how Windows does this? */
+    DWORD c;
+    for (c = 0; c < dsb->device->pwfx->nChannels; ++c)
+        dsb->put_aux(dsb, pos, c, value);
 }
 
 void mixieee32(float *src, float *dst, unsigned samples)
diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c
index 072b25a..538534d 100644
--- a/dlls/dsound/dsound_main.c
+++ b/dlls/dsound/dsound_main.c
@@ -642,7 +642,7 @@ DirectSoundCaptureEnumerateW(
  */
 
 typedef  HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
- 
+
 typedef struct {
     IClassFactory IClassFactory_iface;
     REFCLSID rclsid;
@@ -702,7 +702,7 @@ static HRESULT WINAPI DSCF_CreateInstance(
     *ppobj = NULL;
     return This->pfnCreateInstance(riid, ppobj);
 }
- 
+
 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
 {
     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 1cf6daa..68f6242 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -202,7 +202,7 @@ struct IDirectSoundBufferImpl
 };
 
 float get_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) DECLSPEC_HIDDEN;
-void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN;
+void put_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN;
 
 HRESULT IDirectSoundBufferImpl_Create(
     DirectSoundDevice *device,
@@ -288,7 +288,7 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
 LONG capped_refcount_dec(LONG *ref) DECLSPEC_HIDDEN;
 
 /* duplex.c */
- 
+
 HRESULT DSOUND_FullDuplexCreate(REFIID riid, LPDIRECTSOUNDFULLDUPLEX* ppDSFD) DECLSPEC_HIDDEN;
 
 /* mixer.c */
@@ -305,7 +305,7 @@ DWORD CALLBACK DSOUND_mixthread(void *ptr) DECLSPEC_HIDDEN;
 void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) DECLSPEC_HIDDEN;
 
 /* capture.c */
- 
+
 HRESULT DSOUND_CaptureCreate(REFIID riid, LPDIRECTSOUNDCAPTURE *ppDSC) DECLSPEC_HIDDEN;
 HRESULT DSOUND_CaptureCreate8(REFIID riid, LPDIRECTSOUNDCAPTURE8 *ppDSC8) DECLSPEC_HIDDEN;
 
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 13eb03d..547c666 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -157,7 +157,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
 	else if (ichannels == 1)
 	{
 		dsb->mix_channels = 1;
-		dsb->put = put_mono2stereo;
+		dsb->put = put_mono;
 	}
 	else if (ochannels == 1)
 	{
@@ -166,9 +166,8 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
 	}
 	else
 	{
-		if (ichannels > 2)
-			FIXME("Conversion from %u to %u channels is not implemented, falling back to stereo\n", ichannels, ochannels);
-		dsb->mix_channels = 2;
+		FIXME("Conversion from %u to %u channels is not implemented, falling back to %u channels\n", ichannels, ochannels, ochannels);
+		dsb->mix_channels = ochannels;
 	}
 }
 
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index cfe674e..9fd1ff2 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -484,6 +484,34 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passe
 	goto done;
 
 opened:
+    switch(device->pwfx->nChannels){
+        case 0:
+            device->speaker_config = DSSPEAKER_DIRECTOUT;
+            break;
+        case 1:
+            device->speaker_config = DSSPEAKER_MONO;
+            break;
+        case 2:
+        case 3:
+            device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
+            break;
+        case 4:
+        case 5:
+            device->speaker_config = DSSPEAKER_QUAD;
+            break;
+        case 6:
+        case 7:
+            device->speaker_config = DSSPEAKER_5POINT1_SURROUND;
+            break;
+        case 8:
+            device->speaker_config = DSSPEAKER_7POINT1_SURROUND;
+            break;
+        default:
+            FIXME("Unknown speaker configuration: %u\n", device->pwfx->nChannels);
+            device->speaker_config = DSSPEAKER_DIRECTOUT;
+            break;
+    }
+
 	err = DSOUND_PrimaryOpen(device);
 	if (err != DS_OK) {
 		WARN("DSOUND_PrimaryOpen failed\n");
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 93e2b8d..fa6b05a 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -1544,7 +1544,7 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
         goto exit;
     }
     if(max > 8)
-        max = 2;
+        max = 8;
     if(fmt->nChannels > max){
         hr = S_FALSE;
         closest->nChannels = max;
@@ -1649,8 +1649,8 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
         goto exit;
     }
 
-    if(max_channels > 2)
-        fmt->Format.nChannels = 2;
+    if(max_channels > 8)
+        fmt->Format.nChannels = 8;
     else
         fmt->Format.nChannels = max_channels;
 
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index b374b53..e86ed08 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -1050,13 +1050,13 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
     This->ss.format = PA_SAMPLE_INVALID;
     switch(fmt->wFormatTag) {
     case WAVE_FORMAT_IEEE_FLOAT:
-        if (!fmt->nChannels || fmt->nChannels > 2 || fmt->wBitsPerSample != 32)
+        if (!fmt->nChannels || fmt->nChannels > 8 || fmt->wBitsPerSample != 32)
             break;
         This->ss.format = PA_SAMPLE_FLOAT32LE;
         pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
         break;
     case WAVE_FORMAT_PCM:
-        if (!fmt->nChannels || fmt->nChannels > 2)
+        if (!fmt->nChannels || fmt->nChannels > 8)
             break;
         if (fmt->wBitsPerSample == 8)
             This->ss.format = PA_SAMPLE_U8;
-- 
1.7.9.5


More information about the wine-patches mailing list