Module: wine Branch: master Commit: cbbe26ea88f182ef45f977879c568901aa489746 URL: http://source.winehq.org/git/wine.git/?a=commit;h=cbbe26ea88f182ef45f977879c...
Author: Maarten Lankhorst m.b.lankhorst@gmail.com Date: Mon Nov 2 11:53:12 2015 -0600
winepulse: Fixup IsFormatSupported calls.
Signed-off-by: Andrew Eikum aeikum@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
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 35453af..9f933ef 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;