From cbbe26ea88f182ef45f977879c568901aa489746 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 2 Nov 2015 11:53:12 -0600 Subject: [PATCH] winepulse: Fixup IsFormatSupported calls. Signed-off-by: Andrew Eikum Signed-off-by: Alexandre Julliard --- dlls/winepulse.drv/mmdevdrv.c | 174 +++++++++++++++++++++++++++++------------- 1 file changed, 120 insertions(+), 54 deletions(-) diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c index 35453af7161..9f933efa200 100644 --- a/dlls/winepulse.drv/mmdevdrv.c +++ b/dlls/winepulse.drv/mmdevdrv.c @@ -1144,10 +1144,8 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt) } } This->map.channels = fmt->nChannels; - if (!mask || mask == SPEAKER_ALL) + if (!mask || (mask & (SPEAKER_ALL|SPEAKER_RESERVED))) mask = get_channel_mask(fmt->nChannels); - else if (mask == ~0U && fmt->nChannels == 1) - mask = SPEAKER_FRONT_CENTER; for (j = 0; j < sizeof(pulse_pos_from_wfx)/sizeof(*pulse_pos_from_wfx) && i < fmt->nChannels; ++j) { if (mask & (1 << j)) This->map.map[i++] = pulse_pos_from_wfx[j]; @@ -1430,79 +1428,147 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface, ACImpl *This = impl_from_IAudioClient(iface); HRESULT hr = S_OK; WAVEFORMATEX *closest = NULL; + BOOL exclusive; TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out); - if (!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out)) + if (!fmt) return E_POINTER; if (out) *out = NULL; - if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) + + 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 (mode == AUDCLNT_SHAREMODE_EXCLUSIVE) - return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED; - switch (fmt->wFormatTag) { - case WAVE_FORMAT_EXTENSIBLE: - if (fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) - return E_INVALIDARG; - dump_fmt(fmt); - break; - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - case WAVE_FORMAT_IEEE_FLOAT: - case WAVE_FORMAT_PCM: - dump_fmt(fmt); - break; - default: - dump_fmt(fmt); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } + if (fmt->nChannels == 0) return AUDCLNT_E_UNSUPPORTED_FORMAT; + closest = clone_format(fmt); - if (!closest) { - if (out) - *out = NULL; + if (!closest) return E_OUTOFMEMORY; - } - if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - UINT32 mask = 0, i, channels = 0; + dump_fmt(fmt); + + switch (fmt->wFormatTag) { + case WAVE_FORMAT_EXTENSIBLE: { WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)closest; - if ((fmt->nChannels > 1 && ext->dwChannelMask == SPEAKER_ALL) || - (fmt->nChannels == 1 && ext->dwChannelMask == ~0U)) { - mask = ext->dwChannelMask; - channels = fmt->nChannels; - } else if (ext->dwChannelMask) { - for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) { - if (i & ext->dwChannelMask) { - mask |= i; - channels++; + 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 (channels < fmt->nChannels) - mask = get_channel_mask(fmt->nChannels); - } else - mask = ext->dwChannelMask; - if (ext->dwChannelMask != mask) { - ext->dwChannelMask = mask; - hr = S_FALSE; } + + if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { + if (fmt->wBitsPerSample != 32) { + hr = E_INVALIDARG; + break; + } + + 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; + } + + 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 (hr == S_OK || !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; + } + + if (exclusive && hr != S_OK) { + hr = AUDCLNT_E_UNSUPPORTED_FORMAT; + CoTaskMemFree(closest); + } else if (hr != S_FALSE) CoTaskMemFree(closest); - if (out) - *out = NULL; - } else if (closest) { - closest->nBlockAlign = - closest->nChannels * closest->wBitsPerSample / 8; - closest->nAvgBytesPerSec = - closest->nBlockAlign * closest->nSamplesPerSec; + else *out = closest; - } + + /* 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: %08x %p\n", hr, out ? *out : NULL); return hr; -- 2.11.4.GIT