This should fix some spurious test failure in `test_media_session_Close`, as sometimes the source shutdown happens quickly enough and changes the session state to SESSION_STATE_STOPPED, causing the later Close command to succeed when it consistently returns E_SHUTDOWN on Windows.
-- v3: mf/session: Simplify the media session shutdown event handling. mf/session: Introduce a SESSION_FLAG_SOURCE_SHUTDOWN presentation flag. mf/session: Replace SESSION_FLAG_END_OF_PRESENTATION with dedicated states. mf/session: Replace SESSION_FLAG_FINALIZE_SINKS with dedicated states. mf/session: Remove unnecessary SESSION_FLAG_PENDING_COMMAND flag. mf/session: Move internal states to a separate command_state enum. mf/session: Clarify internal states from session states separation.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 54 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 15 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 47760cc44a7..bff858854ca 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -19,6 +19,7 @@ #include <stdarg.h> #include <math.h> #include <float.h> +#include <assert.h>
#define COBJMACROS
@@ -92,19 +93,24 @@ struct queued_topology enum session_state { SESSION_STATE_STOPPED = 0, - SESSION_STATE_STARTING_SOURCES, - SESSION_STATE_PREROLLING_SINKS, - SESSION_STATE_STARTING_SINKS, - SESSION_STATE_RESTARTING_SOURCES, SESSION_STATE_STARTED, - SESSION_STATE_PAUSING_SINKS, - SESSION_STATE_PAUSING_SOURCES, SESSION_STATE_PAUSED, - SESSION_STATE_STOPPING_SINKS, - SESSION_STATE_STOPPING_SOURCES, - SESSION_STATE_FINALIZING_SINKS, SESSION_STATE_CLOSED, SESSION_STATE_SHUT_DOWN, + + /* STOPPED | PAUSED | STARTED -> STARTED transition */ + SESSION_STATE_RESTARTING_SOURCES, /* -> SESSION_STATE_STARTING_SOURCES */ + SESSION_STATE_STARTING_SOURCES, /* -> SESSION_STATE_PREROLLING_SINKS | SESSION_STATE_STARTING_SINKS */ + SESSION_STATE_PREROLLING_SINKS, /* -> SESSION_STATE_STARTING_SINKS */ + SESSION_STATE_STARTING_SINKS, /* -> SESSION_STATE_STARTED */ + /* STARTED -> PAUSED transition */ + SESSION_STATE_PAUSING_SINKS, /* -> SESSION_STATE_PAUSING_SOURCES */ + SESSION_STATE_PAUSING_SOURCES, /* -> SESSION_STATE_PAUSED */ + /* STARTED | PAUSED -> STOPPED transition */ + SESSION_STATE_STOPPING_SINKS, /* -> SESSION_STATE_STOPPING_SOURCES */ + SESSION_STATE_STOPPING_SOURCES, /* -> SESSION_STATE_STOPPED */ + /* STARTED | PAUSED | STOPPED -> CLOSED transition */ + SESSION_STATE_FINALIZING_SINKS, };
enum object_state @@ -1152,12 +1158,15 @@ static void session_start(struct media_session *session, const GUID *time_format session->presentation.start_position.vt = VT_EMPTY; PropVariantCopy(&session->presentation.start_position, start_position);
- /* SESSION_STATE_STARTED -> SESSION_STATE_RESTARTING_SOURCES -> SESSION_STATE_STARTED */ session->state = SESSION_STATE_RESTARTING_SOURCES; break; - default: + case SESSION_STATE_CLOSED: + case SESSION_STATE_SHUT_DOWN: session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL); break; + default: + assert(0); + break; } }
@@ -1233,8 +1242,14 @@ static void session_pause(struct media_session *session) case SESSION_STATE_STOPPED: hr = MF_E_SESSION_PAUSEWHILESTOPPED; break; - default: + case SESSION_STATE_PAUSED: + case SESSION_STATE_CLOSED: + case SESSION_STATE_SHUT_DOWN: hr = MF_E_INVALIDREQUEST; + break; + default: + assert(0); + break; }
if (FAILED(hr)) @@ -1296,9 +1311,13 @@ static void session_stop(struct media_session *session) case SESSION_STATE_STOPPED: hr = S_OK; /* fallthrough */ - default: + case SESSION_STATE_CLOSED: + case SESSION_STATE_SHUT_DOWN: session_command_complete_with_event(session, MESessionStopped, hr, NULL); break; + default: + assert(0); + break; } }
@@ -1340,7 +1359,6 @@ static void session_close(struct media_session *session) switch (session->state) { case SESSION_STATE_STOPPED: - case SESSION_STATE_RESTARTING_SOURCES: hr = session_finalize_sinks(session); break; case SESSION_STATE_STARTED: @@ -1349,9 +1367,13 @@ static void session_close(struct media_session *session) if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) session->state = SESSION_STATE_STOPPING_SINKS; break; - default: + case SESSION_STATE_CLOSED: + case SESSION_STATE_SHUT_DOWN: hr = MF_E_INVALIDREQUEST; break; + default: + assert(0); + break; }
session_clear_queued_topologies(session); @@ -2803,6 +2825,7 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, LeaveCriticalSection(&session->cs); return S_OK; } + assert( session->state <= SESSION_STATE_SHUT_DOWN );
list_remove(&op->entry); session->presentation.flags |= SESSION_FLAG_PENDING_COMMAND; @@ -3303,6 +3326,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn break;
session_flush_nodes(session); + session->state = SESSION_STATE_STOPPED;
/* Start sources */ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 124 ++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 58 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index bff858854ca..dc7fe9c9b93 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -97,20 +97,24 @@ enum session_state SESSION_STATE_PAUSED, SESSION_STATE_CLOSED, SESSION_STATE_SHUT_DOWN, +};
+enum command_state +{ + COMMAND_STATE_COMPLETE = 0, /* STOPPED | PAUSED | STARTED -> STARTED transition */ - SESSION_STATE_RESTARTING_SOURCES, /* -> SESSION_STATE_STARTING_SOURCES */ - SESSION_STATE_STARTING_SOURCES, /* -> SESSION_STATE_PREROLLING_SINKS | SESSION_STATE_STARTING_SINKS */ - SESSION_STATE_PREROLLING_SINKS, /* -> SESSION_STATE_STARTING_SINKS */ - SESSION_STATE_STARTING_SINKS, /* -> SESSION_STATE_STARTED */ + COMMAND_STATE_RESTARTING_SOURCES, /* -> COMMAND_STATE_STARTING_SOURCES */ + COMMAND_STATE_STARTING_SOURCES, /* -> COMMAND_STATE_PREROLLING_SINKS | COMMAND_STATE_STARTING_SINKS */ + COMMAND_STATE_PREROLLING_SINKS, /* -> COMMAND_STATE_STARTING_SINKS */ + COMMAND_STATE_STARTING_SINKS, /* -> SESSION_STATE_STARTED */ /* STARTED -> PAUSED transition */ - SESSION_STATE_PAUSING_SINKS, /* -> SESSION_STATE_PAUSING_SOURCES */ - SESSION_STATE_PAUSING_SOURCES, /* -> SESSION_STATE_PAUSED */ + COMMAND_STATE_PAUSING_SINKS, /* -> COMMAND_STATE_PAUSING_SOURCES */ + COMMAND_STATE_PAUSING_SOURCES, /* -> SESSION_STATE_PAUSED */ /* STARTED | PAUSED -> STOPPED transition */ - SESSION_STATE_STOPPING_SINKS, /* -> SESSION_STATE_STOPPING_SOURCES */ - SESSION_STATE_STOPPING_SOURCES, /* -> SESSION_STATE_STOPPED */ + COMMAND_STATE_STOPPING_SINKS, /* -> COMMAND_STATE_STOPPING_SOURCES */ + COMMAND_STATE_STOPPING_SOURCES, /* -> SESSION_STATE_STOPPED */ /* STARTED | PAUSED | STOPPED -> CLOSED transition */ - SESSION_STATE_FINALIZING_SINKS, + COMMAND_STATE_FINALIZING_SINKS, /* -> SESSION_STATE_CLOSED */ };
enum object_state @@ -270,6 +274,7 @@ struct media_session struct list topologies; struct list commands; enum session_state state; + enum command_state command_state; DWORD caps; CRITICAL_SECTION cs; }; @@ -972,6 +977,7 @@ static void session_command_complete(struct media_session *session) struct list *e; HRESULT hr;
+ session->command_state = COMMAND_STATE_COMPLETE; session->presentation.flags &= ~SESSION_FLAG_PENDING_COMMAND;
/* Submit next command. */ @@ -1127,7 +1133,7 @@ static void session_start(struct media_session *session, const GUID *time_format } }
- session->state = SESSION_STATE_STARTING_SOURCES; + session->command_state = COMMAND_STATE_STARTING_SOURCES; break; case SESSION_STATE_STARTED: /* Check for invalid positions */ @@ -1158,15 +1164,12 @@ static void session_start(struct media_session *session, const GUID *time_format session->presentation.start_position.vt = VT_EMPTY; PropVariantCopy(&session->presentation.start_position, start_position);
- session->state = SESSION_STATE_RESTARTING_SOURCES; + session->command_state = COMMAND_STATE_RESTARTING_SOURCES; break; case SESSION_STATE_CLOSED: case SESSION_STATE_SHUT_DOWN: session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL); break; - default: - assert(0); - break; } }
@@ -1234,7 +1237,7 @@ static void session_pause(struct media_session *session)
/* Transition in two steps - pause the clock, wait for sinks, then pause sources. */ if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock))) - session->state = SESSION_STATE_PAUSING_SINKS; + session->command_state = COMMAND_STATE_PAUSING_SINKS; state = SESSION_STATE_PAUSED;
break; @@ -1247,9 +1250,6 @@ static void session_pause(struct media_session *session) case SESSION_STATE_SHUT_DOWN: hr = MF_E_INVALIDREQUEST; break; - default: - assert(0); - break; }
if (FAILED(hr)) @@ -1303,7 +1303,7 @@ static void session_stop(struct media_session *session) /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */ IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time); if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) - session->state = SESSION_STATE_STOPPING_SINKS; + session->command_state = COMMAND_STATE_STOPPING_SINKS; else session_set_stopped(session, hr);
@@ -1315,9 +1315,6 @@ static void session_stop(struct media_session *session) case SESSION_STATE_SHUT_DOWN: session_command_complete_with_event(session, MESessionStopped, hr, NULL); break; - default: - assert(0); - break; } }
@@ -1329,7 +1326,7 @@ static HRESULT session_finalize_sinks(struct media_session *session) HRESULT hr = S_OK;
session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS; - session->state = SESSION_STATE_FINALIZING_SINKS; + session->command_state = COMMAND_STATE_FINALIZING_SINKS;
LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry) { @@ -1365,15 +1362,12 @@ static void session_close(struct media_session *session) case SESSION_STATE_PAUSED: session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS; if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) - session->state = SESSION_STATE_STOPPING_SINKS; + session->command_state = COMMAND_STATE_STOPPING_SINKS; break; case SESSION_STATE_CLOSED: case SESSION_STATE_SHUT_DOWN: hr = MF_E_INVALIDREQUEST; break; - default: - assert(0); - break; }
session_clear_queued_topologies(session); @@ -2825,8 +2819,6 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, LeaveCriticalSection(&session->cs); return S_OK; } - assert( session->state <= SESSION_STATE_SHUT_DOWN ); - list_remove(&op->entry); session->presentation.flags |= SESSION_FLAG_PENDING_COMMAND;
@@ -2959,26 +2951,30 @@ static void session_handle_source_shutdown(struct media_session *session)
/* When stopping the session, MESessionStopped is sent without waiting * for MESourceStopped, so we need do nothing in that case. */ - switch (session->state) + switch (session->command_state) { - case SESSION_STATE_STARTING_SOURCES: - case SESSION_STATE_RESTARTING_SOURCES: - case SESSION_STATE_PREROLLING_SINKS: - case SESSION_STATE_STARTING_SINKS: + case COMMAND_STATE_STARTING_SOURCES: + case COMMAND_STATE_RESTARTING_SOURCES: + case COMMAND_STATE_PREROLLING_SINKS: + case COMMAND_STATE_STARTING_SINKS: IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL, MF_E_INVALIDREQUEST, NULL); break; - case SESSION_STATE_STOPPING_SINKS: - case SESSION_STATE_STOPPING_SOURCES: + case COMMAND_STATE_STOPPING_SINKS: + case COMMAND_STATE_STOPPING_SOURCES: if (!finalize_sinks) IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, MF_E_INVALIDREQUEST, NULL); break; - default: + case COMMAND_STATE_PAUSING_SINKS: + case COMMAND_STATE_PAUSING_SOURCES: + case COMMAND_STATE_FINALIZING_SINKS: + case COMMAND_STATE_COMPLETE: + WARN("Ignoring source shutdown in command state %#x\n", session->command_state); break; }
- if (session->state != SESSION_STATE_CLOSED) + if (session->state != SESSION_STATE_CLOSED || session->command_state != COMMAND_STATE_COMPLETE) { if (finalize_sinks) session_finalize_sinks(session); @@ -3264,9 +3260,9 @@ static void session_set_source_object_state(struct media_session *session, IUnkn if (!changed) return;
- switch (session->state) + switch (session->command_state) { - case SESSION_STATE_STARTING_SOURCES: + case COMMAND_STATE_STARTING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED)) break;
@@ -3315,13 +3311,13 @@ static void session_set_source_object_state(struct media_session *session, IUnkn } } } - session->state = SESSION_STATE_PREROLLING_SINKS; + session->command_state = COMMAND_STATE_PREROLLING_SINKS; } else if (SUCCEEDED(session_start_clock(session))) - session->state = SESSION_STATE_STARTING_SINKS; + session->command_state = COMMAND_STATE_STARTING_SINKS;
break; - case SESSION_STATE_RESTARTING_SOURCES: + case COMMAND_STATE_RESTARTING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED)) break;
@@ -3339,15 +3335,15 @@ static void session_set_source_object_state(struct media_session *session, IUnkn return; } } - session->state = SESSION_STATE_STARTING_SOURCES; + session->command_state = COMMAND_STATE_STARTING_SOURCES; break; - case SESSION_STATE_PAUSING_SOURCES: + case COMMAND_STATE_PAUSING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED)) break;
session_set_paused(session, SESSION_STATE_PAUSED, S_OK); break; - case SESSION_STATE_STOPPING_SOURCES: + case COMMAND_STATE_STOPPING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED)) break;
@@ -3360,8 +3356,14 @@ static void session_set_source_object_state(struct media_session *session, IUnkn session_set_stopped(session, S_OK);
break; - default: - ; + case COMMAND_STATE_COMPLETE: + case COMMAND_STATE_PREROLLING_SINKS: + case COMMAND_STATE_STARTING_SINKS: + case COMMAND_STATE_PAUSING_SINKS: + case COMMAND_STATE_STOPPING_SINKS: + case COMMAND_STATE_FINALIZING_SINKS: + WARN("Ignoring source state change in command state %#x\n", session->command_state); + break; } }
@@ -3379,26 +3381,26 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state))) return;
- switch (session->state) + switch (session->command_state) { - case SESSION_STATE_PREROLLING_SINKS: + case COMMAND_STATE_PREROLLING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED)) break;
if (SUCCEEDED(session_start_clock(session))) - session->state = SESSION_STATE_STARTING_SINKS; + session->command_state = COMMAND_STATE_STARTING_SINKS; break; - case SESSION_STATE_STARTING_SINKS: + case COMMAND_STATE_STARTING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED)) break;
session_set_started(session); break; - case SESSION_STATE_PAUSING_SINKS: + case COMMAND_STATE_PAUSING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED)) break;
- session->state = SESSION_STATE_PAUSING_SOURCES; + session->command_state = COMMAND_STATE_PAUSING_SOURCES;
LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -3410,11 +3412,11 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre session_set_paused(session, SESSION_STATE_PAUSED, hr);
break; - case SESSION_STATE_STOPPING_SINKS: + case COMMAND_STATE_STOPPING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) break;
- session->state = SESSION_STATE_STOPPING_SOURCES; + session->command_state = COMMAND_STATE_STOPPING_SOURCES;
LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -3435,8 +3437,14 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre }
break; - default: - ; + case COMMAND_STATE_COMPLETE: + case COMMAND_STATE_RESTARTING_SOURCES: + case COMMAND_STATE_STARTING_SOURCES: + case COMMAND_STATE_PAUSING_SOURCES: + case COMMAND_STATE_STOPPING_SOURCES: + case COMMAND_STATE_FINALIZING_SINKS: + WARN("Ignoring sink state change in command state %#x\n", session->command_state); + break; } }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index dc7fe9c9b93..df86ba1e3ad 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -231,7 +231,6 @@ enum presentation_flags SESSION_FLAG_NEEDS_PREROLL = 0x8, SESSION_FLAG_END_OF_PRESENTATION = 0x10, SESSION_FLAG_PENDING_RATE_CHANGE = 0x20, - SESSION_FLAG_PENDING_COMMAND = 0x40, };
struct media_session @@ -484,7 +483,7 @@ static HRESULT session_submit_command(struct media_session *session, struct sess EnterCriticalSection(&session->cs); if (SUCCEEDED(hr = session_is_shut_down(session))) { - if (list_empty(&session->commands) && !(session->presentation.flags & SESSION_FLAG_PENDING_COMMAND)) + if (list_empty(&session->commands) && session->command_state == COMMAND_STATE_COMPLETE) { hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface); op->submitted = SUCCEEDED(hr); @@ -978,7 +977,6 @@ static void session_command_complete(struct media_session *session) HRESULT hr;
session->command_state = COMMAND_STATE_COMPLETE; - session->presentation.flags &= ~SESSION_FLAG_PENDING_COMMAND;
/* Submit next command. */ if ((e = list_head(&session->commands))) @@ -2813,14 +2811,13 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
EnterCriticalSection(&session->cs);
- if (session->presentation.flags & SESSION_FLAG_PENDING_COMMAND) + if (session->command_state != COMMAND_STATE_COMPLETE) { WARN("session %p command is in progress, waiting for it to complete.\n", session); LeaveCriticalSection(&session->cs); return S_OK; } list_remove(&op->entry); - session->presentation.flags |= SESSION_FLAG_PENDING_COMMAND;
switch (op->command) { @@ -4172,7 +4169,8 @@ static void session_raise_end_of_presentation(struct media_session *session) { if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION)) { - session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION | SESSION_FLAG_PENDING_COMMAND; + session->command_state = COMMAND_STATE_STOPPING_SINKS; + session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION; IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL); } }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 54 +++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 23 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index df86ba1e3ad..e04376c5e2c 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -114,6 +114,8 @@ enum command_state COMMAND_STATE_STOPPING_SINKS, /* -> COMMAND_STATE_STOPPING_SOURCES */ COMMAND_STATE_STOPPING_SOURCES, /* -> SESSION_STATE_STOPPED */ /* STARTED | PAUSED | STOPPED -> CLOSED transition */ + COMMAND_STATE_CLOSING_SINKS, /* -> COMMAND_STATE_CLOSING_SOURCES */ + COMMAND_STATE_CLOSING_SOURCES, /* -> COMMAND_STATE_FINALIZING_SINKS */ COMMAND_STATE_FINALIZING_SINKS, /* -> SESSION_STATE_CLOSED */ };
@@ -227,7 +229,6 @@ enum presentation_flags { SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1, SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2, - SESSION_FLAG_FINALIZE_SINKS = 0x4, SESSION_FLAG_NEEDS_PREROLL = 0x8, SESSION_FLAG_END_OF_PRESENTATION = 0x10, SESSION_FLAG_PENDING_RATE_CHANGE = 0x20, @@ -1323,7 +1324,6 @@ static HRESULT session_finalize_sinks(struct media_session *session) struct media_sink *sink; HRESULT hr = S_OK;
- session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS; session->command_state = COMMAND_STATE_FINALIZING_SINKS;
LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry) @@ -1358,9 +1358,8 @@ static void session_close(struct media_session *session) break; case SESSION_STATE_STARTED: case SESSION_STATE_PAUSED: - session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS; if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) - session->command_state = COMMAND_STATE_STOPPING_SINKS; + session->command_state = COMMAND_STATE_CLOSING_SINKS; break; case SESSION_STATE_CLOSED: case SESSION_STATE_SHUT_DOWN: @@ -2932,8 +2931,6 @@ static const IMFAsyncCallbackVtbl session_sa_ready_callback_vtbl =
static void session_handle_source_shutdown(struct media_session *session) { - BOOL finalize_sinks; - EnterCriticalSection(&session->cs);
/* Shutdown may be notified via a dedicated callback or by Begin/EndGetEvent() failure. */ @@ -2944,8 +2941,6 @@ static void session_handle_source_shutdown(struct media_session *session) } session->source_shutdown_handled = TRUE;
- finalize_sinks = session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS; - /* When stopping the session, MESessionStopped is sent without waiting * for MESourceStopped, so we need do nothing in that case. */ switch (session->command_state) @@ -2959,12 +2954,13 @@ static void session_handle_source_shutdown(struct media_session *session) break; case COMMAND_STATE_STOPPING_SINKS: case COMMAND_STATE_STOPPING_SOURCES: - if (!finalize_sinks) - IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, - MF_E_INVALIDREQUEST, NULL); + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, + MF_E_INVALIDREQUEST, NULL); break; case COMMAND_STATE_PAUSING_SINKS: case COMMAND_STATE_PAUSING_SOURCES: + case COMMAND_STATE_CLOSING_SINKS: + case COMMAND_STATE_CLOSING_SOURCES: case COMMAND_STATE_FINALIZING_SINKS: case COMMAND_STATE_COMPLETE: WARN("Ignoring source shutdown in command state %#x\n", session->command_state); @@ -2973,7 +2969,7 @@ static void session_handle_source_shutdown(struct media_session *session)
if (session->state != SESSION_STATE_CLOSED || session->command_state != COMMAND_STATE_COMPLETE) { - if (finalize_sinks) + if (session->command_state == COMMAND_STATE_CLOSING_SINKS || session->command_state == COMMAND_STATE_CLOSING_SOURCES) session_finalize_sinks(session); else session_reset(session); @@ -3346,18 +3342,22 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
session_flush_nodes(session); session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); + session_set_stopped(session, S_OK); + break; + case COMMAND_STATE_CLOSING_SOURCES: + if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED)) + break;
- if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS) - session_finalize_sinks(session); - else - session_set_stopped(session, S_OK); - + session_flush_nodes(session); + session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); + session_finalize_sinks(session); break; case COMMAND_STATE_COMPLETE: case COMMAND_STATE_PREROLLING_SINKS: case COMMAND_STATE_STARTING_SINKS: case COMMAND_STATE_PAUSING_SINKS: case COMMAND_STATE_STOPPING_SINKS: + case COMMAND_STATE_CLOSING_SINKS: case COMMAND_STATE_FINALIZING_SINKS: WARN("Ignoring source state change in command state %#x\n", session->command_state); break; @@ -3426,19 +3426,27 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) session_set_stopped(session, hr); else if (FAILED(hr)) - { - if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS) - session_set_closed(session, hr); - else - session_set_stopped(session, hr); - } + session_set_stopped(session, hr); + break; + case COMMAND_STATE_CLOSING_SINKS: + if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) + break; + + session->command_state = COMMAND_STATE_CLOSING_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_set_closed(session, hr); break; case COMMAND_STATE_COMPLETE: case COMMAND_STATE_RESTARTING_SOURCES: case COMMAND_STATE_STARTING_SOURCES: case COMMAND_STATE_PAUSING_SOURCES: case COMMAND_STATE_STOPPING_SOURCES: + case COMMAND_STATE_CLOSING_SOURCES: case COMMAND_STATE_FINALIZING_SINKS: WARN("Ignoring sink state change in command state %#x\n", session->command_state); break;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 56 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index e04376c5e2c..4ee9717c199 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -110,6 +110,9 @@ enum command_state /* STARTED -> PAUSED transition */ COMMAND_STATE_PAUSING_SINKS, /* -> COMMAND_STATE_PAUSING_SOURCES */ COMMAND_STATE_PAUSING_SOURCES, /* -> SESSION_STATE_PAUSED */ + /* STARTED -> STOPPED transition when presentation ends */ + COMMAND_STATE_ENDING_STREAMS, /* -> COMMAND_STATE_ENDING_SINKS */ + COMMAND_STATE_ENDING_SINKS, /* -> SESSION_STATE_STOPPED */ /* STARTED | PAUSED -> STOPPED transition */ COMMAND_STATE_STOPPING_SINKS, /* -> COMMAND_STATE_STOPPING_SOURCES */ COMMAND_STATE_STOPPING_SOURCES, /* -> SESSION_STATE_STOPPED */ @@ -230,7 +233,6 @@ enum presentation_flags SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1, SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2, SESSION_FLAG_NEEDS_PREROLL = 0x8, - SESSION_FLAG_END_OF_PRESENTATION = 0x10, SESSION_FLAG_PENDING_RATE_CHANGE = 0x20, };
@@ -1260,7 +1262,6 @@ static void session_clear_end_of_presentation(struct media_session *session) struct media_source *source; struct topo_node *node;
- session->presentation.flags &= ~SESSION_FLAG_END_OF_PRESENTATION; LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { source->flags &= ~SOURCE_FLAG_END_OF_PRESENTATION; @@ -1272,13 +1273,11 @@ static void session_clear_end_of_presentation(struct media_session *session) session->presentation.topo_status = MF_TOPOSTATUS_READY; }
-static void session_set_stopped(struct media_session *session, HRESULT status) +static void session_set_stopped(struct media_session *session, MediaEventType event_type, HRESULT status) { - MediaEventType event_type; IMFMediaEvent *event;
session->state = SESSION_STATE_STOPPED; - event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event))) { @@ -1304,7 +1303,7 @@ static void session_stop(struct media_session *session) if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) session->command_state = COMMAND_STATE_STOPPING_SINKS; else - session_set_stopped(session, hr); + session_set_stopped(session, MESessionStopped, hr);
break; case SESSION_STATE_STOPPED: @@ -2952,6 +2951,8 @@ static void session_handle_source_shutdown(struct media_session *session) IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL, MF_E_INVALIDREQUEST, NULL); break; + case COMMAND_STATE_ENDING_STREAMS: + case COMMAND_STATE_ENDING_SINKS: case COMMAND_STATE_STOPPING_SINKS: case COMMAND_STATE_STOPPING_SOURCES: IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, @@ -3342,7 +3343,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
session_flush_nodes(session); session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); - session_set_stopped(session, S_OK); + session_set_stopped(session, MESessionStopped, S_OK); break; case COMMAND_STATE_CLOSING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED)) @@ -3357,6 +3358,8 @@ static void session_set_source_object_state(struct media_session *session, IUnkn case COMMAND_STATE_STARTING_SINKS: case COMMAND_STATE_PAUSING_SINKS: case COMMAND_STATE_STOPPING_SINKS: + case COMMAND_STATE_ENDING_STREAMS: + case COMMAND_STATE_ENDING_SINKS: case COMMAND_STATE_CLOSING_SINKS: case COMMAND_STATE_FINALIZING_SINKS: WARN("Ignoring source state change in command state %#x\n", session->command_state); @@ -3408,6 +3411,15 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre if (FAILED(hr)) session_set_paused(session, SESSION_STATE_PAUSED, hr);
+ break; + case COMMAND_STATE_ENDING_SINKS: + if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) + break; + + LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) + IMFMediaSource_Stop(source->source); + + session_set_stopped(session, MESessionEnded, S_OK); break; case COMMAND_STATE_STOPPING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) @@ -3416,17 +3428,11 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre session->command_state = COMMAND_STATE_STOPPING_SOURCES;
LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) - { - if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) - IMFMediaSource_Stop(source->source); - else if (FAILED(hr = IMFMediaSource_Stop(source->source))) + if (FAILED(hr = IMFMediaSource_Stop(source->source))) break; - }
- if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) - session_set_stopped(session, hr); - else if (FAILED(hr)) - session_set_stopped(session, hr); + if (FAILED(hr)) + session_set_stopped(session, MESessionStopped, hr); break; case COMMAND_STATE_CLOSING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) @@ -3445,6 +3451,7 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre case COMMAND_STATE_RESTARTING_SOURCES: case COMMAND_STATE_STARTING_SOURCES: case COMMAND_STATE_PAUSING_SOURCES: + case COMMAND_STATE_ENDING_STREAMS: case COMMAND_STATE_STOPPING_SOURCES: case COMMAND_STATE_CLOSING_SOURCES: case COMMAND_STATE_FINALIZING_SINKS: @@ -4170,15 +4177,14 @@ static void session_nodes_unset_mask(struct media_session *session, MF_TOPOLOGY_
static void session_raise_end_of_presentation(struct media_session *session) { - if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM))) + if (!session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)) return;
- if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)) + if (session->command_state == COMMAND_STATE_COMPLETE) { if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION)) { - session->command_state = COMMAND_STATE_STOPPING_SINKS; - session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION; + session->command_state = COMMAND_STATE_ENDING_STREAMS; IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL); } } @@ -4221,6 +4227,7 @@ static void session_handle_end_of_presentation(struct media_session *session, IM static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink) { struct topo_node *node; + HRESULT hr;
if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE)) || node->flags & TOPO_NODE_END_OF_STREAM) @@ -4230,12 +4237,17 @@ static void session_sink_stream_marker(struct media_session *session, IMFStreamS
node->flags |= TOPO_NODE_END_OF_STREAM;
- if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION && + if (session->command_state == COMMAND_STATE_ENDING_STREAMS && session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM)) { session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED); session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); - session_stop(session); + + IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time); + if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) + session->command_state = COMMAND_STATE_ENDING_SINKS; + else + session_set_stopped(session, MESessionEnded, hr); } }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 4ee9717c199..93e9034e78b 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -233,6 +233,7 @@ enum presentation_flags SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1, SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2, SESSION_FLAG_NEEDS_PREROLL = 0x8, + SESSION_FLAG_SOURCE_SHUTDOWN = 0x10, SESSION_FLAG_PENDING_RATE_CHANGE = 0x20, };
@@ -1066,6 +1067,7 @@ static void session_reset(struct media_session *session) * forced source shutdown, but we try to clean up as well as possible. */ session->state = SESSION_STATE_STOPPED; session_clear_presentation(session); + session->presentation.flags |= SESSION_FLAG_SOURCE_SHUTDOWN; session_purge_pending_commands(session); session_command_complete(session); } @@ -2820,26 +2822,43 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, switch (op->command) { case SESSION_CMD_CLEAR_TOPOLOGIES: + session->presentation.flags &= ~SESSION_FLAG_SOURCE_SHUTDOWN; session_clear_topologies(session); break; case SESSION_CMD_SET_TOPOLOGY: + session->presentation.flags &= ~SESSION_FLAG_SOURCE_SHUTDOWN; session_set_topology(session, op->set_topology.flags, op->set_topology.topology); session_command_complete(session); break; case SESSION_CMD_START: - session_start(session, &op->start.time_format, &op->start.start_position); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionStarted, MF_E_SHUTDOWN, NULL); + else + session_start(session, &op->start.time_format, &op->start.start_position); break; case SESSION_CMD_PAUSE: - session_pause(session); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionPaused, MF_E_SHUTDOWN, NULL); + else + session_pause(session); break; case SESSION_CMD_STOP: - session_stop(session); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionStopped, MF_E_SHUTDOWN, NULL); + else + session_stop(session); break; case SESSION_CMD_CLOSE: - session_close(session); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionClosed, MF_E_SHUTDOWN, NULL); + else + session_close(session); break; case SESSION_CMD_SET_RATE: - session_set_rate(session, op->set_rate.thin, op->set_rate.rate); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionRateChanged, MF_E_SHUTDOWN, NULL); + else + session_set_rate(session, op->set_rate.thin, op->set_rate.rate); break; case SESSION_CMD_SHUTDOWN: session_clear_command_list(session); @@ -2976,6 +2995,8 @@ static void session_handle_source_shutdown(struct media_session *session) session_reset(session); }
+ session->presentation.flags |= SESSION_FLAG_SOURCE_SHUTDOWN; + LeaveCriticalSection(&session->cs); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 122 ++++++++++++++-------------------------------- 1 file changed, 37 insertions(+), 85 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 93e9034e78b..071ee0b0f1a 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -250,7 +250,6 @@ struct media_session IMFAsyncCallback events_callback; IMFAsyncCallback sink_finalizer_callback; LONG refcount; - BOOL source_shutdown_handled; IMFMediaEventQueue *event_queue; IMFPresentationClock *clock; IMFPresentationTimeSource *system_time_source; @@ -1039,48 +1038,7 @@ static void session_flush_nodes(struct media_session *session) } }
-static void session_purge_pending_commands(struct media_session *session) -{ - struct session_op *op, *op2; - - /* Purge all commands which are no longer valid after a forced source shutdown. - * Calling Stop() in this case is not required in native Windows. */ - LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry) - { - if (op->command == SESSION_CMD_SET_TOPOLOGY) - break; - if (op->command == SESSION_CMD_CLEAR_TOPOLOGIES || op->command == SESSION_CMD_CLOSE - || op->command == SESSION_CMD_SHUTDOWN) - continue; - /* Once a command is submitted, the callback becomes responsible - * for removal from the list and release of the ref. */ - if (op->submitted) - continue; - list_remove(&op->entry); - IUnknown_Release(&op->IUnknown_iface); - } -} - -static void session_reset(struct media_session *session) -{ - /* Media sessions in native Windows are not consistently usable after a - * forced source shutdown, but we try to clean up as well as possible. */ - session->state = SESSION_STATE_STOPPED; - session_clear_presentation(session); - session->presentation.flags |= SESSION_FLAG_SOURCE_SHUTDOWN; - session_purge_pending_commands(session); - session_command_complete(session); -} - -static void session_handle_start_error(struct media_session *session, HRESULT hr) -{ - if (hr == MF_E_SHUTDOWN) - { - session_reset(session); - hr = MF_E_INVALIDREQUEST; - } - session_command_complete_with_event(session, MESessionStarted, hr, NULL); -} +static void session_handle_source_shutdown(struct media_session *session);
static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position) { @@ -1103,6 +1061,7 @@ static void session_start(struct media_session *session, const GUID *time_format
/* fallthrough */ case SESSION_STATE_PAUSED: + session->command_state = COMMAND_STATE_STARTING_SOURCES;
session->presentation.time_format = *time_format; session->presentation.start_position.vt = VT_EMPTY; @@ -1110,8 +1069,9 @@ static void session_start(struct media_session *session, const GUID *time_format
if (FAILED(hr = session_subscribe_sources(session))) { - session_handle_start_error(session, hr); - return; + if (hr == MF_E_SHUTDOWN) + return session_handle_source_shutdown(session); + return session_command_complete_with_event(session, MESessionStarted, hr, NULL); }
LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) @@ -1119,8 +1079,9 @@ static void session_start(struct media_session *session, const GUID *time_format if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position))) { WARN("Failed to start media source %p, hr %#lx.\n", source->source, hr); - session_handle_start_error(session, hr); - return; + if (hr == MF_E_SHUTDOWN) + return session_handle_source_shutdown(session); + return session_command_complete_with_event(session, MESessionStarted, hr, NULL); } }
@@ -1135,10 +1096,10 @@ static void session_start(struct media_session *session, const GUID *time_format } } } - - session->command_state = COMMAND_STATE_STARTING_SOURCES; break; case SESSION_STATE_STARTED: + session->command_state = COMMAND_STATE_RESTARTING_SOURCES; + /* Check for invalid positions */ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -1158,16 +1119,15 @@ static void session_start(struct media_session *session, const GUID *time_format if (FAILED(hr = IMFMediaSource_Stop(source->source))) { WARN("Failed to stop media source %p, hr %#lx.\n", source->source, hr); - session_command_complete_with_event(session, MESessionStarted, hr, NULL); - return; + if (hr == MF_E_SHUTDOWN) + return session_handle_source_shutdown(session); + return session_command_complete_with_event(session, MESessionStarted, hr, NULL); } }
session->presentation.time_format = *time_format; session->presentation.start_position.vt = VT_EMPTY; PropVariantCopy(&session->presentation.start_position, start_position); - - session->command_state = COMMAND_STATE_RESTARTING_SOURCES; break; case SESSION_STATE_CLOSED: case SESSION_STATE_SHUT_DOWN: @@ -2025,8 +1985,6 @@ static HRESULT session_set_current_topology(struct media_session *session, IMFTo return hr; }
- session->source_shutdown_handled = FALSE; - session_collect_nodes(session);
LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) @@ -2951,50 +2909,43 @@ static void session_handle_source_shutdown(struct media_session *session) { EnterCriticalSection(&session->cs);
- /* Shutdown may be notified via a dedicated callback or by Begin/EndGetEvent() failure. */ - if (session->source_shutdown_handled) - { - LeaveCriticalSection(&session->cs); - return; - } - session->source_shutdown_handled = TRUE; - - /* When stopping the session, MESessionStopped is sent without waiting - * for MESourceStopped, so we need do nothing in that case. */ switch (session->command_state) { case COMMAND_STATE_STARTING_SOURCES: case COMMAND_STATE_RESTARTING_SOURCES: case COMMAND_STATE_PREROLLING_SINKS: case COMMAND_STATE_STARTING_SINKS: - IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL, - MF_E_INVALIDREQUEST, NULL); + session_clear_presentation(session); + session->state = SESSION_STATE_STOPPED; + session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL); + break; + case COMMAND_STATE_PAUSING_SINKS: + case COMMAND_STATE_PAUSING_SOURCES: + session_clear_presentation(session); + session->state = SESSION_STATE_STOPPED; + session_command_complete_with_event(session, MESessionPaused, MF_E_SHUTDOWN, NULL); break; case COMMAND_STATE_ENDING_STREAMS: case COMMAND_STATE_ENDING_SINKS: case COMMAND_STATE_STOPPING_SINKS: case COMMAND_STATE_STOPPING_SOURCES: - IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, - MF_E_INVALIDREQUEST, NULL); + session_clear_presentation(session); + session->state = SESSION_STATE_STOPPED; + session_command_complete_with_event(session, MESessionStopped, MF_E_SHUTDOWN, NULL); break; - case COMMAND_STATE_PAUSING_SINKS: - case COMMAND_STATE_PAUSING_SOURCES: case COMMAND_STATE_CLOSING_SINKS: case COMMAND_STATE_CLOSING_SOURCES: case COMMAND_STATE_FINALIZING_SINKS: + session_clear_presentation(session); + session->state = SESSION_STATE_CLOSED; + session_command_complete_with_event(session, MESessionClosed, MF_E_SHUTDOWN, NULL); + break; case COMMAND_STATE_COMPLETE: - WARN("Ignoring source shutdown in command state %#x\n", session->command_state); + if (session->state == SESSION_STATE_STARTED || session->state == SESSION_STATE_PAUSED) + session_set_stopped(session, MESessionStopped, MF_E_SHUTDOWN); break; }
- if (session->state != SESSION_STATE_CLOSED || session->command_state != COMMAND_STATE_COMPLETE) - { - if (session->command_state == COMMAND_STATE_CLOSING_SINKS || session->command_state == COMMAND_STATE_CLOSING_SOURCES) - session_finalize_sinks(session); - else - session_reset(session); - } - session->presentation.flags |= SESSION_FLAG_SOURCE_SHUTDOWN;
LeaveCriticalSection(&session->cs); @@ -3338,6 +3289,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
session_flush_nodes(session); session->state = SESSION_STATE_STOPPED; + session->command_state = COMMAND_STATE_STARTING_SOURCES;
/* Start sources */ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) @@ -3346,11 +3298,11 @@ static void session_set_source_object_state(struct media_session *session, IUnkn &session->presentation.time_format, &session->presentation.start_position))) { WARN("Failed to start media source %p, hr %#lx.\n", source->source, hr); - session_command_complete_with_event(session, MESessionStarted, hr, NULL); - return; + if (hr == MF_E_SHUTDOWN) + return session_handle_source_shutdown(session); + return session_command_complete_with_event(session, MESessionStarted, hr, NULL); } } - session->command_state = COMMAND_STATE_STARTING_SOURCES; break; case COMMAND_STATE_PAUSING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED)) @@ -4311,7 +4263,7 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event))) { - if (hr == MF_E_SHUTDOWN) + if (hr == MF_E_SHUTDOWN && session_get_media_source(session, (IMFMediaSource *)event_source)) { session_handle_source_shutdown(session); } @@ -4517,7 +4469,7 @@ failed:
if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source))) { - if (hr == MF_E_SHUTDOWN) + if (hr == MF_E_SHUTDOWN && session_get_media_source(session, (IMFMediaSource *)event_source)) { session_handle_source_shutdown(session); }
v2: Clarify the session state machine using separate enums for command sub states, replacing several of the flags. I think it makes it easier to understand all the possible transitions, and then possible to simplify source shutdown handling.
It's a much larger change than I initially intended but I always had a difficult time with all the session states, and I think this makes it much easier to follow. Let me know if you don't like it, I'll get back to a simpler change instead.
I'm getting a compiler warning:
``` In function ‘session_pause’, inlined from ‘session_commands_callback_Invoke’ at ../../wine-git/dlls/mf/session.c:2801:17: ../../wine-git/dlls/mf/session.c:1218:8: warning: ‘hr’ may be used uninitialized [-Wmaybe-uninitialized] 1218 | if (FAILED(hr)) | ^ ../../wine-git/dlls/mf/session.c: In function ‘session_commands_callback_Invoke’: ../../wine-git/dlls/mf/session.c:1195:13: note: ‘hr’ was declared here 1195 | HRESULT hr; | ^~ CCLD dlls/mf/x86_64-windows/mf.dll ```