We have met a couple of machines which have two Kcontrols with the exact same names and with the different index numbers, for example: (1 physical headphone jack + 1 physical headset jack on front panel) - Simple mixer control 'Headphone',0 (volume and switch) - Simple mixer control 'Headphone',1 (volume and switch) (1 physical mic jack + 1 physical headset jack on front panel) - iface=CARD,name='Mic Jack' index 0 - iface=CARD,name='Mic Jack' index 1 To let pulseaudio treat them as different Jacks or differnt Elements, we introduce index to the pa_alsa_jack and pa_alsa_element. When probing jacks or elements, we add index as a parameter. Signed-off-by: Hui Wang <hui.wang@xxxxxxxxxxxxx> --- src/modules/alsa/alsa-mixer.c | 59 ++++++++++++++----- src/modules/alsa/alsa-mixer.h | 2 + src/modules/alsa/alsa-ucm.c | 2 +- src/modules/alsa/alsa-util.c | 4 +- src/modules/alsa/alsa-util.h | 2 +- .../mixer/paths/analog-output.conf.common | 5 ++ src/modules/alsa/module-alsa-card.c | 4 +- 7 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 91dfc66ee..e32ec5cd7 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -718,11 +718,11 @@ static pa_volume_t from_alsa_volume(long v, long min, long max) { return (pa_volume_t) round(((double) (v - min) * PA_VOLUME_NORM) / (double) (max - min)); } -#define SELEM_INIT(sid, name) \ +#define SELEM_INIT(sid, name, index) \ do { \ snd_mixer_selem_id_alloca(&(sid)); \ snd_mixer_selem_id_set_name((sid), (name)); \ - snd_mixer_selem_id_set_index((sid), 0); \ + snd_mixer_selem_id_set_index((sid), index); \ } while(false) static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v) { @@ -737,7 +737,7 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann pa_assert(cm); pa_assert(v); - SELEM_INIT(sid, e->alsa_name); + SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -902,7 +902,7 @@ static int element_get_switch(pa_alsa_element *e, snd_mixer_t *m, bool *b) { pa_assert(e); pa_assert(b); - SELEM_INIT(sid, e->alsa_name); + SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -1066,7 +1066,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann pa_assert(v); pa_assert(pa_cvolume_compatible_with_channel_map(v, cm)); - SELEM_INIT(sid, e->alsa_name); + SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -1256,7 +1256,7 @@ static int element_set_switch(pa_alsa_element *e, snd_mixer_t *m, bool b) { pa_assert(m); pa_assert(e); - SELEM_INIT(sid, e->alsa_name); + SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -1307,7 +1307,7 @@ static int element_set_constant_volume(pa_alsa_element *e, snd_mixer_t *m) { pa_assert(m); pa_assert(e); - SELEM_INIT(sid, e->alsa_name); + SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -1734,7 +1734,7 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) { pa_assert(e); pa_assert(e->path); - SELEM_INIT(sid, e->alsa_name); + SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { @@ -1837,7 +1837,7 @@ static int jack_probe(pa_alsa_jack *j, pa_alsa_mapping *mapping, snd_mixer_t *m) j->append_pcm_to_name = false; } - has_control = pa_alsa_mixer_find(m, j->alsa_name, 0) != NULL; + has_control = pa_alsa_mixer_find(m, j->alsa_name, 0, j->index) != NULL; pa_alsa_jack_set_has_control(j, has_control); if (j->has_control) { @@ -1959,6 +1959,36 @@ finish: return o; } +static int element_parse_index(pa_config_parser_state *state) { + pa_alsa_path *p; + pa_alsa_element *e; + pa_alsa_jack *j; + uint32_t ind; + + pa_assert(state); + + p = state->userdata; + + e = element_get(p, state->section, true); + j = jack_get(p, state->section); + if (!e && !j) + goto error; + + if (pa_atou(state->rvalue, &ind) < 0) + goto error; + + if (e) + e->index = ind; + else + j->index = ind; + + return 0; + +error: + pa_log("[%s:%u] Required makes no sense in '%s'", state->filename, state->lineno, state->section); + return -1; +} + static int element_parse_switch(pa_config_parser_state *state) { pa_alsa_path *p; pa_alsa_element *e; @@ -2399,7 +2429,7 @@ static int element_set_option(pa_alsa_element *e, snd_mixer_t *m, int alsa_idx) pa_assert(e); pa_assert(m); - SELEM_INIT(sid, e->alsa_name); + SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -2606,6 +2636,7 @@ pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa { "append-pcm-to-name", jack_parse_append_pcm_to_name, NULL, NULL }, /* [Element ...] */ + { "index", element_parse_index, NULL, NULL }, { "switch", element_parse_switch, NULL, NULL }, { "volume", element_parse_volume, NULL, NULL }, { "enumeration", element_parse_enumeration, NULL, NULL }, @@ -3014,7 +3045,7 @@ static void element_set_callback(pa_alsa_element *e, snd_mixer_t *m, snd_mixer_e pa_assert(m); pa_assert(cb); - SELEM_INIT(sid, e->alsa_name); + SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return; @@ -3294,7 +3325,7 @@ static bool element_is_subset(pa_alsa_element *a, pa_alsa_element *b, snd_mixer_ snd_mixer_selem_id_t *sid; snd_mixer_elem_t *me; - SELEM_INIT(sid, a->alsa_name); + SELEM_INIT(sid, a->alsa_name, a->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", a->alsa_name); return false; @@ -3402,7 +3433,7 @@ static void path_set_condense(pa_alsa_path_set *ps, snd_mixer_t *m) { continue; PA_LLIST_FOREACH(jb, p2->jacks) { - if (jb->has_control && pa_streq(jb->alsa_name, ja->alsa_name) && + if (jb->has_control && pa_streq(jb->alsa_name, ja->alsa_name) && (jb->index == ja->index) && (ja->state_plugged == jb->state_plugged) && (ja->state_unplugged == jb->state_unplugged)) { exists = true; @@ -3424,7 +3455,7 @@ static void path_set_condense(pa_alsa_path_set *ps, snd_mixer_t *m) { break; PA_LLIST_FOREACH(eb, p2->elements) { - if (pa_streq(ea->alsa_name, eb->alsa_name)) { + if (pa_streq(ea->alsa_name, eb->alsa_name) && (ea->index == eb->index)) { found_matching_element = true; is_subset = element_is_subset(ea, eb, m); break; diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h index 3ea4d7329..5a8ed03b6 100644 --- a/src/modules/alsa/alsa-mixer.h +++ b/src/modules/alsa/alsa-mixer.h @@ -124,6 +124,7 @@ struct pa_alsa_element { PA_LLIST_FIELDS(pa_alsa_element); char *alsa_name; + uint32_t index; pa_alsa_direction_t direction; pa_alsa_switch_use_t switch_use; @@ -160,6 +161,7 @@ struct pa_alsa_jack { char *name; /* E g "Headphone" */ char *alsa_name; /* E g "Headphone Jack" */ + uint32_t index; bool has_control; /* is the jack itself present? */ bool plugged_in; /* is this jack currently plugged in? */ snd_mixer_elem_t *melem; /* Jack detection handle */ diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index d2d3ee1eb..bde6e4d0f 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1515,7 +1515,7 @@ static void ucm_mapping_jack_probe(pa_alsa_mapping *m) { PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { bool has_control; - has_control = pa_alsa_mixer_find(mixer_handle, dev->jack->alsa_name, 0) != NULL; + has_control = pa_alsa_mixer_find(mixer_handle, dev->jack->alsa_name, 0, dev->jack->index) != NULL; pa_alsa_jack_set_has_control(dev->jack, has_control); pa_log_info("UCM jack %s has_control=%d", dev->jack->name, dev->jack->has_control); } diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index c5f6188e6..242645c59 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1595,7 +1595,7 @@ bool pa_alsa_may_tsched(bool want) { #define SND_MIXER_ELEM_PULSEAUDIO (SND_MIXER_ELEM_LAST + 10) -snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, unsigned int device) { +snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, unsigned int device, unsigned int index) { snd_mixer_elem_t *elem; for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) { @@ -1607,6 +1607,8 @@ snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, unsig continue; if (snd_hctl_elem_get_device(helem) != device) continue; + if (snd_hctl_elem_get_index(helem) != index) + continue; return elem; } return NULL; diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 6b27339ec..58fc211c0 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -141,7 +141,7 @@ const char* pa_alsa_strerror(int errnum); bool pa_alsa_may_tsched(bool want); -snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, unsigned int device); +snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, unsigned int device, unsigned int index); snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device); diff --git a/src/modules/alsa/mixer/paths/analog-output.conf.common b/src/modules/alsa/mixer/paths/analog-output.conf.common index e52830d99..8730ab5a4 100644 --- a/src/modules/alsa/mixer/paths/analog-output.conf.common +++ b/src/modules/alsa/mixer/paths/analog-output.conf.common @@ -86,6 +86,9 @@ ; required-absent = ignore | enumeration | any # In this element, this option must not exist or the path will be invalid ; ; [Element ...] # For each element that we shall control +; index = <the index number> # If the index number of this Element is not 0, we need to set the correct index number here, +; # if it is 0, don't need to set it here +; ; required = ignore | switch | volume | enumeration | any # If set, require this element to be of this kind and available, ; # otherwise don't consider this path valid for the card ; required-any = ignore | switch | volume | enumeration | any # If set, at least one of the elements or jacks with required-any in this @@ -120,6 +123,8 @@ ; # channels in a mask ; [Jack ...] # For each jack that we will use for jack detection ; # The name 'Jack Foo' must match ALSA's 'Foo Jack' control. +; index = <the index number> # If the index number of this Jack is not 0, we need to set the correct index number here, +; # if it is 0, don't need to set it here ; required = ignore | any # If not set to ignore, make the path invalid if this jack control is not present. ; required-absent = ignore | any # If not set to ignore, make the path invalid if this jack control is present. ; required-any = ignore | any # If not set to ignore, make the path invalid if no jack controls and no elements with diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index 473248767..656b58278 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -583,7 +583,7 @@ static void init_eld_ctls(struct userdata *u) { if (device < 0) continue; - melem = pa_alsa_mixer_find(u->mixer_handle, "ELD", device); + melem = pa_alsa_mixer_find(u->mixer_handle, "ELD", device, 0); if (melem) { snd_mixer_elem_set_callback(melem, hdmi_eld_changed); snd_mixer_elem_set_callback_private(melem, u); @@ -630,7 +630,7 @@ static void init_jacks(struct userdata *u) { u->mixer_handle = pa_alsa_open_mixer(u->alsa_card_index, NULL); if (u->mixer_handle && pa_alsa_fdlist_set_handle(u->mixer_fdl, u->mixer_handle, NULL, u->core->mainloop) >= 0) { PA_HASHMAP_FOREACH(jack, u->jacks, state) { - jack->melem = pa_alsa_mixer_find(u->mixer_handle, jack->alsa_name, 0); + jack->melem = pa_alsa_mixer_find(u->mixer_handle, jack->alsa_name, 0, jack->index); if (!jack->melem) { pa_log_warn("Jack '%s' seems to have disappeared.", jack->alsa_name); pa_alsa_jack_set_has_control(jack, false); -- 2.17.1 _______________________________________________ pulseaudio-discuss mailing list pulseaudio-discuss@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss