[PATCH 2/3] xaudio2: Implement IXAudio2::GetDeviceDetails

Andrew Eikum aeikum at codeweavers.com
Fri Aug 21 09:40:30 CDT 2015


---
 configure.ac                     |   1 +
 dlls/xaudio2_7/tests/Makefile.in |   5 +
 dlls/xaudio2_7/tests/xaudio2.c   |  93 ++++++++++++++++++
 dlls/xaudio2_7/xaudio_dll.c      | 197 +++++++++++++++++++++++++++++++++++++--
 4 files changed, 288 insertions(+), 8 deletions(-)
 create mode 100644 dlls/xaudio2_7/tests/Makefile.in
 create mode 100644 dlls/xaudio2_7/tests/xaudio2.c

diff --git a/configure.ac b/configure.ac
index 2b0b405..13f8738 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3425,6 +3425,7 @@ WINE_CONFIG_DLL(xapofx1_3)
 WINE_CONFIG_DLL(xapofx1_4)
 WINE_CONFIG_DLL(xapofx1_5)
 WINE_CONFIG_DLL(xaudio2_7,,[clean])
+WINE_CONFIG_TEST(dlls/xaudio2_7/tests,[clean])
 WINE_CONFIG_DLL(xaudio2_8)
 WINE_CONFIG_DLL(xinput1_1)
 WINE_CONFIG_DLL(xinput1_2)
diff --git a/dlls/xaudio2_7/tests/Makefile.in b/dlls/xaudio2_7/tests/Makefile.in
new file mode 100644
index 0000000..20dea32
--- /dev/null
+++ b/dlls/xaudio2_7/tests/Makefile.in
@@ -0,0 +1,5 @@
+TESTDLL = xaudio2_7.dll
+IMPORTS = ole32
+
+C_SRCS = \
+	 xaudio2.c
diff --git a/dlls/xaudio2_7/tests/xaudio2.c b/dlls/xaudio2_7/tests/xaudio2.c
new file mode 100644
index 0000000..669e5ed
--- /dev/null
+++ b/dlls/xaudio2_7/tests/xaudio2.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015 Andrew Eikum 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 <windows.h>
+
+#define COBJMACROS
+#include "wine/test.h"
+#include "initguid.h"
+#include "xaudio2.h"
+
+static BOOL xaudio27;
+
+static HRESULT (WINAPI *pXAudio2Create)(IXAudio2 **, UINT32, XAUDIO2_PROCESSOR) = NULL;
+
+static void test_DeviceDetails(IXAudio27 *xa)
+{
+    HRESULT hr;
+    XAUDIO2_DEVICE_DETAILS dd;
+    UINT32 count, i;
+
+    hr = IXAudio27_GetDeviceCount(xa, &count);
+    ok(hr == S_OK, "GetDeviceCount failed: %08x\n", hr);
+
+    if(count == 0)
+        return;
+
+    for(i = 0; i < count; ++i){
+        hr = IXAudio27_GetDeviceDetails(xa, i, &dd);
+        ok(hr == S_OK, "GetDeviceDetails failed: %08x\n", hr);
+
+        if(i == 0)
+            ok(dd.Role == GlobalDefaultDevice, "Got wrong role for index 0: 0x%x\n", dd.Role);
+        else
+            ok(dd.Role == NotDefaultDevice, "Got wrong role for index %u: 0x%x\n", i, dd.Role);
+    }
+}
+
+START_TEST(xaudio2)
+{
+    HRESULT hr;
+    IXAudio27 *xa27 = NULL;
+    IXAudio2 *xa = NULL;
+    HANDLE xa28dll;
+
+    CoInitialize(NULL);
+
+    xa28dll = LoadLibraryA("xaudio2_8.dll");
+    if(xa28dll)
+        pXAudio2Create = (void*)GetProcAddress(xa28dll, "XAudio2Create");
+
+    /* XAudio 2.7 (Jun 2010 DirectX) */
+    hr = CoCreateInstance(&CLSID_XAudio2, NULL, CLSCTX_INPROC_SERVER,
+            &IID_IXAudio27, (void**)&xa27);
+    if(hr == S_OK){
+        xaudio27 = TRUE;
+
+        hr = IXAudio27_Initialize(xa27, 0, XAUDIO2_ANY_PROCESSOR);
+        ok(hr == S_OK, "Initialize failed: %08x\n", hr);
+
+        test_DeviceDetails(xa27);
+
+        IXAudio27_Release(xa27);
+    }else
+        win_skip("XAudio 2.7 not available\n");
+
+    /* XAudio 2.8 (Win8+) */
+    if(pXAudio2Create){
+        xaudio27 = FALSE;
+
+        hr = pXAudio2Create(&xa, 0, XAUDIO2_DEFAULT_PROCESSOR);
+        ok(hr == S_OK, "XAudio2Create failed: %08x\n", hr);
+
+        IXAudio2_Release(xa);
+    }else
+        win_skip("XAudio 2.8 not available\n");
+
+    CoUninitialize();
+}
diff --git a/dlls/xaudio2_7/xaudio_dll.c b/dlls/xaudio2_7/xaudio_dll.c
index e0afd3e..1eaa7e6 100644
--- a/dlls/xaudio2_7/xaudio_dll.c
+++ b/dlls/xaudio2_7/xaudio_dll.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015 Mark Harmstone
+ * Copyright (c) 2015 Andrew Eikum for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -18,6 +19,8 @@
 
 #include <stdarg.h>
 
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
 #define COBJMACROS
 
 #include "windef.h"
