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

Andrew Eikum aeikum at codeweavers.com
Sat Jul 14 13:38:30 CDT 2012


On Sat, Jul 14, 2012 at 05:00:02PM +1000, Donny Yang wrote:
> Andrew, I've removed the two driver edits. IAudioClient_GetMixFormat()
> needs an initialised client parameter which doesn't exist in
> DirectSoundDevice_Create(), so it can only be done after the client is
> initialised, which is approximately where I put the code.
> 

No, you can call GetMixFormat with an IAudioClient that hasn't been
initialized.

> Also, I'm new to this, so is this the correct way to resend a patch?
> 

No, you'll have to resend the patch to wine-patches. It's probably
best to resend the entire series, and of course be sure to test your
changes before sending :)

Thanks,
Andrew

> On Fri, Jul 13, 2012 at 11:10 PM, Andrew Eikum <aeikum at codeweavers.com> wrote:
> > 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

> From 4d454498c8f4cf6593d4afe405fb602ebb0e2722 Mon Sep 17 00:00:00 2001
> From: Donny Yang <xiao.tai.lang.de.email at gmail.com>
> Date: Sat, 14 Jul 2012 16:40:07 +1000
> Subject: dsound: Add detection of output format and upmixing from mono to any
>  number of channels
> 
> ---
>  dlls/dsound/dsound.c         |   19 +++++++++++++++++++
>  dlls/dsound/dsound_convert.c |    8 +++++---
>  dlls/dsound/dsound_private.h |    2 +-
>  dlls/dsound/mixer.c          |    7 +++----
>  dlls/dsound/primary.c        |   28 ++++++++++++++++++++++++++++
>  5 files changed, 56 insertions(+), 8 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_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,
> 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");
> -- 
> 1.7.9.5
> 




More information about the wine-devel mailing list