From ffdc95655e9ae9613bf1ded3a339b63a2ec7edac Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 8 Jul 2026 14:03:13 +0200 Subject: [PATCH] filter-graph: pass softVolume unmodified if not used If the filter-graph can apply volume, it will set the softVolume to 1.0 so that the rest of the audioconvert will not apply softVolume anymore. If it however not applies softVolume, it should pass the given softVolume and softMute unmodified to be applied elsewhere. The problem is that the filter-graph completely removed the softVolume and softMute properties and in case the filter-graph was in use, this resulted in the channelVolumes being applied in software. This then could result in double volumes, once in hardware and another time in software, causing sudden volume loss. Fixes #5344 --- spa/plugins/filter-graph/filter-graph.c | 33 ++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/spa/plugins/filter-graph/filter-graph.c b/spa/plugins/filter-graph/filter-graph.c index 5df00604a..3f84edd8b 100644 --- a/spa/plugins/filter-graph/filter-graph.c +++ b/spa/plugins/filter-graph/filter-graph.c @@ -760,6 +760,9 @@ static int impl_set_props(void *object, enum spa_direction direction, const stru char buf[1024]; struct spa_pod_dynamic_builder b; struct volume *vol = &graph->volume[direction]; + float soft_vols[MAX_CHANNELS]; + uint32_t n_soft_vols = 0; + bool soft_mute = false, have_soft_mute = false; bool do_volume = false; spa_pod_dynamic_builder_init(&b, buf, sizeof(buf), 1024); @@ -805,7 +808,12 @@ static int impl_set_props(void *object, enum spa_direction direction, const stru break; } case SPA_PROP_softVolumes: + n_soft_vols = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, soft_vols, + SPA_N_ELEMENTS(soft_vols)); + break; case SPA_PROP_softMute: + if (spa_pod_get_bool(&prop->value, &soft_mute) == 0) + have_soft_mute = true; break; default: spa_pod_builder_raw_padded(&b.b, prop, SPA_POD_PROP_SIZE(prop)); @@ -813,24 +821,27 @@ static int impl_set_props(void *object, enum spa_direction direction, const stru } } if (do_volume && vol->n_ports != 0) { - float soft_vols[MAX_CHANNELS]; uint32_t i; for (i = 0; i < vol->n_volumes; i++) soft_vols[i] = (vol->mute || vol->volumes[i] == 0.0f) ? 0.0f : 1.0f; - - spa_pod_builder_prop(&b.b, SPA_PROP_softMute, 0); - spa_pod_builder_bool(&b.b, vol->mute); - spa_pod_builder_prop(&b.b, SPA_PROP_softVolumes, 0); - spa_pod_builder_array(&b.b, sizeof(float), SPA_TYPE_Float, - vol->n_volumes, soft_vols); - props = spa_pod_builder_pop(&b.b, &f[0]); + n_soft_vols = vol->n_volumes; + soft_mute = vol->mute; + have_soft_mute = true; sync_volume(graph, vol); - - } else { - props = spa_pod_builder_pop(&b.b, &f[0]); } + if (have_soft_mute) { + spa_pod_builder_prop(&b.b, SPA_PROP_softMute, 0); + spa_pod_builder_bool(&b.b, soft_mute); + } + if (n_soft_vols > 0) { + spa_pod_builder_prop(&b.b, SPA_PROP_softVolumes, 0); + spa_pod_builder_array(&b.b, sizeof(float), SPA_TYPE_Float, + n_soft_vols, soft_vols); + } + props = spa_pod_builder_pop(&b.b, &f[0]); + spa_filter_graph_emit_apply_props(&impl->hooks, direction, props); spa_pod_dynamic_builder_clean(&b);