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.
-- v18: mmdevapi: add stub for IDeviceTopology mmdevapi/tests: add test for IDeviceTopology
From: David McFarland corngood@gmail.com
--- dlls/mmdevapi/tests/render.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 3e24ac45944..fac88e211e4 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -341,8 +341,28 @@ 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 = 0, unit_period, min_period, max_period; + + hr = IAudioClient3_GetSharedModeEnginePeriod( + ac3, pwfx, &default_period, &unit_period, &min_period, &max_period); + todo_wine + ok(hr == S_OK, "GetSharedModeEnginePeriod returns %08lx\n", hr); + + hr = IAudioClient3_InitializeSharedAudioStream( + ac3, AUDCLNT_SHAREMODE_SHARED, default_period, pwfx, NULL); + todo_wine + 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); + } + else + win_skip("IAudioClient3 is not present\n");
test_uninitialized(ac);
From: David McFarland corngood@gmail.com
--- dlls/mmdevapi/client.c | 11 +++++++++-- dlls/mmdevapi/tests/render.c | 1 - 2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 3e0c70a44f4..02199622efe 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -949,9 +949,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 = diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index fac88e211e4..14442036763 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -351,7 +351,6 @@ static void test_audioclient(void)
hr = IAudioClient3_InitializeSharedAudioStream( ac3, AUDCLNT_SHAREMODE_SHARED, default_period, pwfx, NULL); - todo_wine ok(hr == S_OK, "InitializeSharedAudioStream returns %08lx\n", hr);
IAudioClient3_Release(ac3);
From: David McFarland corngood@gmail.com
For now min/max/default are all hard-coded to ~10ms. --- dlls/mmdevapi/client.c | 15 +++++++++++---- dlls/mmdevapi/tests/render.c | 1 - 2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 02199622efe..ef1e9faef81 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, diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 14442036763..a7da68ec3f1 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -346,7 +346,6 @@ static void test_audioclient(void)
hr = IAudioClient3_GetSharedModeEnginePeriod( ac3, pwfx, &default_period, &unit_period, &min_period, &max_period); - todo_wine ok(hr == S_OK, "GetSharedModeEnginePeriod returns %08lx\n", hr);
hr = IAudioClient3_InitializeSharedAudioStream(
From: David McFarland corngood@gmail.com
--- dlls/mmdevapi/tests/mmdevenum.c | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
diff --git a/dlls/mmdevapi/tests/mmdevenum.c b/dlls/mmdevapi/tests/mmdevenum.c index a5b692a53ee..f34386a575a 100644 --- a/dlls/mmdevapi/tests/mmdevenum.c +++ b/dlls/mmdevapi/tests/mmdevenum.c @@ -29,6 +29,7 @@ #include "dshow.h" #include "dsound.h" #include "devpkey.h" +#include "devicetopology.h"
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
@@ -382,6 +383,71 @@ static IMMNotificationClientVtbl notif_vtbl = {
static IMMNotificationClient notif = { ¬if_vtbl };
+static void test_connectors(IDeviceTopology *dt) +{ + 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); + } + } +} + +static void test_DeviceTopology(IMMDeviceEnumerator *mme) +{ + IMMDevice *dev = NULL; + IDeviceTopology *dt = NULL; + HRESULT hr; + + 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) + win_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) + todo_wine + win_skip("IDeviceTopology interface not found\n"); + else + skip("IDeviceTopology Activation returns 0x%08lx\n", hr); + goto cleanup; + } + + test_connectors(dt); + + IDeviceTopology_Release(dt); + +cleanup: + if (dev) + IMMDevice_Release(dev); +} + /* Only do parameter tests here, the actual MMDevice testing should be a separate test */ START_TEST(mmdevenum) { @@ -478,6 +544,8 @@ START_TEST(mmdevenum) hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); ok(hr == E_NOTFOUND, "UnregisterEndpointNotificationCallback failed: %08lx\n", hr);
+ test_DeviceTopology(mme); + IMMDeviceEnumerator_Release(mme);
test_ActivateAudioInterfaceAsync();
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 + dlls/mmdevapi/tests/mmdevenum.c | 1 - 5 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 dlls/mmdevapi/devicetopology.c
diff --git a/dlls/mmdevapi/Makefile.in b/dlls/mmdevapi/Makefile.in index 90c2302ef50..1d4cce74217 100644 --- a/dlls/mmdevapi/Makefile.in +++ b/dlls/mmdevapi/Makefile.in @@ -6,6 +6,7 @@ SOURCES = \ audiovolume.c \ client.c \ devenum.c \ + devicetopology.c \ main.c \ mmdevapi_classes.idl \ session.c \ diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index 3c2085339ed..636102a5e49 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -667,7 +667,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 5ef19ffc0d1..950251a1457 100644 --- a/dlls/mmdevapi/mmdevapi_private.h +++ b/dlls/mmdevapi/mmdevapi_private.h @@ -73,6 +73,7 @@ extern HRESULT AudioClient_Create(GUID *guid, IMMDevice *device, IAudioClient ** extern HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolumeEx **ppv); extern HRESULT AudioSessionManager_Create(IMMDevice *device, IAudioSessionManager2 **ppv); extern HRESULT SpatialAudioClient_Create(IMMDevice *device, ISpatialAudioClient **out); +extern HRESULT DeviceTopology_Create(IMMDevice *device, IDeviceTopology **out);
extern HRESULT load_devices_from_reg(void); extern HRESULT load_driver_devices(EDataFlow flow); diff --git a/dlls/mmdevapi/tests/mmdevenum.c b/dlls/mmdevapi/tests/mmdevenum.c index f34386a575a..3bceefb91a3 100644 --- a/dlls/mmdevapi/tests/mmdevenum.c +++ b/dlls/mmdevapi/tests/mmdevenum.c @@ -432,7 +432,6 @@ static void test_DeviceTopology(IMMDeviceEnumerator *mme) if (hr != S_OK || !dev) { if (hr == E_NOINTERFACE) - todo_wine win_skip("IDeviceTopology interface not found\n"); else skip("IDeviceTopology Activation returns 0x%08lx\n", hr);
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=143697
Your paranoid android.
=== w8 (32 bit report) ===
mmdevapi: render.c:1376: Test failed: GetBuffer large (20671) at iteration 1 render.c:1376: Test failed: GetBuffer large (20671) at iteration 2
=== w1064v1809 (32 bit report) ===
mmdevapi: render.c:1376: Test failed: GetBuffer large (20671) at iteration 3
=== w1064_tsign (32 bit report) ===
mmdevapi: render.c:1376: Test failed: GetBuffer large (22500) at iteration 6 render.c:1376: Test failed: GetBuffer large (22500) at iteration 7
=== w10pro64 (32 bit report) ===
mmdevapi: render.c:1376: Test failed: GetBuffer large (22500) at iteration 7
=== w1064_adm (64 bit report) ===
mmdevapi: render.c:1376: Test failed: GetBuffer large (22500) at iteration 1