From 1a534cd9075fc9cc82c36903fb27939304934f35 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 8 Jun 2026 16:23:10 +0200 Subject: [PATCH] acp: add min and max volume properties This way, the min/max volume can be updated and saved in the same way as the volume is updated. Also add support for this in audioconvert channelmix. --- spa/include/spa/param/props-types.h | 2 ++ spa/include/spa/param/props.h | 2 ++ spa/plugins/alsa/acp/acp.c | 35 +++++++++++++++++++++++++ spa/plugins/alsa/acp/acp.h | 2 ++ spa/plugins/alsa/alsa-acp-device.c | 14 ++++++++++ spa/plugins/audioconvert/audioconvert.c | 16 +++++++++++ 6 files changed, 71 insertions(+) diff --git a/spa/include/spa/param/props-types.h b/spa/include/spa/param/props-types.h index 0a7c916b8..712405def 100644 --- a/spa/include/spa/param/props-types.h +++ b/spa/include/spa/param/props-types.h @@ -66,6 +66,8 @@ static const struct spa_type_info spa_type_props[] = { { SPA_PROP_volumeRampTime, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampTime", NULL }, { SPA_PROP_volumeRampStepTime, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampStepTime", NULL }, { SPA_PROP_volumeRampScale, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "volumeRampScale", spa_type_audio_volume_ramp_scale }, + { SPA_PROP_volumeMin, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeMin", NULL }, + { SPA_PROP_volumeMax, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeMax", NULL }, { SPA_PROP_brightness, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "brightness", NULL }, { SPA_PROP_contrast, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "contrast", NULL }, diff --git a/spa/include/spa/param/props.h b/spa/include/spa/param/props.h index 48338b870..acc067ba9 100644 --- a/spa/include/spa/param/props.h +++ b/spa/include/spa/param/props.h @@ -98,6 +98,8 @@ enum spa_prop { * to ramp the */ SPA_PROP_volumeRampScale, /**< the scale or graph to used to ramp the * volume */ + SPA_PROP_volumeMin, /**< the minimum volume */ + SPA_PROP_volumeMax, /**< the maximum volume */ SPA_PROP_START_Video = 0x20000, /**< video related properties */ SPA_PROP_brightness, diff --git a/spa/plugins/alsa/acp/acp.c b/spa/plugins/alsa/acp/acp.c index cb16f3242..e227daa72 100644 --- a/spa/plugins/alsa/acp/acp.c +++ b/spa/plugins/alsa/acp/acp.c @@ -2339,6 +2339,41 @@ int acp_device_set_port(struct acp_device *dev, uint32_t port_index, uint32_t fl return res; } +int acp_device_get_volume_limit(struct acp_device *dev, float *min, float *max) +{ + pa_alsa_device *d = (pa_alsa_device*)dev; + pa_card *impl = d->card; + pa_device_port *p; + float *volume_range; + + if ((p = d->active_port) != NULL) + volume_range = p->volume_range; + else + volume_range = impl->volume_range; + + if (min) + *min = volume_range[0]; + if (max) + *max = volume_range[1]; + return 0; +} +int acp_device_set_volume_limit(struct acp_device *dev, float min, float max) +{ + pa_alsa_device *d = (pa_alsa_device*)dev; + pa_card *impl = d->card; + pa_device_port *p; + float *volume_range; + + if ((p = d->active_port) != NULL) + volume_range = p->volume_range; + else + volume_range = impl->volume_range; + + volume_range[0] = min; + volume_range[1] = max; + return 0; +} + int acp_device_set_volume(struct acp_device *dev, const float *volume, uint32_t n_volume) { pa_alsa_device *d = (pa_alsa_device*)dev; diff --git a/spa/plugins/alsa/acp/acp.h b/spa/plugins/alsa/acp/acp.h index 5fb5b96f7..9c75cd634 100644 --- a/spa/plugins/alsa/acp/acp.h +++ b/spa/plugins/alsa/acp/acp.h @@ -303,6 +303,8 @@ int acp_device_get_soft_volume(struct acp_device *dev, float *volume, uint32_t n int acp_device_get_volume(struct acp_device *dev, float *volume, uint32_t n_volume); int acp_device_set_mute(struct acp_device *dev, bool mute); int acp_device_get_mute(struct acp_device *dev, bool *mute); +int acp_device_get_volume_limit(struct acp_device *dev, float *min, float *max); +int acp_device_set_volume_limit(struct acp_device *dev, float min, float max); typedef void (*acp_log_func) (void *data, int level, const char *file, int line, const char *func, diff --git a/spa/plugins/alsa/alsa-acp-device.c b/spa/plugins/alsa/alsa-acp-device.c index 47ff03c99..f066cf9e8 100644 --- a/spa/plugins/alsa/alsa-acp-device.c +++ b/spa/plugins/alsa/alsa-acp-device.c @@ -710,6 +710,20 @@ static int apply_device_props(struct impl *this, struct acp_device *dev, struct changed++; } break; + case SPA_PROP_volumeMin: + acp_device_get_volume_limit(dev, &volumes[0], &volumes[1]); + if (spa_pod_get_float(&prop->value, &volumes[0]) == 0) { + acp_device_set_volume_limit(dev, volumes[0], volumes[1]); + changed++; + } + break; + case SPA_PROP_volumeMax: + acp_device_get_volume_limit(dev, &volumes[0], &volumes[1]); + if (spa_pod_get_float(&prop->value, &volumes[1]) == 0) { + acp_device_set_volume_limit(dev, volumes[0], volumes[1]); + changed++; + } + break; case SPA_PROP_latencyOffsetNsec: { int64_t latency_ns; diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index e474ebaa6..fd5dc74cc 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -905,6 +905,8 @@ static int node_param_props(struct impl *this, uint32_t id, uint32_t index, SPA_TYPE_Float, p->monitor.n_volumes, p->monitor.volumes), + SPA_PROP_volumeMin, SPA_POD_Float(p->min_volume), + SPA_PROP_volumeMax, SPA_POD_Float(p->max_volume), 0); spa_pod_builder_prop(b, SPA_PROP_params, 0); spa_pod_builder_push_struct(b, &f[1]); @@ -1867,6 +1869,20 @@ static int apply_props(struct impl *this, const struct spa_pod *param) changed++; } break; + case SPA_PROP_volumeMin: + if (!p->lock_volumes && + spa_pod_get_float(&prop->value, &p->min_volume) == 0) { + spa_log_debug(this->log, "%p new min-volume %f", this, p->min_volume); + changed++; + } + break; + case SPA_PROP_volumeMax: + if (!p->lock_volumes && + spa_pod_get_float(&prop->value, &p->max_volume) == 0) { + spa_log_debug(this->log, "%p new max-volume %f", this, p->min_volume); + changed++; + } + break; case SPA_PROP_rate: if (spa_pod_get_double(&prop->value, &p->rate) == 0 && !this->rate_adjust && p->rate != 1.0) {