mirror of
https://github.com/alsa-project/alsa-utils
synced 2025-01-03 18:59:44 +01:00
topology: pre-process-dapm: add support for route objects
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>
This commit is contained in:
parent
79033ceae4
commit
758e4dba81
3 changed files with 290 additions and 0 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue