-- v3: mf: Implement audio capture device enumeration in MFEnumDeviceSources().
This merge request was approved by Nikolay Sivov.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/tests/mf.c | 111 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index fa5b0f55391..6847030b329 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -30,7 +30,6 @@ #include "mfapi.h" #include "mferror.h" #include "mfidl.h" -#include "mmdeviceapi.h" #include "uuids.h" #include "wmcodecdsp.h" #include "nserror.h" @@ -40,6 +39,8 @@ #include "wine/test.h"
#include "initguid.h" +#include "mmdeviceapi.h" +#include "devpkey.h" #include "evr9.h"
#define DEFINE_EXPECT(func) \ @@ -6426,6 +6427,113 @@ static void test_media_session_Start(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); }
+static void test_MFEnumDeviceSources(void) +{ + static const WCHAR devinterface_audio_capture_wstr[] = L"{2eef81be-33fa-4800-9670-1cd474972c3f}"; + static const WCHAR mmdev_path_prefix[] = L"\\?\SWD#MMDEVAPI#"; + IMMDeviceEnumerator *devenum; + IMMDeviceCollection *devices; + UINT32 i, count, count2; + IMFActivate **sources; + IMFAttributes *attrs; + IMMDevice *device; + HRESULT hr; + GUID guid; + + hr = MFCreateAttributes(&attrs, 3); + ok(hr == S_OK, "got %#lx.\n", hr); + + sources = (void *)0xdeadbeef; + count = 0xdeadbeef; + hr = MFEnumDeviceSources(attrs, &sources, &count); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + todo_wine ok(count == 0xdeadbeef, "got %#x.\n", count); + ok(sources == (void *)0xdeadbeef, "got %p.\n", sources); + + hr = CoInitialize(NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = IMFAttributes_SetGUID(attrs, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = MFEnumDeviceSources(attrs, &sources, &count); + todo_wine ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + hr = IMFAttributes_SetGUID(attrs, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID); + ok(hr == S_OK, "got %#lx.\n", hr); + + /* Some random guid. */ + hr = IMFAttributes_SetUINT32(attrs, &CLSID_MMDeviceEnumerator, 1); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = MFEnumDeviceSources(attrs, &sources, &count); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void **)&devenum); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, eCapture, DEVICE_STATE_ACTIVE, &devices); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IMMDeviceCollection_GetCount(devices, &count2); + ok(hr == S_OK, "got %#lx.\n", hr); + todo_wine ok(count2 == count, "got %u, %u.\n", count, count2); + + for (i = 0; i < count; ++i) + { + WCHAR str[512], expect_str[512], *device_id; + IMFActivate *source = sources[i]; + IPropertyStore *ps; + PROPVARIANT pv; + + hr = IMMDeviceCollection_Item(devices, i, &device); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = IMFActivate_GetString(source, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID, str, sizeof(str), NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IMMDevice_GetId(device, &device_id); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(!wcscmp(str, device_id), "got %s, %s.\n", debugstr_w(str), debugstr_w(device_id)); + + hr = IMFActivate_GetString(source, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_SYMBOLIC_LINK, str, sizeof(str), NULL); + ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Win7 */, "got %#lx.\n", hr); + if (hr == S_OK) + { + swprintf(expect_str, ARRAY_SIZE(expect_str), L"%s%s#%s", mmdev_path_prefix, device_id, devinterface_audio_capture_wstr); + ok(!wcscmp(str, expect_str), "got %s, expected %s.\n", debugstr_w(str), debugstr_w(expect_str)); + } + + hr = IMFActivate_GetGUID(source, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &guid); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID), "got %s.\n", debugstr_guid(&guid)); + + hr = IMFActivate_GetUINT32(source, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ROLE, &count2); + /* The attribute is filled if specified in input attributes as a filter. */ + ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + + hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); + ok(hr == S_OK, "got %#lx.\n", hr); + IPropertyStore_Release(ps); + + ok(pv.vt == VT_LPWSTR, "got %#x.\n", pv.vt); + hr = IMFActivate_GetString(source, &MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, str, sizeof(str), NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(!wcscmp(str, pv.pwszVal), "got %s, %s.\n", debugstr_w(str), debugstr_w(pv.pwszVal)); + + PropVariantClear(&pv); + + CoTaskMemFree(device_id); + IMMDevice_Release(device); + IMFActivate_Release(source); + } + + IMMDeviceCollection_Release(devices); + IMMDeviceEnumerator_Release(devenum); + IMFAttributes_Release(attrs); + + CoTaskMemFree(sources); + CoUninitialize(); +} + START_TEST(mf) { init_functions(); @@ -6459,4 +6567,5 @@ START_TEST(mf) test_mpeg4_media_sink(); test_MFCreateSequencerSegmentOffset(); test_media_session_Start(); + test_MFEnumDeviceSources(); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/Makefile.in | 1 + dlls/mf/main.c | 23 ++++++-- dlls/mf/mf_private.h | 2 + dlls/mf/sac.c | 131 +++++++++++++++++++++++++++++++++++++++++++ dlls/mf/tests/mf.c | 10 ++-- 5 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 dlls/mf/sac.c
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index 8eb1809be9b..d1e6dca62cd 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -14,6 +14,7 @@ SOURCES = \ mf.rc \ quality.c \ samplegrabber.c \ + sac.c \ sar.c \ scheme_handler.c \ session.c \ diff --git a/dlls/mf/main.c b/dlls/mf/main.c index 92558a86b30..e74a4ae8e4c 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -747,16 +747,29 @@ HRESULT WINAPI MFShutdownObject(IUnknown *object) /*********************************************************************** * MFEnumDeviceSources (mf.@) */ -HRESULT WINAPI MFEnumDeviceSources(IMFAttributes *attributes, IMFActivate ***sources, UINT32 *count) +HRESULT WINAPI MFEnumDeviceSources(IMFAttributes *attributes, IMFActivate ***sources, UINT32 *ret_count) { - FIXME("%p, %p, %p.\n", attributes, sources, count); + GUID source_type; + HRESULT hr; + + TRACE("%p, %p, %p.\n", attributes, sources, ret_count);
- if (!attributes || !sources || !count) + if (!attributes || !sources || !ret_count) return E_INVALIDARG;
- *count = 0; + if (FAILED(hr = IMFAttributes_GetGUID(attributes, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &source_type))) + return hr;
- return S_OK; + if (IsEqualGUID(&source_type, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)) + { + FIXME("Not implemented for video capture devices.\n"); + *ret_count = 0; + return S_OK; + } + if (IsEqualGUID(&source_type, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID)) + return enum_audio_capture_sources(attributes, sources, ret_count); + + return E_INVALIDARG; }
struct simple_type_handler diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index 401e1f55b49..7d169c0711f 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -122,3 +122,5 @@ extern HRESULT create_topology(TOPOID id, IMFTopology **topology); extern HRESULT topology_node_get_object(IMFTopologyNode *node, REFIID riid, void **obj); extern HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaTypeHandler **handler); extern HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type); + +extern HRESULT enum_audio_capture_sources(IMFAttributes *attributes, IMFActivate ***sources, UINT32 *ret_count); diff --git a/dlls/mf/sac.c b/dlls/mf/sac.c new file mode 100644 index 00000000000..d5c6518a72c --- /dev/null +++ b/dlls/mf/sac.c @@ -0,0 +1,131 @@ +/* + * Copyright 2024 Paul Gofman 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 + */ + +#define COBJMACROS + +#include "mfapi.h" +#include "mfidl.h" +#include "mf_private.h" +#include "mmdeviceapi.h" +#include "audioclient.h" + +#include "initguid.h" +#include "devpkey.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +static HRESULT audio_capture_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj) +{ + FIXME("%p, %p, %p stub.\n", attributes, user_context, obj); + + return E_NOTIMPL; +} + +static void audio_capture_shutdown_object(void *user_context, IUnknown *obj) +{ + TRACE("%p %p.\n", user_context, obj); +} + +static void audio_capture_free_private(void *user_context) +{ + TRACE("%p.\n", user_context); +} + +static const struct activate_funcs audio_capture_activate_funcs = +{ + audio_capture_create_object, + audio_capture_shutdown_object, + audio_capture_free_private, +}; + +HRESULT enum_audio_capture_sources(IMFAttributes *attributes, IMFActivate ***ret_sources, UINT32 *ret_count) +{ + IMMDeviceEnumerator *devenum = NULL; + IMMDeviceCollection *devices = NULL; + UINT32 i, count, created_count = 0; + IMFActivate **sources = NULL; + ERole role; + HRESULT hr; + + if (FAILED(hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, + (void **)&devenum))) + goto done; + if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ROLE, (UINT32 *)&role))) + FIXME("Specifying role (%d) is not supported.\n", role); + if (FAILED(hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, eCapture, DEVICE_STATE_ACTIVE, &devices))) + goto done; + if (FAILED(hr = IMMDeviceCollection_GetCount(devices, &count))) + goto done; + sources = CoTaskMemAlloc(count * sizeof(*sources)); + for (i = 0; i < count; ++i) + { + IMMDevice *device = NULL; + IPropertyStore *ps; + WCHAR *str = NULL; + PROPVARIANT pv; + + if (FAILED(hr = create_activation_object(NULL, &audio_capture_activate_funcs, &sources[i]))) + goto done; + ++created_count; + + hr = IMFActivate_SetGUID(sources[i], &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID); + if (SUCCEEDED(hr)) + hr = IMMDeviceCollection_Item(devices, i, &device); + if (SUCCEEDED(hr)) + hr = IMMDevice_GetId(device, &str); + if (SUCCEEDED(hr)) + hr = IMFActivate_SetString(sources[i], &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID, str); + CoTaskMemFree(str); + + PropVariantInit(&pv); + if (SUCCEEDED(hr) && SUCCEEDED((hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps)))) + { + hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); + IPropertyStore_Release(ps); + } + if (device) + IMMDevice_Release(device); + + if (SUCCEEDED(hr) && pv.vt != VT_LPWSTR) + hr = E_FAIL; + + if (SUCCEEDED(hr)) + hr = IMFActivate_SetString(sources[i], &MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, pv.pwszVal); + PropVariantClear(&pv); + if (FAILED(hr)) + goto done; + } + *ret_count = count; + *ret_sources = sources; + +done: + if (FAILED(hr)) + { + for (i = 0; i < created_count; ++i) + IMFActivate_Release(sources[i]); + CoTaskMemFree(sources); + } + if (devices) + IMMDeviceCollection_Release(devices); + if (devenum) + IMMDeviceEnumerator_Release(devenum); + TRACE("ret %#lx, *ret_count %u.\n", hr, *ret_count); + return hr; +} diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 6847030b329..a2f183e5cc4 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6446,8 +6446,8 @@ static void test_MFEnumDeviceSources(void) sources = (void *)0xdeadbeef; count = 0xdeadbeef; hr = MFEnumDeviceSources(attrs, &sources, &count); - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); - todo_wine ok(count == 0xdeadbeef, "got %#x.\n", count); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + ok(count == 0xdeadbeef, "got %#x.\n", count); ok(sources == (void *)0xdeadbeef, "got %p.\n", sources);
hr = CoInitialize(NULL); @@ -6456,7 +6456,7 @@ static void test_MFEnumDeviceSources(void) hr = IMFAttributes_SetGUID(attrs, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE); ok(hr == S_OK, "got %#lx.\n", hr); hr = MFEnumDeviceSources(attrs, &sources, &count); - todo_wine ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr);
hr = IMFAttributes_SetGUID(attrs, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID); ok(hr == S_OK, "got %#lx.\n", hr); @@ -6474,7 +6474,7 @@ static void test_MFEnumDeviceSources(void) ok(hr == S_OK, "got %#lx.\n", hr); hr = IMMDeviceCollection_GetCount(devices, &count2); ok(hr == S_OK, "got %#lx.\n", hr); - todo_wine ok(count2 == count, "got %u, %u.\n", count, count2); + ok(count2 == count, "got %u, %u.\n", count, count2);
for (i = 0; i < count; ++i) { @@ -6493,7 +6493,7 @@ static void test_MFEnumDeviceSources(void) ok(!wcscmp(str, device_id), "got %s, %s.\n", debugstr_w(str), debugstr_w(device_id));
hr = IMFActivate_GetString(source, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_SYMBOLIC_LINK, str, sizeof(str), NULL); - ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Win7 */, "got %#lx.\n", hr); + todo_wine ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Win7 */, "got %#lx.\n", hr); if (hr == S_OK) { swprintf(expect_str, ARRAY_SIZE(expect_str), L"%s%s#%s", mmdev_path_prefix, device_id, devinterface_audio_capture_wstr);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=145872
Your paranoid android.
=== debian11b (build log) ===
error: patch failed: dlls/mf/tests/mf.c:30 error: patch failed: dlls/mf/Makefile.in:14 error: patch failed: dlls/mf/main.c:747 error: patch failed: dlls/mf/mf_private.h:122 error: patch failed: dlls/mf/tests/mf.c:6446 Task: Patch failed to apply
v3: - fix a typo; - don't code mm device path / interface and don't set MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_SYMBOLIC_LINK; - use IsEqualGUID(); - Check result when setting attributes; - Cascade checks for hr.