diff --git a/dlls/xaudio2_7/tests/xaudio2.c b/dlls/xaudio2_7/tests/xaudio2.c index 54176eaf86e..ff402f87c4f 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 13f591630fd..8f15ded0236 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 f28a0aec477..1a4aa08ce5f 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;