From 116376a0a6fcd78b9d11dbfbf2ee8e453c6e6bf4 Mon Sep 17 00:00:00 2001
From: Julian Bouzas <julian.bouzas@collabora.com>
Date: Thu, 9 Jan 2020 13:45:06 -0500
Subject: [PATCH] proxy: add local_object property to handle local objects

---
 lib/wp/core.c    | 19 +++++++-----
 lib/wp/monitor.c |  4 +--
 lib/wp/private.h |  3 ++
 lib/wp/proxy.c   | 78 +++++++++++++++++++++++++++++++++++-------------
 lib/wp/proxy.h   |  4 +--
 5 files changed, 76 insertions(+), 32 deletions(-)

diff --git a/lib/wp/core.c b/lib/wp/core.c
index 85d45b68..5a86415c 100644
--- a/lib/wp/core.c
+++ b/lib/wp/core.c
@@ -552,7 +552,7 @@ wp_core_create_local_object (WpCore * self, const gchar *factory_name,
 {
   struct pw_proxy *pw_proxy = NULL;
   struct pw_factory *factory = NULL;
-  gpointer iface = NULL;
+  gpointer local_object = NULL;
 
   g_return_val_if_fail (WP_IS_CORE (self), NULL);
   g_return_val_if_fail (self->pw_core, NULL);
@@ -562,24 +562,27 @@ wp_core_create_local_object (WpCore * self, const gchar *factory_name,
   if (!factory)
     return NULL;
 
-  iface = pw_factory_create_object (factory,
+  local_object = pw_factory_create_object (factory,
       NULL,
       interface_type,
       interface_version,
       properties ? wp_properties_to_pw_properties (properties) : NULL,
       0);
-  if (!iface)
+  if (!local_object)
     return NULL;
 
   pw_proxy = pw_remote_export (self->pw_remote,
       interface_type,
       properties ? wp_properties_to_pw_properties (properties) : NULL,
-      iface,
+      local_object,
       0);
-  if (!pw_proxy)
+  if (!pw_proxy) {
+    wp_proxy_local_object_destroy_for_type (interface_type, local_object);
     return NULL;
+  }
 
-  return wp_proxy_new_wrap (self, pw_proxy, interface_type, interface_version);
+  return wp_proxy_new_wrap (self, pw_proxy, interface_type, interface_version,
+      local_object);
 }
 
 WpProxy *
@@ -595,8 +598,8 @@ wp_core_create_remote_object (WpCore *self,
   pw_proxy = pw_core_proxy_create_object (self->core_proxy, factory_name,
       interface_type, interface_version,
       properties ? wp_properties_peek_dict (properties) : NULL, 0);
-  return wp_proxy_new_wrap (self, pw_proxy, interface_type,
-      interface_version);
+  return wp_proxy_new_wrap (self, pw_proxy, interface_type, interface_version,
+      NULL);
 }
 
 struct pw_core_proxy *
diff --git a/lib/wp/monitor.c b/lib/wp/monitor.c
index 7be2aae6..d32bb8ce 100644
--- a/lib/wp/monitor.c
+++ b/lib/wp/monitor.c
@@ -301,7 +301,7 @@ node_new (struct object *dev, uint32_t id,
   node->type = SPA_TYPE_INTERFACE_Node;
   node->node = pw_node;
   node->proxy = wp_proxy_new_wrap (core, pw_proxy, PW_TYPE_INTERFACE_Node,
-      PW_VERSION_NODE_PROXY);
+      PW_VERSION_NODE_PROXY, NULL);
 
   return node;
 }
@@ -368,7 +368,7 @@ device_new (WpMonitor *self, uint32_t id, const gchar *factory_name,
   dev->spa_dev = g_steal_pointer (&spa_dev);
   dev->properties = g_steal_pointer (&props);
   dev->proxy = wp_proxy_new_wrap (core, proxy, PW_TYPE_INTERFACE_Device,
-      PW_VERSION_DEVICE_PROXY);
+      PW_VERSION_DEVICE_PROXY, NULL);
 
   /* Add device listener for events */
   if ((ret = spa_device_add_listener ((struct spa_device *) dev->spa_dev->interface,
diff --git a/lib/wp/private.h b/lib/wp/private.h
index 2dbda919..682c06dd 100644
--- a/lib/wp/private.h
+++ b/lib/wp/private.h
@@ -85,6 +85,9 @@ void wp_object_manager_rm_object (WpObjectManager * self, GObject * object);
 
 /* proxy */
 
+void wp_proxy_local_object_destroy_for_type (guint32 type,
+    gpointer local_object);
+
 WpProxy * wp_proxy_new_global (WpCore * core, WpGlobal * global);
 
 void wp_proxy_set_feature_ready (WpProxy * self, WpProxyFeatures feature);
diff --git a/lib/wp/proxy.c b/lib/wp/proxy.c
index 99a4e3a0..e5b2c626 100644
--- a/lib/wp/proxy.c
+++ b/lib/wp/proxy.c
@@ -34,6 +34,7 @@ struct _WpProxyPrivate
 
   guint32 iface_type;
   guint32 iface_version;
+  gpointer local_object;
 
   struct pw_proxy *pw_proxy;
 
@@ -58,6 +59,7 @@ enum {
   PROP_INTERFACE_NAME,
   PROP_INTERFACE_QUARK,
   PROP_INTERFACE_VERSION,
+  PROP_LOCAL_OBJECT,
   PROP_PW_PROXY,
   PROP_FEATURES,
 };
@@ -101,24 +103,26 @@ static struct {
   GType (*get_type) (void);
   /* a function returning a quark that identifies the interface */
   GQuark (*get_quark) (void);
+  /* the destroy function of the local object, if any */
+  void (*local_object_destroy) (gpointer);
 } types_assoc[] = {
-  { PW_TYPE_INTERFACE_Core, 0, wp_proxy_get_type, wp_proxy_core_quark },
-  { PW_TYPE_INTERFACE_Registry, 0, wp_proxy_get_type, wp_proxy_registry_quark },
-  { PW_TYPE_INTERFACE_Node, 0, wp_proxy_node_get_type, wp_proxy_node_quark },
-  { PW_TYPE_INTERFACE_Port, 0, wp_proxy_port_get_type, wp_proxy_port_quark },
-  { PW_TYPE_INTERFACE_Factory, 0, wp_proxy_get_type, wp_proxy_factory_quark },
-  { PW_TYPE_INTERFACE_Link, 0, wp_proxy_link_get_type, wp_proxy_link_quark },
-  { PW_TYPE_INTERFACE_Client, 0, wp_proxy_client_get_type, wp_proxy_client_quark },
-  { PW_TYPE_INTERFACE_Module, 0, wp_proxy_get_type, wp_proxy_module_quark },
-  { PW_TYPE_INTERFACE_Device, 0, wp_proxy_device_get_type, wp_proxy_device_quark },
-  { PW_TYPE_INTERFACE_Metadata, 0, wp_proxy_get_type, wp_proxy_metadata_quark },
-  { PW_TYPE_INTERFACE_Session, 0, wp_proxy_session_get_type, wp_proxy_session_quark },
-  { PW_TYPE_INTERFACE_Endpoint, 0, wp_proxy_endpoint_get_type, wp_proxy_endpoint_quark },
-  { PW_TYPE_INTERFACE_EndpointStream, 0, wp_proxy_get_type, wp_proxy_endpoint_stream_quark },
-  { PW_TYPE_INTERFACE_EndpointLink, 0, wp_proxy_get_type, wp_proxy_endpoint_link_quark },
-  { PW_TYPE_INTERFACE_ClientNode, 0, wp_proxy_get_type, wp_proxy_client_node_quark },
-  { PW_TYPE_INTERFACE_ClientSession, 0, wp_proxy_get_type, wp_proxy_client_session_quark },
-  { PW_TYPE_INTERFACE_ClientEndpoint, 0, wp_proxy_get_type, wp_proxy_client_endpoint_quark },
+  { PW_TYPE_INTERFACE_Core, 0, wp_proxy_get_type, wp_proxy_core_quark, NULL },
+  { PW_TYPE_INTERFACE_Registry, 0, wp_proxy_get_type, wp_proxy_registry_quark, NULL },
+  { PW_TYPE_INTERFACE_Node, 0, wp_proxy_node_get_type, wp_proxy_node_quark, (GDestroyNotify)pw_node_destroy },
+  { PW_TYPE_INTERFACE_Port, 0, wp_proxy_port_get_type, wp_proxy_port_quark, NULL, },
+  { PW_TYPE_INTERFACE_Factory, 0, wp_proxy_get_type, wp_proxy_factory_quark, (GDestroyNotify)pw_factory_destroy },
+  { PW_TYPE_INTERFACE_Link, 0, wp_proxy_link_get_type, wp_proxy_link_quark, (GDestroyNotify)pw_link_destroy },
+  { PW_TYPE_INTERFACE_Client, 0, wp_proxy_client_get_type, wp_proxy_client_quark, (GDestroyNotify)pw_client_destroy },
+  { PW_TYPE_INTERFACE_Module, 0, wp_proxy_get_type, wp_proxy_module_quark, (GDestroyNotify)pw_module_destroy },
+  { PW_TYPE_INTERFACE_Device, 0, wp_proxy_device_get_type, wp_proxy_device_quark, (GDestroyNotify)pw_device_destroy },
+  { PW_TYPE_INTERFACE_Metadata, 0, wp_proxy_get_type, wp_proxy_metadata_quark, NULL },
+  { PW_TYPE_INTERFACE_Session, 0, wp_proxy_session_get_type, wp_proxy_session_quark, NULL },
+  { PW_TYPE_INTERFACE_Endpoint, 0, wp_proxy_endpoint_get_type, wp_proxy_endpoint_quark, NULL },
+  { PW_TYPE_INTERFACE_EndpointStream, 0, wp_proxy_get_type, wp_proxy_endpoint_stream_quark, NULL, },
+  { PW_TYPE_INTERFACE_EndpointLink, 0, wp_proxy_get_type, wp_proxy_endpoint_link_quark, NULL, },
+  { PW_TYPE_INTERFACE_ClientNode, 0, wp_proxy_get_type, wp_proxy_client_node_quark, NULL },
+  { PW_TYPE_INTERFACE_ClientSession, 0, wp_proxy_get_type, wp_proxy_client_session_quark, NULL },
+  { PW_TYPE_INTERFACE_ClientEndpoint, 0, wp_proxy_get_type, wp_proxy_client_endpoint_quark, NULL },
 };
 
 static inline GType
@@ -144,6 +148,20 @@ wp_proxy_find_quark_for_type (guint32 type)
   return 0;
 }
 
+void
+wp_proxy_local_object_destroy_for_type (guint32 type, gpointer local_object)
+{
+  g_return_if_fail (local_object);
+
+  for (gint i = 0; i < SPA_N_ELEMENTS (types_assoc); i++) {
+    if (types_assoc[i].pw_type == type) {
+      if (types_assoc[i].local_object_destroy)
+         types_assoc[i].local_object_destroy (local_object);
+      return;
+    }
+  }
+}
+
 static void
 proxy_event_destroy (void *data)
 {
@@ -255,7 +273,15 @@ wp_proxy_dispose (GObject * object)
 static void
 wp_proxy_finalize (GObject * object)
 {
-  WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
+  WpProxy *self = WP_PROXY (object);
+  WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
+
+  /* Clear the local object */
+  if (priv->local_object) {
+    wp_proxy_local_object_destroy_for_type (priv->iface_type,
+        priv->local_object);
+    priv->local_object = NULL;
+  }
 
   g_clear_pointer (&priv->augment_tasks, g_ptr_array_unref);
   g_clear_pointer (&priv->global, wp_global_unref);
@@ -284,6 +310,9 @@ wp_proxy_set_property (GObject * object, guint property_id,
   case PROP_INTERFACE_VERSION:
     priv->iface_version = g_value_get_uint (value);
     break;
+  case PROP_LOCAL_OBJECT:
+    priv->local_object = g_value_get_pointer (value);
+    break;
   case PROP_PW_PROXY:
     priv->pw_proxy = g_value_get_pointer (value);
     break;
@@ -325,6 +354,9 @@ wp_proxy_get_property (GObject * object, guint property_id, GValue * value,
   case PROP_INTERFACE_VERSION:
     g_value_set_uint (value, priv->iface_version);
     break;
+  case PROP_LOCAL_OBJECT:
+    g_value_set_pointer (value, priv->local_object);
+    break;
   case PROP_PW_PROXY:
     g_value_set_pointer (value, priv->pw_proxy);
     break;
@@ -429,6 +461,11 @@ wp_proxy_class_init (WpProxyClass * klass)
           "The pipewire interface version", 0, G_MAXUINT, 0,
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (object_class, PROP_LOCAL_OBJECT,
+      g_param_spec_pointer ("local-object", "local-object",
+          "The local object this proxy refers to, if any",
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_property (object_class, PROP_PW_PROXY,
       g_param_spec_pointer ("pw-proxy", "pw-proxy", "The struct pw_proxy *",
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
@@ -463,8 +500,8 @@ wp_proxy_new_global (WpCore * core, WpGlobal * global)
 }
 
 WpProxy *
-wp_proxy_new_wrap (WpCore * core,
-    struct pw_proxy * proxy, guint32 type, guint32 version)
+wp_proxy_new_wrap (WpCore * core, struct pw_proxy * proxy, guint32 type,
+    guint32 version, gpointer local_object)
 {
   GType gtype = wp_proxy_find_instance_type (type, version);
   return g_object_new (gtype,
@@ -472,6 +509,7 @@ wp_proxy_new_wrap (WpCore * core,
       "pw-proxy", proxy,
       "interface-type", type,
       "interface-version", version,
+      "local-object", local_object,
       NULL);
 }
 
diff --git a/lib/wp/proxy.h b/lib/wp/proxy.h
index 75eda4d5..5408ab86 100644
--- a/lib/wp/proxy.h
+++ b/lib/wp/proxy.h
@@ -40,8 +40,8 @@ struct _WpProxyClass
   void (*pw_proxy_destroyed) (WpProxy * self);
 };
 
-WpProxy * wp_proxy_new_wrap (WpCore * core,
-    struct pw_proxy * proxy, guint32 type, guint32 version);
+WpProxy * wp_proxy_new_wrap (WpCore * core, struct pw_proxy * proxy,
+    guint32 type, guint32 version, gpointer local_object);
 
 void wp_proxy_augment (WpProxy *self,
     WpProxyFeatures wanted_features, GCancellable * cancellable,
-- 
GitLab