This fixes a looping audio issue during seek in VRChat. The issue is that on Windows the stop request in handled immediately thus the AVPro MFT (which loops the audio) can be immediately flushed. Wine currently waits for a pending sample request to be completed before handling the stop request. As a result, the AVPro MFT loops audio whilst it waits for another sample (or to be flushed).
This MR releases the source CS before calling `wg_parser_stream_get_buffer` so it does not delay the handling of the stop request. This appears to be safe as the Unix side of `wg_parser_stream_get_buffer` has its own set of primitives.
-- v2: winegstreamer: Don't hold lock during wg_parser_stream_get_buffer. winegstreamer: Signal eos on disconnect.
From: Brendan McGrath bmcgrath@codeweavers.com
--- dlls/winegstreamer/wg_parser.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index e806298fb57..1a29015356e 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1792,7 +1792,9 @@ static NTSTATUS wg_parser_disconnect(void *args) for (i = 0; i < parser->stream_count; ++i) { parser->streams[i]->flushing = true; + parser->streams[i]->eos = true; pthread_cond_signal(&parser->streams[i]->event_empty_cond); + pthread_cond_signal(&parser->streams[i]->event_cond); } pthread_mutex_unlock(&parser->mutex);
From: Brendan McGrath bmcgrath@codeweavers.com
--- dlls/winegstreamer/media_source.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ab842b3e438..15f65cb41cb 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -791,6 +791,20 @@ static HRESULT media_stream_send_eos(struct media_source *source, struct media_s return S_OK; }
+static bool stream_get_buffer(struct media_stream *stream, struct wg_parser_buffer *buffer) +{ + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + wg_parser_stream_t wg_stream = stream->wg_stream; + wg_parser_t wg_parser = source->wg_parser; + bool ret; + + LeaveCriticalSection(&source->cs); + ret = wg_parser_stream_get_buffer(wg_parser, wg_stream, buffer); + EnterCriticalSection(&source->cs); + + return ret; +} + static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token) { struct media_source *source = impl_from_IMFMediaSource(stream->media_source); @@ -798,7 +812,7 @@ static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token)
TRACE("%p, %p\n", stream, token);
- while (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer)) + while (stream_get_buffer(stream, &buffer)) { HRESULT hr = media_stream_send_sample(stream, &buffer, token); if (hr != S_FALSE)
Oops. Not as safe as I thought. One of the `mfmediaengine` tests failed. Looks like we can now be waiting on `stream->event_cond` within `wait_parser_stream_buffer` when `wg_parser_disconnect` is called, which was previously not possible.
So I've just added another commit that sets `eos` and signals `stream->event_cond` within `wg_parser_disconnect`. This fixes the failing test.