alsa-mixer: Handle the index for ALSA mixer jack identifiers
authorKai-Heng Feng <kai.heng.feng@canonical.com>
Tue, 22 Dec 2020 05:39:05 +0000 (13:39 +0800)
committerPulseAudio Marge Bot <pulseaudio-maintainers@lists.freedesktop.org>
Wed, 30 Dec 2020 15:49:09 +0000 (15:49 +0000)
Some systems have two jacks with same name but different index, we need
to take index into consideration to use both jacks.

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/272>

src/modules/alsa/alsa-mixer.c
src/modules/alsa/alsa-mixer.h
src/modules/alsa/alsa-ucm.c
src/modules/alsa/alsa-util.c
src/modules/alsa/alsa-util.h
src/modules/alsa/module-alsa-card.c

index 8cd17cc..58c33bf 100644 (file)
@@ -113,7 +113,7 @@ struct description2_map {
     pa_device_port_type_t type;
 };
 
-static char *alsa_id_str(char *dst, size_t dst_len, pa_alsa_mixer_id *id) {
+char *pa_alsa_mixer_id_to_string(char *dst, size_t dst_len, pa_alsa_mixer_id *id) {
     if (id->index > 0) {
         snprintf(dst, dst_len, "'%s',%d", id->name, id->index);
     } else {
@@ -153,7 +153,7 @@ static int alsa_id_decode(const char *src, char *name, int *index) {
     return 0;
 }
 
-pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name, const char *name) {
+pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name, const char *name, int index) {
     pa_alsa_jack *jack;
 
     pa_assert(name);
@@ -162,7 +162,8 @@ pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name
     jack->path = path;
     jack->mixer_device_name = pa_xstrdup(mixer_device_name);
     jack->name = pa_xstrdup(name);
-    jack->alsa_name = pa_sprintf_malloc("%s Jack", name);
+    jack->alsa_id.name = pa_sprintf_malloc("%s Jack", name);
+    jack->alsa_id.index = index;
     jack->state_unplugged = PA_AVAILABLE_NO;
     jack->state_plugged = PA_AVAILABLE_YES;
     jack->ucm_devices = pa_dynarray_new(NULL);
@@ -177,7 +178,7 @@ void pa_alsa_jack_free(pa_alsa_jack *jack) {
     pa_dynarray_free(jack->ucm_hw_mute_devices);
     pa_dynarray_free(jack->ucm_devices);
 
-    pa_xfree(jack->alsa_name);
+    pa_xfree(jack->alsa_id.name);
     pa_xfree(jack->name);
     pa_xfree(jack->mixer_device_name);
     pa_xfree(jack);
@@ -835,7 +836,7 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
 
     SELEM_INIT(sid, &e->alsa_id);
     if (!(me = snd_mixer_find_selem(m, sid))) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Element %s seems to have disappeared.", buf);
         return -1;
     }
@@ -861,14 +862,14 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
                             if (value < e->db_fix->min_step) {
                                 value = e->db_fix->min_step;
                                 snd_mixer_selem_set_playback_volume(me, c, value);
-                                alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+                                pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
                                 pa_log_debug("Playback volume for element %s channel %i was below the dB fix limit. "
                                              "Volume reset to %0.2f dB.", buf, c,
                                              e->db_fix->db_values[value - e->db_fix->min_step] / 100.0);
                             } else if (value > e->db_fix->max_step) {
                                 value = e->db_fix->max_step;
                                 snd_mixer_selem_set_playback_volume(me, c, value);
-                                alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+                                pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
                                 pa_log_debug("Playback volume for element %s channel %i was over the dB fix limit. "
                                              "Volume reset to %0.2f dB.", buf, c,
                                              e->db_fix->db_values[value - e->db_fix->min_step] / 100.0);
@@ -891,14 +892,14 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
                             if (value < e->db_fix->min_step) {
                                 value = e->db_fix->min_step;
                                 snd_mixer_selem_set_capture_volume(me, c, value);
-                                alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+                                pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
                                 pa_log_debug("Capture volume for element %s channel %i was below the dB fix limit. "
                                              "Volume reset to %0.2f dB.", buf, c,
                                              e->db_fix->db_values[value - e->db_fix->min_step] / 100.0);
                             } else if (value > e->db_fix->max_step) {
                                 value = e->db_fix->max_step;
                                 snd_mixer_selem_set_capture_volume(me, c, value);
-                                alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+                                pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
                                 pa_log_debug("Capture volume for element %s channel %i was over the dB fix limit. "
                                              "Volume reset to %0.2f dB.", buf, c,
                                              e->db_fix->db_values[value - e->db_fix->min_step] / 100.0);
@@ -1006,7 +1007,7 @@ static int element_get_switch(pa_alsa_element *e, snd_mixer_t *m, bool *b) {
 
     SELEM_INIT(sid, &e->alsa_id);
     if (!(me = snd_mixer_find_selem(m, sid))) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Element %s seems to have disappeared.", buf);
         return -1;
     }
@@ -1172,7 +1173,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
 
     SELEM_INIT(sid, &e->alsa_id);
     if (!(me = snd_mixer_find_selem(m, sid))) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Element %s seems to have disappeared.", buf);
         return -1;
     }
@@ -1364,7 +1365,7 @@ static int element_set_switch(pa_alsa_element *e, snd_mixer_t *m, bool b) {
 
     SELEM_INIT(sid, &e->alsa_id);
     if (!(me = snd_mixer_find_selem(m, sid))) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Element %s seems to have disappeared.", buf);
         return -1;
     }
@@ -1375,7 +1376,7 @@ static int element_set_switch(pa_alsa_element *e, snd_mixer_t *m, bool b) {
         r = snd_mixer_selem_set_capture_switch_all(me, b);
 
     if (r < 0) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Failed to set switch of %s: %s", buf, pa_alsa_strerror(errno));
     }
 
@@ -1419,7 +1420,7 @@ static int element_set_constant_volume(pa_alsa_element *e, snd_mixer_t *m) {
 
     SELEM_INIT(sid, &e->alsa_id);
     if (!(me = snd_mixer_find_selem(m, sid))) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Element %s seems to have disappeared.", buf);
         return -1;
     }
@@ -1464,7 +1465,7 @@ static int element_set_constant_volume(pa_alsa_element *e, snd_mixer_t *m) {
     }
 
     if (r < 0) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Failed to set volume of %s: %s", buf, pa_alsa_strerror(errno));
     }
 
@@ -1670,19 +1671,19 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) {
         r = snd_mixer_selem_get_capture_volume_range(me, &e->min_volume, &e->max_volume);
 
     if (r < 0) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Failed to get volume range of %s: %s", buf, pa_alsa_strerror(r));
         return false;
     }
 
     if (e->min_volume >= e->max_volume) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Your kernel driver is broken for element %s: it reports a volume range from %li to %li which makes no sense.",
                     buf, e->min_volume, e->max_volume);
         return false;
     }
     if (e->volume_use == PA_ALSA_VOLUME_CONSTANT && (e->min_volume > e->constant_volume || e->max_volume < e->constant_volume)) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Constant volume %li configured for element %s, but the available range is from %li to %li.",
                     e->constant_volume, buf, e->min_volume, e->max_volume);
         return false;
