Andrew Eikum : xaudio2: Ignore buffers returned from OpenAL after Stop.

Alexandre Julliard julliard at winehq.org
Thu Nov 30 14:19:35 CST 2017


Module: wine
Branch: master
Commit: e2c73fc394bace00c4463b6fcb6dfe9dc64084bc
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e2c73fc394bace00c4463b6fcb6dfe9dc64084bc

Author: Andrew Eikum <aeikum at codeweavers.com>
Date:   Thu Nov 30 08:01:53 2017 -0600

xaudio2: Ignore buffers returned from OpenAL after Stop.

Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/xaudio2_7/tests/xaudio2.c  | 78 ++++++++++++++++++++++++++++++++++++++++
 dlls/xaudio2_7/xaudio_dll.c     | 79 +++++++++++++++++++++++++----------------
 dlls/xaudio2_7/xaudio_private.h |  2 +-
 3 files changed, 128 insertions(+), 31 deletions(-)

diff --git a/dlls/xaudio2_7/tests/xaudio2.c b/dlls/xaudio2_7/tests/xaudio2.c
index 54176ea..ff402f8 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 13f5916..8f15ded 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;
-
-            alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
+        if(processed > src->abandoned_albufs){
+            for(i = src->abandoned_albufs; i < processed; ++i){
+                ALint bufsize;
 
-            src->in_al_bytes -= bufsize;
-            src->played_frames += bufsize / src->submit_blocksize;
+                alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
 
-            if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
-                DWORD old_buf = src->first_buf;
+                src->in_al_bytes -= bufsize;
+                src->played_frames += bufsize / src->submit_blocksize;
 
-                src->first_buf++;
-                src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
-                src->nbufs--;
+                if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
+                    DWORD old_buf = src->first_buf;
 
-                TRACE("%p: done with buffer %u\n", src, old_buf);
+                    src->first_buf++;
+                    src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
+                    src->nbufs--;
 
-                if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
-                    src->played_frames = 0;
+                    TRACE("%p: done with buffer %u\n", src, old_buf);
 
-                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->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);
+
+                        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 f28a0ae..1a4aa08 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;




More information about the wine-cvs mailing list