diff --git a/lib/wp/remote-pipewire.c b/lib/wp/remote-pipewire.c
index 66bb09c5b52bc9eb9256afeb914092ded1a0d5e6..023190c065d3cb917fdb2e1432a8dc8ebd6844c9 100644
--- a/lib/wp/remote-pipewire.c
+++ b/lib/wp/remote-pipewire.c
@@ -15,6 +15,9 @@
 
 #define WP_LOOP_SOURCE(x) ((WpLoopSource *) x)
 
+G_DEFINE_QUARK (node, signal_detail_node)
+G_DEFINE_QUARK (port, signal_detail_port)
+
 typedef struct _WpLoopSource WpLoopSource;
 struct _WpLoopSource
 {
@@ -74,6 +77,11 @@ struct _WpRemotePipewire
   struct pw_core *core;
   struct pw_remote *remote;
   struct spa_hook remote_listener;
+  struct pw_core_proxy *core_proxy;
+
+  /* Registry */
+  struct pw_registry_proxy *registry_proxy;
+  struct spa_hook registry_listener;
 
   GMainContext *context;
 };
@@ -87,8 +95,61 @@ enum {
   PROP_CONTEXT,
 };
 
+enum
+{
+  SIGNAL_GLOBAL_ADDED,
+  SIGNAL_GLOBAL_REMOVED,
+  LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 G_DEFINE_TYPE (WpRemotePipewire, wp_remote_pipewire, WP_TYPE_REMOTE)
 
+static void
+registry_global(void *data, uint32_t id, uint32_t parent_id,
+		uint32_t permissions, uint32_t type, uint32_t version,
+		const struct spa_dict *props)
+{
+  switch (type) {
+  case PW_TYPE_INTERFACE_Node:
+    g_signal_emit (data, signals[SIGNAL_GLOBAL_ADDED],
+        signal_detail_node_quark (), id, parent_id, props);
+    break;
+  case PW_TYPE_INTERFACE_Port:
+    g_signal_emit (data, signals[SIGNAL_GLOBAL_ADDED],
+        signal_detail_port_quark (), id, parent_id, props);
+    break;
+  default:
+    break;
+  }
+}
+
+static void
+registry_global_remove (void *data, uint32_t id)
+{
+  g_signal_emit (data, signals[SIGNAL_GLOBAL_REMOVED], 0, id);
+}
+
+static const struct pw_registry_proxy_events registry_proxy_events = {
+  PW_VERSION_REGISTRY_PROXY_EVENTS,
+  .global = registry_global,
+  .global_remove = registry_global_remove,
+};
+
+static void
+registry_init (WpRemotePipewire *self)
+{
+  /* Get the core proxy */
+  self->core_proxy = pw_remote_get_core_proxy (self->remote);
+
+  /* Registry */
+  self->registry_proxy = pw_core_proxy_get_registry (self->core_proxy,
+      PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0);
+  pw_registry_proxy_add_listener(self->registry_proxy, &self->registry_listener,
+      &registry_proxy_events, self);
+}
+
 static void
 on_remote_state_changed (void *d, enum pw_remote_state old_state,
     enum pw_remote_state new_state, const char *error)
@@ -99,6 +160,10 @@ on_remote_state_changed (void *d, enum pw_remote_state old_state,
       pw_remote_state_as_string (old_state),
       pw_remote_state_as_string (new_state));
 
+  /* Init the registry when connected */
+  if (!self->registry_proxy && new_state == PW_REMOTE_STATE_CONNECTED)
+    registry_init (self);
+
   g_object_notify (G_OBJECT (self), "state");
 }
 
@@ -138,6 +203,8 @@ wp_remote_pipewire_finalize (GObject *object)
   pw_remote_destroy (self->remote);
   pw_core_destroy (self->core);
   g_clear_pointer (&self->context, g_main_context_unref);
+  self->core_proxy= NULL;
+  self->registry_proxy = NULL;
 
   G_OBJECT_CLASS (wp_remote_pipewire_parent_class)->finalize (object);
 }
@@ -242,6 +309,15 @@ wp_remote_pipewire_class_init (WpRemotePipewireClass *klass)
   g_object_class_install_property (object_class, PROP_PW_REMOTE,
       g_param_spec_pointer ("pw-remote", "pw-remote", "The pipewire remote",
           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  /* Signals */
+  signals[SIGNAL_GLOBAL_ADDED] = g_signal_new ("global-added",
+      G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST,
+      0, NULL, NULL, NULL, G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT,
+      G_TYPE_POINTER);
+  signals[SIGNAL_GLOBAL_REMOVED] = g_signal_new ("global-removed",
+      G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
 }
 
 WpRemote *
@@ -260,3 +336,25 @@ wp_remote_pipewire_new (WpCore *core, GMainContext *context)
 
   return remote;
 }
+
+gpointer
+wp_remote_pipewire_proxy_bind (WpRemotePipewire *self, guint global_id,
+    guint global_type)
+{
+  g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL);
+  g_return_val_if_fail (self->registry_proxy, NULL);
+
+  return pw_registry_proxy_bind (self->registry_proxy, global_id, global_type,
+      0, 0);
+}
+
+gpointer
+wp_remote_pipewire_create_object (WpRemotePipewire *self,
+    const char *factory_name, guint global_type, gconstpointer props)
+{
+  g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL);
+  g_return_val_if_fail (self->core_proxy, NULL);
+
+  return pw_core_proxy_create_object(self->core_proxy, factory_name,
+      global_type, 0, props, 0);
+}
diff --git a/lib/wp/remote-pipewire.h b/lib/wp/remote-pipewire.h
index d7da043df3aefcc7efdd965a9852808f9b378ee2..347ffae0fb99ca101033c2389f2172463d882a07 100644
--- a/lib/wp/remote-pipewire.h
+++ b/lib/wp/remote-pipewire.h
@@ -19,6 +19,11 @@ G_DECLARE_FINAL_TYPE (WpRemotePipewire, wp_remote_pipewire,
 
 WpRemote *wp_remote_pipewire_new (WpCore *core, GMainContext *context);
 
+gpointer wp_remote_pipewire_proxy_bind (WpRemotePipewire *self, guint global_id,
+    guint global_type);
+gpointer wp_remote_pipewire_create_object (WpRemotePipewire *self,
+    const char *factory_name, guint global_type, gconstpointer props);
+
 G_END_DECLS
 
 #endif