[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