Skip to content

Commit

Permalink
topology: pre-processor: Introduce extends/overrides keywords for cla…
Browse files Browse the repository at this point in the history
…sses

Add 2 new keywords for class definitions to allow new pipeline classes
extend the definitions in the base class. This feature is useful for
extending previous pipeline class definitions with the addition of one
or more widgets without having to duplicate everything in the new class
definition.

For example: Consider a pipeline class definition as below. Note that
only the widgets & routes are shown here.

Class.Pipeline.mixout-gain-dai-copier-playback {
	Object.Widget {
		mixout."1" {}
		dai-copier."1" {}
		gain."1" {}
		pipeline."1" {}
	}

	Object.Base {
		!route [
			{
				source mixout.$index.1
				sink	gain.$index.1
			}
		]
	}
}

If we want to extend this pipeline with the addition of an eqiir/eqfir,
the extends keyword can be used as below:

Class.Pipeline.mixout-gain-eqiir-eqfir-dai-copier-playback {
	extends "mixout-gain-dai-copier-playback"

	Object.Widget {
		eqiir.1 {}
		eqfir.1 {}
	}

	Object.Base {
		!route [
			{
				source gain.$index.1
				sink   eqiir.$index.1
			}
			{
				source eqiir.$index.1
				sink   eqfir.$index.1
			}
		]
	}
}

This allows for defining a new class without having to duplicate
everything in the base class and just adding the new widgets/routes that
extend the current pipeline definition in the base class. The extends
keyword is useful when extending a pipeline while keeping the routes in
the base class intact and adding new widgets at the end of
the pipeline.

But if we want to modify an existing pipeline class while modifying the
order of widgets and/or inserting new widgets, we should use the
overridess keyword instead. This allows for adding new widgets to the
list of widgets in the base class definition while also allowing
overriding the routes to allow inserting the new widgets and reordering
the widgets in the base class. For example, if we want to add a drc
widget between the gain and the eqiir modules in the above class, we can
do the following:

Class.Pipeline.mixout-efx-dai-copier-playback {
	overrides "mixout-gain-eqiir-eqfir-dai-copier-playback"

	Object.Widget {
		drc.1 {}
	}

	Object.Base {
		!route [
			{
				source mixout.$index.1
				sink	gain.$index.1
			}
			{
				source gain.$index.1
				sink	drc.$index.1
			}
			{
				source	drc.$index.1
				sink	eqiir.$index.1
			}
			{
				source	eqiir.$index.1
				sink	eqfir.$index.1
			}
		]
	}
}

Note that the routes array contains all the routes in the new class
definition.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
  • Loading branch information
ranj063 committed May 22, 2024
1 parent cc0bcef commit 9b5c5fa
Showing 1 changed file with 161 additions and 0 deletions.
161 changes: 161 additions & 0 deletions topology/pre-processor.c
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,159 @@ static int pre_process_arrays(struct tplg_pre_processor *tplg_pp, snd_config_t *
return 0;
}

