]> git.alsa-project.org Git - alsa-utils.git/commitdiff
topology: pre-processor: Add support for CombineArrays
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Wed, 24 May 2023 01:13:35 +0000 (18:13 -0700)
committerJaroslav Kysela <perex@perex.cz>
Tue, 1 Aug 2023 07:40:51 +0000 (09:40 +0200)
Introduce a new keyword, "CombineArrays" to instantiate multiple nodes
of the type specified. For example:

CombineArrays.Object.Base.input_audio_format [
{
in_rate [
8000
16000
48000
]
in_bit_depth [
32
]
in_valid_bit_depth [
24
32
]
}
]

This would be expanded into 6 objects with the rate, bit_depth and
valid_bit_depth combinations of the arrays of values above.

Object.Base.input_audio_format [
{
in_rate 8000
in_bit_depth 32
in_valid_bit_depth 32
}
{
in_rate 16000
in_bit_depth 32
in_valid_bit_depth 32
}
{
in_rate 48000
in_bit_depth 32
in_valid_bit_depth 32
}
{
in_rate 8000
in_bit_depth 32
in_valid_bit_depth 24
}
{
in_rate 16000
in_bit_depth 32
in_valid_bit_depth 24
}
{
in_rate 48000
in_bit_depth 32
in_valid_bit_depth 24
}
]

The CombineArrays definition is an array so that multiple combinations can
be specified in order to deal with only valid combinations. For example,
16-bit bit_depth is only valid with 16-bit valid_bit_depth. So if we
also want to add those combinations with the multiple rates, the
definition would look like:

CombineArrays.Object.Base.input_audio_format [
        {
                in_rate [
                        8000
                        16000
                        48000
                ]
                in_bit_depth [
                        32
                ]
                in_valid_bit_depth [
                        24
                        32
                ]
        }
        {
                in_rate [
                        8000
                        16000
                        48000
                ]
                in_bit_depth [
                        16
                ]
                in_valid_bit_depth [
                        16
                ]
        }
]

Fixes: https://github.com/alsa-project/alsa-utils/pull/216
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
topology/pre-processor.c

index 3f2025235672d0ae1e0e4a915cfa160092e7e7a4..390b5c90a72f823d84b3a81e599084cc2e911aec 100644 (file)
@@ -637,6 +637,287 @@ static int pre_process_includes_all(struct tplg_pre_processor *tplg_pp, snd_conf
 
        return 0;
 }
