[PATCH 5/8] winealsa: Move get_mix_format to the unixlib.

Andrew Eikum aeikum at codeweavers.com
Thu Feb 17 09:25:52 CST 2022


Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>

On Wed, Feb 16, 2022 at 09:34:51AM +0000, Huw Davies wrote:
> Signed-off-by: Huw Davies <huw at codeweavers.com>
> ---
>  dlls/winealsa.drv/alsa.c     | 178 +++++++++++++++++++++++++++++++++++
>  dlls/winealsa.drv/mmdevdrv.c | 126 +++----------------------
>  dlls/winealsa.drv/unixlib.h  |   9 ++
>  3 files changed, 199 insertions(+), 114 deletions(-)
> 
> diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
> index ae05c7a8b9b..320d676effb 100644
> --- a/dlls/winealsa.drv/alsa.c
> +++ b/dlls/winealsa.drv/alsa.c
> @@ -39,6 +39,7 @@
>  #include "wine/list.h"
>  #include "wine/unixlib.h"
>  
> +#include "initguid.h"
>  #include "unixlib.h"
>  
>  WINE_DEFAULT_DEBUG_CHANNEL(alsa);
> @@ -452,7 +453,184 @@ static NTSTATUS get_endpoint_ids(void *args)
>      return STATUS_SUCCESS;
>  }
>  
> +static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle,
> +                                snd_pcm_hw_params_t **hw_params)
> +{
> +    snd_pcm_stream_t pcm_stream;
> +    int err;
> +
> +    if(flow == eRender)
> +        pcm_stream = SND_PCM_STREAM_PLAYBACK;
> +    else if(flow == eCapture)
> +        pcm_stream = SND_PCM_STREAM_CAPTURE;
> +    else
> +        return E_UNEXPECTED;
> +
> +    err = snd_pcm_open(pcm_handle, alsa_name, pcm_stream, SND_PCM_NONBLOCK);
> +    if(err < 0){
> +        WARN("Unable to open PCM \"%s\": %d (%s)\n", alsa_name, err, snd_strerror(err));
> +        switch(err){
> +        case -EBUSY:
> +            return AUDCLNT_E_DEVICE_IN_USE;
> +        default:
> +            return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
> +        }
> +    }
> +
> +    *hw_params = malloc(snd_pcm_hw_params_sizeof());
> +    if(!*hw_params){
> +        snd_pcm_close(*pcm_handle);
> +        return E_OUTOFMEMORY;
> +    }
> +
> +    return S_OK;
> +}
> +
> +static DWORD get_channel_mask(unsigned int channels)
> +{
> +    switch(channels){
> +    case 0:
> +        return 0;
> +    case 1:
> +        return KSAUDIO_SPEAKER_MONO;
> +    case 2:
> +        return KSAUDIO_SPEAKER_STEREO;
> +    case 3:
> +        return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
> +    case 4:
> +        return KSAUDIO_SPEAKER_QUAD;    /* not _SURROUND */
> +    case 5:
> +        return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
> +    case 6:
> +        return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
> +    case 7:
> +        return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
> +    case 8:
> +        return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
> +    }
> +    FIXME("Unknown speaker configuration: %u\n", channels);
> +    return 0;
> +}
> +
> +static NTSTATUS get_mix_format(void *args)
> +{
> +    struct get_mix_format_params *params = args;
> +    WAVEFORMATEXTENSIBLE *fmt = params->fmt;
> +    snd_pcm_t *pcm_handle;
> +    snd_pcm_hw_params_t *hw_params;
> +    snd_pcm_format_mask_t *formats;
> +    unsigned int max_rate, max_channels;
> +    int err;
> +
> +    params->result = alsa_open_device(params->alsa_name, params->flow, &pcm_handle, &hw_params);
> +    if(FAILED(params->result))
> +        return STATUS_SUCCESS;
> +
> +    formats = calloc(1, snd_pcm_format_mask_sizeof());
> +    if(!formats){
> +        free(hw_params);
> +        snd_pcm_close(pcm_handle);
> +        params->result = E_OUTOFMEMORY;
> +        return STATUS_SUCCESS;
> +    }
> +
> +    if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){
> +        WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
> +        params->result = AUDCLNT_E_DEVICE_INVALIDATED;
> +        goto exit;
> +    }
> +
> +    snd_pcm_hw_params_get_format_mask(hw_params, formats);
> +
> +    fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
> +    if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
> +        fmt->Format.wBitsPerSample = 32;
> +        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
> +    }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
> +        fmt->Format.wBitsPerSample = 16;
> +        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
> +    }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
> +        fmt->Format.wBitsPerSample = 8;
> +        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
> +    }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
> +        fmt->Format.wBitsPerSample = 32;
> +        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
> +    }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
> +        fmt->Format.wBitsPerSample = 24;
> +        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
> +    }else{
> +        ERR("Didn't recognize any available ALSA formats\n");
> +        params->result = AUDCLNT_E_DEVICE_INVALIDATED;
> +        goto exit;
> +    }
> +
> +    if((err = snd_pcm_hw_params_get_channels_max(hw_params, &max_channels)) < 0){
> +        WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
> +        params->result = AUDCLNT_E_DEVICE_INVALIDATED;
> +        goto exit;
> +    }
> +
> +    if(max_channels > 6)
> +        fmt->Format.nChannels = 2;
> +    else
> +        fmt->Format.nChannels = max_channels;
> +
> +    if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){
> +        /* For most hardware on Windows, users must choose a configuration with an even
> +         * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
> +         * channels, but those channels are still reported to applications from
> +         * GetMixFormat! Some applications behave badly if given an odd number of
> +         * channels (e.g. 2.1). */
> +
> +        if(fmt->Format.nChannels < max_channels)
> +            fmt->Format.nChannels += 1;
> +        else
> +            /* We could "fake" more channels and downmix the emulated channels,
> +             * but at that point you really ought to tweak your ALSA setup or
> +             * just use PulseAudio. */
> +            WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
> +    }
> +
> +    fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
> +
> +    if((err = snd_pcm_hw_params_get_rate_max(hw_params, &max_rate, NULL)) < 0){
> +        WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
> +        params->result = AUDCLNT_E_DEVICE_INVALIDATED;
> +        goto exit;
> +    }
> +
> +    if(max_rate >= 48000)
> +        fmt->Format.nSamplesPerSec = 48000;
> +    else if(max_rate >= 44100)
> +        fmt->Format.nSamplesPerSec = 44100;
> +    else if(max_rate >= 22050)
> +        fmt->Format.nSamplesPerSec = 22050;
> +    else if(max_rate >= 11025)
> +        fmt->Format.nSamplesPerSec = 11025;
> +    else if(max_rate >= 8000)
> +        fmt->Format.nSamplesPerSec = 8000;
> +    else{
> +        ERR("Unknown max rate: %u\n", max_rate);
> +        params->result = AUDCLNT_E_DEVICE_INVALIDATED;
> +        goto exit;
> +    }
> +
> +    fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample * fmt->Format.nChannels) / 8;
> +    fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec * fmt->Format.nBlockAlign;
> +
> +    fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
> +    fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
> +
> +exit:
> +    free(formats);
> +    free(hw_params);
> +    snd_pcm_close(pcm_handle);
> +
> +    return STATUS_SUCCESS;
> +}
> +
>  unixlib_entry_t __wine_unix_call_funcs[] =
>  {
>      get_endpoint_ids,
> +    get_mix_format,
>  };
> diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
> index ecd74d373aa..24c6755d697 100644
> --- a/dlls/winealsa.drv/mmdevdrv.c
> +++ b/dlls/winealsa.drv/mmdevdrv.c
> @@ -1446,11 +1446,7 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
>          WAVEFORMATEX **pwfx)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> -    WAVEFORMATEXTENSIBLE *fmt;
> -    snd_pcm_format_mask_t *formats;
> -    unsigned int max_rate, max_channels;
> -    int err;
> -    HRESULT hr = S_OK;
> +    struct get_mix_format_params params;
>  
>      TRACE("(%p)->(%p)\n", This, pwfx);
>  
> @@ -1458,119 +1454,21 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
>          return E_POINTER;
>      *pwfx = NULL;
>  
> -    fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
> -    if(!fmt)
> +    params.alsa_name = This->alsa_name;
> +    params.flow = This->dataflow;
> +    params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
> +    if(!params.fmt)
>          return E_OUTOFMEMORY;
>  
> -    formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof());
> -    if(!formats){
> -        CoTaskMemFree(fmt);
> -        return E_OUTOFMEMORY;
> -    }
> -
> -    EnterCriticalSection(&This->lock);
> -
> -    if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
> -        WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
> -        hr = AUDCLNT_E_DEVICE_INVALIDATED;
> -        goto exit;
> -    }
> -
> -    snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats);
> -
> -    fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
> -    if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
> -        fmt->Format.wBitsPerSample = 32;
> -        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
> -    }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
> -        fmt->Format.wBitsPerSample = 16;
> -        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
> -    }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
> -        fmt->Format.wBitsPerSample = 8;
> -        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
> -    }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
> -        fmt->Format.wBitsPerSample = 32;
> -        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
> -    }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
> -        fmt->Format.wBitsPerSample = 24;
> -        fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
> -    }else{
> -        ERR("Didn't recognize any available ALSA formats\n");
> -        hr = AUDCLNT_E_DEVICE_INVALIDATED;
> -        goto exit;
> -    }
> -
> -    if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params,
> -                    &max_channels)) < 0){
> -        WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
> -        hr = AUDCLNT_E_DEVICE_INVALIDATED;
> -        goto exit;
> -    }
> -
> -    if(max_channels > 6)
> -        fmt->Format.nChannels = 2;
> -    else
> -        fmt->Format.nChannels = max_channels;
> -
> -    if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){
> -        /* For most hardware on Windows, users must choose a configuration with an even
> -         * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
> -         * channels, but those channels are still reported to applications from
> -         * GetMixFormat! Some applications behave badly if given an odd number of
> -         * channels (e.g. 2.1). */
> -
> -        if(fmt->Format.nChannels < max_channels)
> -            fmt->Format.nChannels += 1;
> -        else
> -            /* We could "fake" more channels and downmix the emulated channels,
> -             * but at that point you really ought to tweak your ALSA setup or
> -             * just use PulseAudio. */
> -            WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
> -    }
> -
> -    fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
> +    ALSA_CALL(get_mix_format, &params);
>  
> -    if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max_rate,
> -                    NULL)) < 0){
> -        WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
> -        hr = AUDCLNT_E_DEVICE_INVALIDATED;
> -        goto exit;
> -    }
> -
> -    if(max_rate >= 48000)
> -        fmt->Format.nSamplesPerSec = 48000;
> -    else if(max_rate >= 44100)
> -        fmt->Format.nSamplesPerSec = 44100;
> -    else if(max_rate >= 22050)
> -        fmt->Format.nSamplesPerSec = 22050;
> -    else if(max_rate >= 11025)
> -        fmt->Format.nSamplesPerSec = 11025;
> -    else if(max_rate >= 8000)
> -        fmt->Format.nSamplesPerSec = 8000;
> -    else{
> -        ERR("Unknown max rate: %u\n", max_rate);
> -        hr = AUDCLNT_E_DEVICE_INVALIDATED;
> -        goto exit;
> -    }
> -
> -    fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
> -            fmt->Format.nChannels) / 8;
> -    fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
> -        fmt->Format.nBlockAlign;
> -
> -    fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
> -    fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
> -
> -    dump_fmt((WAVEFORMATEX*)fmt);
> -    *pwfx = (WAVEFORMATEX*)fmt;
> -
> -exit:
> -    LeaveCriticalSection(&This->lock);
> -    if(FAILED(hr))
> -        CoTaskMemFree(fmt);
> -    HeapFree(GetProcessHeap(), 0, formats);
> +    if(SUCCEEDED(params.result)){
> +        *pwfx = &params.fmt->Format;
> +        dump_fmt(*pwfx);
> +    } else
> +        CoTaskMemFree(params.fmt);
>  
> -    return hr;
> +    return params.result;
>  }
>  
>  static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
> diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
> index 8a20710b7e5..ef5b470e1ed 100644
> --- a/dlls/winealsa.drv/unixlib.h
> +++ b/dlls/winealsa.drv/unixlib.h
> @@ -67,9 +67,18 @@ struct get_endpoint_ids_params
>      unsigned int default_idx;
>  };
>  
> +struct get_mix_format_params
> +{
> +    const char *alsa_name;
> +    EDataFlow flow;
> +    WAVEFORMATEXTENSIBLE *fmt;
> +    HRESULT result;
> +};
> +
>  enum alsa_funcs
>  {
>      alsa_get_endpoint_ids,
> +    alsa_get_mix_format,
>  };
>  
>  extern unixlib_handle_t alsa_handle;
> -- 
> 2.25.1
> 
> 



More information about the wine-devel mailing list