diff --git a/modules/module-pipewire/simple-endpoint.c b/modules/module-pipewire/simple-endpoint.c index 7cdef091..0a5e3f17 100644 --- a/modules/module-pipewire/simple-endpoint.c +++ b/modules/module-pipewire/simple-endpoint.c @@ -260,6 +260,7 @@ on_proxy_node_created(GObject *initable, GAsyncResult *res, gpointer data) uint32_t ids[1] = { SPA_PARAM_Props }; uint32_t n_ids = 1; struct pw_node_proxy *node_proxy = NULL; + const struct spa_dict *props; /* Get the proxy node */ self->proxy_node = WP_PROXY_NODE (object_safe_new_finish (self, initable, @@ -267,11 +268,18 @@ on_proxy_node_created(GObject *initable, GAsyncResult *res, gpointer data) if (!self->proxy_node) return; + props = wp_proxy_node_get_info (self->proxy_node)->props; + /* Set the role and target name */ - self->role = g_strdup (spa_dict_lookup ( - wp_proxy_node_get_info (self->proxy_node)->props, "media.role")); - self->target = g_strdup (spa_dict_lookup ( - wp_proxy_node_get_info (self->proxy_node)->props, "target.name")); + self->role = g_strdup (spa_dict_lookup (props, "media.role")); + self->target = g_strdup (spa_dict_lookup (props, "target.name")); + + /* HACK to tell the policy module that this endpoint needs to be linked always */ + if (spa_dict_lookup (props, "wireplumber.keep-linked")) { + g_autofree gchar *c = g_strdup_printf ("Persistent/%s", + spa_dict_lookup(props, "media.class")); + g_object_set (self, "media-class", c, NULL); + } /* Emit the ports */ emit_endpoint_ports(self); diff --git a/modules/module-simple-policy.c b/modules/module-simple-policy.c index a11ffca9..1971d017 100644 --- a/modules/module-simple-policy.c +++ b/modules/module-simple-policy.c @@ -273,10 +273,12 @@ handle_client (WpPolicy *policy, WpEndpoint *ep) g_autoptr (WpEndpoint) target = NULL; guint32 stream_id; gboolean is_capture = FALSE; + gboolean is_persistent = FALSE; g_autofree gchar *role, *target_name = NULL; /* Detect if the client is doing capture or playback */ is_capture = g_str_has_prefix (media_class, "Stream/Input"); + is_persistent = g_str_has_prefix (media_class, "Persistent/"); /* Locate the target endpoint */ g_variant_dict_init (&d, NULL); @@ -334,10 +336,19 @@ handle_client (WpPolicy *policy, WpEndpoint *ep) * this function is being called after sorting all the client endpoints * and therefore we can safely unlink the previous client */ - if (wp_endpoint_is_linked (target) && !is_capture) { - g_debug ("Unlink target '%s' from other clients", - wp_endpoint_get_name (target)); - wp_endpoint_unlink (target); + if (!is_capture && wp_endpoint_is_linked (target)) { + if (is_persistent) { + /* HACK: link persistent endpoints to the already linked stream, + as linking to another stream does not work properly + (floatmix on the master dsp port does not accept the link) */ + GPtrArray *links = wp_endpoint_get_links (target); + WpEndpointLink *l = g_ptr_array_index (links, 0); + stream_id = wp_endpoint_link_get_sink_stream (l); + } else { + g_debug ("Unlink target '%s' from other clients", + wp_endpoint_get_name (target)); + wp_endpoint_unlink (target); + } } /* Link the client with the target */ @@ -411,6 +422,17 @@ simple_policy_rescan_in_idle (WpSimplePolicy *self) handle_client (WP_POLICY (self), ep); } } + g_clear_pointer (&endpoints, g_ptr_array_unref); + + endpoints = wp_endpoint_find (core, "Persistent/Stream/Input/Audio"); + if (endpoints) { + /* link all persistent capture clients */ + for (i = 0; i < endpoints->len; i++) { + ep = g_ptr_array_index (endpoints, i); + handle_client (WP_POLICY (self), ep); + } + } + g_clear_pointer (&endpoints, g_ptr_array_unref); endpoints = wp_endpoint_find (core, "Stream/Output/Audio"); if (endpoints && endpoints->len > 0) { @@ -422,6 +444,17 @@ simple_policy_rescan_in_idle (WpSimplePolicy *self) ep = g_ptr_array_index (endpoints, 0); handle_client (WP_POLICY (self), ep); } + g_clear_pointer (&endpoints, g_ptr_array_unref); + + endpoints = wp_endpoint_find (core, "Persistent/Stream/Output/Audio"); + if (endpoints) { + /* link all persistent output clients */ + for (i = 0; i < endpoints->len; i++) { + ep = g_ptr_array_index (endpoints, i); + handle_client (WP_POLICY (self), ep); + } + } + g_clear_pointer (&endpoints, g_ptr_array_unref); self->pending_rescan = 0; return G_SOURCE_REMOVE; @@ -443,8 +476,7 @@ simple_policy_handle_endpoint (WpPolicy *policy, WpEndpoint *ep) /* TODO: For now we only accept audio stream clients */ media_class = wp_endpoint_get_media_class(ep); - if (!g_str_has_prefix (media_class, "Stream") || - !g_str_has_suffix (media_class, "Audio")) { + if (!g_str_has_suffix (media_class, "Audio")) { return FALSE; }