static int pre_process_class(struct tplg_pre_processor *tplg_pp, snd_config_t *top)
{
snd_config_iterator_t i, next;
snd_config_t *classes;
int ret;

ret = snd_config_search(top, "Class", &classes);
if (ret < 0)
return 0;

snd_config_for_each(i, next, classes) {
snd_config_iterator_t i2, next2;
snd_config_t *n, *class_cfg, *base_class, *tmp, *base_class_cfg, *tmp1;
snd_config_t * widget_cfg;
const char *class_name, *base_class_name, *class_type;
char *string;

n = snd_config_iterator_entry(i);
ret = snd_config_get_id(n, &class_type);
if (ret < 0)
return ret;

/* only "Pipeline" classes support the extends/overrides keyword */
if (strcmp(class_type, "Pipeline"))
continue;

snd_config_for_each(i2, next2, n) {
class_cfg = snd_config_iterator_entry(i2);
bool override = false;

/* check if the class extends/overrides a base class */
ret = snd_config_search(class_cfg, "extends", &base_class);
if (ret < 0) {
ret = snd_config_search(class_cfg, "overrides", &base_class);
if (ret < 0)
continue;
override = true;
}

ret = snd_config_get_id(class_cfg, &class_name);
if (ret < 0)
return ret;

/* get the base class name */
ret = snd_config_get_string(base_class, &base_class_name);
if (ret < 0) {
SNDERR("Invalid base class name for %s\n", class_name);
return ret;
}

string = tplg_snprintf("Class.%s.%s", class_type, base_class_name);
if (!string)
return -ENOMEM;

/* search base class config */
ret = snd_config_search(top, string, &base_class_cfg);
free(string);
if (ret < 0) {
SNDERR("Cannot find class definition for %s\n", base_class_name);
return ret;
}

/* create a temp node with the base class definition */
ret = snd_config_copy(&tmp, base_class_cfg);
if(ret < 0)
return ret;

/* create a temp node with the new class definition */
ret = snd_config_copy(&tmp1, class_cfg);
if(ret < 0) {
snd_config_delete(tmp);
return ret;
}

/*
* merge the base class config node with the new class config.
* The override flag when set indicates that the base class defaults in
* terms of pipeline params or routes must be overridden with the
* new class defaults. When overriding routes, a subclass must define all
* the routes in the pipeline.
*/
ret = snd_config_merge(tmp, tmp1, override);
if (ret < 0) {
SNDERR("Failed to merge base class definition for %s\n",
class_name);
snd_config_delete(tmp);
snd_config_delete(tmp1);
return ret;
}

/* merge the new config into the class config */
ret = snd_config_merge(class_cfg, tmp, true);
if (ret < 0) {
snd_config_delete(tmp);
return ret;
}

/* delete the extends/overrides node from the class config */
snd_config_delete(base_class);

if (!override)
continue;

/*
* since a merge with override removes all widgets from the base class,
* copy them back into the new class config
*/
ret = snd_config_search(base_class_cfg, "Object.Widget", &widget_cfg);
if (ret < 0)
continue;

ret = snd_config_copy(&tmp, widget_cfg);
if (ret < 0) {
SNDERR("failed to copy widgets from the base class %s\n",
base_class_name);
return ret;
}

ret = snd_config_search(class_cfg, "Object.Widget", &widget_cfg);
if (ret < 0) {
snd_config_delete(tmp);
continue;
}

ret = snd_config_merge(widget_cfg, tmp, false);
if (ret < 0) {
SNDERR("failed to merge widgets from the base class %s to the sub class %s\n",
base_class_name, class_name);
return ret;
}
}
}

return 0;
}

static int pre_process_classes(struct tplg_pre_processor *tplg_pp, snd_config_t *top)
{
int ret;

if (snd_config_get_type(top) != SND_CONFIG_TYPE_COMPOUND)
return 0;

/* process classes at this node */
ret = pre_process_class(tplg_pp, top);
if (ret < 0) {
fprintf(stderr, "Failed to preprocess classes\n");
return ret;
}

return 0;
}

#endif /* version < 1.2.6 */

int pre_process(struct tplg_pre_processor *tplg_pp, char *config, size_t config_size,
Expand Down Expand Up @@ -980,6 +1133,14 @@ int pre_process(struct tplg_pre_processor *tplg_pp, char *config, size_t config_
fprintf(stderr, "Failed to process object arrays in input config\n");
goto err;
}

/* expand subclasses */
err = pre_process_classes(tplg_pp, tplg_pp->input_cfg);
if (err < 0) {
fprintf(stderr, "Failed to process sub classes in input config\n");
goto err;
}

#endif

err = pre_process_config(tplg_pp, tplg_pp->input_cfg);
Expand Down

0 comments on commit 9b5c5fa

Please sign in to comment.