From 7966a8d45688ede44215d207518227fdbc665bf4 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis <george.kiagiadakis@collabora.com> Date: Tue, 5 May 2020 16:31:53 +0300 Subject: [PATCH] si-standard-link: fix endpoint linking bugs and add some debug statements --- lib/wp/endpoint-link.c | 2 +- lib/wp/endpoint.c | 92 ++++++++++++++++++------------ lib/wp/session-item.c | 19 +++++-- modules/module-si-standard-link.c | 95 ++++++++----------------------- 4 files changed, 94 insertions(+), 114 deletions(-) diff --git a/lib/wp/endpoint-link.c b/lib/wp/endpoint-link.c index 2bba0711..9f77ccdb 100644 --- a/lib/wp/endpoint-link.c +++ b/lib/wp/endpoint-link.c @@ -443,7 +443,7 @@ on_si_link_flags_changed (WpSiLink * item, WpSiFlags flags, { enum pw_endpoint_link_state old_state = self->info.state; - if (flags & WP_SI_FLAG_EXPORT_ERROR) + if (flags & WP_SI_FLAG_ACTIVATE_ERROR) self->info.state = PW_ENDPOINT_LINK_STATE_ERROR; else if (flags & WP_SI_FLAG_ACTIVE) self->info.state = PW_ENDPOINT_LINK_STATE_ACTIVE; diff --git a/lib/wp/endpoint.c b/lib/wp/endpoint.c index 3f1bb234..3d6d0a93 100644 --- a/lib/wp/endpoint.c +++ b/lib/wp/endpoint.c @@ -677,10 +677,14 @@ impl_set_param (void *object, uint32_t id, uint32_t flags, } static void -destroy_deconfigured_link (WpSessionItem * link, WpSiFlags flags, gpointer data) +on_stream_flags_changed (WpSessionItem * stream, WpSiFlags flags, + WpSessionItem * link) { - if (!(flags & WP_SI_FLAG_CONFIGURED)) + /* stream was deactivated; destroy the associated link */ + if (!(flags & WP_SI_FLAG_ACTIVE)) { + wp_session_item_reset (link); g_object_unref (link); + } } static void @@ -692,11 +696,7 @@ on_si_link_exported (WpSessionItem * link, GAsyncResult * res, gpointer data) if (!wp_session_item_export_finish (link, res, &error)) { wp_warning_object (self, "failed to export link: %s", error->message); g_object_unref (link); - return; } - - g_signal_connect (link, "flags-changed", - G_CALLBACK (destroy_deconfigured_link), NULL); } static int @@ -708,11 +708,14 @@ impl_create_link (void *object, const struct spa_dict *props) WpSiStream *self_si_stream = NULL; g_autoptr (WpSiStream) peer_si_stream = NULL; g_autoptr (WpSession) session = NULL; + g_autoptr (WpEndpointStream) self_stream_proxy = NULL; + g_autoptr (WpEndpoint) peer_ep_proxy = NULL; + g_autoptr (WpEndpointStream) peer_stream_proxy = NULL; /* find the session */ session = wp_session_item_get_associated_proxy ( WP_SESSION_ITEM (self->item), WP_TYPE_SESSION); - g_return_val_if_fail (!session, -ENAVAIL); + g_return_val_if_fail (session, -ENAVAIL); if (self->info.direction == PW_DIRECTION_OUTPUT) { self_ep = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT); @@ -726,6 +729,9 @@ impl_create_link (void *object, const struct spa_dict *props) peer_stream = spa_dict_lookup (props, PW_KEY_ENDPOINT_LINK_OUTPUT_STREAM); } + wp_debug_object (self, "requested link between %s:%s [self] & %s:%s [peer]", + self_ep, self_stream, peer_ep, peer_stream); + /* verify arguments */ if (!peer_ep) { wp_warning_object (self, @@ -770,42 +776,49 @@ impl_create_link (void *object, const struct spa_dict *props) return -EINVAL; } - /* find the peer stream */ - { - g_autoptr (WpEndpoint) peer_ep_proxy = NULL; - g_autoptr (WpEndpointStream) peer_stream_proxy = NULL; - - peer_ep_proxy = wp_session_lookup_endpoint (session, - WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", peer_ep_id, NULL); - if (!peer_ep_proxy) { - wp_warning_object (self, "endpoint %d not found in session", peer_ep_id); - return -EINVAL; - } + self_stream_proxy = wp_session_item_get_associated_proxy ( + WP_SESSION_ITEM (self_si_stream), WP_TYPE_ENDPOINT_STREAM); - if (peer_stream_id != SPA_ID_INVALID) { - peer_stream_proxy = wp_endpoint_lookup_stream (peer_ep_proxy, - WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", peer_stream_id, NULL); - } else { - peer_stream_proxy = wp_endpoint_lookup_stream (peer_ep_proxy, NULL); - } + /* find the peer stream */ + peer_ep_proxy = wp_session_lookup_endpoint (session, + WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", peer_ep_id, NULL); + if (!peer_ep_proxy) { + wp_warning_object (self, "endpoint %d not found in session", peer_ep_id); + return -EINVAL; + } - if (!peer_stream_proxy) { - wp_warning_object (self, "stream %d not found in %d", peer_stream_id, - peer_ep_id); - return -EINVAL; - } + if (peer_stream_id != SPA_ID_INVALID) { + peer_stream_proxy = wp_endpoint_lookup_stream (peer_ep_proxy, + WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", peer_stream_id, NULL); + } else { + peer_stream_proxy = wp_endpoint_lookup_stream (peer_ep_proxy, NULL); + } - if (!WP_IS_IMPL_ENDPOINT_LINK (peer_stream_proxy)) { - /* TODO - if the stream is not implemented by our session manager, - we can still make things work by calling the peer endpoint's - create_link() and negotiating ports, while creating a dummy - WpSiEndpoint / WpSiStream on our end to satisfy the API */ - return -ENAVAIL; - } + if (!peer_stream_proxy) { + wp_warning_object (self, "stream %d not found in %d", peer_stream_id, + peer_ep_id); + return -EINVAL; + } - g_object_get (peer_stream_proxy, "item", &peer_si_stream, NULL); + if (!WP_IS_IMPL_ENDPOINT_STREAM (peer_stream_proxy)) { + /* TODO - if the stream is not implemented by our session manager, + we can still make things work by calling the peer endpoint's + create_link() and negotiating ports, while creating a dummy + WpSiEndpoint / WpSiStream on our end to satisfy the API */ + return -ENAVAIL; } + g_object_get (peer_stream_proxy, "item", &peer_si_stream, NULL); + + wp_info_object (self, "creating endpoint link between " + "%s|%s " WP_OBJECT_FORMAT ", %s|%s " WP_OBJECT_FORMAT, + wp_endpoint_get_name (WP_ENDPOINT (self)), + wp_endpoint_stream_get_name (self_stream_proxy), + WP_OBJECT_ARGS (self_si_stream), + wp_endpoint_get_name (peer_ep_proxy), + wp_endpoint_stream_get_name (peer_stream_proxy), + WP_OBJECT_ARGS (peer_si_stream)); + /* create the link */ { g_autoptr (WpSessionItem) link = NULL; @@ -838,6 +851,11 @@ impl_create_link (void *object, const struct spa_dict *props) return -ENAVAIL; } + g_signal_connect_object (self_si_stream, "flags-changed", + 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); + wp_session_item_export (link, session, (GAsyncReadyCallback) on_si_link_exported, self); link = NULL; diff --git a/lib/wp/session-item.c b/lib/wp/session-item.c index de3459e1..906ba69e 100644 --- a/lib/wp/session-item.c +++ b/lib/wp/session-item.c @@ -144,6 +144,7 @@ wp_session_item_default_get_associated_proxy (WpSessionItem * self, GType proxy_type) { WpSessionItemPrivate *priv; + gpointer ret = NULL; if (WP_IS_SI_STREAM (self)) { g_autoptr (WpSiEndpoint) ep = @@ -154,23 +155,26 @@ wp_session_item_default_get_associated_proxy (WpSessionItem * self, } if (proxy_type == WP_TYPE_SESSION) { - return g_weak_ref_get (&priv->session); + ret = g_weak_ref_get (&priv->session); } else if (proxy_type == WP_TYPE_ENDPOINT) { if (priv->impl_proxy && WP_IS_ENDPOINT (priv->impl_proxy)) - return g_object_ref (priv->impl_proxy); + ret = g_object_ref (priv->impl_proxy); } else if (proxy_type == WP_TYPE_ENDPOINT_LINK) { if (priv->impl_proxy && WP_IS_ENDPOINT_LINK (priv->impl_proxy)) - return g_object_ref (priv->impl_proxy); + ret = g_object_ref (priv->impl_proxy); } else if (proxy_type == WP_TYPE_ENDPOINT_STREAM) { gpointer impl_stream = priv->impl_streams ? g_hash_table_lookup (priv->impl_streams, self) : NULL; - return impl_stream ? g_object_ref (impl_stream) : NULL; + ret = impl_stream ? g_object_ref (impl_stream) : NULL; } - return NULL; + wp_trace_object (self, "associated %s: " WP_OBJECT_FORMAT, + g_type_name (proxy_type), WP_OBJECT_ARGS (ret)); + + return ret; } static guint @@ -622,6 +626,8 @@ wp_session_item_activate (WpSessionItem * self, g_signal_connect (transition, "notify::completed", (GCallback) on_activate_transition_completed, self); + wp_debug_object (self, "activating item"); + priv->flags &= ~WP_SI_FLAG_ACTIVATE_ERROR; priv->flags |= WP_SI_FLAG_ACTIVATING; g_signal_emit (self, signals[SIGNAL_FLAGS_CHANGED], 0, priv->flags); @@ -750,6 +756,9 @@ wp_session_item_export (WpSessionItem * self, WpSession * session, g_signal_connect (transition, "notify::completed", (GCallback) on_export_transition_completed, self); + wp_debug_object (self, "exporting item on session " WP_OBJECT_FORMAT, + WP_OBJECT_ARGS (session)); + priv->flags &= ~WP_SI_FLAG_EXPORT_ERROR; priv->flags |= WP_SI_FLAG_EXPORTING; g_signal_emit (self, signals[SIGNAL_FLAGS_CHANGED], 0, priv->flags); diff --git a/modules/module-si-standard-link.c b/modules/module-si-standard-link.c index 3168ef3d..e50d0afd 100644 --- a/modules/module-si-standard-link.c +++ b/modules/module-si-standard-link.c @@ -33,37 +33,6 @@ G_DECLARE_FINAL_TYPE (WpSiStandardLink, si_standard_link, WP, SI_STANDARD_LINK, G_DEFINE_TYPE_WITH_CODE (WpSiStandardLink, si_standard_link, WP_TYPE_SESSION_ITEM, G_IMPLEMENT_INTERFACE (WP_TYPE_SI_LINK, si_standard_link_link_init)) -static void -on_stream_destroyed (gpointer data, GObject * stream) -{ - WpSiStandardLink *self = WP_SI_STANDARD_LINK (data); - - if ((gpointer) self->out_stream == (gpointer) stream) - self->out_stream = NULL; - else if ((gpointer) self->in_stream == (gpointer) stream) - self->in_stream = NULL; - - wp_session_item_reset (WP_SESSION_ITEM (self)); -} - -static void -on_stream_flags_changed (WpSessionItem * stream, WpSiFlags flags, - WpSiStandardLink *self) -{ - /* stream was deactivated; treat it as destroyed and reset */ - if (!(flags & WP_SI_FLAG_ACTIVE)) - wp_session_item_reset (WP_SESSION_ITEM (self)); -} - -static inline void -disconnect_stream (WpSiStandardLink *self, WpSiStream * stream) -{ - if (stream) { - g_signal_handlers_disconnect_by_data (stream, self); - g_object_weak_unref (G_OBJECT (stream), on_stream_destroyed, self); - } -} - static void si_standard_link_init (WpSiStandardLink * self) { @@ -76,8 +45,6 @@ si_standard_link_reset (WpSessionItem * item) WP_SESSION_ITEM_CLASS (si_standard_link_parent_class)->reset (item); - disconnect_stream (self, self->out_stream); - disconnect_stream (self, self->in_stream); self->out_stream = NULL; self->in_stream = NULL; @@ -124,19 +91,9 @@ si_standard_link_configure (WpSessionItem * item, GVariant * args) !(wp_session_item_get_flags (in_stream) & WP_SI_FLAG_ACTIVE)) return FALSE; - disconnect_stream (self, self->out_stream); - disconnect_stream (self, self->in_stream); - self->out_stream = WP_SI_STREAM (out_stream); self->in_stream = WP_SI_STREAM (in_stream); - g_signal_connect_object (self->out_stream, "flags-changed", - G_CALLBACK (on_stream_flags_changed), self, 0); - g_signal_connect_object (self->in_stream, "flags-changed", - G_CALLBACK (on_stream_flags_changed), self, 0); - g_object_weak_ref (G_OBJECT (self->out_stream), on_stream_destroyed, self); - g_object_weak_ref (G_OBJECT (self->in_stream), on_stream_destroyed, self); - wp_session_item_set_flag (item, WP_SI_FLAG_CONFIGURED); return TRUE; @@ -217,12 +174,12 @@ find_core (WpSiStandardLink * self) } static gboolean -create_links (WpSiStandardLink * self, GVariant * out_ports, GVariant * in_ports) +create_links (WpSiStandardLink * self, WpTransition * transition, + GVariant * out_ports, GVariant * in_ports) { g_autoptr (GPtrArray) in_ports_arr = NULL; g_autoptr (WpCore) core = NULL; - WpLink *link; - GVariantIter *iter; + GVariantIter *iter = NULL; GVariant *child; guint32 out_node_id, in_node_id; guint32 out_port_id, in_port_id; @@ -235,9 +192,9 @@ create_links (WpSiStandardLink * self, GVariant * out_ports, GVariant * in_ports uint32 port_id; uint32 channel; // enum spa_audio_channel */ - if (!g_variant_is_of_type (out_ports, G_VARIANT_TYPE("a(uuu)"))) + if (!out_ports || !g_variant_is_of_type (out_ports, G_VARIANT_TYPE("a(uuu)"))) return FALSE; - if (!g_variant_is_of_type (in_ports, G_VARIANT_TYPE("a(uuu)"))) + if (!in_ports || !g_variant_is_of_type (in_ports, G_VARIANT_TYPE("a(uuu)"))) return FALSE; core = find_core (self); @@ -253,8 +210,9 @@ create_links (WpSiStandardLink * self, GVariant * out_ports, GVariant * in_ports g_ptr_array_set_size (in_ports_arr, i); g_variant_get (in_ports, "a(uuu)", &iter); - while ((child = g_variant_iter_next_value (iter))) - g_ptr_array_insert (in_ports_arr, --i, child); + while ((child = g_variant_iter_next_value (iter))) { + g_ptr_array_index (in_ports_arr, --i) = child; + } g_variant_iter_free (iter); /* now loop over the out ports and figure out where they should be linked */ @@ -280,6 +238,7 @@ create_links (WpSiStandardLink * self, GVariant * out_ports, GVariant * in_ports in_channel == SPA_AUDIO_CHANNEL_UNKNOWN) { g_autoptr (WpProperties) props = NULL; + WpLink *link; /* Create the properties */ props = wp_properties_new_empty (); @@ -288,7 +247,7 @@ create_links (WpSiStandardLink * self, GVariant * out_ports, GVariant * in_ports wp_properties_setf (props, PW_KEY_LINK_INPUT_NODE, "%u", in_node_id); wp_properties_setf (props, PW_KEY_LINK_INPUT_PORT, "%u", in_port_id); - g_debug ("Create pw link: %u:%u (%s) -> %u:%u (%s)", + wp_debug_object (self, "create pw link: %u:%u (%s) -> %u:%u (%s)", out_node_id, out_port_id, spa_debug_type_find_name (spa_type_audio_channel, out_channel), in_node_id, in_port_id, @@ -302,7 +261,7 @@ create_links (WpSiStandardLink * self, GVariant * out_ports, GVariant * in_ports /* augment to ensure it is created without errors */ self->n_async_ops_wait++; wp_proxy_augment (WP_PROXY (link), WP_PROXY_FEATURES_STANDARD, NULL, - (GAsyncReadyCallback) on_link_augmented, self); + (GAsyncReadyCallback) on_link_augmented, transition); /* continue to link all input ports, if requested */ if (link_all) @@ -367,7 +326,7 @@ si_standard_link_activate_execute_step (WpSessionItem * item, in_ports = wp_si_port_info_get_ports (WP_SI_PORT_INFO (self->in_stream), NULL); - if (!create_links (self, out_ports, in_ports)) { + if (!create_links (self, transition, out_ports, in_ports)) { wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT, "Bad port info returned from one of the streams")); @@ -387,18 +346,19 @@ si_standard_link_activate_rollback (WpSessionItem * item) g_autoptr (WpSiEndpoint) in_endpoint = NULL; WpSiStreamAcquisition *out_acquisition, *in_acquisition; - out_endpoint = wp_si_stream_get_parent_endpoint (self->out_stream); - in_endpoint = wp_si_stream_get_parent_endpoint (self->in_stream); - out_acquisition = wp_si_endpoint_get_stream_acquisition (out_endpoint); - in_acquisition = wp_si_endpoint_get_stream_acquisition (in_endpoint); - - if (out_acquisition) { - wp_si_stream_acquisition_release (out_acquisition, WP_SI_LINK (self), - self->out_stream); + if (self->out_stream) { + out_endpoint = wp_si_stream_get_parent_endpoint (self->out_stream); + out_acquisition = wp_si_endpoint_get_stream_acquisition (out_endpoint); + if (out_acquisition) + wp_si_stream_acquisition_release (out_acquisition, WP_SI_LINK (self), + self->out_stream); } - if (in_acquisition) { - wp_si_stream_acquisition_release (in_acquisition, WP_SI_LINK (self), - self->in_stream); + if (self->in_stream) { + in_endpoint = wp_si_stream_get_parent_endpoint (self->in_stream); + in_acquisition = wp_si_endpoint_get_stream_acquisition (in_endpoint); + if (in_acquisition) + wp_si_stream_acquisition_release (in_acquisition, WP_SI_LINK (self), + self->in_stream); } g_clear_pointer (&self->node_links, g_ptr_array_unref); @@ -425,12 +385,6 @@ si_standard_link_get_registration_info (WpSiLink * item) return g_variant_builder_end (&b); } -static WpProperties * -si_standard_link_get_properties (WpSiLink * item) -{ - return wp_properties_new_empty (); -} - static WpSiStream * si_standard_link_get_out_stream (WpSiLink * item) { @@ -449,7 +403,6 @@ static void si_standard_link_link_init (WpSiLinkInterface * iface) { iface->get_registration_info = si_standard_link_get_registration_info; - iface->get_properties = si_standard_link_get_properties; iface->get_out_stream = si_standard_link_get_out_stream; iface->get_in_stream = si_standard_link_get_in_stream; } -- GitLab