acp: add volume base and step

Add a READONLY property flag to makr properties READONLY
Set the base_volume and volume_step in the acp device
Send the base volume and step as REAONLY properties. Use these
in pulse layer.
This commit is contained in:
Wim Taymans 2020-07-07 13:12:57 +02:00
parent f75dfde89c
commit e030445e49
8 changed files with 40 additions and 11 deletions

View file

@ -384,6 +384,12 @@ static void parse_props(struct global *g, const struct spa_pod *param, bool devi
prop->flags & SPA_POD_PROP_FLAG_HARDWARE); prop->flags & SPA_POD_PROP_FLAG_HARDWARE);
break; break;
} }
case SPA_PROP_volumeBase:
spa_pod_get_float(&prop->value, &g->node_info.base_volume);
break;
case SPA_PROP_volumeStep:
spa_pod_get_float(&prop->value, &g->node_info.volume_step);
break;
default: default:
break; break;
} }
@ -1037,8 +1043,10 @@ static int set_mask(pa_context *c, struct global *g)
g->node_info.device_id = SPA_ID_INVALID; g->node_info.device_id = SPA_ID_INVALID;
ginfo = &node_info; ginfo = &node_info;
g->node_info.volume = 1.0; g->node_info.volume = 1.0f;
g->node_info.mute = false; g->node_info.mute = false;
g->node_info.base_volume = 1.0f;
g->node_info.volume_step = 1.0f / (PA_VOLUME_NORM+1);
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Port) == 0) { } else if (strcmp(g->type, PW_TYPE_INTERFACE_Port) == 0) {
if (g->props == NULL) if (g->props == NULL)
return 0; return 0;

View file

@ -283,6 +283,8 @@ struct global {
float channel_volumes[SPA_AUDIO_MAX_CHANNELS]; float channel_volumes[SPA_AUDIO_MAX_CHANNELS];
uint32_t device_id; /* id of device (card) */ uint32_t device_id; /* id of device (card) */
uint32_t profile_device_id; /* id in profile */ uint32_t profile_device_id; /* id in profile */
float base_volume;
float volume_step;
} node_info; } node_info;
struct { struct {
uint32_t node_id; uint32_t node_id;

View file

@ -149,9 +149,9 @@ static void sink_callback(pa_context *c, struct global *g, struct sink_data *d)
i.flags |= PA_SINK_HW_MUTE_CTRL; i.flags |= PA_SINK_HW_MUTE_CTRL;
i.proplist = pa_proplist_new_dict(info->props); i.proplist = pa_proplist_new_dict(info->props);
i.configured_latency = 0; i.configured_latency = 0;
i.base_volume = PA_VOLUME_NORM; i.base_volume = g->node_info.base_volume * PA_VOLUME_NORM;
i.n_volume_steps = g->node_info.volume_step * (PA_VOLUME_NORM+1);
i.state = node_state_to_sink(info->state); i.state = node_state_to_sink(info->state);
i.n_volume_steps = PA_VOLUME_NORM+1;
i.card = g->node_info.device_id; i.card = g->node_info.device_id;
i.n_ports = 0; i.n_ports = 0;
i.ports = NULL; i.ports = NULL;
@ -872,9 +872,9 @@ static void source_callback(pa_context *c, struct global *g, struct source_data
i.flags = flags; i.flags = flags;
i.proplist = pa_proplist_new_dict(info->props); i.proplist = pa_proplist_new_dict(info->props);
i.configured_latency = 0; i.configured_latency = 0;
i.base_volume = PA_VOLUME_NORM; i.base_volume = g->node_info.base_volume * PA_VOLUME_NORM;
i.n_volume_steps = g->node_info.volume_step * (PA_VOLUME_NORM+1);
i.state = node_state_to_source(info->state); i.state = node_state_to_source(info->state);
i.n_volume_steps = PA_VOLUME_NORM+1;
i.card = g->node_info.device_id; i.card = g->node_info.device_id;
i.n_ports = 0; i.n_ports = 0;
i.ports = NULL; i.ports = NULL;

View file

@ -69,12 +69,15 @@ enum spa_prop {
SPA_PROP_START_Audio = 0x10000, /**< audio related properties */ SPA_PROP_START_Audio = 0x10000, /**< audio related properties */
SPA_PROP_waveType, SPA_PROP_waveType,
SPA_PROP_frequency, SPA_PROP_frequency,
SPA_PROP_volume, SPA_PROP_volume, /**< a volume (Float), 0.0 silence, 1.0 normal */
SPA_PROP_mute, SPA_PROP_mute, /**< mute (Bool) */
SPA_PROP_patternType, SPA_PROP_patternType,
SPA_PROP_ditherType, SPA_PROP_ditherType,
SPA_PROP_truncate, SPA_PROP_truncate,
SPA_PROP_channelVolumes, SPA_PROP_channelVolumes, /**< a volume array, one volume per
* channel (Array of Float) */
SPA_PROP_volumeBase, /**< a volume base (Float) */
SPA_PROP_volumeStep, /**< a volume step (Float) */
SPA_PROP_START_Video = 0x20000, /**< video related properties */ SPA_PROP_START_Video = 0x20000, /**< video related properties */
SPA_PROP_brightness, SPA_PROP_brightness,

View file

@ -194,7 +194,8 @@ struct spa_pod_fd {
struct spa_pod_prop { struct spa_pod_prop {
uint32_t key; /**< key of property, list of valid keys depends on the uint32_t key; /**< key of property, list of valid keys depends on the
* object type */ * object type */
#define SPA_POD_PROP_FLAG_HARDWARE (1u<<0) /**< property for some sort of hardware parameter */ #define SPA_POD_PROP_FLAG_READONLY (1u<<0) /**< is read-only */
#define SPA_POD_PROP_FLAG_HARDWARE (1u<<1) /**< some sort of hardware parameter */
uint32_t flags; /**< flags for property */ uint32_t flags; /**< flags for property */
struct spa_pod value; struct spa_pod value;
/* value follows */ /* value follows */

View file

@ -55,7 +55,7 @@ static void init_device(pa_card *impl, pa_alsa_device *dev, pa_alsa_direction_t
dev->device.format.format_mask = m->sample_spec.format; dev->device.format.format_mask = m->sample_spec.format;
dev->device.format.rate_mask = m->sample_spec.rate; dev->device.format.rate_mask = m->sample_spec.rate;
dev->device.format.channels = m->channel_map.channels; dev->device.format.channels = m->channel_map.channels;
pa_cvolume_set(&dev->real_volume, m->channel_map.channels, PA_VOLUME_NORM); pa_cvolume_reset(&dev->real_volume, m->channel_map.channels);
for (i = 0; i < m->channel_map.channels; i++) for (i = 0; i < m->channel_map.channels; i++)
dev->device.format.map[i]= m->channel_map.map[i]; dev->device.format.map[i]= m->channel_map.map[i];
dev->direction = direction; dev->direction = direction;
@ -813,6 +813,8 @@ static void mixer_volume_init(pa_alsa_device *dev) {
dev->read_volume = NULL; dev->read_volume = NULL;
dev->set_volume = NULL; dev->set_volume = NULL;
pa_log_info("Driver does not support hardware volume control, falling back to software volume control."); pa_log_info("Driver does not support hardware volume control, falling back to software volume control.");
dev->base_volume = PA_VOLUME_NORM;
dev->n_volume_steps = PA_VOLUME_NORM+1;
dev->device.flags &= ~ACP_DEVICE_HW_VOLUME; dev->device.flags &= ~ACP_DEVICE_HW_VOLUME;
} else { } else {
dev->read_volume = read_volume; dev->read_volume = read_volume;
@ -846,6 +848,8 @@ static void mixer_volume_init(pa_alsa_device *dev) {
pa_log_info("Using hardware volume control. Hardware dB scale %s.", pa_log_info("Using hardware volume control. Hardware dB scale %s.",
dev->mixer_path->has_dB ? "supported" : "not supported"); dev->mixer_path->has_dB ? "supported" : "not supported");
} }
dev->device.base_volume = (float)dev->base_volume / PA_VOLUME_NORM;
dev->device.volume_step = 1.0f / dev->n_volume_steps;
if (!dev->mixer_path || !dev->mixer_path->has_mute) { if (!dev->mixer_path || !dev->mixer_path->has_mute) {
dev->read_mute = NULL; dev->read_mute = NULL;

View file

@ -169,6 +169,9 @@ struct acp_device {
char **device_strings; char **device_strings;
struct acp_format format; struct acp_format format;
float base_volume;
float volume_step;
struct acp_port **ports; struct acp_port **ports;
uint32_t n_ports; uint32_t n_ports;
}; };

View file

@ -354,15 +354,23 @@ static struct spa_pod *build_route(struct spa_pod_builder *b, uint32_t id,
spa_pod_builder_prop(b, SPA_PARAM_ROUTE_props, 0); spa_pod_builder_prop(b, SPA_PARAM_ROUTE_props, 0);
spa_pod_builder_push_object(b, &f[1], SPA_TYPE_OBJECT_Props, id); spa_pod_builder_push_object(b, &f[1], SPA_TYPE_OBJECT_Props, id);
spa_pod_builder_prop(b, SPA_PROP_mute, spa_pod_builder_prop(b, SPA_PROP_mute,
SPA_FLAG_IS_SET(dev->flags, ACP_DEVICE_HW_MUTE) ? SPA_FLAG_IS_SET(dev->flags, ACP_DEVICE_HW_MUTE) ?
SPA_POD_PROP_FLAG_HARDWARE : 0); SPA_POD_PROP_FLAG_HARDWARE : 0);
spa_pod_builder_bool(b, mute); spa_pod_builder_bool(b, mute);
spa_pod_builder_prop(b, SPA_PROP_channelVolumes, spa_pod_builder_prop(b, SPA_PROP_channelVolumes,
SPA_FLAG_IS_SET(dev->flags, ACP_DEVICE_HW_VOLUME) ? SPA_FLAG_IS_SET(dev->flags, ACP_DEVICE_HW_VOLUME) ?
SPA_POD_PROP_FLAG_HARDWARE : 0); SPA_POD_PROP_FLAG_HARDWARE : 0);
spa_pod_builder_array(b, sizeof(float), SPA_TYPE_Float, spa_pod_builder_array(b, sizeof(float), SPA_TYPE_Float,
channels, volumes); channels, volumes);
spa_pod_builder_prop(b, SPA_PROP_volumeBase, SPA_POD_PROP_FLAG_READONLY);
spa_pod_builder_float(b, dev->base_volume);
spa_pod_builder_prop(b, SPA_PROP_volumeStep, SPA_POD_PROP_FLAG_READONLY);
spa_pod_builder_float(b, dev->volume_step);
spa_pod_builder_pop(b, &f[1]); spa_pod_builder_pop(b, &f[1]);
} }
return spa_pod_builder_pop(b, &f[0]); return spa_pod_builder_pop(b, &f[0]);
@ -653,7 +661,7 @@ static void on_volume_changed(void *data, struct acp_device *dev)
static void on_mute_changed(void *data, struct acp_device *dev) static void on_mute_changed(void *data, struct acp_device *dev)
{ {
struct impl *this = data; struct impl *this = data;
spa_log_debug(this->log, "device %s mute changed", dev->name); spa_log_info(this->log, "device %s mute changed", dev->name);
this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS; this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
this->params[3].flags ^= SPA_PARAM_INFO_SERIAL; this->params[3].flags ^= SPA_PARAM_INFO_SERIAL;
emit_info(this, false); emit_info(this, false);