From: Conor McCarthy cmccarthy@codeweavers.com
Windows robustly handles asynchronous shutdown of a media source used in a session. --- dlls/mf/session.c | 59 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index e24cc6376b4..67af5ade4ae 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1001,6 +1001,54 @@ 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_CLEAR_TOPOLOGIES || op->command == SESSION_CMD_SET_TOPOLOGY + || op->command == SESSION_CMD_CLOSE || op->command == SESSION_CMD_SHUTDOWN) + 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_purge_pending_commands(session); + session_command_complete(session); +} + +static void session_handle_source_shutdown(struct media_session *session) +{ + EnterCriticalSection(&session->cs); + + /* When stopping the session, MESessionStopped is sent without waiting + * for MESourceStopped, so we need do nothing in that case. */ + switch (session->state) + { + case SESSION_STATE_STARTING_SOURCES: + case SESSION_STATE_RESTARTING_SOURCES: + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL, + MF_E_INVALIDREQUEST, NULL); + break; + default: + break; + } + + session_reset(session); + + LeaveCriticalSection(&session->cs); +} + static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position) { struct media_source *source; @@ -4050,8 +4098,15 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event))) { - WARN("Failed to get event from %p, hr %#lx.\n", event_source, hr); - IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEError, &GUID_NULL, hr, NULL); + if (hr == MF_E_SHUTDOWN) + { + session_handle_source_shutdown(session); + } + else + { + WARN("Failed to get event from %p, hr %#lx.\n", event_source, hr); + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEError, &GUID_NULL, hr, NULL); + } IMFMediaEventGenerator_Release(event_source); return hr; }