diff --git a/src/pipewire/filter.c b/src/pipewire/filter.c index 39e1dc025..e306f738c 100644 --- a/src/pipewire/filter.c +++ b/src/pipewire/filter.c @@ -152,6 +152,7 @@ struct filter { unsigned int process_rt:1; unsigned int driving:1; unsigned int trigger:1; + int in_emit_param_changed; }; static int get_param_index(uint32_t id) @@ -276,6 +277,8 @@ static void clear_params(struct filter *impl, struct port *port, uint32_t id) { struct param *p, *t; struct spa_list *param_list; + bool found = false; + int i, idx; if (port) param_list = &port->param_list; @@ -285,10 +288,42 @@ static void clear_params(struct filter *impl, struct port *port, uint32_t id) spa_list_for_each_safe(p, t, param_list, link) { if (id == SPA_ID_INVALID || (p->id == id && !(p->flags & PARAM_FLAG_LOCKED))) { + found = true; spa_list_remove(&p->link); free(p); } } + if (found) { + if (id == SPA_ID_INVALID) { + if (port) { + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + for (i = 0; i < N_PORT_PARAMS; i++) { + port->params[i].flags &= ~SPA_PARAM_INFO_READ; + port->params[i].user++; + } + } else { + impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + for (i = 0; i < N_NODE_PARAMS; i++) { + impl->params[i].flags &= ~SPA_PARAM_INFO_READ; + impl->params[i].user++; + } + } + } else { + if (port) { + if ((idx = get_port_param_index(id)) != -1) { + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->params[idx].flags &= ~SPA_PARAM_INFO_READ; + port->params[idx].user++; + } + } else { + if ((idx = get_param_index(id)) != -1) { + impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + impl->params[idx].flags &= ~SPA_PARAM_INFO_READ; + impl->params[idx].user++; + } + } + } + } } static struct port *alloc_port(struct filter *filter, @@ -434,12 +469,19 @@ static int impl_enum_params(void *object, int seq, uint32_t id, uint32_t start, return enum_params(impl, &impl->param_list, seq, id, start, num, filter); } +static inline void emit_param_changed(struct filter *impl, void *port, + uint32_t id, const struct spa_pod *param) +{ + struct pw_filter *filter = &impl->this; + if (impl->in_emit_param_changed++ == 0) + pw_filter_emit_param_changed(filter, port, id, param); + impl->in_emit_param_changed--; +} + static int impl_set_param(void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) { struct filter *impl = object; - struct pw_filter *filter = &impl->this; - - pw_filter_emit_param_changed(filter, NULL, id, param); + emit_param_changed(impl, NULL, id, param); return 0; } @@ -777,7 +819,6 @@ static int default_latency(struct filter *impl, struct port *port, enum spa_dire static int handle_latency(struct filter *impl, struct port *port, const struct spa_pod *param) { - struct pw_filter *filter = &impl->this; struct spa_latency_info info; int res; @@ -797,7 +838,7 @@ static int handle_latency(struct filter *impl, struct port *port, const struct s return 0; if (SPA_FLAG_IS_SET(impl->flags, PW_FILTER_FLAG_CUSTOM_LATENCY)) { - pw_filter_emit_param_changed(filter, port->user_data, + emit_param_changed(impl, port->user_data, SPA_PARAM_Latency, param); } else { default_latency(impl, port, info.direction); @@ -849,7 +890,7 @@ static int impl_port_set_param(void *object, } if (emit) - pw_filter_emit_param_changed(filter, port->user_data, id, param); + emit_param_changed(impl, port->user_data, id, param); if (filter->state == PW_FILTER_STATE_ERROR) return filter->error_res; diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index 038f71b79..2d0c9ea3d 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -158,6 +158,7 @@ struct stream { unsigned int using_trigger:1; unsigned int trigger:1; int in_set_param; + int in_emit_param_changed; }; static int get_param_index(uint32_t id) @@ -268,14 +269,42 @@ static struct param *add_param(struct stream *impl, static void clear_params(struct stream *impl, uint32_t id) { struct param *p, *t; + bool found = false; + int i, idx; spa_list_for_each_safe(p, t, &impl->param_list, link) { if (id == SPA_ID_INVALID || (p->id == id && !(p->flags & PARAM_FLAG_LOCKED))) { + found = true; spa_list_remove(&p->link); free(p); } } + if (found) { + if (id == SPA_ID_INVALID) { + impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + for (i = 0; i < N_NODE_PARAMS; i++) { + impl->params[i].flags &= ~SPA_PARAM_INFO_READ; + impl->params[i].user++; + } + impl->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + for (i = 0; i < N_PORT_PARAMS; i++) { + impl->port_params[i].flags &= ~SPA_PARAM_INFO_READ; + impl->port_params[i].user++; + } + } else { + if ((idx = get_param_index(id)) != -1) { + impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + impl->params[idx].flags &= ~SPA_PARAM_INFO_READ; + impl->params[idx].user++; + } + if ((idx = get_port_param_index(id)) != -1) { + impl->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + impl->port_params[idx].flags &= ~SPA_PARAM_INFO_READ; + impl->port_params[idx].user++; + } + } + } } static int update_params(struct stream *impl, uint32_t id, @@ -563,16 +592,24 @@ static int impl_enum_params(void *object, int seq, uint32_t id, uint32_t start, return enum_params(object, false, seq, id, start, num, filter); } +static inline void emit_param_changed(struct stream *impl, + uint32_t id, const struct spa_pod *param) +{ + struct pw_stream *stream = &impl->this; + if (impl->in_emit_param_changed++ == 0) + pw_stream_emit_param_changed(stream, id, param); + impl->in_emit_param_changed--; +} + static int impl_set_param(void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) { struct stream *impl = object; - struct pw_stream *stream = &impl->this; if (id != SPA_PARAM_Props) return -ENOTSUP; if (impl->in_set_param == 0) - pw_stream_emit_param_changed(stream, id, param); + emit_param_changed(impl, id, param); return 0; } @@ -885,7 +922,7 @@ static int impl_port_set_param(void *object, break; } - pw_stream_emit_param_changed(stream, id, param); + emit_param_changed(impl, id, param); if (stream->state == PW_STREAM_STATE_ERROR) return stream->error_res;