!8598 will require some more work, so I wrote a number of tests in preparation for it. There will be another MR for capturing tests.
This MR also enable 32-bit PCM samples for PulseAudio, since they're already enabled for other drivers and it's useful to have some uniformity between the drivers in order to avoid making writing todo conditions even more of a nightmare than it already is. 32-bit samples are already enabled to extensible wave formats, so it doesn't seem intentional that they were not enabled for non-extensible formats.
-- v2: mmdevapi/tests: Test extensible wave formats when rendering. mmdevapi/tests: Test flag AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM when rendering. mmdevapi/tests: Test flag AUDCLNT_STREAMFLAGS_RATEADJUST when rendering. mmdevapi/tests: Check that Initialize() matches IsFormatSupported() when rendering. mmdevapi/tests: Simplify checking IsFormatSupported() result when rendering. mmdevapi/tests: Test more audio formats when rendering. mmdevapi/tests: Iterate independently on sampling rates, channel counts and sample formats when rendering. winecoreaudio.drv: Do not spam fixmes for unknown channels.
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/capture.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index 678fda5baca..45b4e8e2c8f 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -657,6 +657,7 @@ static void test_formats(AUDCLNT_SHAREMODE mode) "Initialize(noexcl., %c%lux%2ux%u) returns %08lx(%08lx)\n", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, hrs); else + todo_wine_if(hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) ok(hrs == S_OK ? hr == S_OK : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "Initialize(exclus., %c%lux%2ux%u) returns %08lx\n",
From: Giovanni Mascellani gmascellani@codeweavers.com
This segfaults on my Windows 11 system. It's not a particularly useful test anyway. --- dlls/mmdevapi/tests/capture.c | 3 --- dlls/mmdevapi/tests/render.c | 3 --- 2 files changed, 6 deletions(-)
diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index 45b4e8e2c8f..1c1c3a589fb 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -435,9 +435,6 @@ static void test_audioclient(void)
handle = CreateEventW(NULL, FALSE, FALSE, NULL);
- hr = IAudioClient_QueryInterface(ac, &IID_IUnknown, NULL); - ok(hr == E_POINTER, "QueryInterface(NULL) returned %08lx\n", hr); - unk = (void*)(LONG_PTR)0x12345678; hr = IAudioClient_QueryInterface(ac, &IID_NULL, (void**)&unk); ok(hr == E_NOINTERFACE, "QueryInterface(IID_NULL) returned %08lx\n", hr); diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index f674935de00..8a3d732a99b 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -196,9 +196,6 @@ static void test_audioclient(void)
handle = CreateEventW(NULL, FALSE, FALSE, NULL);
- hr = IAudioClient_QueryInterface(ac, &IID_IUnknown, NULL); - ok(hr == E_POINTER, "QueryInterface(NULL) returned %08lx\n", hr); - unk = (void*)(LONG_PTR)0x12345678; hr = IAudioClient_QueryInterface(ac, &IID_NULL, (void**)&unk); ok(hr == E_NOINTERFACE, "QueryInterface(IID_NULL) returned %08lx\n", hr);
From: Giovanni Mascellani gmascellani@codeweavers.com
They're already allowed on the ALSA and CoreAudio drivers. --- dlls/winepulse.drv/pulse.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index 4b287578e8b..9a218e75c1b 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -962,6 +962,8 @@ static HRESULT pulse_spec_from_waveformat(struct pulse_stream *stream, const WAV stream->ss.format = PA_SAMPLE_U8; else if (fmt->wBitsPerSample == 16) stream->ss.format = PA_SAMPLE_S16LE; + else if (fmt->wBitsPerSample == 32) + stream->ss.format = PA_SAMPLE_S32LE; else return AUDCLNT_E_UNSUPPORTED_FORMAT; pa_channel_map_init_auto(&stream->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/winecoreaudio.drv/coreaudio.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/winecoreaudio.drv/coreaudio.c b/dlls/winecoreaudio.drv/coreaudio.c index 6b81a7d1d5c..ced8f3838fb 100644 --- a/dlls/winecoreaudio.drv/coreaudio.c +++ b/dlls/winecoreaudio.drv/coreaudio.c @@ -853,6 +853,7 @@ static UINT ca_channel_layout_to_channel_mask(const AudioChannelLayout *layout) switch (layout->mChannelDescriptions[i].mChannelLabel) { default: FIXME("Unhandled channel 0x%x\n", (unsigned int)layout->mChannelDescriptions[i].mChannelLabel); break; + case kAudioChannelLabel_Unknown: break; case kAudioChannelLabel_Left: mask |= SPEAKER_FRONT_LEFT; break; case kAudioChannelLabel_Mono: case kAudioChannelLabel_Center: mask |= SPEAKER_FRONT_CENTER; break;
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/render.c | 216 ++++++++++++++++------------------- 1 file changed, 100 insertions(+), 116 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 8a3d732a99b..06bfd39a233 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -41,30 +41,10 @@ #include "audiopolicy.h" #include "endpointvolume.h"
-#define PCM WAVE_FORMAT_PCM -#define FLOAT WAVE_FORMAT_IEEE_FLOAT - -static const unsigned int win_formats[][4] = { - {PCM, 8000, 8, 1}, {PCM, 8000, 8, 2}, {PCM, 8000, 16, 1}, {PCM, 8000, 16, 2}, - {PCM, 11025, 8, 1}, {PCM, 11025, 8, 2}, {PCM, 11025, 16, 1}, {PCM, 11025, 16, 2}, - {PCM, 12000, 8, 1}, {PCM, 12000, 8, 2}, {PCM, 12000, 16, 1}, {PCM, 12000, 16, 2}, - {PCM, 16000, 8, 1}, {PCM, 16000, 8, 2}, {PCM, 16000, 16, 1}, {PCM, 16000, 16, 2}, - {PCM, 22050, 8, 1}, {PCM, 22050, 8, 2}, {PCM, 22050, 16, 1}, {PCM, 22050, 16, 2}, - {PCM, 44100, 8, 1}, {PCM, 44100, 8, 2}, {PCM, 44100, 16, 1}, {PCM, 44100, 16, 2}, - {PCM, 48000, 8, 1}, {PCM, 48000, 8, 2}, {PCM, 48000, 16, 1}, {PCM, 48000, 16, 2}, - {PCM, 96000, 8, 1}, {PCM, 96000, 8, 2}, {PCM, 96000, 16, 1}, {PCM, 96000, 16, 2}, - {FLOAT, 8000, 32, 1}, {FLOAT, 8000, 32, 2}, - {FLOAT, 11025, 32, 1}, {FLOAT, 11025, 32, 2}, - {FLOAT, 12000, 32, 1}, {FLOAT, 12000, 32, 2}, - {FLOAT, 16000, 32, 1}, {FLOAT, 16000, 32, 2}, - {FLOAT, 22050, 32, 1}, {FLOAT, 22050, 32, 2}, - {FLOAT, 44100, 32, 1}, {FLOAT, 44100, 32, 2}, - {FLOAT, 48000, 32, 1}, {FLOAT, 48000, 32, 2}, - {FLOAT, 96000, 32, 1}, {FLOAT, 96000, 32, 2}, -}; - -#undef PCM -#undef FLOAT +static const unsigned int sampling_rates[] = { 8000, 11025, 12000, 16000, 22050, 44100, 48000, 96000 }; +static const unsigned int channel_counts[] = { 1, 2 }; +static const unsigned int sample_formats[][2] = { {WAVE_FORMAT_PCM, 8}, {WAVE_FORMAT_PCM, 16}, + {WAVE_FORMAT_IEEE_FLOAT, 32} };
#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
@@ -527,102 +507,106 @@ static void test_formats(AUDCLNT_SHAREMODE mode) IAudioClient *ac; HRESULT hr, hrs; WAVEFORMATEX fmt, *pwfx, *pwfx2; - int i; + int i, j, k;
fmt.cbSize = 0;
- for(i = 0; i < ARRAY_SIZE(win_formats); i++) { - char format_chr; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - continue; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - fmt.wFormatTag = win_formats[i][0]; - fmt.nSamplesPerSec = win_formats[i][1]; - fmt.wBitsPerSample = win_formats[i][2]; - fmt.nChannels = win_formats[i][3]; - fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; - fmt.nAvgBytesPerSec= fmt.nBlockAlign * fmt.nSamplesPerSec; - - format_chr = fmt.wFormatTag == WAVE_FORMAT_PCM ? 'P' : 'F'; - - pwfx2 = (WAVEFORMATEX*)0xDEADF00D; - hr = IAudioClient_IsFormatSupported(ac, mode, &fmt, &pwfx2); - hrs = hr; - /* Only shared mode suggests something ... GetMixFormat! */ - ok(hr == S_OK || (mode == AUDCLNT_SHAREMODE_SHARED - ? hr == S_FALSE || broken(hr == AUDCLNT_E_UNSUPPORTED_FORMAT && - /* 5:1 card exception when asked for 1 channel at mixer rate */ - pwfx->nChannels > 2 && fmt.nSamplesPerSec == pwfx->nSamplesPerSec) - : (hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl)), - "IsFormatSupported(%d, %c%lux%2ux%u) returns %08lx\n", mode, - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - if (hr == S_OK) - trace("IsSupported(%s, %c%lux%2ux%u)\n", - mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels); - - /* In shared mode you can only change bit width, not sampling rate or channel count. */ - if (mode == AUDCLNT_SHAREMODE_SHARED) - { - BOOL compatible = fmt.nSamplesPerSec == pwfx->nSamplesPerSec && fmt.nChannels == pwfx->nChannels; - HRESULT expected = compatible ? S_OK : S_FALSE; - ok(hr == expected, "Got %lx expected %lx\n", hr, expected); - } - - ok((hr == S_FALSE)^(pwfx2 == NULL), "hr %lx<->suggest %p\n", hr, pwfx2); - if (pwfx2) { - ok(pwfx2->wFormatTag == pwfx->wFormatTag && - pwfx2->nSamplesPerSec == pwfx->nSamplesPerSec && - pwfx2->nChannels == pwfx->nChannels && - pwfx2->wBitsPerSample == pwfx->wBitsPerSample, - "Suggestion %c%lux%2ux%u differs from GetMixFormat\n", - format_chr, pwfx2->nSamplesPerSec, pwfx2->wBitsPerSample, pwfx2->nChannels); + 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++) { + char format_chr; + + hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, + NULL, (void**)&ac); + ok(hr == S_OK, "Activation failed with %08lx\n", hr); + if(hr != S_OK) + continue; + + hr = IAudioClient_GetMixFormat(ac, &pwfx); + ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); + + fmt.wFormatTag = sample_formats[k][0]; + fmt.nSamplesPerSec = sampling_rates[i]; + fmt.wBitsPerSample = sample_formats[k][1]; + fmt.nChannels = channel_counts[j]; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec= fmt.nBlockAlign * fmt.nSamplesPerSec; + + format_chr = fmt.wFormatTag == WAVE_FORMAT_PCM ? 'P' : 'F'; + + pwfx2 = (WAVEFORMATEX*)0xDEADF00D; + hr = IAudioClient_IsFormatSupported(ac, mode, &fmt, &pwfx2); + hrs = hr; + /* Only shared mode suggests something ... GetMixFormat! */ + ok(hr == S_OK || (mode == AUDCLNT_SHAREMODE_SHARED + ? hr == S_FALSE || broken(hr == AUDCLNT_E_UNSUPPORTED_FORMAT && + /* 5:1 card exception when asked for 1 channel at mixer rate */ + pwfx->nChannels > 2 && fmt.nSamplesPerSec == pwfx->nSamplesPerSec) + : (hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl)), + "IsFormatSupported(%d, %c%lux%2ux%u) returns %08lx\n", mode, + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + if (hr == S_OK) + trace("IsSupported(%s, %c%lux%2ux%u)\n", + mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels); + + /* In shared mode you can only change bit width, not sampling rate or channel count. */ + if (mode == AUDCLNT_SHAREMODE_SHARED) + { + BOOL compatible = fmt.nSamplesPerSec == pwfx->nSamplesPerSec && fmt.nChannels == pwfx->nChannels; + HRESULT expected = compatible ? S_OK : S_FALSE; + ok(hr == expected, "Got %lx expected %lx\n", hr, expected); + } + + ok((hr == S_FALSE)^(pwfx2 == NULL), "hr %lx<->suggest %p\n", hr, pwfx2); + if (pwfx2) { + ok(pwfx2->wFormatTag == pwfx->wFormatTag && + pwfx2->nSamplesPerSec == pwfx->nSamplesPerSec && + pwfx2->nChannels == pwfx->nChannels && + pwfx2->wBitsPerSample == pwfx->wBitsPerSample, + "Suggestion %c%lux%2ux%u differs from GetMixFormat\n", + format_chr, pwfx2->nSamplesPerSec, pwfx2->wBitsPerSample, pwfx2->nChannels); + } + + /* Vista returns E_INVALIDARG upon AUDCLNT_STREAMFLAGS_RATEADJUST */ + hr = IAudioClient_Initialize(ac, mode, 0, 5000000, 0, &fmt, NULL); + if ((hrs == S_OK) ^ (hr == S_OK)) + trace("Initialize (%s, %c%lux%2ux%u) returns %08lx unlike IsFormatSupported\n", + mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + if (mode == AUDCLNT_SHAREMODE_SHARED) + ok(hrs == S_OK ? hr == S_OK : hr == AUDCLNT_E_UNSUPPORTED_FORMAT, + "Initialize(shared, %c%lux%2ux%u) returns %08lx\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + 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), + "Initialize(noexcl., %c%lux%2ux%u) returns %08lx(%08lx)\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, hrs); + else + /* On testbot 48000x16x1 claims support, but does not Initialize. + * Some cards Initialize 44100|48000x16x1 yet claim no support; + * F. Gouget's w7 bots do that for 12000|96000x8|16x1|2 */ + 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 || + broken(hr == S_OK && + ((fmt.nChannels == 1 && fmt.wBitsPerSample == 16) || + (fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))), + "Initialize(exclus., %c%lux%2ux%u) returns %08lx\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + + /* Bug in native (Vista/w2k8/w7): after Initialize failed, better + * Release this ac and Activate a new one. + * A second call (with a known working format) would yield + * ALREADY_INITIALIZED in shared mode yet be unusable, and in exclusive + * mode some entity keeps a lock on the device, causing DEVICE_IN_USE to + * all subsequent calls until the audio engine service is restarted. */ + + CoTaskMemFree(pwfx2); + CoTaskMemFree(pwfx); + IAudioClient_Release(ac); + } } - - /* Vista returns E_INVALIDARG upon AUDCLNT_STREAMFLAGS_RATEADJUST */ - hr = IAudioClient_Initialize(ac, mode, 0, 5000000, 0, &fmt, NULL); - if ((hrs == S_OK) ^ (hr == S_OK)) - trace("Initialize (%s, %c%lux%2ux%u) returns %08lx unlike IsFormatSupported\n", - mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - if (mode == AUDCLNT_SHAREMODE_SHARED) - ok(hrs == S_OK ? hr == S_OK : hr == AUDCLNT_E_UNSUPPORTED_FORMAT, - "Initialize(shared, %c%lux%2ux%u) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - 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), - "Initialize(noexcl., %c%lux%2ux%u) returns %08lx(%08lx)\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, hrs); - else - /* On testbot 48000x16x1 claims support, but does not Initialize. - * Some cards Initialize 44100|48000x16x1 yet claim no support; - * F. Gouget's w7 bots do that for 12000|96000x8|16x1|2 */ - 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 || - broken(hr == S_OK && - ((fmt.nChannels == 1 && fmt.wBitsPerSample == 16) || - (fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))), - "Initialize(exclus., %c%lux%2ux%u) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - - /* Bug in native (Vista/w2k8/w7): after Initialize failed, better - * Release this ac and Activate a new one. - * A second call (with a known working format) would yield - * ALREADY_INITIALIZED in shared mode yet be unusable, and in exclusive - * mode some entity keeps a lock on the device, causing DEVICE_IN_USE to - * all subsequent calls until the audio engine service is restarted. */ - - CoTaskMemFree(pwfx2); - CoTaskMemFree(pwfx); - IAudioClient_Release(ac); } }
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/render.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 06bfd39a233..de05b267018 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -41,10 +41,10 @@ #include "audiopolicy.h" #include "endpointvolume.h"
-static const unsigned int sampling_rates[] = { 8000, 11025, 12000, 16000, 22050, 44100, 48000, 96000 }; -static const unsigned int channel_counts[] = { 1, 2 }; +static const unsigned int sampling_rates[] = { 8000, 11025, 12000, 16000, 22050, 32000, 44100, 48000, 96000, 192000 }; +static const unsigned int channel_counts[] = { 1, 2, 4, 6, 8 }; static const unsigned int sample_formats[][2] = { {WAVE_FORMAT_PCM, 8}, {WAVE_FORMAT_PCM, 16}, - {WAVE_FORMAT_IEEE_FLOAT, 32} }; + {WAVE_FORMAT_PCM, 32}, {WAVE_FORMAT_IEEE_FLOAT, 32} };
#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
@@ -539,9 +539,7 @@ static void test_formats(AUDCLNT_SHAREMODE mode) hrs = hr; /* Only shared mode suggests something ... GetMixFormat! */ ok(hr == S_OK || (mode == AUDCLNT_SHAREMODE_SHARED - ? hr == S_FALSE || broken(hr == AUDCLNT_E_UNSUPPORTED_FORMAT && - /* 5:1 card exception when asked for 1 channel at mixer rate */ - pwfx->nChannels > 2 && fmt.nSamplesPerSec == pwfx->nSamplesPerSec) + ? hr == S_FALSE || (hr == AUDCLNT_E_UNSUPPORTED_FORMAT && fmt.nChannels > 2) : (hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl)), "IsFormatSupported(%d, %c%lux%2ux%u) returns %08lx\n", mode, format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); @@ -555,7 +553,11 @@ static void test_formats(AUDCLNT_SHAREMODE mode) { BOOL compatible = fmt.nSamplesPerSec == pwfx->nSamplesPerSec && fmt.nChannels == pwfx->nChannels; HRESULT expected = compatible ? S_OK : S_FALSE; - ok(hr == expected, "Got %lx expected %lx\n", hr, expected); + if (fmt.nChannels > 2) + expected = AUDCLNT_E_UNSUPPORTED_FORMAT; + todo_wine_if(fmt.nChannels > 2 && hr != expected) + ok(hr == expected, "IsFormatSupported(shared, %c%lux%2ux%u) returns %08lx, expected %08lx\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, expected); }
ok((hr == S_FALSE)^(pwfx2 == NULL), "hr %lx<->suggest %p\n", hr, pwfx2); @@ -575,7 +577,8 @@ static void test_formats(AUDCLNT_SHAREMODE mode) mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); if (mode == AUDCLNT_SHAREMODE_SHARED) - ok(hrs == S_OK ? hr == S_OK : hr == AUDCLNT_E_UNSUPPORTED_FORMAT, + ok(hrs == S_OK ? hr == S_OK : hr == AUDCLNT_E_UNSUPPORTED_FORMAT + || (hr == E_INVALIDARG && fmt.nChannels > 2), "Initialize(shared, %c%lux%2ux%u) returns %08lx\n", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) @@ -587,11 +590,13 @@ static void test_formats(AUDCLNT_SHAREMODE mode) /* On testbot 48000x16x1 claims support, but does not Initialize. * Some cards Initialize 44100|48000x16x1 yet claim no support; * F. Gouget's w7 bots do that for 12000|96000x8|16x1|2 */ + todo_wine_if(fmt.nChannels > 2 && hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) 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 || broken(hr == S_OK && ((fmt.nChannels == 1 && fmt.wBitsPerSample == 16) || - (fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))), + (fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))) + || (hr == E_INVALIDARG && fmt.nChannels > 2), "Initialize(exclus., %c%lux%2ux%u) returns %08lx\n", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr);
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/render.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index de05b267018..9395434ed97 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -537,20 +537,13 @@ static void test_formats(AUDCLNT_SHAREMODE mode) pwfx2 = (WAVEFORMATEX*)0xDEADF00D; hr = IAudioClient_IsFormatSupported(ac, mode, &fmt, &pwfx2); hrs = hr; - /* Only shared mode suggests something ... GetMixFormat! */ - ok(hr == S_OK || (mode == AUDCLNT_SHAREMODE_SHARED - ? hr == S_FALSE || (hr == AUDCLNT_E_UNSUPPORTED_FORMAT && fmt.nChannels > 2) - : (hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl)), - "IsFormatSupported(%d, %c%lux%2ux%u) returns %08lx\n", mode, - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); if (hr == S_OK) trace("IsSupported(%s, %c%lux%2ux%u)\n", mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels);
/* In shared mode you can only change bit width, not sampling rate or channel count. */ - if (mode == AUDCLNT_SHAREMODE_SHARED) - { + if (mode == AUDCLNT_SHAREMODE_SHARED) { BOOL compatible = fmt.nSamplesPerSec == pwfx->nSamplesPerSec && fmt.nChannels == pwfx->nChannels; HRESULT expected = compatible ? S_OK : S_FALSE; if (fmt.nChannels > 2) @@ -558,8 +551,13 @@ static void test_formats(AUDCLNT_SHAREMODE mode) todo_wine_if(fmt.nChannels > 2 && hr != expected) ok(hr == expected, "IsFormatSupported(shared, %c%lux%2ux%u) returns %08lx, expected %08lx\n", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, expected); + } else { + ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl, + "IsFormatSupported(exclusive, %c%lux%2ux%u) returns %08lx\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); }
+ /* Only shared mode suggests something ... GetMixFormat! */ ok((hr == S_FALSE)^(pwfx2 == NULL), "hr %lx<->suggest %p\n", hr, pwfx2); if (pwfx2) { ok(pwfx2->wFormatTag == pwfx->wFormatTag &&
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/render.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 9395434ed97..e1c58a448b9 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -574,12 +574,14 @@ static void test_formats(AUDCLNT_SHAREMODE mode) trace("Initialize (%s, %c%lux%2ux%u) returns %08lx unlike IsFormatSupported\n", mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - if (mode == AUDCLNT_SHAREMODE_SHARED) - ok(hrs == S_OK ? hr == S_OK : hr == AUDCLNT_E_UNSUPPORTED_FORMAT - || (hr == E_INVALIDARG && fmt.nChannels > 2), - "Initialize(shared, %c%lux%2ux%u) returns %08lx\n", + if (mode == AUDCLNT_SHAREMODE_SHARED) { + HRESULT expected = hrs == S_OK ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; + if (fmt.nChannels > 2) + expected = E_INVALIDARG; + todo_wine_if(fmt.nChannels > 2) + ok(hr == expected, "Initialize(shared, %c%lux%2ux%u) returns %08lx\n", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) + } 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), "Initialize(noexcl., %c%lux%2ux%u) returns %08lx(%08lx)\n",
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/render.c | 47 ++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index e1c58a448b9..fbbdc7d660c 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -505,9 +505,10 @@ cleanup: static void test_formats(AUDCLNT_SHAREMODE mode) { IAudioClient *ac; - HRESULT hr, hrs; + HRESULT hr, hrs, expected; WAVEFORMATEX fmt, *pwfx, *pwfx2; int i, j, k; + BOOL compatible;
fmt.cbSize = 0;
@@ -544,8 +545,8 @@ static void test_formats(AUDCLNT_SHAREMODE mode)
/* In shared mode you can only change bit width, not sampling rate or channel count. */ if (mode == AUDCLNT_SHAREMODE_SHARED) { - BOOL compatible = fmt.nSamplesPerSec == pwfx->nSamplesPerSec && fmt.nChannels == pwfx->nChannels; - HRESULT expected = compatible ? S_OK : S_FALSE; + compatible = fmt.nSamplesPerSec == pwfx->nSamplesPerSec && fmt.nChannels == pwfx->nChannels; + expected = compatible ? S_OK : S_FALSE; if (fmt.nChannels > 2) expected = AUDCLNT_E_UNSUPPORTED_FORMAT; todo_wine_if(fmt.nChannels > 2 && hr != expected) @@ -568,14 +569,13 @@ static void test_formats(AUDCLNT_SHAREMODE mode) format_chr, pwfx2->nSamplesPerSec, pwfx2->wBitsPerSample, pwfx2->nChannels); }
- /* Vista returns E_INVALIDARG upon AUDCLNT_STREAMFLAGS_RATEADJUST */ hr = IAudioClient_Initialize(ac, mode, 0, 5000000, 0, &fmt, NULL); if ((hrs == S_OK) ^ (hr == S_OK)) trace("Initialize (%s, %c%lux%2ux%u) returns %08lx unlike IsFormatSupported\n", mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); if (mode == AUDCLNT_SHAREMODE_SHARED) { - HRESULT expected = hrs == S_OK ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; + expected = hrs == S_OK ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; if (fmt.nChannels > 2) expected = E_INVALIDARG; todo_wine_if(fmt.nChannels > 2) @@ -600,6 +600,43 @@ static void test_formats(AUDCLNT_SHAREMODE mode) "Initialize(exclus., %c%lux%2ux%u) returns %08lx\n", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr);
+ IAudioClient_Release(ac); + + hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, + NULL, (void**)&ac); + ok(hr == S_OK, "Activation failed with %08lx\n", hr); + if(hr != S_OK) + continue; + + /* With AUDCLNT_STREAMFLAGS_RATEADJUST channel count must match, but sampling rate doesn't. */ + hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_RATEADJUST, 5000000, 0, &fmt, NULL); + if (mode == AUDCLNT_SHAREMODE_SHARED) { + compatible = fmt.nChannels == pwfx->nChannels; + expected = compatible ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; + if (fmt.nChannels > 2) + expected = E_INVALIDARG; + todo_wine_if(hr != expected) + ok(hr == expected, "Initialize(shared, %c%lux%2ux%u, RATEADJUST) returns %08lx\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + } 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), + "Initialize(noexcl., %c%lux%2ux%u, RATEADJUST) returns %08lx(%08lx)\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, hrs); + else + /* On testbot 48000x16x1 claims support, but does not Initialize. + * Some cards Initialize 44100|48000x16x1 yet claim no support; + * F. Gouget's w7 bots do that for 12000|96000x8|16x1|2 */ + todo_wine_if(fmt.nChannels > 2 && hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) + 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.nChannels > 2) || + broken(hr == S_OK && + ((fmt.nChannels == 1 && fmt.wBitsPerSample == 16) || + (fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))), + "Initialize(exclus., %c%lux%2ux%u, RATEADJUST) returns %08lx\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + /* Bug in native (Vista/w2k8/w7): after Initialize failed, better * Release this ac and Activate a new one. * A second call (with a known working format) would yield
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/render.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index fbbdc7d660c..1e090947420 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -637,6 +637,27 @@ static void test_formats(AUDCLNT_SHAREMODE mode) "Initialize(exclus., %c%lux%2ux%u, RATEADJUST) returns %08lx\n", format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr);
+ IAudioClient_Release(ac); + + hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, + NULL, (void**)&ac); + ok(hr == S_OK, "Activation failed with %08lx\n", hr); + if(hr != S_OK) + continue; + + /* With AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM it always succeeds. */ + hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, 5000000, 0, &fmt, NULL); + if (mode == AUDCLNT_SHAREMODE_SHARED) { + expected = fmt.nChannels <= 2 ? S_OK : E_INVALIDARG; + todo_wine_if(hr != expected) + ok(hr == expected, "Initialize(shared, %c%lux%2ux%u, AUTOCONVERTPCM) returns %08lx\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + } else { + todo_wine_if(hr != E_INVALIDARG) + ok(hr == E_INVALIDARG, "Initialize(exclus., %c%lux%2ux%u, AUTOCONVERTPCM) returns %08lx\n", + format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + } + /* Bug in native (Vista/w2k8/w7): after Initialize failed, better * Release this ac and Activate a new one. * A second call (with a known working format) would yield
From: Giovanni Mascellani gmascellani@codeweavers.com
This adds a few more cases in which initializing in exclusive mode can fail even when IsFormatSupported() returned positively. To avoid making the broken() conditions overly complicated I remove the side conditions, which are probably not very useful and depend on the driver anyway.
Also, testing configurations with more than two channels somehow alters the state of the device in a way that is not restored even after releasing the IMMDevice object and creating it again. Specifically, GetChannelVolume() will return more then two channels, even if the audio client is initialized with just two channels. To avoid those failures the format tests are moved to the end. --- dlls/mmdevapi/tests/render.c | 144 +++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 66 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 1e090947420..dd07026c423 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -502,20 +502,21 @@ cleanup: CoTaskMemFree(pwfx); }
-static void test_formats(AUDCLNT_SHAREMODE mode) +static void test_formats(AUDCLNT_SHAREMODE mode, BOOL extensible) { IAudioClient *ac; HRESULT hr, hrs, expected; - WAVEFORMATEX fmt, *pwfx, *pwfx2; + WAVEFORMATEX *pwfx, *pwfx2; + WAVEFORMATEXTENSIBLE fmt; int i, j, k; BOOL compatible;
- fmt.cbSize = 0; + 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++) { - char format_chr; + char format_chr[3];
hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&ac); @@ -526,36 +527,55 @@ static void test_formats(AUDCLNT_SHAREMODE mode) hr = IAudioClient_GetMixFormat(ac, &pwfx); ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr);
- fmt.wFormatTag = sample_formats[k][0]; - fmt.nSamplesPerSec = sampling_rates[i]; - fmt.wBitsPerSample = sample_formats[k][1]; - fmt.nChannels = channel_counts[j]; - fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; - fmt.nAvgBytesPerSec= fmt.nBlockAlign * fmt.nSamplesPerSec; + 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; + } + /* We don't want to fight with the driver over the speaker configuration, + * so just take whatever they give us. */ + if (fmt.Format.nChannels == pwfx->nChannels && pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + fmt.dwChannelMask = ((WAVEFORMATEXTENSIBLE*)pwfx)->dwChannelMask; + fmt.SubFormat = sample_formats[k][0] == WAVE_FORMAT_PCM ? + KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + }
- format_chr = fmt.wFormatTag == WAVE_FORMAT_PCM ? 'P' : 'F'; + format_chr[0] = sample_formats[k][0] == WAVE_FORMAT_PCM ? 'P' : 'F'; + format_chr[1] = extensible ? 'X' : '\0'; + format_chr[2] = '\0';
pwfx2 = (WAVEFORMATEX*)0xDEADF00D; - hr = IAudioClient_IsFormatSupported(ac, mode, &fmt, &pwfx2); + hr = IAudioClient_IsFormatSupported(ac, mode, (WAVEFORMATEX*)&fmt, &pwfx2); hrs = hr; if (hr == S_OK) - trace("IsSupported(%s, %c%lux%2ux%u)\n", + trace("IsSupported(%s, %s%lux%2ux%u)\n", mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels); + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels);
/* In shared mode you can only change bit width, not sampling rate or channel count. */ if (mode == AUDCLNT_SHAREMODE_SHARED) { - compatible = fmt.nSamplesPerSec == pwfx->nSamplesPerSec && fmt.nChannels == pwfx->nChannels; + compatible = fmt.Format.nSamplesPerSec == pwfx->nSamplesPerSec && fmt.Format.nChannels == pwfx->nChannels; expected = compatible ? S_OK : S_FALSE; - if (fmt.nChannels > 2) + if (fmt.Format.nChannels > 2 && !extensible) expected = AUDCLNT_E_UNSUPPORTED_FORMAT; - todo_wine_if(fmt.nChannels > 2 && hr != expected) - ok(hr == expected, "IsFormatSupported(shared, %c%lux%2ux%u) returns %08lx, expected %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, expected); + todo_wine_if(fmt.Format.nChannels > 2 && hr != expected) + ok(hr == expected, "IsFormatSupported(shared, %s%lux%2ux%u) returns %08lx, expected %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr, expected); } else { ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl, - "IsFormatSupported(exclusive, %c%lux%2ux%u) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + "IsFormatSupported(exclusive, %s%lux%2ux%u) returns %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr); }
/* Only shared mode suggests something ... GetMixFormat! */ @@ -565,40 +585,35 @@ static void test_formats(AUDCLNT_SHAREMODE mode) pwfx2->nSamplesPerSec == pwfx->nSamplesPerSec && pwfx2->nChannels == pwfx->nChannels && pwfx2->wBitsPerSample == pwfx->wBitsPerSample, - "Suggestion %c%lux%2ux%u differs from GetMixFormat\n", + "Suggestion %s%lux%2ux%u differs from GetMixFormat\n", format_chr, pwfx2->nSamplesPerSec, pwfx2->wBitsPerSample, pwfx2->nChannels); }
- hr = IAudioClient_Initialize(ac, mode, 0, 5000000, 0, &fmt, NULL); + hr = IAudioClient_Initialize(ac, mode, 0, 5000000, 0, (WAVEFORMATEX*)&fmt, NULL); if ((hrs == S_OK) ^ (hr == S_OK)) - trace("Initialize (%s, %c%lux%2ux%u) returns %08lx unlike IsFormatSupported\n", + trace("Initialize (%s, %s%lux%2ux%u) returns %08lx unlike IsFormatSupported\n", mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr); if (mode == AUDCLNT_SHAREMODE_SHARED) { expected = hrs == S_OK ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; - if (fmt.nChannels > 2) + if (fmt.Format.nChannels > 2 && !extensible) expected = E_INVALIDARG; - todo_wine_if(fmt.nChannels > 2) - ok(hr == expected, "Initialize(shared, %c%lux%2ux%u) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + todo_wine_if(fmt.Format.nChannels > 2 && !extensible) + ok(hr == expected, "Initialize(shared, %s%lux%2ux%u) returns %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr); } 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), - "Initialize(noexcl., %c%lux%2ux%u) returns %08lx(%08lx)\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, hrs); + "Initialize(noexcl., %s%lux%2ux%u) returns %08lx(%08lx)\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr, hrs); else - /* On testbot 48000x16x1 claims support, but does not Initialize. - * Some cards Initialize 44100|48000x16x1 yet claim no support; - * F. Gouget's w7 bots do that for 12000|96000x8|16x1|2 */ - todo_wine_if(fmt.nChannels > 2 && hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) + /* For some drivers Initialize() doesn't match IsFormatSupported(). */ + todo_wine_if(fmt.Format.nChannels > 2 && hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) 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 || - broken(hr == S_OK && - ((fmt.nChannels == 1 && fmt.wBitsPerSample == 16) || - (fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))) - || (hr == E_INVALIDARG && fmt.nChannels > 2), - "Initialize(exclus., %c%lux%2ux%u) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + (hr == E_INVALIDARG && fmt.Format.nChannels > 2 && !extensible) || broken(hr == S_OK), + "Initialize(exclus., %s%lux%2ux%u) returns %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr);
IAudioClient_Release(ac);
@@ -609,33 +624,28 @@ static void test_formats(AUDCLNT_SHAREMODE mode) continue;
/* With AUDCLNT_STREAMFLAGS_RATEADJUST channel count must match, but sampling rate doesn't. */ - hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_RATEADJUST, 5000000, 0, &fmt, NULL); + hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_RATEADJUST, 5000000, 0, (WAVEFORMATEX*)&fmt, NULL); if (mode == AUDCLNT_SHAREMODE_SHARED) { - compatible = fmt.nChannels == pwfx->nChannels; + compatible = fmt.Format.nChannels == pwfx->nChannels; expected = compatible ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT; - if (fmt.nChannels > 2) + if (fmt.Format.nChannels > 2 && !extensible) expected = E_INVALIDARG; todo_wine_if(hr != expected) - ok(hr == expected, "Initialize(shared, %c%lux%2ux%u, RATEADJUST) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + ok(hr == expected, "Initialize(shared, %s%lux%2ux%u, RATEADJUST) returns %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr); } 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), - "Initialize(noexcl., %c%lux%2ux%u, RATEADJUST) returns %08lx(%08lx)\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, hrs); + "Initialize(noexcl., %s%lux%2ux%u, RATEADJUST) returns %08lx(%08lx)\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr, hrs); else - /* On testbot 48000x16x1 claims support, but does not Initialize. - * Some cards Initialize 44100|48000x16x1 yet claim no support; - * F. Gouget's w7 bots do that for 12000|96000x8|16x1|2 */ - todo_wine_if(fmt.nChannels > 2 && hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) + /* For some drivers Initialize() doesn't match IsFormatSupported(). */ + todo_wine_if(fmt.Format.nChannels > 2 && hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) 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.nChannels > 2) || - broken(hr == S_OK && - ((fmt.nChannels == 1 && fmt.wBitsPerSample == 16) || - (fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))), - "Initialize(exclus., %c%lux%2ux%u, RATEADJUST) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + (hr == E_INVALIDARG && fmt.Format.nChannels > 2 && !extensible) || broken(hr == S_OK), + "Initialize(exclus., %s%lux%2ux%u, RATEADJUST) returns %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr);
IAudioClient_Release(ac);
@@ -646,16 +656,16 @@ static void test_formats(AUDCLNT_SHAREMODE mode) continue;
/* With AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM it always succeeds. */ - hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, 5000000, 0, &fmt, NULL); + hr = IAudioClient_Initialize(ac, mode, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, 5000000, 0, (WAVEFORMATEX*)&fmt, NULL); if (mode == AUDCLNT_SHAREMODE_SHARED) { - expected = fmt.nChannels <= 2 ? S_OK : E_INVALIDARG; + expected = fmt.Format.nChannels <= 2 || extensible ? S_OK : E_INVALIDARG; todo_wine_if(hr != expected) - ok(hr == expected, "Initialize(shared, %c%lux%2ux%u, AUTOCONVERTPCM) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + ok(hr == expected, "Initialize(shared, %s%lux%2ux%u, AUTOCONVERTPCM) returns %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr); } else { todo_wine_if(hr != E_INVALIDARG) - ok(hr == E_INVALIDARG, "Initialize(exclus., %c%lux%2ux%u, AUTOCONVERTPCM) returns %08lx\n", - format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); + ok(hr == E_INVALIDARG, "Initialize(exclus., %s%lux%2ux%u, AUTOCONVERTPCM) returns %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr); }
/* Bug in native (Vista/w2k8/w7): after Initialize failed, better @@ -2826,8 +2836,6 @@ START_TEST(render) }
test_audioclient(); - test_formats(AUDCLNT_SHAREMODE_EXCLUSIVE); - test_formats(AUDCLNT_SHAREMODE_SHARED); test_references(); test_marshal(); if (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode)) @@ -2848,6 +2856,10 @@ 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);
IMMDevice_Release(dev);
On Mon Jul 28 16:32:50 2025 +0000, Giovanni Mascellani wrote:
I should probably note that I tested this MR on Windows (with a few different hardware and virtual sound cards, configured with many different channel counts), on Linux (both PulseAudio and ALSA, again with different hardwares and channel counts; though I'm not sure ALSA was sensitive to configuration with more than two channels) and macOS (I couldn't test more than two channels here, because I don't know how to configure that).
Ok, the macOS surround configuration was hidden inside the "MIDI audio" settings, not sure why. Anyway, I tested again with that on and relaxed a few todos to make them pass as well.
Paul Gofman (@gofman) commented about dlls/mmdevapi/tests/render.c:
else
/* On testbot 48000x16x1 claims support, but does not Initialize.
* Some cards Initialize 44100|48000x16x1 yet claim no support;
* F. Gouget's w7 bots do that for 12000|96000x8|16x1|2 */
todo_wine_if(fmt.nChannels > 2 && hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED)
/* For some drivers Initialize() doesn't match IsFormatSupported(). */
todo_wine_if(fmt.Format.nChannels > 2 && hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) 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.nChannels > 2) ||
broken(hr == S_OK &&
((fmt.nChannels == 1 && fmt.wBitsPerSample == 16) ||
(fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))),
"Initialize(exclus., %c%lux%2ux%u, RATEADJUST) returns %08lx\n",
format_chr, fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr);
(hr == E_INVALIDARG && fmt.Format.nChannels > 2 && !extensible) || broken(hr == S_OK),
I'd suggest to avoid such complicated and multivariant conditions in tests (there are also more like that), it is very hard to follow. E. g., maybe establish the condition whether the call is supposed to succeed or not and have separate ok's, and then maybe additionally split other cases, or, if the variance for how that fails depends on hardware configuration or Windows version maybe we don't care about detail of every failure status and can just limit those details to simplify the condition. Also, it seems like that this tests accepts just any result in the sense we care for: e. g., for hrs == S_OK it can be either S_OK or AUDCLNT_E_UNSUPPORTED_FORMAT. Is it really random in such cases across hardware whether it is OK or UNSUPPORTED_FORMAT? Or if it varies across different format and other cases, I think it would be valuable to distinguish in test when it is OK and when not, that seems to be directly related to the Wine implementation parts being touched. If that varies across Wind ows version I'd suggest to keep the latest as expected variant and keep the rest in broken().
On Mon Jul 28 17:21:20 2025 +0000, Paul Gofman wrote:
I'd suggest to avoid such complicated and multivariant conditions in tests (there are also more like that), it is very hard to follow. E. g., maybe establish the condition whether the call is supposed to succeed or not and have separate ok's, and then maybe additionally split other cases, or, if the variance for how that fails depends on hardware configuration or Windows version maybe we don't care about detail of every failure status and can just limit those details to simplify the condition. Also, it seems like that this tests accepts just any result in the sense we care for: e. g., for hrs == S_OK it can be either S_OK or AUDCLNT_E_UNSUPPORTED_FORMAT. Is it really random in such cases across hardware whether it is OK or UNSUPPORTED_FORMAT? Or if it varies across different format and other cases, I think it would be valuable to distinguish in test when it is OK and when not, that seems to be directly related to the Wine implementation parts being touched. If that varies across Windows version I'd suggest to keep the latest as expected variant and keep the rest in broken().
E. g., a bit we want to know practically if specific channel configuration translation is supported between two given once, it would be great that the test would be showing that explicitly in some form, and not effectively accept any result from _Initialize.
On Mon Jul 28 17:25:06 2025 +0000, Paul Gofman wrote:
E. g., a bit we want to know practically if specific channel configuration translation is supported between two given once, it would be great that the test would be showing that explicitly in some form, and not effectively accept any result from _Initialize.
For the moment I'm only focusing on shared access tests. Exclusive access tests are an entirely different can of worms, so I'm touching them just enough to have them pass; but if I also spend time on making them as good as possible this won't ever be over. I think it's better to leave them for another time, when certainly we should do something like I'm doing for shared access tests: establish which return code you expect and validate that. That's quite complicated already for shared access tests and even more for exclusive access tests, so as I said I think it's best left for another time.