[pulseaudio-discuss] [PATCH 1/3] alsa-mixer: add query_hw_device option to mappings

Tanu Kaskinen tanuk at iki.fi
Mon Jun 12 15:45:14 UTC 2017


We have so far assumed that HDMI always uses device indexes 3, 7, 8, 9,
10, 11, 12 and 13. These values are hardcoded in the path configuration.
The Intel HDMI LPE driver, however, uses a different device numbering
scheme.

This patch adds a new configuration option for mappings. The option
tells PulseAudio to query the hw device index using snd_pcm_info(). It's
disabled by default, because querying the hw device doesn't always work
(but it's expected work for all hdmi devices).

This patch doesn't yet use the queried device index, that's left for
the subsequent patches.

BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=100488
---
 src/modules/alsa/alsa-mixer.c                    | 83 +++++++++++++++++++++---
 src/modules/alsa/alsa-mixer.h                    | 12 ++++
 src/modules/alsa/mixer/profile-sets/default.conf | 37 +++++++++++
 3 files changed, 124 insertions(+), 8 deletions(-)

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index f59cad394..8bd90a728 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3504,6 +3504,7 @@ pa_alsa_mapping *pa_alsa_mapping_get(pa_alsa_profile_set *ps, const char *name)
     pa_sample_spec_init(&m->sample_spec);
     pa_channel_map_init(&m->channel_map);
     m->proplist = pa_proplist_new();
+    m->hw_device_index = -1;
 
     pa_hashmap_put(ps->mappings, m->name, m);
 
@@ -3641,6 +3642,31 @@ static int mapping_parse_exact_channels(pa_config_parser_state *state) {
     return 0;
 }
 
+static int mapping_parse_query_hw_device(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] Option '%s' not expected 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->query_hw_device = b;
+
+    return 0;
+}
+
 static int mapping_parse_element(pa_config_parser_state *state) {
     pa_alsa_profile_set *ps;
     pa_alsa_mapping *m;
@@ -4357,6 +4383,7 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel
         { "element-output",         mapping_parse_element,        NULL, NULL },
         { "direction",              mapping_parse_direction,      NULL, NULL },
         { "exact-channels",         mapping_parse_exact_channels, NULL, NULL },
+        { "query-hw-device",        mapping_parse_query_hw_device,NULL, NULL },
 
         /* Shared by [Mapping ...] and [Profile ...] */
         { "description",            mapping_parse_description,    NULL, NULL },
@@ -4531,6 +4558,24 @@ static int add_profiles_to_probe(
     return i;
 }
 
+static int mapping_query_hw_device(pa_alsa_mapping *mapping, snd_pcm_t *pcm) {
+    int r;
+    snd_pcm_info_t* pcm_info;
+    snd_pcm_info_alloca(&pcm_info);
+
+    pa_assert(mapping->query_hw_device);
+
+    r = snd_pcm_info(pcm, pcm_info);
+    if (r < 0) {
+        pa_log("Mapping %s has query_hw_device enabled, but snd_pcm_info() failed %s: ", mapping->name, pa_alsa_strerror(r));
+        return -1;
+    }
+
+    mapping->hw_device_index = snd_pcm_info_get_device(pcm_info);
+
+    return 0;
+}
+
 void pa_alsa_profile_set_probe(
         pa_alsa_profile_set *ps,
         const char *dev_id,
@@ -4574,6 +4619,7 @@ void pa_alsa_profile_set_probe(
 
         /* Skip if this is already marked that it is supported (i.e. from the config file) */
         if (!p->supported) {
+            bool only_one_mapping;
 
             profile_finalize_probing(last, p);
             p->supported = true;
@@ -4601,6 +4647,15 @@ void pa_alsa_profile_set_probe(
             if (p->supported)
                 pa_log_debug("Looking at profile %s", p->name);
 
+            if (p->output_mappings && pa_idxset_size(p->output_mappings) == 1 &&
+                ((!p->input_mappings) || pa_idxset_size(p->input_mappings) == 0))
+                only_one_mapping = true;
+            else if (p->input_mappings && pa_idxset_size(p->input_mappings) == 1 &&
+                     ((!p->output_mappings) || pa_idxset_size(p->output_mappings) == 0))
+                only_one_mapping = true;
+            else
+                only_one_mapping = false;
+
             /* Check if we can open all new ones */
             if (p->output_mappings && p->supported)
                 PA_IDXSET_FOREACH(m, p->output_mappings, idx) {
@@ -4612,11 +4667,17 @@ void pa_alsa_profile_set_probe(
                     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))) {
+                                                           default_fragment_size_msec)))
                         p->supported = false;
-                        if (pa_idxset_size(p->output_mappings) == 1 &&
-                            ((!p->input_mappings) || pa_idxset_size(p->input_mappings) == 0)) {
-                            pa_log_debug("Caching failure to open output:%s", m->name);
+
+                    if (m->output_pcm && m->query_hw_device && m->hw_device_index < 0) {
+                        if (mapping_query_hw_device(m, m->output_pcm) < 0)
+                            p->supported = false;
+                    }
+
+                    if (!p->supported) {
+                        if (only_one_mapping) {
+                            pa_log_debug("Caching failure to use output:%s", m->name);
                             pa_hashmap_put(broken_outputs, m, m);
                         }
                         break;
@@ -4633,11 +4694,17 @@ void pa_alsa_profile_set_probe(
                     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))) {
+                                                          default_fragment_size_msec)))
                         p->supported = false;
