mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-02 09:01:48 -05:00
ucm: add support for verb variants
The bellow configuration example creates two verbs ("HiFi" and "HiFi 7+1")
with different playback channels for the "Speaker" device.
SectionUseCase."HiFi" {
File "HiFi.conf"
Variant."HiFi" {
Comment "Default"
}
Variant."HiFi 7+1" {
Comment "HiFi 7.1"
}
}
SectionDevice."Speaker" {
Value {
PlaybackChannels 2
}
Variant."HiFi 7+1".Value {
PlaybackChannels 8
}
}
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
25e44bbeb9
commit
c3a5d32ac3
2 changed files with 189 additions and 20 deletions
207
src/ucm/parser.c
207
src/ucm/parser.c
|
|
@ -531,8 +531,7 @@ static int evaluate_include(snd_use_case_mgr_t *uc_mgr,
|
|||
/*
|
||||
* Evaluate condition (in-place)
|
||||
*/
|
||||
static int evaluate_condition(snd_use_case_mgr_t *uc_mgr,
|
||||
snd_config_t *cfg)
|
||||
static int evaluate_condition(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
||||
{
|
||||
snd_config_t *n;
|
||||
int err;
|
||||
|
|
@ -548,6 +547,58 @@ static int evaluate_condition(snd_use_case_mgr_t *uc_mgr,
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate variant (in-place)
|
||||
*/
|
||||
static int evaluate_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
snd_config_t *n, *c;
|
||||
const char *id;
|
||||
int err;
|
||||
|
||||
err = snd_config_search(cfg, "Variant", &c);
|
||||
if (err == -ENOENT)
|
||||
return 1;
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (uc_mgr->conf_format < 6) {
|
||||
uc_error("Variant is supported in v6+ syntax");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uc_mgr->parse_master_section)
|
||||
return 1;
|
||||
|
||||
if (uc_mgr->parse_variant == NULL)
|
||||
goto __ret;
|
||||
|
||||
snd_config_for_each(i, next, c) {
|
||||
n = snd_config_iterator_entry(i);
|
||||
|
||||
if (snd_config_get_id(n, &id) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (strcmp(id, uc_mgr->parse_variant))
|
||||
continue;
|
||||
|
||||
err = uc_mgr_evaluate_inplace(uc_mgr, n);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = uc_mgr_config_tree_merge(uc_mgr, cfg, n, NULL, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_config_delete(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__ret:
|
||||
snd_config_delete(c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* In-place evaluate
|
||||
*/
|
||||
|
|
@ -555,9 +606,9 @@ int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
|
|||
snd_config_t *cfg)
|
||||
{
|
||||
long iterations = 10000;
|
||||
int err1 = 0, err2 = 0, err3 = 0, err4 = 0;
|
||||
int err1 = 0, err2 = 0, err3 = 0, err4 = 0, err5 = 0;
|
||||
|
||||
while (err1 == 0 || err2 == 0 || err3 == 0 || err4 == 0) {
|
||||
while (err1 == 0 || err2 == 0 || err3 == 0 || err4 == 0 || err5 == 0) {
|
||||
if (iterations == 0) {
|
||||
uc_error("Maximal inplace evaluation iterations number reached (recursive references?)");
|
||||
return -EINVAL;
|
||||
|
|
@ -575,20 +626,25 @@ int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
|
|||
/* conditions may depend on them */
|
||||
if (err2 == 0)
|
||||
continue;
|
||||
err3 = evaluate_variant(uc_mgr, cfg);
|
||||
if (err3 < 0)
|
||||
return err3;
|
||||
if (err3 == 0)
|
||||
continue;
|
||||
uc_mgr->macro_hops++;
|
||||
if (uc_mgr->macro_hops > 100) {
|
||||
uc_error("Maximal macro hops reached!");
|
||||
return -EINVAL;
|
||||
}
|
||||
err3 = evaluate_macro(uc_mgr, cfg);
|
||||
err4 = evaluate_macro(uc_mgr, cfg);
|
||||
uc_mgr->macro_hops--;
|
||||
if (err3 < 0)
|
||||
return err3;
|
||||
if (err3 == 0)
|
||||
continue;
|
||||
err4 = evaluate_condition(uc_mgr, cfg);
|
||||
if (err4 < 0)
|
||||
return err3;
|
||||
return err4;
|
||||
if (err4 == 0)
|
||||
continue;
|
||||
err5 = evaluate_condition(uc_mgr, cfg);
|
||||
if (err5 < 0)
|
||||
return err5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1998,6 +2054,65 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse variant information
|
||||
*/
|
||||
static int parse_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
|
||||
char **_vfile, char **_vcomment)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
snd_config_t *n;
|
||||
char *file = NULL, *comment = NULL;
|
||||
int err;
|
||||
|
||||
/* parse master config sections */
|
||||
snd_config_for_each(i, next, cfg) {
|
||||
const char *id;
|
||||
n = snd_config_iterator_entry(i);
|
||||
if (snd_config_get_id(n, &id) < 0)
|
||||
continue;
|
||||
|
||||
/* get use case verb file name */
|
||||
if (strcmp(id, "File") == 0) {
|
||||
if (_vfile) {
|
||||
err = parse_string_substitute3(uc_mgr, n, &file);
|
||||
if (err < 0) {
|
||||
uc_error("failed to get File");
|
||||
goto __error;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get optional use case comment */
|
||||
if (strncmp(id, "Comment", 7) == 0) {
|
||||
if (_vcomment) {
|
||||
err = parse_string_substitute3(uc_mgr, n, &comment);
|
||||
if (err < 0) {
|
||||
uc_error("error: failed to get Comment");
|
||||
goto __error;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
uc_error("unknown field '%s' in Variant section", id);
|
||||
err = -EINVAL;
|
||||
goto __error;
|
||||
}
|
||||
|
||||
if (_vfile)
|
||||
*_vfile = file;
|
||||
if (_vcomment)
|
||||
*_vcomment = comment;
|
||||
return 0;
|
||||
|
||||
__error:
|
||||
free(file);
|
||||
free(comment);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse master section for "Use Case" and "File" tags.
|
||||
*/
|
||||
|
|
@ -2006,8 +2121,9 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
|
|||
void *data2 ATTRIBUTE_UNUSED)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
snd_config_t *n;
|
||||
snd_config_t *n, *variant = NULL;
|
||||
char *use_case_name, *file = NULL, *comment = NULL;
|
||||
bool variant_ok = false;
|
||||
int err;
|
||||
|
||||
if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
||||
|
|
@ -2022,7 +2138,9 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
|
|||
}
|
||||
|
||||
/* in-place evaluation */
|
||||
uc_mgr->parse_master_section = 1;
|
||||
err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
|
||||
uc_mgr->parse_master_section = 0;
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
|
||||
|
|
@ -2053,20 +2171,69 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
|
|||
continue;
|
||||
}
|
||||
|
||||
uc_error("unknown field %s in master section");
|
||||
if (uc_mgr->conf_format >= 6 && strcmp(id, "Variant") == 0) {
|
||||
snd_config_iterator_t i2, next2;
|
||||
variant = n;
|
||||
snd_config_for_each(i2, next2, n) {
|
||||
const char *id2;
|
||||
snd_config_t *n2;
|
||||
n2 = snd_config_iterator_entry(i2);
|
||||
if (snd_config_get_id(n2, &id2) < 0)
|
||||
continue;
|
||||
err = uc_mgr_evaluate_inplace(uc_mgr, n2);
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
if (strcmp(use_case_name, id2) == 0)
|
||||
variant_ok = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
uc_error("unknown field '%s' in SectionUseCase", id);
|
||||
}
|
||||
|
||||
uc_dbg("use_case_name %s file '%s'", use_case_name, file);
|
||||
|
||||
/* do we have both use case name and file ? */
|
||||
if (!file) {
|
||||
uc_error("error: use case missing file");
|
||||
if (variant && !variant_ok) {
|
||||
uc_error("error: undefined variant '%s'", use_case_name);
|
||||
err = -EINVAL;
|
||||
goto __error;
|
||||
}
|
||||
|
||||
/* parse verb file */
|
||||
err = parse_verb_file(uc_mgr, use_case_name, comment, file);
|
||||
if (!variant) {
|
||||
uc_dbg("use_case_name %s file '%s'", use_case_name, file);
|
||||
|
||||
/* do we have both use case name and file ? */
|
||||
if (!file) {
|
||||
uc_error("error: use case missing file");
|
||||
err = -EINVAL;
|
||||
goto __error;
|
||||
}
|
||||
|
||||
/* parse verb file */
|
||||
err = parse_verb_file(uc_mgr, use_case_name, comment, file);
|
||||
} else {
|
||||
/* parse variants */
|
||||
snd_config_for_each(i, next, variant) {
|
||||
char *vfile, *vcomment;
|
||||
const char *id;
|
||||
n = snd_config_iterator_entry(i);
|
||||
if (snd_config_get_id(n, &id) < 0)
|
||||
continue;
|
||||
if (!parse_is_name_safe(id)) {
|
||||
err = -EINVAL;
|
||||
goto __error;
|
||||
}
|
||||
err = parse_variant(uc_mgr, n, &vfile, &vcomment);
|
||||
if (err < 0)
|
||||
break;
|
||||
uc_mgr->parse_variant = id;
|
||||
err = parse_verb_file(uc_mgr, id,
|
||||
vcomment ? vcomment : comment,
|
||||
vfile ? vfile : file);
|
||||
uc_mgr->parse_variant = NULL;
|
||||
free(vfile);
|
||||
free(vcomment);
|
||||
}
|
||||
}
|
||||
|
||||
__error:
|
||||
free(use_case_name);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue