[PATCH 2/2] mf/sar: Request a new sample immediately if the buffer is too empty.

Giovanni Mascellani gmascellani at codeweavers.com
Mon Jun 21 10:52:54 CDT 2021


The IAudioClient implementation from both Windows and winepulse.drv
never sets the event more than once per period, which is usually
around 10 ms long. Some codecs produce audio samples shorter than
10 ms, which currently result into the SAR not being able to keep
up with the audio client, because the SAR never requests more than
a sample per event cycle.

This patch causes the event to be set each time the available buffer
space is less then half full, and each time a sample is received,
so that short samples do not lead to audio client underruns.

Of course it would be even better if the codecs didn't generate
too short samples, because they uselessly require more CPU cycle,
but we should handle them properly anyway.

This patch fixes audio stuttering problems in the logo videos
of Borderlands 3, Deep Rock Galactic and probably other games.

Signed-off-by: Giovanni Mascellani <gmascellani at codeweavers.com>
---
 dlls/mf/sar.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c
index eba822ae0fe..1916cbd50c9 100644
--- a/dlls/mf/sar.c
+++ b/dlls/mf/sar.c
@@ -1360,6 +1360,7 @@ static HRESULT WINAPI audio_renderer_stream_ProcessSample(IMFStreamSink *iface,
     if (renderer->state == STREAM_STATE_RUNNING)
         hr = stream_queue_sample(renderer, sample);
     renderer->flags &= ~SAR_SAMPLE_REQUESTED;
+    SetEvent(renderer->buffer_ready_event);
     LeaveCriticalSection(&renderer->cs);
 
     return hr;
@@ -1757,6 +1758,7 @@ static void audio_renderer_render(struct audio_renderer *renderer, IMFAsyncResul
     IMFMediaBuffer *buffer;
     BYTE *dst, *src;
     HRESULT hr;
+    BOOL retry_immediately = FALSE;
 
     LIST_FOR_EACH_ENTRY_SAFE(obj, obj2, &renderer->queue, struct queued_object, entry)
     {
@@ -1780,6 +1782,7 @@ static void audio_renderer_render(struct audio_renderer *renderer, IMFAsyncResul
                                 max_frames -= pad_frames;
                                 src_frames -= obj->u.sample.frame_offset;
                                 dst_frames = min(src_frames, max_frames);
+                                retry_immediately = max_frames - dst_frames > dst_frames;
 
                                 if (SUCCEEDED(hr = IAudioRenderClient_GetBuffer(renderer->audio_render_client, dst_frames, &dst)))
                                 {
@@ -1814,6 +1817,8 @@ static void audio_renderer_render(struct audio_renderer *renderer, IMFAsyncResul
         renderer->flags |= SAR_SAMPLE_REQUESTED;
     }
 
+    if (retry_immediately)
+        SetEvent(renderer->buffer_ready_event);
     if (FAILED(hr = MFPutWaitingWorkItem(renderer->buffer_ready_event, 0, result, &renderer->buffer_ready_key)))
         WARN("Failed to submit wait item, hr %#x.\n", hr);
 }
-- 
2.32.0




More information about the wine-devel mailing list