Commit f5baa375 authored by Davide Beatrici's avatar Davide Beatrici Committed by Alexandre Julliard

winepulse: Implement is_format_supported in unixlib.

parent 2127a8a0
......@@ -620,27 +620,6 @@ static void dump_fmt(const WAVEFORMATEX *fmt)
}
}
static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
{
WAVEFORMATEX *ret;
size_t size;
if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
size = sizeof(WAVEFORMATEXTENSIBLE);
else
size = sizeof(WAVEFORMATEX);
ret = CoTaskMemAlloc(size);
if (!ret)
return NULL;
memcpy(ret, fmt, size);
ret->cbSize = size - sizeof(WAVEFORMATEX);
return ret;
}
static void session_init_vols(AudioSession *session, UINT channels)
{
if (session->channel_count < channels) {
......@@ -888,152 +867,33 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
WAVEFORMATEX **out)
{
ACImpl *This = impl_from_IAudioClient3(iface);
HRESULT hr = S_OK;
WAVEFORMATEX *closest = NULL;
BOOL exclusive;
struct is_format_supported_params params;
TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
if (!fmt)
return E_POINTER;
if (out)
*out = NULL;
if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
exclusive = 1;
out = NULL;
} else if (mode == AUDCLNT_SHAREMODE_SHARED) {
exclusive = 0;
if (!out)
return E_POINTER;
} else
return E_INVALIDARG;
if (fmt->nChannels == 0)
return AUDCLNT_E_UNSUPPORTED_FORMAT;
closest = clone_format(fmt);
if (!closest)
return E_OUTOFMEMORY;
dump_fmt(fmt);
switch (fmt->wFormatTag) {
case WAVE_FORMAT_EXTENSIBLE: {
WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)closest;
if ((fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) &&
fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE)) ||
fmt->nBlockAlign != fmt->wBitsPerSample / 8 * fmt->nChannels ||
ext->Samples.wValidBitsPerSample > fmt->wBitsPerSample ||
fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec) {
hr = E_INVALIDARG;
break;
}
if (exclusive) {
UINT32 mask = 0, i, channels = 0;
if (!(ext->dwChannelMask & (SPEAKER_ALL | SPEAKER_RESERVED))) {
for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) {
if (i & ext->dwChannelMask) {
mask |= i;
channels++;
}
}
if (channels != fmt->nChannels || (ext->dwChannelMask & ~mask)) {
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
} else {
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
}
if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
if (fmt->wBitsPerSample != 32) {
hr = E_INVALIDARG;
break;
}
if (fmt)
dump_fmt(fmt);
if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample) {
hr = S_FALSE;
ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
}
} else if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
if (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8) {
hr = E_INVALIDARG;
break;
}
params.device = This->device_name;
params.flow = This->dataflow;
params.share = mode;
params.fmt_in = fmt;
params.fmt_out = NULL;
if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample &&
!(fmt->wBitsPerSample == 32 &&
ext->Samples.wValidBitsPerSample == 24)) {
hr = S_FALSE;
ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
break;
}
} else {
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
break;
if (out) {
*out = NULL;
if (mode == AUDCLNT_SHAREMODE_SHARED)
params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
}
case WAVE_FORMAT_ALAW:
case WAVE_FORMAT_MULAW:
if (fmt->wBitsPerSample != 8) {
hr = E_INVALIDARG;
break;
}
/* Fall-through */
case WAVE_FORMAT_IEEE_FLOAT:
if (fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT && fmt->wBitsPerSample != 32) {
hr = E_INVALIDARG;
break;
}
/* Fall-through */
case WAVE_FORMAT_PCM:
if (fmt->wFormatTag == WAVE_FORMAT_PCM &&
(!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8)) {
hr = E_INVALIDARG;
break;
}
if (fmt->nChannels > 2) {
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
/*
* fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
* ignored, invalid values are happily accepted.
*/
break;
default:
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
pulse_call(is_format_supported, &params);
if (exclusive && hr != S_OK) {
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
CoTaskMemFree(closest);
} else if (hr != S_FALSE)
CoTaskMemFree(closest);
if (params.result == S_FALSE)
*out = &params.fmt_out->Format;
else
*out = closest;
CoTaskMemFree(params.fmt_out);
/* Winepulse does not currently support exclusive mode, if you know of an
* application that uses it, I will correct this..
*/
if (hr == S_OK && exclusive)
return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
TRACE("returning: %08lx %p\n", hr, out ? *out : NULL);
return hr;
return params.result;
}
static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
......
......@@ -2077,6 +2077,149 @@ static NTSTATUS pulse_release_capture_buffer(void *args)
return STATUS_SUCCESS;
}
static NTSTATUS pulse_is_format_supported(void *args)
{
struct is_format_supported_params *params = args;
WAVEFORMATEXTENSIBLE in;
WAVEFORMATEXTENSIBLE *out;
const WAVEFORMATEX *fmt = &in.Format;
const BOOLEAN exclusive = params->share == AUDCLNT_SHAREMODE_EXCLUSIVE;
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 {
memcpy(&in, params->fmt_in, params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE ?
sizeof(in) : sizeof(in.Format));
if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
if (fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
params->result = E_INVALIDARG;
else if (fmt->nAvgBytesPerSec == 0 || fmt->nBlockAlign == 0 ||
(in.Samples.wValidBitsPerSample > fmt->wBitsPerSample))
params->result = E_INVALIDARG;
else if (fmt->nChannels == 0)
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
}
}
if (FAILED(params->result))
return STATUS_SUCCESS;
if (exclusive)
out = &in;
else {
out = params->fmt_out;
memcpy(out, fmt, fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE ?
sizeof(*out) : sizeof((*out).Format));
}
switch (fmt->wFormatTag) {
case WAVE_FORMAT_EXTENSIBLE: {
if ((fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) &&
fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE)) ||
fmt->nBlockAlign != fmt->wBitsPerSample / 8 * fmt->nChannels ||
in.Samples.wValidBitsPerSample > fmt->wBitsPerSample ||
fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec) {
params->result = E_INVALIDARG;
break;
}
if (exclusive) {
UINT32 mask = 0, i, channels = 0;
if (!(in.dwChannelMask & (SPEAKER_ALL | SPEAKER_RESERVED))) {
for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) {
if (i & in.dwChannelMask) {
mask |= i;
++channels;
}
}
if (channels != fmt->nChannels || (in.dwChannelMask & ~mask)) {
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
} else {
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
}
if (IsEqualGUID(&in.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
if (fmt->wBitsPerSample != 32) {
params->result = E_INVALIDARG;
break;
}
if (in.Samples.wValidBitsPerSample != fmt->wBitsPerSample) {
params->result = S_FALSE;
out->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
}
} else if (IsEqualGUID(&in.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
if (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8) {
params->result = E_INVALIDARG;
break;
}
if (in.Samples.wValidBitsPerSample != fmt->wBitsPerSample &&
!(fmt->wBitsPerSample == 32 &&
in.Samples.wValidBitsPerSample == 24)) {
params->result = S_FALSE;
out->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
break;
}
} else {
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
break;
}
case WAVE_FORMAT_ALAW:
case WAVE_FORMAT_MULAW:
if (fmt->wBitsPerSample != 8) {
params->result = E_INVALIDARG;
break;
}
/* Fall-through */
case WAVE_FORMAT_IEEE_FLOAT:
if (fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT && fmt->wBitsPerSample != 32) {
params->result = E_INVALIDARG;
break;
}
/* Fall-through */
case WAVE_FORMAT_PCM: {
if (fmt->wFormatTag == WAVE_FORMAT_PCM &&
(!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8)) {
params->result = E_INVALIDARG;
break;
}
if (fmt->nChannels > 2) {
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
/* fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
* ignored, invalid values are happily accepted. */
break;
}
default:
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
break;
}
/* This driver does not support exclusive mode. */
if (exclusive && params->result == S_OK)
params->result = params->flow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
return STATUS_SUCCESS;
}
static NTSTATUS pulse_get_mix_format(void *args)
{
struct get_mix_format_params *params = args;
......@@ -2395,7 +2538,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
pulse_release_render_buffer,
pulse_get_capture_buffer,
pulse_release_capture_buffer,
pulse_not_implemented,
pulse_is_format_supported,
pulse_get_mix_format,
pulse_get_device_period,
pulse_get_buffer_size,
......@@ -2561,6 +2704,30 @@ static NTSTATUS pulse_wow64_get_capture_buffer(void *args)
return STATUS_SUCCESS;
};
static NTSTATUS pulse_wow64_is_format_supported(void *args)
{
struct
{
PTR32 device;
EDataFlow flow;
AUDCLNT_SHAREMODE share;
PTR32 fmt_in;
PTR32 fmt_out;
HRESULT result;
} *params32 = args;
struct is_format_supported_params params =
{
.device = ULongToPtr(params32->device),
.flow = params32->flow,
.share = params32->share,
.fmt_in = ULongToPtr(params32->fmt_in),
.fmt_out = ULongToPtr(params32->fmt_out)
};
pulse_is_format_supported(&params);
params32->result = params.result;
return STATUS_SUCCESS;
}
static NTSTATUS pulse_wow64_get_mix_format(void *args)
{
struct
......@@ -2840,7 +3007,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
pulse_release_render_buffer,
pulse_wow64_get_capture_buffer,
pulse_release_capture_buffer,
pulse_not_implemented,
pulse_wow64_is_format_supported,
pulse_wow64_get_mix_format,
pulse_wow64_get_device_period,
pulse_wow64_get_buffer_size,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment