Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Wed, Apr 06, 2022 at 07:55:55AM +0100, Huw Davies wrote:
Signed-off-by: Huw Davies huw@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