[PATCH 5/8] wineoss: Move is_format_supported to the unixlib.

Andrew Eikum aeikum at codeweavers.com
Mon Apr 11 08:59:55 CDT 2022


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

On Wed, Apr 06, 2022 at 07:55:55AM +0100, Huw Davies wrote:
> Signed-off-by: Huw Davies <huw at codeweavers.com>
> ---
>  dlls/wineoss.drv/mmdevdrv.c |  51 ++++-----
>  dlls/wineoss.drv/oss.c      | 202 ++++++++++++++++++++++++++++++++++++
>  dlls/wineoss.drv/unixlib.h  |  11 ++
>  3 files changed, 233 insertions(+), 31 deletions(-)
> 
> diff --git a/dlls/wineoss.drv/mmdevdrv.c b/dlls/wineoss.drv/mmdevdrv.c
> index 4f8460a3b3b..242d2e0b359 100644
> --- a/dlls/wineoss.drv/mmdevdrv.c
> +++ b/dlls/wineoss.drv/mmdevdrv.c
> @@ -1094,45 +1094,34 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
>  }
>  
>  static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
> -        AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
> -        WAVEFORMATEX **outpwfx)
> +        AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
> +        WAVEFORMATEX **out)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> -    int fd = -1;
> -    HRESULT ret;
> +    struct is_format_supported_params params;
>  
> -    TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
> +    TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
> +    if(fmt) dump_fmt(fmt);
>  
> -    if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
> -        return E_POINTER;
> -
> -    if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
> -        return E_INVALIDARG;
> +    params.device = This->devnode;
> +    params.flow = This->dataflow;
> +    params.share = mode;
> +    params.fmt_in = fmt;
> +    params.fmt_out = NULL;
>  
> -    if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
> -            pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
> -        return E_INVALIDARG;
> -
> -    dump_fmt(pwfx);
> -
> -    if(outpwfx){
> -        *outpwfx = NULL;
> -        if(mode != AUDCLNT_SHAREMODE_SHARED)
> -            outpwfx = NULL;
> +    if(out){
> +        *out = NULL;
> +        if(mode == AUDCLNT_SHAREMODE_SHARED)
> +            params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
>      }
> +    OSS_CALL(is_format_supported, &params);
>  
> -    fd = open_device(This->devnode, This->dataflow);
> -    if(fd < 0){
> -        WARN("Unable to open device %s: %d (%s)\n", This->devnode, errno,
> -                strerror(errno));
> -        return AUDCLNT_E_DEVICE_INVALIDATED;
> -    }
> -
> -    ret = setup_oss_device(mode, fd, pwfx, outpwfx);
> -
> -    close(fd);
> +    if(params.result == S_FALSE)
> +        *out = &params.fmt_out->Format;
> +    else
> +        CoTaskMemFree(params.fmt_out);
>  
> -    return ret;
> +    return params.result;
>  }
>  
>  static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
> diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c
> index ab7751ac174..49173ec6b6b 100644
> --- a/dlls/wineoss.drv/oss.c
> +++ b/dlls/wineoss.drv/oss.c
> @@ -35,6 +35,7 @@
>  #include "ntstatus.h"
>  #define WIN32_NO_STATUS
>  #include "winternl.h"
> +#include "initguid.h"
>  #include "audioclient.h"
>  
>  #include "wine/debug.h"
> @@ -294,8 +295,209 @@ static NTSTATUS get_endpoint_ids(void *args)
>      return STATUS_SUCCESS;
>  }
>  
> +static UINT 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 int get_oss_format(const WAVEFORMATEX *fmt)
> +{
> +    WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
> +
> +    if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
> +            (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
> +             IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
> +        switch(fmt->wBitsPerSample){
> +        case 8:
> +            return AFMT_U8;
> +        case 16:
> +            return AFMT_S16_LE;
> +        case 24:
> +            return AFMT_S24_LE;
> +        case 32:
> +            return AFMT_S32_LE;
> +        }
> +        return -1;
> +    }
> +
> +#ifdef AFMT_FLOAT
> +    if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
> +            (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
> +             IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
> +        if(fmt->wBitsPerSample != 32)
> +            return -1;
> +
> +        return AFMT_FLOAT;
> +    }
> +#endif
> +
> +    return -1;
> +}
> +
> +static WAVEFORMATEXTENSIBLE *clone_format(const WAVEFORMATEX *fmt)
> +{
> +    WAVEFORMATEXTENSIBLE *ret;
> +    size_t size;
> +
> +    if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
> +        size = sizeof(WAVEFORMATEXTENSIBLE);
> +    else
> +        size = sizeof(WAVEFORMATEX);
> +
> +    ret = malloc(size);
> +    if(!ret)
> +        return NULL;
> +
> +    memcpy(ret, fmt, size);
> +
> +    ret->Format.cbSize = size - sizeof(WAVEFORMATEX);
> +
> +    return ret;
> +}
> +
> +static HRESULT setup_oss_device(AUDCLNT_SHAREMODE share, int fd,
> +                                const WAVEFORMATEX *fmt, WAVEFORMATEXTENSIBLE *out)
> +{
> +    const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
> +    int tmp, oss_format;
> +    double tenth;
> +    HRESULT ret = S_OK;
> +    WAVEFORMATEXTENSIBLE *closest;
> +
> +    tmp = oss_format = get_oss_format(fmt);
> +    if(oss_format < 0)
> +        return AUDCLNT_E_UNSUPPORTED_FORMAT;
> +    if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
> +        WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
> +        return E_FAIL;
> +    }
> +    if(tmp != oss_format){
> +        TRACE("Format unsupported by this OSS version: %x\n", oss_format);
> +        return AUDCLNT_E_UNSUPPORTED_FORMAT;
> +    }
> +
> +    if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
> +            (fmtex->Format.nAvgBytesPerSec == 0 ||
> +             fmtex->Format.nBlockAlign == 0 ||
> +             fmtex->Samples.wValidBitsPerSample > fmtex->Format.wBitsPerSample))
> +        return E_INVALIDARG;
> +
> +    if(fmt->nChannels == 0)
> +        return AUDCLNT_E_UNSUPPORTED_FORMAT;
> +
> +    closest = clone_format(fmt);
> +    if(!closest)
> +        return E_OUTOFMEMORY;
> +
> +    tmp = fmt->nSamplesPerSec;
> +    if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
> +        WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
> +        free(closest);
> +        return E_FAIL;
> +    }
> +    tenth = fmt->nSamplesPerSec * 0.1;
> +    if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
> +        ret = S_FALSE;
> +        closest->Format.nSamplesPerSec = tmp;
> +    }
> +
> +    tmp = fmt->nChannels;
> +    if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
> +        WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
> +        free(closest);
> +        return E_FAIL;
> +    }
> +    if(tmp != fmt->nChannels){
> +        ret = S_FALSE;
> +        closest->Format.nChannels = tmp;
> +    }
> +
> +    if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
> +        closest->dwChannelMask = get_channel_mask(closest->Format.nChannels);
> +
> +    if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
> +            fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
> +            (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
> +             fmtex->Samples.wValidBitsPerSample < fmtex->Format.wBitsPerSample))
> +        ret = S_FALSE;
> +
> +    if(share == AUDCLNT_SHAREMODE_EXCLUSIVE &&
> +            fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
> +        if(fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)
> +            ret = S_FALSE;
> +    }
> +
> +    if(ret == S_FALSE && !out)
> +        ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
> +
> +    if(ret == S_FALSE && out){
> +        closest->Format.nBlockAlign =
> +            closest->Format.nChannels * closest->Format.wBitsPerSample / 8;
> +        closest->Format.nAvgBytesPerSec =
> +            closest->Format.nBlockAlign * closest->Format.nSamplesPerSec;
> +        if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
> +            closest->Samples.wValidBitsPerSample = closest->Format.wBitsPerSample;
> +        memcpy(out, closest, closest->Format.cbSize + sizeof(WAVEFORMATEX));
> +    }
> +    free(closest);
> +
> +    TRACE("returning: %08x\n", ret);
> +    return ret;
> +}
> +
> +static NTSTATUS is_format_supported(void *args)
> +{
> +    struct is_format_supported_params *params = args;
> +    int fd;
> +
> +    params->result = S_OK;
> +
> +    if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out))
> +        params->result = E_POINTER;
> +    else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE)
> +        params->result = E_INVALIDARG;
> +    else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
> +            params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
> +        params->result = E_INVALIDARG;
> +    if(FAILED(params->result))
> +        return STATUS_SUCCESS;
> +
> +    fd = open_device(params->device, params->flow);
> +    if(fd < 0){
> +        WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
> +        params->result = AUDCLNT_E_DEVICE_INVALIDATED;
> +        return STATUS_SUCCESS;
> +    }
> +    params->result = setup_oss_device(params->share, fd, params->fmt_in, params->fmt_out);
> +    close(fd);
> +
> +    return STATUS_SUCCESS;
> +}
> +
>  unixlib_entry_t __wine_unix_call_funcs[] =
>  {
>      test_connect,
>      get_endpoint_ids,
> +    is_format_supported,
>  };
> diff --git a/dlls/wineoss.drv/unixlib.h b/dlls/wineoss.drv/unixlib.h
> index f498609898a..b89e2142d93 100644
> --- a/dlls/wineoss.drv/unixlib.h
> +++ b/dlls/wineoss.drv/unixlib.h
> @@ -67,10 +67,21 @@ struct get_endpoint_ids_params
>      unsigned int default_idx;
>  };
>  
> +struct is_format_supported_params
> +{
> +    const char *device;
> +    EDataFlow flow;
> +    AUDCLNT_SHAREMODE share;
> +    const WAVEFORMATEX *fmt_in;
> +    WAVEFORMATEXTENSIBLE *fmt_out;
> +    HRESULT result;
> +};
> +
>  enum oss_funcs
>  {
>      oss_test_connect,
>      oss_get_endpoint_ids,
> +    oss_is_format_supported,
>  };
>  
>  extern unixlib_handle_t oss_handle;
> -- 
> 2.25.1
> 
> 



More information about the wine-devel mailing list