-                        if (pa_idxset_size(p->input_mappings) == 1 &&
-                            ((!p->output_mappings) || pa_idxset_size(p->output_mappings) == 0)) {
-                            pa_log_debug("Caching failure to open input:%s", m->name);
+
+                    if (m->input_pcm && m->query_hw_device && m->hw_device_index < 0) {
+                        if (mapping_query_hw_device(m, m->input_pcm) < 0)
+                            p->supported = false;
+                    }
+
+                    if (!p->supported) {
+                        if (only_one_mapping) {
+                            pa_log_debug("Caching failure to use input:%s", m->name);
                             pa_hashmap_put(broken_inputs, m, m);
                         }
                         break;
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 4ebf1922b..96678aea4 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -275,6 +275,18 @@ struct pa_alsa_mapping {
     bool exact_channels:1;
     bool fallback:1;
 
+    /* Should we try to figure out which hw device this mapping is using? HDMI
+     * jack detection and ELD handling requires us to know the underlying hw
+     * device. This defaults to false, because we only need this for HDMI, and
+     * it's not always possible to figure out the hw device (for example, a
+     * surround device might consist of several stereo hw devices). */
+    bool query_hw_device;
+
+    /* The "y" in "hw:x,y". This is set to -1 before the device index has been
+     * queried, or if the query failed. If query_hw_device is false, this is
+     * always -1. */
+    int hw_device_index;
+
     /* Temporarily used during probing */
     snd_pcm_t *input_pcm;
     snd_pcm_t *output_pcm;
diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf
index f412058ff..01203b3c3 100644
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -57,6 +57,10 @@
 ; 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
+; query-hw-device = no | yes                # Defaults to "no", needs to be set to "yes" for HDMI mappings. HDMI
+;                                           # jack detection and ELD handling requires us to know which hw:x,y
+;                                           # device the hdmi:x,z device corresponds to. This defaults to "no",
+;                                           # because querying the hw device doesn't work for all devices.
 ; [Profile id]
 ; input-mappings = ...                      # Lists mappings for sources on this profile, those mapping must be
 ;                                           # defined in this file too
@@ -164,6 +168,7 @@ channel-map = left,right
 paths-input = iec958-stereo-input
 paths-output = iec958-stereo-output
 priority = 5
+query-hw-device = yes
 
 [Mapping iec958-ac3-surround-40]
 device-strings = a52:%f
@@ -193,6 +198,7 @@ paths-output = hdmi-output-0
 channel-map = left,right
 priority = 4
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround]
 description = Digital Surround 5.1 (HDMI)
@@ -201,6 +207,7 @@ paths-output = hdmi-output-0
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 3
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround71]
 description = Digital Surround 7.1 (HDMI)
@@ -209,6 +216,7 @@ paths-output = hdmi-output-0
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 priority = 3
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-dts-surround]
 description = Digital Surround 5.1 (HDMI/DTS)
@@ -217,6 +225,7 @@ paths-output = hdmi-output-0
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-stereo-extra1]
 description = Digital Stereo (HDMI 2)
@@ -225,6 +234,7 @@ paths-output = hdmi-output-1
 channel-map = left,right
 priority = 2
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround-extra1]
 description = Digital Surround 5.1 (HDMI 2)
@@ -233,6 +243,7 @@ paths-output = hdmi-output-1
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround71-extra1]
 description = Digital Surround 7.1 (HDMI 2)
