From 7a1b48b741aa796c2e4168817045ba86f4d6711c Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Mon, 11 Jul 2022 17:17:45 +0300 Subject: [PATCH] module-default-nodes: prioritize previous configured defaults The node priorities are difficult to configure for users, and are not necessarily meaningful for them. When there is no configured default node, or the configured default node does not exist, prioritize previously configured default nodes over the automatic node priorities. Keep track of a stack of previous configured nodes, and update the stack when the configured node changes. --- modules/module-default-nodes.c | 79 ++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/modules/module-default-nodes.c b/modules/module-default-nodes.c index 87450ee9..822b75cc 100644 --- a/modules/module-default-nodes.c +++ b/modules/module-default-nodes.c @@ -19,6 +19,7 @@ #define DEFAULT_AUTO_ECHO_CANCEL TRUE #define DEFAULT_ECHO_CANCEL_SINK_NAME "echo-cancel-sink" #define DEFAULT_ECHO_CANCEL_SOURCE_NAME "echo-cancel-source" +#define N_PREV_CONFIGS 16 enum { PROP_0, @@ -34,6 +35,7 @@ struct _WpDefaultNode { gchar *value; gchar *config_value; + gchar *prev_config_value[N_PREV_CONFIGS]; }; struct _WpDefaultNodes @@ -62,13 +64,49 @@ wp_default_nodes_init (WpDefaultNodes * self) { } +static void +update_prev_config_values (WpDefaultNode *def) +{ + gint pos = N_PREV_CONFIGS - 1; + + if (!def->config_value) + return; + + /* Find if the current configured value is already in the stack */ + for (gint i = 0; i < N_PREV_CONFIGS; ++i) { + if (!g_strcmp0(def->config_value, def->prev_config_value[i])) { + pos = i; + break; + } + } + + if (pos == 0) + return; + + /* Insert on top position */ + g_clear_pointer (&def->prev_config_value[pos], g_free); + + for (gint i = pos; i > 0; --i) + def->prev_config_value[i] = def->prev_config_value[i-1]; + + def->prev_config_value[0] = g_strdup(def->config_value); +} + static void load_state (WpDefaultNodes * self) { g_autoptr (WpProperties) props = wp_state_load (self->state); for (gint i = 0; i < N_DEFAULT_NODES; i++) { const gchar *value = wp_properties_get (props, DEFAULT_CONFIG_KEY[i]); + self->defaults[i].config_value = g_strdup (value); + + for (gint j = 0; j < N_PREV_CONFIGS; ++j) { + g_autofree gchar *key = g_strdup_printf("%s.%d", DEFAULT_CONFIG_KEY[i], j); + + value = wp_properties_get (props, key); + self->defaults[i].prev_config_value[j] = g_strdup(value); + } } } @@ -82,6 +120,12 @@ timeout_save_state_callback (WpDefaultNodes *self) if (self->defaults[i].config_value) wp_properties_set (props, DEFAULT_CONFIG_KEY[i], self->defaults[i].config_value); + + for (gint j = 0; j < N_PREV_CONFIGS; ++j) { + g_autofree gchar *key = g_strdup_printf("%s.%d", DEFAULT_CONFIG_KEY[i], j); + + wp_properties_set (props, key, self->defaults[i].prev_config_value[j]); + } } if (!wp_state_save (self->state, props, &error)) @@ -209,7 +253,7 @@ is_echo_cancel_node (WpDefaultNodes * self, WpNode *node, WpDirection direction) static WpNode * find_best_media_class_node (WpDefaultNodes * self, const gchar *media_class, - const gchar *node_name, WpDirection direction, gint *priority) + const WpDefaultNode *def, WpDirection direction, gint *priority) { g_autoptr (WpIterator) it = NULL; g_auto (GValue) val = G_VALUE_INIT; @@ -243,8 +287,20 @@ find_best_media_class_node (WpDefaultNodes * self, const gchar *media_class, if (self->auto_echo_cancel && is_echo_cancel_node (self, node, direction)) prio += 10000; - if (name && node_name && g_strcmp0 (name, node_name) == 0) - prio += 20000; + if (name && def->config_value && g_strcmp0 (name, def->config_value) == 0) { + prio += 20000 * (N_PREV_CONFIGS + 1); + } else if (name) { + for (gint i = 0; i < N_PREV_CONFIGS; ++i) { + if (!def->prev_config_value[i]) + continue; + + /* Match by name */ + if (g_strcmp0 (name, def->prev_config_value[i]) == 0) { + prio += (N_PREV_CONFIGS - i) * 20000; + break; + } + } + } if (prio > highest_prio || res == NULL) { highest_prio = prio; @@ -260,14 +316,14 @@ find_best_media_class_node (WpDefaultNodes * self, const gchar *media_class, static WpNode * find_best_media_classes_node (WpDefaultNodes * self, - const gchar **media_classes, const gchar *node_name, WpDirection direction) + const gchar **media_classes, const WpDefaultNode *def, WpDirection direction) { gint highest_prio = -1; WpNode *res = NULL; for (guint i = 0; media_classes[i]; i++) { gint prio = -1; WpNode *node = find_best_media_class_node (self, media_classes[i], - node_name, direction, &prio); + def, direction, &prio); if (node && (!res || prio > highest_prio)) { highest_prio = prio; res = node; @@ -279,7 +335,7 @@ find_best_media_classes_node (WpDefaultNodes * self, static WpNode * find_best_node (WpDefaultNodes * self, gint node_t) { - const gchar *name = self->defaults[node_t].config_value; + const WpDefaultNode *def = &self->defaults[node_t]; switch (node_t) { case AUDIO_SINK: { @@ -287,7 +343,7 @@ find_best_node (WpDefaultNodes * self, gint node_t) "Audio/Sink", "Audio/Duplex", NULL}; - return find_best_media_classes_node (self, media_classes, name, + return find_best_media_classes_node (self, media_classes, def, WP_DIRECTION_INPUT); } case AUDIO_SOURCE: { @@ -297,7 +353,7 @@ find_best_node (WpDefaultNodes * self, gint node_t) "Audio/Duplex", "Audio/Sink", NULL}; - return find_best_media_classes_node (self, media_classes, name, + return find_best_media_classes_node (self, media_classes, def, WP_DIRECTION_OUTPUT); } case VIDEO_SOURCE: { @@ -305,7 +361,7 @@ find_best_node (WpDefaultNodes * self, gint node_t) "Video/Source", "Video/Source/Virtual", NULL}; - return find_best_media_classes_node (self, media_classes, name, + return find_best_media_classes_node (self, media_classes, def, WP_DIRECTION_OUTPUT); } default: @@ -408,6 +464,8 @@ on_metadata_changed (WpMetadata *m, guint32 subject, self->defaults[node_t].config_value = g_strdup (name); } + update_prev_config_values (&self->defaults[node_t]); + wp_debug_object (m, "changed '%s' -> '%s'", key, self->defaults[node_t].config_value); @@ -507,6 +565,9 @@ wp_default_nodes_disable (WpPlugin * plugin) for (guint i = 0; i < N_DEFAULT_NODES; i++) { g_clear_pointer (&self->defaults[i].value, g_free); g_clear_pointer (&self->defaults[i].config_value, g_free); + + for (guint j = 0; j < N_PREV_CONFIGS; j++) + g_clear_pointer (&self->defaults[i].prev_config_value[j], g_free); } g_clear_object (&self->metadata_om);