diff options
Diffstat (limited to 'src/modules/alsa/alsa-mixer.c')
-rw-r--r-- | src/modules/alsa/alsa-mixer.c | 109 |
1 files changed, 60 insertions, 49 deletions
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 20381fb50..7e316e281 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -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; } @@ -3113,16 +3121,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); @@ -3231,7 +3240,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) { @@ -3251,7 +3260,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, @@ -3311,7 +3320,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; } @@ -3606,7 +3615,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; } @@ -3637,7 +3646,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; @@ -3714,7 +3723,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; @@ -4404,7 +4414,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; |