[pulseaudio-discuss] [RFC PATCH 2/3] alsa: Allow "fallback" configuration for mappings and profiles

David Henningsson david.henningsson at canonical.com
Fri Jul 25 06:31:12 PDT 2014


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;
+
+    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:
     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
 ; [DecibelFix element]                      # Decibel fixes can be used to work around missing or incorrect dB
 ;                                           # information from alsa. A decibel fix is a table that maps volume steps
 ;                                           # to decibel values for one volume element. The "element" part in the
-- 
1.9.1



More information about the pulseaudio-discuss mailing list