Blob Blame History Raw
From 18dc92eac270a50fb40607602352efb4d3db8207 Mon Sep 17 00:00:00 2001
From: Wim Taymans <wtaymans@redhat.com>
Date: Tue, 14 Jan 2020 09:37:09 +0100
Subject: [PATCH] PipeWire: update to 0.3 API

(cherry picked from commit a38901e5e7f835efe7b7a06c55790c8c20bc91a2)
---
 configure.ac      |   2 +-
 src/camera.c      |  24 ++++----
 src/pipewire.c    | 141 +++++++++++++---------------------------------
 src/pipewire.h    |  10 ++--
 src/screen-cast.c |  98 ++++++--------------------------
 5 files changed, 72 insertions(+), 203 deletions(-)

diff --git a/configure.ac b/configure.ac
index 89902fa..62d7960 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,7 +97,7 @@ AC_ARG_ENABLE(pipewire,
 	      [AS_HELP_STRING([--enable-pipewire],[Enable PipeWire support. Needed for screen cast portal])],
 	      enable_pipewire=$enableval, enable_pipewire=yes)
 if test x$enable_pipewire = xyes ; then
-	PKG_CHECK_MODULES(PIPEWIRE, [libpipewire-0.2 >= 0.2.6])
+	PKG_CHECK_MODULES(PIPEWIRE, [libpipewire-0.3 >= 0.2.90])
 	AC_DEFINE([HAVE_PIPEWIRE],[1], [Define to enable PipeWire support])
 fi
 AM_CONDITIONAL([HAVE_PIPEWIRE],[test "$enable_pipewire" = "yes"])