@@ -1690,7 +1691,7 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) {
 
 
     if (e->db_fix && ((e->min_volume > e->db_fix->min_step) || (e->max_volume < e->db_fix->max_step))) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("The step range of the decibel fix for element %s (%li-%li) doesn't fit to the "
                     "real hardware range (%li-%li). Disabling the decibel fix.", buf,
                     e->db_fix->min_step, e->db_fix->max_step, e->min_volume, e->max_volume);
@@ -1717,19 +1718,19 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) {
         long max_dB_checked = 0;
 
         if (element_ask_vol_dB(me, e->direction, e->min_volume, &min_dB_checked) < 0) {
-            alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+            pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
             pa_log_warn("Failed to query the dB value for %s at volume level %li", buf, e->min_volume);
             return false;
         }
 
         if (element_ask_vol_dB(me, e->direction, e->max_volume, &max_dB_checked) < 0) {
-            alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+            pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
             pa_log_warn("Failed to query the dB value for %s at volume level %li", buf, e->max_volume);
             return false;
         }
 
         if (min_dB != min_dB_checked || max_dB != max_dB_checked) {
-            alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+            pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
             pa_log_warn("Your kernel driver is broken: the reported dB range for %s (from %0.2f dB to %0.2f dB) "
                         "doesn't match the dB values at minimum and maximum volume levels: %0.2f dB at level %li, "
                         "%0.2f dB at level %li.", buf, min_dB / 100.0, max_dB / 100.0,
@@ -1752,7 +1753,7 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) {
 
     if (e->volume_limit >= 0) {
         if (e->volume_limit <= e->min_volume || e->volume_limit > e->max_volume) {
-            alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+            pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
             pa_log_warn("Volume limit for element %s of path %s is invalid: %li isn't within the valid range "
                         "%li-%li. The volume limit is ignored.",
                         buf, e->path->name, e->volume_limit, e->min_volume + 1, e->max_volume);
@@ -1764,7 +1765,7 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) {
                     e->db_fix->max_step = e->max_volume;
                     e->max_dB = ((double) e->db_fix->db_values[e->db_fix->max_step - e->db_fix->min_step]) / 100.0;
                 } else if (element_ask_vol_dB(me, e->direction, e->max_volume, &max_dB) < 0) {
-                    alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+                    pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
                     pa_log_warn("Failed to get dB value of %s: %s", buf, pa_alsa_strerror(r));
                     e->has_dB = false;
                 } else
@@ -1809,7 +1810,7 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) {
     }
 
     if (e->n_channels <= 0) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Volume element %s with no channels?", buf);
         return false;
     } else if (e->n_channels > POSITION_MASK_CHANNELS) {
@@ -1824,7 +1825,7 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) {
          * Since the array size is fixed at POSITION_MASK_CHANNELS, we obviously
          * don't support elements with more than POSITION_MASK_CHANNELS
          * channels... */
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Volume element %s has %u channels. That's too much! I can't handle that!", buf, e->n_channels);
         return false;
     }
@@ -1973,12 +1974,12 @@ static int jack_probe(pa_alsa_jack *j, pa_alsa_mapping *mapping, snd_mixer_t *m)
         }
 
         new_name = pa_sprintf_malloc("%s,pcm=%i Jack", j->name, mapping->hw_device_index);
-        pa_xfree(j->alsa_name);
-        j->alsa_name = new_name;
+        pa_xfree(j->alsa_id.name);
+        j->alsa_id.name = new_name;
         j->append_pcm_to_name = false;
     }
 
