From 8fff69353b521ba67427ad111baa55fb27e3a047 Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Fri, 10 Mar 2023 23:21:13 +0100 Subject: [PATCH] gst: deviceprodiver: Sort devices by session priority Applications using the device provider typically list devices in the order they were added. In order to ensure that apps pick nodes like cameras with the highest priority by default, sort devices accordingly. This unfortunately does not not have an effect on nodes added later, e.g. on hotplug. Closes https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/3072 --- src/gst/gstpipewiredeviceprovider.c | 46 +++++++++++++++++++++++++---- src/gst/gstpipewiredeviceprovider.h | 1 + 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/gst/gstpipewiredeviceprovider.c b/src/gst/gstpipewiredeviceprovider.c index 80e93c4f8..fa08e3ec6 100644 --- a/src/gst/gstpipewiredeviceprovider.c +++ b/src/gst/gstpipewiredeviceprovider.c @@ -210,6 +210,7 @@ new_node (GstPipeWireDeviceProvider *self, struct node_data *data) const struct pw_node_info *info = data->info; const gchar *element = NULL; GstPipeWireDevice *gstdev; + int priority = 0; if (info->max_input_ports > 0 && info->max_output_ports == 0) { type = GST_PIPEWIRE_DEVICE_TYPE_SINK; @@ -224,11 +225,16 @@ new_node (GstPipeWireDeviceProvider *self, struct node_data *data) props = gst_structure_new_empty ("pipewire-proplist"); if (info->props) { const struct spa_dict_item *item; + const char *str; + spa_dict_for_each (item, info->props) gst_structure_set (props, item->key, G_TYPE_STRING, item->value, NULL); klass = spa_dict_lookup (info->props, PW_KEY_MEDIA_CLASS); name = spa_dict_lookup (info->props, PW_KEY_NODE_DESCRIPTION); + + if ((str = spa_dict_lookup(info->props, PW_KEY_PRIORITY_SESSION))) + priority = atoi(str); } if (klass == NULL) klass = "unknown/unknown"; @@ -244,26 +250,56 @@ new_node (GstPipeWireDeviceProvider *self, struct node_data *data) gstdev->serial = data->serial; gstdev->type = type; gstdev->element = element; + gstdev->priority = priority; if (props) gst_structure_free (props); return GST_DEVICE (gstdev); } +static int +compare_device_session_priority (const void *a, + const void *b) +{ + const GstPipeWireDevice *dev_a = a; + const GstPipeWireDevice *dev_b = b; + + if (dev_a->priority < dev_b->priority) + return 1; + else if (dev_a->priority > dev_b->priority) + return -1; + else + return 0; +} + static void do_add_nodes(GstPipeWireDeviceProvider *self) { struct node_data *nd; + GList *new_devices = NULL; + GList *l; spa_list_for_each(nd, &self->nodes, link) { if (nd->dev != NULL) continue; pw_log_info("add node %d", nd->id); nd->dev = new_node (self, nd); - if (nd->dev) { - if(self->list_only) - self->devices = g_list_prepend (self->devices, gst_object_ref_sink (nd->dev)); - else - gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), nd->dev); + if (nd->dev) + new_devices = g_list_prepend (new_devices, nd->dev); + } + if (!new_devices) + return; + + new_devices = g_list_sort (new_devices, + compare_device_session_priority); + for (l = new_devices; l != NULL; l = l->next) { + GstDevice *device = l->data; + + if(self->list_only) { + self->devices = g_list_insert_sorted (self->devices, + gst_object_ref_sink (device), + compare_device_session_priority); + } else { + gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), device); } } } diff --git a/src/gst/gstpipewiredeviceprovider.h b/src/gst/gstpipewiredeviceprovider.h index 719bb2844..f4c343ff9 100644 --- a/src/gst/gstpipewiredeviceprovider.h +++ b/src/gst/gstpipewiredeviceprovider.h @@ -39,6 +39,7 @@ struct _GstPipeWireDevice { uint64_t serial; int fd; const gchar *element; + int priority; }; struct _GstPipeWireDeviceClass {