From b0f72311cf49e25ea05279e3a978bb4db54dd332 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Mon, 20 Dec 2010 12:29:27 +0100 Subject: alsa-mixer: add required-any and required-* for enum options Now you can add required-any to elements in a path and the path will be valid as long as at least one of the elements are present. Also you can have required, required-any and required-absent in element options, causing a path to be unsupported if an option is (not) present (simplified example: to skip line in path if "Capture source" doesn't have a "Line In" option). Signed-off-by: David Henningsson --- src/modules/alsa/alsa-mixer.c | 90 +++++++++++++++++++--- src/modules/alsa/alsa-mixer.h | 8 ++ .../alsa/mixer/paths/analog-output.conf.common | 5 ++ 3 files changed, 91 insertions(+), 12 deletions(-) (limited to 'src/modules/alsa') diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index c1bbdce7..967140bf 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -1121,6 +1121,41 @@ static int check_required(pa_alsa_element *e, snd_mixer_elem_t *me) { if (e->required_absent == PA_ALSA_REQUIRED_ANY && (has_switch || has_volume || has_enumeration)) return -1; + if (e->required_any != PA_ALSA_REQUIRED_IGNORE) { + switch (e->required_any) { + case PA_ALSA_REQUIRED_VOLUME: + e->path->req_any_present |= (e->volume_use != PA_ALSA_VOLUME_IGNORE); + break; + case PA_ALSA_REQUIRED_SWITCH: + e->path->req_any_present |= (e->switch_use != PA_ALSA_SWITCH_IGNORE); + break; + case PA_ALSA_REQUIRED_ENUMERATION: + e->path->req_any_present |= (e->enumeration_use != PA_ALSA_ENUMERATION_IGNORE); + break; + case PA_ALSA_REQUIRED_ANY: + e->path->req_any_present |= + (e->volume_use != PA_ALSA_VOLUME_IGNORE) || + (e->switch_use != PA_ALSA_SWITCH_IGNORE) || + (e->enumeration_use != PA_ALSA_ENUMERATION_IGNORE); + break; + } + } + + if (e->enumeration_use == PA_ALSA_ENUMERATION_SELECT) { + pa_alsa_option *o; + PA_LLIST_FOREACH(o, e->options) { + e->path->req_any_present |= (o->required_any != PA_ALSA_REQUIRED_IGNORE) && + (o->alsa_idx >= 0); + if (o->required != PA_ALSA_REQUIRED_IGNORE && o->alsa_idx < 0) + return -1; + if (o->required_absent != PA_ALSA_REQUIRED_IGNORE && o->alsa_idx >= 0) + return -1; + } + } + + if (check_required(e, me) < 0) + return -1; + return 0; } @@ -1293,9 +1328,6 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) { } - if (check_required(e, me) < 0) - return -1; - if (e->switch_use == PA_ALSA_SWITCH_SELECT) { pa_alsa_option *o; @@ -1581,20 +1613,23 @@ static int element_parse_required( pa_alsa_path *p = userdata; pa_alsa_element *e; + pa_alsa_option *o; pa_alsa_required_t req; pa_assert(p); - if (!(e = element_get(p, section, TRUE))) { + e = element_get(p, section, TRUE); + o = option_get(p, section); + if (!e && !o) { pa_log("[%s:%u] Required makes no sense in '%s'", filename, line, section); return -1; } if (pa_streq(rvalue, "ignore")) req = PA_ALSA_REQUIRED_IGNORE; - else if (pa_streq(rvalue, "switch")) + else if (pa_streq(rvalue, "switch") && e) req = PA_ALSA_REQUIRED_SWITCH; - else if (pa_streq(rvalue, "volume")) + else if (pa_streq(rvalue, "volume") && e) req = PA_ALSA_REQUIRED_VOLUME; else if (pa_streq(rvalue, "enumeration")) req = PA_ALSA_REQUIRED_ENUMERATION; @@ -1605,10 +1640,28 @@ static int element_parse_required( return -1; } - if (pa_streq(lvalue, "required-absent")) - e->required_absent = req; - else - e->required = req; + if (pa_streq(lvalue, "required-absent")) { + if (e) + e->required_absent = req; + if (o) + o->required_absent = req; + } + else if (pa_streq(lvalue, "required-any")) { + if (e) { + e->required_any = req; + e->path->has_req_any = TRUE; + } + if (o) { + o->required_any = req; + o->element->path->has_req_any = TRUE; + } + } + else { + if (e) + e->required = req; + if (o) + o->required = req; + } return 0; } @@ -1860,7 +1913,10 @@ static int element_verify(pa_alsa_element *e) { pa_assert(e); +// pa_log_debug("Element %s, path %s: r=%d, r-any=%d, r-abs=%d", e->alsa_name, e->path->name, e->required, e->required_any, e->required_absent); if ((e->required != PA_ALSA_REQUIRED_IGNORE && e->required == e->required_absent) || + (e->required_any != PA_ALSA_REQUIRED_IGNORE && e->required_any == e->required_absent) || + (e->required_absent == PA_ALSA_REQUIRED_ANY && e->required_any != PA_ALSA_REQUIRED_IGNORE) || (e->required_absent == PA_ALSA_REQUIRED_ANY && e->required != PA_ALSA_REQUIRED_IGNORE)) { pa_log("Element %s cannot be required and absent at the same time.", e->alsa_name); return -1; @@ -1941,6 +1997,7 @@ pa_alsa_path* pa_alsa_path_new(const char *fname, pa_alsa_direction_t direction) { "override-map.2", element_parse_override_map, NULL, NULL }, /* ... later on we might add override-map.3 and so on here ... */ { "required", element_parse_required, NULL, NULL }, + { "required-any", element_parse_required, NULL, NULL }, { "required-absent", element_parse_required, NULL, NULL }, { "direction", element_parse_direction, NULL, NULL }, { "direction-try-other", element_parse_direction_try_other, NULL, NULL }, @@ -2185,11 +2242,13 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) { min_dB[t] += e->min_dB; max_dB[t] += e->max_dB; } - } else + } else { /* Hmm, there's another element before us * which cannot do dB volumes, so we we need * to 'neutralize' this slider */ e->volume_use = PA_ALSA_VOLUME_ZERO; + pa_log_info("Zeroing volume of '%s' on path '%s'", e->alsa_name, p->name); + } } } else if (p->has_volume) /* We can't use this volume, so let's ignore it */ @@ -2202,6 +2261,12 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) { p->has_mute = TRUE; } + if (p->has_req_any && !p->req_any_present) { + p->supported = FALSE; + pa_log_debug("Skipping path '%s', none of required-any elements preset.", p->name); + return -1; + } + path_drop_unsupported(p); path_make_options_unique(p); path_create_settings(p); @@ -2247,13 +2312,14 @@ void pa_alsa_element_dump(pa_alsa_element *e) { pa_alsa_option *o; pa_assert(e); - pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, enumeration=%i, required=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%s", + pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, enumeration=%i, required=%i, required_any=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%s", e->alsa_name, e->direction, e->switch_use, e->volume_use, e->enumeration_use, e->required, + e->required_any, e->required_absent, (long long unsigned) e->merged_mask, e->n_channels, diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h index 7fb408a6..0fcfc0a4 100644 --- a/src/modules/alsa/alsa-mixer.h +++ b/src/modules/alsa/alsa-mixer.h @@ -112,6 +112,10 @@ struct pa_alsa_option { char *name; char *description; unsigned priority; + + pa_alsa_required_t required; + pa_alsa_required_t required_any; + pa_alsa_required_t required_absent; }; /* And element wraps one specific ALSA element. A series of elements * @@ -129,6 +133,7 @@ struct pa_alsa_element { pa_alsa_enumeration_use_t enumeration_use; pa_alsa_required_t required; + pa_alsa_required_t required_any; pa_alsa_required_t required_absent; pa_bool_t override_map:1; @@ -164,6 +169,9 @@ struct pa_alsa_path { pa_bool_t has_mute:1; pa_bool_t has_volume:1; pa_bool_t has_dB:1; + /* These two are used during probing only */ + pa_bool_t has_req_any:1; + pa_bool_t req_any_present:1; long min_volume, max_volume; double min_dB, max_dB; diff --git a/src/modules/alsa/mixer/paths/analog-output.conf.common b/src/modules/alsa/mixer/paths/analog-output.conf.common index 6131da5c..ffd1b413 100644 --- a/src/modules/alsa/mixer/paths/analog-output.conf.common +++ b/src/modules/alsa/mixer/paths/analog-output.conf.common @@ -63,10 +63,15 @@ ; # by the option name, resp. on/off if the element is a switch. ; name = ... # Logical name to use in the path identifier ; priority = ... # Priority if this is made into a device port +; required = ignore | enumeration | any # In this element, this option must exist or the path will be invalid. ("any" is an alias for "enumeration".) +; required-any = ignore | enumeration | any # In this element, either this or another option must exist (or an element) +; required-absent = ignore | enumeration | any # In this element, this option must not exist or the path will be invalid ; ; [Element ...] # For each element that we shall control ; required = ignore | switch | volume | enumeration | any # If set, require this element to be of this kind and available, ; # otherwise don't consider this path valid for the card +; required-any = ignore | switch | volume | enumeration | any # If set, at least one of the elements with required-any in this +; # path must be present, otherwise this path is invalid for the card ; required-absent = ignore | switch | volume # If set, require this element to not be of this kind and not ; # available, otherwise don't consider this path valid for the card ; -- cgit