]> git.alsa-project.org Git - alsa-utils.git/commitdiff
topology: pre-processor: Move the call to expand variables
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Sat, 11 Dec 2021 18:45:43 +0000 (10:45 -0800)
committerJaroslav Kysela <perex@perex.cz>
Sun, 19 Dec 2021 19:32:38 +0000 (20:32 +0100)
Remove the call to snd_config_expand_custom() to expand the top-level
input config. And replace it with calls to snd_config_evaluate_string()
for each non-compound config while processing individual objects. This
will allow retreving variable definitions from object attribute values
and global definitions.

Add a new field "current_obj_cfg" to hold the current object config
being pre-processed.

This will facilitate adding simple math expressions for computing
attribute values for objects based on other attributes. For ex: we can
set the expression for buffer size as follows:

buffer_size "$[($in_channels * 48) * 4]"

The buffer_size attribute value will be computed with the attribute
value "in_channels" based on the expression above. So if $in_channels =
2, buffer_size will be evaluated to 384.

Additionally this change also permits computing attribute values based
on previously computed values. For example:

buffer_size "$[($in_channels * 48) * 4]"
dma_buffer_size "$[$buffer_size * 2]"

dma_buffer_size will be computed as 768. Note that the order of
definitions for buffer_size and dma_buffer_size matters because the
evaluation for dma_buffer_size depends on the evaluation of buffer_size.
In order to conform to this, the tplg_object_copy_and_add_param() is
modified to add attribute configs from class config to an object using
snd_config_before() instead of snd_config_add().

With this change, we no longer need to set the auto_attr_updater for
buffer type widget objects. So remove it.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
alsaucm/go.sh
aplay/aplay.c
topology/pre-process-dapm.c
topology/pre-process-object.c
topology/pre-processor.c
topology/pre-processor.h
topology/topology.h

index 1754fa263f20055dd61c6d1b415b0e532624b8d1..8f1b93bf4f96366d43f11b73e9dafbd14c86eae0 100755 (executable)
@@ -3,9 +3,13 @@
 #GDB="gdb --args"
 #GDB="strace"
 #GDB="valgrind --leak-check=yes --show-reachable=yes"
-GDB="perf stat"
+#GDB="perf stat"
+PROG=./alsaucm
+PROG=/home/perex/git/pipewire/builddir/spa/plugins/alsa/spa-acp-tool
+PROG="$HOME/git/pulseaudio/build/src/daemon/pulseaudio -n -F $HOME/git/pulseaudio/build/src/daemon/default.pa -p $HOME/git/pulseaudio/build/src/modules/"
+#PROG=pulseaudio
 
 #ALSA_CONFIG_UCM="$HOME/alsa/alsa-ucm-conf/ucm" \
 ALSA_CONFIG_UCM2="$HOME/alsa/alsa-ucm-conf/ucm2" \
 LD_PRELOAD="$HOME/alsa/alsa-lib/src/.libs/libasound.so" \
-$GDB ./alsaucm "$@"
+$GDB $PROG "$@"
index 63a4e3437fd97a801dd4bd1dc37f310f4794b04b..4f796d20308ad077aaa6bde7624b6f6d0e38609f 100644 (file)
@@ -41,6 +41,7 @@
 #include <time.h>
 #include <locale.h>
 #include <alsa/asoundlib.h>
+#include <alsa/use-case.h>
 #include <assert.h>
 #include <termios.h>
 #include <signal.h>
@@ -452,6 +453,30 @@ static ssize_t xwrite(int fd, const void *buf, size_t count)
        return offset;
 }
 
