Huw Davies : wineoss: Move is_format_supported to the unixlib.
Alexandre Julliard
julliard at winehq.org
Mon Apr 11 15:55:00 CDT 2022
Module: wine
Branch: master
Commit: a465ecd7453b4ece41358e90ba6e1d44b44a06e2
URL: https://source.winehq.org/git/wine.git/?a=commit;h=a465ecd7453b4ece41358e90ba6e1d44b44a06e2
Author: Huw Davies <huw at codeweavers.com>
Date: Wed Apr 6 07:55:55 2022 +0100
wineoss: Move is_format_supported to the unixlib.
Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
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;
More information about the wine-cvs
mailing list