diff --git a/src/camera.c b/src/camera.c
index c2b392c..20fe3aa 100644
--- a/src/camera.c
+++ b/src/camera.c
@@ -141,7 +141,7 @@ open_pipewire_camera_remote (const char *app_id,
                              GError **error)
 {
   PipeWireRemote *remote;
-  struct spa_dict_item permission_items[1];
+  struct pw_permission permission_items[2];
   struct pw_properties *pipewire_properties;
 
   pipewire_properties =
@@ -158,12 +158,12 @@ open_pipewire_camera_remote (const char *app_id,
    * Hide all existing and future nodes by default. PipeWire will use the
    * permission store to set up permissions.
    */
-  permission_items[0].key = PW_CORE_PROXY_PERMISSIONS_DEFAULT;
-  permission_items[0].value = "---";
+  permission_items[0] = PW_PERMISSION_INIT (PW_ID_CORE, PW_PERM_RWX);
+  permission_items[1] = PW_PERMISSION_INIT (PW_ID_ANY, 0);
 
-  pw_core_proxy_permissions (pw_remote_get_core_proxy (remote->remote),
-                             &SPA_DICT_INIT (permission_items,
-                                             G_N_ELEMENTS (permission_items)));
+  pw_client_update_permissions (pw_core_get_client(remote->core),
+                                G_N_ELEMENTS (permission_items),
+                                permission_items);
 
   pipewire_remote_roundtrip (remote);
 
@@ -219,7 +219,7 @@ handle_open_pipewire_remote (XdpCamera *object,
     }
 
   out_fd_list = g_unix_fd_list_new ();
-  fd = pw_remote_steal_fd (remote->remote);
+  fd = pw_core_steal_fd (remote->core);
   fd_id = g_unix_fd_list_append (out_fd_list, fd, &error);
   close (fd);
   pipewire_remote_destroy (remote);
@@ -250,29 +250,28 @@ camera_iface_init (XdpCameraIface *iface)
 static void
 global_added_cb (PipeWireRemote *remote,
                  uint32_t id,
-                 uint32_t type,
+                 const char *type,
                  const struct spa_dict *props,
                  gpointer user_data)
 {
   Camera *camera = user_data;
-  struct pw_type *core_type = pw_core_get_type (remote->core);
   const struct spa_dict_item *media_class;
   const struct spa_dict_item *media_role;
 
-  if (type != core_type->node)
+  if (strcmp(type, PW_TYPE_INTERFACE_Node) != 0)
     return;
 
   if (!props)
     return;
 
-  media_class = spa_dict_lookup_item (props, "media.class");
+  media_class = spa_dict_lookup_item (props, PW_KEY_MEDIA_CLASS);
   if (!media_class)
     return;
 
   if (g_strcmp0 (media_class->value, "Video/Source") != 0)
     return;
 
-  media_role = spa_dict_lookup_item (props, "media.role");
+  media_role = spa_dict_lookup_item (props, PW_KEY_MEDIA_ROLE);
   if (!media_role)
     return;
 
@@ -342,6 +341,7 @@ create_pipewire_remote (Camera *camera,
     }
 
   pipewire_properties = pw_properties_new ("pipewire.access.portal.is_portal", "true",
+                                           "portal.monitor", "Camera",
                                            NULL);
   camera->pipewire_remote = pipewire_remote_new_sync (pipewire_properties,
                                                       global_added_cb,
diff --git a/src/pipewire.c b/src/pipewire.c
index 793a378..162cd55 100644
--- a/src/pipewire.c
+++ b/src/pipewire.c
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <glib.h>
 #include <pipewire/pipewire.h>
+#include <spa/utils/result.h>
 
 #include "pipewire.h"
 
@@ -36,27 +37,25 @@ static gboolean is_pipewire_initialized = FALSE;
 static void
 registry_event_global (void *user_data,
                        uint32_t id,
-                       uint32_t parent_id,
                        uint32_t permissions,
-                       uint32_t type,
+                       const char *type,
                        uint32_t version,
                        const struct spa_dict *props)
 {
   PipeWireRemote *remote = user_data;
-  struct pw_type *core_type = pw_core_get_type (remote->core);
   const struct spa_dict_item *factory_object_type;
   PipeWireGlobal *global;
 
   global = g_new0 (PipeWireGlobal, 1);
   *global = (PipeWireGlobal) {
-    .parent_id = parent_id,
+    .parent_id = id,
   };
 
   g_hash_table_insert (remote->globals, GINT_TO_POINTER (id), global);
   if (remote->global_added_cb)
     remote->global_added_cb (remote, id, type, props, remote->user_data);
 
-  if (type != core_type->factory)
+  if (strcmp(type, PW_TYPE_INTERFACE_Factory) != 0)
     return;
 
   factory_object_type = spa_dict_lookup_item (props, "factory.type.name");
@@ -81,8 +80,8 @@ registry_event_global_remove (void *user_data,
   g_hash_table_remove (remote->globals, GINT_TO_POINTER (id));
 }
 
-static const struct pw_registry_proxy_events registry_events = {
-  PW_VERSION_REGISTRY_PROXY_EVENTS,
+static const struct pw_registry_events registry_events = {
+  PW_VERSION_REGISTRY_EVENTS,
   .global = registry_event_global,
   .global_remove = registry_event_global_remove,
 };
@@ -90,7 +89,7 @@ static const struct pw_registry_proxy_events registry_events = {
 void
 pipewire_remote_roundtrip (PipeWireRemote *remote)
 {
-  pw_core_proxy_sync (remote->core_proxy, ++remote->sync_seq);
+  remote->sync_seq = pw_core_sync (remote->core, PW_ID_CORE, remote->sync_seq);
   pw_main_loop_run (remote->loop);
 }
 
@@ -98,16 +97,13 @@ static gboolean
 discover_node_factory_sync (PipeWireRemote *remote,
                             GError **error)
 {
-  struct pw_type *core_type = pw_core_get_type (remote->core);
-  struct pw_registry_proxy *registry_proxy;
+  struct pw_registry *registry;
 
-  registry_proxy = pw_core_proxy_get_registry (remote->core_proxy,
-                                               core_type->registry,
-                                               PW_VERSION_REGISTRY, 0);
-  pw_registry_proxy_add_listener (registry_proxy,
-                                  &remote->registry_listener,
-                                  &registry_events,
-                                  remote);
+  registry = pw_core_get_registry (remote->core, PW_VERSION_REGISTRY, 0);
+  pw_registry_add_listener (registry,
+                            &remote->registry_listener,
+                            &registry_events,
+                            remote);
 
   pipewire_remote_roundtrip (remote);
 
@@ -122,59 +118,35 @@ discover_node_factory_sync (PipeWireRemote *remote,
 }
 
 static void
-on_state_changed (void *user_data,
-                  enum pw_remote_state old,
-                  enum pw_remote_state state,
-                  const char *error)
+core_event_error (void       *user_data,
+                  uint32_t    id,
+		  int         seq,
+		  int         res,
+		  const char *message)
 {
   PipeWireRemote *remote = user_data;
 
-  switch (state)
+  if (id == PW_ID_CORE)
     {
-    case PW_REMOTE_STATE_ERROR:
-      if (!remote->error)
-        {
-          g_set_error (&remote->error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                       "%s", error);
-        }
+      g_set_error (&remote->error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                 "%s", message);
       pw_main_loop_quit (remote->loop);
-      break;
-    case PW_REMOTE_STATE_UNCONNECTED:
-      if (!remote->error)
-        {
-          g_set_error (&remote->error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                       "Disconnected");
-        }
-      pw_main_loop_quit (remote->loop);
-      break;
-    case PW_REMOTE_STATE_CONNECTING:
-      break;
-    case PW_REMOTE_STATE_CONNECTED:
-      pw_main_loop_quit (remote->loop);
-      break;
-    default:
-      g_warning ("Unknown PipeWire state");
-      break;
     }
 }
 
-static const struct pw_remote_events remote_events = {
-  PW_VERSION_REMOTE_EVENTS,
-  .state_changed = on_state_changed,
-};
-
 static void
 core_event_done (void *user_data,
-                 uint32_t seq)
+                 uint32_t id, int seq)
 {
   PipeWireRemote *remote = user_data;
 
-  if (remote->sync_seq == seq)
+  if (id == PW_ID_CORE && remote->sync_seq == seq)
     pw_main_loop_quit (remote->loop);
 }
 
-static const struct pw_core_proxy_events core_events = {
-  PW_VERSION_CORE_PROXY_EVENTS,
+static const struct pw_core_events core_events = {
+  PW_VERSION_CORE_EVENTS,
+  .error = core_event_error,
   .done = core_event_done,
 };
 
@@ -237,8 +209,8 @@ void
 pipewire_remote_destroy (PipeWireRemote *remote)
 {
   g_clear_pointer (&remote->globals, g_hash_table_destroy);
-  g_clear_pointer (&remote->remote, pw_remote_destroy);
-  g_clear_pointer (&remote->core, pw_core_destroy);
+  g_clear_pointer (&remote->core, pw_core_disconnect);
+  g_clear_pointer (&remote->context, pw_context_destroy);
   g_clear_pointer (&remote->loop, pw_main_loop_destroy);
   g_clear_error (&remote->error);
 
@@ -307,68 +279,31 @@ pipewire_remote_new_sync (struct pw_properties *pipewire_properties,
       return NULL;
     }
 
-  remote->core = pw_core_new (pw_main_loop_get_loop (remote->loop), NULL);
-  if (!remote->core)
+  remote->context = pw_context_new (pw_main_loop_get_loop (remote->loop), NULL, 0);
+  if (!remote->context)
     {
       pipewire_remote_destroy (remote);
       pw_properties_free (pipewire_properties);
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Couldn't create PipeWire core");
+                   "Couldn't create PipeWire context");
       return NULL;
     }
 
-  remote->remote = pw_remote_new (remote->core, pipewire_properties, 0);
-  if (!remote->remote)
+  remote->core = pw_context_connect (remote->context, pipewire_properties, 0);
+  if (!remote->core)
     {
       pipewire_remote_destroy (remote);
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Couldn't create PipeWire remote");
+                   "Couldn't connect to PipeWire");
       return NULL;
     }
 
   remote->globals = g_hash_table_new_full (NULL, NULL, NULL, g_free);
 
-  pw_remote_add_listener (remote->remote,
-                          &remote->remote_listener,
-                          &remote_events,
-                          remote);
-
-  if (pw_remote_connect (remote->remote) != 0)
-    {
-      pipewire_remote_destroy (remote);
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Couldn't connect PipeWire remote");
-      return NULL;
-    }
-
-  pw_main_loop_run (remote->loop);
-
-  switch (pw_remote_get_state (remote->remote, NULL))
-    {
-    case PW_REMOTE_STATE_ERROR:
-    case PW_REMOTE_STATE_UNCONNECTED:
-      *error = g_steal_pointer (&remote->error);
-      pipewire_remote_destroy (remote);
-      return NULL;
-    case PW_REMOTE_STATE_CONNECTING:
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "PipeWire loop stopped unexpectedly");
-      pipewire_remote_destroy (remote);
-      return NULL;
-    case PW_REMOTE_STATE_CONNECTED:
-      break;
-    default:
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Unexpected PipeWire state");
-      pipewire_remote_destroy (remote);
-      return NULL;
-    }
-
-  remote->core_proxy = pw_remote_get_core_proxy (remote->remote);
-  pw_core_proxy_add_listener (remote->core_proxy,
-                              &remote->core_listener,
-                              &core_events,
-                              remote);
+  pw_core_add_listener (remote->core,
+                        &remote->core_listener,
+                        &core_events,
+                        remote);
 
   if (!discover_node_factory_sync (remote, error))
     {
diff --git a/src/pipewire.h b/src/pipewire.h
index 0f1bf54..bf48d5e 100644
--- a/src/pipewire.h
+++ b/src/pipewire.h
@@ -32,7 +32,7 @@ typedef struct _PipeWireGlobal
 
 typedef void (* PipeWireGlobalAddedCallback) (PipeWireRemote *remote,
                                               uint32_t id,
-                                              uint32_t type,
+                                              const char *type,
                                               const struct spa_dict *props,
                                               gpointer user_data);
 
@@ -43,13 +43,11 @@ typedef void (* PipeWireGlobalRemovedCallback) (PipeWireRemote *remote,
 struct _PipeWireRemote
 {
   struct pw_main_loop *loop;
+  struct pw_context *context;
   struct pw_core *core;
-  struct pw_remote *remote;
-  struct spa_hook remote_listener;
-
-  struct pw_core_proxy *core_proxy;
   struct spa_hook core_listener;
-  uint32_t sync_seq;
+
+  int sync_seq;
 
   struct spa_hook registry_listener;
 
diff --git a/src/screen-cast.c b/src/screen-cast.c
index 7881ddc..1677050 100644
--- a/src/screen-cast.c
+++ b/src/screen-cast.c
@@ -31,10 +31,10 @@
 #include "xdp-impl-dbus.h"
 #include "xdp-utils.h"
 
-#define PERMISSION_ITEM(item_key, item_value) \
-  ((struct spa_dict_item) { \
-    .key = item_key, \
-    .value = item_value \
+#define PERMISSION_ITEM(item_id, item_permissions) \
+  ((struct pw_permission) { \
+    .id = item_id, \
+    .permissions = item_permissions \
   })
 
 typedef struct _ScreenCast ScreenCast;
@@ -517,42 +517,9 @@ screen_cast_stream_get_pipewire_node_id (ScreenCastStream *stream)
   return stream->id;
 }
 
-static void
-append_parent_permissions (PipeWireRemote *remote,
-                           GArray *permission_items,
-                           GList **string_stash,
-                           PipeWireGlobal *global,
-                           const char *permission)
-{
-  PipeWireGlobal *parent;
-  char *parent_permission_value;
-
-  if (global->parent_id == 0)
-    return;
-
-  parent = g_hash_table_lookup (remote->globals, GINT_TO_POINTER (global->parent_id));
-
-  if (parent->permission_set)
-    return;
-  parent->permission_set = TRUE;
-
-  append_parent_permissions (remote, permission_items, string_stash,
-                             parent, permission);
-
-  parent_permission_value = g_strdup_printf ("%u:%s",
-                                             global->parent_id,
-                                             permission);
-  *string_stash = g_list_prepend (*string_stash, parent_permission_value);
-
-  g_array_append_val (permission_items,
-                      PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_GLOBAL,
-                                       parent_permission_value));
-}
-
 static void
 append_stream_permissions (PipeWireRemote *remote,
                            GArray *permission_items,
-                           GList **string_stash,
                            GList *streams)
 {
   GList *l;
@@ -561,21 +528,10 @@ append_stream_permissions (PipeWireRemote *remote,
     {
       ScreenCastStream *stream = l->data;
       uint32_t stream_id;
-      PipeWireGlobal *stream_global;
-      char *stream_permission_value;
 
       stream_id = screen_cast_stream_get_pipewire_node_id (stream);
-      stream_global = g_hash_table_lookup (remote->globals,
-                                           GINT_TO_POINTER (stream_id));
-
-      append_parent_permissions (remote, permission_items, string_stash,
-                                 stream_global, "r--");
-
-      stream_permission_value = g_strdup_printf ("%u:rwx", stream_id);
-      *string_stash = g_list_prepend (*string_stash, stream_permission_value);
       g_array_append_val (permission_items,
-                          PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_GLOBAL,
-                                           stream_permission_value));
+                          PERMISSION_ITEM (stream_id, PW_PERM_RWX));
     }
 }
 
@@ -587,9 +543,6 @@ open_pipewire_screen_cast_remote (const char *app_id,
   struct pw_properties *pipewire_properties;
   PipeWireRemote *remote;
   g_autoptr(GArray) permission_items = NULL;
-  char *node_factory_permission_string;
-  GList *string_stash = NULL;
-  struct spa_dict *permission_dict;
   PipeWireGlobal *node_global;
 
   pipewire_properties = pw_properties_new ("pipewire.access.portal.app_id", app_id,
@@ -603,48 +556,31 @@ open_pipewire_screen_cast_remote (const char *app_id,
 
   permission_items = g_array_new (FALSE, TRUE, sizeof (struct spa_dict_item));
 
-  /*
-   * Hide all existing and future nodes (except the ones we explicitly list below.
-   */
-  g_array_append_val (permission_items,
-                      PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_EXISTING,
-                                       "---"));
-  g_array_append_val (permission_items,
-                      PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_DEFAULT,
-                                       "---"));
-
   /*
    * PipeWire:Interface:Core
    * Needs rwx to be able create the sink node using the create-object method
    */
   g_array_append_val (permission_items,
-                      PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_GLOBAL,
-                                       "0:rwx"));
+                      PERMISSION_ITEM (PW_ID_CORE, PW_PERM_RWX));
 
   /*
    * PipeWire:Interface:NodeFactory
    * Needs r-- so it can be passed to create-object when creating the sink node.
    */
-  node_factory_permission_string = g_strdup_printf ("%d:r--",
-                                                    remote->node_factory_id);
-  string_stash = g_list_prepend (string_stash, node_factory_permission_string);
   g_array_append_val (permission_items,
-                      PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_GLOBAL,
-                                       node_factory_permission_string));
-  node_global = g_hash_table_lookup (remote->globals,
-                                     GINT_TO_POINTER (remote->node_factory_id));
-  append_parent_permissions (remote, permission_items, &string_stash,
-                             node_global, "r--");
+                      PERMISSION_ITEM (remote->node_factory_id, PW_PERM_R));
 
-  append_stream_permissions (remote, permission_items, &string_stash, streams);
+  append_stream_permissions (remote, permission_items, streams);
 
-  permission_dict =
-    &SPA_DICT_INIT ((struct spa_dict_item *) permission_items->data,
-                    permission_items->len);
-  pw_core_proxy_permissions (pw_remote_get_core_proxy (remote->remote),
-                             permission_dict);
+  /*
+   * Hide all existing and future nodes (except the ones we explicitly list above).
+   */
+  g_array_append_val (permission_items,
+                      PERMISSION_ITEM (PW_ID_ANY, 0));
 
-  g_list_free_full (string_stash, g_free);
+  pw_client_update_permissions (pw_core_get_client(remote->core),
+                                permission_items->len,
+                                (const struct pw_permission *)permission_items->data);
 
   pipewire_remote_roundtrip (remote);
 
@@ -943,7 +879,7 @@ handle_open_pipewire_remote (XdpScreenCast *object,
     }
 
   out_fd_list = g_unix_fd_list_new ();
-  fd = pw_remote_steal_fd (remote->remote);
+  fd = pw_core_steal_fd (remote->core);
   fd_id = g_unix_fd_list_append (out_fd_list, fd, &error);
   close (fd);
   pipewire_remote_destroy (remote);
-- 
2.26.2