[pulseaudio-commits] 3 commits - src/modules

David Henningsson diwic at kemper.freedesktop.org
Fri Aug 1 09:06:34 PDT 2014


 src/modules/alsa/alsa-mixer.c                    |  121 +++++++++++++++++++++--
 src/modules/alsa/alsa-mixer.h                    |    4 
 src/modules/alsa/mixer/profile-sets/default.conf |   15 ++
 3 files changed, 130 insertions(+), 10 deletions(-)

New commits:
commit 48edd0a00f455df075efcf1986103e5f507c816f
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Jul 25 15:16:41 2014 +0200

    alsa: Add a multichannel fallback mapping
    
    In case all other profiles fail, try this fallback mapping as well.
    It allows the device to specify the channel count, so it can be used
    for devices that only supports being opened in multichannel mode.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 9aa28a3..b4f4bbd 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3859,6 +3859,7 @@ static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) {
     static const struct description_map well_known_descriptions[] = {
         { "analog-mono",            N_("Analog Mono") },
         { "analog-stereo",          N_("Analog Stereo") },
+        { "multichannel",           N_("Multichannel") },
         { "analog-surround-21",     N_("Analog Surround 2.1") },
         { "analog-surround-30",     N_("Analog Surround 3.0") },
         { "analog-surround-31",     N_("Analog Surround 3.1") },
diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf
index ebe2324..8b67e33 100644
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -107,7 +107,7 @@ device-strings = hw:%f
 channel-map = mono
 paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-desktop-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono
 paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic
-priority = 1
+priority = 2
 
 [Mapping analog-stereo]
 device-strings = front:%f hw:%f
@@ -165,7 +165,7 @@ direction = output
 # device name standardized in alsa.
 device-strings = hw:%f
 channel-map = aux0,aux1,aux2,aux3
-priority = 1
+priority = 2
 direction = input
 
 [Mapping iec958-stereo]
@@ -452,6 +452,13 @@ channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
 
+[Mapping multichannel]
+device-strings = hw:%f
+channel-map = left,right,rear-left,rear-right
+exact-channels = false
+fallback = yes
+priority = 1
+
 ; An example for defining multiple-sink profiles
 #[Profile output:analog-stereo+output:iec958-stereo+input:analog-stereo]
 #description = Foobar

commit c15107eaf6045711d799a71204a8f94a1c424182
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Jul 25 15:05:45 2014 +0200

    alsa: Allow "fallback" configuration for mappings and profiles
    
    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>

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 99466eb..ebe2324 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

commit be8311417caedc3c5a539cc06a7549bfdbd167e3
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Jul 25 14:57:55 2014 +0200

    alsa: Add "exact-channels" mapping configurability
    
    Allow a mapping to relax the exact channel restriction:
    
    exact-channels = yes | no # If no, and the exact number of channels is not supported,
                              # allow device to be opened with another channel count
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 58f9182..77c3c7e 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3368,6 +3368,7 @@ pa_alsa_mapping *pa_alsa_mapping_get(pa_alsa_profile_set *ps, const char *name)
 
     m = pa_xnew0(pa_alsa_mapping, 1);
     m->profile_set = ps;
+    m->exact_channels = true;
     m->name = pa_xstrdup(name);
     pa_sample_spec_init(&m->sample_spec);
     pa_channel_map_init(&m->channel_map);
@@ -3485,6 +3486,30 @@ static int mapping_parse_paths(pa_config_parser_state *state) {
     return 0;
 }
 
+static int mapping_parse_exact_channels(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
+    pa_alsa_mapping *m;
+    int b;
+
+    pa_assert(state);
+
+    ps = state->userdata;
+
+    if (!(m = pa_alsa_mapping_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
+        return -1;
+    }
+
+    if ((b = pa_parse_boolean(state->rvalue)) < 0) {
+        pa_log("[%s:%u] %s has invalid value '%s'", state->filename, state->lineno, state->lvalue, state->section);
+        return -1;
+    }
+
+    m->exact_channels = b;
+
+    return 0;
+}
+
 static int mapping_parse_element(pa_config_parser_state *state) {
     pa_alsa_profile_set *ps;
     pa_alsa_mapping *m;
@@ -4156,6 +4181,7 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel
         { "element-input",          mapping_parse_element,        NULL, NULL },
         { "element-output",         mapping_parse_element,        NULL, NULL },
         { "direction",              mapping_parse_direction,      NULL, NULL },
+        { "exact-channels",         mapping_parse_exact_channels, NULL, NULL },
 
         /* Shared by [Mapping ...] and [Profile ...] */
         { "description",            mapping_parse_description,    NULL, NULL },
@@ -4264,10 +4290,12 @@ static void profile_finalize_probing(pa_alsa_profile *to_be_finalized, pa_alsa_p
 static snd_pcm_t* mapping_open_pcm(pa_alsa_mapping *m,
                                    const pa_sample_spec *ss,
                                    const char *dev_id,
+                                   bool exact_channels,
                                    int mode,
                                    unsigned default_n_fragments,
                                    unsigned default_fragment_size_msec) {
 
+    snd_pcm_t* handle;
     pa_sample_spec try_ss = *ss;
     pa_channel_map try_map = m->channel_map;
     snd_pcm_uframes_t try_period_size, try_buffer_size;
@@ -4279,10 +4307,17 @@ static snd_pcm_t* mapping_open_pcm(pa_alsa_mapping *m,
         pa_frame_size(&try_ss);
     try_buffer_size = default_n_fragments * try_period_size;
 
-    return pa_alsa_open_by_template(
+    handle = pa_alsa_open_by_template(
                               m->device_strings, dev_id, NULL, &try_ss,
                               &try_map, mode, &try_period_size,
-                              &try_buffer_size, 0, NULL, NULL, true);
+                              &try_buffer_size, 0, NULL, NULL, exact_channels);
+    if (handle && !exact_channels && m->channel_map.channels != try_map.channels) {
+        char buf[PA_CHANNEL_MAP_SNPRINT_MAX];
+        pa_log_debug("Channel map for mapping '%s' permanently changed to '%s'", m->name,
+                     pa_channel_map_snprint(buf, sizeof(buf), &try_map));
+        m->channel_map = try_map;
+    }
+    return handle;
 }
 
 static void paths_drop_unused(pa_hashmap* h, pa_hashmap *keep) {
@@ -4365,7 +4400,7 @@ void pa_alsa_profile_set_probe(
                         continue;
 
                     pa_log_debug("Checking for playback on %s (%s)", m->description, m->name);
-                    if (!(m->output_pcm = mapping_open_pcm(m, ss, dev_id,
+                    if (!(m->output_pcm = mapping_open_pcm(m, ss, dev_id, m->exact_channels,
                                                            SND_PCM_STREAM_PLAYBACK,
                                                            default_n_fragments,
                                                            default_fragment_size_msec))) {
@@ -4386,7 +4421,7 @@ void pa_alsa_profile_set_probe(
                         continue;
 
                     pa_log_debug("Checking for recording on %s (%s)", m->description, m->name);
-                    if (!(m->input_pcm = mapping_open_pcm(m, ss, dev_id,
+                    if (!(m->input_pcm = mapping_open_pcm(m, ss, dev_id, m->exact_channels,
                                                           SND_PCM_STREAM_CAPTURE,
                                                           default_n_fragments,
                                                           default_fragment_size_msec))) {
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 995a34b..d04c2bb 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -264,6 +264,7 @@ struct pa_alsa_mapping {
     pa_alsa_path_set *output_path_set;
 
     unsigned supported;
+    bool exact_channels:1;
 
     /* Temporarily used during probing */
     snd_pcm_t *input_pcm;
diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf
index 917510d..99466eb 100644
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -55,6 +55,8 @@
 ; priority = ...
 ; direction = any | input | output          # Only useful for?
 ;
+; exact-channels = yes | no                 # If no, and the exact number of channels is not supported,
+;                                           # allow device to be opened with another channel count
 ; [Profile id]
 ; input-mappings = ...                      # Lists mappings for sources on this profile, those mapping must be
 ;                                           # defined in this file too



More information about the pulseaudio-commits mailing list