For bug 40963.
Signed-off-by: Andrew Eikum <aeikum(a)codeweavers.com>
---
dlls/xaudio2_7/tests/xaudio2.c | 78 +++++++++++++++++++++++++++++++++++++++++
dlls/xaudio2_7/xaudio_dll.c | 77 +++++++++++++++++++++++++---------------
dlls/xaudio2_7/xaudio_private.h | 2 +-
3 files changed, 127 insertions(+), 30 deletions(-)
diff --git a/dlls/xaudio2_7/tests/xaudio2.c b/dlls/xaudio2_7/tests/xaudio2.c
index 54176eaf86..ff402f87c4 100644
--- a/dlls/xaudio2_7/tests/xaudio2.c
+++ b/dlls/xaudio2_7/tests/xaudio2.c
@@ -841,6 +841,82 @@ static void test_submix(IXAudio2 *xa)
IXAudio2MasteringVoice_DestroyVoice(master);
}
+static void test_flush(IXAudio2 *xa)
+{
+ HRESULT hr;
+ IXAudio2MasteringVoice *master;
+ IXAudio2SourceVoice *src;
+ WAVEFORMATEX fmt;
+ XAUDIO2_BUFFER buf;
+ XAUDIO2_VOICE_STATE state;
+
+ 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, NULL, NULL, NULL);
+ ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
+
+ memset(&buf, 0, sizeof(buf));
+ buf.AudioBytes = 22050 * fmt.nBlockAlign;
+ buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes);
+ fill_buf((float*)buf.pAudioData, &fmt, 440, 22050);
+
+ 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 >= 2205)
+ break;
+ Sleep(10);
+ }
+
+ hr = IXAudio2SourceVoice_Stop(src, 0, XAUDIO2_COMMIT_NOW);
+ ok(hr == S_OK, "Stop failed: %08x\n", hr);
+
+ hr = IXAudio2SourceVoice_FlushSourceBuffers(src);
+ ok(hr == S_OK, "FlushSourceBuffers failed: %08x\n", hr);
+
+ hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW);
+ ok(hr == S_OK, "Start failed: %08x\n", hr);
+
+ Sleep(100);
+
+ hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
+ ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
+
+ if(xaudio27){
+ IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src);
+ }else{
+ IXAudio2SourceVoice_DestroyVoice(src);
+ }
+ IXAudio2MasteringVoice_DestroyVoice(master);
+
+ HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData);
+}
+
static UINT32 test_DeviceDetails(IXAudio27 *xa)
{
HRESULT hr;
@@ -1136,6 +1212,7 @@ START_TEST(xaudio2)
test_buffer_callbacks((IXAudio2*)xa27);
test_looping((IXAudio2*)xa27);
test_submix((IXAudio2*)xa27);
+ test_flush((IXAudio2*)xa27);
}else
skip("No audio devices available\n");
@@ -1159,6 +1236,7 @@ START_TEST(xaudio2)
test_buffer_callbacks(xa);
test_looping(xa);
test_submix(xa);
+ test_flush(xa);
}else
skip("No audio devices available\n");
diff --git a/dlls/xaudio2_7/xaudio_dll.c b/dlls/xaudio2_7/xaudio_dll.c
index 13f591630f..8f15ded023 100644
--- a/dlls/xaudio2_7/xaudio_dll.c
+++ b/dlls/xaudio2_7/xaudio_dll.c
@@ -414,6 +414,7 @@ static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface)
This->nbufs = 0;
This->first_buf = 0;
This->cur_buf = 0;
+ This->abandoned_albufs = 0;
LeaveCriticalSection(&This->lock);
}
@@ -438,11 +439,18 @@ static HRESULT WINAPI XA2SRC_Stop(IXAudio2SourceVoice *iface, UINT32 Flags,
UINT32 OperationSet)
{
XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+ ALint bufs;
TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
+ palcSetThreadContext(This->xa2->al_ctx);
+
EnterCriticalSection(&This->lock);
+ alGetSourcei(This->al_src, AL_BUFFERS_QUEUED, &bufs);
+
+ This->abandoned_albufs = bufs;
+
This->running = FALSE;
LeaveCriticalSection(&This->lock);
@@ -2273,44 +2281,53 @@ static void update_source_state(XA2SourceImpl *src)
ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
alSourceUnqueueBuffers(src->al_src, processed, al_buffers);
+
src->first_al_buf += processed;
src->first_al_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
src->al_bufs_used -= processed;
- for(i = 0; i < processed; ++i){
- ALint bufsize;
+ if(processed > src->abandoned_albufs){
+ for(i = src->abandoned_albufs; i < processed; ++i){
+ ALint bufsize;
- alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
+ alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
- src->in_al_bytes -= bufsize;
- src->played_frames += bufsize / src->submit_blocksize;
+ src->in_al_bytes -= bufsize;
+ src->played_frames += bufsize / src->submit_blocksize;
- if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
- DWORD old_buf = src->first_buf;
+ if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
+ DWORD old_buf = src->first_buf;
- src->first_buf++;
- src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
- src->nbufs--;
+ src->first_buf++;
+ src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
+ src->nbufs--;
- TRACE("%p: done with buffer %u\n", src, old_buf);
+ TRACE("%p: done with buffer %u\n", src, old_buf);
- if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
- src->played_frames = 0;
-
- if(src->cb){
- IXAudio2VoiceCallback_OnBufferEnd(src->cb,
- src->buffers[old_buf].xa2buffer.pContext);
if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
- IXAudio2VoiceCallback_OnStreamEnd(src->cb);
+ src->played_frames = 0;
- if(src->nbufs > 0)
- IXAudio2VoiceCallback_OnBufferStart(src->cb,
- src->buffers[src->first_buf].xa2buffer.pContext);
+ if(src->cb){
+ IXAudio2VoiceCallback_OnBufferEnd(src->cb,
+ src->buffers[old_buf].xa2buffer.pContext);
+ if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
+ IXAudio2VoiceCallback_OnStreamEnd(src->cb);
+
+ if(src->nbufs > 0)
+ IXAudio2VoiceCallback_OnBufferStart(src->cb,
+ src->buffers[src->first_buf].xa2buffer.pContext);
+ }
}
}
- }
+
+ src->abandoned_albufs = 0;
+ }else
+ src->abandoned_albufs -= processed;
}
+ if(!src->running)
+ return;
+
alGetSourcei(src->al_src, AL_BYTE_OFFSET, &bufpos);
/* maintain IN_AL_PERIODS periods in AL */
@@ -2384,12 +2401,12 @@ static void do_engine_tick(IXAudio2Impl *This)
EnterCriticalSection(&src->lock);
- if(!src->in_use || !src->running){
+ if(!src->in_use){
LeaveCriticalSection(&src->lock);
continue;
}
- if(src->cb){
+ if(src->cb && This->running){
#if XAUDIO2_VER == 0
IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback*)src->cb);
#else
@@ -2403,12 +2420,14 @@ static void do_engine_tick(IXAudio2Impl *This)
update_source_state(src);
- alGetSourcei(src->al_src, AL_SOURCE_STATE, &st);
- if(st != AL_PLAYING)
- alSourcePlay(src->al_src);
+ if(This->running){
+ alGetSourcei(src->al_src, AL_SOURCE_STATE, &st);
+ if(st != AL_PLAYING)
+ alSourcePlay(src->al_src);
- if(src->cb)
- IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src->cb);
+ if(src->cb)
+ IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src->cb);
+ }
LeaveCriticalSection(&src->lock);
}
diff --git a/dlls/xaudio2_7/xaudio_private.h b/dlls/xaudio2_7/xaudio_private.h
index f28a0aec47..1a4aa08ce5 100644
--- a/dlls/xaudio2_7/xaudio_private.h
+++ b/dlls/xaudio2_7/xaudio_private.h
@@ -81,7 +81,7 @@ typedef struct _XA2SourceImpl {
/* most cases will only need about 4 AL buffers, but some corner cases
* could require up to MAX_QUEUED_BUFFERS */
ALuint al_bufs[XAUDIO2_MAX_QUEUED_BUFFERS];
- DWORD first_al_buf, al_bufs_used;
+ DWORD first_al_buf, al_bufs_used, abandoned_albufs;
struct list entry;
} XA2SourceImpl;
--
2.15.0