@@ -34,6 +37,9 @@
 
 #include "mmsystem.h"
 #include "xaudio2.h"
+#include "devpkey.h"
+#include "mmdeviceapi.h"
+#include "audioclient.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
 
@@ -155,6 +161,11 @@ typedef struct {
 
     struct list source_voices;
     struct list submix_voices;
+
+    IMMDeviceEnumerator *devenum;
+
+    WCHAR **devids;
+    UINT32 ndevs;
 } IXAudio2Impl;
 
 static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
@@ -1098,6 +1109,7 @@ static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
     TRACE("(%p)->(): Refcount now %u\n", This, ref);
 
     if (!ref) {
+        int i;
         XA2SourceImpl *src, *src2;
         XA2SubmixImpl *sub, *sub2;
 
@@ -1113,6 +1125,12 @@ static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
             HeapFree(GetProcessHeap(), 0, sub);
         }
 
+        if(This->devenum)
+            IMMDeviceEnumerator_Release(This->devenum);
+        for(i = 0; i < This->ndevs; ++i)
+            CoTaskMemFree(This->devids[i]);
+        HeapFree(GetProcessHeap(), 0, This->devids);
+
         DeleteCriticalSection(&This->lock);
 
         HeapFree(GetProcessHeap(), 0, This);
@@ -1365,16 +1383,93 @@ static ULONG WINAPI XA27_Release(IXAudio27 *iface)
 static HRESULT WINAPI XA27_GetDeviceCount(IXAudio27 *iface, UINT32 *pCount)
 {
     IXAudio2Impl *This = impl_from_IXAudio27(iface);
-    TRACE("(%p)->(%p)\n", This, pCount);
-    return E_NOTIMPL;
+
+    TRACE("%p, %p\n", This, pCount);
+
+    *pCount = This->ndevs;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI XA27_GetDeviceDetails(IXAudio27 *iface, UINT32 index,
         XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
 {
     IXAudio2Impl *This = impl_from_IXAudio27(iface);
-    TRACE("(%p)->(%u, %p)\n", This, index, pDeviceDetails);
-    return E_NOTIMPL;
+    HRESULT hr;
+    IMMDevice *dev;
+    IAudioClient *client;
+    IPropertyStore *ps;
+    WAVEFORMATEX *wfx;
+    PROPVARIANT var;
+
+    TRACE("%p, %u, %p\n", This, index, pDeviceDetails);
+
+    if(index >= This->ndevs)
+        return E_INVALIDARG;
+
+    hr = IMMDeviceEnumerator_GetDevice(This->devenum, This->devids[index], &dev);
+    if(FAILED(hr)){
+        WARN("GetDevice failed: %08x\n", hr);
+        return hr;
+    }
+
+    hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER,
+            NULL, (void**)&client);
+    if(FAILED(hr)){
+        WARN("Activate failed: %08x\n", hr);
+        IMMDevice_Release(dev);
+        return hr;
+    }
+
+    hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, &ps);
+    if(FAILED(hr)){
+        WARN("OpenPropertyStore failed: %08x\n", hr);
+        IAudioClient_Release(client);
+        IMMDevice_Release(dev);
+        return hr;
+    }
+
+    PropVariantInit(&var);
+
+    hr = IPropertyStore_GetValue(ps, (PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &var);
+    if(FAILED(hr)){
+        WARN("GetValue failed: %08x\n", hr);
+        goto done;
+    }
+
+    lstrcpynW(pDeviceDetails->DisplayName, var.u.pwszVal, sizeof(pDeviceDetails->DisplayName)/sizeof(WCHAR));
+
+    PropVariantClear(&var);
+
+    hr = IAudioClient_GetMixFormat(client, &wfx);
+    if(FAILED(hr)){
+        WARN("GetMixFormat failed: %08x\n", hr);
+        goto done;
+    }
+
+    lstrcpyW(pDeviceDetails->DeviceID, This->devids[index]);
+
+    if(index == 0)
+        pDeviceDetails->Role = GlobalDefaultDevice;
+    else
+        pDeviceDetails->Role = NotDefaultDevice;
+
+    if(sizeof(WAVEFORMATEX) + wfx->cbSize > sizeof(pDeviceDetails->OutputFormat)){
+        FIXME("AudioClient format is too large to fit into WAVEFORMATEXTENSIBLE!\n");
+        CoTaskMemFree(wfx);
+        hr = E_FAIL;
+        goto done;
+    }
+    memcpy(&pDeviceDetails->OutputFormat, wfx, sizeof(WAVEFORMATEX) + wfx->cbSize);
+
+    CoTaskMemFree(wfx);
+
+done:
+    IPropertyStore_Release(ps);
+    IAudioClient_Release(client);
+    IMMDevice_Release(dev);
+
+    return hr;
 }
 
 static HRESULT WINAPI XA27_Initialize(IXAudio27 *iface, UINT32 flags,
@@ -1429,12 +1524,16 @@ static HRESULT WINAPI XA27_CreateMasteringVoice(IXAudio27 *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
     IXAudio2Impl *This = impl_from_IXAudio27(iface);
+
     TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p)\n", This, ppMasteringVoice,
             inputChannels, inputSampleRate, flags, deviceIndex,
             pEffectChain);
-    /* TODO: Convert DeviceIndex to DeviceId */
-    return IXAudio2Impl_CreateMasteringVoice(&This->IXAudio2_iface,
-            ppMasteringVoice, inputChannels, inputSampleRate, flags, 0,
+
+    if(deviceIndex >= This->ndevs)
+        return E_INVALIDARG;
+
+    return IXAudio2Impl_CreateMasteringVoice(&This->IXAudio2_iface, ppMasteringVoice,
+            inputChannels, inputSampleRate, flags, This->devids[deviceIndex],
             pEffectChain, AudioCategory_GameEffects);
 }
 
@@ -1516,6 +1615,79 @@ static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
     return 1;
 }
 
