]> git.alsa-project.org Git - alsa-utils.git/commitdiff
topology: pre-process-dapm: add support for route objects
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Mon, 26 Apr 2021 20:07:00 +0000 (13:07 -0700)
committerJaroslav Kysela <perex@perex.cz>
Tue, 25 May 2021 16:26:51 +0000 (18:26 +0200)
DAPM route objects such as:
Object.Base.route."1" {
source "dai.SSP.0.dai.capture"
sink "buffer.2.1"
}

will be converted to:

SectionGraph."Endpoint.route.1" {
index 0
lines [
"dai.SSP.0.capture, , buffer.2.1"
]
}

If the source/sink names are references to objects within a parent pipeline
object, the index attribute value can be skipped and it will be
populated when the object is pre-processed

Object.Pipeline.volume-capture."1" {
Object.Base.route."1" {
source "pga..0"
sink "buffer..0"
}
}

The reference pga..0 will need to be resolved to
get the widget name pga.1.0 and buffer..0 will
be resolved to buffer.1.0 before creating the SectionGraph as follows:

SectionGraph."volume-capture.1.route.1" {
index 2
lines [
"pga.1.0, , buffer.1.0"
]
}

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

index 63dd1fba488c26d56e825ab5903d583157c2fd48..d2b3b7aa3733ab83eb2b3454f79ded819a877aee 100644 (file)
@@ -129,3 +129,290 @@ int tplg_build_bytes_control(struct tplg_pre_processor *tplg_pp, snd_config_t *o
 {
        return tplg_build_control(tplg_pp, obj_cfg, parent, "bytes");
 }
+
+/*
+ * Widget names for pipeline endpoints can be of the following type:
+ * "class.<constructor args separated by .> ex: pga.0.1, buffer.1.1 etc
+ * Optionally, the index argument for a widget can be omitted and will be substituted with
+ * the index from the route: ex: pga..0, host..playback etc
+ */
+static int tplg_pp_get_widget_name(struct tplg_pre_processor *tplg_pp,
+                                     const char *string, long index, char **widget)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *temp_cfg, *child, *class_cfg, *n;
+       char *class_name, *args, *widget_name;
+       int ret;
+
+       /* get class name */
+       args = strchr(string, '.');
+       class_name = calloc(1, strlen(string) - strlen(args) + 1);
+       if (!class_name)
+               return -ENOMEM;
+
+       snprintf(class_name, strlen(string) - strlen(args) + 1, "%s", string);
+
+       /* create config with Widget class type */
+       ret = snd_config_make(&temp_cfg, "Widget", SND_CONFIG_TYPE_COMPOUND);
+       if (ret < 0) {
+               free(class_name);
+               return ret;
+       }
+
+       /* create config with class name and add it to the Widget config */
+       ret = tplg_config_make_add(&child, class_name, SND_CONFIG_TYPE_COMPOUND, temp_cfg);
+       if (ret < 0) {
+               free(class_name);
+               return ret;
+       }
+
+       /* get class definition for widget */
+       class_cfg = tplg_class_lookup(tplg_pp, temp_cfg);
+       snd_config_delete(temp_cfg);
+       if (!class_cfg) {
+               free(class_name);
+               return -EINVAL;
+       }
+
+       /* get constructor for class */
+       ret = snd_config_search(class_cfg, "attributes.constructor", &temp_cfg);
+       if (ret < 0) {
+               SNDERR("No arguments in class for widget %s\n", string);
+               free(class_name);
+               return ret;
+       }
+
+       widget_name = strdup(class_name);
+       free(class_name);
+       if (!widget_name)
+               return -ENOMEM;
+
+       /* construct widget name using the constructor argument values */
+       snd_config_for_each(i, next, temp_cfg) {
+               const char *id;
+               char *arg, *remaining, *temp;
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_string(n, &id) < 0)
+                       continue;
+
+               if (!args) {
+                       SNDERR("insufficient arugments for widget %s\n", string);
+                       return -EINVAL;
+               }
+
+               remaining = strchr(args + 1, '.');
+               if (remaining) {
+                       arg = calloc(1, strlen(args + 1) - strlen(remaining) + 1);
+                       if (!arg) {
+                               ret = -ENOMEM;
+                               goto err;
+                       }
+                       snprintf(arg, strlen(args + 1) - strlen(remaining) + 1, "%s", args + 1);
+               } else {
+                       arg = calloc(1, strlen(args + 1) + 1);
+                       if (!arg) {
+                               ret = -ENOMEM;
+                               goto err;
+                       }
+
+                       snprintf(arg, strlen(args + 1) + 1, "%s", args + 1);
+               }
+
+               /* if no index provided, substitue with route index */
+               if (!strcmp(arg, "") && !strcmp(id, "index")) {
+                       free(arg);
+                       arg = tplg_snprintf("%ld", index);
+                       if (!arg) {
+                               ret = -ENOMEM;
+                               free(arg);
+                               goto err;
+                       }
+               }
+               
+               temp = tplg_snprintf("%s.%s", widget_name, arg);
+               if (!temp) {
+                       ret = -ENOMEM;
+                       free(arg);
+                       goto err;
+               }
+
+               free(widget_name);
+               widget_name = temp;
+               free(arg);
+               if (remaining)
+                       args = remaining;
+               else
+                       args = NULL;
+       }
+
+       *widget = widget_name;
+       return 0;
+
+err:
+       free(widget_name);
+       return ret;
+}
+
+int tplg_build_dapm_route_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
+                             snd_config_t *parent)
+{
+       snd_config_t *top, *obj, *cfg, *route, *child, *parent_obj;
+       const char *name, *wname;
+       const char *parent_name = "Endpoint";
+       char *src_widget_name, *sink_widget_name, *line_str, *route_name;
+       const char *control = "";
+       long index = 0;
+       int ret;
+
+       obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
+
+       ret = snd_config_get_id(obj, &name);
+       if (ret < 0)
+               return -EINVAL;
+
+       /* endpoint connections at the top-level conf have no parent */
+       if (parent) {
+               parent_obj = tplg_object_get_instance_config(tplg_pp, parent);
+
+               ret = snd_config_get_id(parent_obj, &parent_name);
+               if (ret < 0)
+                       return -EINVAL;
+       }
+
+       tplg_pp_debug("Building DAPM route object: '%s' ...", name);
+
+       ret = snd_config_search(tplg_pp->output_cfg, "SectionGraph", &top);
+       if (ret < 0) {
+               ret = tplg_config_make_add(&top, "SectionGraph",
+                                         SND_CONFIG_TYPE_COMPOUND, tplg_pp->output_cfg);
+               if (ret < 0) {
+                       SNDERR("Error creating 'SectionGraph' config\n");
+                       return ret;
+               }
+       }
+
+       /* get route index */
+       ret = snd_config_search(obj, "index", &cfg);
+       if (ret >= 0) {
+               ret = snd_config_get_integer(cfg, &index);
+               if (ret < 0) {
+                       SNDERR("Invalid index route %s\n", name);
+                       return ret;
+               }
+       }
+
+       /* get source widget name */
+       ret = snd_config_search(obj, "source", &cfg);
+       if (ret < 0) {
+               SNDERR("No source for route %s\n", name);
+               return ret;
+       }
+
+       ret = snd_config_get_string(cfg, &wname);
+       if (ret < 0) {
+               SNDERR("Invalid name for source in route %s\n", name);
+               return ret;
+       }
+
+       ret = tplg_pp_get_widget_name(tplg_pp, wname, index, &src_widget_name);
+       if (ret < 0) {
+               SNDERR("error getting widget name for %s\n", wname);
+               return ret;
+       }
+
+       /* get sink widget name */
+       ret = snd_config_search(obj, "sink", &cfg);
+       if (ret < 0) {
+               SNDERR("No sink for route %s\n", name);
+               free(src_widget_name);
+               return ret;
+       }
+
+       ret = snd_config_get_string(cfg, &wname);
+       if (ret < 0) {
+               SNDERR("Invalid name for sink in route %s\n", name);
+               free(src_widget_name);
+               return ret;
+       }
+
+       ret = tplg_pp_get_widget_name(tplg_pp, wname, index, &sink_widget_name);
+       if (ret < 0) {
+               SNDERR("error getting widget name for %s\n", wname);
+               free(src_widget_name);
+               return ret;
+       }
+
+       /* get control name */
+       ret = snd_config_search(obj, "control", &cfg);
+       if (ret >= 0) {
+               ret = snd_config_get_string(cfg, &control);
+               if (ret < 0) {
+                       SNDERR("Invalid control name for route %s\n", name);
+                       goto err;
+               }
+       }
+
+       /* add route */
+       route_name = tplg_snprintf("%s.%s", parent_name, name);
+       if (!route_name) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = snd_config_make(&route, route_name, SND_CONFIG_TYPE_COMPOUND);
+       free(route_name);
+       if (ret < 0) {
+               SNDERR("Error creating route config for %s %d\n", name, ret);
+               goto err;
+       }
+
+       ret = snd_config_add(top, route);
+       if (ret < 0) {
+               SNDERR("Error adding route config for %s %d\n", name, ret);
+               goto err;
+       }
+
+       /* add index */
+       ret = tplg_config_make_add(&child, "index", SND_CONFIG_TYPE_INTEGER, route);
+       if (ret < 0) {
+               SNDERR("Error creating index config for %s\n", name);
+               goto err;
+       }
+
+       ret = snd_config_set_integer(child, index);
+       if (ret < 0) {
+               SNDERR("Error setting index config for %s\n", name);
+               goto err;
+       }
+
+       /* add lines */
+       ret = tplg_config_make_add(&cfg, "lines", SND_CONFIG_TYPE_COMPOUND, route);
+       if (ret < 0) {
+               SNDERR("Error creating lines config for %s\n", name);
+               goto err;
+       }
+
+       /* add route string */
+       ret = tplg_config_make_add(&child, "0", SND_CONFIG_TYPE_STRING, cfg);
+       if (ret < 0) {
+               SNDERR("Error creating lines config for %s\n", name);
+               goto err;
+       }
+
+       line_str = tplg_snprintf("%s, %s, %s", src_widget_name, control, sink_widget_name);
+       if (!line_str) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* set the line string */
+       ret = snd_config_set_string(child, line_str);
+       free(line_str);
+       if (ret < 0)
+               SNDERR("Error creating lines config for %s\n", name);
+err:
+       free(src_widget_name);
+       free(sink_widget_name);
+       return ret;
+}
index 8e49be8f0bcebd7292ff1d10d070c83531784690..1c8988d4cedc0b3123c3a7a7e1ba3d36fec71c96 100644 (file)
@@ -899,6 +899,7 @@ const struct build_function_map object_build_map[] = {
        {"Base", "extops", "extops" ,&tplg_build_ops_object, &ops_config},
        {"Base", "channel", "channel", &tplg_build_channel_object, &channel_config},
        {"Base", "VendorToken", "SectionVendorTokens", &tplg_build_vendor_token_object, NULL},
+       {"Base", "route", "SectionGraph", &tplg_build_dapm_route_object, NULL},
        {"Widget", "", "SectionWidget", &tplg_build_generic_object, &widget_config},
        {"Control", "mixer", "SectionControlMixer", &tplg_build_mixer_control,
         &mixer_control_config},
index e89fad6bcd5b484d0447f7d71443ffc4e0f58599..9c311075f3616481e99ddc8a9255ff56490cffb8 100644 (file)
@@ -65,6 +65,8 @@ int tplg_build_mixer_control(struct tplg_pre_processor *tplg_pp, snd_config_t *o
                              snd_config_t *parent);
 int tplg_build_bytes_control(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
                              snd_config_t *parent);
+int tplg_build_dapm_route_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);