-    has_control = pa_alsa_mixer_find_card(m, j->alsa_name, 0) != NULL;
+    has_control = pa_alsa_mixer_find_card(m, &j->alsa_id, 0) != NULL;
     pa_alsa_jack_set_has_control(j, has_control);
 
     if (j->has_control) {
@@ -2041,19 +2042,26 @@ finish:
 
 static pa_alsa_jack* jack_get(pa_alsa_path *p, const char *section) {
     pa_alsa_jack *j;
+    char *name;
+    int index;
 
     if (!pa_startswith(section, "Jack "))
         return NULL;
     section += 5;
 
-    if (p->last_jack && pa_streq(p->last_jack->name, section))
+    name = alloca(strlen(section) + 1);
+    if (alsa_id_decode(section, name, &index))
+        return NULL;
+
+    if (p->last_jack && pa_streq(p->last_jack->name, name) &&
+        p->last_jack->alsa_id.index == index)
         return p->last_jack;
 
     PA_LLIST_FOREACH(j, p->jacks)
-        if (pa_streq(j->name, section))
+        if (pa_streq(j->name, name) && j->alsa_id.index == index)
             goto finish;
 
-    j = pa_alsa_jack_new(p, NULL, section);
+    j = pa_alsa_jack_new(p, NULL, name, index);
     PA_LLIST_INSERT_AFTER(pa_alsa_jack, p->jacks, p->last_jack, j);
 
 finish:
@@ -2645,7 +2653,7 @@ static int element_set_option(pa_alsa_element *e, snd_mixer_t *m, int alsa_idx)
 
     SELEM_INIT(sid, &e->alsa_id);
     if (!(me = snd_mixer_find_selem(m, sid))) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Element %s seems to have disappeared.", buf);
         return -1;
     }
@@ -2658,7 +2666,7 @@ static int element_set_option(pa_alsa_element *e, snd_mixer_t *m, int alsa_idx)
             r = snd_mixer_selem_set_capture_switch_all(me, alsa_idx);
 
         if (r < 0) {
-            alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+            pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
             pa_log_warn("Failed to set switch of %s: %s", buf, pa_alsa_strerror(errno));
         }
 
@@ -2666,7 +2674,7 @@ static int element_set_option(pa_alsa_element *e, snd_mixer_t *m, int alsa_idx)
         pa_assert(e->enumeration_use == PA_ALSA_ENUMERATION_SELECT);
 
         if ((r = snd_mixer_selem_set_enum_item(me, 0, alsa_idx)) < 0) {
-            alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+            pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
             pa_log_warn("Failed to set enumeration of %s: %s", buf, pa_alsa_strerror(errno));
         }
     }
