From ff2420b70aa304507542cf22e5c73a9cc49b4690 Mon Sep 17 00:00:00 2001
From: Julian Bouzas <julian.bouzas@collabora.com>
Date: Mon, 24 Jun 2019 14:27:52 -0400
Subject: [PATCH] modules: add support for multiple channels linking

---
 .../module-pipewire/simple-endpoint-link.c    | 58 ++++++++++++++-----
 modules/module-pipewire/simple-endpoint.c     | 18 +++++-
 modules/module-pw-audio-softdsp-endpoint.c    | 43 +++++---------
 3 files changed, 73 insertions(+), 46 deletions(-)

diff --git a/modules/module-pipewire/simple-endpoint-link.c b/modules/module-pipewire/simple-endpoint-link.c
index 9b899369..a7e8edc7 100644
--- a/modules/module-pipewire/simple-endpoint-link.c
+++ b/modules/module-pipewire/simple-endpoint-link.c
@@ -48,31 +48,57 @@ simple_endpoint_link_create (WpEndpointLink * epl, GVariant * src_data,
 {
   WpPipewireSimpleEndpointLink *self = WP_PIPEWIRE_SIMPLE_ENDPOINT_LINK(epl);
   struct pw_properties *props;
-  guint32 output_node_id, input_node_id, output_port_id, input_port_id;
+  guint32 output_node_id, input_node_id;
+  GVariant *src_ports, *sink_ports;
+  GVariantIter *out_iter, *in_iter;
+  guint64 out_ptr, in_ptr;
 
   /* Get the node ids and port ids */
   if (!g_variant_lookup (src_data, "node-id", "u", &output_node_id))
       return FALSE;
-  if (!g_variant_lookup (src_data, "node-port-id", "u", &output_port_id))
+  src_ports = g_variant_lookup_value (src_data, "ports", G_VARIANT_TYPE_ARRAY);
+  if (!src_ports)
       return FALSE;
   if (!g_variant_lookup (sink_data, "node-id", "u", &input_node_id))
       return FALSE;
-  if (!g_variant_lookup (sink_data, "node-port-id", "u", &input_port_id))
+  sink_ports = g_variant_lookup_value (sink_data, "ports", G_VARIANT_TYPE_ARRAY);
+  if (!sink_ports)
       return FALSE;
 
-  /* Create the properties */
-  props = pw_properties_new(NULL, NULL);
-  pw_properties_setf(props, PW_LINK_OUTPUT_NODE_ID, "%d", output_node_id);
-  pw_properties_setf(props, PW_LINK_OUTPUT_PORT_ID, "%d", output_port_id);
-  pw_properties_setf(props, PW_LINK_INPUT_NODE_ID, "%d", input_node_id);
-  pw_properties_setf(props, PW_LINK_INPUT_PORT_ID, "%d", input_port_id);
-
-  /* Create the link */
-  pw_core_proxy_create_object(self->core_proxy, "link-factory",
-      PW_TYPE_INTERFACE_Link, PW_VERSION_LINK, &props->dict, 0);
-
-  /* Clean up */
-  pw_properties_free(props);
+  /* Link all the output ports with the input ports */
+  g_variant_get (src_ports, "at", &out_iter);
+  while (g_variant_iter_loop (out_iter, "t", &out_ptr)) {
+    WpProxyPort *out_p = (gpointer)out_ptr;
+    enum pw_direction out_direction = wp_proxy_port_get_info(out_p)->direction;
+    guint out_id = wp_proxy_get_global_id(WP_PROXY(out_p));
+    if (out_direction == PW_DIRECTION_INPUT)
+      continue;
+
+    g_variant_get (sink_ports, "at", &in_iter);
+    while (g_variant_iter_loop (in_iter, "t", &in_ptr)) {
+      WpProxyPort *in_p = (gpointer)in_ptr;
+      enum pw_direction in_direction = wp_proxy_port_get_info(in_p)->direction;
+      guint in_id = wp_proxy_get_global_id(WP_PROXY(in_p));
+      if (in_direction == PW_DIRECTION_OUTPUT)
+        continue;
+
+      /* Create the properties */
+      props = pw_properties_new(NULL, NULL);
+      pw_properties_setf(props, PW_LINK_OUTPUT_NODE_ID, "%d", output_node_id);
+      pw_properties_setf(props, PW_LINK_OUTPUT_PORT_ID, "%d", out_id);
+      pw_properties_setf(props, PW_LINK_INPUT_NODE_ID, "%d", input_node_id);
+      pw_properties_setf(props, PW_LINK_INPUT_PORT_ID, "%d", in_id);
+
+      /* Create the link */
+      pw_core_proxy_create_object(self->core_proxy, "link-factory",
+          PW_TYPE_INTERFACE_Link, PW_VERSION_LINK, &props->dict, 0);
+
+      /* Clean up */
+      pw_properties_free(props);
+    }
+    g_variant_iter_free (in_iter);
+  }
+  g_variant_iter_free (out_iter);
 
   return TRUE;
 }
diff --git a/modules/module-pipewire/simple-endpoint.c b/modules/module-pipewire/simple-endpoint.c
index d3d33766..6f617d50 100644
--- a/modules/module-pipewire/simple-endpoint.c
+++ b/modules/module-pipewire/simple-endpoint.c
@@ -363,19 +363,31 @@ simple_endpoint_get_property (GObject * object, guint property_id,
   }
 }
 
