[PATCH 2/3 (try2)] xaudio2: Implement IXAudio2::GetDeviceDetails
Andrew Eikum
aeikum at codeweavers.com
Fri Aug 21 11:22:13 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 1c56152..39a5a79 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