[PATCH v4 0/5] MR10109: mmdevapi/tests: Test a curated list of wave formats.
The main commit is quite large. I figured that shouldn't be a problem, since most of it is long lists of formats rather than code, but if that's better I can split it more granularly. -- v4: mmdevapi/tests: Test capturing with RATEADJUST in exclusive mode more specifically. mmdevapi/tests: Tweak test logging a little bit. mmdevapi/tests: Test a curated list of wave formats. mmdevapi/tests: Introduce a helper to decide whether a wave format is valid. https://gitlab.winehq.org/wine/wine/-/merge_requests/10109
From: Giovanni Mascellani <gmascellani@codeweavers.com> --- dlls/mmdevapi/tests/capture.c | 8 ++-- dlls/mmdevapi/tests/mmdevapi_tests_private.h | 45 ++++++++++++++++++++ dlls/mmdevapi/tests/render.c | 8 ++-- 3 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 dlls/mmdevapi/tests/mmdevapi_tests_private.h diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index a2cdc0a6af8..7683d1ce155 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -37,6 +37,8 @@ #include "mmdeviceapi.h" #include "audioclient.h" +#include "mmdevapi_tests_private.h" + static const unsigned int sampling_rates[] = { 8000, 16000, 22050, 44100, 48000, 96000 }; static const unsigned int channel_counts[] = { 1, 2, 8 }; static const unsigned int sample_formats[][2] = { {WAVE_FORMAT_PCM, 8}, {WAVE_FORMAT_PCM, 16}, @@ -714,12 +716,8 @@ static void test_formats(AUDCLNT_SHAREMODE mode, BOOL extensible) KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; } - winetest_push_context("%c%s%lux%ux%u", sample_formats[k][0] == WAVE_FORMAT_PCM ? 'P' : 'F', - extensible ? "X" : "", fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, - fmt.Format.nChannels); - + push_format_context(&fmt); test_format(mode, &fmt); - winetest_pop_context(); } } diff --git a/dlls/mmdevapi/tests/mmdevapi_tests_private.h b/dlls/mmdevapi/tests/mmdevapi_tests_private.h new file mode 100644 index 00000000000..5cef994184b --- /dev/null +++ b/dlls/mmdevapi/tests/mmdevapi_tests_private.h @@ -0,0 +1,45 @@ +/* + * Copyright 2025 Giovanni Mascellani for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "wine/test.h" + +#include "audioclient.h" + +inline static void push_format_context(const WAVEFORMATEXTENSIBLE *fmt) +{ + static const char *format_str[] = + { + [WAVE_FORMAT_PCM] = "P", + [WAVE_FORMAT_IEEE_FLOAT] = "F", + [WAVE_FORMAT_ALAW] = "A", + [WAVE_FORMAT_MULAW] = "MU", + }; + + if (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) + { + winetest_push_context("%sX%u(%u)x%lux%u:%lx", format_str[fmt->SubFormat.Data1], + fmt->Format.wBitsPerSample, fmt->Samples.wValidBitsPerSample, + fmt->Format.nSamplesPerSec, fmt->Format.nChannels, fmt->dwChannelMask); + } + else + { + winetest_push_context("%s%ux%lux%u", format_str[fmt->Format.wFormatTag], + fmt->Format.wBitsPerSample, fmt->Format.nSamplesPerSec, fmt->Format.nChannels); + } + +} diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index f6f7545e43b..209a3757f11 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -41,6 +41,8 @@ #include "audiopolicy.h" #include "endpointvolume.h" +#include "mmdevapi_tests_private.h" + static const unsigned int sampling_rates[] = { 8000, 16000, 22050, 44100, 48000, 96000 }; static const unsigned int channel_counts[] = { 1, 2, 8 }; static const unsigned int sample_formats[][2] = { {WAVE_FORMAT_PCM, 8}, {WAVE_FORMAT_PCM, 16}, @@ -675,12 +677,8 @@ static void test_formats(AUDCLNT_SHAREMODE mode, BOOL extensible) KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; } - winetest_push_context("%c%s%lux%ux%u", sample_formats[k][0] == WAVE_FORMAT_PCM ? 'P' : 'F', - extensible ? "X" : "", fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, - fmt.Format.nChannels); - + push_format_context(&fmt); test_format(mode, &fmt); - winetest_pop_context(); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10109
From: Giovanni Mascellani <gmascellani@codeweavers.com> --- dlls/mmdevapi/tests/capture.c | 36 +++-- dlls/mmdevapi/tests/mmdevapi_tests_private.h | 3 +- dlls/mmdevapi/tests/render.c | 148 +++++++++++++++---- 3 files changed, 145 insertions(+), 42 deletions(-) diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index 7683d1ce155..90e8623a31b 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -598,11 +598,21 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) /* In shared mode you can only change bit width, not sampling rate or channel count. */ if (mode == AUDCLNT_SHAREMODE_SHARED) { compatible = fmt->Format.nSamplesPerSec == pwfx->nSamplesPerSec && fmt->Format.nChannels == pwfx->nChannels; - expected = compatible ? S_OK : S_FALSE; - if (fmt->Format.nChannels > 2 && !extensible) - expected = AUDCLNT_E_UNSUPPORTED_FORMAT; - todo_wine_if(hr != expected) - ok(hr == expected, "IsFormatSupported() returns %08lx, expected %08lx\n", hr, expected); + expected = validate_fmt(fmt, TRUE); + if (expected == S_OK) { + /* Correct formats should be accepted, possibly with S_FALSE if they are not compatible. */ + if (!compatible) + expected = S_FALSE; + todo_wine_if(hr != expected) + ok(hr == expected, "IsFormatSupported() returns %08lx, expected %08lx\n", hr, expected); + } else { + /* With incorrect formats it's a mess. Native emits all sorts of possible + * error codes, including S_OK and S_FALSE, without any apparent logic. + * I tried to find some regularity, but it seems hopeless. Also different + * drivers do wildly different things. */ + ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG || broken(hr == S_OK || hr == S_FALSE), + "IsFormatSupported() returns %08lx\n", hr); + } } else { ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || (hr == E_INVALIDARG && extensible), "IsFormatSupported() returns %08lx\n", hr); @@ -622,18 +632,18 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) if ((hrs == S_OK) ^ (hr == S_OK)) trace("Initialize() returns %08lx unlike IsFormatSupported\n", hr); if (mode == AUDCLNT_SHAREMODE_SHARED) { - HRESULT expected = hrs == S_OK ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; - if (fmt->Format.nChannels > 2 && !extensible) - expected = E_INVALIDARG; - todo_wine_if(fmt->Format.nChannels > 2 && !extensible) + compatible = fmt->Format.nSamplesPerSec == pwfx->nSamplesPerSec && fmt->Format.nChannels == pwfx->nChannels; + expected = validate_fmt(fmt, compatible); + todo_wine_if(hr != expected) ok(hr == expected, "Initialize() returns %08lx, expected %08lx\n", hr, expected); } else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) /* Unsupported format implies "create failed" and shadows "not allowed" */ ok(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == hrs, "Initialize() returns %08lx(%08lx)\n", hr, hrs); else + /* For some drivers Initialize() doesn't match IsFormatSupported(). */ todo_wine_if(hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED || (hr == S_OK && hrs != S_OK)) - ok(hrs == S_OK ? hr == S_OK + ok(hrs == S_OK ? hr == S_OK || broken(hr == E_INVALIDARG) : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG, "Initialize() returns %08lx\n", hr); @@ -649,9 +659,7 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_RATEADJUST, 5000000, 0, (WAVEFORMATEX*)fmt, NULL); if (mode == AUDCLNT_SHAREMODE_SHARED) { compatible = fmt->Format.nChannels == pwfx->nChannels; - expected = compatible ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; - if (fmt->Format.nChannels > 2 && !extensible) - expected = E_INVALIDARG; + expected = validate_fmt(fmt, compatible); todo_wine_if(hr != expected) ok(hr == expected, "Initialize(RATEADJUST) returns %08lx, expected %08lx\n", hr, expected); } else { @@ -671,7 +679,7 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) /* With AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM it always succeeds. */ hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, 5000000, 0, (WAVEFORMATEX*)fmt, NULL); if (mode == AUDCLNT_SHAREMODE_SHARED) { - expected = fmt->Format.nChannels <= 2 || extensible? S_OK : E_INVALIDARG; + expected = validate_fmt(fmt, TRUE); todo_wine_if(hr != expected) ok(hr == expected, "Initialize(AUTOCONVERTPCM) returns %08lx\n", hr); } else { diff --git a/dlls/mmdevapi/tests/mmdevapi_tests_private.h b/dlls/mmdevapi/tests/mmdevapi_tests_private.h index 5cef994184b..d68e75010d3 100644 --- a/dlls/mmdevapi/tests/mmdevapi_tests_private.h +++ b/dlls/mmdevapi/tests/mmdevapi_tests_private.h @@ -41,5 +41,6 @@ inline static void push_format_context(const WAVEFORMATEXTENSIBLE *fmt) winetest_push_context("%s%ux%lux%u", format_str[fmt->Format.wFormatTag], fmt->Format.wBitsPerSample, fmt->Format.nSamplesPerSec, fmt->Format.nChannels); } - } + +HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible); diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 209a3757f11..f02a94cab74 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -509,15 +509,109 @@ cleanup: CoTaskMemFree(pwfx); } +HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible) +{ + WAVEFORMATEXTENSIBLE fmt2 = *fmt; + HRESULT ret; + + /* Reduce non-extensible formats to extensible ones. */ + if (fmt2.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) + { + switch (fmt2.Format.wFormatTag) + { + case WAVE_FORMAT_PCM: fmt2.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; break; + case WAVE_FORMAT_IEEE_FLOAT: fmt2.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; break; + default: return AUDCLNT_E_UNSUPPORTED_FORMAT; + } + + if (fmt2.Format.nChannels > 2) + return E_INVALIDARG; + + fmt2.dwChannelMask = (1u << fmt2.Format.nChannels) - 1; + fmt2.Samples.wValidBitsPerSample = fmt2.Format.wBitsPerSample; + fmt2.Format.cbSize = sizeof(fmt2) - sizeof(fmt2.Format); + } + + if (fmt2.Format.cbSize < sizeof(fmt2) - sizeof(fmt2.Format)) + ret = E_INVALIDARG; + else if (fmt2.Format.nChannels == 0 || fmt2.Format.nSamplesPerSec == 0) + ret = E_INVALIDARG; + else if (fmt2.Format.nBlockAlign != fmt2.Format.nChannels * fmt2.Format.wBitsPerSample / 8) + ret = E_INVALIDARG; + else if (fmt2.Format.nAvgBytesPerSec != fmt2.Format.nBlockAlign * fmt2.Format.nSamplesPerSec) + ret = E_INVALIDARG; + else if (fmt2.Samples.wValidBitsPerSample == 0) + ret = E_INVALIDARG; + else if (fmt2.Samples.wValidBitsPerSample > fmt2.Format.wBitsPerSample) + ret = E_INVALIDARG; + else if (IsEqualGUID(&fmt2.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) + { + if (fmt2.Format.wBitsPerSample != 8 && fmt2.Format.wBitsPerSample != 16 + && fmt2.Format.wBitsPerSample != 24 && fmt2.Format.wBitsPerSample != 32) + ret = E_INVALIDARG; + else if (fmt2.Format.wBitsPerSample == 32 && fmt2.Samples.wValidBitsPerSample == 24) + ret = S_OK; + else if (fmt2.Samples.wValidBitsPerSample != fmt2.Format.wBitsPerSample) + ret = AUDCLNT_E_UNSUPPORTED_FORMAT; + else + ret = S_OK; + } + else if (IsEqualGUID(&fmt2.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + if (fmt2.Format.wBitsPerSample != 32 && fmt2.Format.wBitsPerSample != 64) + ret = E_INVALIDARG; + else if (fmt2.Format.wBitsPerSample != 32) + ret = AUDCLNT_E_UNSUPPORTED_FORMAT; + else if (fmt2.Samples.wValidBitsPerSample != fmt2.Format.wBitsPerSample) + ret = AUDCLNT_E_UNSUPPORTED_FORMAT; + else + ret = S_OK; + } + else + ret = AUDCLNT_E_UNSUPPORTED_FORMAT; + + if (!compatible && ret == S_OK) + ret = AUDCLNT_E_UNSUPPORTED_FORMAT; + + return ret; +} + static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) { IAudioClient *ac; HRESULT hr, hrs, expected; WAVEFORMATEX *pwfx, *pwfx2; - BOOL compatible, extensible; + BOOL compatible, extensible, channel_mismatch = FALSE; extensible = fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE; + if (extensible) + { + switch (fmt->Format.nChannels) + { + case 1: + channel_mismatch = fmt->dwChannelMask != KSAUDIO_SPEAKER_MONO; + break; + + case 2: + channel_mismatch = fmt->dwChannelMask != KSAUDIO_SPEAKER_STEREO; + break; + + case 4: + channel_mismatch = fmt->dwChannelMask != KSAUDIO_SPEAKER_QUAD; + break; + + case 6: + channel_mismatch = fmt->dwChannelMask != KSAUDIO_SPEAKER_5POINT1; + break; + + case 8: + channel_mismatch = fmt->dwChannelMask != KSAUDIO_SPEAKER_7POINT1_SURROUND + && fmt->dwChannelMask != KSAUDIO_SPEAKER_7POINT1; + break; + } + } + hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&ac); ok(hr == S_OK, "Activation failed with %08lx\n", hr); @@ -527,16 +621,6 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) hr = IAudioClient_GetMixFormat(ac, &pwfx); ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - if (extensible) { - WAVEFORMATEXTENSIBLE *pxwfx = (WAVEFORMATEXTENSIBLE*)pwfx; - - /* We don't want to fight with the driver over the speaker configuration, - * so just take whatever they give us, if it's valid. */ - if (fmt->Format.nChannels == pwfx->nChannels && pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE - && pxwfx->dwChannelMask != 0) - fmt->dwChannelMask = pxwfx->dwChannelMask; - } - pwfx2 = (WAVEFORMATEX*)0xDEADF00D; hr = IAudioClient_IsFormatSupported(ac, mode, (WAVEFORMATEX*)fmt, &pwfx2); hrs = hr; @@ -546,11 +630,22 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) /* In shared mode you can only change bit width, not sampling rate or channel count. */ if (mode == AUDCLNT_SHAREMODE_SHARED) { compatible = fmt->Format.nSamplesPerSec == pwfx->nSamplesPerSec && fmt->Format.nChannels == pwfx->nChannels; - expected = compatible ? S_OK : S_FALSE; - if (fmt->Format.nChannels > 2 && !extensible) - expected = AUDCLNT_E_UNSUPPORTED_FORMAT; - todo_wine_if(hr != expected) - ok(hr == expected, "IsFormatSupported() returns %08lx, expected %08lx\n", hr, expected); + expected = validate_fmt(fmt, TRUE); + if (expected == S_OK) { + /* Correct formats should be accepted, possibly with S_FALSE if they are not compatible. */ + if (!compatible) + expected = S_FALSE; + todo_wine_if(hr != expected) + ok(hr == expected || broken(hr == S_OK || (hr == S_FALSE && channel_mismatch)) /* Some drivers are more relaxed. */, + "IsFormatSupported() returns %08lx, expected %08lx\n", hr, expected); + } else { + /* With incorrect formats it's a mess. Native emits all sorts of possible + * error codes, including S_OK and S_FALSE, without any apparent logic. + * I tried to find some regularity, but it seems hopeless. Also different + * drivers do wildly different things. */ + ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG || broken(hr == S_OK || hr == S_FALSE), + "IsFormatSupported() returns %08lx\n", hr); + } } else { ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl, "IsFormatSupported() returns %08lx\n", hr); @@ -570,11 +665,11 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) if ((hrs == S_OK) ^ (hr == S_OK)) trace("Initialize() returns %08lx unlike IsFormatSupported\n", hr); if (mode == AUDCLNT_SHAREMODE_SHARED) { - expected = hrs == S_OK ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; - if (fmt->Format.nChannels > 2 && !extensible) - expected = E_INVALIDARG; - todo_wine_if(fmt->Format.nChannels > 2 && !extensible) - ok(hr == expected, "Initialize() returns %08lx, expected %08lx\n", hr, expected); + compatible = fmt->Format.nSamplesPerSec == pwfx->nSamplesPerSec && fmt->Format.nChannels == pwfx->nChannels; + expected = validate_fmt(fmt, compatible); + todo_wine_if(hr != expected) + ok(hr == expected || broken(hr == S_OK) /* Some drivers are more relaxed. */, + "Initialize() returns %08lx, expected %08lx\n", hr, expected); } else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) /* Unsupported format implies "create failed" and shadows "not allowed" */ ok(hrs == hexcl && (hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == hrs), @@ -598,11 +693,10 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_RATEADJUST, 5000000, 0, (WAVEFORMATEX*)fmt, NULL); if (mode == AUDCLNT_SHAREMODE_SHARED) { compatible = fmt->Format.nChannels == pwfx->nChannels; - expected = compatible ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; - if (fmt->Format.nChannels > 2 && !extensible) - expected = E_INVALIDARG; + expected = validate_fmt(fmt, compatible); todo_wine_if(hr != expected) - ok(hr == expected, "Initialize(RATEADJUST) returns %08lx, expected %08lx\n", hr, expected); + ok(hr == expected || broken(hr == S_OK || (hr == AUDCLNT_E_UNSUPPORTED_FORMAT && channel_mismatch)) /* Some drivers are more relaxed. */, + "Initialize(RATEADJUST) returns %08lx, expected %08lx\n", hr, expected); } else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) /* Unsupported format implies "create failed" and shadows "not allowed" */ ok(hrs == hexcl && (hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == hrs), @@ -625,9 +719,9 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) /* With AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM it always succeeds. */ hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, 5000000, 0, (WAVEFORMATEX*)fmt, NULL); if (mode == AUDCLNT_SHAREMODE_SHARED) { - expected = fmt->Format.nChannels <= 2 || extensible ? S_OK : E_INVALIDARG; + expected = validate_fmt(fmt, TRUE); todo_wine_if(hr != expected) - ok(hr == expected, "Initialize(AUTOCONVERTPCM) returns %08lx\n", hr); + ok(hr == expected, "Initialize(AUTOCONVERTPCM) returns %08lx, expected %08lx\n", hr, expected); } else { todo_wine_if(hr != E_INVALIDARG) ok(hr == E_INVALIDARG, "Initialize(AUTOCONVERTPCM) returns %08lx\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10109
From: Giovanni Mascellani <gmascellani@codeweavers.com> Which includes invalid formats. Previously only valid formats were tested. --- dlls/mmdevapi/tests/capture.c | 54 +-- dlls/mmdevapi/tests/mmdevapi_tests_private.h | 10 + dlls/mmdevapi/tests/render.c | 355 ++++++++++++++++--- 3 files changed, 328 insertions(+), 91 deletions(-) diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index 90e8623a31b..38de957dfb8 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -39,11 +39,6 @@ #include "mmdevapi_tests_private.h" -static const unsigned int sampling_rates[] = { 8000, 16000, 22050, 44100, 48000, 96000 }; -static const unsigned int channel_counts[] = { 1, 2, 8 }; -static const unsigned int sample_formats[][2] = { {WAVE_FORMAT_PCM, 8}, {WAVE_FORMAT_PCM, 16}, - {WAVE_FORMAT_PCM, 32}, {WAVE_FORMAT_IEEE_FLOAT, 32} }; - #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) /* undocumented error code */ @@ -475,6 +470,8 @@ static void test_audioclient(void) &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)?"FLOAT":"Other")); } + fill_wave_formats((WAVEFORMATEXTENSIBLE *)pwfx); + pwfx2 = (WAVEFORMATEX*)0xDEADF00D; hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2); ok(hr == S_OK, "Valid IsFormatSupported(Shared) call returns %08lx\n", hr); @@ -610,11 +607,12 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) * error codes, including S_OK and S_FALSE, without any apparent logic. * I tried to find some regularity, but it seems hopeless. Also different * drivers do wildly different things. */ + todo_wine_if(SUCCEEDED(hr)) ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG || broken(hr == S_OK || hr == S_FALSE), "IsFormatSupported() returns %08lx\n", hr); } } else { - ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || (hr == E_INVALIDARG && extensible), + ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG || (hr == E_INVALIDARG && extensible), "IsFormatSupported() returns %08lx\n", hr); } @@ -694,41 +692,21 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) static void test_formats(AUDCLNT_SHAREMODE mode, BOOL extensible) { - WAVEFORMATEXTENSIBLE fmt; - int i, j, k; + unsigned int i; winetest_push_context("%s", mode == AUDCLNT_SHAREMODE_SHARED ? "shared" : "exclusive"); - fmt.Format.cbSize = extensible ? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0; - - for (i = 0; i < ARRAY_SIZE(sampling_rates); i++) { - for (j = 0; j < ARRAY_SIZE(channel_counts); j++) { - for (k = 0; k < ARRAY_SIZE(sample_formats); k++) { - fmt.Format.wFormatTag = extensible ? WAVE_FORMAT_EXTENSIBLE : sample_formats[k][0]; - fmt.Format.nSamplesPerSec = sampling_rates[i]; - fmt.Format.wBitsPerSample = sample_formats[k][1]; - fmt.Format.nChannels = channel_counts[j]; - fmt.Format.nBlockAlign = fmt.Format.nChannels * fmt.Format.wBitsPerSample / 8; - fmt.Format.nAvgBytesPerSec= fmt.Format.nBlockAlign * fmt.Format.nSamplesPerSec; - - if (extensible) { - fmt.Samples.wValidBitsPerSample = fmt.Format.wBitsPerSample; - switch (fmt.Format.nChannels) { - case 1: fmt.dwChannelMask = KSAUDIO_SPEAKER_MONO; break; - case 2: fmt.dwChannelMask = KSAUDIO_SPEAKER_STEREO; break; - case 4: fmt.dwChannelMask = KSAUDIO_SPEAKER_SURROUND; break; - case 6: fmt.dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break; - case 8: fmt.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND; break; - } - fmt.SubFormat = sample_formats[k][0] == WAVE_FORMAT_PCM ? - KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } - - push_format_context(&fmt); - test_format(mode, &fmt); - winetest_pop_context(); - } - } + for (i = 0; i < wave_format_count; ++i) + { + const char *additional_context = wave_formats[i].additional_context; + WAVEFORMATEXTENSIBLE fmt = wave_formats[i].format; + + winetest_push_context("test %u%s%s", i, additional_context ? ", " : "", + additional_context ? additional_context : ""); + push_format_context(&fmt); + test_format(mode, &fmt); + winetest_pop_context(); + winetest_pop_context(); } winetest_pop_context(); diff --git a/dlls/mmdevapi/tests/mmdevapi_tests_private.h b/dlls/mmdevapi/tests/mmdevapi_tests_private.h index d68e75010d3..11c1214f67b 100644 --- a/dlls/mmdevapi/tests/mmdevapi_tests_private.h +++ b/dlls/mmdevapi/tests/mmdevapi_tests_private.h @@ -20,6 +20,15 @@ #include "audioclient.h" +struct wave_format +{ + WAVEFORMATEXTENSIBLE format; + const char *additional_context; +}; + +extern struct wave_format *wave_formats; +extern size_t wave_format_count; + inline static void push_format_context(const WAVEFORMATEXTENSIBLE *fmt) { static const char *format_str[] = @@ -44,3 +53,4 @@ inline static void push_format_context(const WAVEFORMATEXTENSIBLE *fmt) } HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible); +void fill_wave_formats(const WAVEFORMATEXTENSIBLE *base_fmt); diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index f02a94cab74..25153b5c85f 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -24,6 +24,7 @@ #include <math.h> #include <stdio.h> +#include <assert.h> #include "wine/test.h" @@ -43,11 +44,6 @@ #include "mmdevapi_tests_private.h" -static const unsigned int sampling_rates[] = { 8000, 16000, 22050, 44100, 48000, 96000 }; -static const unsigned int channel_counts[] = { 1, 2, 8 }; -static const unsigned int sample_formats[][2] = { {WAVE_FORMAT_PCM, 8}, {WAVE_FORMAT_PCM, 16}, - {WAVE_FORMAT_PCM, 32}, {WAVE_FORMAT_IEEE_FLOAT, 32} }; - #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) /* undocumented error code */ @@ -261,6 +257,8 @@ static void test_audioclient(void) CoTaskMemFree(pwfx2); } + fill_wave_formats((WAVEFORMATEXTENSIBLE *)pwfx); + pwfx2 = (WAVEFORMATEX*)0xDEADF00D; hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2); ok(hr == S_OK, "Valid IsFormatSupported(Shared) call returns %08lx\n", hr); @@ -509,6 +507,280 @@ cleanup: CoTaskMemFree(pwfx); } +struct wave_format *wave_formats = NULL; +size_t wave_format_count = 0; +size_t wave_format_capacity = 0; + +static WAVEFORMATEXTENSIBLE *push_wave_format_with_context(const WAVEFORMATEXTENSIBLE *base_fmt, + const char *additional_context) +{ + if (wave_format_count == wave_format_capacity) + { + wave_format_capacity = max(1, 2 * wave_format_capacity); + + wave_formats = realloc(wave_formats, + sizeof(*wave_formats) * wave_format_capacity); + assert(wave_formats); + } + + wave_formats[wave_format_count].format = *base_fmt; + wave_formats[wave_format_count].additional_context = additional_context; + + return &wave_formats[wave_format_count++].format; +} + +static WAVEFORMATEXTENSIBLE *push_wave_format(const WAVEFORMATEXTENSIBLE *base_fmt) +{ + return push_wave_format_with_context(base_fmt, NULL); +} + +static void convert_to_unextensible(WAVEFORMATEXTENSIBLE *fmt) +{ + assert(fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE); + + fmt->Format.wFormatTag = fmt->SubFormat.Data1; + fmt->Format.cbSize = 0; + memset((&fmt->Format) + 1, 0, sizeof(*fmt) - sizeof(fmt->Format)); +} + +static WAVEFORMATEX *repush_wave_format_as_unextensible(void) +{ + WAVEFORMATEXTENSIBLE *fmt; + + fmt = push_wave_format_with_context(&wave_formats[wave_format_count - 1].format, + wave_formats[wave_format_count - 1].additional_context); + + convert_to_unextensible(fmt); + + return &fmt->Format; +} + +void fill_wave_formats(const WAVEFORMATEXTENSIBLE *base_fmt) +{ + static const DWORD channel_count_mask[][2] = + { + {0, 0}, + + {1, KSAUDIO_SPEAKER_DIRECTOUT}, + {1, KSAUDIO_SPEAKER_MONO}, + {1, KSAUDIO_SPEAKER_STEREO}, + {1, SPEAKER_BACK_LEFT}, + {1, SPEAKER_BACK_LEFT | SPEAKER_TOP_BACK_CENTER}, + {1, KSAUDIO_SPEAKER_7POINT1_SURROUND}, + {1, KSAUDIO_SPEAKER_MONO | SPEAKER_ALL}, + {1, SPEAKER_ALL}, + {1, KSAUDIO_SPEAKER_MONO | SPEAKER_RESERVED}, + {1, SPEAKER_RESERVED}, + + {2, KSAUDIO_SPEAKER_DIRECTOUT}, + {2, KSAUDIO_SPEAKER_MONO}, + {2, KSAUDIO_SPEAKER_STEREO}, + {2, SPEAKER_BACK_LEFT}, + {2, SPEAKER_BACK_LEFT | SPEAKER_TOP_BACK_CENTER}, + {2, KSAUDIO_SPEAKER_7POINT1_SURROUND}, + {2, KSAUDIO_SPEAKER_MONO | SPEAKER_ALL}, + {2, KSAUDIO_SPEAKER_STEREO | SPEAKER_ALL}, + {2, SPEAKER_ALL}, + {2, KSAUDIO_SPEAKER_STEREO | SPEAKER_RESERVED}, + {2, SPEAKER_RESERVED}, + + {4, KSAUDIO_SPEAKER_DIRECTOUT}, + {4, KSAUDIO_SPEAKER_QUAD}, + {4, KSAUDIO_SPEAKER_QUAD | SPEAKER_ALL}, + {4, SPEAKER_ALL}, + {4, KSAUDIO_SPEAKER_QUAD | SPEAKER_RESERVED}, + {4, SPEAKER_RESERVED}, + + {4, KSAUDIO_SPEAKER_DIRECTOUT}, + {4, KSAUDIO_SPEAKER_5POINT1}, + {4, KSAUDIO_SPEAKER_5POINT1 | SPEAKER_ALL}, + {4, SPEAKER_ALL}, + {4, KSAUDIO_SPEAKER_5POINT1 | SPEAKER_RESERVED}, + {4, SPEAKER_RESERVED}, + + {8, KSAUDIO_SPEAKER_DIRECTOUT}, + {8, KSAUDIO_SPEAKER_MONO}, + {8, KSAUDIO_SPEAKER_STEREO}, + {8, KSAUDIO_SPEAKER_7POINT1_SURROUND}, + {8, KSAUDIO_SPEAKER_7POINT1_SURROUND & ~SPEAKER_SIDE_LEFT}, + {8, (KSAUDIO_SPEAKER_7POINT1_SURROUND & ~SPEAKER_SIDE_LEFT) | SPEAKER_FRONT_RIGHT_OF_CENTER}, + {8, KSAUDIO_SPEAKER_7POINT1_SURROUND | SPEAKER_ALL}, + {8, SPEAKER_ALL}, + {8, KSAUDIO_SPEAKER_7POINT1_SURROUND | SPEAKER_RESERVED}, + {8, SPEAKER_RESERVED}, + }; + + static const DWORD sample_formats[][3] = + { + {WAVE_FORMAT_PCM, 0, 0}, + {WAVE_FORMAT_PCM, 1, 1}, + {WAVE_FORMAT_PCM, 15, 15}, + {WAVE_FORMAT_PCM, 16, 0}, + {WAVE_FORMAT_PCM, 16, 1}, + {WAVE_FORMAT_PCM, 16, 8}, + {WAVE_FORMAT_PCM, 16, 15}, + {WAVE_FORMAT_PCM, 16, 16}, + {WAVE_FORMAT_PCM, 16, 17}, + {WAVE_FORMAT_PCM, 24, 16}, + {WAVE_FORMAT_PCM, 24, 23}, + {WAVE_FORMAT_PCM, 24, 24}, + {WAVE_FORMAT_PCM, 24, 25}, + {WAVE_FORMAT_PCM, 32, 0}, + {WAVE_FORMAT_PCM, 32, 1}, + {WAVE_FORMAT_PCM, 32, 8}, + {WAVE_FORMAT_PCM, 32, 16}, + {WAVE_FORMAT_PCM, 32, 17}, + {WAVE_FORMAT_PCM, 32, 24}, + {WAVE_FORMAT_PCM, 32, 31}, + {WAVE_FORMAT_PCM, 32, 33}, + {WAVE_FORMAT_PCM, 32, 32}, + {WAVE_FORMAT_PCM, 64, 64}, + {WAVE_FORMAT_PCM, 96, 96}, + {WAVE_FORMAT_PCM, 100, 100}, + + {WAVE_FORMAT_IEEE_FLOAT, 0, 0}, + {WAVE_FORMAT_IEEE_FLOAT, 1, 1}, + {WAVE_FORMAT_IEEE_FLOAT, 15, 15}, + {WAVE_FORMAT_IEEE_FLOAT, 16, 16}, + {WAVE_FORMAT_IEEE_FLOAT, 24, 24}, + {WAVE_FORMAT_IEEE_FLOAT, 32, 0}, + {WAVE_FORMAT_IEEE_FLOAT, 32, 1}, + {WAVE_FORMAT_IEEE_FLOAT, 32, 16}, + {WAVE_FORMAT_IEEE_FLOAT, 32, 31}, + {WAVE_FORMAT_IEEE_FLOAT, 32, 32}, + {WAVE_FORMAT_IEEE_FLOAT, 32, 33}, + {WAVE_FORMAT_IEEE_FLOAT, 64, 0}, + {WAVE_FORMAT_IEEE_FLOAT, 64, 32}, + {WAVE_FORMAT_IEEE_FLOAT, 64, 63}, + {WAVE_FORMAT_IEEE_FLOAT, 64, 64}, + {WAVE_FORMAT_IEEE_FLOAT, 64, 65}, + {WAVE_FORMAT_IEEE_FLOAT, 96, 96}, + {WAVE_FORMAT_IEEE_FLOAT, 100, 100}, + + {WAVE_FORMAT_ALAW, 8, 0}, + {WAVE_FORMAT_ALAW, 8, 1}, + {WAVE_FORMAT_ALAW, 8, 7}, + {WAVE_FORMAT_ALAW, 8, 8}, + {WAVE_FORMAT_ALAW, 8, 9}, + {WAVE_FORMAT_ALAW, 16, 0}, + {WAVE_FORMAT_ALAW, 16, 1}, + {WAVE_FORMAT_ALAW, 16, 8}, + {WAVE_FORMAT_ALAW, 16, 16}, + {WAVE_FORMAT_ALAW, 16, 17}, + + {WAVE_FORMAT_MULAW, 8, 0}, + {WAVE_FORMAT_MULAW, 8, 1}, + {WAVE_FORMAT_MULAW, 8, 7}, + {WAVE_FORMAT_MULAW, 8, 8}, + {WAVE_FORMAT_MULAW, 8, 9}, + {WAVE_FORMAT_MULAW, 16, 0}, + {WAVE_FORMAT_MULAW, 16, 1}, + {WAVE_FORMAT_MULAW, 16, 8}, + {WAVE_FORMAT_MULAW, 16, 16}, + {WAVE_FORMAT_MULAW, 16, 17}, + }; + + static const DWORD sample_rates[] = + { + 0, + 100, + 8000, + 11025, + 16000, + 22050, + 43123, + 44100, + 48000, + 96000, + 192000, + 384000, + }; + + WAVEFORMATEXTENSIBLE *fmt; + unsigned int i; + + wave_format_count = 0; + + push_wave_format(base_fmt); + repush_wave_format_as_unextensible(); + + /* Change channel count or mask. */ + for (i = 0; i < ARRAY_SIZE(channel_count_mask); ++i) + { + fmt = push_wave_format(base_fmt); + fmt->Format.nChannels = channel_count_mask[i][0]; + fmt->dwChannelMask = channel_count_mask[i][1]; + + if (i == 0 || channel_count_mask[i][0] != channel_count_mask[i - 1][0]) + repush_wave_format_as_unextensible(); + } + + /* Change sample format. */ + for (i = 0; i < ARRAY_SIZE(sample_formats); ++i) + { + fmt = push_wave_format(base_fmt); + fmt->SubFormat.Data1 = sample_formats[i][0]; + fmt->Format.wBitsPerSample = sample_formats[i][1]; + fmt->Samples.wValidBitsPerSample = sample_formats[i][2]; + + if (fmt->Format.wBitsPerSample == fmt->Samples.wValidBitsPerSample) + repush_wave_format_as_unextensible(); + } + + /* Change the sample rate. */ + for (i = 0; i < ARRAY_SIZE(sample_rates); ++i) + { + fmt = push_wave_format(base_fmt); + fmt->Format.nSamplesPerSec = sample_rates[i]; + repush_wave_format_as_unextensible(); + } + + /* Fix nBlockAlign and nAvgBytesPerSec up to here. */ + for (i = 0; i < wave_format_count; ++i) + { + fmt = &wave_formats[i].format; + + fmt->Format.nBlockAlign = fmt->Format.nChannels * fmt->Format.wBitsPerSample / CHAR_BIT; + fmt->Format.nAvgBytesPerSec = fmt->Format.nBlockAlign * fmt->Format.nSamplesPerSec; + } + + /* Break nAvgBytesPerSec. */ + fmt = push_wave_format_with_context(base_fmt, "nAvgBytesPerSec = 0"); + fmt->Format.nAvgBytesPerSec = 0; + repush_wave_format_as_unextensible(); + + fmt = push_wave_format_with_context(base_fmt, "nAvgBytesPerSec += 1"); + fmt->Format.nAvgBytesPerSec += 1; + repush_wave_format_as_unextensible(); + + fmt = push_wave_format_with_context(base_fmt, "nAvgBytesPerSec -= 1"); + fmt->Format.nAvgBytesPerSec -= 1; + repush_wave_format_as_unextensible(); + + /* Break nBlockAlign. */ + fmt = push_wave_format_with_context(base_fmt, "nBlockAlign = 0"); + fmt->Format.nBlockAlign = 0; + repush_wave_format_as_unextensible(); + + fmt = push_wave_format_with_context(base_fmt, "nBlockAlign += 1"); + fmt->Format.nBlockAlign += 1; + repush_wave_format_as_unextensible(); + + fmt = push_wave_format_with_context(base_fmt, "nBlockAlign -= 1"); + fmt->Format.nBlockAlign -= 1; + repush_wave_format_as_unextensible(); + + /* Break cbSize. */ + fmt = push_wave_format_with_context(base_fmt, "cbSize = 0"); + fmt->Format.cbSize = 0; + + fmt = push_wave_format_with_context(base_fmt, "cbSize += 1"); + fmt->Format.cbSize += 1; + + fmt = push_wave_format_with_context(base_fmt, "cbSize -= 1"); + fmt->Format.cbSize -= 1; +} + HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible) { WAVEFORMATEXTENSIBLE fmt2 = *fmt; @@ -581,11 +853,9 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) IAudioClient *ac; HRESULT hr, hrs, expected; WAVEFORMATEX *pwfx, *pwfx2; - BOOL compatible, extensible, channel_mismatch = FALSE; - - extensible = fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE; + BOOL compatible, channel_mismatch = FALSE; - if (extensible) + if (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { switch (fmt->Format.nChannels) { @@ -643,11 +913,12 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) * error codes, including S_OK and S_FALSE, without any apparent logic. * I tried to find some regularity, but it seems hopeless. Also different * drivers do wildly different things. */ + todo_wine_if(SUCCEEDED(hr)) ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG || broken(hr == S_OK || hr == S_FALSE), "IsFormatSupported() returns %08lx\n", hr); } } else { - ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl, + ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG || hr == hexcl, "IsFormatSupported() returns %08lx\n", hr); } @@ -676,9 +947,9 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) "Initialize() returns %08lx(%08lx)\n", hr, hrs); else /* For some drivers Initialize() doesn't match IsFormatSupported(). */ - ok(hrs == S_OK ? hr == S_OK || broken(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED) - : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || - (hr == E_INVALIDARG && fmt->Format.nChannels > 2 && !extensible) || broken(hr == S_OK), + ok(hrs == S_OK ? hr == S_OK || broken(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == E_INVALIDARG) + : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT + || hr == E_INVALIDARG || broken(hr == S_OK), "Initialize() returns %08lx\n", hr); IAudioClient_Release(ac); @@ -703,9 +974,9 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) "Initialize(RATEADJUST) returns %08lx(%08lx)\n", hr, hrs); else /* For some drivers Initialize() doesn't match IsFormatSupported(). */ - ok(hrs == S_OK ? hr == S_OK || broken(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED) - : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || - (hr == E_INVALIDARG && fmt->Format.nChannels > 2 && !extensible) || broken(hr == S_OK), + ok(hrs == S_OK ? hr == S_OK || broken(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == E_INVALIDARG) + : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT + || hr == E_INVALIDARG || broken(hr == S_OK), "Initialize(RATEADJUST) returns %08lx\n", hr); IAudioClient_Release(ac); @@ -739,43 +1010,23 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) IAudioClient_Release(ac); } -static void test_formats(AUDCLNT_SHAREMODE mode, BOOL extensible) +static void test_formats(AUDCLNT_SHAREMODE mode) { - WAVEFORMATEXTENSIBLE fmt; - int i, j, k; + unsigned int i; winetest_push_context("%s", mode == AUDCLNT_SHAREMODE_SHARED ? "shared" : "exclusive"); - fmt.Format.cbSize = extensible ? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0; - - for (i = 0; i < ARRAY_SIZE(sampling_rates); i++) { - for (j = 0; j < ARRAY_SIZE(channel_counts); j++) { - for (k = 0; k < ARRAY_SIZE(sample_formats); k++) { - fmt.Format.wFormatTag = extensible ? WAVE_FORMAT_EXTENSIBLE : sample_formats[k][0]; - fmt.Format.nSamplesPerSec = sampling_rates[i]; - fmt.Format.wBitsPerSample = sample_formats[k][1]; - fmt.Format.nChannels = channel_counts[j]; - fmt.Format.nBlockAlign = fmt.Format.nChannels * fmt.Format.wBitsPerSample / 8; - fmt.Format.nAvgBytesPerSec= fmt.Format.nBlockAlign * fmt.Format.nSamplesPerSec; - - if (extensible) { - fmt.Samples.wValidBitsPerSample = fmt.Format.wBitsPerSample; - switch (fmt.Format.nChannels) { - case 1: fmt.dwChannelMask = KSAUDIO_SPEAKER_MONO; break; - case 2: fmt.dwChannelMask = KSAUDIO_SPEAKER_STEREO; break; - case 4: fmt.dwChannelMask = KSAUDIO_SPEAKER_SURROUND; break; - case 6: fmt.dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break; - case 8: fmt.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND; break; - } - fmt.SubFormat = sample_formats[k][0] == WAVE_FORMAT_PCM ? - KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } - - push_format_context(&fmt); - test_format(mode, &fmt); - winetest_pop_context(); - } - } + for (i = 0; i < wave_format_count; ++i) + { + const char *additional_context = wave_formats[i].additional_context; + WAVEFORMATEXTENSIBLE fmt = wave_formats[i].format; + + winetest_push_context("test %u%s%s", i, additional_context ? ", " : "", + additional_context ? additional_context : ""); + push_format_context(&fmt); + test_format(mode, &fmt); + winetest_pop_context(); + winetest_pop_context(); } winetest_pop_context(); @@ -2977,10 +3228,8 @@ START_TEST(render) test_worst_case(); test_endpointvolume(); test_audio_clock_adjustment(); - test_formats(AUDCLNT_SHAREMODE_EXCLUSIVE, FALSE); - test_formats(AUDCLNT_SHAREMODE_SHARED, FALSE); - test_formats(AUDCLNT_SHAREMODE_EXCLUSIVE, TRUE); - test_formats(AUDCLNT_SHAREMODE_SHARED, TRUE); + test_formats(AUDCLNT_SHAREMODE_EXCLUSIVE); + test_formats(AUDCLNT_SHAREMODE_SHARED); IMMDevice_Release(dev); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10109
From: Giovanni Mascellani <gmascellani@codeweavers.com> In particular, dump whether Initialize() passed, rather than IsFormatSupported(), which is much more unreliable. --- dlls/mmdevapi/tests/capture.c | 7 ++++--- dlls/mmdevapi/tests/render.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index 38de957dfb8..22ccab208d8 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -589,8 +589,6 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) pwfx2 = (WAVEFORMATEX*)0xDEADF00D; hr = IAudioClient_IsFormatSupported(ac, mode, (WAVEFORMATEX*)fmt, &pwfx2); hrs = hr; - if (hr == S_OK) - trace("IsSupported() is true\n"); /* In shared mode you can only change bit width, not sampling rate or channel count. */ if (mode == AUDCLNT_SHAREMODE_SHARED) { @@ -628,7 +626,7 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) hr = IAudioClient_Initialize(ac, mode, 0, 5000000, 0, (WAVEFORMATEX*)fmt, NULL); if ((hrs == S_OK) ^ (hr == S_OK)) - trace("Initialize() returns %08lx unlike IsFormatSupported\n", hr); + trace("Initialize() returns %08lx while IsFormatSupported() returns %08lx\n", hr, hrs); if (mode == AUDCLNT_SHAREMODE_SHARED) { compatible = fmt->Format.nSamplesPerSec == pwfx->nSamplesPerSec && fmt->Format.nChannels == pwfx->nChannels; expected = validate_fmt(fmt, compatible); @@ -645,6 +643,9 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG, "Initialize() returns %08lx\n", hr); + if (hr == S_OK) + trace("Initialize() succeeded\n"); + IAudioClient_Release(ac); hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 25153b5c85f..799b6ccfffb 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -894,8 +894,6 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) pwfx2 = (WAVEFORMATEX*)0xDEADF00D; hr = IAudioClient_IsFormatSupported(ac, mode, (WAVEFORMATEX*)fmt, &pwfx2); hrs = hr; - if (hr == S_OK) - trace("IsFormatSupported() is true\n"); /* In shared mode you can only change bit width, not sampling rate or channel count. */ if (mode == AUDCLNT_SHAREMODE_SHARED) { @@ -934,7 +932,7 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) hr = IAudioClient_Initialize(ac, mode, 0, 5000000, 0, (WAVEFORMATEX*)fmt, NULL); if ((hrs == S_OK) ^ (hr == S_OK)) - trace("Initialize() returns %08lx unlike IsFormatSupported\n", hr); + trace("Initialize() returns %08lx while IsFormatSupported() returns %08lx\n", hr, hrs); if (mode == AUDCLNT_SHAREMODE_SHARED) { compatible = fmt->Format.nSamplesPerSec == pwfx->nSamplesPerSec && fmt->Format.nChannels == pwfx->nChannels; expected = validate_fmt(fmt, compatible); @@ -952,6 +950,9 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) || hr == E_INVALIDARG || broken(hr == S_OK), "Initialize() returns %08lx\n", hr); + if (hr == S_OK) + trace("Initialize() succeeded\n"); + IAudioClient_Release(ac); hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10109
From: Giovanni Mascellani <gmascellani@codeweavers.com> Similarly to what happens for rendering. --- dlls/mmdevapi/tests/capture.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index 22ccab208d8..34e47b56fb1 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -661,11 +661,16 @@ static void test_format(AUDCLNT_SHAREMODE mode, WAVEFORMATEXTENSIBLE *fmt) expected = validate_fmt(fmt, compatible); todo_wine_if(hr != expected) ok(hr == expected, "Initialize(RATEADJUST) returns %08lx, expected %08lx\n", hr, expected); - } else { - ok(hr == S_OK || hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED - || hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG, - "Initialize(RATEADJUST) returns %08lx\n", hr); - } + } else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) + /* Unsupported format implies "create failed" and shadows "not allowed" */ + ok(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == hrs, + "Initialize() returns %08lx(%08lx)\n", hr, hrs); + else + /* For some drivers Initialize() doesn't match IsFormatSupported(). */ + todo_wine_if(hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED || (hr == S_OK && hrs != S_OK)) + ok(hrs == S_OK ? hr == S_OK || broken(hr == E_INVALIDARG) + : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == E_INVALIDARG, + "Initialize() returns %08lx\n", hr); IAudioClient_Release(ac); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10109
I've been testing those on a few different computers, and no two of them have the exact same results. Including the CI, of course. Now the tests should pass everywhere. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10109#note_129734
This merge request was approved by Huw Davies. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10109
participants (3)
-
Giovanni Mascellani -
Giovanni Mascellani (@giomasce) -
Huw Davies (@huw)