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

David Henningsson david.henningsson at canonical.com
Tue Jul 29 07:43:59 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                    | 77 ++++++++++++++++++++++--
 src/modules/alsa/alsa-mixer.h                    |  3 +
 src/modules/alsa/mixer/profile-sets/default.conf |  2 +
 3 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 77c3c7e..9aa28a3 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3611,6 +3611,34 @@ 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;
+
+    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;
+    }
+
+    if ((m = pa_alsa_mapping_get(ps, state->section)))
+        m->fallback = k;
+    else if ((p = profile_get(ps, state->section)))
+        p->fallback_input = p->fallback_output = k;
+    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 +3967,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_output = 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_input = n->fallback;
     }
 
     pa_hashmap_put(ps->profiles, p->name, p);
@@ -4186,6 +4216,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 +4368,24 @@ static void paths_drop_unused(pa_hashmap* h, pa_hashmap *keep) {
     }
 }
 
+static int add_profiles_to_probe(
+        pa_alsa_profile **list,
+        pa_hashmap *profiles,
+        bool fallback_output,
+        bool fallback_input) {
+
+    int i = 0;
+    void *state;
+    pa_alsa_profile *p;
+    PA_HASHMAP_FOREACH(p, profiles, state)
+        if (p->fallback_input == fallback_input && p->fallback_output == fallback_output) {
+            *list = p;
+            list++;
+            i++;
+        }
+    return i;
+}
+
 void pa_alsa_profile_set_probe(
         pa_alsa_profile_set *ps,
         const char *dev_id,
@@ -4344,8 +4393,10 @@ void pa_alsa_profile_set_probe(
         unsigned default_n_fragments,
         unsigned default_fragment_size_msec) {
 
-    void *state;
+    bool found_output = false, found_input = false;
+
     pa_alsa_profile *p, *last = NULL;
+    pa_alsa_profile **pp, **probe_order;
     pa_alsa_mapping *m;
     pa_hashmap *broken_inputs, *broken_outputs, *used_paths;
 
@@ -4359,9 +4410,22 @@ void pa_alsa_profile_set_probe(
     broken_inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
     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);
+    pp = probe_order = pa_xnew0(pa_alsa_profile *, pa_hashmap_size(ps->profiles) + 1);
 
-    PA_HASHMAP_FOREACH(p, ps->profiles, state) {
+    pp += add_profiles_to_probe(pp, ps->profiles, false, false);
+    pp += add_profiles_to_probe(pp, ps->profiles, false, true);
+    pp += add_profiles_to_probe(pp, ps->profiles, true, false);
+    pp += add_profiles_to_probe(pp, ps->profiles, true, true);
+
+    for (pp = probe_order; *pp; pp++) {
         uint32_t idx;
+        p = *pp;
+
+        /* Skip if fallback and already found something */
+        if (found_input && p->fallback_input)
+            continue;
+        if (found_output && p->fallback_output)
+            continue;
 
         /* Skip if this is already marked that it is supported (i.e. from the config file) */
         if (!p->supported) {
@@ -4445,13 +4509,17 @@ void pa_alsa_profile_set_probe(
 
         if (p->output_mappings)
             PA_IDXSET_FOREACH(m, p->output_mappings, idx)
-                if (m->output_pcm)
+                if (m->output_pcm) {
+                    found_output |= !p->fallback_output;
                     mapping_paths_probe(m, p, PA_ALSA_DIRECTION_OUTPUT, used_paths);
+                }
 
         if (p->input_mappings)
             PA_IDXSET_FOREACH(m, p->input_mappings, idx)
-                if (m->input_pcm)
+                if (m->input_pcm) {
+                    found_input |= !p->fallback_input;
                     mapping_paths_probe(m, p, PA_ALSA_DIRECTION_INPUT, used_paths);
+                }
     }
 
     /* Clean up */
@@ -4464,6 +4532,7 @@ void pa_alsa_profile_set_probe(
     pa_hashmap_free(broken_inputs);
     pa_hashmap_free(broken_outputs);
     pa_hashmap_free(used_paths);
+    pa_xfree(probe_order);
 
     ps->probed = true;
 }
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index d04c2bb..4949560 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,8 @@ struct pa_alsa_profile {
     unsigned priority;
 
     bool supported:1;
+    bool fallback_input:1;
+    bool fallback_output: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..feede52 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 profile 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