@@ -2723,7 +2731,7 @@ static int option_verify(pa_alsa_option *o) {
 
     if (o->element->enumeration_use != PA_ALSA_ENUMERATION_SELECT &&
         o->element->switch_use != PA_ALSA_SWITCH_SELECT) {
-        alsa_id_str(buf, sizeof(buf), &o->element->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &o->element->alsa_id);
         pa_log("Element %s of option %s not set for select.", buf, o->name);
         return -1;
     }
@@ -2731,7 +2739,7 @@ static int option_verify(pa_alsa_option *o) {
     if (o->element->switch_use == PA_ALSA_SWITCH_SELECT &&
         !pa_streq(o->alsa_name, "on") &&
         !pa_streq(o->alsa_name, "off")) {
-        alsa_id_str(buf, sizeof(buf), &o->element->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &o->element->alsa_id);
         pa_log("Switch %s options need be named off or on ", buf);
         return -1;
     }
@@ -2757,13 +2765,13 @@ static int element_verify(pa_alsa_element *e) {
         (e->required_any != PA_ALSA_REQUIRED_IGNORE && e->required_any == e->required_absent) ||
         (e->required_absent == PA_ALSA_REQUIRED_ANY && e->required_any != PA_ALSA_REQUIRED_IGNORE) ||
         (e->required_absent == PA_ALSA_REQUIRED_ANY && e->required != PA_ALSA_REQUIRED_IGNORE)) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log("Element %s cannot be required and absent at the same time.", buf);
         return -1;
     }
 
     if (e->switch_use == PA_ALSA_SWITCH_SELECT && e->enumeration_use == PA_ALSA_ENUMERATION_SELECT) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log("Element %s cannot set select for both switch and enumeration.", buf);
         return -1;
     }
