diff --git a/modules/module-pipewire/simple-endpoint.c b/modules/module-pipewire/simple-endpoint.c index 06f5833a..fedf06b6 100644 --- a/modules/module-pipewire/simple-endpoint.c +++ b/modules/module-pipewire/simple-endpoint.c @@ -27,7 +27,9 @@ struct _WpPipewireSimpleEndpoint /* The global-id this endpoint refers to */ guint global_id; + /* properties */ gchar *role; + guint64 creation_time; /* The task to signal the endpoint is initialized */ GTask *init_task; @@ -56,6 +58,7 @@ enum { PROP_0, PROP_GLOBAL_ID, PROP_ROLE, + PROP_CREATION_TIME, }; enum { @@ -359,6 +362,7 @@ static void simple_endpoint_init (WpPipewireSimpleEndpoint * self) { self->init_abort = FALSE; + self->creation_time = (guint64) g_get_monotonic_time (); } static void @@ -416,6 +420,9 @@ simple_endpoint_get_property (GObject * object, guint property_id, case PROP_ROLE: g_value_set_string (value, self->role); break; + case PROP_CREATION_TIME: + g_value_set_uint64 (value, self->creation_time); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -541,6 +548,11 @@ simple_endpoint_class_init (WpPipewireSimpleEndpointClass * klass) g_object_class_install_property (object_class, PROP_ROLE, g_param_spec_string ("role", "role", "The role of the wrapped node", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_CREATION_TIME, + g_param_spec_uint64 ("creation-time", "creation-time", + "The time that this endpoint was created, in monotonic time", + 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } void diff --git a/modules/module-simple-policy.c b/modules/module-simple-policy.c index 816c2fe4..56f90d84 100644 --- a/modules/module-simple-policy.c +++ b/modules/module-simple-policy.c @@ -347,28 +347,44 @@ handle_client (WpPolicy *policy, WpEndpoint *ep) } static gint -compare_client_roles (gconstpointer a, gconstpointer b, gpointer user_data) +compare_client_priority (gconstpointer a, gconstpointer b, gpointer user_data) { GVariant *v = user_data; WpEndpoint *ae = *(const gpointer *) a; WpEndpoint *be = *(const gpointer *) b; - g_autofree gchar *a_role = NULL; - g_autofree gchar *b_role = NULL; - gint a_priority = 0, b_priority = 0; + gint ret = 0; - /* if no role priorities specified, everything is equal */ - if (!v) return 0; + /* if no role priorities are specified, we treat all roles as equal */ + if (v) { + g_autofree gchar *a_role = NULL; + g_autofree gchar *b_role = NULL; + gint a_priority = 0, b_priority = 0; - g_object_get (ae, "role", &a_role, NULL); - g_object_get (be, "role", &b_role, NULL); + g_object_get (ae, "role", &a_role, NULL); + g_object_get (be, "role", &b_role, NULL); - if (a_role) - g_variant_lookup (v, a_role, "i", &a_priority); - if (b_role) - g_variant_lookup (v, b_role, "i", &b_priority); + if (a_role) + g_variant_lookup (v, a_role, "i", &a_priority); + if (b_role) + g_variant_lookup (v, b_role, "i", &b_priority); - /* return b - a in order to sort descending */ - return b_priority - a_priority; + /* return b - a in order to sort descending */ + ret = b_priority - a_priority; + } + + /* when role priority is equal, the newest client wins */ + if (ret == 0) { + guint64 a_time = 0, b_time = 0; + + g_object_get (ae, "creation-time", &a_time, NULL); + g_object_get (be, "creation-time", &b_time, NULL); + + /* since a_time and b_time are expressed in system monotonic time, + * there is absolutely no chance that they will be equal */ + ret = (b_time > a_time) ? 1 : -1; + } + + return ret; } static gboolean @@ -393,7 +409,7 @@ simple_policy_rescan_in_idle (WpSimplePolicy *self) endpoints = wp_endpoint_find (core, "Stream/Output/Audio"); if (endpoints && endpoints->len > 0) { /* sort based on role priorities */ - g_ptr_array_sort_with_data (endpoints, compare_client_roles, + g_ptr_array_sort_with_data (endpoints, compare_client_priority, self->role_priorities); /* link the highest priority client */