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.
-- v4: 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 | 147 ++++++++++++++++++++++++---------------------- 1 file changed, 76 insertions(+), 71 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index bff858854ca..e864dab7336 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; } }
@@ -1204,12 +1207,12 @@ static void session_set_started(struct media_session *session) session_command_complete(session); }
-static void session_set_paused(struct media_session *session, unsigned int state, HRESULT status) +static void session_set_paused(struct media_session *session, HRESULT status) { /* Failed event status could indicate a failure during normal transition to paused state, or an attempt to pause from invalid initial state. To finalize failed transition in the former case, state is still forced to PAUSED, otherwise previous state is retained. */ - if (state != ~0u) session->state = state; + session->state = SESSION_STATE_PAUSED; if (SUCCEEDED(status)) session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); session_command_complete_with_event(session, MESessionPaused, status, NULL); @@ -1225,7 +1228,6 @@ static void session_set_closed(struct media_session *session, HRESULT status)
static void session_pause(struct media_session *session) { - unsigned int state = ~0u; HRESULT hr;
switch (session->state) @@ -1233,27 +1235,22 @@ static void session_pause(struct media_session *session) case SESSION_STATE_STARTED:
/* 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; - state = SESSION_STATE_PAUSED; + session->command_state = COMMAND_STATE_PAUSING_SINKS; + hr = IMFPresentationClock_Pause(session->clock);
- break; + if (FAILED(hr)) + session_set_paused(session, hr);
+ break; case SESSION_STATE_STOPPED: - hr = MF_E_SESSION_PAUSEWHILESTOPPED; + session_command_complete_with_event(session, MESessionPaused, MF_E_SESSION_PAUSEWHILESTOPPED, NULL); break; case SESSION_STATE_PAUSED: case SESSION_STATE_CLOSED: case SESSION_STATE_SHUT_DOWN: - hr = MF_E_INVALIDREQUEST; - break; - default: - assert(0); + session_command_complete_with_event(session, MESessionPaused, MF_E_INVALIDREQUEST, NULL); break; } - - if (FAILED(hr)) - session_set_paused(session, state, hr); }
static void session_clear_end_of_presentation(struct media_session *session) @@ -1303,7 +1300,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 +1312,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 +1323,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 +1359,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 +2816,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 +2948,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 +3257,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 +3308,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 +3332,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); + session_set_paused(session, 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 +3353,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 +3378,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) { @@ -3407,14 +3406,14 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre }
if (FAILED(hr)) - session_set_paused(session, SESSION_STATE_PAUSED, hr); + session_set_paused(session, 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 +3434,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 e864dab7336..da37fddd6e7 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))) @@ -2810,14 +2808,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) { @@ -4169,7 +4166,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 da37fddd6e7..659fc8156a5 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, @@ -1320,7 +1321,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) @@ -1355,9 +1355,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: @@ -2929,8 +2928,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. */ @@ -2941,8 +2938,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) @@ -2956,12 +2951,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); @@ -2970,7 +2966,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); @@ -3343,18 +3339,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; @@ -3423,19 +3423,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 659fc8156a5..b7818269114 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, };
@@ -1257,7 +1259,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; @@ -1269,13 +1270,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))) { @@ -1301,7 +1300,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: @@ -2949,6 +2948,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, @@ -3339,7 +3340,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)) @@ -3354,6 +3355,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); @@ -3405,6 +3408,15 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre if (FAILED(hr)) session_set_paused(session, 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)) @@ -3413,17 +3425,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)) @@ -3442,6 +3448,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: @@ -4167,15 +4174,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); } } @@ -4218,6 +4224,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) @@ -4227,12 +4234,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 b7818269114..c3f5764e6dd 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); } @@ -2817,26 +2819,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); @@ -2973,6 +2992,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 c3f5764e6dd..7322b5e9efe 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: @@ -2022,8 +1982,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) @@ -2948,50 +2906,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); @@ -3335,6 +3286,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) @@ -3343,11 +3295,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)) @@ -4308,7 +4260,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); } @@ -4514,7 +4466,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); }
v3: Make session_set_paused more like session_set_closed and fix uninitialized result warning.
On Wed Jun 25 13:13:17 2025 +0000, Nikolay Sivov wrote:
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
I didn't get that warning but it should be fixed now.