From: Paul Gofman pgofman@codeweavers.com
--- dlls/xaudio2_7/tests/xaudio2.c | 160 +++++++++++++++++++++++++++++++++ dlls/xaudio2_7/xaudio_dll.c | 87 ++++++++++++++---- 2 files changed, 230 insertions(+), 17 deletions(-)
diff --git a/dlls/xaudio2_7/tests/xaudio2.c b/dlls/xaudio2_7/tests/xaudio2.c index 006d3b6b463..1165db2a1f6 100644 --- a/dlls/xaudio2_7/tests/xaudio2.c +++ b/dlls/xaudio2_7/tests/xaudio2.c @@ -842,6 +842,126 @@ static void test_looping(IXAudio2 *xa) HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData); }
+struct test_xapo +{ + IXAPO IXAPO_iface; +}; + +static struct test_xapo test_xapo; +static BOOL test_xapo_supports_ixapo; +static BOOL test_xapo_supports_ixapo27; + +static HRESULT WINAPI test_xapo_QueryInterface(IXAPO *iface, REFIID riid, void **ppvObject) +{ + if (IsEqualGUID(riid, &IID_IUnknown)) + *ppvObject = &test_xapo.IXAPO_iface; + else if (test_xapo_supports_ixapo && IsEqualGUID(riid, &IID_IXAPO)) + *ppvObject = &test_xapo.IXAPO_iface; + else if (test_xapo_supports_ixapo27 && IsEqualGUID(riid, &IID_IXAPO27)) + *ppvObject = &test_xapo.IXAPO_iface; + else + *ppvObject = NULL; + + if(*ppvObject) + return S_OK; + + return E_NOINTERFACE; +} + +static ULONG WINAPI test_xapo_AddRef(IXAPO *iface) +{ + return 1; +} + +static ULONG WINAPI test_xapo_Release(IXAPO *iface) +{ + return 1; +} + +static HRESULT WINAPI test_xapo_GetRegistrationProperties(IXAPO *iface, + XAPO_REGISTRATION_PROPERTIES **props) +{ + XAPO_REGISTRATION_PROPERTIES *p; + + *props = CoTaskMemAlloc(sizeof(**props)); + memset(*props, 0, sizeof(**props)); + p = *props; + p->MinInputBufferCount = 1; + p->MaxInputBufferCount = 1000; + p->MinOutputBufferCount = 1; + p->MaxOutputBufferCount = 1000; + return S_OK; +} + +static HRESULT WINAPI test_xapo_IsInputFormatSupported(IXAPO *iface, + const WAVEFORMATEX *output_fmt, const WAVEFORMATEX *input_fmt, + WAVEFORMATEX **supported_fmt) +{ + return S_OK; +} + +static HRESULT WINAPI test_xapo_IsOutputFormatSupported(IXAPO *iface, + const WAVEFORMATEX *input_fmt, const WAVEFORMATEX *output_fmt, + WAVEFORMATEX **supported_fmt) +{ + return S_OK; +} + +static HRESULT WINAPI test_xapo_Initialize(IXAPO *iface, const void *data, + UINT32 data_len) +{ + return S_OK; +} + +static void WINAPI test_xapo_Reset(IXAPO *iface) +{ +} + +static HRESULT WINAPI test_xapo_LockForProcess(IXAPO *iface, UINT32 in_params_count, + const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *in_params, + UINT32 out_params_count, + const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *out_params) +{ + return S_OK; +} + +static void WINAPI test_xapo_UnlockForProcess(IXAPO *iface) +{ +} + +static void WINAPI test_xapo_Process(IXAPO *iface, UINT32 in_params_count, + const XAPO_PROCESS_BUFFER_PARAMETERS *in_params, + UINT32 out_params_count, + XAPO_PROCESS_BUFFER_PARAMETERS *out_params, BOOL enabled) +{ +} + +static UINT32 WINAPI test_xapo_CalcInputFrames(IXAPO *iface, UINT32 output_frames) +{ + return 0; +} + +static UINT32 WINAPI test_xapo_CalcOutputFrames(IXAPO *iface, UINT32 input_frames) +{ + return 0; +} + +static const IXAPOVtbl test_xapo_vtbl = { + test_xapo_QueryInterface, + test_xapo_AddRef, + test_xapo_Release, + test_xapo_GetRegistrationProperties, + test_xapo_IsInputFormatSupported, + test_xapo_IsOutputFormatSupported, + test_xapo_Initialize, + test_xapo_Reset, + test_xapo_LockForProcess, + test_xapo_UnlockForProcess, + test_xapo_Process, + test_xapo_CalcInputFrames, + test_xapo_CalcOutputFrames, +}; + static void test_submix(IXAudio2 *xa) { HRESULT hr; @@ -850,6 +970,8 @@ static void test_submix(IXAudio2 *xa) IXAudio2SubmixVoice *sub, *sub2; XAUDIO2_SEND_DESCRIPTOR send_desc = { 0 }; XAUDIO2_VOICE_SENDS sends = { 1, &send_desc }; + XAUDIO2_EFFECT_DESCRIPTOR effect; + XAUDIO2_EFFECT_CHAIN chain;
check_refcount((IUnknown *)xa, 1);
@@ -858,6 +980,44 @@ static void test_submix(IXAudio2 *xa) hr = create_mastering_voice(xa, 2, &master); ok(hr == S_OK, "CreateMasteringVoice failed: %08lx\n", hr);
+ effect.InitialState = TRUE; + effect.OutputChannels = 2; + effect.pEffect = NULL; + + chain.EffectCount = 1; + chain.pEffectDescriptors = &effect; + + if (XAUDIO2_VER >= 8) + { + /* These tests with invalid effect crash on earlier xaudio2 versions. */ + hr = IXAudio2MasteringVoice_SetEffectChain(master, NULL); + ok(!hr, "got %#lx\n", hr); + hr = IXAudio2MasteringVoice_SetEffectChain(master, &chain); + ok(hr == XAUDIO2_E_INVALID_CALL, "got %#lx\n", hr); + + hr = IXAudio2_CreateSubmixVoice(xa, &sub, 2, 44100, 0, 0, NULL, &chain); + ok(hr == XAUDIO2_E_INVALID_CALL, "got %#lx\n", hr); + test_xapo.IXAPO_iface.lpVtbl = &test_xapo_vtbl; + + test_xapo_supports_ixapo = FALSE; + test_xapo_supports_ixapo27 = FALSE; + effect.pEffect = (IUnknown *)&test_xapo.IXAPO_iface; + hr = IXAudio2_CreateSubmixVoice(xa, &sub, 2, 44100, 0, 0, NULL, &chain); + ok(hr == XAUDIO2_E_INVALID_CALL, "got %#lx\n", hr); + + test_xapo_supports_ixapo27 = TRUE; + hr = IXAudio2_CreateSubmixVoice(xa, &sub, 2, 44100, 0, 0, NULL, &chain); + ok(hr == XAUDIO2_E_INVALID_CALL, "got %#lx\n", hr); + hr = IXAudio2MasteringVoice_SetEffectChain(master, &chain); + ok(hr == XAUDIO2_E_INVALID_CALL, "got %#lx\n", hr); + + test_xapo_supports_ixapo = TRUE; + test_xapo_supports_ixapo27 = FALSE; + hr = IXAudio2_CreateSubmixVoice(xa, &sub, 2, 44100, 0, 0, NULL, &chain); + ok(!hr, "got %#lx.\n", hr); + IXAudio2SubmixVoice_DestroyVoice(sub); + } + hr = IXAudio2_CreateSubmixVoice(xa, &sub, 2, 44100, 0, 0, NULL, NULL); ok(hr == S_OK, "CreateSubmixVoice failed: %08lx\n", hr);
diff --git a/dlls/xaudio2_7/xaudio_dll.c b/dlls/xaudio2_7/xaudio_dll.c index 6eac068f986..fe9351e8b4a 100644 --- a/dlls/xaudio2_7/xaudio_dll.c +++ b/dlls/xaudio2_7/xaudio_dll.c @@ -272,6 +272,11 @@ static XA2XAPOImpl *wrap_xapo(IUnknown *unk) #if XAUDIO2_VER <= 7 hr = IUnknown_QueryInterface(unk, &IID_IXAPO27, (void**)&xapo); #else + if (!unk) + { + WARN("NULL XAPO interface.\n"); + return NULL; + } hr = IUnknown_QueryInterface(unk, &IID_IXAPO, (void**)&xapo); #endif if(FAILED(hr)){ @@ -301,9 +306,20 @@ static XA2XAPOImpl *wrap_xapo(IUnknown *unk) 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); + free(chain); +} + FAudioEffectChain *wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN *pEffectChain) { FAudioEffectChain *ret; + XA2XAPOImpl *xapo; int i;
if(!pEffectChain) @@ -315,7 +331,16 @@ FAudioEffectChain *wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN *pEffectChain) ret->pEffectDescriptors = (void*)(ret + 1);
for(i = 0; i < ret->EffectCount; ++i){ - ret->pEffectDescriptors[i].pEffect = &wrap_xapo(pEffectChain->pEffectDescriptors[i].pEffect)->FAPO_vtbl; + xapo = wrap_xapo(pEffectChain->pEffectDescriptors[i].pEffect); +#if XAUDIO2_VER >= 8 + if (!xapo) + { + ret->EffectCount = i; + free_effect_chain(ret); + return NULL; + } +#endif + ret->pEffectDescriptors[i].pEffect = &xapo->FAPO_vtbl; ret->pEffectDescriptors[i].InitialState = pEffectChain->pEffectDescriptors[i].InitialState; ret->pEffectDescriptors[i].OutputChannels = pEffectChain->pEffectDescriptors[i].OutputChannels; } @@ -323,16 +348,6 @@ FAudioEffectChain *wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN *pEffectChain) 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); - free(chain); -} - /* Send Wrapping */
static FAudioVoiceSends *wrap_voice_sends(const XAUDIO2_VOICE_SENDS *sends) @@ -560,12 +575,18 @@ static HRESULT WINAPI XA2SRC_SetEffectChain(IXAudio2SourceVoice *iface, const XAUDIO2_EFFECT_CHAIN *pEffectChain) { XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface); + FAudioEffectChain *chain; HRESULT hr;
TRACE("%p, %p\n", This, pEffectChain);
+ chain = wrap_effect_chain(pEffectChain); +#if XAUDIO2_VER >= 8 + if (pEffectChain && !chain) + return XAUDIO2_E_INVALID_CALL; +#endif free_effect_chain(This->effect_chain); - This->effect_chain = wrap_effect_chain(pEffectChain); + This->effect_chain = chain;
hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
@@ -922,12 +943,18 @@ static HRESULT WINAPI XA2SUB_SetEffectChain(IXAudio2SubmixVoice *iface, const XAUDIO2_EFFECT_CHAIN *pEffectChain) { XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface); + FAudioEffectChain *chain; HRESULT hr;
TRACE("%p, %p\n", This, pEffectChain);
+ chain = wrap_effect_chain(pEffectChain); +#if XAUDIO2_VER >= 8 + if (pEffectChain && !chain) + return XAUDIO2_E_INVALID_CALL; +#endif free_effect_chain(This->effect_chain); - This->effect_chain = wrap_effect_chain(pEffectChain); + This->effect_chain = chain;
hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
@@ -1167,12 +1194,18 @@ static HRESULT WINAPI XA2M_SetEffectChain(IXAudio2MasteringVoice *iface, const XAUDIO2_EFFECT_CHAIN *pEffectChain) { XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface); + FAudioEffectChain *chain; HRESULT hr;
TRACE("%p, %p\n", This, pEffectChain);
+ chain = wrap_effect_chain(pEffectChain); +#if XAUDIO2_VER >= 8 + if (pEffectChain && !chain) + return XAUDIO2_E_INVALID_CALL; +#endif free_effect_chain(This->effect_chain); - This->effect_chain = wrap_effect_chain(pEffectChain); + This->effect_chain = chain;
hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
@@ -1586,11 +1619,17 @@ static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface, XA2VoiceImpl *src; HRESULT hr; FAudioVoiceSends *faudio_sends; + FAudioEffectChain *chain;
TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This, ppSourceVoice, pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList, pEffectChain);
+ chain = wrap_effect_chain(pEffectChain); +#if XAUDIO2_VER >= 8 + if (pEffectChain && !chain) + return XAUDIO2_E_INVALID_CALL; +#endif EnterCriticalSection(&This->lock);
LIST_FOR_EACH_ENTRY(src, &This->voices, XA2VoiceImpl, entry){ @@ -1607,7 +1646,7 @@ static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
LeaveCriticalSection(&This->lock);
- src->effect_chain = wrap_effect_chain(pEffectChain); + src->effect_chain = chain; faudio_sends = wrap_voice_sends(pSendList);
hr = FAudio_CreateSourceVoice(This->faudio, &src->faudio_voice, @@ -1642,11 +1681,18 @@ static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface, IXAudio2Impl *This = impl_from_IXAudio2(iface); XA2VoiceImpl *sub; FAudioVoiceSends *faudio_sends; + FAudioEffectChain *chain;
TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This, ppSubmixVoice, inputChannels, inputSampleRate, flags, processingStage, pSendList, pEffectChain);
+ chain = wrap_effect_chain(pEffectChain); +#if XAUDIO2_VER >= 8 + if (pEffectChain && !chain) + return XAUDIO2_E_INVALID_CALL; +#endif + EnterCriticalSection(&This->lock);
LIST_FOR_EACH_ENTRY(sub, &This->voices, XA2VoiceImpl, entry){ @@ -1663,7 +1709,7 @@ static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
LeaveCriticalSection(&This->lock);
- sub->effect_chain = wrap_effect_chain(pEffectChain); + sub->effect_chain = chain; faudio_sends = wrap_voice_sends(pSendList);
hr = FAudio_CreateSubmixVoice(This->faudio, &sub->faudio_voice, inputChannels, @@ -1701,10 +1747,17 @@ static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface, ) { IXAudio2Impl *This = impl_from_IXAudio2(iface); + FAudioEffectChain *chain;
TRACE("(%p)->(%p, %u, %u, 0x%x, %p)\n", This, ppMasteringVoice, inputChannels, inputSampleRate, flags, pEffectChain);
+ chain = wrap_effect_chain(pEffectChain); +#if XAUDIO2_VER >= 8 + if (pEffectChain && !chain) + return XAUDIO2_E_INVALID_CALL; +#endif + EnterCriticalSection(&This->lock);
*ppMasteringVoice = &This->mst.IXAudio2MasteringVoice_iface; @@ -1719,7 +1772,7 @@ static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
LeaveCriticalSection(&This->lock);
- This->mst.effect_chain = wrap_effect_chain(pEffectChain); + This->mst.effect_chain = chain;
#if XAUDIO2_VER >= 8 TRACE("device id %s, category %#x\n", debugstr_w(deviceId), streamCategory);