From: Brendan McGrath bmcgrath@codeweavers.com
Fixes missing Started, Stopped or Closed events during this scenario --- dlls/mf/session.c | 132 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 113 insertions(+), 19 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index dc9578ce86b..fed72495bc1 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -230,7 +230,6 @@ struct media_session IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface; IMFAsyncCallback commands_callback; IMFAsyncCallback sa_ready_callback; - IMFAsyncCallback events_callback; IMFAsyncCallback sink_finalizer_callback; LONG refcount; IMFMediaEventQueue *event_queue; @@ -278,11 +277,6 @@ static struct media_session *impl_from_sa_ready_callback_IMFAsyncCallback(IMFAsy return CONTAINING_RECORD(iface, struct media_session, sa_ready_callback); }
-static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct media_session, events_callback); -} - static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface) { return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback); @@ -966,6 +960,32 @@ static void session_command_complete_with_event(struct media_session *session, M session_command_complete(session); }
+struct events_callback +{ + IMFAsyncCallback IMFAsyncCallback_iface; + LONG refcount; + BOOL awaiting_event; + struct media_session *session; + enum MF_TOPOLOGY_TYPE type; +}; + +static struct events_callback* events_callback_create(struct media_session *session, enum MF_TOPOLOGY_TYPE type); + +static HRESULT events_callback_begin(IMFMediaEventGenerator *event_generator, + struct media_session *session, enum MF_TOPOLOGY_TYPE type, IUnknown *punkState) +{ + HRESULT hr; + struct events_callback *callback = events_callback_create(session, type); + callback->awaiting_event = TRUE; + hr = IMFMediaEventGenerator_BeginGetEvent(event_generator, &callback->IMFAsyncCallback_iface, punkState); + if (FAILED(hr)) + callback->awaiting_event = FALSE; + + IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); + + return hr; +} + static HRESULT session_subscribe_sources(struct media_session *session) { struct media_source *source; @@ -976,8 +996,8 @@ static HRESULT session_subscribe_sources(struct media_session *session)
LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { - if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback, - source->object))) + if (FAILED(hr = events_callback_begin((IMFMediaEventGenerator*)source->source, + session, MF_TOPOLOGY_SOURCESTREAM_NODE, source->object))) { WARN("Failed to subscribe to source events, hr %#lx.\n", hr); return hr; @@ -1425,8 +1445,8 @@ static void session_set_presentation_clock(struct media_session *session) if (node->type != MF_TOPOLOGY_OUTPUT_NODE) continue;
- if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback, - node->object.object))) + if (FAILED(hr = events_callback_begin((IMFMediaEventGenerator*)node->object.sink_stream, + session, MF_TOPOLOGY_OUTPUT_NODE, node->object.object))) { WARN("Failed to subscribe to stream sink events, hr %#lx.\n", hr); } @@ -1440,8 +1460,8 @@ static void session_set_presentation_clock(struct media_session *session)
LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry) { - if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator, - &session->events_callback, (IUnknown *)sink->event_generator))) + if (sink->event_generator && FAILED(hr = events_callback_begin((IMFMediaEventGenerator*)sink->event_generator, + session, MF_TOPOLOGY_OUTPUT_NODE, (IUnknown *)sink->event_generator))) { WARN("Failed to subscribe to sink events, hr %#lx.\n", hr); } @@ -2812,6 +2832,11 @@ static const IMFAsyncCallbackVtbl session_sa_ready_callback_vtbl = session_sa_ready_callback_Invoke, };
+static inline struct events_callback *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct events_callback, IMFAsyncCallback_iface); +} + static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) || @@ -2829,14 +2854,65 @@ static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *i
static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface) { - struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface); - return IMFMediaSession_AddRef(&session->IMFMediaSession_iface); + struct events_callback *callback = impl_from_events_callback_IMFAsyncCallback(iface); + ULONG refcount = InterlockedIncrement(&callback->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static void session_events_handle_shutdown(struct media_session *session, enum MF_TOPOLOGY_TYPE type) +{ + TRACE("session %p state %d type %d.\n", session, session->state, type); + + switch(session->state) + { + case SESSION_STATE_STARTING_SOURCES: + if (type == MF_TOPOLOGY_SOURCESTREAM_NODE) + session_command_complete_with_event(session, MESessionStarted, MF_E_SHUTDOWN, NULL); + break; + case SESSION_STATE_PREROLLING_SINKS: + case SESSION_STATE_STARTING_SINKS: + if (type == MF_TOPOLOGY_OUTPUT_NODE) + session_command_complete_with_event(session, MESessionStarted, MF_E_SHUTDOWN, NULL); + break; + + case SESSION_STATE_STOPPING_SINKS: + if (type == MF_TOPOLOGY_OUTPUT_NODE) + session_command_complete_with_event(session, (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS) ? MESessionClosed : MESessionStopped, MF_E_SHUTDOWN, NULL); + break; + case SESSION_STATE_STOPPING_SOURCES: + if (type == MF_TOPOLOGY_SOURCESTREAM_NODE) + session_command_complete_with_event(session, (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS) ? MESessionClosed : MESessionStopped, MF_E_SHUTDOWN, NULL); + break; + + default: + FIXME("unhandled session state %d %d %p\n", session->state, type, session); + break; + } }
static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface) { - struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface); - return IMFMediaSession_Release(&session->IMFMediaSession_iface); + struct events_callback *callback = impl_from_events_callback_IMFAsyncCallback(iface); + ULONG refcount = InterlockedDecrement(&callback->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + struct media_session *session = callback->session; + if (callback->awaiting_event) + { + WARN("Shutdown whilst waiting for event %p\n", session); + session_events_handle_shutdown(session, callback->type); + } + IMFMediaSession_Release(&session->IMFMediaSession_iface); + free(callback); + } + + return refcount; }
static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) @@ -4008,7 +4084,8 @@ static void session_sink_stream_scrub_complete(struct media_session *session, IM
static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { - struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface); + struct events_callback *callback = impl_from_events_callback_IMFAsyncCallback(iface); + struct media_session *session = callback->session; IMFMediaEventGenerator *event_source; IMFMediaEvent *event = NULL; MediaEventType event_type; @@ -4018,6 +4095,8 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM PROPVARIANT value; HRESULT hr;
+ callback->awaiting_event = FALSE; + if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source))) return hr;
@@ -4115,7 +4194,8 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
EnterCriticalSection(&session->cs); if (SUCCEEDED(hr = session_add_media_stream(session, source, stream))) - hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream); + hr = events_callback_begin((IMFMediaEventGenerator*)stream, + session, MF_TOPOLOGY_SOURCESTREAM_NODE, (IUnknown *)stream); LeaveCriticalSection(&session->cs);
IMFMediaSource_Release(source); @@ -4220,9 +4300,12 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
failed:
+ callback->awaiting_event = TRUE; if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source))) { + callback->awaiting_event = FALSE; WARN("Failed to re-subscribe, hr %#lx.\n", hr); + session_events_handle_shutdown(session, callback->type); IMFMediaEventQueue_QueueEvent(session->event_queue, event); }
@@ -4243,6 +4326,18 @@ static const IMFAsyncCallbackVtbl session_events_callback_vtbl = session_events_callback_Invoke, };
+static struct events_callback* events_callback_create(struct media_session *session, enum MF_TOPOLOGY_TYPE type) +{ + struct events_callback *callback = malloc(sizeof(*callback)); + callback->IMFAsyncCallback_iface.lpVtbl = &session_events_callback_vtbl; + callback->refcount = 1; + callback->awaiting_event = FALSE; + callback->session = session; + callback->type = type; + IMFMediaSession_AddRef(&session->IMFMediaSession_iface); + return callback; +} + static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) || @@ -4591,7 +4686,6 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl; object->commands_callback.lpVtbl = &session_commands_callback_vtbl; object->sa_ready_callback.lpVtbl = &session_sa_ready_callback_vtbl; - object->events_callback.lpVtbl = &session_events_callback_vtbl; object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl; object->refcount = 1; list_init(&object->topologies);