Commit cc22fdaf authored by Andrew Eikum's avatar Andrew Eikum Committed by Alexandre Julliard

xaudio2: Implement IXAudio2::GetDeviceDetails.

parent 8027a526
...@@ -17824,6 +17824,7 @@ wine_fn_config_dll xapofx1_3 enable_xapofx1_3 ...@@ -17824,6 +17824,7 @@ wine_fn_config_dll xapofx1_3 enable_xapofx1_3
wine_fn_config_dll xapofx1_4 enable_xapofx1_4 wine_fn_config_dll xapofx1_4 enable_xapofx1_4
wine_fn_config_dll xapofx1_5 enable_xapofx1_5 wine_fn_config_dll xapofx1_5 enable_xapofx1_5
wine_fn_config_dll xaudio2_7 enable_xaudio2_7 clean wine_fn_config_dll xaudio2_7 enable_xaudio2_7 clean
wine_fn_config_test dlls/xaudio2_7/tests xaudio2_7_test
wine_fn_config_dll xaudio2_8 enable_xaudio2_8 wine_fn_config_dll xaudio2_8 enable_xaudio2_8
wine_fn_config_dll xinput1_1 enable_xinput1_1 wine_fn_config_dll xinput1_1 enable_xinput1_1
wine_fn_config_dll xinput1_2 enable_xinput1_2 wine_fn_config_dll xinput1_2 enable_xinput1_2
......
...@@ -3425,6 +3425,7 @@ WINE_CONFIG_DLL(xapofx1_3) ...@@ -3425,6 +3425,7 @@ WINE_CONFIG_DLL(xapofx1_3)
WINE_CONFIG_DLL(xapofx1_4) WINE_CONFIG_DLL(xapofx1_4)
WINE_CONFIG_DLL(xapofx1_5) WINE_CONFIG_DLL(xapofx1_5)
WINE_CONFIG_DLL(xaudio2_7,,[clean]) WINE_CONFIG_DLL(xaudio2_7,,[clean])
WINE_CONFIG_TEST(dlls/xaudio2_7/tests)
WINE_CONFIG_DLL(xaudio2_8) WINE_CONFIG_DLL(xaudio2_8)
WINE_CONFIG_DLL(xinput1_1) WINE_CONFIG_DLL(xinput1_1)
WINE_CONFIG_DLL(xinput1_2) WINE_CONFIG_DLL(xinput1_2)
......
TESTDLL = xaudio2_7.dll
IMPORTS = ole32
C_SRCS = \
xaudio2.c
/*
* 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();
}
/* /*
* Copyright (c) 2015 Mark Harmstone * Copyright (c) 2015 Mark Harmstone
* Copyright (c) 2015 Andrew Eikum for CodeWeavers
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -18,6 +19,8 @@ ...@@ -18,6 +19,8 @@
#include <stdarg.h> #include <stdarg.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#define COBJMACROS #define COBJMACROS
#include "windef.h" #include "windef.h"
...@@ -34,6 +37,9 @@ ...@@ -34,6 +37,9 @@
#include "mmsystem.h" #include "mmsystem.h"
#include "xaudio2.h" #include "xaudio2.h"
#include "devpkey.h"
#include "mmdeviceapi.h"
#include "audioclient.h"
WINE_DEFAULT_DEBUG_CHANNEL(xaudio2); WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
...@@ -155,6 +161,11 @@ typedef struct { ...@@ -155,6 +161,11 @@ typedef struct {
struct list source_voices; struct list source_voices;
struct list submix_voices; struct list submix_voices;
IMMDeviceEnumerator *devenum;
WCHAR **devids;
UINT32 ndevs;
} IXAudio2Impl; } IXAudio2Impl;
static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface) static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
...@@ -1098,6 +1109,7 @@ static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface) ...@@ -1098,6 +1109,7 @@ static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
TRACE("(%p)->(): Refcount now %u\n", This, ref); TRACE("(%p)->(): Refcount now %u\n", This, ref);
if (!ref) { if (!ref) {
int i;
XA2SourceImpl *src, *src2; XA2SourceImpl *src, *src2;
XA2SubmixImpl *sub, *sub2; XA2SubmixImpl *sub, *sub2;
...@@ -1113,6 +1125,12 @@ static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface) ...@@ -1113,6 +1125,12 @@ static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
HeapFree(GetProcessHeap(), 0, sub); 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); DeleteCriticalSection(&This->lock);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
...@@ -1365,16 +1383,93 @@ static ULONG WINAPI XA27_Release(IXAudio27 *iface) ...@@ -1365,16 +1383,93 @@ static ULONG WINAPI XA27_Release(IXAudio27 *iface)
static HRESULT WINAPI XA27_GetDeviceCount(IXAudio27 *iface, UINT32 *pCount) static HRESULT WINAPI XA27_GetDeviceCount(IXAudio27 *iface, UINT32 *pCount)
{ {
IXAudio2Impl *This = impl_from_IXAudio27(iface); 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, static HRESULT WINAPI XA27_GetDeviceDetails(IXAudio27 *iface, UINT32 index,
XAUDIO2_DEVICE_DETAILS *pDeviceDetails) XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
{ {
IXAudio2Impl *This = impl_from_IXAudio27(iface); IXAudio2Impl *This = impl_from_IXAudio27(iface);
TRACE("(%p)->(%u, %p)\n", This, index, pDeviceDetails); HRESULT hr;
return E_NOTIMPL; 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, static HRESULT WINAPI XA27_Initialize(IXAudio27 *iface, UINT32 flags,
...@@ -1429,12 +1524,16 @@ static HRESULT WINAPI XA27_CreateMasteringVoice(IXAudio27 *iface, ...@@ -1429,12 +1524,16 @@ static HRESULT WINAPI XA27_CreateMasteringVoice(IXAudio27 *iface,
const XAUDIO2_EFFECT_CHAIN *pEffectChain) const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{ {
IXAudio2Impl *This = impl_from_IXAudio27(iface); IXAudio2Impl *This = impl_from_IXAudio27(iface);
TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p)\n", This, ppMasteringVoice, TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p)\n", This, ppMasteringVoice,
inputChannels, inputSampleRate, flags, deviceIndex, inputChannels, inputSampleRate, flags, deviceIndex,
pEffectChain); pEffectChain);
/* TODO: Convert DeviceIndex to DeviceId */
return IXAudio2Impl_CreateMasteringVoice(&This->IXAudio2_iface, if(deviceIndex >= This->ndevs)
ppMasteringVoice, inputChannels, inputSampleRate, flags, 0, return E_INVALIDARG;
return IXAudio2Impl_CreateMasteringVoice(&This->IXAudio2_iface, ppMasteringVoice,
inputChannels, inputSampleRate, flags, This->devids[deviceIndex],
pEffectChain, AudioCategory_GameEffects); pEffectChain, AudioCategory_GameEffects);
} }
...@@ -1516,6 +1615,79 @@ static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface) ...@@ -1516,6 +1615,79 @@ static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
return 1; 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, static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
REFIID riid, void **ppobj) REFIID riid, void **ppobj)
{ {
...@@ -1549,8 +1721,17 @@ static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *p ...@@ -1549,8 +1721,17 @@ static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *p
object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock"); object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock");
hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj); hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj);
if(FAILED(hr)) if(FAILED(hr)){
HeapFree(GetProcessHeap(), 0, object); HeapFree(GetProcessHeap(), 0, object);
return hr;
}
hr = initialize_mmdevices(object);
if(FAILED(hr)){
IUnknown_Release((IUnknown*)*ppobj);
return hr;
}
return hr; return hr;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment