From 6abe9f0920b33e33eebc2c5c60aaf7307f4ed210 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 28 Aug 2015 08:22:33 -0500 Subject: [PATCH] xaudio2/tests: Add callback tests. --- dlls/xaudio2_7/tests/xaudio2.c | 307 ++++++++++++++++++++++++++++++++- 1 file changed, 305 insertions(+), 2 deletions(-) diff --git a/dlls/xaudio2_7/tests/xaudio2.c b/dlls/xaudio2_7/tests/xaudio2.c index 01fabd61bbc..949a5cf9f96 100644 --- a/dlls/xaudio2_7/tests/xaudio2.c +++ b/dlls/xaudio2_7/tests/xaudio2.c @@ -30,6 +30,7 @@ static BOOL xaudio27; static HRESULT (WINAPI *pXAudio2Create)(IXAudio2 **, UINT32, XAUDIO2_PROCESSOR) = NULL; #define XA2CALL_0(method) if(xaudio27) hr = IXAudio27_##method((IXAudio27*)xa); else hr = IXAudio2_##method(xa); +#define XA2CALL_0V(method) if(xaudio27) IXAudio27_##method((IXAudio27*)xa); else IXAudio2_##method(xa); #define XA2CALL_V(method, ...) if(xaudio27) IXAudio27_##method((IXAudio27*)xa, __VA_ARGS__); else IXAudio2_##method(xa, __VA_ARGS__); #define XA2CALL(method, ...) if(xaudio27) hr = IXAudio27_##method((IXAudio27*)xa, __VA_ARGS__); else hr = IXAudio2_##method(xa, __VA_ARGS__); @@ -44,6 +45,121 @@ static void fill_buf(float *buf, WAVEFORMATEX *fmt, DWORD hz, DWORD len_frames) memset(buf, 0, sizeof(float) * len_frames * fmt->nChannels); } +static struct _cb_state { + BOOL start_called, end_called; +} ecb_state, src1_state, src2_state; + +static int pass_state = 0; +static BOOL buffers_called = FALSE; + +static void WINAPI ECB_OnProcessingPassStart(IXAudio2EngineCallback *This) +{ + ok(!xaudio27 || pass_state == 0, "Callbacks called out of order: %u\n", pass_state); + ++pass_state; +} + +static void WINAPI ECB_OnProcessingPassEnd(IXAudio2EngineCallback *This) +{ + ok(!xaudio27 || pass_state == (buffers_called ? 7 : 5), "Callbacks called out of order: %u\n", pass_state); + pass_state = 0; + buffers_called = FALSE; +} + +static void WINAPI ECB_OnCriticalError(IXAudio2EngineCallback *This, HRESULT Error) +{ + ok(0, "Unexpected OnCriticalError\n"); +} + +static const IXAudio2EngineCallbackVtbl ecb_vtbl = { + ECB_OnProcessingPassStart, + ECB_OnProcessingPassEnd, + ECB_OnCriticalError +}; + +static IXAudio2EngineCallback ecb = { &ecb_vtbl }; + +static IXAudio2VoiceCallback vcb1; +static IXAudio2VoiceCallback vcb2; + +static void WINAPI VCB_OnVoiceProcessingPassStart(IXAudio2VoiceCallback *This, + UINT32 BytesRequired) +{ + if(This == &vcb1){ + ok(!xaudio27 || pass_state == (buffers_called ? 4 : 3), "Callbacks called out of order: %u\n", pass_state); + ++pass_state; + }else{ + ok(!xaudio27 || pass_state == 1, "Callbacks called out of order: %u\n", pass_state); + ++pass_state; + } +} + +static void WINAPI VCB_OnVoiceProcessingPassEnd(IXAudio2VoiceCallback *This) +{ + if(This == &vcb1){ + ok(!xaudio27 || pass_state == (buffers_called ? 6 : 4), "Callbacks called out of order: %u\n", pass_state); + ++pass_state; + }else{ + ok(!xaudio27 || pass_state == (buffers_called ? 3 : 2), "Callbacks called out of order: %u\n", pass_state); + ++pass_state; + } +} + +static void WINAPI VCB_OnStreamEnd(IXAudio2VoiceCallback *This) +{ + ok(0, "Unexpected OnStreamEnd\n"); +} + +static void WINAPI VCB_OnBufferStart(IXAudio2VoiceCallback *This, + void *pBufferContext) +{ + if(This == &vcb1){ + ok(!xaudio27 || pass_state == 5, "Callbacks called out of order: %u\n", pass_state); + ++pass_state; + }else{ + ok(!xaudio27 || pass_state == 2, "Callbacks called out of order: %u\n", pass_state); + ++pass_state; + buffers_called = TRUE; + } +} + +static void WINAPI VCB_OnBufferEnd(IXAudio2VoiceCallback *This, + void *pBufferContext) +{ + if(This == &vcb1){ + ok(!xaudio27 || pass_state == 5, "Callbacks called out of order: %u\n", pass_state); + ++pass_state; + }else{ + ok(!xaudio27 || pass_state == 2, "Callbacks called out of order: %u\n", pass_state); + ++pass_state; + buffers_called = TRUE; + } +} + +static void WINAPI VCB_OnLoopEnd(IXAudio2VoiceCallback *This, + void *pBufferContext) +{ + ok(0, "Unexpected OnLoopEnd\n"); +} + +static void WINAPI VCB_OnVoiceError(IXAudio2VoiceCallback *This, + void *pBuffercontext, HRESULT Error) +{ + ok(0, "Unexpected OnVoiceError\n"); +} + +static const IXAudio2VoiceCallbackVtbl vcb_vtbl = { + VCB_OnVoiceProcessingPassStart, + VCB_OnVoiceProcessingPassEnd, + VCB_OnStreamEnd, + VCB_OnBufferStart, + VCB_OnBufferEnd, + VCB_OnLoopEnd, + VCB_OnVoiceError +}; + +static IXAudio2VoiceCallback vcb1 = { &vcb_vtbl }; +static IXAudio2VoiceCallback vcb2 = { &vcb_vtbl }; + static void test_simple_streaming(IXAudio2 *xa) { HRESULT hr; @@ -53,6 +169,21 @@ static void test_simple_streaming(IXAudio2 *xa) XAUDIO2_BUFFER buf, buf2; XAUDIO2_VOICE_STATE state; + memset(&ecb_state, 0, sizeof(ecb_state)); + memset(&src1_state, 0, sizeof(src1_state)); + memset(&src2_state, 0, sizeof(src2_state)); + + XA2CALL_0V(StopEngine); + + /* Tests show in native XA2.8, ECB is called from a mixer thread, but VCBs + * may be called from other threads in any order. So we can't rely on any + * sequencing between VCB calls. + * + * XA2.7 does all mixing from a single thread, so call sequence can be + * tested. */ + XA2CALL(RegisterForCallbacks, &ecb); + ok(hr == S_OK, "RegisterForCallbacks failed: %08x\n", hr); + if(xaudio27) hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL); else @@ -67,7 +198,7 @@ static void test_simple_streaming(IXAudio2 *xa) fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; fmt.cbSize = 0; - XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, NULL, NULL, NULL); + XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &vcb1, NULL, NULL); ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); memset(&buf, 0, sizeof(buf)); @@ -82,7 +213,7 @@ static void test_simple_streaming(IXAudio2 *xa) ok(hr == S_OK, "Start failed: %08x\n", hr); - XA2CALL(CreateSourceVoice, &src2, &fmt, 0, 1.f, NULL, NULL, NULL); + XA2CALL(CreateSourceVoice, &src2, &fmt, 0, 1.f, &vcb2, NULL, NULL); ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); memset(&buf2, 0, sizeof(buf2)); @@ -96,6 +227,9 @@ static void test_simple_streaming(IXAudio2 *xa) hr = IXAudio2SourceVoice_Start(src2, 0, XAUDIO2_COMMIT_NOW); ok(hr == S_OK, "Start failed: %08x\n", hr); + XA2CALL_0(StartEngine); + ok(hr == S_OK, "StartEngine failed: %08x\n", hr); + while(1){ if(xaudio27) IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state); @@ -119,6 +253,172 @@ static void test_simple_streaming(IXAudio2 *xa) IXAudio2SourceVoice_DestroyVoice(src2); } IXAudio2MasteringVoice_DestroyVoice(master); + + XA2CALL_V(UnregisterForCallbacks, &ecb); +} + +static void WINAPI vcb_buf_OnVoiceProcessingPassStart(IXAudio2VoiceCallback *This, + UINT32 BytesRequired) +{ +} + +static void WINAPI vcb_buf_OnVoiceProcessingPassEnd(IXAudio2VoiceCallback *This) +{ +} + +static void WINAPI vcb_buf_OnStreamEnd(IXAudio2VoiceCallback *This) +{ + ok(0, "Unexpected OnStreamEnd\n"); +} + +struct vcb_buf_testdata { + int idx; + IXAudio2SourceVoice *src; +}; + +static int obs_calls = 0; +static int obe_calls = 0; + +static void WINAPI vcb_buf_OnBufferStart(IXAudio2VoiceCallback *This, + void *pBufferContext) +{ + struct vcb_buf_testdata *data = pBufferContext; + XAUDIO2_VOICE_STATE state; + + ok(data->idx == obs_calls, "Buffer callback out of order: %u\n", data->idx); + + if(xaudio27) + IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)data->src, &state); + else + IXAudio2SourceVoice_GetState(data->src, &state, 0); + + ok(state.BuffersQueued == 5 - obs_calls, "Got wrong number of buffers remaining: %u\n", state.BuffersQueued); + ok(state.pCurrentBufferContext == pBufferContext, "Got wrong buffer from GetState\n"); + + ++obs_calls; +} + +static void WINAPI vcb_buf_OnBufferEnd(IXAudio2VoiceCallback *This, + void *pBufferContext) +{ + struct vcb_buf_testdata *data = pBufferContext; + XAUDIO2_VOICE_STATE state; + + ok(data->idx == obe_calls, "Buffer callback out of order: %u\n", data->idx); + + if(xaudio27) + IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)data->src, &state); + else + IXAudio2SourceVoice_GetState(data->src, &state, 0); + + ok(state.BuffersQueued == 5 - obe_calls - 1, "Got wrong number of buffers remaining: %u\n", state.BuffersQueued); + if(state.BuffersQueued == 0) + ok(state.pCurrentBufferContext == NULL, "Got wrong buffer from GetState: %p\n", state.pCurrentBufferContext); + else + ok(state.pCurrentBufferContext == data + 1, "Got wrong buffer from GetState: %p\n", state.pCurrentBufferContext); + + ++obe_calls; +} + +static void WINAPI vcb_buf_OnLoopEnd(IXAudio2VoiceCallback *This, + void *pBufferContext) +{ + ok(0, "Unexpected OnLoopEnd\n"); +} + +static void WINAPI vcb_buf_OnVoiceError(IXAudio2VoiceCallback *This, + void *pBuffercontext, HRESULT Error) +{ + ok(0, "Unexpected OnVoiceError\n"); +} + +static const IXAudio2VoiceCallbackVtbl vcb_buf_vtbl = { + vcb_buf_OnVoiceProcessingPassStart, + vcb_buf_OnVoiceProcessingPassEnd, + vcb_buf_OnStreamEnd, + vcb_buf_OnBufferStart, + vcb_buf_OnBufferEnd, + vcb_buf_OnLoopEnd, + vcb_buf_OnVoiceError +}; + +static IXAudio2VoiceCallback vcb_buf = { &vcb_buf_vtbl }; + +static void test_buffer_callbacks(IXAudio2 *xa) +{ + HRESULT hr; + IXAudio2MasteringVoice *master; + IXAudio2SourceVoice *src; + WAVEFORMATEX fmt; + XAUDIO2_BUFFER buf; + XAUDIO2_VOICE_STATE state; + struct vcb_buf_testdata testdata[5]; + int i; + + obs_calls = 0; + obe_calls = 0; + + XA2CALL_0V(StopEngine); + + if(xaudio27) + hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL); + else + hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects); + ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr); + + fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + fmt.nChannels = 2; + fmt.nSamplesPerSec = 44100; + fmt.wBitsPerSample = 32; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + fmt.cbSize = 0; + + XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &vcb_buf, NULL, NULL); + ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr); + + memset(&buf, 0, sizeof(buf)); + buf.AudioBytes = 4410 * fmt.nBlockAlign; + buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes); + fill_buf((float*)buf.pAudioData, &fmt, 440, 4410); + + /* submit same buffer fragment 5 times */ + for(i = 0; i < 5; ++i){ + testdata[i].idx = i; + testdata[i].src = src; + buf.pContext = &testdata[i]; + + hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL); + ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr); + } + + hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW); + ok(hr == S_OK, "Start failed: %08x\n", hr); + + + XA2CALL_0(StartEngine); + ok(hr == S_OK, "StartEngine failed: %08x\n", hr); + + while(1){ + if(xaudio27) + IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state); + else + IXAudio2SourceVoice_GetState(src, &state, 0); + if(state.SamplesPlayed >= 4410 * 5) + break; + Sleep(100); + } + + ok(state.SamplesPlayed == 4410 * 5, "Got wrong samples played\n"); + + HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData); + + if(xaudio27) + IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src); + else + IXAudio2SourceVoice_DestroyVoice(src); + + IXAudio2MasteringVoice_DestroyVoice(master); } static UINT32 test_DeviceDetails(IXAudio27 *xa) @@ -185,7 +485,9 @@ START_TEST(xaudio2) has_devices = test_DeviceDetails(xa27); if(has_devices){ + test_DeviceDetails(xa27); test_simple_streaming((IXAudio2*)xa27); + test_buffer_callbacks((IXAudio2*)xa27); }else skip("No audio devices available\n"); @@ -203,6 +505,7 @@ START_TEST(xaudio2) has_devices = check_has_devices(xa); if(has_devices){ test_simple_streaming(xa); + test_buffer_callbacks(xa); }else skip("No audio devices available\n");