From ebe6f8b51a31ff7bd71d560991a12283f710b937 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 20 Mar 2023 18:28:10 +0100 Subject: [PATCH] alsa-ucm: Disable old modifiers when switching profiles of same verb While switching profiles of the same UCM verb, existing code first disables devices that are only on the first profile to avoid conflicts. However, it only disables devices, not modifiers. Even worse, modifiers which have PlaybackPCM/CapturePCM are incorrectly treated as devices and result in a segmentation fault. Check what we are disabling, and call the appropriate disable function for both devices and modifiers. Modifiers are disabled before devices, because _dismod calls fail when the modifier's supported devices are disabled. Signed-off-by: Alper Nebi Yasak --- spa/plugins/alsa/acp/alsa-ucm.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/spa/plugins/alsa/acp/alsa-ucm.c b/spa/plugins/alsa/acp/alsa-ucm.c index d48db3adc..f39425646 100644 --- a/spa/plugins/alsa/acp/alsa-ucm.c +++ b/spa/plugins/alsa/acp/alsa-ucm.c @@ -1485,15 +1485,28 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof } } else if (ucm->active_verb) { - /* Disable devices not in new profile */ + /* Disable modifiers not in new profile. Has to be done before + * devices, because _dismod fails if a modifier's supported + * devices are disabled. */ PA_IDXSET_FOREACH(map, old_profile->input_mappings, idx) if (new_profile && !pa_idxset_contains(new_profile->input_mappings, map)) - if (ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) + if (map->ucm_context.ucm_modifier && ucm_modifier_disable(ucm, map->ucm_context.ucm_modifier) < 0) ret = -1; PA_IDXSET_FOREACH(map, old_profile->output_mappings, idx) if (new_profile && !pa_idxset_contains(new_profile->output_mappings, map)) - if (ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) + if (map->ucm_context.ucm_modifier && ucm_modifier_disable(ucm, map->ucm_context.ucm_modifier) < 0) + ret = -1; + + /* Disable devices not in new profile */ + PA_IDXSET_FOREACH(map, old_profile->input_mappings, idx) + if (new_profile && !pa_idxset_contains(new_profile->input_mappings, map)) + if (map->ucm_context.ucm_device && ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) + ret = -1; + + PA_IDXSET_FOREACH(map, old_profile->output_mappings, idx) + if (new_profile && !pa_idxset_contains(new_profile->output_mappings, map)) + if (map->ucm_context.ucm_device && ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) ret = -1; } ucm->active_verb = verb;