Before https://gitlab.winehq.org/wine/wine/-/merge_requests/140, and to avoid a situation in the future where we might decide to implement this, and where the callback would be called asynchronously as they are supposed to, without the ASF reader filter supporting it.
-- v2: winegstreamer: Make IWMReader state transitions asynchronous. winegstreamer: Move IWMReaderCallbackAdvanced *callback_advanced to a local variable. wmvcore/tests: Add more IWMReader_(Open|Start|Stop|Close) async checks.
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/wmvcore/tests/wmvcore.c | 140 ++++++++++++++++++++++++++++++----- 1 file changed, 122 insertions(+), 18 deletions(-)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index f639184de90..a1a8fa5c44f 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1422,8 +1422,11 @@ struct callback IWMReaderCallbackAdvanced IWMReaderCallbackAdvanced_iface; IWMReaderAllocatorEx IWMReaderAllocatorEx_iface; LONG refcount; - HANDLE got_opened, got_stopped, eof_event; - unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof; + HANDLE expect_opened, got_opened; + HANDLE expect_started, got_started; + HANDLE expect_stopped, got_stopped; + HANDLE eof_event; + unsigned int got_closed, started_count, got_sample, got_end_of_streaming, got_eof; bool all_streams_off; bool allocated_samples;
@@ -1480,6 +1483,7 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta HRESULT hr, WMT_ATTR_DATATYPE type, BYTE *value, void *context) { struct callback *callback = impl_from_IWMReaderCallback(iface); + DWORD ret;
if (winetest_debug > 1) trace("%lu: %04lx: IWMReaderCallback::OnStatus(status %u, hr %#lx, type %#x, value %p)\n", @@ -1491,6 +1495,9 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type); ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xdeadbeef, "Got unexpected context %p.\n", context); + ret = WaitForSingleObject(callback->expect_opened, 100); + todo_wine + ok(!ret, "Wait timed out.\n"); SetEvent(callback->got_opened); break;
@@ -1498,14 +1505,21 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type); ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); + ret = WaitForSingleObject(callback->expect_started, 100); + todo_wine + ok(!ret, "Wait timed out.\n"); callback->got_end_of_streaming = callback->got_eof = callback->got_sample = 0; - ++callback->got_started; + SetEvent(callback->got_started); + ++callback->started_count; break;
case WMT_STOPPED: ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type); ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); + ret = WaitForSingleObject(callback->expect_stopped, 100); + todo_wine + ok(!ret, "Wait timed out.\n"); SetEvent(callback->got_stopped); break;
@@ -1613,7 +1627,7 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, check_async_sample(callback, sample);
ok(!callback->read_compressed, "OnSample() should not be called when reading compressed samples.\n"); - ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started); + ok(callback->started_count > 0, "Got %u WMT_STARTED callbacks.\n", callback->started_count); ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof); ++callback->got_sample;
@@ -1666,7 +1680,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced check_async_sample(callback, sample);
ok(callback->read_compressed, "OnStreamSample() should not be called unless reading compressed samples.\n"); - ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started); + ok(callback->started_count > 0, "Got %u WMT_STARTED callbacks.\n", callback->started_count); ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof); ++callback->got_sample;
@@ -1840,7 +1854,11 @@ static void callback_init(struct callback *callback) callback->IWMReaderCallbackAdvanced_iface.lpVtbl = &callback_advanced_vtbl; callback->IWMReaderAllocatorEx_iface.lpVtbl = &callback_allocator_vtbl; callback->refcount = 1; + callback->expect_opened = CreateEventW(NULL, FALSE, FALSE, NULL); callback->got_opened = CreateEventW(NULL, FALSE, FALSE, NULL); + callback->expect_started = CreateEventW(NULL, FALSE, FALSE, NULL); + callback->got_started = CreateEventW(NULL, FALSE, FALSE, NULL); + callback->expect_stopped = CreateEventW(NULL, FALSE, FALSE, NULL); callback->got_stopped = CreateEventW(NULL, FALSE, FALSE, NULL); callback->eof_event = CreateEventW(NULL, FALSE, FALSE, NULL); callback->ontime_event = CreateEventW(NULL, FALSE, FALSE, NULL); @@ -1849,7 +1867,11 @@ static void callback_init(struct callback *callback) static void callback_cleanup(struct callback *callback) { CloseHandle(callback->got_opened); + CloseHandle(callback->expect_opened); + CloseHandle(callback->got_started); + CloseHandle(callback->expect_started); CloseHandle(callback->got_stopped); + CloseHandle(callback->expect_stopped); CloseHandle(callback->eof_event); CloseHandle(callback->ontime_event); } @@ -1860,13 +1882,22 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st DWORD ret;
callback->got_closed = 0; - callback->got_started = 0; + callback->started_count = 0; callback->got_sample = 0; callback->got_end_of_streaming = 0; callback->got_eof = 0;
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); + ret = WaitForSingleObject(callback->got_started, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback->expect_started); + ret = WaitForSingleObject(callback->got_started, 1000); + ok(!ret, "Wait timed out.\n"); + }
hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1879,8 +1910,15 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); - ret = WaitForSingleObject(callback->got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); + ret = WaitForSingleObject(callback->got_stopped, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback->expect_stopped); + ret = WaitForSingleObject(callback->got_stopped, 1000); + ok(!ret, "Wait timed out.\n"); + }
ok(!outstanding_buffers, "Got %ld outstanding buffers.\n", outstanding_buffers); } @@ -2178,8 +2216,15 @@ static void test_async_reader_streaming(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); + ret = WaitForSingleObject(callback.got_opened, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n"); + }
hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr); @@ -2205,6 +2250,15 @@ static void test_async_reader_streaming(void)
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); + ret = WaitForSingleObject(callback.got_started, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n"); + }
/* By default the reader will time itself, and attempt to deliver samples * according to their presentation time. Call DeliverTime with the file @@ -2235,6 +2289,15 @@ static void test_async_reader_streaming(void)
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); + ret = WaitForSingleObject(callback.got_started, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n"); + }
hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2245,13 +2308,27 @@ static void test_async_reader_streaming(void)
hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); - ret = WaitForSingleObject(callback.got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); + ret = WaitForSingleObject(callback.got_stopped, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback.expect_stopped); + ret = WaitForSingleObject(callback.got_stopped, 1000); + ok(!ret, "Wait timed out.\n"); + }
hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); - ret = WaitForSingleObject(callback.got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); + ret = WaitForSingleObject(callback.got_stopped, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback.expect_stopped); + ret = WaitForSingleObject(callback.got_stopped, 1000); + ok(!ret, "Wait timed out.\n"); + }
test_reader_attributes(profile); test_async_reader_selection(reader, advanced, &callback); @@ -2263,6 +2340,8 @@ static void test_async_reader_streaming(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(callback.got_closed == 1, "Got %u WMT_CLOSED callbacks.\n", callback.got_closed); ok(callback.refcount == 1, "Got outstanding refcount %ld.\n", callback.refcount); + ret = WaitForSingleObject(callback.got_stopped, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); callback_cleanup(&callback);
hr = IWMReader_Stop(reader); @@ -2318,8 +2397,15 @@ static void test_async_reader_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); + ret = WaitForSingleObject(callback.got_opened, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n"); + }
for (i = 0; i < 2; ++i) { @@ -2541,8 +2627,15 @@ static void test_async_reader_file(void) hr = IWMReader_Open(reader, filename, &callback.IWMReaderCallback_iface, (void **)0xdeadbeef); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); + ret = WaitForSingleObject(callback.got_opened, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n"); + }
hr = IWMReader_Open(reader, filename, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr); @@ -2554,11 +2647,22 @@ static void test_async_reader_file(void)
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); + ret = WaitForSingleObject(callback.got_started, 0); + todo_wine + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); + if (ret == WAIT_TIMEOUT) + { + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n"); + }
hr = IWMReader_Close(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(callback.got_closed == 1, "Got %u WMT_CLOSED callbacks.\n", callback.got_closed); ok(callback.refcount == 1, "Got outstanding refcount %ld.\n", callback.refcount); + ret = WaitForSingleObject(callback.got_stopped, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); callback_cleanup(&callback);
hr = IWMReader_Close(reader);
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 4 +--- dlls/winegstreamer/wm_asyncreader.c | 27 +++++++++++++++------------ dlls/winegstreamer/wm_reader.c | 7 +------ dlls/winegstreamer/wm_syncreader.c | 2 +- 4 files changed, 18 insertions(+), 22 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 8348d2e8360..2c3039acbe9 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -180,8 +180,6 @@ struct wm_reader struct wm_stream *streams; WORD stream_count;
- IWMReaderCallbackAdvanced *callback_advanced; - const struct wm_reader_ops *ops; };
@@ -201,7 +199,7 @@ HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps **props); struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number); -HRESULT wm_reader_get_stream_sample(struct wm_reader *reader, WORD stream_number, +HRESULT wm_reader_get_stream_sample(struct wm_reader *reader, IWMReaderCallbackAdvanced *callback_advanced, WORD stream_number, INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags, WORD *ret_stream_number); HRESULT wm_reader_get_stream_selection(struct wm_reader *reader, WORD stream_number, WMT_STREAM_SELECTION *selection); diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index ef6e445a51b..9d8c2be45cb 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -57,22 +57,17 @@ static REFERENCE_TIME get_current_time(const struct async_reader *reader) static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context) { static const DWORD zero; - HRESULT hr;
IWMReaderCallback_AddRef(reader->callback = callback); reader->context = context; IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context); - - if (FAILED(hr = IWMReaderCallback_QueryInterface(callback, - &IID_IWMReaderCallbackAdvanced, (void **)&reader->reader.callback_advanced))) - reader->reader.callback_advanced = NULL; - TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr); }
static DWORD WINAPI stream_thread(void *arg) { struct async_reader *reader = arg; IWMReaderCallback *callback = reader->callback; + IWMReaderCallbackAdvanced *callback_advanced; REFERENCE_TIME start_time; struct wm_stream *stream; static const DWORD zero; @@ -86,9 +81,14 @@ static DWORD WINAPI stream_thread(void *arg)
EnterCriticalSection(&reader->stream_cs);
+ if (FAILED(hr = IWMReaderCallback_QueryInterface(callback, + &IID_IWMReaderCallbackAdvanced, (void **)&callback_advanced))) + callback_advanced = NULL; + TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr); + while (reader->running) { - hr = wm_reader_get_stream_sample(&reader->reader, 0, &sample, &pts, &duration, &flags, &stream_number); + hr = wm_reader_get_stream_sample(&reader->reader, callback_advanced, 0, &sample, &pts, &duration, &flags, &stream_number); if (hr != S_OK) break;
@@ -98,10 +98,10 @@ static DWORD WINAPI stream_thread(void *arg) { QWORD user_time = reader->user_time;
- if (pts > user_time && reader->reader.callback_advanced) + if (pts > user_time && callback_advanced) { LeaveCriticalSection(&reader->stream_cs); - IWMReaderCallbackAdvanced_OnTime(reader->reader.callback_advanced, user_time, reader->context); + IWMReaderCallbackAdvanced_OnTime(callback_advanced, user_time, reader->context); EnterCriticalSection(&reader->stream_cs); }
@@ -126,7 +126,7 @@ static DWORD WINAPI stream_thread(void *arg) { LeaveCriticalSection(&reader->stream_cs); if (stream->read_compressed) - hr = IWMReaderCallbackAdvanced_OnStreamSample(reader->reader.callback_advanced, + hr = IWMReaderCallbackAdvanced_OnStreamSample(callback_advanced, stream_number, pts, duration, flags, sample, reader->context); else hr = IWMReaderCallback_OnSample(callback, stream_number - 1, pts, duration, @@ -148,12 +148,12 @@ static DWORD WINAPI stream_thread(void *arg) IWMReaderCallback_OnStatus(callback, WMT_EOF, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
- if (reader->user_clock && reader->reader.callback_advanced) + if (reader->user_clock && callback_advanced) { /* We can only get here if user_time is greater than the PTS * of all samples, in which case we cannot have sent this * notification already. */ - IWMReaderCallbackAdvanced_OnTime(reader->reader.callback_advanced, + IWMReaderCallbackAdvanced_OnTime(callback_advanced, reader->user_time, reader->context); }
@@ -164,6 +164,9 @@ static DWORD WINAPI stream_thread(void *arg) ERR("Failed to get sample, hr %#lx.\n", hr); }
+ if (callback_advanced) + IWMReaderCallbackAdvanced_Release(callback_advanced); + TRACE("Reader is stopping; exiting.\n"); return 0; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 03adea8a318..8038b61f7a7 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1607,10 +1607,6 @@ HRESULT wm_reader_close(struct wm_reader *reader) CloseHandle(reader->read_thread); reader->read_thread = NULL;
- if (reader->callback_advanced) - IWMReaderCallbackAdvanced_Release(reader->callback_advanced); - reader->callback_advanced = NULL; - wg_parser_destroy(reader->wg_parser); reader->wg_parser = NULL;
@@ -1871,10 +1867,9 @@ static WORD get_earliest_buffer(struct wm_reader *reader, struct wg_parser_buffe return stream_number; }
-HRESULT wm_reader_get_stream_sample(struct wm_reader *reader, WORD stream_number, +HRESULT wm_reader_get_stream_sample(struct wm_reader *reader, IWMReaderCallbackAdvanced *callback_advanced, WORD stream_number, INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags, WORD *ret_stream_number) { - IWMReaderCallbackAdvanced *callback_advanced = reader->callback_advanced; struct wg_parser_stream *wg_stream; struct wg_parser_buffer wg_buffer; struct wm_stream *stream; diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index c7cccd52c4f..c80574b87fd 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -92,7 +92,7 @@ static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface,
EnterCriticalSection(&reader->reader.cs);
- hr = wm_reader_get_stream_sample(&reader->reader, stream_number, sample, pts, duration, flags, &stream_number); + hr = wm_reader_get_stream_sample(&reader->reader, NULL, stream_number, sample, pts, duration, flags, &stream_number); if (output_number && hr == S_OK) *output_number = stream_number - 1; if (ret_stream_number && (hr == S_OK || stream_number))
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/wm_asyncreader.c | 208 +++++++++++++++++++--------- dlls/wmvcore/tests/wmvcore.c | 103 ++++---------- 2 files changed, 175 insertions(+), 136 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index 9d8c2be45cb..1acc7cffbe5 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -40,7 +40,12 @@ struct async_reader CRITICAL_SECTION stream_cs; CONDITION_VARIABLE stream_cv;
- bool running; + enum async_reader_state + { + STATE_CLOSED = 1, + STATE_STOPPED = 2, + STATE_RUNNING = 3, + } state, next_state;
bool user_clock; QWORD user_time; @@ -54,20 +59,62 @@ static REFERENCE_TIME get_current_time(const struct async_reader *reader) return (time.QuadPart * 1000) / reader->clock_frequency.QuadPart * 10000; }
-static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context) +static void execute_state_transition(struct async_reader *reader) { static const DWORD zero;
- IWMReaderCallback_AddRef(reader->callback = callback); - reader->context = context; - IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context); + switch (MAKELONG(reader->state, reader->next_state)) + { + case MAKELONG(STATE_CLOSED, STATE_CLOSED): + break; + case MAKELONG(STATE_CLOSED, STATE_STOPPED): + IWMReaderCallback_OnStatus(reader->callback, WMT_OPENED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + case MAKELONG(STATE_CLOSED, STATE_RUNNING): + break; + + case MAKELONG(STATE_STOPPED, STATE_CLOSED): + IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + case MAKELONG(STATE_STOPPED, STATE_STOPPED): + IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + case MAKELONG(STATE_STOPPED, STATE_RUNNING): + IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + + case MAKELONG(STATE_RUNNING, STATE_RUNNING): + break; + case MAKELONG(STATE_RUNNING, STATE_CLOSED): + IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + case MAKELONG(STATE_RUNNING, STATE_STOPPED): + IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + } + + reader->state = reader->next_state; + reader->next_state = 0; }
-static DWORD WINAPI stream_thread(void *arg) +static void request_state_transition(struct async_reader *reader, enum async_reader_state new_state) +{ + reader->next_state = new_state; + if (!reader->stream_thread) + execute_state_transition(reader); + else + WakeConditionVariable(&reader->stream_cv); +} + +static void stream_thread_running(struct async_reader *reader, IWMReaderCallbackAdvanced *callback_advanced) { - struct async_reader *reader = arg; IWMReaderCallback *callback = reader->callback; - IWMReaderCallbackAdvanced *callback_advanced; REFERENCE_TIME start_time; struct wm_stream *stream; static const DWORD zero; @@ -79,14 +126,7 @@ static DWORD WINAPI stream_thread(void *arg)
start_time = get_current_time(reader);
- EnterCriticalSection(&reader->stream_cs); - - if (FAILED(hr = IWMReaderCallback_QueryInterface(callback, - &IID_IWMReaderCallbackAdvanced, (void **)&callback_advanced))) - callback_advanced = NULL; - TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr); - - while (reader->running) + while (reader->state == STATE_RUNNING) { hr = wm_reader_get_stream_sample(&reader->reader, callback_advanced, 0, &sample, &pts, &duration, &flags, &stream_number); if (hr != S_OK) @@ -105,12 +145,12 @@ static DWORD WINAPI stream_thread(void *arg) EnterCriticalSection(&reader->stream_cs); }
- while (pts > reader->user_time && reader->running) + while (pts > reader->user_time && reader->state == STATE_RUNNING) SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs, INFINITE); } else { - while (reader->running) + while (reader->state == STATE_RUNNING) { REFERENCE_TIME current_time = get_current_time(reader);
@@ -122,7 +162,7 @@ static DWORD WINAPI stream_thread(void *arg) } }
- if (reader->running) + if (reader->state == STATE_RUNNING) { LeaveCriticalSection(&reader->stream_cs); if (stream->read_compressed) @@ -139,46 +179,97 @@ static DWORD WINAPI stream_thread(void *arg) INSSBuffer_Release(sample); }
- LeaveCriticalSection(&reader->stream_cs); - if (hr == NS_E_NO_MORE_SAMPLES) { + BOOL user_clock = reader->user_clock; + QWORD user_time = reader->user_time; + + LeaveCriticalSection(&reader->stream_cs); + IWMReaderCallback_OnStatus(callback, WMT_END_OF_STREAMING, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); IWMReaderCallback_OnStatus(callback, WMT_EOF, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
- if (reader->user_clock && callback_advanced) + if (user_clock && callback_advanced) { /* We can only get here if user_time is greater than the PTS * of all samples, in which case we cannot have sent this * notification already. */ IWMReaderCallbackAdvanced_OnTime(callback_advanced, - reader->user_time, reader->context); + user_time, reader->context); }
+ EnterCriticalSection(&reader->stream_cs); + TRACE("Reached end of stream; exiting.\n"); } else if (hr != S_OK) { ERR("Failed to get sample, hr %#lx.\n", hr); } +} + +static DWORD WINAPI stream_thread(void *arg) +{ + struct async_reader *reader = arg; + IWMReaderCallback *callback = reader->callback; + IWMReaderCallbackAdvanced *callback_advanced; + HRESULT hr = S_OK; + + EnterCriticalSection(&reader->stream_cs); + + if (FAILED(hr = IWMReaderCallback_QueryInterface(callback, + &IID_IWMReaderCallbackAdvanced, (void **)&callback_advanced))) + callback_advanced = NULL; + TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr); + + while (reader->state != STATE_CLOSED || reader->next_state) + { + execute_state_transition(reader); + + if (reader->state == STATE_RUNNING) + { + stream_thread_running(reader, callback_advanced); + if (!reader->next_state) + reader->state = STATE_STOPPED; + } + + while (reader->state != STATE_CLOSED && !reader->next_state) + SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs, INFINITE); + }
if (callback_advanced) IWMReaderCallbackAdvanced_Release(callback_advanced);
+ LeaveCriticalSection(&reader->stream_cs); + TRACE("Reader is stopping; exiting.\n"); return 0; }
-static void stop_streaming(struct async_reader *reader) +static HRESULT open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context) +{ + IWMReaderCallback_AddRef((reader->callback = callback)); + reader->context = context; + reader->state = STATE_CLOSED; + reader->next_state = STATE_STOPPED; + + if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL))) + { + IWMReaderCallback_Release(reader->callback); + reader->callback = NULL; + reader->context = NULL; + return E_OUTOFMEMORY; + } + + return S_OK; +} + +static void close_stream(struct async_reader *reader) { if (reader->stream_thread) { - EnterCriticalSection(&reader->stream_cs); - reader->running = false; - LeaveCriticalSection(&reader->stream_cs); - WakeConditionVariable(&reader->stream_cv); WaitForSingleObject(reader->stream_thread, INFINITE); CloseHandle(reader->stream_thread); reader->stream_thread = NULL; @@ -229,8 +320,9 @@ static HRESULT WINAPI WMReader_Open(IWMReader *iface, const WCHAR *url, return E_UNEXPECTED; }
- if (SUCCEEDED(hr = wm_reader_open_file(&reader->reader, url))) - open_stream(reader, callback, context); + if (SUCCEEDED(hr = wm_reader_open_file(&reader->reader, url)) + && FAILED(hr = open_stream(reader, callback, context))) + wm_reader_close(&reader->reader);
LeaveCriticalSection(&reader->reader.cs); return hr; @@ -239,22 +331,21 @@ static HRESULT WINAPI WMReader_Open(IWMReader *iface, const WCHAR *url, static HRESULT WINAPI WMReader_Close(IWMReader *iface) { struct async_reader *reader = impl_from_IWMReader(iface); - static const DWORD zero; HRESULT hr;
TRACE("reader %p.\n", reader);
EnterCriticalSection(&reader->reader.cs);
- stop_streaming(reader); + EnterCriticalSection(&reader->stream_cs); + request_state_transition(reader, STATE_CLOSED); + LeaveCriticalSection(&reader->stream_cs); + + close_stream(reader);
hr = wm_reader_close(&reader->reader); if (reader->callback) - { - IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK, - WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); IWMReaderCallback_Release(reader->callback); - } reader->callback = NULL;
LeaveCriticalSection(&reader->reader.cs); @@ -315,7 +406,6 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface, QWORD start, QWORD duration, float rate, void *context) { struct async_reader *reader = impl_from_IWMReader(iface); - static const DWORD zero;
TRACE("reader %p, start %s, duration %s, rate %.8e, context %p.\n", reader, debugstr_time(start), debugstr_time(duration), rate, context); @@ -332,24 +422,13 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface, return NS_E_INVALID_REQUEST; }
- stop_streaming(reader); - - IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context); - reader->context = context; - + EnterCriticalSection(&reader->stream_cs); wm_reader_seek(&reader->reader, start, duration); - - reader->running = true; - reader->user_time = 0; - - if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL))) - { - LeaveCriticalSection(&reader->reader.cs); - return E_OUTOFMEMORY; - } + reader->context = context; + request_state_transition(reader, STATE_RUNNING); + LeaveCriticalSection(&reader->stream_cs);
LeaveCriticalSection(&reader->reader.cs); - WakeConditionVariable(&reader->stream_cv);
return S_OK; } @@ -357,7 +436,6 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface, static HRESULT WINAPI WMReader_Stop(IWMReader *iface) { struct async_reader *reader = impl_from_IWMReader(iface); - static const DWORD zero;
TRACE("reader %p.\n", reader);
@@ -370,9 +448,10 @@ static HRESULT WINAPI WMReader_Stop(IWMReader *iface) return E_UNEXPECTED; }
- stop_streaming(reader); - IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK, - WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + EnterCriticalSection(&reader->stream_cs); + request_state_transition(reader, STATE_STOPPED); + LeaveCriticalSection(&reader->stream_cs); + LeaveCriticalSection(&reader->reader.cs); return S_OK; } @@ -732,8 +811,9 @@ static HRESULT WINAPI WMReaderAdvanced2_OpenStream(IWMReaderAdvanced6 *iface, return E_UNEXPECTED; }
- if (SUCCEEDED(hr = wm_reader_open_stream(&reader->reader, stream))) - open_stream(reader, callback, context); + if (SUCCEEDED(hr = wm_reader_open_stream(&reader->reader, stream)) + && FAILED(hr = open_stream(reader, callback, context))) + wm_reader_close(&reader->reader);
LeaveCriticalSection(&reader->reader.cs); return hr; @@ -1588,11 +1668,13 @@ static void async_reader_destroy(struct wm_reader *iface)
TRACE("reader %p.\n", reader);
- if (reader->stream_thread) - { - WaitForSingleObject(reader->stream_thread, INFINITE); - CloseHandle(reader->stream_thread); - } + EnterCriticalSection(&reader->stream_cs); + reader->state = STATE_CLOSED; + reader->next_state = 0; + LeaveCriticalSection(&reader->stream_cs); + WakeConditionVariable(&reader->stream_cv); + + close_stream(reader);
reader->stream_cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&reader->stream_cs); diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index a1a8fa5c44f..ec3738ad4a4 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1496,7 +1496,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xdeadbeef, "Got unexpected context %p.\n", context); ret = WaitForSingleObject(callback->expect_opened, 100); - todo_wine ok(!ret, "Wait timed out.\n"); SetEvent(callback->got_opened); break; @@ -1506,7 +1505,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); ret = WaitForSingleObject(callback->expect_started, 100); - todo_wine ok(!ret, "Wait timed out.\n"); callback->got_end_of_streaming = callback->got_eof = callback->got_sample = 0; SetEvent(callback->got_started); @@ -1518,7 +1516,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); ret = WaitForSingleObject(callback->expect_stopped, 100); - todo_wine ok(!ret, "Wait timed out.\n"); SetEvent(callback->got_stopped); break; @@ -1890,14 +1887,10 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback->got_started, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback->expect_started); - ret = WaitForSingleObject(callback->got_started, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback->expect_started); + ret = WaitForSingleObject(callback->got_started, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1911,14 +1904,10 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback->got_stopped, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback->expect_stopped); - ret = WaitForSingleObject(callback->got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback->expect_stopped); + ret = WaitForSingleObject(callback->got_stopped, 1000); + ok(!ret, "Wait timed out.\n");
ok(!outstanding_buffers, "Got %ld outstanding buffers.\n", outstanding_buffers); } @@ -2217,14 +2206,10 @@ static void test_async_reader_streaming(void) ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); ret = WaitForSingleObject(callback.got_opened, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_opened); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr); @@ -2251,14 +2236,10 @@ static void test_async_reader_streaming(void) hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_started, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_started); - ret = WaitForSingleObject(callback.got_started, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n");
/* By default the reader will time itself, and attempt to deliver samples * according to their presentation time. Call DeliverTime with the file @@ -2290,14 +2271,10 @@ static void test_async_reader_streaming(void) hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_started, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_started); - ret = WaitForSingleObject(callback.got_started, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2309,26 +2286,18 @@ static void test_async_reader_streaming(void) hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_stopped, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_stopped); - ret = WaitForSingleObject(callback.got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_stopped); + ret = WaitForSingleObject(callback.got_stopped, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_stopped, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_stopped); - ret = WaitForSingleObject(callback.got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_stopped); + ret = WaitForSingleObject(callback.got_stopped, 1000); + ok(!ret, "Wait timed out.\n");
test_reader_attributes(profile); test_async_reader_selection(reader, advanced, &callback); @@ -2398,14 +2367,10 @@ static void test_async_reader_types(void) ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); ret = WaitForSingleObject(callback.got_opened, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_opened); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n");
for (i = 0; i < 2; ++i) { @@ -2628,14 +2593,10 @@ static void test_async_reader_file(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); ret = WaitForSingleObject(callback.got_opened, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_opened); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReader_Open(reader, filename, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr); @@ -2648,14 +2609,10 @@ static void test_async_reader_file(void) hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_started, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_started); - ret = WaitForSingleObject(callback.got_started, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReader_Close(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr);
The third patch is causing intermittent failures for me, along these lines:
wmvcore.c:1628: Test failed: Got 1 WMT_EOF callbacks. wmvcore.c:1628: Test failed: Got 1 WMT_EOF callbacks. wmvcore.c:1534: Test failed: Got 1 WMT_EOF callbacks. wmvcore.c:1546: Test failed: Got 2 WMT_END_OF_STREAMING callbacks. wmvcore.c:2277: Test failed: Wait timed out. wmvcore.c:2284: Test failed: Got 2 WMT_EOF callbacks.
The first line is repeated many times.
FWIW, I can consistently reproduce within a short period of time by adding the following diff:
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index ec3738ad4a4..a0246147cb0 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -2654,7 +2654,8 @@ START_TEST(wmvcore) test_sync_reader_streaming(); test_sync_reader_types(); test_sync_reader_file(); - test_async_reader_streaming(); + while (!winetest_get_failures()) + test_async_reader_streaming(); test_async_reader_types(); test_async_reader_file();
I'd sign off on the first two patches, but alas, gitlab doesn't allow for that...
I think we need to be able to buffer multiple state transitions. Consider the following diff on top of patch 1/3, which mostly passes the tests:
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index ec3738ad4a4..6995b231633 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1901,6 +1901,8 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ok(!ret, "Wait timed out.\n"); ok(callback->got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
+ hr = IWMReader_Stop(reader); + ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback->got_stopped, 0); @@ -1908,6 +1910,9 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st SetEvent(callback->expect_stopped); ret = WaitForSingleObject(callback->got_stopped, 1000); ok(!ret, "Wait timed out.\n"); + SetEvent(callback->expect_stopped); + ret = WaitForSingleObject(callback->got_stopped, 1000); + ok(!ret, "Wait timed out.\n");
ok(!outstanding_buffers, "Got %ld outstanding buffers.\n", outstanding_buffers); }
On 7/26/22 03:04, Rémi Bernon wrote:
+static DWORD WINAPI stream_thread(void *arg) +{
- struct async_reader *reader = arg;
- IWMReaderCallback *callback = reader->callback;
- IWMReaderCallbackAdvanced *callback_advanced;
- HRESULT hr = S_OK;
- EnterCriticalSection(&reader->stream_cs);
- if (FAILED(hr = IWMReaderCallback_QueryInterface(callback,
&IID_IWMReaderCallbackAdvanced, (void **)&callback_advanced)))
callback_advanced = NULL;
- TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr);
- while (reader->state != STATE_CLOSED || reader->next_state)
- {
execute_state_transition(reader);
if (reader->state == STATE_RUNNING)
{
stream_thread_running(reader, callback_advanced);
if (!reader->next_state)
reader->state = STATE_STOPPED;
}
while (reader->state != STATE_CLOSED && !reader->next_state)
SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs, INFINITE);
- }
It's not a huge deal, since stream_thread_running() already does this, but do you think you could write this in a way that doesn't need a nested loop?
v2: Do not reset user time on `Start`.