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);