+static void
+proxies_port_foreach_func(gpointer data, gpointer user_data)
+{
+  GVariantBuilder *b = user_data;
+  g_variant_builder_add (b, "t", data);
+}
+
 static gboolean
 simple_endpoint_prepare_link (WpEndpoint * ep, guint32 stream_id,
     WpEndpointLink * link, GVariant ** properties, GError ** error)
 {
   WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (ep);
-  GVariantBuilder b;
+  GVariantBuilder b, *b_ports;
+  GVariant *v_ports;
+
+  /* Create a variant array with all the ports */
+  b_ports = g_variant_builder_new (G_VARIANT_TYPE ("at"));
+  g_ptr_array_foreach(self->proxies_port, proxies_port_foreach_func, b_ports);
+  v_ports = g_variant_builder_end (b_ports);
 
   /* Set the properties */
   g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
   g_variant_builder_add (&b, "{sv}", "node-id",
       g_variant_new_uint32 (self->global_id));
-  g_variant_builder_add (&b, "{sv}", "node-port-id",
-      g_variant_new_uint32 (-1));
+  g_variant_builder_add (&b, "{sv}", "ports", v_ports);
   *properties = g_variant_builder_end (&b);
 
   return TRUE;
diff --git a/modules/module-pw-audio-softdsp-endpoint.c b/modules/module-pw-audio-softdsp-endpoint.c
index f901508e..d7da449d 100644
--- a/modules/module-pw-audio-softdsp-endpoint.c
+++ b/modules/module-pw-audio-softdsp-endpoint.c
@@ -53,7 +53,6 @@ struct _WpPwAudioSoftdspEndpoint
   gboolean master_mute;
 
   /* DSP */
-  uint32_t dsp_port_id;
   struct spa_hook dsp_listener;
   struct pw_proxy *link_proxy;
 };
@@ -80,24 +79,37 @@ G_DEFINE_TYPE_WITH_CODE (WpPwAudioSoftdspEndpoint, endpoint, WP_TYPE_ENDPOINT,
     G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
                            wp_endpoint_async_initable_init))
 
+static void
+proxies_dsp_port_foreach_func(gpointer data, gpointer user_data)
+{
+  GVariantBuilder *b = user_data;
+  g_variant_builder_add (b, "t", data);
+}
+
 static gboolean
 endpoint_prepare_link (WpEndpoint * ep, guint32 stream_id,
     WpEndpointLink * link, GVariant ** properties, GError ** error)
 {
   WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (ep);
   const struct pw_node_info *dsp_info = NULL;
-  GVariantBuilder b;
+  GVariantBuilder b, *b_ports;
+  GVariant *v_ports;
 
   /* Get the dsp info */
   dsp_info = wp_proxy_node_get_info(self->proxy_dsp);
   g_return_val_if_fail (dsp_info, FALSE);
 
+  /* Create a variant array with all the ports */
+  b_ports = g_variant_builder_new (G_VARIANT_TYPE ("at"));
+  g_ptr_array_foreach(self->proxies_dsp_port, proxies_dsp_port_foreach_func,
+      b_ports);
+  v_ports = g_variant_builder_end (b_ports);
+
   /* Set the properties */
   g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
   g_variant_builder_add (&b, "{sv}", "node-id",
       g_variant_new_uint32 (dsp_info->id));
-  g_variant_builder_add (&b, "{sv}", "node-port-id",
-      g_variant_new_uint32 (self->dsp_port_id));
+  g_variant_builder_add (&b, "{sv}", "ports", v_ports);
   *properties = g_variant_builder_end (&b);
 
   return TRUE;
@@ -436,36 +448,13 @@ static void
 handle_dsp_port(WpPwAudioSoftdspEndpoint *self, guint id, guint parent_id,
   const struct spa_dict *props)
 {
-  const char *direction_prop = NULL;
   struct pw_port_proxy *port_proxy = NULL;
-  enum pw_direction direction;
 
   /* Create the proxy dsp port async */
   port_proxy = wp_remote_pipewire_proxy_bind (self->remote_pipewire, id,
       PW_TYPE_INTERFACE_Port);
   g_return_if_fail(port_proxy);
   wp_proxy_port_new(id, port_proxy, on_proxy_dsp_port_created, self);
-
-  /* Make sure the port has porperties */
-  g_return_if_fail(props);
-
-  /* TODO: For now we only handle 1 DSP port */
-  if (self->dsp_port_id != 0)
-    return;
-
-  /* Get the direction property */
-  direction_prop = spa_dict_lookup(props, "port.direction");
-  if (!direction_prop)
-    return;
-  direction =
-      !strcmp(direction_prop, "out") ? PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT;
-
-  /* Only handle ports with the opposite direction of the endpoint */
-  if (self->direction == direction)
-    return;
-
-  /* Set the dsp port id */
-  self->dsp_port_id = id;
 }
 
 static void
-- 
GitLab