On Fri, 2014-07-25 at 15:31 +0200, David Henningsson wrote: > A fallback mapping or profile will only be considered for probing > if all non-fallback profiles fail. > > If auto-profiles are used, a profile made up of one non-fallback > mapping and one fallback mapping will be considered a fallback profile. > > Signed-off-by: David Henningsson <david.henningsson at canonical.com> > --- > src/modules/alsa/alsa-mixer.c | 45 ++++++++++++++++++++++++ > src/modules/alsa/alsa-mixer.h | 2 ++ > src/modules/alsa/mixer/profile-sets/default.conf | 2 ++ > 3 files changed, 49 insertions(+) > > diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c > index 014499b..57d56c0 100644 > --- a/src/modules/alsa/alsa-mixer.c > +++ b/src/modules/alsa/alsa-mixer.c > @@ -3611,6 +3611,36 @@ static int mapping_parse_priority(pa_config_parser_state *state) { > return 0; > } > > +static int mapping_parse_fallback(pa_config_parser_state *state) { > + pa_alsa_profile_set *ps; > + pa_alsa_profile *p; > + pa_alsa_mapping *m; > + int k; > + bool fallback; > + > + pa_assert(state); > + > + ps = state->userdata; > + > + if ((k = pa_parse_boolean(state->rvalue)) < 0) { > + pa_log("[%s:%u] Fallback invalid of '%s'", state->filename, state->lineno, state->section); > + return -1; > + } > + fallback = !!k; Unnecessary !!. > + > + if ((m = pa_alsa_mapping_get(ps, state->section))) > + m->fallback = fallback; > + else if ((p = profile_get(ps, state->section))) > + p->fallback = fallback; > + else { > + pa_log("[%s:%u] Section name %s invalid.", state->filename, state->lineno, state->section); > + return -1; > + } > + > + return 0; > +} > + > + > static int profile_parse_mappings(pa_config_parser_state *state) { > pa_alsa_profile_set *ps; > pa_alsa_profile *p; > @@ -3939,12 +3969,14 @@ static void profile_set_add_auto_pair( > p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); > pa_idxset_put(p->output_mappings, m, NULL); > p->priority += m->priority * 100; > + p->fallback = m->fallback; > } > > if (n) { > p->input_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); > pa_idxset_put(p->input_mappings, n, NULL); > p->priority += n->priority; > + p->fallback |= n->fallback; > } > > pa_hashmap_put(ps->profiles, p->name, p); > @@ -4186,6 +4218,7 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel > /* Shared by [Mapping ...] and [Profile ...] */ > { "description", mapping_parse_description, NULL, NULL }, > { "priority", mapping_parse_priority, NULL, NULL }, > + { "fallback", mapping_parse_fallback, NULL, NULL }, > > /* [Profile ...] */ > { "input-mappings", profile_parse_mappings, NULL, NULL }, > @@ -4337,6 +4370,8 @@ void pa_alsa_profile_set_probe( > unsigned default_fragment_size_msec) { > > void *state; > + bool tryfallback = false; > + int profilesfound = 0; > pa_alsa_profile *p, *last = NULL; > pa_alsa_mapping *m; > pa_hashmap *broken_inputs, *broken_outputs, *used_paths; > @@ -4352,9 +4387,13 @@ void pa_alsa_profile_set_probe( > broken_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); > used_paths = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); > > +again: Alexander already complained about the goto, and you said that you probably will anyway need to improve this code. You didn't say how you plan to improve it, so here's my suggestion: When you encounter a fallback profile, add it to a temporary dynarray. Then after the first loop is finished, and no supported profiles have been found, loop over the dynarray that has the fallback profiles. That way the goto is avoided, and probing non-fallback profiles twice is avoided too. > PA_HASHMAP_FOREACH(p, ps->profiles, state) { > uint32_t idx; > > + if (p->fallback != tryfallback) > + continue; > + > /* Skip if this is already marked that it is supported (i.e. from the config file) */ > if (!p->supported) { > > @@ -4434,6 +4473,7 @@ void pa_alsa_profile_set_probe( > } > > pa_log_debug("Profile %s supported.", p->name); > + profilesfound++; > > if (p->output_mappings) > PA_IDXSET_FOREACH(m, p->output_mappings, idx) > @@ -4446,6 +4486,11 @@ void pa_alsa_profile_set_probe( > mapping_paths_probe(m, p, PA_ALSA_DIRECTION_INPUT, used_paths); > } > > + if (!tryfallback && (profilesfound == 0)) { > + tryfallback = true; > + goto again; > + } > + > /* Clean up */ > profile_finalize_probing(last, NULL); > > diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h > index d04c2bb..f394743 100644 > --- a/src/modules/alsa/alsa-mixer.h > +++ b/src/modules/alsa/alsa-mixer.h > @@ -265,6 +265,7 @@ struct pa_alsa_mapping { > > unsigned supported; > bool exact_channels:1; > + bool fallback:1; > > /* Temporarily used during probing */ > snd_pcm_t *input_pcm; > @@ -285,6 +286,7 @@ struct pa_alsa_profile { > unsigned priority; > > bool supported:1; > + bool fallback:1; > > char **input_mapping_names; > char **output_mapping_names; > diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf > index 77a4d76..a481efa 100644 > --- a/src/modules/alsa/mixer/profile-sets/default.conf > +++ b/src/modules/alsa/mixer/profile-sets/default.conf > @@ -57,6 +57,7 @@ > ; > ; exact-channels = yes | no # If no, and the exact number of channels is not supported, > ; # allow device to be opened with another channel count > +; fallback = no | yes # This mapping will only be considered if all non-fallback mappings fail > ; [Profile id] > ; input-mappings = ... # Lists mappings for sources on this profile, those mapping must be > ; # defined in this file too > @@ -68,6 +69,7 @@ > ; # will be assumed as working without probing. Makes initialization > ; # a bit faster but only works if the card is really known well. > ; > +; fallback = no | yes # This mapping will only be considered if all non-fallback profiles fail s/mapping/profile/ -- Tanu