@@ -241,6 +252,7 @@ paths-output = hdmi-output-1
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-dts-surround-extra1]
 description = Digital Surround 5.1 (HDMI 2/DTS)
@@ -249,6 +261,7 @@ paths-output = hdmi-output-1
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-stereo-extra2]
 description = Digital Stereo (HDMI 3)
@@ -257,6 +270,7 @@ paths-output = hdmi-output-2
 channel-map = left,right
 priority = 2
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround-extra2]
 description = Digital Surround 5.1 (HDMI 3)
@@ -265,6 +279,7 @@ paths-output = hdmi-output-2
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround71-extra2]
 description = Digital Surround 7.1 (HDMI 3)
@@ -273,6 +288,7 @@ paths-output = hdmi-output-2
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-dts-surround-extra2]
 description = Digital Surround 5.1 (HDMI 3/DTS)
@@ -281,6 +297,7 @@ paths-output = hdmi-output-2
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-stereo-extra3]
 description = Digital Stereo (HDMI 4)
@@ -289,6 +306,7 @@ paths-output = hdmi-output-3
 channel-map = left,right
 priority = 2
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround-extra3]
 description = Digital Surround 5.1 (HDMI 4)
@@ -297,6 +315,7 @@ paths-output = hdmi-output-3
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround71-extra3]
 description = Digital Surround 7.1 (HDMI 4)
@@ -305,6 +324,7 @@ paths-output = hdmi-output-3
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-dts-surround-extra3]
 description = Digital Surround 5.1 (HDMI 4/DTS)
@@ -313,6 +333,7 @@ paths-output = hdmi-output-3
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-stereo-extra4]
 description = Digital Stereo (HDMI 5)
@@ -321,6 +342,7 @@ paths-output = hdmi-output-4
 channel-map = left,right
 priority = 2
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround-extra4]
 description = Digital Surround 5.1 (HDMI 5)
@@ -329,6 +351,7 @@ paths-output = hdmi-output-4
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround71-extra4]
 description = Digital Surround 7.1 (HDMI 5)
@@ -337,6 +360,7 @@ paths-output = hdmi-output-4
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-dts-surround-extra4]
 description = Digital Surround 5.1 (HDMI 5/DTS)
@@ -345,6 +369,7 @@ paths-output = hdmi-output-4
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-stereo-extra5]
 description = Digital Stereo (HDMI 6)
@@ -353,6 +378,7 @@ paths-output = hdmi-output-5
 channel-map = left,right
 priority = 2
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround-extra5]
 description = Digital Surround 5.1 (HDMI 6)
@@ -361,6 +387,7 @@ paths-output = hdmi-output-5
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround71-extra5]
 description = Digital Surround 7.1 (HDMI 6)
@@ -369,6 +396,7 @@ paths-output = hdmi-output-5
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-dts-surround-extra5]
 description = Digital Surround 5.1 (HDMI 6/DTS)
@@ -377,6 +405,7 @@ paths-output = hdmi-output-5
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-stereo-extra6]
 description = Digital Stereo (HDMI 7)
@@ -385,6 +414,7 @@ paths-output = hdmi-output-6
 channel-map = left,right
 priority = 2
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround-extra6]
 description = Digital Surround 5.1 (HDMI 7)
@@ -393,6 +423,7 @@ paths-output = hdmi-output-6
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround71-extra6]
 description = Digital Surround 7.1 (HDMI 7)
@@ -401,6 +432,7 @@ paths-output = hdmi-output-6
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-dts-surround-extra6]
 description = Digital Surround 5.1 (HDMI 7/DTS)
@@ -409,6 +441,7 @@ paths-output = hdmi-output-6
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-stereo-extra7]
 description = Digital Stereo (HDMI 8)
@@ -417,6 +450,7 @@ paths-output = hdmi-output-7
 channel-map = left,right
 priority = 2
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround-extra7]
 description = Digital Surround 5.1 (HDMI 8)
@@ -425,6 +459,7 @@ paths-output = hdmi-output-7
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-surround71-extra7]
 description = Digital Surround 7.1 (HDMI 8)
@@ -433,6 +468,7 @@ paths-output = hdmi-output-7
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping hdmi-dts-surround-extra7]
 description = Digital Surround 5.1 (HDMI 8/DTS)
@@ -441,6 +477,7 @@ paths-output = hdmi-output-7
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 priority = 1
 direction = output
+query-hw-device = yes
 
 [Mapping multichannel-output]
 device-strings = hw:%f
-- 
2.11.0



More information about the pulseaudio-discuss mailing list