[PATCH 1/5] amstream: Wait for the state transition to complete in AMMultiMediaStream::SetState.

Anton Baskanov baskanov at gmail.com
Thu Oct 22 14:06:12 CDT 2020


Signed-off-by: Anton Baskanov <baskanov at gmail.com>
---
 dlls/amstream/multimedia.c     |  4 ++
 dlls/amstream/tests/amstream.c | 84 ++++++++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+)

diff --git a/dlls/amstream/multimedia.c b/dlls/amstream/multimedia.c
index 82ef4822344..967baacb747 100644
--- a/dlls/amstream/multimedia.c
+++ b/dlls/amstream/multimedia.c
@@ -156,7 +156,11 @@ static HRESULT WINAPI multimedia_stream_SetState(IAMMultiMediaStream *iface, STR
     {
         hr = IMediaControl_Run(This->media_control);
         if (SUCCEEDED(hr))
+        {
+            FILTER_STATE state;
+            IMediaControl_GetState(This->media_control, INFINITE, (OAFilterState *)&state);
             hr = S_OK;
+        }
     }
     else if (new_state == STREAMSTATE_STOP)
         hr = IMediaControl_Stop(This->media_control);
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c
index b436840e407..cb2b3dd76db 100644
--- a/dlls/amstream/tests/amstream.c
+++ b/dlls/amstream/tests/amstream.c
@@ -924,11 +924,13 @@ struct testfilter
     LONGLONG current_position;
     LONGLONG stop_position;
     const AM_MEDIA_TYPE *preferred_mt;
+    CONDITION_VARIABLE wait_state_cv;
     HRESULT get_duration_hr;
     HRESULT get_stop_position_hr;
     HRESULT set_positions_hr;
     HRESULT init_stream_hr;
     HRESULT cleanup_stream_hr;
+    HRESULT wait_state_hr;
 };
 
 static inline struct testfilter *impl_from_BaseFilter(struct strmbase_filter *iface)
@@ -971,12 +973,37 @@ static HRESULT testfilter_cleanup_stream(struct strmbase_filter *iface)
     return filter->cleanup_stream_hr;
 }
 
+static HRESULT testfilter_wait_state(struct strmbase_filter *iface, DWORD timeout)
+{
+    struct testfilter *filter = impl_from_BaseFilter(iface);
+    DWORD start_time = GetTickCount();
+    DWORD elapsed = 0;
+    HRESULT hr;
+
+    EnterCriticalSection(&filter->filter.csFilter);
+
+    while (filter->wait_state_hr == VFW_S_STATE_INTERMEDIATE && elapsed < timeout)
+    {
+        DWORD sleep_time = timeout - elapsed;
+        if (!SleepConditionVariableCS(&filter->wait_state_cv, &filter->filter.csFilter, sleep_time))
+            break;
+        elapsed = GetTickCount() - start_time;
+    }
+
+    hr = filter->wait_state_hr;
+
+    LeaveCriticalSection(&filter->filter.csFilter);
+
+    return hr;
+}
+
 static const struct strmbase_filter_ops testfilter_ops =
 {
     .filter_get_pin = testfilter_get_pin,
     .filter_destroy = testfilter_destroy,
     .filter_init_stream = testfilter_init_stream,
     .filter_cleanup_stream = testfilter_cleanup_stream,
+    .filter_wait_state = testfilter_wait_state,
 };
 
 static inline struct testfilter *impl_from_base_pin(struct strmbase_pin *iface)
@@ -1060,6 +1087,7 @@ static void testfilter_init(struct testfilter *filter)
     strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
     strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
     filter->stop_position = 0x8000000000000000ULL;
+    InitializeConditionVariable(&filter->wait_state_cv);
 }
 
 static inline struct testfilter *impl_from_IMediaSeeking(IMediaSeeking *iface)
@@ -2319,11 +2347,25 @@ static void test_initialize(void)
     IUnknown_Release(graph_inner_unk);
 }
 
+static IAMMultiMediaStream *mmstream_mmstream;
+static STREAM_STATE mmstream_state;
+
+static DWORD CALLBACK mmstream_set_state(void *param)
+{
+    HRESULT hr;
+
+    hr = IAMMultiMediaStream_SetState(mmstream_mmstream, mmstream_state);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    return 0;
+}
+
 static void test_set_state(void)
 {
     IAMMultiMediaStream *mmstream = create_ammultimediastream();
     struct testfilter source;
     IGraphBuilder *graph;
+    HANDLE thread;
     HRESULT hr;
     ULONG ref;
 
@@ -2353,6 +2395,41 @@ static void test_set_state(void)
     hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
 
+    source.wait_state_hr = E_FAIL;
+    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    source.wait_state_hr = S_OK;
+    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
+
+    mmstream_mmstream = mmstream;
+    mmstream_state = STREAMSTATE_RUN;
+    thread = CreateThread(NULL, 0, mmstream_set_state, NULL, 0, NULL);
+
+    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "SetState returned prematurely.\n");
+
+    EnterCriticalSection(&source.filter.csFilter);
+    source.wait_state_hr = S_OK;
+    WakeAllConditionVariable(&source.wait_state_cv);
+    LeaveCriticalSection(&source.filter.csFilter);
+
+    ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
+    CloseHandle(thread);
+
+    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    source.init_stream_hr = E_FAIL;
+    source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
+    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
+    ok(hr == E_FAIL, "Got hr %#x.\n", hr);
+    source.init_stream_hr = S_OK;
+    source.wait_state_hr = S_OK;
+    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
     hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
     source.cleanup_stream_hr = E_FAIL;
@@ -2369,6 +2446,13 @@ static void test_set_state(void)
     ok(hr == S_FALSE, "Got hr %#x.\n", hr);
     source.cleanup_stream_hr = S_OK;
 
+    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
+    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    source.wait_state_hr = S_OK;
+
     ref = IAMMultiMediaStream_Release(mmstream);
     ok(!ref, "Got outstanding refcount %d.\n", ref);
     ref = IGraphBuilder_Release(graph);
-- 
2.17.1




More information about the wine-devel mailing list