mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
alsa-mixer: fix the re-attach code for the mixer control element
The new helem must be tracked and old helem must be cleared
to make the code work properly. Introduce the pointer to helem
as the private value for melem and add the necessary code.
Also, add a check for the duplicate mixer elements. The duplicate
mixer element invokes the abort check in alsa-lib. Print a warning
instead and handle the exit gracefully.
Fixes: def8eb074 ("alsa-mixer: allow to re-attach the mixer control element")
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/730>
This commit is contained in:
parent
eb870fcba9
commit
d1675df0cd
2 changed files with 52 additions and 11 deletions
|
|
@ -1618,10 +1618,11 @@ static snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer,
|
|||
snd_mixer_elem_t *elem;
|
||||
|
||||
for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) {
|
||||
snd_hctl_elem_t *helem;
|
||||
snd_hctl_elem_t **_helem, *helem;
|
||||
if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_PULSEAUDIO)
|
||||
continue;
|
||||
helem = snd_mixer_elem_get_private(elem);
|
||||
_helem = snd_mixer_elem_get_private(elem);
|
||||
helem = *_helem;
|
||||
if (snd_hctl_elem_get_interface(helem) != iface)
|
||||
continue;
|
||||
if (!pa_streq(snd_hctl_elem_get_name(helem), name))
|
||||
|
|
@ -1649,16 +1650,26 @@ static int mixer_class_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_
|
|||
return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1);
|
||||
}
|
||||
|
||||
static void mixer_melem_free(snd_mixer_elem_t *elem)
|
||||
{
|
||||
snd_hctl_elem_t **_helem;
|
||||
_helem = snd_mixer_elem_get_private(elem);
|
||||
pa_xfree(_helem);
|
||||
}
|
||||
|
||||
static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask,
|
||||
snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
|
||||
{
|
||||
int err;
|
||||
const char *name = snd_hctl_elem_get_name(helem);
|
||||
snd_hctl_elem_t **_helem;
|
||||
/* NOTE: The remove event is defined as '~0U`. */
|
||||
if (mask == SND_CTL_EVENT_MASK_REMOVE) {
|
||||
/* NOTE: Unless we remove the pointer to melem from the linked-list at
|
||||
* private_data of helem, an assertion will be hit in alsa-lib since
|
||||
* the list is not empty. */
|
||||
_helem = snd_mixer_elem_get_private(melem);
|
||||
*_helem = NULL;
|
||||
snd_mixer_elem_detach(melem, helem);
|
||||
} else if (mask & SND_CTL_EVENT_MASK_ADD) {
|
||||
snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
|
||||
|
|
@ -1669,25 +1680,48 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask,
|
|||
const int index = snd_hctl_elem_get_index(helem);
|
||||
const int device = snd_hctl_elem_get_device(helem);
|
||||
snd_mixer_elem_t *new_melem;
|
||||
|
||||
bool found = true;
|
||||
|
||||
new_melem = pa_alsa_mixer_find(mixer, iface, name, index, device);
|
||||
if (!new_melem) {
|
||||
_helem = pa_xmalloc(sizeof(snd_hctl_elem_t *));
|
||||
*_helem = helem;
|
||||
/* Put the hctl pointer as our private data - it will be useful for callbacks */
|
||||
if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) {
|
||||
if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, _helem, mixer_melem_free)) < 0) {
|
||||
pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
found = false;
|
||||
} else {
|
||||
_helem = snd_mixer_elem_get_private(new_melem);
|
||||
if (_helem) {
|
||||
char *s1, *s2;
|
||||
snd_ctl_elem_id_t *id1, *id2;
|
||||
snd_ctl_elem_id_alloca(&id1);
|
||||
snd_ctl_elem_id_alloca(&id2);
|
||||
snd_hctl_elem_get_id(helem, id1);
|
||||
snd_hctl_elem_get_id(*_helem, id2);
|
||||
s1 = snd_ctl_ascii_elem_id_get(id1);
|
||||
s2 = snd_ctl_ascii_elem_id_get(id2);
|
||||
pa_log_warn("mixer_class_event - duplicate mixer controls: %s | %s", s1, s2);
|
||||
free(s2);
|
||||
free(s1);
|
||||
return 0;
|
||||
}
|
||||
*_helem = helem;
|
||||
}
|
||||
|
||||
if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) {
|
||||
pa_log_warn("snd_mixer_elem_attach failed: %s", pa_alsa_strerror(err));
|
||||
snd_mixer_elem_free(melem);
|
||||
snd_mixer_elem_free(melem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = snd_mixer_elem_add(new_melem, class)) < 0) {
|
||||
pa_log_warn("snd_mixer_elem_add failed: %s", pa_alsa_strerror(err));
|
||||
return 0;
|
||||
if (!found) {
|
||||
if ((err = snd_mixer_elem_add(new_melem, class)) < 0) {
|
||||
pa_log_warn("snd_mixer_elem_add failed: %s", pa_alsa_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ struct temp_port_avail {
|
|||
|
||||
static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
|
||||
struct userdata *u = snd_mixer_elem_get_callback_private(melem);
|
||||
snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
|
||||
snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem;
|
||||
snd_ctl_elem_value_t *elem_value;
|
||||
bool plugged_in;
|
||||
void *state;
|
||||
|
|
@ -380,6 +380,8 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
|
|||
pa_available_t active_available = PA_AVAILABLE_UNKNOWN;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(_elem);
|
||||
elem = *_elem;
|
||||
|
||||
/* Changing the jack state may cause a port change, and a port change will
|
||||
* make the sink or source change the mixer settings. If there are multiple
|
||||
|
|
@ -562,13 +564,18 @@ static pa_device_port* find_port_with_eld_device(struct userdata *u, int device)
|
|||
|
||||
static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask) {
|
||||
struct userdata *u = snd_mixer_elem_get_callback_private(melem);
|
||||
snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
|
||||
int device = snd_hctl_elem_get_device(elem);
|
||||
snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem;
|
||||
int device;
|
||||
const char *old_monitor_name;
|
||||
pa_device_port *p;
|
||||
pa_hdmi_eld eld;
|
||||
bool changed = false;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(_elem);
|
||||
elem = *_elem;
|
||||
device = snd_hctl_elem_get_device(elem);
|
||||
|
||||
if (mask == SND_CTL_EVENT_MASK_REMOVE)
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue