gst: device-provider: don't re-add metadata listener on permission change

PipeWire re-emits the registry global event for an existing object when the
client's permissions change. This can cause pw_metadata_add_listener() to be
called again on the same hook, corrupting the proxy's object_listener_list.

This is easily triggered by WirePlumber 0.5.15, whose reworked client access
logic sets portal permissions in several stages, causing the metadata global to
be announced more than once.

Bind the default metadata and add the listener only once, and tear down the
proxy and listener in global_remove so a genuine remove/re-add still works.
This commit is contained in:
Julian Bouzas 2026-07-08 13:31:20 -04:00 committed by Wim Taymans
parent 9931921c21
commit cf7faec4fe
2 changed files with 16 additions and 0 deletions

View file

@ -729,8 +729,16 @@ static void registry_event_global(void *data, uint32_t id, uint32_t permissions,
if (!spa_streq(name, "default")) if (!spa_streq(name, "default"))
return; return;
/* PipeWire re-emits the global event for the same id when the client's
* permissions change. Only bind and add the listener once, otherwise we
* would re-append the already-linked metadata_listener hook and corrupt
* the proxy's listener list. */
if (self->metadata != NULL)
return;
self->metadata = self->metadata =
pw_registry_bind(self->registry, id, type, PW_VERSION_METADATA, 0); pw_registry_bind(self->registry, id, type, PW_VERSION_METADATA, 0);
self->metadata_id = id;
pw_metadata_add_listener(self->metadata, &self->metadata_listener, pw_metadata_add_listener(self->metadata, &self->metadata_listener,
&metadata_events, self); &metadata_events, self);
} }
@ -744,6 +752,13 @@ no_mem:
static void registry_event_global_remove(void *data, uint32_t id) static void registry_event_global_remove(void *data, uint32_t id)
{ {
GstPipeWireDeviceProvider *self = data;
if (self->metadata != NULL && self->metadata_id == id) {
spa_hook_remove(&self->metadata_listener);
pw_proxy_destroy((struct pw_proxy *)self->metadata);
self->metadata = NULL;
}
} }
static const struct pw_registry_events registry_events = { static const struct pw_registry_events registry_events = {

View file

@ -52,6 +52,7 @@ struct _GstPipeWireDeviceProvider {
struct spa_hook registry_listener; struct spa_hook registry_listener;
struct pw_metadata *metadata; struct pw_metadata *metadata;
uint32_t metadata_id;
struct spa_hook metadata_listener; struct spa_hook metadata_listener;
gchar *default_audio_source_name; gchar *default_audio_source_name;