[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, ¶ms);
>
> - 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 = ¶ms.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