From fbc051465ccc92985d5fee0bea02680d3f42b95e Mon Sep 17 00:00:00 2001 From: Kalev Lember Date: Tue, 10 Mar 2020 07:37:38 +0100 Subject: [PATCH] Backport PipeWire 0.3 support --- 0001-PipeWire-update-to-0.3-API.patch | 554 ++++++++++++++++++++++++++ xdg-desktop-portal.spec | 20 +- 2 files changed, 570 insertions(+), 4 deletions(-) create mode 100644 0001-PipeWire-update-to-0.3-API.patch diff --git a/0001-PipeWire-update-to-0.3-API.patch b/0001-PipeWire-update-to-0.3-API.patch new file mode 100644 index 0000000..b12faee --- /dev/null +++ b/0001-PipeWire-update-to-0.3-API.patch @@ -0,0 +1,554 @@ +From a38901e5e7f835efe7b7a06c55790c8c20bc91a2 Mon Sep 17 00:00:00 2001 +From: Wim Taymans +Date: Tue, 14 Jan 2020 09:37:09 +0100 +Subject: [PATCH] PipeWire: update to 0.3 API + +--- + 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 + #include + #include ++#include + + #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, +- ®istry_events, +- remote); ++ registry = pw_core_get_registry (remote->core, PW_VERSION_REGISTRY, 0); ++ pw_registry_add_listener (registry, ++ &remote->registry_listener, ++ ®istry_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.24.1 + diff --git a/xdg-desktop-portal.spec b/xdg-desktop-portal.spec index 8dc8ad0..5ff17e8 100644 --- a/xdg-desktop-portal.spec +++ b/xdg-desktop-portal.spec @@ -1,16 +1,18 @@ -%global pipewire_version 0.2.6 +%global pipewire_version 0.2.90 %global geoclue_version 2.5.2 %global glib_version 2.63.3 %global low_memory_monitor_version 2.0 Name: xdg-desktop-portal Version: 1.6.0 -Release: 3%{?dist} +Release: 4%{?dist} Summary: Portal frontend service to flatpak License: LGPLv2+ URL: https://github.com/flatpak/xdg-desktop-portal/ Source0: https://github.com/flatpak/xdg-desktop-portal/releases/download/%{version}/%{name}-%{version}.tar.xz +# Backported from upstream +Patch0: 0001-PipeWire-update-to-0.3-API.patch BuildRequires: gcc BuildRequires: pkgconfig(flatpak) @@ -19,10 +21,13 @@ BuildRequires: pkgconfig(fuse) BuildRequires: pkgconfig(gio-unix-2.0) >= %{glib_version} BuildRequires: pkgconfig(json-glib-1.0) BuildRequires: pkgconfig(libgeoclue-2.0) >= %{geoclue_version} -BuildRequires: pkgconfig(libpipewire-0.2) >= %{pipewire_version} +BuildRequires: pkgconfig(libpipewire-0.3) >= %{pipewire_version} BuildRequires: /usr/bin/xmlto %{?systemd_requires} BuildRequires: systemd +# For patch0 +BuildRequires: autoconf automake libtool gettext-devel + Requires: dbus # Required version for icon validator. Recommends: flatpak >= 1.2.0 @@ -50,7 +55,11 @@ The pkg-config file for %{name}. %prep -%setup -q +%autosetup -p1 + +# For patch0 +autoreconf -fi + %build %configure --enable-docbook-docs --disable-libportal @@ -100,6 +109,9 @@ install -dm 755 %{buildroot}/%{_datadir}/%{name}/portals %changelog +* Tue Mar 10 2020 Kalev Lember - 1.6.0-4 +- Backport PipeWire 0.3 support + * Fri Jan 31 2020 Fedora Release Engineering - 1.6.0-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild