]> git.alsa-project.org Git - alsa-lib.git/commitdiff
ucm: add support for device names with colon (':')
authorJaroslav Kysela <perex@perex.cz>
Tue, 18 Nov 2025 12:13:20 +0000 (13:13 +0100)
committerJaroslav Kysela <perex@perex.cz>
Tue, 18 Nov 2025 12:37:09 +0000 (13:37 +0100)
The colon identifier means to automatically assign
a device index for this device.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/ucm/parser.c

index cb0f51a29abf2060cf9876057820a4fdd942bbef..64ff5fe75516313465ff95c9d3703c782e6eb29f 100644 (file)
@@ -1875,18 +1875,36 @@ static int verb_dev_list_check(struct use_case_verb *verb)
        return 0;
 }
 
+/*
+ * Check if a device name is already in use
+ */
+static int is_device_name_used(struct use_case_verb *verb, const char *name, struct use_case_device *current)
+{
+       struct list_head *pos;
+       struct use_case_device *device;
+
+       list_for_each(pos, &verb->device_list) {
+               device = list_entry(pos, struct use_case_device, list);
+               if (device != current && strcmp(device->name, name) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Normalize device names according to use-case.h specification.
  * Device names like "HDMI 1" or "Line 1" should be normalized to "HDMI1" and "Line1".
+ * When device name contains ':', add index and remove everything after ':' (including).
+ * If final name is already used, retry with higher index.
  * Also updates dev_list members in modifiers and devices to reference the normalized names.
  */
-static int verb_normalize_device_names(struct use_case_verb *verb)
+static int verb_normalize_device_names(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
 {
        struct list_head *pos, *pos2, *pos3;
        struct use_case_device *device, *device2;
        struct use_case_modifier *modifier;
        struct dev_list_node *dlist;
-       char *orig_name, *norm_name;
+       char *orig_name, *norm_name, *colon;
        char temp[80];
        int err, index;
 
@@ -1903,19 +1921,41 @@ static int verb_normalize_device_names(struct use_case_verb *verb)
                        goto __error;
                }
 
-               err = parse_device_index(&norm_name, &index);
-               if (err < 0) {
-                       snd_error(UCM, "cannot parse device name '%s'", device->name);
-                       goto __error;
-               }
+               if (uc_mgr->conf_format < 8)
+                       goto __no_colon;
+
+               colon = strchr(norm_name, ':');
+               if (colon) {
+                       *colon = '\0';
+                       index = 1;
+                       do {
+                               snprintf(temp, sizeof(temp), "%s%d", norm_name, index);
+                               if (!is_device_name_used(verb, temp, device))
+                                       break;
+                               index++;
+                       } while (index < 100); /* Safety limit */
+                       if (index >= 100) {
+                               snd_error(UCM, "too many device name conflicts for '%s'", norm_name);
+                               err = -EINVAL;
+                               goto __error;
+                       }
 
-               if (index <= 0) {
-                       free(orig_name);
-                       free(norm_name);
-                       continue;
+               } else {
+__no_colon:
+                       err = parse_device_index(&norm_name, &index);
+                       if (err < 0) {
+                               snd_error(UCM, "cannot parse device name '%s'", device->name);
+                               goto __error;
+                       }
+
+                       if (index <= 0) {
+                               free(orig_name);
+                               free(norm_name);
+                               continue;
+                       }
+                       snprintf(temp, sizeof(temp), "%s%d", norm_name, index);
                }
 
-               snprintf(temp, sizeof(temp), "%s%d", norm_name, index);
                free(device->name);
                device->name = strdup(temp);
                if (device->name == NULL) {
@@ -1965,7 +2005,7 @@ __error:
        return err;
 }
 
-static int verb_device_management(struct use_case_verb *verb)
+static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
 {
        struct list_head *pos;
        struct ucm_dev_name *dev;
@@ -1996,7 +2036,7 @@ static int verb_device_management(struct use_case_verb *verb)
        uc_mgr_free_dev_name_list(&verb->remove_list);
 
        /* normalize device names to remove spaces per use-case.h specification */
-       err = verb_normalize_device_names(verb);
+       err = verb_normalize_device_names(uc_mgr, verb);
        if (err < 0)
                return err;
 
@@ -2230,7 +2270,7 @@ static int parse_verb_config(snd_use_case_mgr_t *uc_mgr,
        }
 
        /* do device rename and delete */
-       err = verb_device_management(verb);
+       err = verb_device_management(uc_mgr, verb);
        if (err < 0) {
                snd_error(UCM, "device management error in verb '%s'", verb->name);
                return err;