From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/capture.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c index 678fda5baca..86187609e96 100644 --- a/dlls/mmdevapi/tests/capture.c +++ b/dlls/mmdevapi/tests/capture.c @@ -657,6 +657,9 @@ 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 + /* When both AUDCLNT_E_UNSUPPORTED_FORMAT and AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED apply, + * IsFormatSupported() should return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED, but currently doesn't. */ + todo_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 86187609e96..a912ef3f014 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
The current method relies on IsFormatSupported() accepting formats which differs by channel count from the mix format. However that was changed in 00211db0d08d60ee9a0e40206bf7cf9b5b88987b, because it doesn't match native behavior.
The check in SpatialAudioClient_Create() doesn't look particularly useful anyway; the real format check is done in ActivateSpatialAudioStream(), where all the parameters (including channel count) are known. --- dlls/mmdevapi/spatialaudio.c | 42 ------------------------------------ 1 file changed, 42 deletions(-)
diff --git a/dlls/mmdevapi/spatialaudio.c b/dlls/mmdevapi/spatialaudio.c index b721af6229b..58d1005d741 100644 --- a/dlls/mmdevapi/spatialaudio.c +++ b/dlls/mmdevapi/spatialaudio.c @@ -931,9 +931,6 @@ static IAudioFormatEnumeratorVtbl IAudioFormatEnumerator_vtbl = { HRESULT SpatialAudioClient_Create(IMMDevice *mmdev, ISpatialAudioClient **out) { SpatialAudioImpl *obj; - IAudioClient *aclient; - WAVEFORMATEX *closest; - HRESULT hr;
obj = calloc(1, sizeof(*obj));
@@ -949,45 +946,6 @@ HRESULT SpatialAudioClient_Create(IMMDevice *mmdev, ISpatialAudioClient **out) obj->object_fmtex.Format.nAvgBytesPerSec = obj->object_fmtex.Format.nSamplesPerSec * obj->object_fmtex.Format.nBlockAlign; obj->object_fmtex.Format.cbSize = 0;
- hr = IMMDevice_Activate(mmdev, &IID_IAudioClient, - CLSCTX_INPROC_SERVER, NULL, (void**)&aclient); - if(FAILED(hr)){ - WARN("Activate failed: %08lx\n", hr); - free(obj); - return hr; - } - - hr = IAudioClient_IsFormatSupported(aclient, AUDCLNT_SHAREMODE_SHARED, &obj->object_fmtex.Format, &closest); - - IAudioClient_Release(aclient); - - if(hr == S_FALSE){ - if(sizeof(WAVEFORMATEX) + closest->cbSize > sizeof(obj->object_fmtex)){ - ERR("Returned format too large: %s\n", debugstr_fmtex(closest)); - CoTaskMemFree(closest); - free(obj); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - }else if(!((closest->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&((WAVEFORMATEXTENSIBLE *)closest)->SubFormat, - &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) && - closest->wBitsPerSample == 32)){ - ERR("Returned format not 32-bit float: %s\n", debugstr_fmtex(closest)); - CoTaskMemFree(closest); - free(obj); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - WARN("The audio stack doesn't support 48kHz 32bit float. Using the closest match. Audio may be glitchy. %s\n", debugstr_fmtex(closest)); - memcpy(&obj->object_fmtex, - closest, - sizeof(WAVEFORMATEX) + closest->cbSize); - CoTaskMemFree(closest); - } else if(hr != S_OK){ - WARN("Checking supported formats failed: %08lx\n", hr); - free(obj); - return hr; - } - obj->mmdev = mmdev; IMMDevice_AddRef(mmdev);
From: Giovanni Mascellani gmascellani@codeweavers.com
It was already confirmed in ActivateSpatialAudioStream() that the format is 32-bit floating point, which is hardcoded in SpatialAudioClient_Create(). --- dlls/mmdevapi/spatialaudio.c | 8 -------- 1 file changed, 8 deletions(-)
diff --git a/dlls/mmdevapi/spatialaudio.c b/dlls/mmdevapi/spatialaudio.c index 58d1005d741..eab3ceade6b 100644 --- a/dlls/mmdevapi/spatialaudio.c +++ b/dlls/mmdevapi/spatialaudio.c @@ -702,17 +702,9 @@ static void static_mask_to_channels(AudioObjectType static_mask, WORD *count, DW
static HRESULT activate_stream(SpatialAudioStreamImpl *stream) { - WAVEFORMATEXTENSIBLE *object_fmtex = (WAVEFORMATEXTENSIBLE *)stream->params.ObjectFormat; HRESULT hr; REFERENCE_TIME period;
- if(!(object_fmtex->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (object_fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&object_fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))){ - FIXME("Only float formats are supported for now\n"); - return E_INVALIDARG; - } - hr = IMMDevice_Activate(stream->sa_client->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&stream->client); if(FAILED(hr)){
From: Giovanni Mascellani gmascellani@codeweavers.com
Since 00211db0d08d60ee9a0e40206bf7cf9b5b88987b, and on native, IAudioClient::Initialize() rejects formats that differ by channel count from the mix format, which might be smaller than the channel count the underlying audio system supports. Therefore an internal API is introduced to bypass the channel count check.
This fixes a failure in spatialaudio tests. --- dlls/mmdevapi/client.c | 9 +++++---- dlls/mmdevapi/mmdevapi_private.h | 6 ++++++ dlls/mmdevapi/spatialaudio.c | 7 ++++++- 3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 61b9167f3c6..23aa3c745cf 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -366,7 +366,8 @@ skip: return wcsdup(name); }
-static HRESULT stream_init(struct audio_client *client, const BOOLEAN force_def_period, +HRESULT stream_init(struct audio_client *client, const BOOLEAN force_def_period, + const BOOL check_mix_format, const AUDCLNT_SHAREMODE mode, const DWORD flags, REFERENCE_TIME duration, REFERENCE_TIME period, const WAVEFORMATEX *fmt, const GUID *sessionguid) @@ -398,7 +399,7 @@ static HRESULT stream_init(struct audio_client *client, const BOOLEAN force_def_ return E_INVALIDARG; }
- if (mode == AUDCLNT_SHAREMODE_SHARED) { + if (check_mix_format && mode == AUDCLNT_SHAREMODE_SHARED) { WAVEFORMATEX *mix_fmt; HRESULT hr;
@@ -702,7 +703,7 @@ static HRESULT WINAPI client_Initialize(IAudioClient3 *iface, AUDCLNT_SHAREMODE wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
- return stream_init(This, TRUE, mode, flags, duration, period, fmt, sessionguid); + return stream_init(This, TRUE, TRUE, mode, flags, duration, period, fmt, sessionguid); }
static HRESULT WINAPI client_GetBufferSize(IAudioClient3 *iface, UINT32 *out) @@ -1137,7 +1138,7 @@ static HRESULT WINAPI client_InitializeSharedAudioStream(IAudioClient3 *iface, D
period = period_frames * (REFERENCE_TIME)10000000 / format->nSamplesPerSec;
- return stream_init(This, FALSE, AUDCLNT_SHAREMODE_SHARED, flags, 0, period, format, session_guid); + return stream_init(This, FALSE, TRUE, AUDCLNT_SHAREMODE_SHARED, flags, 0, period, format, session_guid); }
const IAudioClient3Vtbl AudioClient3_Vtbl = diff --git a/dlls/mmdevapi/mmdevapi_private.h b/dlls/mmdevapi/mmdevapi_private.h index 8dff5aa0805..094698ef345 100644 --- a/dlls/mmdevapi/mmdevapi_private.h +++ b/dlls/mmdevapi/mmdevapi_private.h @@ -134,3 +134,9 @@ extern void main_loop_stop(void); extern const WCHAR drv_keyW[];
extern HRESULT get_audio_sessions(IMMDevice *device, GUID **ret, int *ret_count); + +extern HRESULT stream_init(struct audio_client *client, const BOOLEAN force_def_period, + const BOOL check_mix_format, + const AUDCLNT_SHAREMODE mode, const DWORD flags, + REFERENCE_TIME duration, REFERENCE_TIME period, + const WAVEFORMATEX *fmt, const GUID *sessionguid); diff --git a/dlls/mmdevapi/spatialaudio.c b/dlls/mmdevapi/spatialaudio.c index eab3ceade6b..82b5f917e2a 100644 --- a/dlls/mmdevapi/spatialaudio.c +++ b/dlls/mmdevapi/spatialaudio.c @@ -700,6 +700,11 @@ static void static_mask_to_channels(AudioObjectType static_mask, WORD *count, DW CONVERT_MASK(AudioObjectType_BackCenter, SPEAKER_BACK_CENTER); }
+static inline struct audio_client *impl_from_IAudioClient(IAudioClient *iface) +{ + return CONTAINING_RECORD(iface, struct audio_client, IAudioClient3_iface); +} + static HRESULT activate_stream(SpatialAudioStreamImpl *stream) { HRESULT hr; @@ -731,7 +736,7 @@ static HRESULT activate_stream(SpatialAudioStreamImpl *stream) stream->stream_fmtex.Samples.wValidBitsPerSample = stream->stream_fmtex.Format.wBitsPerSample; stream->stream_fmtex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
- hr = IAudioClient_Initialize(stream->client, AUDCLNT_SHAREMODE_SHARED, + hr = stream_init(impl_from_IAudioClient(stream->client), TRUE, FALSE, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, period, 0, &stream->stream_fmtex.Format, NULL); if(FAILED(hr)){
From: Giovanni Mascellani gmascellani@codeweavers.com
They're not particularly important, but since I happened to write them it shouldn't hurt to keep them. --- dlls/mmdevapi/tests/spatialaudio.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/dlls/mmdevapi/tests/spatialaudio.c b/dlls/mmdevapi/tests/spatialaudio.c index 2a7fd041060..2bc672da413 100644 --- a/dlls/mmdevapi/tests/spatialaudio.c +++ b/dlls/mmdevapi/tests/spatialaudio.c @@ -56,6 +56,8 @@ static void test_formats(void) ok(hr == S_OK, "Getting format failed: 0x%08lx\n", hr); ok(fmt != NULL, "Expected to get non-NULL format\n");
+ /* On native 48kHz is reported even when a different sampling rate is configured + * on the device (and returned as IAudioClient mix format). */ ok(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT, "Wrong format, expected WAVE_FORMAT_IEEE_FLOAT got %hx\n", fmt->wFormatTag); ok(fmt->nChannels == 1, "Wrong number of channels, expected 1 got %hu\n", fmt->nChannels); ok(fmt->nSamplesPerSec == 48000, "Wrong sample ret, expected 48000 got %lu\n", fmt->nSamplesPerSec); @@ -272,6 +274,15 @@ static void test_audio_object_activation(void) hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_Dynamic, &sao2); ok(hr == SPTLAUDCLNT_E_NO_MORE_OBJECTS, "Expected to not have no more dynamic objects: 0x%08lx\n", hr);
+ hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideLeft | AudioObjectType_SideRight | AudioObjectType_FrontLeft, &sao2); + todo_wine + ok(hr == SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE, "Expected audio object to be already active: 0x%08lx\n", hr); + + hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideLeft | AudioObjectType_SideRight, &sao2); + todo_wine + ok(hr == S_OK, "Cannot create spatial audio object with two types: 0x%08lx\n", hr); + + ISpatialAudioObject_Release(sao2); ISpatialAudioObject_Release(sao1); ISpatialAudioObjectRenderStream_Release(sas); }