[pulseaudio-discuss] [PATCH RFC] alsa-mixer: add query_hw_device option to mappings

Tanu Kaskinen tanuk at iki.fi
Tue May 23 19:19:22 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 HDMI path
configuration files (the index is used for setting the ELD device and
the jack mixer element name). The Intel HDMI LPE driver, however, uses
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
subsequent patches.

BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=100488
---

This is just an RFC at this point. Does the approach seem ok? One issue
with this patch is that if skip-probe is used in some custom profile-set
configuration, then the query is never done, because it happens during
probing. I think that's not a serious problem, because custom
configuration for well-known hardware that doesn't need probing should
be able to continue using hardcoded values.

Here's how the path configuration for HDMI looks currently:

[General]
description = HDMI / DisplayPort 8
priority = 52
eld-device = 13

[Properties]
device.icon_name = video-display

[Jack HDMI/DP,pcm=13]
required = ignore

Regarding the ELD device, my current plan is to allow setting the
"eld-device" option value to "auto", which will use the queried device
index of the mapping.

For the jack element name, I suggest this:

[Jack HDMI/DP]
append-pcm-to-name = yes

As can be expected, that option will append ",pcm=X" to the jack name,
with X replaced by the device index.

Any comments would be welcome.

 src/modules/alsa/alsa-mixer.c                    | 86 +++++++++++++++++++++---
 src/modules/alsa/alsa-mixer.h                    | 12 ++++
 src/modules/alsa/mixer/profile-sets/default.conf | 37 ++++++++++
 3 files changed, 127 insertions(+), 8 deletions(-)

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index f59cad394..6bf8f27fe 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;
@@ -4052,6 +4078,8 @@ static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) {
             m->priority += 30;
     }
 
+    pa_log_debug("XXX: Mapping %s: query_hw_device = %s", m->name, m->query_hw_device ? "true" : "false");
+
     return 0;
 }
 
@@ -4357,6 +4385,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 +4560,25 @@ 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);
+    pa_log_debug("XXX: Mapping %s: hw_device_index = %u", mapping->name, (unsigned) mapping->hw_device_index);
+
+    return 0;
+}
+
 void pa_alsa_profile_set_probe(
         pa_alsa_profile_set *ps,
         const char *dev_id,
@@ -4574,6 +4622,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 +4650,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 +4670,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 +4697,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