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

Andrew Eikum aeikum at codeweavers.com
Fri Jul 13 08:10:45 CDT 2012


Thanks, Donny. Nice work overall. Some comments below.

On Fri, Jul 13, 2012 at 05:57:48PM +1000, Donny Yang wrote:
> 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.

You probably already discovered that ALSA's multi-channel support is
primitive at best. You have to test each channel and hand-craft an
asoundrc to match your hardware. See some more information here:
<http://drona.csa.iisc.ernet.in/~uday/alsamch.shtml>

> @@ -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;

This looks like a hack. I think it fits better in
DirectSoundDevice_Create, where the default values are copied in. Is
there a reason it couldn't be done there?

> -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);
>  }
>  

I think this is fine. I wonder if we should skip the LOWFREQ channel,
though we'd have to be careful not to affect performance too much, as
this runs in a really tight loop.

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

The only changes to this file are whitespace changes. I'd exclude
these changes when you resend.

> 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;
>  

Likewise, more unneeded whitespace changes.

> 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;
>  

This needs to be a separate patch. Also, winealsa's multi-channel
handling needs a closer examination. My current thinking is
GetMixFormat should just return some sane, supported default (2ch,
48kHz, 16bps, or less as supported).  It seems impossible to detect
what the ALSA device actually supports, so we probably shouldn't even
try like we do now.

> 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;

Wine doesn't have a PulseAudio driver yet, so this chunk won't apply.

Andrew



More information about the wine-devel mailing list