diff --git a/src/modules/module-protocol-pulse/manager.c b/src/modules/module-protocol-pulse/manager.c index c4942aab4..97a05e14b 100644 --- a/src/modules/module-protocol-pulse/manager.c +++ b/src/modules/module-protocol-pulse/manager.c @@ -73,24 +73,45 @@ static void core_sync(struct manager *m) pw_log_debug("sync start %u", m->sync_seq); } +static uint32_t clear_params(struct spa_list *param_list, uint32_t id) +{ + struct pw_manager_param *p, *t; + uint32_t count = 0; + + spa_list_for_each_safe(p, t, param_list, link) { + if (id == SPA_ID_INVALID || p->id == id) { + spa_list_remove(&p->link); + free(p); + count++; + } + } + return count; +} + static struct pw_manager_param *add_param(struct spa_list *params, uint32_t id, const struct spa_pod *param) { struct pw_manager_param *p; - if (param == NULL || !spa_pod_is_object(param)) { - errno = EINVAL; - return NULL; - } - if (id == SPA_ID_INVALID) + if (id == SPA_ID_INVALID) { + if (param == NULL || !spa_pod_is_object(param)) { + errno = EINVAL; + return NULL; + } id = SPA_POD_OBJECT_ID(param); + } - p = malloc(sizeof(*p) + SPA_POD_SIZE(param)); + p = malloc(sizeof(*p) + (param != NULL ? SPA_POD_SIZE(param) : 0)); if (p == NULL) return NULL; p->id = id; - p->param = SPA_MEMBER(p, sizeof(*p), struct spa_pod); - memcpy(p->param, param, SPA_POD_SIZE(param)); + if (param != NULL) { + p->param = SPA_MEMBER(p, sizeof(*p), struct spa_pod); + memcpy(p->param, param, SPA_POD_SIZE(param)); + } else { + clear_params(params, id); + p->param = NULL; + } spa_list_append(params, &p->link); return p; @@ -108,21 +129,6 @@ static bool has_param(struct spa_list *param_list, struct pw_manager_param *p) return false; } -static uint32_t clear_params(struct spa_list *param_list, uint32_t id) -{ - struct pw_manager_param *p, *t; - uint32_t count = 0; - - spa_list_for_each_safe(p, t, param_list, link) { - if (id == SPA_ID_INVALID || p->id == id) { - spa_list_remove(&p->link); - free(p); - count++; - } - } - return count; -} - static struct object *find_object(struct manager *m, uint32_t id) { @@ -140,12 +146,14 @@ static void object_update_params(struct object *o) { struct pw_manager_param *p; - spa_list_for_each(p, &o->pending_list, link) - clear_params(&o->this.param_list, p->id); - spa_list_consume(p, &o->pending_list, link) { spa_list_remove(&p->link); - spa_list_append(&o->this.param_list, &p->link); + if (p->param == NULL) { + clear_params(&o->this.param_list, p->id); + free(p); + } else { + spa_list_append(&o->this.param_list, &p->link); + } } } @@ -277,7 +285,7 @@ static void device_event_info(void *object, const struct pw_device_info *info) case SPA_PARAM_Route: break; } - clear_params(&o->pending_list, id); + add_param(&o->pending_list, id, NULL); if (!(info->params[i].flags & SPA_PARAM_INFO_READ)) continue; @@ -382,7 +390,7 @@ static void node_event_info(void *object, const struct pw_node_info *info) info->params[i].user = 0; changed++; - clear_params(&o->pending_list, id); + add_param(&o->pending_list, id, NULL); if (!(info->params[i].flags & SPA_PARAM_INFO_READ)) continue; diff --git a/src/pipewire/impl-device.c b/src/pipewire/impl-device.c index 0aeb8610d..414bf5c84 100644 --- a/src/pipewire/impl-device.c +++ b/src/pipewire/impl-device.c @@ -53,6 +53,7 @@ struct result_device_params_data { uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param); int seq; + uint32_t count; unsigned int cache:1; }; @@ -277,6 +278,8 @@ static void result_device_params(void *data, int seq, int res, uint32_t type, co d->callback(d->data, seq, r->id, r->index, r->next, r->param); if (d->cache) { pw_log_debug(NAME" %p: add param %d", impl, r->id); + if (d->count++ == 0) + pw_param_add(&impl->pending_list, r->id, NULL); pw_param_add(&impl->pending_list, r->id, r->param); } break; @@ -298,7 +301,7 @@ int pw_impl_device_for_each_param(struct pw_impl_device *device, { int res; struct impl *impl = SPA_CONTAINER_OF(device, struct impl, this); - struct result_device_params_data user_data = { impl, data, callback, seq, false }; + struct result_device_params_data user_data = { impl, data, callback, seq, 0, false }; struct spa_hook listener; struct spa_param_info *pi; static const struct spa_device_events device_events = { @@ -347,7 +350,8 @@ int pw_impl_device_for_each_param(struct pw_impl_device *device, } res = 0; } else { - user_data.cache = impl->cache_params && filter == NULL; + user_data.cache = impl->cache_params && + (filter == NULL && index == 0 && max == UINT32_MAX); spa_zero(listener); spa_device_add_listener(device->device, &listener, @@ -412,7 +416,9 @@ static int device_enum_params(void *object, int seq, uint32_t id, uint32_t start data->data.impl = impl; data->data.data = data; data->data.callback = reply_param; - data->data.cache = impl->cache_params && filter == NULL; + data->data.count = 0; + data->data.cache = impl->cache_params && + (filter == NULL && start == 0); if (data->end == -1) spa_device_add_listener(device->device, &data->listener, &device_events, data); @@ -714,7 +720,6 @@ static void emit_params(struct pw_impl_device *device, uint32_t *changed_ids, ui static void device_info(void *data, const struct spa_device_info *info) { struct pw_impl_device *device = data; - struct impl *impl = SPA_CONTAINER_OF(device, struct impl, this); uint32_t changed_ids[MAX_PARAMS], n_changed_ids = 0; pw_log_debug(NAME" %p: flags:%08"PRIx64" change_mask:%08"PRIx64, @@ -741,7 +746,6 @@ static void device_info(void *data, const struct spa_device_info *info) continue; pw_log_debug(NAME" %p: update param %d", device, id); - pw_param_clear(&impl->pending_list, id); device->info.params[i] = info->params[i]; device->info.params[i].user = 0; diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index a2c72bc1c..e1cfbe481 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -1247,7 +1247,6 @@ int pw_impl_node_update_properties(struct pw_impl_node *node, const struct spa_d static void node_info(void *data, const struct spa_node_info *info) { struct pw_impl_node *node = data; - struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); uint32_t changed_ids[MAX_PARAMS], n_changed_ids = 0; bool flags_changed = false; @@ -1286,7 +1285,6 @@ static void node_info(void *data, const struct spa_node_info *info) continue; pw_log_debug(NAME" %p: update param %d", node, id); - pw_param_clear(&impl->pending_list, id); node->info.params[i] = info->params[i]; node->info.params[i].user = 0; @@ -1766,6 +1764,7 @@ struct result_node_params_data { uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param); int seq; + uint32_t count; unsigned int cache:1; }; @@ -1779,8 +1778,11 @@ static void result_node_params(void *data, int seq, int res, uint32_t type, cons const struct spa_result_node_params *r = result; if (d->seq == seq) { d->callback(d->data, seq, r->id, r->index, r->next, r->param); - if (d->cache) + if (d->cache) { + if (d->count++ == 0) + pw_param_add(&impl->pending_list, r->id, NULL); pw_param_add(&impl->pending_list, r->id, r->param); + } } break; } @@ -1801,7 +1803,7 @@ int pw_impl_node_for_each_param(struct pw_impl_node *node, { int res; struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); - struct result_node_params_data user_data = { impl, data, callback, seq, false }; + struct result_node_params_data user_data = { impl, data, callback, seq, 0, false }; struct spa_hook listener; struct spa_param_info *pi; static const struct spa_node_events node_events = { @@ -1850,7 +1852,8 @@ int pw_impl_node_for_each_param(struct pw_impl_node *node, } res = 0; } else { - user_data.cache = impl->cache_params && filter == NULL; + user_data.cache = impl->cache_params && + (filter == NULL && index == 0 && max == UINT32_MAX); spa_zero(listener); spa_node_add_listener(node->node, &listener, &node_events, &user_data); diff --git a/src/pipewire/impl-port.c b/src/pipewire/impl-port.c index b01581d38..7d2f11734 100644 --- a/src/pipewire/impl-port.c +++ b/src/pipewire/impl-port.c @@ -344,7 +344,6 @@ static void emit_params(struct pw_impl_port *port, uint32_t *changed_ids, uint32 static void update_info(struct pw_impl_port *port, const struct spa_port_info *info) { - struct impl *impl = SPA_CONTAINER_OF(port, struct impl, this); uint32_t changed_ids[MAX_PARAMS], n_changed_ids = 0; pw_log_debug(NAME" %p: flags:%08"PRIx64" change_mask:%08"PRIx64, @@ -378,7 +377,6 @@ static void update_info(struct pw_impl_port *port, const struct spa_port_info *i continue; pw_log_debug(NAME" %p: update param %d", port, id); - pw_param_clear(&impl->pending_list, id); port->info.params[i] = info->params[i]; port->info.params[i].user = 0; @@ -1069,6 +1067,7 @@ struct result_port_params_data { uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param); int seq; + uint32_t count; unsigned int cache:1; }; @@ -1082,8 +1081,11 @@ static void result_port_params(void *data, int seq, int res, uint32_t type, cons const struct spa_result_node_params *r = result; if (d->seq == seq) { d->callback(d->data, seq, r->id, r->index, r->next, r->param); - if (d->cache) + if (d->cache) { + if (d->count++ == 0) + pw_param_add(&impl->pending_list, r->id, NULL); pw_param_add(&impl->pending_list, r->id, r->param); + } } break; } @@ -1105,7 +1107,7 @@ int pw_impl_port_for_each_param(struct pw_impl_port *port, int res; struct impl *impl = SPA_CONTAINER_OF(port, struct impl, this); struct pw_impl_node *node = port->node; - struct result_port_params_data user_data = { impl, data, callback, seq, false }; + struct result_port_params_data user_data = { impl, data, callback, seq, 0, false }; struct spa_hook listener; struct spa_param_info *pi; static const struct spa_node_events node_events = { @@ -1154,7 +1156,8 @@ int pw_impl_port_for_each_param(struct pw_impl_port *port, } res = 0; } else { - user_data.cache = filter == NULL; + user_data.cache = impl->cache_params && + (filter == NULL && index == 0 && max == UINT32_MAX); spa_zero(listener); spa_node_add_listener(node->node, &listener, &node_events, &user_data); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index d8d8c3166..9830bf823 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -90,28 +90,6 @@ struct pw_param { struct spa_pod *param; }; -static inline struct pw_param *pw_param_add(struct spa_list *params, - uint32_t id, const struct spa_pod *param) -{ - struct pw_param *p; - - if (param == NULL || !spa_pod_is_object(param)) { - errno = EINVAL; - return NULL; - } - if (id == SPA_ID_INVALID) - id = SPA_POD_OBJECT_ID(param); - - if ((p = malloc(sizeof(*p) + SPA_POD_SIZE(param))) == NULL) - return NULL; - - p->id = id; - p->param = SPA_MEMBER(p, sizeof(*p), struct spa_pod); - memcpy(p->param, param, SPA_POD_SIZE(param)); - spa_list_append(params, &p->link); - return p; -} - static inline uint32_t pw_param_clear(struct spa_list *param_list, uint32_t id) { struct pw_param *p, *t; @@ -127,16 +105,46 @@ static inline uint32_t pw_param_clear(struct spa_list *param_list, uint32_t id) return count; } +static inline struct pw_param *pw_param_add(struct spa_list *params, + uint32_t id, const struct spa_pod *param) +{ + struct pw_param *p; + + if (id == SPA_ID_INVALID) { + if (param == NULL || !spa_pod_is_object(param)) { + errno = EINVAL; + return NULL; + } + id = SPA_POD_OBJECT_ID(param); + } + + if ((p = malloc(sizeof(*p) + (param != NULL ? SPA_POD_SIZE(param) : 0))) == NULL) + return NULL; + + p->id = id; + if (param != NULL) { + p->param = SPA_MEMBER(p, sizeof(*p), struct spa_pod); + memcpy(p->param, param, SPA_POD_SIZE(param)); + } else { + pw_param_clear(params, id); + p->param = NULL; + } + spa_list_append(params, &p->link); + return p; +} + static inline void pw_param_update(struct spa_list *param_list, struct spa_list *pending_list) { struct pw_param *p; - spa_list_for_each(p, pending_list, link) - pw_param_clear(param_list, p->id); - spa_list_consume(p, pending_list, link) { spa_list_remove(&p->link); - spa_list_append(param_list, &p->link); + if (p->param == NULL) { + pw_param_clear(param_list, p->id); + free(p); + } else { + spa_list_append(param_list, &p->link); + } } } diff --git a/src/tools/pw-dump.c b/src/tools/pw-dump.c index 03536224d..9d8e79918 100644 --- a/src/tools/pw-dump.c +++ b/src/tools/pw-dump.c @@ -122,29 +122,6 @@ static void core_sync(struct data *d) pw_log_debug("sync start %u", d->sync_seq); } -static struct param *add_param(struct spa_list *params, uint32_t id, const struct spa_pod *param) -{ - struct param *p; - - if (param == NULL || !spa_pod_is_object(param)) { - errno = EINVAL; - return NULL; - } - if (id == SPA_ID_INVALID) - id = SPA_POD_OBJECT_ID(param); - - p = malloc(sizeof(*p) + SPA_POD_SIZE(param)); - if (p == NULL) - return NULL; - - p->id = id; - p->param = SPA_MEMBER(p, sizeof(*p), struct spa_pod); - memcpy(p->param, param, SPA_POD_SIZE(param)); - spa_list_append(params, &p->link); - - return p; -} - static uint32_t clear_params(struct spa_list *param_list, uint32_t id) { struct param *p, *t; @@ -160,6 +137,35 @@ static uint32_t clear_params(struct spa_list *param_list, uint32_t id) return count; } +static struct param *add_param(struct spa_list *params, uint32_t id, const struct spa_pod *param) +{ + struct param *p; + + if (id == SPA_ID_INVALID) { + if (param == NULL || !spa_pod_is_object(param)) { + errno = EINVAL; + return NULL; + } + id = SPA_POD_OBJECT_ID(param); + } + + p = malloc(sizeof(*p) + (param != NULL ? SPA_POD_SIZE(param) : 0)); + if (p == NULL) + return NULL; + + p->id = id; + if (param != NULL) { + p->param = SPA_MEMBER(p, sizeof(*p), struct spa_pod); + memcpy(p->param, param, SPA_POD_SIZE(param)); + } else { + clear_params(params, id); + p->param = NULL; + } + spa_list_append(params, &p->link); + + return p; +} + static struct object *find_object(struct data *d, uint32_t id) { struct object *o; @@ -174,12 +180,14 @@ static void object_update_params(struct object *o) { struct param *p; - spa_list_for_each(p, &o->pending_list, link) - clear_params(&o->param_list, p->id); - spa_list_consume(p, &o->pending_list, link) { spa_list_remove(&p->link); - spa_list_append(&o->param_list, &p->link); + if (p->param == NULL) { + clear_params(&o->param_list, p->id); + free(p); + } else { + spa_list_append(&o->param_list, &p->link); + } } } @@ -482,7 +490,7 @@ static void put_params(struct data *d, const char *key, put_begin(d, spa_debug_type_find_short_name(spa_type_param, pi->id), "[", flags); spa_list_for_each(p, list, link) { - if (p->id == pi->id && flags == 0) + if (p->id == pi->id) put_pod(d, NULL, p->param); } put_end(d, "]", flags); @@ -834,7 +842,7 @@ static void node_event_info(void *object, const struct pw_node_info *info) info->params[i].user = 0; changed++; - clear_params(&o->pending_list, id); + add_param(&o->pending_list, id, NULL); if (!(info->params[i].flags & SPA_PARAM_INFO_READ)) continue; @@ -917,7 +925,7 @@ static void port_event_info(void *object, const struct pw_port_info *info) info->params[i].user = 0; changed++; - clear_params(&o->pending_list, id); + add_param(&o->pending_list, id, NULL); if (!(info->params[i].flags & SPA_PARAM_INFO_READ)) continue;