diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c index 1e2184a20..147977e8f 100644 --- a/src/examples/media-session/media-session.c +++ b/src/examples/media-session/media-session.c @@ -2184,12 +2184,27 @@ static void session_shutdown(struct impl *impl) { struct sm_object *obj; struct registry_event *re; + struct spa_list free_list; pw_log_info(NAME" %p", impl); sm_media_session_emit_shutdown(impl); - spa_list_consume(obj, &impl->object_list, link) - sm_object_destroy(obj); + /* + * Monitors may still hold references to objects, which they + * drop in session destroy event, so don't free undiscarded + * objects yet. Destroy event handlers may remove any objects + * in the list, so iterate carefully. + */ + spa_list_init(&free_list); + spa_list_consume(obj, &impl->object_list, link) { + if (obj->destroyed) { + spa_list_remove(&obj->link); + spa_list_append(&free_list, &obj->link); + } else { + sm_object_destroy_maybe_free(obj); + } + } + spa_list_consume(re, &impl->registry_event_list, link) registry_event_free(re); @@ -2197,6 +2212,11 @@ static void session_shutdown(struct impl *impl) sm_media_session_emit_destroy(impl); + spa_list_consume(obj, &free_list, link) + sm_object_destroy(obj); + spa_list_consume(obj, &impl->object_list, link) + sm_object_destroy(obj); /* in case emit_destroy created new objects */ + if (impl->registry) { spa_hook_remove(&impl->registry_listener); pw_proxy_destroy((struct pw_proxy*)impl->registry);