+static int open_ucm(snd_use_case_mgr_t **uc_mgr, char **pcm_name, const char *name)
+{
+       char *s, *p;
+       int err;
+
+       s = strdup(name);
+       if (s == NULL)
+               return -ENOMEM;
+       p = strchr(s, '.');
+       if (p == NULL)
+               return -EINVAL;
+       *p = '\0';
+       err = snd_use_case_mgr_open(uc_mgr, s);
+       if (err < 0)
+               return err;
+       err = snd_use_case_get(*uc_mgr, p + 1, (const char **)pcm_name);
+       if (err < 0) {
+               error(_("UCM value '%s' error: %s"), p + 1, snd_strerror(err));
+               snd_use_case_mgr_close(*uc_mgr);
+               return err;
+       }
+       return err;
+}
+
 static long parse_long(const char *str, int *err)
 {
        long val;
@@ -528,6 +553,7 @@ int main(int argc, char *argv[])
        int do_device_list = 0, do_pcm_list = 0, force_sample_format = 0;
        snd_pcm_info_t *info;
        FILE *direction;
+       snd_use_case_mgr_t *uc_mgr = NULL;
 
 #ifdef ENABLE_NLS
        setlocale(LC_ALL, "");
@@ -826,6 +852,16 @@ int main(int argc, char *argv[])
                goto __end;
        }
 
+       if (strncmp(pcm_name, "ucm.", 4) == 0) {
+               err = open_ucm(&uc_mgr, &pcm_name, pcm_name + 4);
+               if (err < 0) {
+                       error(_("UCM open error: %s"), snd_strerror(err));
+                       return 1;
+               }
+               if (verbose)
+                       fprintf(stderr, _("Found UCM PCM device: %s\n"), pcm_name);
+       }
+
        err = snd_pcm_open(&handle, pcm_name, stream, open_mode);
        if (err < 0) {
                error(_("audio open error: %s"), snd_strerror(err));
@@ -915,6 +951,8 @@ int main(int argc, char *argv[])
        if (verbose==2)
                putchar('\n');
        snd_pcm_close(handle);
+       if (uc_mgr)
+               snd_use_case_mgr_close(uc_mgr);
        handle = NULL;
        free(audiobuf);
       __end:
index 49fe8064d1b44a9f77737fe9ea05494d0cff7113..9355a861757d7b3de0f97030070f25d6d3963e6b 100644 (file)
@@ -423,112 +423,3 @@ err:
        free(sink_widget_name);
        return ret;
 }