+
+/* duplicate the existing objects in src into dest and update with new attribute */
+static int pre_process_add_objects(struct tplg_pre_processor *tplg_pp, int *object_count,
+                                  snd_config_t *src, snd_config_t *dest, snd_config_t *attr_cfg)
+{
+       snd_config_iterator_t i, next;
+       int ret;
+
+       snd_config_for_each(i, next, src) {
+               snd_config_t *n, *new, *new_attr;
+               char* new_id = tplg_snprintf("%d", (*object_count)++);
+
+               n = snd_config_iterator_entry(i);
+
+               /* duplicate the existing object */
+               ret = snd_config_copy(&new, n);
+               if (ret < 0) {
+                       free(new_id);
+                       return ret;
+               }
+
+               ret = snd_config_set_id(new, new_id);
+               free(new_id);
+               if (ret < 0) {
+                       snd_config_delete(new);
+                       return ret;
+               }
+
+               ret = snd_config_add(dest, new);
+               if (ret < 0) {
+                       snd_config_delete(new);
+                       return ret;
+               }
+
+               /* and update the new attribute */
+               ret = snd_config_copy(&new_attr, attr_cfg);
+               if (ret < 0)
+                       return ret;
+
+               ret = snd_config_add(new, new_attr);
+               if (ret < 0) {
+                       snd_config_delete(new_attr);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/* Create config based on the number of items in the array */
+static int pre_process_create_items(struct tplg_pre_processor *tplg_pp,
+                                   snd_config_t *cfg, snd_config_t *top,
+                                   int *object_count_offset)
+{
+       snd_config_iterator_t i, next;
+       snd_config_type_t type;
+       const char *class_id;
+       char *class_id_local;
+       int attr_count = 0;
+       int object_count = *object_count_offset;
+       int ret;
+
+       snd_config_get_id(top, &class_id);
+       class_id_local = strdup(class_id);
+
+       snd_config_for_each(i, next, cfg) {
+               snd_config_iterator_t i2, next2;
+               snd_config_t *n, *local_top;
+               const char *attribute;
+               int attr_val_count = 0;
+               object_count = *object_count_offset;
+
+               n = snd_config_iterator_entry(i);
+               type = snd_config_get_type(n);
+               if (type != SND_CONFIG_TYPE_COMPOUND)
+                       continue;
+               if (snd_config_get_id(n, &attribute) < 0)
+                       continue;
+
+               ret = snd_config_make(&local_top, class_id_local, SND_CONFIG_TYPE_COMPOUND);
+
+               snd_config_for_each(i2, next2, n) {
+                       snd_config_t *n2, *new, *new_obj;
+                       snd_config_type_t attr_type;
+                       char *new_id;
+
+                       n2 = snd_config_iterator_entry(i2);
+
+                       attr_type = snd_config_get_type(n2);
+
+                       /* create new config based on type */
+                       if (attr_type == SND_CONFIG_TYPE_INTEGER) {
+                               long val;
+
+                               ret = snd_config_get_integer(n2, &val);
+                               if (ret < 0)
+                                       return ret;
+
+                               ret = snd_config_make(&new, attribute, SND_CONFIG_TYPE_INTEGER);
+                               if (ret < 0)
+                                       return ret;
+
+                               ret = snd_config_set_integer(new, val);
+                       } else {
+                               const char *s;
+
+                               ret = snd_config_get_string(n2, &s);
+                               if (ret < 0)
+                                       return ret;
+                               ret = snd_config_make(&new, attribute, SND_CONFIG_TYPE_STRING);
+                               if (ret < 0)
+                                       return ret;
+
+                               ret = snd_config_set_string(new, s);
+                       }
+
+                       if (ret < 0)
+                               goto err;
+
+                       /* for the first array simply create new conf nodes */
+                       if (!attr_count) {
+                               new_id = tplg_snprintf("%d", object_count++);
+                               ret = snd_config_make(&new_obj, new_id, SND_CONFIG_TYPE_COMPOUND);
+                               free(new_id);
+
+                               ret = snd_config_add(new_obj, new);
+                               if (ret < 0) {
+                                       snd_config_delete(new_obj);
+                                       goto err;
+                               }
+
+                               ret = snd_config_add(local_top, new_obj);
+                               if (ret < 0) {
+                                       snd_config_delete(new_obj);
+                                       goto err;
+                               }
+
+                               continue;
+                       }
+
+                       /*
+                        * for the subsequent arrays, duplicate the existing objects
+                        * and update them with the new ones
+                        */
+                       ret = pre_process_add_objects(tplg_pp, &object_count, top,
+                                                     local_top, new);
+                       if (ret < 0) {
+                               SNDERR("failed to add objects of type %s\n", class_id_local);
+                               goto err;
+                       }
+
+                       attr_val_count++;
+err:
+                       snd_config_delete(new);
+                       if (ret < 0) {
+                               snd_config_delete(local_top);
+                               return ret;
+                       }
+               }
+
+               /* substitute current list of configs with the updated list */
+               ret = snd_config_substitute(top, local_top);
+               if (ret < 0) {
+                       snd_config_delete(local_top);
+                       return ret;
+               }
+               attr_count++;
+       }
+
+       *object_count_offset = object_count;
+       return 0;
+}
+
+static int pre_process_array_item(struct tplg_pre_processor *tplg_pp, snd_config_t *top,
+                                 snd_config_t *array)
+{
+       snd_config_iterator_t i, next;
+       int object_count;
+       int ret;
+
+       snd_config_for_each(i, next, array) {
+               snd_config_iterator_t i3, next3;
+               snd_config_t *n, *new;
+               const char *id;
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               /* Create a new node if it doesn't exist already */
+               if (snd_config_search(top, id, &new) < 0) {
+                       ret = snd_config_make(&new, id, SND_CONFIG_TYPE_COMPOUND);
+                       if (ret < 0)
+                               return ret;
+
+                       /* add the list of objects to the current top */
+                       ret = snd_config_add(top, new);
+                       if (ret < 0) {
+                               snd_config_delete(new);
+                               return ret;
+                       }
+               }
+
+               /* if the conf node is not an array, move on to parse child nodes */
+               if (snd_config_is_array(n) <= 0)
+                       return pre_process_array_item(tplg_pp, new, n);
+
+               object_count = 0;
+               snd_config_for_each(i3, next3, n) {
+                       snd_config_t *n3, *local_top;
+
+                       n3 = snd_config_iterator_entry(i3);
+
+                       ret = snd_config_make(&local_top, id, SND_CONFIG_TYPE_COMPOUND);
+                       if (ret < 0)
+                               return ret;
+
+                       ret = pre_process_create_items(tplg_pp, n3, local_top,
+                                                        &object_count);
+                       if (ret < 0) {
+                               SNDERR("failed to create objects of type %s\n", id);
+                               return ret;
+                       }
+
+                       ret = snd_config_merge(new, local_top, 0);
+                       if (ret < 0) {
+                               snd_config_delete(local_top);
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int pre_process_array(struct tplg_pre_processor *tplg_pp, snd_config_t *top)
+{
+       snd_config_t *arrays;
+       int ret;
+
+       ret = snd_config_search(top, "CombineArrays", &arrays);
+       if (ret < 0)
+               return 0;
+
+       ret = pre_process_array_item(tplg_pp, top, arrays);
+       if (ret < 0)
+               return ret;
+
+       snd_config_delete(arrays);
+       return 0;
+}
+
+static int pre_process_arrays(struct tplg_pre_processor *tplg_pp, snd_config_t *top)
+{
+       snd_config_iterator_t i, next;
+       int ret;
+
+       if (snd_config_get_type(top) != SND_CONFIG_TYPE_COMPOUND)
+               return 0;
+
+       /* process object arrays at this node */
+       ret = pre_process_array(tplg_pp, top);
+       if (ret < 0) {
+               fprintf(stderr, "Failed to process object arrays\n");
+               return ret;
+       }
+
+       /* process object arrays at all child nodes */
+       snd_config_for_each(i, next, top) {
+               snd_config_t *n;
+
+               n = snd_config_iterator_entry(i);
+
+               ret = pre_process_arrays(tplg_pp, n);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
 #endif /* version < 1.2.6 */
 
 int pre_process(struct tplg_pre_processor *tplg_pp, char *config, size_t config_size,
@@ -689,6 +970,13 @@ int pre_process(struct tplg_pre_processor *tplg_pp, char *config, size_t config_
                fprintf(stderr, "Failed to process conditional includes in input config\n");
                goto err;
        }
+
+       /* expand object arrays */
+       err = pre_process_arrays(tplg_pp, tplg_pp->input_cfg);
+       if (err < 0) {
+               fprintf(stderr, "Failed to process object arrays in input config\n");
+               goto err;
+       }
 #endif
 
        err = pre_process_config(tplg_pp, tplg_pp->input_cfg);