[PATCH 3/8] quartz/tests: Add more tests for asynchronous state change.
Zebediah Figura
z.figura12 at gmail.com
Tue Jul 14 19:56:21 CDT 2020
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/quartz/tests/filtergraph.c | 199 ++++++++++++++++++++++++++++++--
1 file changed, 190 insertions(+), 9 deletions(-)
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index de8e32034f8..c0076191a87 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -1173,7 +1173,7 @@ struct testfilter
struct testpin *pins;
unsigned int pin_count, enum_idx;
- HRESULT state_hr, seek_hr;
+ HRESULT state_hr, GetState_hr, seek_hr;
IAMFilterMiscFlags IAMFilterMiscFlags_iface;
ULONG misc_flags;
@@ -1393,7 +1393,7 @@ static HRESULT WINAPI testfilter_GetState(IBaseFilter *iface, DWORD timeout, FIL
if (winetest_debug > 1) trace("%p->GetState(%u)\n", filter, timeout);
*state = filter->state;
- return filter->state_hr;
+ return filter->GetState_hr;
}
static HRESULT WINAPI testfilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
@@ -3199,6 +3199,7 @@ static void test_filter_state(void)
REFERENCE_TIME start_time;
IReferenceClock *clock;
IMediaControl *control;
+ FILTER_STATE mf_state;
IMediaFilter *filter;
OAFilterState state;
HRESULT hr;
@@ -3402,33 +3403,213 @@ todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Stopped);
+ /* Test asynchronous state change. */
+
sink.state_hr = S_FALSE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
hr = IMediaControl_Pause(control);
ok(hr == S_FALSE, "Got hr %#x.\n", hr);
- sink.state_hr = VFW_S_STATE_INTERMEDIATE;
hr = IMediaControl_GetState(control, 0, &state);
ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
ok(state == State_Paused, "Got state %u.\n", state);
- sink.state_hr = VFW_S_CANT_CUE;
+ sink.state_hr = sink.GetState_hr = S_OK;
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(state == State_Paused, "Got state %u.\n", state);
+
+ sink.state_hr = S_FALSE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+ ok(state == State_Stopped, "Got state %u.\n", state);
+
+ sink.state_hr = sink.GetState_hr = S_OK;
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(state == State_Stopped, "Got state %u.\n", state);
+
+ /* Renderers are expected to block completing a state change into paused
+ * until they receive a sample. Because the graph can transition from
+ * stopped -> paused -> running in one call, which itself needs to be
+ * asynchronous, it actually waits on a separate thread for all filters
+ * to be ready, then calls IMediaFilter::Run() once they are.
+ *
+ * However, IMediaControl::GetState() will return VFW_S_STATE_INTERMEDIATE
+ * if filters haven't caught up to the graph yet. To make matters worse, it
+ * doesn't take the above into account, meaning that it'll gladly return
+ * VFW_S_STATE_INTERMEDIATE even if passed an infinite timeout. */
+
+ sink.state_hr = S_FALSE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
+ hr = IMediaControl_Run(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+ ok(state == State_Running, "Got state %u.\n", state);
+ todo_wine ok(sink.state == State_Paused, "Got state %u.\n", sink.state);
+ todo_wine ok(source.state == State_Paused, "Got state %u.\n", source.state);
+
+ hr = IMediaControl_Run(control);
+ todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+ ok(state == State_Running, "Got state %u.\n", state);
+ todo_wine ok(sink.state == State_Paused, "Got state %u.\n", sink.state);
+ todo_wine ok(source.state == State_Paused, "Got state %u.\n", source.state);
+
+ sink.state_hr = sink.GetState_hr = S_OK;
+
+ while ((hr = IMediaControl_GetState(control, INFINITE, &state)) == VFW_S_STATE_INTERMEDIATE)
+ {
+ ok(state == State_Running, "Got state %u.\n", state);
+ todo_wine ok(sink.state == State_Paused, "Got state %u.\n", sink.state);
+ todo_wine ok(source.state == State_Paused, "Got state %u.\n", source.state);
+ Sleep(10);
+ }
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(state == State_Running, "Got state %u.\n", state);
+ ok(sink.state == State_Running, "Got state %u.\n", sink.state);
+ ok(source.state == State_Running, "Got state %u.\n", source.state);
+
+ /* The above logic does not apply to the running -> paused -> stopped
+ * transition. The filter graph will stop a filter regardless of whether
+ * it's completely paused. Inasmuch as stopping the filter is like flushing
+ * it—i.e. it has to succeed—this makes sense. */
+
+ sink.state_hr = S_FALSE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+ ok(sink.state == State_Stopped, "Got state %u.\n", sink.state);
+ ok(source.state == State_Stopped, "Got state %u.\n", source.state);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+ ok(state == State_Stopped, "Got state %u.\n", state);
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ sink.state_hr = sink.GetState_hr = S_OK;
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(state == State_Stopped, "Got state %u.\n", state);
+
+ /* Try an asynchronous stopped->paused->running transition, but pause or
+ * stop the graph before our filter is completely paused. */
+
+ sink.state_hr = S_FALSE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
+ hr = IMediaControl_Run(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ sink.state_hr = sink.GetState_hr = S_OK;
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(state == State_Paused, "Got state %u.\n", state);
+ ok(sink.state == State_Paused, "Got state %u.\n", sink.state);
+ ok(source.state == State_Paused, "Got state %u.\n", source.state);
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ sink.state_hr = S_FALSE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
+ hr = IMediaControl_Run(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+ ok(sink.state == State_Stopped, "Got state %u.\n", sink.state);
+ ok(source.state == State_Stopped, "Got state %u.\n", source.state);
+
+ sink.state_hr = sink.GetState_hr = S_OK;
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(state == State_Stopped, "Got state %u.\n", state);
+ ok(sink.state == State_Stopped, "Got state %u.\n", sink.state);
+ ok(source.state == State_Stopped, "Got state %u.\n", source.state);
+
+ /* This logic doesn't apply when using IMediaFilter methods directly. */
+
+ sink.state_hr = S_FALSE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
+ hr = IMediaFilter_Run(filter, 0);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ hr = IMediaFilter_GetState(filter, 0, &mf_state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+ ok(mf_state == State_Running, "Got state %u.\n", mf_state);
+ ok(sink.state == State_Running, "Got state %u.\n", sink.state);
+ ok(source.state == State_Running, "Got state %u.\n", source.state);
+
+ sink.state_hr = sink.GetState_hr = S_OK;
+ hr = IMediaFilter_GetState(filter, 0, &mf_state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(mf_state == State_Running, "Got state %u.\n", mf_state);
+ ok(sink.state == State_Running, "Got state %u.\n", sink.state);
+ ok(source.state == State_Running, "Got state %u.\n", source.state);
+
+ hr = IMediaFilter_Stop(filter);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(sink.state == State_Stopped, "Got state %u.\n", sink.state);
+ ok(source.state == State_Stopped, "Got state %u.\n", source.state);
+
+ /* Test VFW_S_CANT_CUE. */
+
+ sink.GetState_hr = VFW_S_CANT_CUE;
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
hr = IMediaControl_GetState(control, 0, &state);
ok(hr == VFW_S_CANT_CUE, "Got hr %#x.\n", hr);
ok(state == State_Paused, "Got state %u.\n", state);
- sink.state_hr = VFW_S_STATE_INTERMEDIATE;
- source.state_hr = VFW_S_CANT_CUE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
+ source.GetState_hr = VFW_S_CANT_CUE;
hr = IMediaControl_GetState(control, 0, &state);
ok(hr == VFW_S_CANT_CUE, "Got hr %#x.\n", hr);
ok(state == State_Paused, "Got state %u.\n", state);
- sink.state_hr = VFW_S_CANT_CUE;
- source.state_hr = VFW_S_STATE_INTERMEDIATE;
+ sink.GetState_hr = VFW_S_CANT_CUE;
+ source.GetState_hr = VFW_S_STATE_INTERMEDIATE;
hr = IMediaControl_GetState(control, 0, &state);
ok(hr == VFW_S_CANT_CUE, "Got hr %#x.\n", hr);
ok(state == State_Paused, "Got state %u.\n", state);
- sink.state_hr = source.state_hr = S_OK;
+ sink.GetState_hr = source.GetState_hr = S_OK;
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ sink.state_hr = S_FALSE;
+ sink.GetState_hr = VFW_S_STATE_INTERMEDIATE;
+ source.GetState_hr = VFW_S_CANT_CUE;
+ hr = IMediaControl_Run(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+ ok(sink.state == State_Running, "Got state %u.\n", sink.state);
+ ok(source.state == State_Running, "Got state %u.\n", source.state);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_CANT_CUE, "Got hr %#x.\n", hr);
+ ok(state == State_Running, "Got state %u.\n", state);
+ ok(sink.state == State_Running, "Got state %u.\n", sink.state);
+ ok(source.state == State_Running, "Got state %u.\n", source.state);
+
+ sink.state_hr = sink.GetState_hr = source.GetState_hr = S_OK;
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
/* Destroying the graph while it's running stops all filters. */
--
2.27.0
More information about the wine-devel
mailing list