session-item: handle destroyed endpoint links

We can now call wp_proxy_request_destroy() on endpoint links and
the WpImplEndpointLink together with the session item that created
it will be cleaned up
This commit is contained in:
George Kiagiadakis 2020-05-07 16:02:23 +03:00
parent ded2e34eb6
commit 9db4a54591
3 changed files with 169 additions and 0 deletions

View file

@ -682,6 +682,19 @@ on_stream_flags_changed (WpSessionItem * stream, WpSiFlags flags,
{
/* stream was deactivated; destroy the associated link */
if (!(flags & WP_SI_FLAG_ACTIVE)) {
wp_trace_object (link, "destroying because stream " WP_OBJECT_FORMAT
" was deactivated", WP_OBJECT_ARGS (stream));
wp_session_item_reset (link);
g_object_unref (link);
}
}
static void
on_link_flags_changed (WpSessionItem * link, WpSiFlags flags, gpointer data)
{
const guint mask = (WP_SI_FLAG_EXPORTED | WP_SI_FLAG_EXPORT_ERROR);
if ((flags & mask) == mask) {
wp_trace_object (link, "destroying because impl proxy was destroyed");
wp_session_item_reset (link);
g_object_unref (link);
}
@ -855,6 +868,8 @@ impl_create_link (void *object, const struct spa_dict *props)
G_CALLBACK (on_stream_flags_changed), link, 0);
g_signal_connect_object (peer_si_stream, "flags-changed",
G_CALLBACK (on_stream_flags_changed), link, 0);
g_signal_connect (link, "flags-changed",
G_CALLBACK (on_link_flags_changed), NULL);
wp_session_item_export (link, session,
(GAsyncReadyCallback) on_si_link_exported, self);

View file

@ -190,6 +190,7 @@ enum {
EXPORT_STEP_ENDPOINT = WP_TRANSITION_STEP_CUSTOM_START,
EXPORT_STEP_STREAMS,
EXPORT_STEP_LINK,
EXPORT_STEP_CONNECT_DESTROYED,
};
static guint
@ -229,6 +230,9 @@ wp_session_item_default_export_get_next_step (WpSessionItem * self,
case EXPORT_STEP_LINK:
g_return_val_if_fail (WP_IS_SI_LINK (self), WP_TRANSITION_STEP_ERROR);
return EXPORT_STEP_CONNECT_DESTROYED;
case EXPORT_STEP_CONNECT_DESTROYED:
return WP_TRANSITION_STEP_NONE;
default:
@ -261,6 +265,36 @@ on_export_proxy_augmented (WpProxy * proxy, GAsyncResult * res, gpointer data)
wp_transition_advance (transition);
}
static gboolean
on_export_proxy_destroyed_deferred (WpSessionItem * self)
{
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
g_return_val_if_fail (priv->impl_proxy, G_SOURCE_REMOVE);
g_return_val_if_fail (WP_SESSION_ITEM_GET_CLASS (self)->export_rollback,
G_SOURCE_REMOVE);
wp_info_object (self, "destroying " WP_OBJECT_FORMAT
" upon request by the server", WP_OBJECT_ARGS (priv->impl_proxy));
WP_SESSION_ITEM_GET_CLASS (self)->export_rollback (self);
priv->flags |= WP_SI_FLAG_EXPORT_ERROR;
g_signal_emit (self, signals[SIGNAL_FLAGS_CHANGED], 0, priv->flags);
return G_SOURCE_REMOVE;
}
static void
on_export_proxy_destroyed (WpProxy * proxy, gpointer data)
{
WpSessionItem *self = WP_SESSION_ITEM (data);
g_autoptr (WpCore) core = wp_proxy_get_core (proxy);
wp_core_idle_add_closure (core, NULL, g_cclosure_new_object (
G_CALLBACK (on_export_proxy_destroyed_deferred), G_OBJECT (self)));
}
static void
wp_session_item_default_export_execute_step (WpSessionItem * self,
WpTransition * transition, guint step)
@ -311,6 +345,12 @@ wp_session_item_default_export_execute_step (WpSessionItem * self,
transition);
break;
case EXPORT_STEP_CONNECT_DESTROYED:
g_signal_connect_object (priv->impl_proxy, "pw-proxy-destroyed",
G_CALLBACK (on_export_proxy_destroyed), self, 0);
wp_transition_advance (transition);
break;
default:
g_return_if_reached ();
}
@ -320,6 +360,8 @@ static void
wp_session_item_default_export_rollback (WpSessionItem * self)
{
WpSessionItemPrivate *priv = wp_session_item_get_instance_private (self);
if (priv->impl_proxy)
g_signal_handlers_disconnect_by_data (priv->impl_proxy, self);
g_clear_pointer (&priv->impl_streams, g_hash_table_unref);
g_clear_object (&priv->impl_proxy);
g_weak_ref_set (&priv->session, NULL);

View file

@ -235,6 +235,7 @@ test_si_standard_link_main (TestFixture * f, gconstpointer user_data)
g_assert_cmpuint (wp_endpoint_link_get_state (ep_link, &error), ==,
WP_ENDPOINT_LINK_STATE_ACTIVE);
g_assert_null (error);
g_assert_cmpint (f->activation_state, ==, 2);
}
/* verify the graph state */
@ -290,6 +291,7 @@ test_si_standard_link_main (TestFixture * f, gconstpointer user_data)
g_assert_cmpuint (wp_endpoint_link_get_state (ep_link, &error), ==,
WP_ENDPOINT_LINK_STATE_INACTIVE);
g_assert_null (error);
g_assert_cmpint (f->activation_state, ==, 3);
}
/* verify the graph state */
@ -328,6 +330,110 @@ test_si_standard_link_main (TestFixture * f, gconstpointer user_data)
}
}
static void
on_link_destroyed (WpEndpointLink * link, TestFixture * f)
{
f->activation_state = 10;
}
static void
test_si_standard_link_destroy (TestFixture * f, gconstpointer user_data)
{
g_autoptr (WpSession) session_proxy = NULL;
g_autoptr (WpEndpoint) src_ep = NULL;
g_autoptr (WpEndpoint) sink_ep = NULL;
g_autoptr (WpEndpointLink) ep_link = NULL;
/* find the "audio" session from the client */
{
g_autoptr (WpObjectManager) om = wp_object_manager_new ();
wp_object_manager_add_interest_1 (om, WP_TYPE_SESSION, NULL);
wp_object_manager_request_proxy_features (om, WP_TYPE_SESSION,
WP_SESSION_FEATURES_STANDARD);
g_signal_connect_swapped (om, "installed",
G_CALLBACK (g_main_loop_quit), f->base.loop);
wp_core_install_object_manager (f->base.client_core, om);
g_main_loop_run (f->base.loop);
g_assert_nonnull (session_proxy =
wp_object_manager_lookup (om, WP_TYPE_SESSION,
WP_CONSTRAINT_TYPE_PW_PROPERTY, "session.name", "=s", "audio", NULL));
g_assert_cmpint (wp_proxy_get_bound_id (WP_PROXY (session_proxy)), ==,
wp_proxy_get_bound_id (WP_PROXY (f->session)));
}
/* find the endpoints */
g_assert_nonnull (src_ep = wp_session_lookup_endpoint (session_proxy,
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "audiotestsrc",
NULL));
g_assert_nonnull (sink_ep = wp_session_lookup_endpoint (session_proxy,
WP_CONSTRAINT_TYPE_PW_PROPERTY, "endpoint.name", "=s", "fakesink",
NULL));
g_assert_cmpuint (wp_endpoint_get_n_streams (src_ep), ==, 1);
g_assert_cmpuint (wp_endpoint_get_n_streams (sink_ep), ==, 1);
/* create the link */
{
g_autoptr (WpProperties) props = NULL;
g_autofree gchar * id =
g_strdup_printf ("%u", wp_proxy_get_bound_id (WP_PROXY (sink_ep)));
/* only the peer endpoint id is required,
everything else will be discovered */
props = wp_properties_new ("endpoint-link.input.endpoint", id, NULL);
wp_endpoint_create_link (src_ep, props);
}
g_signal_connect_swapped (session_proxy, "links-changed",
G_CALLBACK (g_main_loop_quit), f->base.loop);
g_main_loop_run (f->base.loop);
/* verify */
g_assert_cmpuint (wp_session_get_n_links (session_proxy), ==, 1);
g_assert_nonnull (ep_link = wp_session_lookup_link (session_proxy, NULL));
g_assert_cmpuint (wp_endpoint_link_get_state (ep_link, NULL), ==,
WP_ENDPOINT_LINK_STATE_INACTIVE);
/* activate */
g_signal_connect (ep_link, "state-changed",
G_CALLBACK (on_link_state_changed), f);
wp_endpoint_link_request_state (ep_link, WP_ENDPOINT_LINK_STATE_ACTIVE);
g_main_loop_run (f->base.loop);
g_assert_cmpuint (wp_endpoint_link_get_state (ep_link, NULL), ==,
WP_ENDPOINT_LINK_STATE_ACTIVE);
/* destroy */
g_signal_connect (ep_link, "pw-proxy-destroyed",
G_CALLBACK (on_link_destroyed), f);
wp_proxy_request_destroy (WP_PROXY (ep_link));
/* loop will quit because the "links-changed" signal from the session
is still connected to quit() from earlier */
g_main_loop_run (f->base.loop);
g_assert_cmpint (f->activation_state, ==, 10);
g_assert_cmpuint (wp_session_get_n_links (session_proxy), ==, 0);
g_assert_cmpuint (wp_proxy_get_bound_id (WP_PROXY (ep_link)), ==, (guint) -1);
/* verify the link was also destroyed on the session manager core */
{
g_autoptr (WpObjectManager) om = wp_object_manager_new ();
wp_object_manager_add_interest_1 (om, WP_TYPE_ENDPOINT_LINK, NULL);
g_signal_connect_swapped (om, "installed",
G_CALLBACK (g_main_loop_quit), f->base.loop);
wp_core_install_object_manager (f->base.core, om);
if (!wp_object_manager_is_installed (om))
g_main_loop_run (f->base.loop);
g_assert_cmpuint (wp_object_manager_get_n_objects (om), ==, 0);
}
}
gint
main (gint argc, gchar *argv[])
{
@ -341,5 +447,11 @@ main (gint argc, gchar *argv[])
test_si_standard_link_main,
test_si_standard_link_teardown);
g_test_add ("/modules/si-standard-link/destroy",
TestFixture, NULL,
test_si_standard_link_setup,
test_si_standard_link_destroy,
test_si_standard_link_teardown);
return g_test_run ();
}