From 57e589f2e14fd515ff8e6c3df49cb478f9756384 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Dec 2025 13:57:50 +0100 Subject: [PATCH] stream: avoid flushing invoke before state change A flushing invoke is dangerous because the application might have queued a destroy, which could then be executed right while we do things. Avoid doing the flushing invoke from the state change function. This was done because previously we would invoke a process call when we were working in non-RT mode. Nowadays we run the process function right from the main thread and we don't need to invoke anymore. This also means that we can't have pending process calls to flush out when we go to paused. We do queue other calls, like drained and trigger-done but it should not cause problems to let those through after the state change. If this causes problems in the future, we can check the state before emiting them. Do a flushing invoke right before freeing the stream. This should be ok because we removed all signal hooks so that the pending invokes would not get to the app. Fixes #5010 --- src/pipewire/filter.c | 5 +++-- src/pipewire/stream.c | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pipewire/filter.c b/src/pipewire/filter.c index 58dd4c998..bb23c9d5c 100644 --- a/src/pipewire/filter.c +++ b/src/pipewire/filter.c @@ -507,8 +507,6 @@ static int impl_send_command(void *object, const struct spa_command *command) case SPA_NODE_COMMAND_Suspend: case SPA_NODE_COMMAND_Flush: case SPA_NODE_COMMAND_Pause: - pw_loop_invoke(impl->main_loop, - NULL, 0, NULL, 0, false, impl); if (filter->state == PW_FILTER_STATE_STREAMING && id != SPA_NODE_COMMAND_Flush) { pw_log_debug("%p: pause", filter); filter_set_state(filter, PW_FILTER_STATE_PAUSED, 0, NULL); @@ -1436,6 +1434,9 @@ void pw_filter_destroy(struct pw_filter *filter) spa_hook_list_clean(&impl->hooks); spa_hook_list_clean(&filter->listener_list); + /* Make sure there are no queued invokes from us anymore */ + pw_loop_invoke(impl->main_loop, NULL, 0, NULL, 0, false, impl); + filter_free(filter); } diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index cfe01d079..ea8dd9b79 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -715,9 +715,6 @@ static int impl_send_command(void *object, const struct spa_command *command) case SPA_NODE_COMMAND_Suspend: case SPA_NODE_COMMAND_Flush: case SPA_NODE_COMMAND_Pause: - /* this ensures we don't have any pending invokes in the queue after we - * emit the state change and/or command. */ - pw_loop_invoke(impl->main_loop, NULL, 0, NULL, 0, false, impl); if (stream->state == PW_STREAM_STATE_STREAMING && id != SPA_NODE_COMMAND_Flush) { pw_log_debug("%p: pause", stream); stream_set_state(stream, PW_STREAM_STATE_PAUSED, 0, NULL); @@ -1796,6 +1793,9 @@ void pw_stream_destroy(struct pw_stream *stream) spa_hook_list_clean(&impl->hooks); spa_hook_list_clean(&stream->listener_list); + /* Make sure there are no queued invokes from us anymore */ + pw_loop_invoke(impl->main_loop, NULL, 0, NULL, 0, false, impl); + stream_free(stream); }