From fe1ac40919fbfc0da6a8f7134e12950a469c6615 Mon Sep 17 00:00:00 2001
From: George Kiagiadakis <george.kiagiadakis@collabora.com>
Date: Mon, 11 May 2020 09:56:06 +0300
Subject: [PATCH] endpoint: ensure that streams are available when
 FEATURE_STREAMS is declared as ready

---
 lib/wp/endpoint.c     | 23 ++++++++++++++++++-----
 lib/wp/session-item.c | 21 +++++++++++++++++++--
 2 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/lib/wp/endpoint.c b/lib/wp/endpoint.c
index bb30d41c..a2da28e7 100644
--- a/lib/wp/endpoint.c
+++ b/lib/wp/endpoint.c
@@ -88,6 +88,7 @@ wp_endpoint_emit_streams_changed (WpObjectManager *streams_om,
     WpEndpoint * self)
 {
   g_signal_emit (self, signals[SIGNAL_STREAMS_CHANGED], 0);
+  wp_proxy_set_feature_ready (WP_PROXY (self), WP_ENDPOINT_FEATURE_STREAMS);
 }
 
 static void
@@ -97,15 +98,15 @@ wp_endpoint_ensure_feature_streams (WpEndpoint * self, guint32 bound_id)
   WpProxyFeatures ft = wp_proxy_get_features (WP_PROXY (self));
 
   if (priv->ft_streams_requested && !priv->streams_om &&
-      (ft & WP_PROXY_FEATURE_BOUND))
+      (ft & WP_PROXY_FEATURES_STANDARD) == WP_PROXY_FEATURES_STANDARD)
   {
     g_autoptr (WpCore) core = wp_proxy_get_core (WP_PROXY (self));
 
     if (!bound_id)
       bound_id = wp_proxy_get_bound_id (WP_PROXY (self));
 
-    wp_debug_object (self, "enabling WP_ENDPOINT_FEATURE_STREAMS, bound_id:%u",
-        bound_id);
+    wp_debug_object (self, "enabling WP_ENDPOINT_FEATURE_STREAMS, bound_id:%u, "
+        "n_streams:%u", bound_id, priv->info->n_streams);
 
     priv->streams_om = wp_object_manager_new ();
     /* proxy endpoint stream -> check for endpoint.id in global properties */
@@ -121,8 +122,18 @@ wp_endpoint_ensure_feature_streams (WpEndpoint * self, guint32 bound_id)
     wp_object_manager_request_proxy_features (priv->streams_om,
         WP_TYPE_ENDPOINT_STREAM, WP_PROXY_FEATURES_STANDARD);
 
-    g_signal_connect_object (priv->streams_om, "installed",
-        G_CALLBACK (wp_endpoint_on_streams_om_installed), self, 0);
+    /* endpoints, under normal circumstances, always have streams.
+       When we export (self is a WpImplEndpoint), we have to export first
+       the endpoint and afterwards the streams (so that the streams can be
+       associated with the endpoint's bound id), but then the issue is that
+       the "installed" signal gets fired here without any streams being ready
+       and we get an endpoint with 0 streams in the WpSession's endpoints
+       object manager... so, unless the endpoint really has no streams,
+       wait for them to be prepared by waiting for the "objects-changed" only */
+    if (G_UNLIKELY (priv->info->n_streams == 0)) {
+      g_signal_connect_object (priv->streams_om, "installed",
+          G_CALLBACK (wp_endpoint_on_streams_om_installed), self, 0);
+    }
     g_signal_connect_object (priv->streams_om, "objects-changed",
         G_CALLBACK (wp_endpoint_emit_streams_changed), self, 0);
 
@@ -237,6 +248,8 @@ endpoint_event_info (void *data, const struct pw_endpoint_info *info)
 
   if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS)
     g_object_notify (G_OBJECT (self), "properties");
+
+  wp_endpoint_ensure_feature_streams (self, 0);
 }
 
 static const struct pw_endpoint_events endpoint_events = {
diff --git a/lib/wp/session-item.c b/lib/wp/session-item.c
index dd4b6117..d9b61c8c 100644
--- a/lib/wp/session-item.c
+++ b/lib/wp/session-item.c
@@ -189,6 +189,7 @@ wp_session_item_default_activate_get_next_step (WpSessionItem * self,
 enum {
   EXPORT_STEP_ENDPOINT = WP_TRANSITION_STEP_CUSTOM_START,
   EXPORT_STEP_STREAMS,
+  EXPORT_STEP_ENDPOINT_FT_STREAMS,
   EXPORT_STEP_LINK,
   EXPORT_STEP_CONNECT_DESTROYED,
 };
@@ -224,10 +225,13 @@ wp_session_item_default_export_get_next_step (WpSessionItem * self,
     /* go to next step only when all impl proxies are augmented */
     if (g_hash_table_size (priv->impl_streams) ==
         wp_si_endpoint_get_n_streams (WP_SI_ENDPOINT (self)))
-      return WP_TRANSITION_STEP_NONE;
+      return EXPORT_STEP_ENDPOINT_FT_STREAMS;
     else
       return step;
 
+  case EXPORT_STEP_ENDPOINT_FT_STREAMS:
+    return WP_TRANSITION_STEP_NONE;
+
   case EXPORT_STEP_LINK:
     g_return_val_if_fail (WP_IS_SI_LINK (self), WP_TRANSITION_STEP_ERROR);
     return EXPORT_STEP_CONNECT_DESTROYED;
@@ -262,6 +266,9 @@ on_export_proxy_augmented (WpProxy * proxy, GAsyncResult * res, gpointer data)
     g_hash_table_insert (priv->impl_streams, si_stream, g_object_ref (proxy));
   }
 
+  wp_debug_object (self, "export proxy " WP_OBJECT_FORMAT " augmented",
+      WP_OBJECT_ARGS (proxy));
+
   wp_transition_advance (transition);
 }
 
@@ -308,7 +315,7 @@ wp_session_item_default_export_execute_step (WpSessionItem * self,
     priv->impl_endpoint = wp_impl_endpoint_new (core, WP_SI_ENDPOINT (self));
 
     wp_proxy_augment (WP_PROXY (priv->impl_endpoint),
-        WP_ENDPOINT_FEATURES_STANDARD, NULL,
+        WP_PROXY_FEATURES_STANDARD, NULL,
         (GAsyncReadyCallback) on_export_proxy_augmented,
         transition);
     break;
@@ -336,6 +343,16 @@ wp_session_item_default_export_execute_step (WpSessionItem * self,
     }
     break;
   }
+  case EXPORT_STEP_ENDPOINT_FT_STREAMS:
+    /* add feature streams only after the streams are exported, otherwise
+       the endpoint will never be augmented in the first place (because it
+       internally waits for the streams to be ready) */
+    wp_proxy_augment (WP_PROXY (priv->impl_endpoint),
+        WP_ENDPOINT_FEATURE_STREAMS, NULL,
+        (GAsyncReadyCallback) on_export_proxy_augmented,
+        transition);
+    break;
+
   case EXPORT_STEP_LINK:
     priv->impl_link = wp_impl_endpoint_link_new (core, WP_SI_LINK (self));
 
-- 
GitLab