+static HRESULT initialize_mmdevices(IXAudio2Impl *This)
+{
+    IMMDeviceCollection *devcoll;
+    UINT devcount;
+    HRESULT hr;
+
+    if(!This->devenum){
+        hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
+                CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&This->devenum);
+        if(FAILED(hr))
+            return hr;
+    }
+
+    hr = IMMDeviceEnumerator_EnumAudioEndpoints(This->devenum, eRender,
+            DEVICE_STATE_ACTIVE, &devcoll);
+    if(FAILED(hr)){
+        return hr;
+    }
+
+    hr = IMMDeviceCollection_GetCount(devcoll, &devcount);
+    if(FAILED(hr)){
+        IMMDeviceCollection_Release(devcoll);
+        return hr;
+    }
+
+    if(devcount > 0){
+        UINT i, count = 1;
+        IMMDevice *dev, *def_dev;
+
+        /* make sure that device 0 is the default device */
+        IMMDeviceEnumerator_GetDefaultAudioEndpoint(This->devenum, eRender, eConsole, &def_dev);
+
+        This->devids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * devcount);
+
+        for(i = 0; i < devcount; ++i){
+            hr = IMMDeviceCollection_Item(devcoll, i, &dev);
+            if(SUCCEEDED(hr)){
+                UINT idx;
+
+                if(dev == def_dev)
+                    idx = 0;
+                else{
+                    idx = count;
+                    ++count;
+                }
+
+                hr = IMMDevice_GetId(dev, &This->devids[idx]);
+                if(FAILED(hr)){
+                    WARN("GetId failed: %08x\n", hr);
+                    HeapFree(GetProcessHeap(), 0, This->devids);
+                    This->devids = NULL;
+                    IMMDevice_Release(dev);
+                    return hr;
+                }
+
+                IMMDevice_Release(dev);
+            }else{
+                WARN("Item failed: %08x\n", hr);
+                HeapFree(GetProcessHeap(), 0, This->devids);
+                This->devids = NULL;
+                IMMDeviceCollection_Release(devcoll);
+                return hr;
+            }
+        }
+    }
+
+    IMMDeviceCollection_Release(devcoll);
+
+    This->ndevs = devcount;
+
+    return S_OK;
+}
+
 static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
                                                REFIID riid, void **ppobj)
 {
@@ -1549,8 +1721,17 @@ static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *p
     object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock");
 
     hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj);
-    if(FAILED(hr))
+    if(FAILED(hr)){
         HeapFree(GetProcessHeap(), 0, object);
+        return hr;
+    }
+
+    hr = initialize_mmdevices(object);
+    if(FAILED(hr)){
+        IUnknown_Release((IUnknown*)*ppobj);
+        return hr;
+    }
+
     return hr;
 }
 
-- 
2.5.0





More information about the wine-patches mailing list