The mmdevapi side of !9438
-- v2: mmdevapi/tests: Conditionally apply todo_wine to SetSampleRate() tests. mmdevapi/tests: Simplify handling of failure to get a capture endpoint. mmdevapi/tests: Get rid of questionable error handling. mmdevapi/tests: Test capture session state in render:test_session_creation(). mmdevapi/tests: Accept any digit before the process ID in the session instance identifier. mmdevapi: Share NULL GUID session.
From: Matteo Bruni mbruni@codeweavers.com
It's just a normal session, there's nothing special about it. It also means that it can be shared among audio clients, just like any other session. --- dlls/mmdevapi/client.c | 2 ++ dlls/mmdevapi/mmdevapi_private.h | 4 ++-- dlls/mmdevapi/session.c | 13 ++++--------- dlls/mmdevapi/tests/render.c | 27 +++++++++++++++++++++++++-- 4 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 94d831370ab..4538eca9e1c 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -515,6 +515,8 @@ static HRESULT stream_init(struct audio_client *client, const BOOLEAN force_def_ FIXME("Unknown flags: %08lx\n", flags); return E_INVALIDARG; } + if (flags & AUDCLNT_STREAMFLAGS_CROSSPROCESS) + FIXME("Cross-process sessions not supported\n");
hr = validate_wfx(fmt, mode);
diff --git a/dlls/mmdevapi/mmdevapi_private.h b/dlls/mmdevapi/mmdevapi_private.h index 8dff5aa0805..672d901bf6d 100644 --- a/dlls/mmdevapi/mmdevapi_private.h +++ b/dlls/mmdevapi/mmdevapi_private.h @@ -27,7 +27,7 @@
#include "unixlib.h"
-typedef struct audio_session { +struct audio_session { GUID guid; struct list clients;
@@ -43,7 +43,7 @@ typedef struct audio_session { GUID grouping_param;
struct list entry; -} AudioSession; +};
typedef struct audio_session_wrapper { IAudioSessionControl2 IAudioSessionControl2_iface; diff --git a/dlls/mmdevapi/session.c b/dlls/mmdevapi/session.c index 9b97cef9df8..8e638251ba2 100644 --- a/dlls/mmdevapi/session.c +++ b/dlls/mmdevapi/session.c @@ -676,6 +676,8 @@ static struct audio_session *session_create(const GUID *guid, IMMDevice *device, if (!ret) return NULL;
+ if (!guid) + guid = &GUID_NULL; memcpy(&ret->guid, guid, sizeof(GUID));
ret->device = device; @@ -725,17 +727,10 @@ HRESULT get_audio_session(const GUID *guid, IMMDevice *device, UINT channels,
TRACE("(%s, %p, %u, %p)\n", debugstr_guid(guid), device, channels, out);
- if (!guid || IsEqualGUID(guid, &GUID_NULL)) { - *out = session_create(&GUID_NULL, device, channels); - if (!*out) - return E_OUTOFMEMORY; - - return S_OK; - } - *out = NULL; LIST_FOR_EACH_ENTRY(session, &sessions, struct audio_session, entry) { - if (session->device == device && IsEqualGUID(guid, &session->guid)) { + if (session->device == device && ((!guid && IsEqualGUID(&session->guid, &GUID_NULL)) || + (guid && IsEqualGUID(guid, &session->guid)))) { session_init_vols(session, channels); *out = session; break; diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 6c9eb9199ac..afefe363ef5 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -2369,7 +2369,7 @@ static void test_session_creation(void) hr = IAudioSessionManager2_GetSessionEnumerator((void *)sesm2, &sess_enum); ok(hr == S_OK, "got %#lx.\n", hr);
- /* create another session after getting the first enumerarot. */ + /* create another session after getting the first enumerator. */ CoCreateGuid(&session_guid2); hr = IAudioSessionManager_GetAudioSessionControl(sesm, &session_guid2, 0, &ctl); ok(hr == S_OK, "got %#lx.\n", hr); @@ -2392,7 +2392,10 @@ static void test_session_creation(void) hr = IAudioSessionControl_GetDisplayName(ctl, &name); ok(hr == S_OK, "got %#lx.\n", hr); if (!wcscmp(name, L"test_session1")) + { found_first = TRUE; + check_session_ids(dev, &session_guid, ctl); + } if (!wcscmp(name, L"test_session2")) found_second = TRUE; CoTaskMemFree(name); @@ -2431,9 +2434,29 @@ static void test_session_creation(void) ok(found_first && found_second, "got %d, %d.\n", found_first, found_second); IAudioSessionEnumerator_Release(sess_enum); IAudioSessionEnumerator_Release(sess_enum2); + ISimpleAudioVolume_Release(sav);
- /* Release completely to show session persistence */ + /* NULL and GUID_NULL both refer to the default session. There is nothing + * special about it */ + hr = IAudioSessionManager_GetSimpleAudioVolume(sesm, NULL, FALSE, &sav); + ok(hr == S_OK, "GetSimpleAudioVolume failed: %08lx\n", hr); + hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); + ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); + ok(vol == 1.0f, "Unexpected vol %.8e\n", vol); + hr = ISimpleAudioVolume_SetMasterVolume(sav, 0.5f, NULL); + ok(hr == S_OK, "SetMasterVolume failed: %08lx\n", hr); ISimpleAudioVolume_Release(sav); + + hr = IAudioSessionManager_GetSimpleAudioVolume(sesm, &GUID_NULL, FALSE, &sav); + ok(hr == S_OK, "GetSimpleAudioVolume failed: %08lx\n", hr); + hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); + ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); + ok(vol == 0.5f, "Unexpected vol %.8e\n", vol); + hr = ISimpleAudioVolume_SetMasterVolume(sav, 1.0f, NULL); + ok(hr == S_OK, "SetMasterVolume failed: %08lx\n", hr); + ISimpleAudioVolume_Release(sav); + + /* Release completely to show session persistence */ IAudioSessionManager_Release(sesm); IAudioSessionManager2_Release(sesm2);
From: Matteo Bruni mbruni@codeweavers.com
I have two Windows systems that use '3' and '4' respectively. --- dlls/mmdevapi/tests/render.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index afefe363ef5..bb5f2d2fa53 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -2319,8 +2319,12 @@ static void check_session_ids_(unsigned int line, IMMDevice *dev, const GUID *se
hr = IAudioSessionControl2_GetSessionInstanceIdentifier(ctl2, &str); ok_(__FILE__, line)(hr == S_OK, "GetSessionInstanceIdentifier failed, hr %#lx.\n", hr); - wsprintfW(expected, L"%s|%s%%b%s|1%%b%lu", dev_id, exe_path, guidstr, GetCurrentProcessId()); - ok_(__FILE__, line)(!wcscmp(str, expected), "got %s, expected %s.\n", debugstr_w(str), debugstr_w(expected)); + wsprintfW(expected, L"%s|%s%%b%s|", dev_id, exe_path, guidstr); + size = wcslen(expected); + ok_(__FILE__, line)(!wcsncmp(str, expected, size), "got %s, expected %s.\n", debugstr_wn(str, size), debugstr_wn(expected, size)); + ok(iswdigit(str[size]), "Unexpected %s.\n", debugstr_w(str)); + wsprintfW(expected, L"%%b%lu", GetCurrentProcessId()); + ok_(__FILE__, line)(!wcscmp(&str[size + 1], expected), "got %s, expected %s.\n", debugstr_w(&str[size + 1]), debugstr_w(expected)); CoTaskMemFree(str);
CoTaskMemFree(dev_id);
From: Matteo Bruni mbruni@codeweavers.com
Make the test a bit more interesting than just showing that you can get the session's ISimpleAudioVolume. --- dlls/mmdevapi/tests/render.c | 39 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index bb5f2d2fa53..124c72af697 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -2471,23 +2471,23 @@ static void test_session_creation(void) if(hr == S_OK){ WAVEFORMATEX *cap_pwfx; IAudioClient *cap_ac; - ISimpleAudioVolume *cap_sav; IAudioSessionManager *cap_sesm; + IAudioSessionControl *cap_sesc; + AudioSessionState state;
hr = IMMDevice_Activate(cap_dev, &IID_IAudioSessionManager, CLSCTX_INPROC_SERVER, NULL, (void**)&cap_sesm); ok((hr == S_OK)^(cap_sesm == NULL), "Activate %08lx &out pointer\n", hr); ok(hr == S_OK, "Activate failed: %08lx\n", hr);
- hr = IAudioSessionManager_GetSimpleAudioVolume(cap_sesm, &session_guid, - FALSE, &cap_sav); - ok(hr == S_OK, "GetSimpleAudioVolume failed: %08lx\n", hr); + hr = IAudioSessionManager_GetAudioSessionControl(cap_sesm, &session_guid, FALSE, &cap_sesc); + ok(hr == S_OK, "GetAudioSessionControl failed: %08lx\n", hr);
- vol = 0.5f; - hr = ISimpleAudioVolume_GetMasterVolume(cap_sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); + hr = IAudioSessionControl_GetState(cap_sesc, &state); + ok(hr == S_OK, "GetState failed: %08lx\n", hr); + ok(state == AudioSessionStateInactive || state == AudioSessionStateExpired, "state %u\n", state);
- ISimpleAudioVolume_Release(cap_sav); + IAudioSessionControl_Release(cap_sesc); IAudioSessionManager_Release(cap_sesm);
hr = IMMDevice_Activate(cap_dev, &IID_IAudioClient, @@ -2505,19 +2505,20 @@ static void test_session_creation(void)
CoTaskMemFree(cap_pwfx);
- if(hr == S_OK){ - hr = IAudioClient_GetService(cap_ac, &IID_ISimpleAudioVolume, - (void**)&cap_sav); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - } - if(hr == S_OK){ - vol = 0.5f; - hr = ISimpleAudioVolume_GetMasterVolume(cap_sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); + hr = IAudioClient_Start(cap_ac); + ok(hr == S_OK, "Start failed: %08lx\n", hr);
- ISimpleAudioVolume_Release(cap_sav); - } + hr = IAudioClient_GetService(cap_ac, &IID_IAudioSessionControl, (void**)&cap_sesc); + ok(hr == S_OK, "GetService failed: %08lx\n", hr); + + hr = IAudioSessionControl_GetState(cap_sesc, &state); + ok(hr == S_OK, "GetState failed: %08lx\n", hr); + ok(state == AudioSessionStateActive, "state %u\n", state); + + hr = IAudioClient_Stop(cap_ac); + ok(hr == S_OK, "Start failed: %08lx\n", hr);
+ IAudioSessionControl_Release(cap_sesc); IAudioClient_Release(cap_ac); }
From: Matteo Bruni mbruni@codeweavers.com
It was handling unexpected behavior while ok() checks would have failed anyway. I don't see this particular behavior in recent test.winehq.org results let's get rid of the extra code for now.
Partially reverts 8e62e823d6a41f40d1b50c5a77083290f525bb0c. --- dlls/mmdevapi/tests/render.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 124c72af697..be62631e3ea 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -1612,7 +1612,6 @@ static void test_session(void) hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&ses1_ac1); ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if (FAILED(hr)) return;
hr = IAudioClient_GetMixFormat(ses1_ac1, &pwfx); ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); @@ -1621,19 +1620,9 @@ static void test_session(void) 0, 5000000, 0, pwfx, &ses1_guid); ok(hr == S_OK, "Initialize failed: %08lx\n", hr);
- if(hr == S_OK){ - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ses1_ac2); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - } - if(hr != S_OK){ - skip("Unable to open the same device twice. Skipping session tests\n"); - - ref = IAudioClient_Release(ses1_ac1); - ok(ref == 0, "AudioClient wasn't released: %lu\n", ref); - CoTaskMemFree(pwfx); - return; - } + hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, + NULL, (void**)&ses1_ac2); + ok(hr == S_OK, "Activation failed with %08lx\n", hr);
hr = IAudioClient_Initialize(ses1_ac2, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, pwfx, &ses1_guid); @@ -1644,7 +1633,6 @@ static void test_session(void) if(hr == S_OK){ hr = IMMDevice_Activate(cap_dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&cap_ac); - ok((hr == S_OK)^(cap_ac == NULL), "Activate %08lx &out pointer\n", hr); ok(hr == S_OK, "Activate failed: %08lx\n", hr); IMMDevice_Release(cap_dev); } @@ -2352,7 +2340,6 @@ static void test_session_creation(void)
hr = IMMDevice_Activate(dev, &IID_IAudioSessionManager, CLSCTX_INPROC_SERVER, NULL, (void**)&sesm); - ok((hr == S_OK)^(sesm == NULL), "Activate %08lx &out pointer\n", hr); ok(hr == S_OK, "Activate failed: %08lx\n", hr);
hr = IAudioSessionManager_GetSimpleAudioVolume(sesm, &session_guid, @@ -2477,7 +2464,6 @@ static void test_session_creation(void)
hr = IMMDevice_Activate(cap_dev, &IID_IAudioSessionManager, CLSCTX_INPROC_SERVER, NULL, (void**)&cap_sesm); - ok((hr == S_OK)^(cap_sesm == NULL), "Activate %08lx &out pointer\n", hr); ok(hr == S_OK, "Activate failed: %08lx\n", hr);
hr = IAudioSessionManager_GetAudioSessionControl(cap_sesm, &session_guid, FALSE, &cap_sesc); @@ -2524,10 +2510,7 @@ static void test_session_creation(void)
hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&ac); - ok((hr == S_OK)^(ac == NULL), "Activate %08lx &out pointer\n", hr); ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return;
hr = IAudioClient_GetMixFormat(ac, &fmt); ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); @@ -2538,14 +2521,12 @@ static void test_session_creation(void)
hr = IAudioClient_GetService(ac, &IID_ISimpleAudioVolume, (void**)&sav); ok(hr == S_OK, "GetService failed: %08lx\n", hr); - if(hr == S_OK){ - vol = 0.5f; - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - ok(fabs(vol - 0.6f) < 0.05f, "Got wrong volume: %f\n", vol); + vol = 0.5f; + hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); + ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); + ok(fabs(vol - 0.6f) < 0.05f, "Got wrong volume: %f\n", vol);
- ISimpleAudioVolume_Release(sav); - } + ISimpleAudioVolume_Release(sav);
CoTaskMemFree(fmt); IAudioClient_Release(ac);
From: Matteo Bruni mbruni@codeweavers.com
I've seen some failures like this on test.winehq.org, so keep some code for it. --- dlls/mmdevapi/tests/render.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index be62631e3ea..b36237bf12d 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -1630,14 +1630,14 @@ static void test_session(void)
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eCapture, eMultimedia, &cap_dev); - if(hr == S_OK){ + if (hr == S_OK) + { + WAVEFORMATEX *cap_pwfx; + hr = IMMDevice_Activate(cap_dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&cap_ac); ok(hr == S_OK, "Activate failed: %08lx\n", hr); IMMDevice_Release(cap_dev); - } - if(hr == S_OK){ - WAVEFORMATEX *cap_pwfx;
hr = IAudioClient_GetMixFormat(cap_ac, &cap_pwfx); ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); @@ -1646,13 +1646,13 @@ static void test_session(void) 0, 5000000, 0, cap_pwfx, &ses1_guid); ok(hr == S_OK, "Initialize failed for capture in rendering session: %08lx\n", hr); CoTaskMemFree(cap_pwfx); - } - if(hr == S_OK){ + hr = IAudioClient_GetService(cap_ac, &IID_IAudioSessionControl, (void**)&cap_ctl); ok(hr == S_OK, "GetService failed: %08lx\n", hr); if(FAILED(hr)) cap_ctl = NULL; - }else + } + else skip("No capture session: %08lx; skipping capture device in render session tests\n", hr);
hr = IAudioClient_GetService(ses1_ac1, &IID_IAudioSessionControl2, (void**)&ses1_ctl);
From: Matteo Bruni mbruni@codeweavers.com
It's currently only implemented by winepulse. --- dlls/mmdevapi/tests/render.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index b36237bf12d..9ac82a65400 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -2806,7 +2806,7 @@ static void test_audio_clock_adjustment(void) ok(hr == S_OK, "Start failed: %08lx\n", hr);
hr = IAudioClockAdjustment_SetSampleRate(aca, 48000.00f); - ok(hr == S_OK, "SetSampleRate failed: %08lx\n", hr); + todo_wine_if(hr == E_NOTIMPL) ok(hr == S_OK, "SetSampleRate failed: %08lx\n", hr);
/* Wait for frame processing */ WaitForSingleObject(event, 1000); @@ -2815,7 +2815,7 @@ static void test_audio_clock_adjustment(void) ok(bufsize == expected_bufsize, "unexpected bufsize %d expected %d\n", bufsize, expected_bufsize);
hr = IAudioClockAdjustment_SetSampleRate(aca, 44100.00f); - ok(hr == S_OK, "SetSampleRate failed: %08lx\n", hr); + todo_wine_if(hr == E_NOTIMPL) ok(hr == S_OK, "SetSampleRate failed: %08lx\n", hr);
/* Wait for frame processing */ WaitForSingleObject(event, 1000);