-
-static int tplg_get_sample_size_from_format(const char *format)
-{
-       if (!strcmp(format, "s32le") || !strcmp(format, "s24le") || !strcmp(format, "float"))
-               return 4;
-
-       if (!strcmp(format, "s16le"))
-               return 2;
-
-       SNDERR("Unsupported format: %s\n", format);
-       return -EINVAL;
-}
-
-int tplg_update_buffer_auto_attr(struct tplg_pre_processor *tplg_pp,
-                                snd_config_t *buffer_cfg, snd_config_t *parent)
-{
-       snd_config_iterator_t i, next;
-       snd_config_t *n, *pipeline_cfg, *child;
-       const char *buffer_id, *format;
-       long periods, channels, sample_size;
-       long sched_period, rate, frames;
-       long buffer_size;
-       int err;
-
-       if (snd_config_get_id(buffer_cfg, &buffer_id) < 0)
-               return -EINVAL;
-
-       if (!parent) {
-               SNDERR("No parent for buffer %s\n", buffer_id);
-               return -EINVAL;
-       }
-
-       /* acquire attributes from buffer config */
-       snd_config_for_each(i, next, buffer_cfg) {
-               const char *id;
-
-               n = snd_config_iterator_entry(i);
-               if (snd_config_get_id(n, &id) < 0)
-                       continue;
-
-               if (!strcmp(id, "periods")) {
-                       if (snd_config_get_integer(n, &periods)) {
-                               SNDERR("Invalid number of periods for buffer %s\n", buffer_id);
-                               return -EINVAL;
-                       }
-               }
-
-               if (!strcmp(id, "channels")) {
-                       if (snd_config_get_integer(n, &channels)) {
-                               SNDERR("Invalid number of channels for buffer %s\n", buffer_id);
-                               return -EINVAL;
-                       }
-               }
-
-               if (!strcmp(id, "format")) {
-                       if (snd_config_get_string(n, &format)) {
-                               SNDERR("Invalid format for buffer %s\n", buffer_id);
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       pipeline_cfg = tplg_object_get_instance_config(tplg_pp, parent);
-
-       /* acquire some other attributes from parent pipeline config */
-       snd_config_for_each(i, next, pipeline_cfg) {
-               const char *id;
-
-               n = snd_config_iterator_entry(i);
-               if (snd_config_get_id(n, &id) < 0)
-                       continue;
-
-               if (!strcmp(id, "period")) {
-                       if (snd_config_get_integer(n, &sched_period)) {
-                               SNDERR("Invalid period for buffer %s\n", buffer_id);
-                               return -EINVAL;
-                       }
-               }
-
-               if (!strcmp(id, "rate")) {
-                       if (snd_config_get_integer(n, &rate)) {
-                               SNDERR("Invalid rate for buffer %s\n", buffer_id);
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       /* calculate buffer size */
-       sample_size = tplg_get_sample_size_from_format(format);
-       if (sample_size < 0) {
-               SNDERR("Invalid sample size value for %s\n", buffer_id);
-               return sample_size;
-       }
-       frames = (rate * sched_period) / 1000000;
-       buffer_size = periods * sample_size * channels * frames;
-
-       /* add size child config to buffer config */
-       err = tplg_config_make_add(&child, "size", SND_CONFIG_TYPE_INTEGER, buffer_cfg);
-       if (err < 0) {
-               SNDERR("Error creating size config for %s\n", buffer_id);
-               return err;
-       }
-
-       err = snd_config_set_integer(child, buffer_size);
-       if (err < 0)
-               SNDERR("Error setting size config for %s\n", buffer_id);
-
-       return err;
-}
index 57699ac54cbe079b6aeb004ed34d0d3cf11ffc29..5ce3beb04264b4b67d5ebe0bd7cfd9eaf32d8a21 100644 (file)
@@ -1014,8 +1014,7 @@ const struct build_function_map object_build_map[] = {
         &hwcfg_config},
        {"Base", "fe_dai", "dai", &tplg_build_fe_dai_object, NULL, &fe_dai_config},
        {"Base", "route", "SectionGraph", &tplg_build_dapm_route_object, NULL, NULL},
-       {"Widget", "buffer", "SectionWidget", &tplg_build_generic_object,
-        tplg_update_buffer_auto_attr, &widget_config},
+       {"Widget", "buffer", "SectionWidget", &tplg_build_generic_object, NULL, &widget_config},
        {"Widget", "", "SectionWidget", &tplg_build_generic_object, NULL, &widget_config},
        {"Control", "mixer", "SectionControlMixer", &tplg_build_mixer_control, NULL,
         &mixer_control_config},
@@ -1087,10 +1086,13 @@ static int tplg_object_copy_and_add_param(struct tplg_pre_processor *tplg_pp,
                                          snd_config_t *attr_cfg,
                                          snd_config_t *search_config)
 {
-       snd_config_t *attr, *new;
+       snd_config_iterator_t first = snd_config_iterator_first(obj);
+       snd_config_t *attr, *new, *first_cfg;
        const char *id, *search_id;
        int ret;
 
+       first_cfg = snd_config_iterator_entry(first);
+
        if (snd_config_get_id(attr_cfg, &id) < 0)
                return 0;
 
@@ -1108,10 +1110,19 @@ static int tplg_object_copy_and_add_param(struct tplg_pre_processor *tplg_pp,
                return ret;
        }
 
-       ret = snd_config_add(obj, new);
-       if (ret < 0) {
-               snd_config_delete(new);
-               SNDERR("error adding attribute '%s' value to %s\n", id, search_id);
+       if (first_cfg) {
+               /* prepend the new config */
+               ret = snd_config_add_before(first_cfg, new);
+               if (ret < 0) {
+                       snd_config_delete(new);
+                       SNDERR("error prepending attribute '%s' value to %s\n", id, search_id);
+               }
+       } else {
+               ret = snd_config_add(obj, new);
+               if (ret < 0) {
+                       snd_config_delete(new);
+                       SNDERR("error adding attribute '%s' value to %s\n", id, search_id);
+               }
        }
 
        return ret;
@@ -1488,12 +1499,67 @@ snd_config_t *tplg_object_get_instance_config(struct tplg_pre_processor *tplg_pp
        return snd_config_iterator_entry(first);
 }
 
+#if SND_LIB_VER(1, 2, 5) < SND_LIB_VERSION
+static int pre_process_find_variable(snd_config_t **dst, const char *str, snd_config_t *config)
+{
+       snd_config_iterator_t i, next;
+
+       snd_config_for_each(i, next, config) {
+               snd_config_t *n;
+               const char *id;
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               if (strcmp(id, str))
+                       continue;
+
+               /* found definition, copy config */
+               return snd_config_copy(dst, n);
+       }
+
+       return -EINVAL;
+}
+static int
+pre_process_object_variables_expand_fcn(snd_config_t **dst, const char *str, void *private_data)
+{
+
+       struct tplg_pre_processor *tplg_pp = private_data;
+       snd_config_t *object_cfg = tplg_pp->current_obj_cfg;
+       snd_config_t *conf_defines;
+       const char *object_id;
+       int ret;
+
+       ret = snd_config_search(tplg_pp->input_cfg, "Define", &conf_defines);
+       if (ret < 0)
+               return 0;
+
+       /* find variable from global definitions first */
+       ret = pre_process_find_variable(dst, str, conf_defines);
+       if (ret >= 0)
+               return ret;
+
+       if (snd_config_get_id(object_cfg, &object_id) < 0)
+               return -EINVAL;
+
+       /* find variable from object attribute values if not found in global definitions */
+       ret = pre_process_find_variable(dst, str, object_cfg);
+       if (ret < 0)
+               SNDERR("Failed to find definition for attribute %s in '%s' object\n",
+                      str, object_id);
+
+       return ret;
+}
+#endif
+
 /* build object config and its child objects recursively */
 static int tplg_build_object(struct tplg_pre_processor *tplg_pp, snd_config_t *new_obj,
                              snd_config_t *parent)
 {
        snd_config_t *obj_local, *class_cfg;
        const struct build_function_map *map;
+       snd_config_iterator_t i, next;
        build_func builder;
        update_auto_attr_func auto_attr_updater;
        const char *id, *class_id;
@@ -1534,6 +1600,46 @@ static int tplg_build_object(struct tplg_pre_processor *tplg_pp, snd_config_t *n
                return ret;
        }
 
+#if SND_LIB_VER(1, 2, 5) < SND_LIB_VERSION
+       tplg_pp_config_debug(tplg_pp, obj_local);
+
+       /* expand all non-compound type child configs in object */
+       snd_config_for_each(i, next, obj_local) {
+               snd_config_t *n, *new;
+               const char *id, *s;
+
+               n = snd_config_iterator_entry(i);
+
+               if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND)
+                       continue;
+
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               if (snd_config_get_string(n, &s) < 0)
+                       continue;
+
+               if (*s != '$')
+                       continue;
+
+               tplg_pp->current_obj_cfg = obj_local;
+
+               /* expand config */
+               ret = snd_config_evaluate_string(&new, s, pre_process_object_variables_expand_fcn,
+                                                tplg_pp);
+               if (ret < 0) {
+                       SNDERR("Failed to evaluate attributes %s in %s\n", id, class_id);
+                       return ret;
+               }
+
+               snd_config_set_id(new, id);
+
+               ret = snd_config_merge(n, new, true);
+               if (ret < 0)
+                       return ret;
+       }
+#endif
+
        /*
         * Build objects if object type is supported.
         * If not, process object attributes and add to parent's data section
index 23963a7df9fa4f3331356b2639a33d9fd4cfa73a..90a1570755c48531213b4bd547247200109b48b9 100644 (file)
@@ -259,57 +259,6 @@ static int pre_process_defines(struct tplg_pre_processor *tplg_pp, const char *p
        return 0;
 }
 
-static int pre_process_variables_expand_fcn(snd_config_t **dst, const char *str,
-                                           void *private_data)
-{
-       struct tplg_pre_processor *tplg_pp = private_data;
-       snd_config_iterator_t i, next;
-       snd_config_t *conf_defines;
-       int ret;
-
-       ret = snd_config_search(tplg_pp->input_cfg, "Define", &conf_defines);
-       if (ret < 0)
-               return 0;
-
-       /* find variable definition */
-       snd_config_for_each(i, next, conf_defines) {
-               snd_config_t *n;
-               const char *id;
-
-               n = snd_config_iterator_entry(i);
-               if (snd_config_get_id(n, &id) < 0)
-                       continue;
-
-               if (strcmp(id, str))
-                       continue;
-
-               /* found definition. Match type and return appropriate config */
-               if (snd_config_get_type(n) == SND_CONFIG_TYPE_STRING) {
-                       const char *s;
-
-                       if (snd_config_get_string(n, &s) < 0)
-                               continue;
-
-                       return snd_config_imake_string(dst, NULL, s);
-               }
-
-               if (snd_config_get_type(n) == SND_CONFIG_TYPE_INTEGER) {
-                       long v;
-
-                       if (snd_config_get_integer(n, &v) < 0)
-                               continue;
-
-                       ret = snd_config_imake_integer(dst, NULL, v);
-                       return ret;
-               }
-
-       }
-
-       fprintf(stderr, "No definition for variable %s\n", str);
-
-       return -EINVAL;
-}
-
 static int pre_process_includes(struct tplg_pre_processor *tplg_pp, snd_config_t *top,
                                const char *pre_processor_defs, const char *inc_path);
 
@@ -558,14 +507,6 @@ 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 pre-processor variables */
-       err = snd_config_expand_custom(tplg_pp->input_cfg, tplg_pp->input_cfg, pre_process_variables_expand_fcn,
-                                      tplg_pp, &tplg_pp->input_cfg);
-       if (err < 0) {
-               fprintf(stderr, "Failed to expand pre-processor definitions in input config\n");
-               goto err;
-       }
 #endif
 
        err = pre_process_config(tplg_pp, tplg_pp->input_cfg);
index c534ead65382ed155821b97145b7dd0f3ad8c6ec..6965a701fb2d126006b5c4166a8aa86efc2d5e05 100644 (file)
@@ -81,8 +81,6 @@ int tplg_build_pcm_caps_object(struct tplg_pre_processor *tplg_pp,
                               snd_config_t *obj_cfg, snd_config_t *parent);
 int tplg_parent_update(struct tplg_pre_processor *tplg_pp, snd_config_t *parent,
                          const char *section_name, const char *item_name);
-int tplg_update_buffer_auto_attr(struct tplg_pre_processor *tplg_pp,
-                                snd_config_t *buffer_cfg, snd_config_t *parent);
 int tplg_add_object_data(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
                         snd_config_t *top, const char *array_name);
 
index 11ee64e9d41f01b63410dd70b7c125e6f4b576fb..4b1e8fd62f538f09e217d2fc543d411253e52ec1 100644 (file)
@@ -25,6 +25,7 @@ struct tplg_pre_processor {
        snd_config_t *output_cfg;
        snd_output_t *output;
        snd_output_t *dbg_output;
+       snd_config_t *current_obj_cfg;
 };
 
 int pre_process(struct tplg_pre_processor *tplg_pp, char *config, size_t config_size,