From ddfb56c0b7fab4c116a469b24e04eb543c04d00e Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 28 Feb 2020 15:01:04 +0300 Subject: [PATCH] mf: Implement Stop() command for media session. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mf/session.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 485b3365702..76310040ee3 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -79,6 +79,8 @@ enum session_state SESSION_STATE_PAUSING_SINKS, SESSION_STATE_PAUSING_SOURCES, SESSION_STATE_PAUSED, + SESSION_STATE_STOPPING_SINKS, + SESSION_STATE_STOPPING_SOURCES, SESSION_STATE_CLOSED, SESSION_STATE_SHUT_DOWN, }; @@ -676,6 +678,36 @@ static void session_pause(struct media_session *session) LeaveCriticalSection(&session->cs); } +static void session_stop(struct media_session *session) +{ + HRESULT hr = S_OK; + + EnterCriticalSection(&session->cs); + + switch (session->state) + { + case SESSION_STATE_RUNNING: + case SESSION_STATE_PAUSED: + + /* Transition in two steps - pause clock, wait for sinks and pause sources. */ + if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) + session->state = SESSION_STATE_STOPPING_SINKS; + + break; + default: + ; + } + + if (FAILED(hr)) + { + session->state = SESSION_STATE_STOPPED; + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, hr, NULL); + } + + LeaveCriticalSection(&session->cs); +} + + static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source) { struct media_source *cur; @@ -1503,6 +1535,9 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, case SESSION_CMD_PAUSE: session_pause(session); break; + case SESSION_CMD_STOP: + session_stop(session); + break; case SESSION_CMD_CLOSE: EnterCriticalSection(&session->cs); if (session->state != SESSION_STATE_CLOSED) @@ -1724,6 +1759,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn MediaEventType event_type) { struct source_node *src_node; + struct output_node *out_node; struct media_source *src; enum object_state state; BOOL changed = FALSE; @@ -1788,6 +1824,22 @@ static void session_set_source_object_state(struct media_session *session, IUnkn IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, S_OK, NULL); + break; + case SESSION_STATE_STOPPING_SOURCES: + if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED)) + break; + + session->state = SESSION_STATE_STOPPED; + + LIST_FOR_EACH_ENTRY(out_node, &session->presentation.output_nodes, struct output_node, entry) + { + IMFStreamSink_Flush(out_node->stream); + } + + session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); + + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, S_OK, NULL); + break; default: ; @@ -1870,6 +1922,25 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, hr, NULL); } + break; + case SESSION_STATE_STOPPING_SINKS: + if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) + break; + + session->state = SESSION_STATE_STOPPING_SOURCES; + + LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) + { + if (FAILED(hr = IMFMediaSource_Stop(source->source))) + break; + } + + if (FAILED(hr)) + { + session->state = SESSION_STATE_STOPPED; + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, hr, NULL); + } + break; default: ;