mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-02 20:18:28 +00:00
xaudio2/tests: Add callback tests.
This commit is contained in:
parent
5423b2353b
commit
6abe9f0920
1 changed files with 305 additions and 2 deletions
|
@ -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");
|
||||
|
||||
|
|
Loading…
Reference in a new issue