@@ -3168,16 +3176,17 @@ int pa_alsa_path_probe(pa_alsa_path *p, pa_alsa_mapping *mapping, snd_mixer_t *m
     pa_log_debug("Probing path '%s'", p->name);
 
     PA_LLIST_FOREACH(j, p->jacks) {
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &j->alsa_id);
         if (jack_probe(j, mapping, m) < 0) {
             p->supported = false;
-            pa_log_debug("Probe of jack '%s' failed.", j->alsa_name);
+            pa_log_debug("Probe of jack %s failed.", buf);
             return -1;
         }
-        pa_log_debug("Probe of jack '%s' succeeded (%s)", j->alsa_name, j->has_control ? "found!" : "not found");
+        pa_log_debug("Probe of jack %s succeeded (%s)", buf, j->has_control ? "found!" : "not found");
     }
 
     PA_LLIST_FOREACH(e, p->elements) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         if (element_probe(e, m) < 0) {
             p->supported = false;
             pa_log_debug("Probe of element %s failed.", buf);
@@ -3286,7 +3295,7 @@ void pa_alsa_setting_dump(pa_alsa_setting *s) {
 void pa_alsa_jack_dump(pa_alsa_jack *j) {
     pa_assert(j);
 
-    pa_log_debug("Jack %s, alsa_name='%s', detection %s", j->name, j->alsa_name, j->has_control ? "possible" : "unavailable");
+    pa_log_debug("Jack %s, alsa_name='%s', index='%d', detection %s", j->name, j->alsa_id.name, j->alsa_id.index, j->has_control ? "possible" : "unavailable");
 }
 
 void pa_alsa_option_dump(pa_alsa_option *o) {
@@ -3306,7 +3315,7 @@ void pa_alsa_element_dump(pa_alsa_element *e) {
     pa_alsa_option *o;
     pa_assert(e);
 
-    alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+    pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
     pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, volume_limit=%li, enumeration=%i, required=%i, required_any=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%02x",
                  buf,
                  e->direction,
@@ -3366,7 +3375,7 @@ static void element_set_callback(pa_alsa_element *e, snd_mixer_t *m, snd_mixer_e
 
     SELEM_INIT(sid, &e->alsa_id);
     if (!(me = snd_mixer_find_selem(m, sid))) {
-        alsa_id_str(buf, sizeof(buf), &e->alsa_id);
+        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &e->alsa_id);
         pa_log_warn("Element %s seems to have disappeared.", buf);
         return;
     }
@@ -3661,7 +3670,7 @@ static bool element_is_subset(pa_alsa_element *a, pa_alsa_element *b, snd_mixer_
 
                     SELEM_INIT(sid, &a->alsa_id);
                     if (!(me = snd_mixer_find_selem(m, sid))) {
-                        alsa_id_str(buf, sizeof(buf), &a->alsa_id);
+                        pa_alsa_mixer_id_to_string(buf, sizeof(buf), &a->alsa_id);
                         pa_log_warn("Element %s seems to have disappeared.", buf);
                         return false;
                     }
@@ -3692,7 +3701,7 @@ static bool element_is_subset(pa_alsa_element *a, pa_alsa_element *b, snd_mixer_
                 return false;
             for (s = 0; s <= SND_MIXER_SCHN_LAST; s++)
                 if (a->masks[s][a->n_channels-1] != b->masks[s][b->n_channels-1]) {
-                    alsa_id_str(buf, sizeof(buf), &a->alsa_id);
+                    pa_alsa_mixer_id_to_string(buf, sizeof(buf), &a->alsa_id);
                     pa_log_debug("Element %s is not a subset - mask a: 0x%" PRIx64 ", mask b: 0x%" PRIx64 ", at channel %d",
                                  buf, a->masks[s][a->n_channels-1], b->masks[s][b->n_channels-1], s);
                     return false;
@@ -3769,7 +3778,8 @@ 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(ja->alsa_id.name, jb->alsa_id.name) &&
+                       (ja->alsa_id.index == jb->alsa_id.index) &&
                        (ja->state_plugged == jb->state_plugged) &&
                        (ja->state_unplugged == jb->state_unplugged)) {
                         exists = true;
@@ -4459,7 +4469,8 @@ static void profile_set_set_availability_groups(pa_alsa_profile_set *ps) {
                 PA_LLIST_FOREACH(j2, p2->jacks) {
                     if (!j2->has_control || j2->state_plugged == PA_AVAILABLE_NO)
                         continue;
-                    if (pa_streq(j->alsa_name, j2->alsa_name)) {
+                    if (pa_streq(j->alsa_id.name, j2->alsa_id.name) &&
+                        j->alsa_id.index == j2->alsa_id.index) {
                         j->state_plugged = PA_AVAILABLE_UNKNOWN;
                         j2->state_plugged = PA_AVAILABLE_UNKNOWN;
                         found = p2->availability_group;
index 8151955..db83102 100644 (file)
@@ -115,6 +115,8 @@ struct pa_alsa_mixer_id {
     int index;
 };
 
+char *pa_alsa_mixer_id_to_string(char *dst, size_t dst_len, pa_alsa_mixer_id *id);
+
 /* An option belongs to an element and refers to one enumeration item
  * of the element is an enumeration item, or a switch status if the
  * element is a switch item. */
@@ -179,8 +181,8 @@ struct pa_alsa_jack {
     snd_mixer_t *mixer_handle;
     char *mixer_device_name;
 
+    struct pa_alsa_mixer_id alsa_id;
     char *name; /* E g "Headphone" */
-    char *alsa_name; /* E g "Headphone Jack" */
     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 */
@@ -196,7 +198,7 @@ struct pa_alsa_jack {
     bool append_pcm_to_name;
 };
 
-pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name, const char *name);
+pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name, const char *name, int index);
 void pa_alsa_jack_free(pa_alsa_jack *jack);
 void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control);
 void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in);
index 18925b7..d9cea61 100644 (file)
@@ -1719,7 +1719,7 @@ static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *d
         pa_log("[%s] No mixer device name for JackControl \"%s\"", device_name, jack_control);
         return NULL;
     }
-    j = pa_alsa_jack_new(NULL, mixer_device_name, name);
+    j = pa_alsa_jack_new(NULL, mixer_device_name, name, 0);
     PA_LLIST_PREPEND(pa_alsa_jack, ucm->jacks, j);
 
 finish:
@@ -1953,7 +1953,7 @@ static void ucm_mapping_jack_probe(pa_alsa_mapping *m, pa_hashmap *mixers) {
             continue;
         }
 
-        has_control = pa_alsa_mixer_find_card(mixer_handle, dev->jack->alsa_name, 0) != NULL;
+        has_control = pa_alsa_mixer_find_card(mixer_handle, &dev->jack->alsa_id, 0) != 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);
     }
index bf35b61..172a7bb 100644 (file)
@@ -1635,8 +1635,8 @@ static snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer,
     return NULL;
 }
 
-snd_mixer_elem_t *pa_alsa_mixer_find_card(snd_mixer_t *mixer, const char *name, unsigned int device) {
-    return pa_alsa_mixer_find(mixer, SND_CTL_ELEM_IFACE_CARD, name, 0, device);
+snd_mixer_elem_t *pa_alsa_mixer_find_card(snd_mixer_t *mixer, struct pa_alsa_mixer_id *alsa_id, unsigned int device) {
+    return pa_alsa_mixer_find(mixer, SND_CTL_ELEM_IFACE_CARD, alsa_id->name, alsa_id->index, device);
 }
 
 snd_mixer_elem_t *pa_alsa_mixer_find_pcm(snd_mixer_t *mixer, const char *name, unsigned int device) {
index cb8be22..2eed3ea 100644 (file)
@@ -148,7 +148,7 @@ const char* pa_alsa_strerror(int errnum);
 
 bool pa_alsa_may_tsched(bool want);
 
-snd_mixer_elem_t *pa_alsa_mixer_find_card(snd_mixer_t *mixer, const char *name, unsigned int device);
+snd_mixer_elem_t *pa_alsa_mixer_find_card(snd_mixer_t *mixer, struct pa_alsa_mixer_id *alsa_id, unsigned int device);
 snd_mixer_elem_t *pa_alsa_mixer_find_pcm(snd_mixer_t *mixer, const char *name, unsigned int device);
 
 snd_mixer_t *pa_alsa_open_mixer(pa_hashmap *mixers, int alsa_card_index, bool probe);
index f2f5038..7ff8239 100644 (file)
@@ -623,6 +623,7 @@ static void init_jacks(struct userdata *u) {
     void *state;
     pa_alsa_path* path;
     pa_alsa_jack* jack;
+    char buf[64];
 
     u->jacks = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
@@ -665,9 +666,10 @@ static void init_jacks(struct userdata *u) {
             }
         }
         pa_alsa_mixer_set_fdlist(u->mixers, jack->mixer_handle, u->core->mainloop);
-        jack->melem = pa_alsa_mixer_find_card(jack->mixer_handle, jack->alsa_name, 0);
+        jack->melem = pa_alsa_mixer_find_card(jack->mixer_handle, &jack->alsa_id, 0);
         if (!jack->melem) {
-            pa_log_warn("Jack '%s' seems to have disappeared.", jack->alsa_name);
+            pa_alsa_mixer_id_to_string(buf, sizeof(buf), &jack->alsa_id);
+            pa_log_warn("Jack %s seems to have disappeared.", buf);
             pa_alsa_jack_set_has_control(jack, false);
             continue;
         }