Sweden-Number/dlls/xaudio2_7/xaudio_dll.c

2105 lines
68 KiB
C

/*
* Copyright (c) 2015 Mark Harmstone
* Copyright (c) 2015 Andrew Eikum for CodeWeavers
* Copyright (c) 2018 Ethan Lee 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 "config.h"
#include <stdarg.h>
#define NONAMELESSUNION
#define COBJMACROS
#include "initguid.h"
#include "xaudio_private.h"
#include "xaudio2fx.h"
#if XAUDIO2_VER >= 8
#include "xapofx.h"
#endif
#include "ole2.h"
#include "rpcproxy.h"
#include "wine/asm.h"
#include "wine/debug.h"
#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
#if XAUDIO2_VER != 0 && defined(__i386__)
/* EVE Online uses an OnVoiceProcessingPassStart callback which corrupts %esi;
* League of Legends uses a callback which corrupts %ebx. */
#define IXAudio2VoiceCallback_OnVoiceProcessingPassStart(a, b) call_on_voice_processing_pass_start(a, b)
extern void call_on_voice_processing_pass_start(IXAudio2VoiceCallback *This, UINT32 BytesRequired);
__ASM_GLOBAL_FUNC( call_on_voice_processing_pass_start,
"pushl %ebp\n\t"
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
__ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
"movl %esp,%ebp\n\t"
__ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
"pushl %esi\n\t"
__ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
"pushl %edi\n\t"
__ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
"pushl %ebx\n\t"
__ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
"subl $4,%esp\n\t"
"pushl 12(%ebp)\n\t" /* BytesRequired */
"pushl 8(%ebp)\n\t" /* This */
"movl 8(%ebp),%eax\n\t"
"movl 0(%eax),%eax\n\t"
"call *0(%eax)\n\t" /* This->lpVtbl->OnVoiceProcessingPassStart */
"leal -12(%ebp),%esp\n\t"
"popl %ebx\n\t"
__ASM_CFI(".cfi_same_value %ebx\n\t")
"popl %edi\n\t"
__ASM_CFI(".cfi_same_value %edi\n\t")
"popl %esi\n\t"
__ASM_CFI(".cfi_same_value %esi\n\t")
"popl %ebp\n\t"
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
__ASM_CFI(".cfi_same_value %ebp\n\t")
"ret" )
#endif
static HINSTANCE instance;
static XA2VoiceImpl *impl_from_IXAudio2Voice(IXAudio2Voice *iface);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
{
TRACE("(%p, %d, %p)\n", hinstDLL, reason, pReserved);
switch (reason)
{
case DLL_PROCESS_ATTACH:
instance = hinstDLL;
DisableThreadLibraryCalls( hinstDLL );
break;
}
return TRUE;
}
HRESULT WINAPI DllCanUnloadNow(void)
{
return S_FALSE;
}
HRESULT WINAPI DllRegisterServer(void)
{
TRACE("\n");
return __wine_register_resources(instance);
}
HRESULT WINAPI DllUnregisterServer(void)
{
TRACE("\n");
return __wine_unregister_resources(instance);
}
/* Effect Wrapping */
static inline XA2XAPOImpl *impl_from_FAPO(FAPO *iface)
{
return CONTAINING_RECORD(iface, XA2XAPOImpl, FAPO_vtbl);
}
static int32_t FAPOCALL XAPO_AddRef(void *iface)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
return InterlockedIncrement(&This->ref);
}
static int32_t FAPOCALL XAPO_Release(void *iface)
{
int32_t r;
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
r = InterlockedDecrement(&This->ref);
if(r == 0){
IXAPO_Release(This->xapo);
if(This->xapo_params)
IXAPOParameters_Release(This->xapo_params);
heap_free(This);
}
return r;
}
static uint32_t FAPOCALL XAPO_GetRegistrationProperties(void *iface,
FAPORegistrationProperties **ppRegistrationProperties)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
XAPO_REGISTRATION_PROPERTIES *xprops;
HRESULT hr;
TRACE("%p\n", This);
hr = IXAPO_GetRegistrationProperties(This->xapo, &xprops);
if(FAILED(hr))
return hr;
/* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
*ppRegistrationProperties = (FAPORegistrationProperties*) xprops;
return 0;
}
static uint32_t FAPOCALL XAPO_IsInputFormatSupported(void *iface,
const FAudioWaveFormatEx *pOutputFormat, const FAudioWaveFormatEx *pRequestedInputFormat,
FAudioWaveFormatEx **ppSupportedInputFormat)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
return IXAPO_IsInputFormatSupported(This->xapo, (const WAVEFORMATEX*)pOutputFormat,
(const WAVEFORMATEX*)pRequestedInputFormat, (WAVEFORMATEX**)ppSupportedInputFormat);
}
static uint32_t FAPOCALL XAPO_IsOutputFormatSupported(void *iface,
const FAudioWaveFormatEx *pInputFormat, const FAudioWaveFormatEx *pRequestedOutputFormat,
FAudioWaveFormatEx **ppSupportedOutputFormat)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
return IXAPO_IsOutputFormatSupported(This->xapo, (const WAVEFORMATEX *)pInputFormat,
(const WAVEFORMATEX *)pRequestedOutputFormat, (WAVEFORMATEX**)ppSupportedOutputFormat);
}
static uint32_t FAPOCALL XAPO_Initialize(void *iface, const void *pData,
uint32_t DataByteSize)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
return IXAPO_Initialize(This->xapo, pData, DataByteSize);
}
static void FAPOCALL XAPO_Reset(void *iface)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
IXAPO_Reset(This->xapo);
}
static uint32_t FAPOCALL XAPO_LockForProcess(void *iface,
uint32_t InputLockedParameterCount,
const FAPOLockForProcessBufferParameters *pInputLockedParameters,
uint32_t OutputLockedParameterCount,
const FAPOLockForProcessBufferParameters *pOutputLockedParameters)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
return IXAPO_LockForProcess(This->xapo,
InputLockedParameterCount,
(const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *)pInputLockedParameters,
OutputLockedParameterCount,
(const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *)pOutputLockedParameters);
}
static void FAPOCALL XAPO_UnlockForProcess(void *iface)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
IXAPO_UnlockForProcess(This->xapo);
}
static void FAPOCALL XAPO_Process(void *iface,
uint32_t InputProcessParameterCount,
const FAPOProcessBufferParameters* pInputProcessParameters,
uint32_t OutputProcessParameterCount,
FAPOProcessBufferParameters* pOutputProcessParameters,
int32_t IsEnabled)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
IXAPO_Process(This->xapo, InputProcessParameterCount,
(const XAPO_PROCESS_BUFFER_PARAMETERS *)pInputProcessParameters,
OutputProcessParameterCount,
(XAPO_PROCESS_BUFFER_PARAMETERS *)pOutputProcessParameters,
IsEnabled);
}
static uint32_t FAPOCALL XAPO_CalcInputFrames(void *iface,
uint32_t OutputFrameCount)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
return IXAPO_CalcInputFrames(This->xapo, OutputFrameCount);
}
static uint32_t FAPOCALL XAPO_CalcOutputFrames(void *iface,
uint32_t InputFrameCount)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
return IXAPO_CalcOutputFrames(This->xapo, InputFrameCount);
}
static void FAPOCALL XAPO_SetParameters(void *iface,
const void *pParameters, uint32_t ParametersByteSize)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
if(This->xapo_params)
IXAPOParameters_SetParameters(This->xapo_params, pParameters, ParametersByteSize);
}
static void FAPOCALL XAPO_GetParameters(void *iface,
void *pParameters, uint32_t ParametersByteSize)
{
XA2XAPOImpl *This = impl_from_FAPO(iface);
TRACE("%p\n", This);
if(This->xapo_params)
IXAPOParameters_GetParameters(This->xapo_params, pParameters, ParametersByteSize);
else
memset(pParameters, 0, ParametersByteSize);
}
static const FAPO FAPO_Vtbl = {
XAPO_AddRef,
XAPO_Release,
XAPO_GetRegistrationProperties,
XAPO_IsInputFormatSupported,
XAPO_IsOutputFormatSupported,
XAPO_Initialize,
XAPO_Reset,
XAPO_LockForProcess,
XAPO_UnlockForProcess,
XAPO_Process,
XAPO_CalcInputFrames,
XAPO_CalcOutputFrames,
XAPO_SetParameters,
XAPO_GetParameters,
};
static XA2XAPOImpl *wrap_xapo(IUnknown *unk)
{
XA2XAPOImpl *ret;
IXAPO *xapo;
IXAPOParameters *xapo_params;
HRESULT hr;
#if XAUDIO2_VER <= 7
hr = IUnknown_QueryInterface(unk, &IID_IXAPO27, (void**)&xapo);
#else
hr = IUnknown_QueryInterface(unk, &IID_IXAPO, (void**)&xapo);
#endif
if(FAILED(hr)){
WARN("XAPO doesn't support IXAPO? %p\n", unk);
return NULL;
}
#if XAUDIO2_VER <= 7
hr = IUnknown_QueryInterface(unk, &IID_IXAPO27Parameters, (void**)&xapo_params);
#else
hr = IUnknown_QueryInterface(unk, &IID_IXAPOParameters, (void**)&xapo_params);
#endif
if(FAILED(hr)){
TRACE("XAPO doesn't support IXAPOParameters %p\n", unk);
xapo_params = NULL;
}
ret = heap_alloc(sizeof(*ret));
ret->xapo = xapo;
ret->xapo_params = xapo_params;
ret->FAPO_vtbl = FAPO_Vtbl;
ret->ref = 1;
TRACE("wrapped IXAPO %p with %p\n", xapo, ret);
return ret;
}
FAudioEffectChain *wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
FAudioEffectChain *ret;
int i;
if(!pEffectChain)
return NULL;
ret = heap_alloc(sizeof(*ret) + sizeof(FAudioEffectDescriptor) * pEffectChain->EffectCount);
ret->EffectCount = pEffectChain->EffectCount;
ret->pEffectDescriptors = (void*)(ret + 1);
for(i = 0; i < ret->EffectCount; ++i){
ret->pEffectDescriptors[i].pEffect = &wrap_xapo(pEffectChain->pEffectDescriptors[i].pEffect)->FAPO_vtbl;
ret->pEffectDescriptors[i].InitialState = pEffectChain->pEffectDescriptors[i].InitialState;
ret->pEffectDescriptors[i].OutputChannels = pEffectChain->pEffectDescriptors[i].OutputChannels;
}
return ret;
}
static void free_effect_chain(FAudioEffectChain *chain)
{
int i;
if(!chain)
return;
for(i = 0; i < chain->EffectCount; ++i)
XAPO_Release(chain->pEffectDescriptors[i].pEffect);
heap_free(chain);
}
/* Send Wrapping */
static FAudioVoiceSends *wrap_voice_sends(const XAUDIO2_VOICE_SENDS *sends)
{
FAudioVoiceSends *ret;
int i;
if(!sends)
return NULL;
ret = heap_alloc(sizeof(*ret) + sends->SendCount * sizeof(FAudioSendDescriptor));
ret->SendCount = sends->SendCount;
ret->pSends = (FAudioSendDescriptor*)(ret + 1);
for(i = 0; i < sends->SendCount; ++i){
XA2VoiceImpl *voice = impl_from_IXAudio2Voice(sends->pSends[i].pOutputVoice);
ret->pSends[i].pOutputVoice = voice->faudio_voice;
ret->pSends[i].Flags = sends->pSends[i].Flags;
}
return ret;
}
static void free_voice_sends(FAudioVoiceSends *sends)
{
if(!sends)
return;
heap_free(sends);
}
/* Voice Callbacks */
static inline XA2VoiceImpl *impl_from_FAudioVoiceCallback(FAudioVoiceCallback *iface)
{
return CONTAINING_RECORD(iface, XA2VoiceImpl, FAudioVoiceCallback_vtbl);
}
static void FAUDIOCALL XA2VCB_OnVoiceProcessingPassStart(FAudioVoiceCallback *iface,
UINT32 BytesRequired)
{
XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
TRACE("%p\n", This);
if(This->cb)
#if XAUDIO2_VER == 0
IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback*)This->cb);
#else
IXAudio2VoiceCallback_OnVoiceProcessingPassStart(This->cb, BytesRequired);
#endif
}
static void FAUDIOCALL XA2VCB_OnVoiceProcessingPassEnd(FAudioVoiceCallback *iface)
{
XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
TRACE("%p\n", This);
if(This->cb)
IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(This->cb);
}
static void FAUDIOCALL XA2VCB_OnStreamEnd(FAudioVoiceCallback *iface)
{
XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
TRACE("%p\n", This);
if(This->cb)
IXAudio2VoiceCallback_OnStreamEnd(This->cb);
}
static void FAUDIOCALL XA2VCB_OnBufferStart(FAudioVoiceCallback *iface,
void *pBufferContext)
{
XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
TRACE("%p\n", This);
if(This->cb)
IXAudio2VoiceCallback_OnBufferStart(This->cb, pBufferContext);
}
static void FAUDIOCALL XA2VCB_OnBufferEnd(FAudioVoiceCallback *iface,
void *pBufferContext)
{
XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
TRACE("%p\n", This);
if(This->cb)
IXAudio2VoiceCallback_OnBufferEnd(This->cb, pBufferContext);
}
static void FAUDIOCALL XA2VCB_OnLoopEnd(FAudioVoiceCallback *iface,
void *pBufferContext)
{
XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
TRACE("%p\n", This);
if(This->cb)
IXAudio2VoiceCallback_OnLoopEnd(This->cb, pBufferContext);
}
static void FAUDIOCALL XA2VCB_OnVoiceError(FAudioVoiceCallback *iface,
void *pBufferContext, unsigned int Error)
{
XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
TRACE("%p\n", This);
if(This->cb)
IXAudio2VoiceCallback_OnVoiceError(This->cb, pBufferContext, (HRESULT)Error);
}
static const FAudioVoiceCallback FAudioVoiceCallback_Vtbl = {
XA2VCB_OnBufferEnd,
XA2VCB_OnBufferStart,
XA2VCB_OnLoopEnd,
XA2VCB_OnStreamEnd,
XA2VCB_OnVoiceError,
XA2VCB_OnVoiceProcessingPassEnd,
XA2VCB_OnVoiceProcessingPassStart
};
/* Engine Callbacks */
static inline IXAudio2Impl *impl_from_FAudioEngineCallback(FAudioEngineCallback *iface)
{
return CONTAINING_RECORD(iface, IXAudio2Impl, FAudioEngineCallback_vtbl);
}
static void FAUDIOCALL XA2ECB_OnProcessingPassStart(FAudioEngineCallback *iface)
{
IXAudio2Impl *This = impl_from_FAudioEngineCallback(iface);
int i;
TRACE("%p\n", This);
for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
IXAudio2EngineCallback_OnProcessingPassStart(This->cbs[i]);
}
static void FAUDIOCALL XA2ECB_OnProcessingPassEnd(FAudioEngineCallback *iface)
{
IXAudio2Impl *This = impl_from_FAudioEngineCallback(iface);
int i;
TRACE("%p\n", This);
for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
IXAudio2EngineCallback_OnProcessingPassEnd(This->cbs[i]);
}
static void FAUDIOCALL XA2ECB_OnCriticalError(FAudioEngineCallback *iface,
uint32_t error)
{
IXAudio2Impl *This = impl_from_FAudioEngineCallback(iface);
int i;
TRACE("%p\n", This);
for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
IXAudio2EngineCallback_OnCriticalError(This->cbs[i], error);
}
static const FAudioEngineCallback FAudioEngineCallback_Vtbl = {
XA2ECB_OnCriticalError,
XA2ECB_OnProcessingPassEnd,
XA2ECB_OnProcessingPassStart
};
/* Common Voice Functions */
static inline void destroy_voice(XA2VoiceImpl *This)
{
FAudioVoice_DestroyVoice(This->faudio_voice);
free_effect_chain(This->effect_chain);
This->effect_chain = NULL;
This->in_use = FALSE;
}
/* Source Voices */
static inline XA2VoiceImpl *impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice *iface)
{
return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio2SourceVoice_iface);
}
static void WINAPI XA2SRC_GetVoiceDetails(IXAudio2SourceVoice *iface,
XAUDIO2_VOICE_DETAILS *pVoiceDetails)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %p\n", This, pVoiceDetails);
FAudioVoice_GetVoiceDetails(This->faudio_voice, (FAudioVoiceDetails *)pVoiceDetails);
}
static HRESULT WINAPI XA2SRC_SetOutputVoices(IXAudio2SourceVoice *iface,
const XAUDIO2_VOICE_SENDS *pSendList)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
FAudioVoiceSends *faudio_sends;
HRESULT hr;
TRACE("%p, %p\n", This, pSendList);
faudio_sends = wrap_voice_sends(pSendList);
hr = FAudioVoice_SetOutputVoices(This->faudio_voice, faudio_sends);
free_voice_sends(faudio_sends);
return hr;
}
static HRESULT WINAPI XA2SRC_SetEffectChain(IXAudio2SourceVoice *iface,
const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
HRESULT hr;
TRACE("%p, %p\n", This, pEffectChain);
free_effect_chain(This->effect_chain);
This->effect_chain = wrap_effect_chain(pEffectChain);
hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
return hr;
}
static HRESULT WINAPI XA2SRC_EnableEffect(IXAudio2SourceVoice *iface, UINT32 EffectIndex,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
return FAudioVoice_EnableEffect(This->faudio_voice, EffectIndex, OperationSet);
}
static HRESULT WINAPI XA2SRC_DisableEffect(IXAudio2SourceVoice *iface, UINT32 EffectIndex,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
return FAudioVoice_DisableEffect(This->faudio_voice, EffectIndex, OperationSet);
}
static void WINAPI XA2SRC_GetEffectState(IXAudio2SourceVoice *iface, UINT32 EffectIndex,
BOOL *pEnabled)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
FAudioVoice_GetEffectState(This->faudio_voice, EffectIndex, (int32_t*)pEnabled);
}
static HRESULT WINAPI XA2SRC_SetEffectParameters(IXAudio2SourceVoice *iface,
UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
ParametersByteSize, OperationSet);
return FAudioVoice_SetEffectParameters(This->faudio_voice, EffectIndex,
pParameters, ParametersByteSize, OperationSet);
}
static HRESULT WINAPI XA2SRC_GetEffectParameters(IXAudio2SourceVoice *iface,
UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
ParametersByteSize);
return FAudioVoice_GetEffectParameters(This->faudio_voice, EffectIndex,
pParameters, ParametersByteSize);
}
static HRESULT WINAPI XA2SRC_SetFilterParameters(IXAudio2SourceVoice *iface,
const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
return FAudioVoice_SetFilterParameters(This->faudio_voice,
(const FAudioFilterParameters *)pParameters, OperationSet);
}
static void WINAPI XA2SRC_GetFilterParameters(IXAudio2SourceVoice *iface,
XAUDIO2_FILTER_PARAMETERS *pParameters)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %p\n", This, pParameters);
FAudioVoice_GetFilterParameters(This->faudio_voice, (FAudioFilterParameters *)pParameters);
}
static HRESULT WINAPI XA2SRC_SetOutputFilterParameters(IXAudio2SourceVoice *iface,
IXAudio2Voice *pDestinationVoice,
const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
return FAudioVoice_SetOutputFilterParameters(This->faudio_voice,
dst ? dst->faudio_voice : NULL, (const FAudioFilterParameters *)pParameters, OperationSet);
}
static void WINAPI XA2SRC_GetOutputFilterParameters(IXAudio2SourceVoice *iface,
IXAudio2Voice *pDestinationVoice,
XAUDIO2_FILTER_PARAMETERS *pParameters)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
FAudioVoice_GetOutputFilterParameters(This->faudio_voice,
dst ? dst->faudio_voice : NULL, (FAudioFilterParameters *)pParameters);
}
static HRESULT WINAPI XA2SRC_SetVolume(IXAudio2SourceVoice *iface, float Volume,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
return FAudioVoice_SetVolume(This->faudio_voice, Volume, OperationSet);
}
static void WINAPI XA2SRC_GetVolume(IXAudio2SourceVoice *iface, float *pVolume)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %p\n", This, pVolume);
return FAudioVoice_GetVolume(This->faudio_voice, pVolume);
}
static HRESULT WINAPI XA2SRC_SetChannelVolumes(IXAudio2SourceVoice *iface, UINT32 Channels,
const float *pVolumes, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
return FAudioVoice_SetChannelVolumes(This->faudio_voice, Channels,
pVolumes, OperationSet);
}
static void WINAPI XA2SRC_GetChannelVolumes(IXAudio2SourceVoice *iface, UINT32 Channels,
float *pVolumes)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %u, %p\n", This, Channels, pVolumes);
return FAudioVoice_GetChannelVolumes(This->faudio_voice, Channels,
pVolumes);
}
static HRESULT WINAPI XA2SRC_SetOutputMatrix(IXAudio2SourceVoice *iface,
IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
UINT32 DestinationChannels, const float *pLevelMatrix,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
return FAudioVoice_SetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
}
static void WINAPI XA2SRC_GetOutputMatrix(IXAudio2SourceVoice *iface,
IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
UINT32 DestinationChannels, float *pLevelMatrix)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
SourceChannels, DestinationChannels, pLevelMatrix);
FAudioVoice_GetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
SourceChannels, DestinationChannels, pLevelMatrix);
}
static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p\n", This);
EnterCriticalSection(&This->lock);
destroy_voice(This);
LeaveCriticalSection(&This->lock);
}
static HRESULT WINAPI XA2SRC_Start(IXAudio2SourceVoice *iface, UINT32 Flags,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
return FAudioSourceVoice_Start(This->faudio_voice, Flags, OperationSet);
}
static HRESULT WINAPI XA2SRC_Stop(IXAudio2SourceVoice *iface, UINT32 Flags,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
return FAudioSourceVoice_Stop(This->faudio_voice, Flags, OperationSet);
}
static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface,
const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %p, %p\n", This, pBuffer, pBufferWMA);
return FAudioSourceVoice_SubmitSourceBuffer(This->faudio_voice, (FAudioBuffer*)pBuffer, (FAudioBufferWMA*)pBufferWMA);
}
static HRESULT WINAPI XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice *iface)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p\n", This);
return FAudioSourceVoice_FlushSourceBuffers(This->faudio_voice);
}
static HRESULT WINAPI XA2SRC_Discontinuity(IXAudio2SourceVoice *iface)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p\n", This);
return FAudioSourceVoice_Discontinuity(This->faudio_voice);
}
static HRESULT WINAPI XA2SRC_ExitLoop(IXAudio2SourceVoice *iface, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, 0x%x\n", This, OperationSet);
return FAudioSourceVoice_ExitLoop(This->faudio_voice, OperationSet);
}
static void WINAPI XA2SRC_GetState(IXAudio2SourceVoice *iface,
XAUDIO2_VOICE_STATE *pVoiceState, UINT32 Flags)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %p, 0x%x\n", This, pVoiceState, Flags);
return FAudioSourceVoice_GetState(This->faudio_voice, (FAudioVoiceState*)pVoiceState, Flags);
}
static HRESULT WINAPI XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice *iface,
float Ratio, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %f, 0x%x\n", This, Ratio, OperationSet);
return FAudioSourceVoice_SetFrequencyRatio(This->faudio_voice, Ratio, OperationSet);
}
static void WINAPI XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice *iface, float *pRatio)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %p\n", This, pRatio);
return FAudioSourceVoice_GetFrequencyRatio(This->faudio_voice, pRatio);
}
static HRESULT WINAPI XA2SRC_SetSourceSampleRate(
IXAudio2SourceVoice *iface,
UINT32 NewSourceSampleRate)
{
XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
TRACE("%p, %u\n", This, NewSourceSampleRate);
return FAudioSourceVoice_SetSourceSampleRate(This->faudio_voice, NewSourceSampleRate);
}
static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl = {
XA2SRC_GetVoiceDetails,
XA2SRC_SetOutputVoices,
XA2SRC_SetEffectChain,
XA2SRC_EnableEffect,
XA2SRC_DisableEffect,
XA2SRC_GetEffectState,
XA2SRC_SetEffectParameters,
XA2SRC_GetEffectParameters,
XA2SRC_SetFilterParameters,
XA2SRC_GetFilterParameters,
XA2SRC_SetOutputFilterParameters,
XA2SRC_GetOutputFilterParameters,
XA2SRC_SetVolume,
XA2SRC_GetVolume,
XA2SRC_SetChannelVolumes,
XA2SRC_GetChannelVolumes,
XA2SRC_SetOutputMatrix,
XA2SRC_GetOutputMatrix,
XA2SRC_DestroyVoice,
XA2SRC_Start,
XA2SRC_Stop,
XA2SRC_SubmitSourceBuffer,
XA2SRC_FlushSourceBuffers,
XA2SRC_Discontinuity,
XA2SRC_ExitLoop,
XA2SRC_GetState,
XA2SRC_SetFrequencyRatio,
XA2SRC_GetFrequencyRatio,
XA2SRC_SetSourceSampleRate
};
/* Submix Voices */
static inline XA2VoiceImpl *impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice *iface)
{
return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio2SubmixVoice_iface);
}
static void WINAPI XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice *iface,
XAUDIO2_VOICE_DETAILS *pVoiceDetails)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %p\n", This, pVoiceDetails);
FAudioVoice_GetVoiceDetails(This->faudio_voice, (FAudioVoiceDetails *)pVoiceDetails);
}
static HRESULT WINAPI XA2SUB_SetOutputVoices(IXAudio2SubmixVoice *iface,
const XAUDIO2_VOICE_SENDS *pSendList)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
FAudioVoiceSends *faudio_sends;
HRESULT hr;
TRACE("%p, %p\n", This, pSendList);
faudio_sends = wrap_voice_sends(pSendList);
hr = FAudioVoice_SetOutputVoices(This->faudio_voice, faudio_sends);
free_voice_sends(faudio_sends);
return hr;
}
static HRESULT WINAPI XA2SUB_SetEffectChain(IXAudio2SubmixVoice *iface,
const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
HRESULT hr;
TRACE("%p, %p\n", This, pEffectChain);
free_effect_chain(This->effect_chain);
This->effect_chain = wrap_effect_chain(pEffectChain);
hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
return hr;
}
static HRESULT WINAPI XA2SUB_EnableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
return FAudioVoice_EnableEffect(This->faudio_voice, EffectIndex, OperationSet);
}
static HRESULT WINAPI XA2SUB_DisableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
return FAudioVoice_DisableEffect(This->faudio_voice, EffectIndex, OperationSet);
}
static void WINAPI XA2SUB_GetEffectState(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
BOOL *pEnabled)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
FAudioVoice_GetEffectState(This->faudio_voice, EffectIndex, (int32_t*)pEnabled);
}
static HRESULT WINAPI XA2SUB_SetEffectParameters(IXAudio2SubmixVoice *iface,
UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
ParametersByteSize, OperationSet);
return FAudioVoice_SetEffectParameters(This->faudio_voice, EffectIndex,
pParameters, ParametersByteSize, OperationSet);
}
static HRESULT WINAPI XA2SUB_GetEffectParameters(IXAudio2SubmixVoice *iface,
UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
ParametersByteSize);
return FAudioVoice_GetEffectParameters(This->faudio_voice, EffectIndex,
pParameters, ParametersByteSize);
}
static HRESULT WINAPI XA2SUB_SetFilterParameters(IXAudio2SubmixVoice *iface,
const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
return FAudioVoice_SetFilterParameters(This->faudio_voice, (const FAudioFilterParameters *)pParameters,
OperationSet);
}
static void WINAPI XA2SUB_GetFilterParameters(IXAudio2SubmixVoice *iface,
XAUDIO2_FILTER_PARAMETERS *pParameters)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %p\n", This, pParameters);
FAudioVoice_GetFilterParameters(This->faudio_voice, (FAudioFilterParameters *)pParameters);
}
static HRESULT WINAPI XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice *iface,
IXAudio2Voice *pDestinationVoice,
const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
return FAudioVoice_SetOutputFilterParameters(This->faudio_voice,
dst ? dst->faudio_voice : NULL, (const FAudioFilterParameters *)pParameters, OperationSet);
}
static void WINAPI XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice *iface,
IXAudio2Voice *pDestinationVoice,
XAUDIO2_FILTER_PARAMETERS *pParameters)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
FAudioVoice_GetOutputFilterParameters(This->faudio_voice,
dst ? dst->faudio_voice : NULL, (FAudioFilterParameters *)pParameters);
}
static HRESULT WINAPI XA2SUB_SetVolume(IXAudio2SubmixVoice *iface, float Volume,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
return FAudioVoice_SetVolume(This->faudio_voice, Volume, OperationSet);
}
static void WINAPI XA2SUB_GetVolume(IXAudio2SubmixVoice *iface, float *pVolume)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %p\n", This, pVolume);
return FAudioVoice_GetVolume(This->faudio_voice, pVolume);
}
static HRESULT WINAPI XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
const float *pVolumes, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
return FAudioVoice_SetChannelVolumes(This->faudio_voice, Channels,
pVolumes, OperationSet);
}
static void WINAPI XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
float *pVolumes)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p, %u, %p\n", This, Channels, pVolumes);
return FAudioVoice_GetChannelVolumes(This->faudio_voice, Channels,
pVolumes);
}
static HRESULT WINAPI XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice *iface,
IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
UINT32 DestinationChannels, const float *pLevelMatrix,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
return FAudioVoice_SetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
}
static void WINAPI XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice *iface,
IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
UINT32 DestinationChannels, float *pLevelMatrix)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
SourceChannels, DestinationChannels, pLevelMatrix);
FAudioVoice_GetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
SourceChannels, DestinationChannels, pLevelMatrix);
}
static void WINAPI XA2SUB_DestroyVoice(IXAudio2SubmixVoice *iface)
{
XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
TRACE("%p\n", This);
EnterCriticalSection(&This->lock);
destroy_voice(This);
LeaveCriticalSection(&This->lock);
}
static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl = {
XA2SUB_GetVoiceDetails,
XA2SUB_SetOutputVoices,
XA2SUB_SetEffectChain,
XA2SUB_EnableEffect,
XA2SUB_DisableEffect,
XA2SUB_GetEffectState,
XA2SUB_SetEffectParameters,
XA2SUB_GetEffectParameters,
XA2SUB_SetFilterParameters,
XA2SUB_GetFilterParameters,
XA2SUB_SetOutputFilterParameters,
XA2SUB_GetOutputFilterParameters,
XA2SUB_SetVolume,
XA2SUB_GetVolume,
XA2SUB_SetChannelVolumes,
XA2SUB_GetChannelVolumes,
XA2SUB_SetOutputMatrix,
XA2SUB_GetOutputMatrix,
XA2SUB_DestroyVoice
};
/* Mastering Voices */
static inline XA2VoiceImpl *impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice *iface)
{
return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio2MasteringVoice_iface);
}
static void WINAPI XA2M_GetVoiceDetails(IXAudio2MasteringVoice *iface,
XAUDIO2_VOICE_DETAILS *pVoiceDetails)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %p\n", This, pVoiceDetails);
FAudioVoice_GetVoiceDetails(This->faudio_voice, (FAudioVoiceDetails *)pVoiceDetails);
}
static HRESULT WINAPI XA2M_SetOutputVoices(IXAudio2MasteringVoice *iface,
const XAUDIO2_VOICE_SENDS *pSendList)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
FAudioVoiceSends *faudio_sends;
HRESULT hr;
TRACE("%p, %p\n", This, pSendList);
faudio_sends = wrap_voice_sends(pSendList);
hr = FAudioVoice_SetOutputVoices(This->faudio_voice, faudio_sends);
free_voice_sends(faudio_sends);
return hr;
}
static HRESULT WINAPI XA2M_SetEffectChain(IXAudio2MasteringVoice *iface,
const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
HRESULT hr;
TRACE("%p, %p\n", This, pEffectChain);
free_effect_chain(This->effect_chain);
This->effect_chain = wrap_effect_chain(pEffectChain);
hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
return hr;
}
static HRESULT WINAPI XA2M_EnableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
return FAudioVoice_EnableEffect(This->faudio_voice, EffectIndex, OperationSet);
}
static HRESULT WINAPI XA2M_DisableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
return FAudioVoice_DisableEffect(This->faudio_voice, EffectIndex, OperationSet);
}
static void WINAPI XA2M_GetEffectState(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
BOOL *pEnabled)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
FAudioVoice_GetEffectState(This->faudio_voice, EffectIndex, (int32_t*)pEnabled);
}
static HRESULT WINAPI XA2M_SetEffectParameters(IXAudio2MasteringVoice *iface,
UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
ParametersByteSize, OperationSet);
return FAudioVoice_SetEffectParameters(This->faudio_voice, EffectIndex,
pParameters, ParametersByteSize, OperationSet);
}
static HRESULT WINAPI XA2M_GetEffectParameters(IXAudio2MasteringVoice *iface,
UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
ParametersByteSize);
return FAudioVoice_GetEffectParameters(This->faudio_voice, EffectIndex,
pParameters, ParametersByteSize);
}
static HRESULT WINAPI XA2M_SetFilterParameters(IXAudio2MasteringVoice *iface,
const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
return FAudioVoice_SetFilterParameters(This->faudio_voice, (const FAudioFilterParameters *)pParameters,
OperationSet);
}
static void WINAPI XA2M_GetFilterParameters(IXAudio2MasteringVoice *iface,
XAUDIO2_FILTER_PARAMETERS *pParameters)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %p\n", This, pParameters);
FAudioVoice_GetFilterParameters(This->faudio_voice, (FAudioFilterParameters *)pParameters);
}
static HRESULT WINAPI XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice *iface,
IXAudio2Voice *pDestinationVoice,
const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
return FAudioVoice_SetOutputFilterParameters(This->faudio_voice,
dst ? dst->faudio_voice : NULL, (const FAudioFilterParameters *)pParameters, OperationSet);
}
static void WINAPI XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice *iface,
IXAudio2Voice *pDestinationVoice,
XAUDIO2_FILTER_PARAMETERS *pParameters)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
FAudioVoice_GetOutputFilterParameters(This->faudio_voice,
dst ? dst->faudio_voice : NULL, (FAudioFilterParameters *)pParameters);
}
static HRESULT WINAPI XA2M_SetVolume(IXAudio2MasteringVoice *iface, float Volume,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
return FAudioVoice_SetVolume(This->faudio_voice, Volume, OperationSet);
}
static void WINAPI XA2M_GetVolume(IXAudio2MasteringVoice *iface, float *pVolume)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %p\n", This, pVolume);
return FAudioVoice_GetVolume(This->faudio_voice, pVolume);
}
static HRESULT WINAPI XA2M_SetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
const float *pVolumes, UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
return FAudioVoice_SetChannelVolumes(This->faudio_voice, Channels,
pVolumes, OperationSet);
}
static void WINAPI XA2M_GetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
float *pVolumes)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %u, %p\n", This, Channels, pVolumes);
return FAudioVoice_GetChannelVolumes(This->faudio_voice, Channels,
pVolumes);
}
static HRESULT WINAPI XA2M_SetOutputMatrix(IXAudio2MasteringVoice *iface,
IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
UINT32 DestinationChannels, const float *pLevelMatrix,
UINT32 OperationSet)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
return FAudioVoice_SetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
}
static void WINAPI XA2M_GetOutputMatrix(IXAudio2MasteringVoice *iface,
IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
UINT32 DestinationChannels, float *pLevelMatrix)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
SourceChannels, DestinationChannels, pLevelMatrix);
FAudioVoice_GetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
SourceChannels, DestinationChannels, pLevelMatrix);
}
static void WINAPI XA2M_DestroyVoice(IXAudio2MasteringVoice *iface)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p\n", This);
EnterCriticalSection(&This->lock);
destroy_voice(This);
pthread_mutex_lock(&This->engine_lock);
This->engine_params.proc = NULL;
pthread_cond_broadcast(&This->engine_ready);
pthread_mutex_unlock(&This->engine_lock);
WaitForSingleObject(This->engine_thread, INFINITE);
This->engine_thread = NULL;
LeaveCriticalSection(&This->lock);
}
static void WINAPI XA2M_GetChannelMask(IXAudio2MasteringVoice *iface,
DWORD *pChannelMask)
{
XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
TRACE("%p, %p\n", This, pChannelMask);
FAudioMasteringVoice_GetChannelMask(This->faudio_voice, pChannelMask);
}
static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl = {
XA2M_GetVoiceDetails,
XA2M_SetOutputVoices,
XA2M_SetEffectChain,
XA2M_EnableEffect,
XA2M_DisableEffect,
XA2M_GetEffectState,
XA2M_SetEffectParameters,
XA2M_GetEffectParameters,
XA2M_SetFilterParameters,
XA2M_GetFilterParameters,
XA2M_SetOutputFilterParameters,
XA2M_GetOutputFilterParameters,
XA2M_SetVolume,
XA2M_GetVolume,
XA2M_SetChannelVolumes,
XA2M_GetChannelVolumes,
XA2M_SetOutputMatrix,
XA2M_GetOutputMatrix,
XA2M_DestroyVoice,
XA2M_GetChannelMask
};
/* More Common Voice Functions */
static XA2VoiceImpl *impl_from_IXAudio2Voice(IXAudio2Voice *iface)
{
if(iface->lpVtbl == (void*)&XAudio2SourceVoice_Vtbl)
return impl_from_IXAudio2SourceVoice((IXAudio2SourceVoice*)iface);
if(iface->lpVtbl == (void*)&XAudio2MasteringVoice_Vtbl)
return impl_from_IXAudio2MasteringVoice((IXAudio2MasteringVoice*)iface);
if(iface->lpVtbl == (void*)&XAudio2SubmixVoice_Vtbl)
return impl_from_IXAudio2SubmixVoice((IXAudio2SubmixVoice*)iface);
#if XAUDIO2_VER == 0
if(iface->lpVtbl == (void*)&XAudio20SourceVoice_Vtbl)
return impl_from_IXAudio20SourceVoice((IXAudio20SourceVoice*)iface);
if(iface->lpVtbl == (void*)&XAudio20SubmixVoice_Vtbl)
return impl_from_IXAudio20SubmixVoice((IXAudio20SubmixVoice*)iface);
if(iface->lpVtbl == (void*)&XAudio20MasteringVoice_Vtbl)
return impl_from_IXAudio20MasteringVoice((IXAudio20MasteringVoice*)iface);
#elif XAUDIO2_VER <= 3
if(iface->lpVtbl == (void*)&XAudio23SourceVoice_Vtbl)
return impl_from_IXAudio23SourceVoice((IXAudio23SourceVoice*)iface);
if(iface->lpVtbl == (void*)&XAudio23SubmixVoice_Vtbl)
return impl_from_IXAudio23SubmixVoice((IXAudio23SubmixVoice*)iface);
if(iface->lpVtbl == (void*)&XAudio23MasteringVoice_Vtbl)
return impl_from_IXAudio23MasteringVoice((IXAudio23MasteringVoice*)iface);
#elif XAUDIO2_VER <= 7
if(iface->lpVtbl == (void*)&XAudio27SourceVoice_Vtbl)
return impl_from_IXAudio27SourceVoice((IXAudio27SourceVoice*)iface);
if(iface->lpVtbl == (void*)&XAudio27SubmixVoice_Vtbl)
return impl_from_IXAudio27SubmixVoice((IXAudio27SubmixVoice*)iface);
if(iface->lpVtbl == (void*)&XAudio27MasteringVoice_Vtbl)
return impl_from_IXAudio27MasteringVoice((IXAudio27MasteringVoice*)iface);
#endif
ERR("invalid IXAudio2Voice pointer: %p\n", iface);
return NULL;
}
/* XAudio2 Engine Implementation */
static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
{
return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2_iface);
}
static HRESULT WINAPI IXAudio2Impl_QueryInterface(IXAudio2 *iface, REFIID riid,
void **ppvObject)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
if(IsEqualGUID(riid, &IID_IUnknown) ||
#if XAUDIO2_VER == 8
IsEqualGUID(riid, &IID_IXAudio28) ||
#endif
IsEqualGUID(riid, &IID_IXAudio2))
*ppvObject = &This->IXAudio2_iface;
else if(IsEqualGUID(riid, &IID_IXAudio27)){
/* all xaudio versions before 28 share an IID */
#if XAUDIO2_VER == 0
*ppvObject = &This->IXAudio20_iface;
#elif XAUDIO2_VER <= 2
*ppvObject = &This->IXAudio22_iface;
#elif XAUDIO2_VER <= 3
*ppvObject = &This->IXAudio23_iface;
#elif XAUDIO2_VER <= 7
*ppvObject = &This->IXAudio27_iface;
#else
*ppvObject = NULL;
#endif
}else
*ppvObject = NULL;
if(*ppvObject){
IUnknown_AddRef((IUnknown*)*ppvObject);
return S_OK;
}
FIXME("(%p)->(%s,%p), not found\n", This,debugstr_guid(riid), ppvObject);
return E_NOINTERFACE;
}
static ULONG WINAPI IXAudio2Impl_AddRef(IXAudio2 *iface)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
ULONG ref = FAudio_AddRef(This->faudio);
TRACE("(%p)->(): Refcount now %u\n", This, ref);
return ref;
}
static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
ULONG ref = FAudio_Release(This->faudio);
TRACE("(%p)->(): Refcount now %u\n", This, ref);
if (!ref) {
XA2VoiceImpl *v, *v2;
LIST_FOR_EACH_ENTRY_SAFE(v, v2, &This->voices, XA2VoiceImpl, entry){
v->lock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&v->lock);
HeapFree(GetProcessHeap(), 0, v);
}
HeapFree(GetProcessHeap(), 0, This->cbs);
This->lock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->lock);
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
static HRESULT WINAPI IXAudio2Impl_RegisterForCallbacks(IXAudio2 *iface,
IXAudio2EngineCallback *pCallback)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
int i;
TRACE("(%p)->(%p)\n", This, pCallback);
EnterCriticalSection(&This->lock);
for(i = 0; i < This->ncbs; ++i){
if(!This->cbs[i] || This->cbs[i] == pCallback){
This->cbs[i] = pCallback;
LeaveCriticalSection(&This->lock);
return S_OK;
}
}
This->ncbs++;
This->cbs = heap_realloc(This->cbs, This->ncbs * sizeof(*This->cbs));
This->cbs[i] = pCallback;
LeaveCriticalSection(&This->lock);
return S_OK;
}
static void WINAPI IXAudio2Impl_UnregisterForCallbacks(IXAudio2 *iface,
IXAudio2EngineCallback *pCallback)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
int i;
TRACE("(%p)->(%p)\n", This, pCallback);
EnterCriticalSection(&This->lock);
if(This->ncbs == 0){
LeaveCriticalSection(&This->lock);
return;
}
for(i = 0; i < This->ncbs; ++i){
if(This->cbs[i] == pCallback)
break;
}
for(; i < This->ncbs - 1 && This->cbs[i + 1]; ++i)
This->cbs[i] = This->cbs[i + 1];
if(i < This->ncbs)
This->cbs[i] = NULL;
LeaveCriticalSection(&This->lock);
}
static inline XA2VoiceImpl *create_voice(IXAudio2Impl *This)
{
XA2VoiceImpl *voice;
voice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*voice));
if(!voice)
return NULL;
list_add_head(&This->voices, &voice->entry);
voice->IXAudio2SourceVoice_iface.lpVtbl = &XAudio2SourceVoice_Vtbl;
#if XAUDIO2_VER == 0
voice->IXAudio20SourceVoice_iface.lpVtbl = &XAudio20SourceVoice_Vtbl;
#elif XAUDIO2_VER <= 3
voice->IXAudio23SourceVoice_iface.lpVtbl = &XAudio23SourceVoice_Vtbl;
#elif XAUDIO2_VER <= 7
voice->IXAudio27SourceVoice_iface.lpVtbl = &XAudio27SourceVoice_Vtbl;
#endif
voice->IXAudio2SubmixVoice_iface.lpVtbl = &XAudio2SubmixVoice_Vtbl;
#if XAUDIO2_VER == 0
voice->IXAudio20SubmixVoice_iface.lpVtbl = &XAudio20SubmixVoice_Vtbl;
#elif XAUDIO2_VER <= 3
voice->IXAudio23SubmixVoice_iface.lpVtbl = &XAudio23SubmixVoice_Vtbl;
#elif XAUDIO2_VER <= 7
voice->IXAudio27SubmixVoice_iface.lpVtbl = &XAudio27SubmixVoice_Vtbl;
#endif
voice->FAudioVoiceCallback_vtbl = FAudioVoiceCallback_Vtbl;
InitializeCriticalSection(&voice->lock);
voice->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2VoiceImpl.lock");
return voice;
}
static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
IXAudio2SourceVoice **ppSourceVoice, const WAVEFORMATEX *pSourceFormat,
UINT32 flags, float maxFrequencyRatio,
IXAudio2VoiceCallback *pCallback, const XAUDIO2_VOICE_SENDS *pSendList,
const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
XA2VoiceImpl *src;
HRESULT hr;
FAudioVoiceSends *faudio_sends;
TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This, ppSourceVoice,
pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList,
pEffectChain);
EnterCriticalSection(&This->lock);
LIST_FOR_EACH_ENTRY(src, &This->voices, XA2VoiceImpl, entry){
EnterCriticalSection(&src->lock);
if(!src->in_use)
break;
LeaveCriticalSection(&src->lock);
}
if(&src->entry == &This->voices){
src = create_voice(This);
EnterCriticalSection(&src->lock);
}
LeaveCriticalSection(&This->lock);
src->effect_chain = wrap_effect_chain(pEffectChain);
faudio_sends = wrap_voice_sends(pSendList);
hr = FAudio_CreateSourceVoice(This->faudio, &src->faudio_voice,
(FAudioWaveFormatEx*)pSourceFormat, flags, maxFrequencyRatio,
&src->FAudioVoiceCallback_vtbl, faudio_sends,
src->effect_chain);
free_voice_sends(faudio_sends);
if(FAILED(hr)){
LeaveCriticalSection(&This->lock);
return hr;
}
src->in_use = TRUE;
src->cb = pCallback;
LeaveCriticalSection(&src->lock);
#if XAUDIO2_VER == 0
*ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio20SourceVoice_iface;
#elif XAUDIO2_VER <= 3
*ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio23SourceVoice_iface;
#elif XAUDIO2_VER <= 7
*ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio27SourceVoice_iface;
#else
*ppSourceVoice = &src->IXAudio2SourceVoice_iface;
#endif
TRACE("Created source voice: %p\n", src);
return S_OK;
}
static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
IXAudio2SubmixVoice **ppSubmixVoice, UINT32 inputChannels,
UINT32 inputSampleRate, UINT32 flags, UINT32 processingStage,
const XAUDIO2_VOICE_SENDS *pSendList,
const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
HRESULT hr;
IXAudio2Impl *This = impl_from_IXAudio2(iface);
XA2VoiceImpl *sub;
FAudioVoiceSends *faudio_sends;
TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This, ppSubmixVoice,
inputChannels, inputSampleRate, flags, processingStage, pSendList,
pEffectChain);
EnterCriticalSection(&This->lock);
LIST_FOR_EACH_ENTRY(sub, &This->voices, XA2VoiceImpl, entry){
EnterCriticalSection(&sub->lock);
if(!sub->in_use)
break;
LeaveCriticalSection(&sub->lock);
}
if(&sub->entry == &This->voices){
sub = create_voice(This);
EnterCriticalSection(&sub->lock);
}
LeaveCriticalSection(&This->lock);
sub->effect_chain = wrap_effect_chain(pEffectChain);
faudio_sends = wrap_voice_sends(pSendList);
hr = FAudio_CreateSubmixVoice(This->faudio, &sub->faudio_voice, inputChannels,
inputSampleRate, flags, processingStage, faudio_sends,
sub->effect_chain);
free_voice_sends(faudio_sends);
if(FAILED(hr)){
LeaveCriticalSection(&sub->lock);
return hr;
}
sub->in_use = TRUE;
LeaveCriticalSection(&sub->lock);
#if XAUDIO2_VER == 0
*ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio20SubmixVoice_iface;
#elif XAUDIO2_VER <= 3
*ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio23SubmixVoice_iface;
#elif XAUDIO2_VER <= 7
*ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio27SubmixVoice_iface;
#else
*ppSubmixVoice = &sub->IXAudio2SubmixVoice_iface;
#endif
TRACE("Created submix voice: %p\n", sub);
return S_OK;
}
/* called thread created by SDL, must not access Wine TEB */
void engine_cb(FAudioEngineCallEXT proc, FAudio *faudio, float *stream, void *user)
{
XA2VoiceImpl *This = user;
pthread_mutex_lock(&This->engine_lock);
This->engine_params.proc = proc;
This->engine_params.stream = stream;
This->engine_params.faudio = faudio;
pthread_cond_broadcast(&This->engine_ready);
while(This->engine_params.proc)
pthread_cond_wait(&This->engine_done, &This->engine_lock);
pthread_mutex_unlock(&This->engine_lock);
}
/* wine thread, OK to access TEB, invoke client code, etc */
DWORD WINAPI engine_thread(void *user)
{
XA2VoiceImpl *This = user;
pthread_mutex_lock(&This->engine_lock);
pthread_cond_broadcast(&This->engine_done);
do{
pthread_cond_wait(&This->engine_ready, &This->engine_lock);
if(This->engine_params.proc){
This->engine_params.proc(This->engine_params.faudio, This->engine_params.stream);
This->engine_params.proc = NULL;
pthread_cond_broadcast(&This->engine_done);
}
}while(This->in_use);
pthread_mutex_unlock(&This->engine_lock);
return 0;
}
static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
IXAudio2MasteringVoice **ppMasteringVoice, UINT32 inputChannels,
UINT32 inputSampleRate, UINT32 flags, const WCHAR *deviceId,
const XAUDIO2_EFFECT_CHAIN *pEffectChain,
AUDIO_STREAM_CATEGORY streamCategory)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This,
ppMasteringVoice, inputChannels, inputSampleRate, flags,
wine_dbgstr_w(deviceId), pEffectChain, streamCategory);
EnterCriticalSection(&This->lock);
/* Note that we don't have paths for each XAUDIO2_VER here.
* All versions < 8 have a very different CreateMasteringVoice, so we
* implement those separately in compat.c.
* -flibit
*/
*ppMasteringVoice = &This->mst.IXAudio2MasteringVoice_iface;
EnterCriticalSection(&This->mst.lock);
if(This->mst.in_use){
LeaveCriticalSection(&This->mst.lock);
LeaveCriticalSection(&This->lock);
return COMPAT_E_INVALID_CALL;
}
LeaveCriticalSection(&This->lock);
This->mst.effect_chain = wrap_effect_chain(pEffectChain);
pthread_mutex_lock(&This->mst.engine_lock);
This->mst.engine_thread = CreateThread(NULL, 0, &engine_thread, &This->mst, 0, NULL);
pthread_cond_wait(&This->mst.engine_done, &This->mst.engine_lock);
pthread_mutex_unlock(&This->mst.engine_lock);
FAudio_SetEngineProcedureEXT(This->faudio, &engine_cb, &This->mst);
FAudio_CreateMasteringVoice8(This->faudio, &This->mst.faudio_voice, inputChannels,
inputSampleRate, flags, NULL /* TODO: (uint16_t*)deviceId */,
This->mst.effect_chain, (FAudioStreamCategory)streamCategory);
This->mst.in_use = TRUE;
LeaveCriticalSection(&This->mst.lock);
return S_OK;
}
static HRESULT WINAPI IXAudio2Impl_StartEngine(IXAudio2 *iface)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
TRACE("(%p)->()\n", This);
return FAudio_StartEngine(This->faudio);
}
static void WINAPI IXAudio2Impl_StopEngine(IXAudio2 *iface)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
TRACE("(%p)->()\n", This);
FAudio_StopEngine(This->faudio);
}
static HRESULT WINAPI IXAudio2Impl_CommitChanges(IXAudio2 *iface,
UINT32 operationSet)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
TRACE("(%p)->(0x%x)\n", This, operationSet);
#ifdef HAVE_FAUDIO_COMMITOPERATIONSET
return FAudio_CommitOperationSet(This->faudio, operationSet);
#else
return FAudio_CommitChanges(This->faudio);
#endif
}
static void WINAPI IXAudio2Impl_GetPerformanceData(IXAudio2 *iface,
XAUDIO2_PERFORMANCE_DATA *pPerfData)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
TRACE("(%p)->(%p): stub!\n", This, pPerfData);
FAudio_GetPerformanceData(This->faudio, (FAudioPerformanceData *)pPerfData);
}
static void WINAPI IXAudio2Impl_SetDebugConfiguration(IXAudio2 *iface,
const XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
void *pReserved)
{
IXAudio2Impl *This = impl_from_IXAudio2(iface);
TRACE("(%p)->(%p, %p): stub!\n", This, pDebugConfiguration, pReserved);
FAudio_SetDebugConfiguration(This->faudio, (FAudioDebugConfiguration *)pDebugConfiguration, pReserved);
}
/* XAudio2 2.8 */
static const IXAudio2Vtbl XAudio2_Vtbl =
{
IXAudio2Impl_QueryInterface,
IXAudio2Impl_AddRef,
IXAudio2Impl_Release,
IXAudio2Impl_RegisterForCallbacks,
IXAudio2Impl_UnregisterForCallbacks,
IXAudio2Impl_CreateSourceVoice,
IXAudio2Impl_CreateSubmixVoice,
IXAudio2Impl_CreateMasteringVoice,
IXAudio2Impl_StartEngine,
IXAudio2Impl_StopEngine,
IXAudio2Impl_CommitChanges,
IXAudio2Impl_GetPerformanceData,
IXAudio2Impl_SetDebugConfiguration
};
/* XAudio2 ClassFactory */
struct xaudio2_cf {
IClassFactory IClassFactory_iface;
LONG ref;
};
static struct xaudio2_cf *impl_from_IClassFactory(IClassFactory *iface)
{
return CONTAINING_RECORD(iface, struct xaudio2_cf, IClassFactory_iface);
}
static HRESULT WINAPI XAudio2CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
{
if(IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IClassFactory))
{
IClassFactory_AddRef(iface);
*ppobj = iface;
return S_OK;
}
*ppobj = NULL;
WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj);
return E_NOINTERFACE;
}
static ULONG WINAPI XAudio2CF_AddRef(IClassFactory *iface)
{
struct xaudio2_cf *This = impl_from_IClassFactory(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p)->(): Refcount now %u\n", This, ref);
return ref;
}
static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
{
struct xaudio2_cf *This = impl_from_IClassFactory(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p)->(): Refcount now %u\n", This, ref);
if (!ref)
HeapFree(GetProcessHeap(), 0, This);
return ref;
}
static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
REFIID riid, void **ppobj)
{
struct xaudio2_cf *This = impl_from_IClassFactory(iface);
HRESULT hr;
IXAudio2Impl *object;
TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
*ppobj = NULL;
if(pOuter)
return CLASS_E_NOAGGREGATION;
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
if(!object)
return E_OUTOFMEMORY;
object->IXAudio2_iface.lpVtbl = &XAudio2_Vtbl;
#if XAUDIO2_VER == 0
object->IXAudio20_iface.lpVtbl = &XAudio20_Vtbl;
#elif XAUDIO2_VER <= 2
object->IXAudio22_iface.lpVtbl = &XAudio22_Vtbl;
#elif XAUDIO2_VER <= 3
object->IXAudio23_iface.lpVtbl = &XAudio23_Vtbl;
#elif XAUDIO2_VER <= 7
object->IXAudio27_iface.lpVtbl = &XAudio27_Vtbl;
#endif
object->mst.IXAudio2MasteringVoice_iface.lpVtbl = &XAudio2MasteringVoice_Vtbl;
#if XAUDIO2_VER == 0
object->mst.IXAudio20MasteringVoice_iface.lpVtbl = &XAudio20MasteringVoice_Vtbl;
#elif XAUDIO2_VER <= 3
object->mst.IXAudio23MasteringVoice_iface.lpVtbl = &XAudio23MasteringVoice_Vtbl;
#elif XAUDIO2_VER <= 7
object->mst.IXAudio27MasteringVoice_iface.lpVtbl = &XAudio27MasteringVoice_Vtbl;
#endif
object->FAudioEngineCallback_vtbl = FAudioEngineCallback_Vtbl;
list_init(&object->voices);
InitializeCriticalSection(&object->lock);
object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock");
InitializeCriticalSection(&object->mst.lock);
object->mst.lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2MasteringVoice.lock");
pthread_mutex_init(&object->mst.engine_lock, NULL);
pthread_cond_init(&object->mst.engine_done, NULL);
pthread_cond_init(&object->mst.engine_ready, NULL);
FAudioCOMConstructWithCustomAllocatorEXT(
&object->faudio,
XAUDIO2_VER,
XAudio_Internal_Malloc,
XAudio_Internal_Free,
XAudio_Internal_Realloc
);
FAudio_RegisterForCallbacks(object->faudio, &object->FAudioEngineCallback_vtbl);
hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj);
if(FAILED(hr)){
object->lock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&object->lock);
HeapFree(GetProcessHeap(), 0, object);
return hr;
}
TRACE("Created XAudio version %u: %p\n", 20 + XAUDIO2_VER, object);
return hr;
}
static HRESULT WINAPI XAudio2CF_LockServer(IClassFactory *iface, BOOL dolock)
{
struct xaudio2_cf *This = impl_from_IClassFactory(iface);
FIXME("(%p)->(%d): stub!\n", This, dolock);
return S_OK;
}
static const IClassFactoryVtbl XAudio2CF_Vtbl =
{
XAudio2CF_QueryInterface,
XAudio2CF_AddRef,
XAudio2CF_Release,
XAudio2CF_CreateInstance,
XAudio2CF_LockServer
};
/* Engine Generators */
static inline HRESULT make_xaudio2_factory(REFIID riid, void **ppv)
{
HRESULT hr;
struct xaudio2_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf));
ret->IClassFactory_iface.lpVtbl = &XAudio2CF_Vtbl;
ret->ref = 0;
hr = IClassFactory_QueryInterface(&ret->IClassFactory_iface, riid, ppv);
if(FAILED(hr))
HeapFree(GetProcessHeap(), 0, ret);
return hr;
}
HRESULT xaudio2_initialize(IXAudio2Impl *This, UINT32 flags, XAUDIO2_PROCESSOR proc)
{
if(proc != XAUDIO2_ANY_PROCESSOR)
WARN("Processor affinity not implemented in FAudio\n");
return FAudio_Initialize(This->faudio, flags, FAUDIO_DEFAULT_PROCESSOR);
}
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
if(IsEqualGUID(rclsid, &CLSID_XAudio20) ||
IsEqualGUID(rclsid, &CLSID_XAudio21) ||
IsEqualGUID(rclsid, &CLSID_XAudio22) ||
IsEqualGUID(rclsid, &CLSID_XAudio23) ||
IsEqualGUID(rclsid, &CLSID_XAudio24) ||
IsEqualGUID(rclsid, &CLSID_XAudio25) ||
IsEqualGUID(rclsid, &CLSID_XAudio26) ||
IsEqualGUID(rclsid, &CLSID_XAudio27))
return make_xaudio2_factory(riid, ppv);
if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter20) ||
IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter21) ||
IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter22) ||
IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter23) ||
IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter24) ||
IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter25) ||
IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter26) ||
IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter27))
return make_xapo_factory(&CLSID_AudioVolumeMeter27, riid, ppv);
if(IsEqualGUID(rclsid, &CLSID_AudioReverb20) ||
IsEqualGUID(rclsid, &CLSID_AudioReverb21) ||
IsEqualGUID(rclsid, &CLSID_AudioReverb22) ||
IsEqualGUID(rclsid, &CLSID_AudioReverb23) ||
IsEqualGUID(rclsid, &CLSID_AudioReverb24) ||
IsEqualGUID(rclsid, &CLSID_AudioReverb25) ||
IsEqualGUID(rclsid, &CLSID_AudioReverb26) ||
IsEqualGUID(rclsid, &CLSID_AudioReverb27))
return make_xapo_factory(&CLSID_AudioReverb27, riid, ppv);
return CLASS_E_CLASSNOTAVAILABLE;
}
#if XAUDIO2_VER >= 8
HRESULT WINAPI XAudio2Create(IXAudio2 **ppxa2, UINT32 flags, XAUDIO2_PROCESSOR proc)
{
HRESULT hr;
IXAudio2 *xa2;
IClassFactory *cf;
TRACE("%p 0x%x 0x%x\n", ppxa2, flags, proc);
hr = make_xaudio2_factory(&IID_IClassFactory, (void**)&cf);
if(FAILED(hr))
return hr;
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IXAudio2, (void**)&xa2);
IClassFactory_Release(cf);
if(FAILED(hr))
return hr;
hr = xaudio2_initialize(impl_from_IXAudio2(xa2), flags, proc);
if(FAILED(hr)){
IXAudio2_Release(xa2);
return hr;
}
*ppxa2 = xa2;
return S_OK;
}
HRESULT WINAPI CreateAudioVolumeMeter(IUnknown **out)
{
IClassFactory *cf;
HRESULT hr;
hr = make_xapo_factory(&CLSID_AudioVolumeMeter27, &IID_IClassFactory, (void**)&cf);
if(FAILED(hr))
return hr;
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)out);
IClassFactory_Release(cf);
return hr;
}
HRESULT WINAPI CreateAudioReverb(IUnknown **out)
{
IClassFactory *cf;
HRESULT hr;
hr = make_xapo_factory(&CLSID_AudioReverb27, &IID_IClassFactory, (void**)&cf);
if(FAILED(hr))
return hr;
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)out);
IClassFactory_Release(cf);
return hr;
}
#endif /* XAUDIO2_VER >= 8 */