From e3b6534872dbcca8b52cd13e2e7aaf3fd6e2329d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 27 Jun 2022 10:09:38 +0900 Subject: [PATCH] acp: avoid assertion at alsa-lib mixer API when element removal PipeWire v0.3.7 or later hits assertion at alsa-lib mixer API due to wrong handling of removal event for mixer element. wireplumber: mixer.c:149: hctl_elem_event_handler: Assertion `bag_empty(bag)' failed. The removal event is defined as '~0U', thus it's not distinguished from the other type of event just by bitwise operator. At the removal event, class implementator for mixer API should detach mixer element from hcontrol element in callback handler since alsa-lib has assertion to check the list of mixer elements for a hcontrol element is empty or not after calling all of handlers. In detail, please refer to MR to alsa-lib: * https://github.com/alsa-project/alsa-lib/pull/244 This commit fixes the above two issues. The issue can be regenerated by `samples/ctl` Python 3 script of alsa-gobject. * https://github.com/alsa-project/alsa-gobject/ It adds some user-defined elements into sound card 0. When terminated by SIGINT signal, it removes the elements. Then PulseAudio dies due to the assertion. Fixes: 1612f5e4d215 ("alsa-acp: Add libacp based card device") --- spa/plugins/alsa/acp/alsa-util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spa/plugins/alsa/acp/alsa-util.c b/spa/plugins/alsa/acp/alsa-util.c index 0a365974e..e9f78d3ca 100644 --- a/spa/plugins/alsa/acp/alsa-util.c +++ b/spa/plugins/alsa/acp/alsa-util.c @@ -1626,7 +1626,12 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, { int err; const char *name = snd_hctl_elem_get_name(helem); - if (mask & SND_CTL_EVENT_MASK_ADD) { + // NOTE: The remove event defined as '~0U`. + if (mask == SND_CTL_EVENT_MASK_REMOVE) { + // NOTE: unless remove pointer to melem from link-list at private_data of helem, hits + // assersion in alsa-lib since the list is not empty. + 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); if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) { snd_mixer_elem_t *new_melem;