mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: emit props change events only if values actually changed
This may avoid infinite loops if parameters are being set based on events sent by parameter changes. It's also what alsa-acp devices do, so bluez5 should follow.
This commit is contained in:
parent
302282ef59
commit
4389e44903
5 changed files with 138 additions and 71 deletions
|
|
@ -308,7 +308,27 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_props_changed(struct impl *this);
|
||||
static void emit_node_info(struct impl *this, bool full);
|
||||
|
||||
static int apply_props(struct impl *this, const struct spa_pod *param)
|
||||
{
|
||||
struct props new_props = this->props;
|
||||
int changed = 0;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(&new_props);
|
||||
} else {
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&new_props.min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&new_props.max_latency),
|
||||
SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&new_props.latency_offset));
|
||||
}
|
||||
|
||||
changed = (memcmp(&new_props, &this->props, sizeof(struct props)) != 0);
|
||||
this->props = new_props;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
|
|
@ -320,19 +340,11 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
switch (id) {
|
||||
case SPA_PARAM_Props:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(p);
|
||||
emit_node_props_changed(this);
|
||||
return 0;
|
||||
if (apply_props(this, param) > 0) {
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[1].flags ^= SPA_PARAM_INFO_SERIAL;
|
||||
emit_node_info(this, false);
|
||||
}
|
||||
if (spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&p->min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&p->max_latency),
|
||||
SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&p->latency_offset)) > 0)
|
||||
emit_node_props_changed(this);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -869,13 +881,6 @@ static void emit_port_info(struct impl *this, struct port *port, bool full)
|
|||
}
|
||||
}
|
||||
|
||||
static void emit_node_props_changed(struct impl *this)
|
||||
{
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[1].flags ^= SPA_PARAM_INFO_SERIAL;
|
||||
emit_node_info(this, false);
|
||||
}
|
||||
|
||||
static int
|
||||
impl_node_add_listener(void *object,
|
||||
struct spa_hook *listener,
|
||||
|
|
|
|||
|
|
@ -262,6 +262,27 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct impl *this, bool full);
|
||||
|
||||
static int apply_props(struct impl *this, const struct spa_pod *param)
|
||||
{
|
||||
struct props new_props = this->props;
|
||||
int changed = 0;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(&new_props);
|
||||
} else {
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&new_props.min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&new_props.max_latency));
|
||||
}
|
||||
|
||||
changed = (memcmp(&new_props, &this->props, sizeof(struct props)) != 0);
|
||||
this->props = new_props;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
|
|
@ -272,16 +293,11 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
switch (id) {
|
||||
case SPA_PARAM_Props:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(p);
|
||||
return 0;
|
||||
if (apply_props(this, param) > 0) {
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[1].flags ^= SPA_PARAM_INFO_SERIAL;
|
||||
emit_node_info(this, false);
|
||||
}
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&p->min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&p->max_latency));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -919,14 +919,18 @@ static int node_set_volume(struct impl *this, struct node *node, float volumes[]
|
|||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod_frame f[1];
|
||||
uint32_t i;
|
||||
int changed = 0;
|
||||
|
||||
if (n_volumes == 0)
|
||||
return -EINVAL;
|
||||
|
||||
spa_log_info(this->log, "node %p volume %f", node, volumes[0]);
|
||||
|
||||
for (i = 0; i < node->n_channels; i++)
|
||||
for (i = 0; i < node->n_channels; i++) {
|
||||
if (node->volumes[i] != volumes[i % n_volumes])
|
||||
++changed;
|
||||
node->volumes[i] = volumes[i % n_volumes];
|
||||
}
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
spa_pod_builder_push_object(&b, &f[0],
|
||||
|
|
@ -944,7 +948,7 @@ static int node_set_volume(struct impl *this, struct node *node, float volumes[]
|
|||
|
||||
spa_device_emit_event(&this->hooks, event);
|
||||
|
||||
return 0;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int node_set_mute(struct impl *this, struct node *node, bool mute)
|
||||
|
|
@ -953,8 +957,11 @@ static int node_set_mute(struct impl *this, struct node *node, bool mute)
|
|||
uint8_t buffer[4096];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod_frame f[1];
|
||||
int changed = 0;
|
||||
|
||||
spa_log_info(this->log, "node %p mute %d", node, mute);
|
||||
|
||||
changed = (node->mute != mute);
|
||||
node->mute = mute;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
|
@ -971,7 +978,7 @@ static int node_set_mute(struct impl *this, struct node *node, bool mute)
|
|||
|
||||
spa_device_emit_event(&this->hooks, event);
|
||||
|
||||
return 0;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int node_set_latency_offset(struct impl *this, struct node *node, int64_t latency_offset)
|
||||
|
|
@ -980,8 +987,11 @@ static int node_set_latency_offset(struct impl *this, struct node *node, int64_t
|
|||
uint8_t buffer[4096];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod_frame f[1];
|
||||
int changed = 0;
|
||||
|
||||
spa_log_info(this->log, "node %p latency offset %"PRIi64" nsec", node, latency_offset);
|
||||
|
||||
changed = (node->latency_offset != latency_offset);
|
||||
node->latency_offset = latency_offset;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
|
@ -998,7 +1008,7 @@ static int node_set_latency_offset(struct impl *this, struct node *node, int64_t
|
|||
|
||||
spa_device_emit_event(&this->hooks, event);
|
||||
|
||||
return 0;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int apply_device_props(struct impl *this, struct node *node, struct spa_pod *props)
|
||||
|
|
@ -1010,7 +1020,7 @@ static int apply_device_props(struct impl *this, struct node *node, struct spa_p
|
|||
int changed = 0;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t channels[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t n_volumes = 0, n_channels = 0;
|
||||
uint32_t n_volumes = 0, SPA_UNUSED n_channels = 0;
|
||||
int64_t latency_offset = 0;
|
||||
|
||||
if (!spa_pod_is_object_type(props, SPA_TYPE_OBJECT_Props))
|
||||
|
|
@ -1020,37 +1030,39 @@ static int apply_device_props(struct impl *this, struct node *node, struct spa_p
|
|||
switch (prop->key) {
|
||||
case SPA_PROP_volume:
|
||||
if (spa_pod_get_float(&prop->value, &volume) == 0) {
|
||||
node_set_volume(this, node, &volume, 1);
|
||||
changed++;
|
||||
int res = node_set_volume(this, node, &volume, 1);
|
||||
if (res > 0)
|
||||
++changed;
|
||||
}
|
||||
break;
|
||||
case SPA_PROP_mute:
|
||||
if (spa_pod_get_bool(&prop->value, &mute) == 0) {
|
||||
node_set_mute(this, node, mute);
|
||||
changed++;
|
||||
int res = node_set_mute(this, node, mute);
|
||||
if (res > 0)
|
||||
++changed;
|
||||
}
|
||||
break;
|
||||
case SPA_PROP_channelVolumes:
|
||||
if ((n_volumes = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
changed++;
|
||||
}
|
||||
n_volumes = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
volumes, SPA_AUDIO_MAX_CHANNELS);
|
||||
break;
|
||||
case SPA_PROP_channelMap:
|
||||
if ((n_channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
|
||||
channels, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
changed++;
|
||||
}
|
||||
n_channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
|
||||
channels, SPA_AUDIO_MAX_CHANNELS);
|
||||
break;
|
||||
case SPA_PROP_latencyOffsetNsec:
|
||||
if (spa_pod_get_long(&prop->value, &latency_offset) == 0) {
|
||||
node_set_latency_offset(this, node, latency_offset);
|
||||
changed++;
|
||||
int res = node_set_latency_offset(this, node, latency_offset);
|
||||
if (res > 0)
|
||||
++changed;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n_volumes > 0)
|
||||
node_set_volume(this, node, volumes, n_volumes);
|
||||
if (n_volumes > 0) {
|
||||
int res = node_set_volume(this, node, volumes, n_volumes);
|
||||
if (res > 0)
|
||||
++changed;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
|
@ -1108,9 +1120,11 @@ static int impl_set_param(void *object,
|
|||
|
||||
node = &this->nodes[device];
|
||||
if (props) {
|
||||
apply_device_props(this, node, props);
|
||||
this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
this->params[IDX_Route].flags ^= SPA_PARAM_INFO_SERIAL;
|
||||
int changed = apply_device_props(this, node, props);
|
||||
if (changed > 0) {
|
||||
this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
this->params[IDX_Route].flags ^= SPA_PARAM_INFO_SERIAL;
|
||||
}
|
||||
emit_info(this, false);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -279,6 +279,27 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct impl *this, bool full);
|
||||
|
||||
static int apply_props(struct impl *this, const struct spa_pod *param)
|
||||
{
|
||||
struct props new_props = this->props;
|
||||
int changed = 0;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(&new_props);
|
||||
} else {
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&new_props.min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&new_props.max_latency));
|
||||
}
|
||||
|
||||
changed = (memcmp(&new_props, &this->props, sizeof(struct props)) != 0);
|
||||
this->props = new_props;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
|
|
@ -289,16 +310,11 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
switch (id) {
|
||||
case SPA_PARAM_Props:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(p);
|
||||
return 0;
|
||||
if (apply_props(this, param) > 0) {
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[1].flags ^= SPA_PARAM_INFO_SERIAL;
|
||||
emit_node_info(this, false);
|
||||
}
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&p->min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&p->max_latency));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -236,6 +236,27 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct impl *this, bool full);
|
||||
|
||||
static int apply_props(struct impl *this, const struct spa_pod *param)
|
||||
{
|
||||
struct props new_props = this->props;
|
||||
int changed = 0;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(&new_props);
|
||||
} else {
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&new_props.min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&new_props.max_latency));
|
||||
}
|
||||
|
||||
changed = (memcmp(&new_props, &this->props, sizeof(struct props)) != 0);
|
||||
this->props = new_props;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
|
|
@ -246,16 +267,11 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
switch (id) {
|
||||
case SPA_PARAM_Props:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(p);
|
||||
return 0;
|
||||
if (apply_props(this, param) > 0) {
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[1].flags ^= SPA_PARAM_INFO_SERIAL;
|
||||
emit_node_info(this, false);
|
||||
}
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&p->min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&p->max_latency));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue