Since Yousician's last update, it was throwing an error when initialising audio output. Unfortunately I don't have access to the old version, but they seem to have dropped win<10 support, and are using only IAudioClient3_InitializeSharedAudioStream. They also use IDeviceTopology to get the type of the first output connector.
This is the bare minimum I needed to get it working.
From: David McFarland corngood@gmail.com
--- dlls/mmdevapi/tests/render.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 8e000f03acb..b59252b67e3 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -325,8 +325,27 @@ static void test_audioclient(void) broken(hr == E_NOINTERFACE) /* win8 */, "Failed to query IAudioClient3 interface: %08lx\n", hr);
- if(hr == S_OK) + if(hr == S_OK){ + UINT32 default_period, unit_period, min_period, max_period; + + hr = IAudioClient3_GetSharedModeEnginePeriod( + ac3, pwfx, &default_period, &unit_period, &min_period, &max_period); + ok(hr == S_OK, "GetSharedModeEnginePeriod returns %08lx\n", hr); + + if(hr == S_OK){ + hr = IAudioClient3_InitializeSharedAudioStream( + ac3, AUDCLNT_SHAREMODE_SHARED, default_period, pwfx, NULL); + ok(hr == S_OK, "InitializeSharedAudioStream returns %08lx\n", hr); + } + IAudioClient3_Release(ac3); + 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); + + }
test_uninitialized(ac);
From: David McFarland corngood@gmail.com
Also, implement IAudioClient3_GetSharedModeEnginePeriod with min/max/default all set to ~10ms. --- dlls/mmdevapi/client.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index d8aad762627..ae1da830218 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -929,10 +929,17 @@ static HRESULT WINAPI client_GetSharedModeEnginePeriod(IAudioClient3 *iface, UINT32 *max_period_frames) { struct audio_client *This = impl_from_IAudioClient3(iface); - FIXME("(%p)->(%p, %p, %p, %p, %p) - stub\n", This, format, default_period_frames, - unit_period_frames, min_period_frames, - max_period_frames); - return E_NOTIMPL; + FIXME("(%p)->(%p, %p, %p, %p, %p) - partial stub\n", + This, format, default_period_frames, + unit_period_frames, min_period_frames, + max_period_frames); + + *default_period_frames = + *min_period_frames = + *max_period_frames = + format->nSamplesPerSec / 100; // ~10ms + *unit_period_frames = 1; + return S_OK; }
static HRESULT WINAPI client_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface, @@ -949,9 +956,16 @@ static HRESULT WINAPI client_InitializeSharedAudioStream(IAudioClient3 *iface, D const WAVEFORMATEX *format, const GUID *session_guid) { + struct audio_client *This = impl_from_IAudioClient3(iface); - FIXME("(%p)->(0x%lx, %u, %p, %s) - stub\n", This, flags, period_frames, format, debugstr_guid(session_guid)); - return E_NOTIMPL; + REFERENCE_TIME duration; + FIXME("(%p)->(0x%lx, %u, %p, %s) - partial stub\n", This, flags, period_frames, format, debugstr_guid(session_guid)); + + if (!format) + return E_POINTER; + + duration = period_frames * (REFERENCE_TIME)10000000 / format->nSamplesPerSec; + return client_Initialize(iface, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, format, session_guid); }
const IAudioClient3Vtbl AudioClient3_Vtbl =
From: David McFarland corngood@gmail.com
--- dlls/mmdevapi/tests/Makefile.in | 1 + dlls/mmdevapi/tests/devicetopology.c | 105 +++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 dlls/mmdevapi/tests/devicetopology.c
diff --git a/dlls/mmdevapi/tests/Makefile.in b/dlls/mmdevapi/tests/Makefile.in index dd180a253b9..b63bd47043f 100644 --- a/dlls/mmdevapi/tests/Makefile.in +++ b/dlls/mmdevapi/tests/Makefile.in @@ -4,6 +4,7 @@ IMPORTS = ole32 version user32 advapi32 winmm C_SRCS = \ capture.c \ dependency.c \ + devicetopology.c \ mmdevenum.c \ propstore.c \ render.c \ diff --git a/dlls/mmdevapi/tests/devicetopology.c b/dlls/mmdevapi/tests/devicetopology.c new file mode 100644 index 00000000000..2c21e93a95e --- /dev/null +++ b/dlls/mmdevapi/tests/devicetopology.c @@ -0,0 +1,105 @@ +/* + * Copyright 2021 Arkadiusz Hiler 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 + */ + +#include <math.h> +#include <stdio.h> + +#include "wine/test.h" + +#define COBJMACROS + +#include "mmdeviceapi.h" +#include "devicetopology.h" +#include "mmsystem.h" + +static IMMDeviceEnumerator *mme = NULL; +static IMMDevice *dev = NULL; +static IDeviceTopology *dt = NULL; + +static void test_connectors(void) +{ + HRESULT hr; + UINT connector_count; + + hr = IDeviceTopology_GetConnectorCount(dt, &connector_count); + ok(hr == S_OK, "GetConnectorCount returns 0x%08lx\n", hr); + trace("connector count: %u\n", connector_count); + + if (hr == S_OK && connector_count > 0) + { + IConnector *connector; + + hr = IDeviceTopology_GetConnector(dt, 0, &connector); + ok(hr == S_OK, "GetConnector returns 0x%08lx\n", hr); + + if (hr == S_OK) + { + ConnectorType type; + + hr = IConnector_GetType(connector, &type); + ok(hr == S_OK, "GetConnector returns 0x%08lx\n", hr); + trace("connector 0 type: %u\n", connector_count); + } + } +} + +START_TEST(devicetopology) +{ + HRESULT hr; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); + if (FAILED(hr)) + { + skip("mmdevapi not available: 0x%08lx\n", hr); + goto cleanup; + } + + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eRender, eMultimedia, &dev); + ok(hr == S_OK || hr == E_NOTFOUND, "GetDefaultAudioEndpoint failed: 0x%08lx\n", hr); + if (hr != S_OK || !dev) + { + if (hr == E_NOTFOUND) + skip("No sound card available\n"); + else + skip("GetDefaultAudioEndpoint returns 0x%08lx\n", hr); + goto cleanup; + } + + hr = IMMDevice_Activate(dev, &IID_IDeviceTopology, CLSCTX_INPROC_SERVER, NULL, (void**)&dt); + ok(hr == S_OK || hr == E_NOINTERFACE, "IDeviceTopology Activation failed: 0x%08lx\n", hr); + if (hr != S_OK || !dev) + { + if (hr == E_NOINTERFACE) + skip("IDeviceTopology interface not found\n"); + else + skip("IDeviceTopology Activation returns 0x%08lx\n", hr); + goto cleanup; + } + + test_connectors(); + + IDeviceTopology_Release(dt); + +cleanup: + if (dev) + IMMDevice_Release(dev); + if (mme) + IMMDeviceEnumerator_Release(mme); + CoUninitialize(); +}
From: David McFarland corngood@gmail.com
--- dlls/mmdevapi/Makefile.in | 1 + dlls/mmdevapi/devenum.c | 2 +- dlls/mmdevapi/devicetopology.c | 322 +++++++++++++++++++++++++++++++ dlls/mmdevapi/mmdevapi_private.h | 1 + 4 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 dlls/mmdevapi/devicetopology.c
diff --git a/dlls/mmdevapi/Makefile.in b/dlls/mmdevapi/Makefile.in index d9ec97b87e5..a380e28f61d 100644 --- a/dlls/mmdevapi/Makefile.in +++ b/dlls/mmdevapi/Makefile.in @@ -6,6 +6,7 @@ C_SRCS = \ audiovolume.c \ client.c \ devenum.c \ + devicetopology.c \ main.c \ session.c \ spatialaudio.c diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index 6344ec66d34..e5caadfa0f2 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -661,7 +661,7 @@ static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD cls } else if (IsEqualIID(riid, &IID_IDeviceTopology)) { - FIXME("IID_IDeviceTopology unsupported\n"); + hr = DeviceTopology_Create(iface, (IDeviceTopology**)ppv); } else if (IsEqualIID(riid, &IID_IDirectSound) || IsEqualIID(riid, &IID_IDirectSound8)) diff --git a/dlls/mmdevapi/devicetopology.c b/dlls/mmdevapi/devicetopology.c new file mode 100644 index 00000000000..e23701695c9 --- /dev/null +++ b/dlls/mmdevapi/devicetopology.c @@ -0,0 +1,322 @@ +/* + * 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 <audiopolicy.h> +#include <mmdeviceapi.h> + +#include <wine/debug.h> + +#include "mmdevapi_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); + +struct connector { + IConnector IConnector_iface; + + LONG ref; +}; + +static inline struct connector *impl_from_IConnector(IConnector *iface) +{ + return CONTAINING_RECORD(iface, struct connector, IConnector_iface); +} + +static HRESULT WINAPI connector_QueryInterface(IConnector *iface, REFIID riid, void **ppv) +{ + struct connector *This = impl_from_IConnector(iface); + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); + + if (!ppv) + return E_POINTER; + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IConnector)) + *ppv = &This->IConnector_iface; + else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*ppv); + + return S_OK; +} + +static ULONG WINAPI connector_AddRef(IConnector *iface) +{ + struct connector *This = impl_from_IConnector(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) new ref %lu\n", This, ref); + return ref; +} + +static ULONG WINAPI connector_Release(IConnector *iface) +{ + struct connector *This = impl_from_IConnector(iface); + ULONG ref = InterlockedDecrement(&This->ref); + TRACE("(%p) new ref %lu\n", This, ref); + + if (!ref) + HeapFree(GetProcessHeap(), 0, This); + + return ref; +} + +static HRESULT WINAPI connector_GetType( + IConnector *This, + ConnectorType *pType) +{ + FIXME("(%p) - partial stub\n", This); + *pType = Physical_Internal; + return S_OK; +} + +static HRESULT WINAPI connector_GetDataFlow( + IConnector *This, + DataFlow *pFlow) +{ + FIXME("(%p) - stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI connector_ConnectTo( + IConnector *This, + IConnector *pConnectTo) +{ + FIXME("(%p) - stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI connector_Disconnect( + IConnector *This) +{ + FIXME("(%p) - stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI connector_IsConnected( + IConnector *This, + BOOL *pbConnected) +{ + FIXME("(%p) - stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI connector_GetConnectedTo( + IConnector *This, + IConnector **ppConTo) +{ + FIXME("(%p) - stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI connector_GetConnectorIdConnectedTo( + IConnector *This, + LPWSTR *ppwstrConnectorId) +{ + FIXME("(%p) - stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI connector_GetDeviceIdConnectedTo( + IConnector *This, + LPWSTR *ppwstrDeviceId) +{ + FIXME("(%p) - stub\n", This); + return E_NOTIMPL; +} + +static const IConnectorVtbl Connector_Vtbl = +{ + connector_QueryInterface, + connector_AddRef, + connector_Release, + connector_GetType, + connector_GetDataFlow, + connector_ConnectTo, + connector_Disconnect, + connector_IsConnected, + connector_GetConnectedTo, + connector_GetConnectorIdConnectedTo, + connector_GetDeviceIdConnectedTo, +}; + +HRESULT connector_Create(IConnector **ppv) +{ + struct connector *This; + + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + + This->IConnector_iface.lpVtbl = &Connector_Vtbl; + This->ref = 1; + + *ppv = &This->IConnector_iface; + + return S_OK; +} + +struct device_topology { + IDeviceTopology IDeviceTopology_iface; + + LONG ref; +}; + +static inline struct device_topology *impl_from_IDeviceTopology(IDeviceTopology *iface) +{ + return CONTAINING_RECORD(iface, struct device_topology, IDeviceTopology_iface); +} + +static HRESULT WINAPI DT_QueryInterface(IDeviceTopology *iface, REFIID riid, void **ppv) +{ + struct device_topology *This = impl_from_IDeviceTopology(iface); + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); + + if (!ppv) + return E_POINTER; + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IDeviceTopology)) + *ppv = &This->IDeviceTopology_iface; + else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*ppv); + + return S_OK; +} + +static ULONG WINAPI DT_AddRef(IDeviceTopology *iface) +{ + struct device_topology *This = impl_from_IDeviceTopology(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) new ref %lu\n", This, ref); + return ref; +} + +static ULONG WINAPI DT_Release(IDeviceTopology *iface) +{ + struct device_topology *This = impl_from_IDeviceTopology(iface); + ULONG ref = InterlockedDecrement(&This->ref); + TRACE("(%p) new ref %lu\n", This, ref); + + if (!ref) + HeapFree(GetProcessHeap(), 0, This); + + return ref; +} + +static HRESULT WINAPI DT_GetConnectorCount(IDeviceTopology *This, + UINT *pCount) +{ + FIXME("(%p)->(%p) - partial stub\n", This, pCount); + + if (!pCount) + return E_POINTER; + + *pCount = 1; + return S_OK; +} + +static HRESULT WINAPI DT_GetConnector(IDeviceTopology *This, + UINT nIndex, + IConnector **ppConnector) +{ + FIXME("(%p)->(%u, %p) - partial stub\n", This, nIndex, ppConnector); + + if (nIndex == 0) + { + return connector_Create(ppConnector); + } + + return E_INVALIDARG; +} + +static HRESULT WINAPI DT_GetSubunitCount(IDeviceTopology *This, + UINT *pCount) +{ + FIXME("(%p)->(%p) - stub\n", This, pCount); + return E_NOTIMPL; +} + +static HRESULT WINAPI DT_GetSubunit(IDeviceTopology *This, + UINT nIndex, + ISubUnit **ppConnector) +{ + FIXME("(%p)->(%u, %p) - stub\n", This, nIndex, ppConnector); + return E_NOTIMPL; +} + +static HRESULT WINAPI DT_GetPartById(IDeviceTopology *This, + UINT nId, + IPart **ppPart) +{ + FIXME("(%p)->(%u, %p) - stub\n", This, nId, ppPart); + return E_NOTIMPL; +} + +static HRESULT WINAPI DT_GetDeviceId(IDeviceTopology *This, + LPWSTR *ppwstrDeviceId) +{ + FIXME("(%p)->(%p) - stub\n", This, ppwstrDeviceId); + return E_NOTIMPL; +} + +static HRESULT WINAPI DT_GetSignalPath(IDeviceTopology *This, + IPart *pIPartFrom, + IPart *pIPartTo, + BOOL bRejectMixedPaths, + IPartsList **ppParts) +{ + FIXME("(%p)->(%p, %p, %s, %p) - stub\n", + This, pIPartFrom, pIPartTo, bRejectMixedPaths ? "TRUE" : "FALSE", ppParts); + return E_NOTIMPL; +} + +static const IDeviceTopologyVtbl DeviceTopology_Vtbl = +{ + DT_QueryInterface, + DT_AddRef, + DT_Release, + DT_GetConnectorCount, + DT_GetConnector, + DT_GetSubunitCount, + DT_GetSubunit, + DT_GetPartById, + DT_GetDeviceId, + DT_GetSignalPath, +}; + +HRESULT DeviceTopology_Create(IMMDevice *device, IDeviceTopology **ppv) +{ + struct device_topology *This; + + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + + This->IDeviceTopology_iface.lpVtbl = &DeviceTopology_Vtbl; + This->ref = 1; + + *ppv = &This->IDeviceTopology_iface; + + return S_OK; +} diff --git a/dlls/mmdevapi/mmdevapi_private.h b/dlls/mmdevapi/mmdevapi_private.h index f8bf7d3a440..762bc725d4f 100644 --- a/dlls/mmdevapi/mmdevapi_private.h +++ b/dlls/mmdevapi/mmdevapi_private.h @@ -79,6 +79,7 @@ extern HRESULT AudioClient_Create(GUID *guid, IMMDevice *device, IAudioClient ** extern HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolumeEx **ppv) DECLSPEC_HIDDEN; extern HRESULT AudioSessionManager_Create(IMMDevice *device, IAudioSessionManager2 **ppv) DECLSPEC_HIDDEN; extern HRESULT SpatialAudioClient_Create(IMMDevice *device, ISpatialAudioClient **out) DECLSPEC_HIDDEN; +extern HRESULT DeviceTopology_Create(IMMDevice *device, IDeviceTopology **out) DECLSPEC_HIDDEN;
extern HRESULT load_devices_from_reg(void) DECLSPEC_HIDDEN; extern HRESULT load_driver_devices(EDataFlow flow) DECLSPEC_HIDDEN;
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=135969
Your paranoid android.
=== w1064v1507 (32 bit report) ===
mmdevapi: render.c:1361: Test failed: GetBuffer large (20671) at iteration 1
=== w1064v1507 (64 bit report) ===
mmdevapi: render.c:1361: Test failed: GetBuffer large (20671) at iteration 3