From ccfe4397869234a8d4b6aacc671f92946f056c3a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 9 Dec 2020 17:07:34 +0100 Subject: [PATCH] Cache node, port and device params So that we don't need to keep asking when it didn't change. Fixes #455 --- src/pipewire/impl-device.c | 127 ++++++++++++++++++++++++++++++++----- src/pipewire/impl-node.c | 105 +++++++++++++++++++++++++----- src/pipewire/impl-port.c | 110 ++++++++++++++++++++++++++++---- src/pipewire/keys.h | 3 + src/pipewire/private.h | 67 +++++++++++++++++++ 5 files changed, 366 insertions(+), 46 deletions(-) diff --git a/src/pipewire/impl-device.c b/src/pipewire/impl-device.c index 9e9c70081..725113166 100644 --- a/src/pipewire/impl-device.c +++ b/src/pipewire/impl-device.c @@ -26,6 +26,7 @@ #include #include +#include #include "pipewire/impl.h" #include "pipewire/private.h" @@ -34,6 +35,11 @@ struct impl { struct pw_impl_device this; + + struct spa_list param_list; + struct spa_list pending_list; + + unsigned int cache_params:1; }; #define pw_device_resource(r,m,v,...) pw_resource_call(r,struct pw_device_events,m,v,__VA_ARGS__) @@ -41,10 +47,13 @@ struct impl { #define pw_device_resource_param(r,...) pw_device_resource(r,param,0,__VA_ARGS__) struct result_device_params_data { + struct impl *impl; void *data; int (*callback) (void *data, int seq, uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param); + int seq; + unsigned int cache:1; }; struct resource_data { @@ -61,6 +70,7 @@ struct resource_data { int seq; int orig_seq; int end; + struct spa_param_info *pi; struct result_device_params_data data; struct spa_hook listener; }; @@ -139,6 +149,9 @@ struct pw_impl_device *pw_context_create_device(struct pw_context *context, res = -errno; goto error_cleanup; } + spa_list_init(&impl->param_list); + spa_list_init(&impl->pending_list); + impl->cache_params = true; this = &impl->this; this->name = strdup("device"); @@ -179,6 +192,7 @@ error_cleanup: SPA_EXPORT void pw_impl_device_destroy(struct pw_impl_device *device) { + struct impl *impl = SPA_CONTAINER_OF(device, struct impl, this); struct object_data *od; pw_log_debug(NAME" %p: destroy", device); @@ -200,6 +214,9 @@ void pw_impl_device_destroy(struct pw_impl_device *device) pw_log_debug(NAME" %p: free", device); pw_impl_device_emit_free(device); + pw_param_clear(&impl->param_list, SPA_ID_INVALID); + pw_param_clear(&impl->pending_list, SPA_ID_INVALID); + spa_hook_list_clean(&device->listener_list); pw_properties_free(device->properties); @@ -210,7 +227,15 @@ void pw_impl_device_destroy(struct pw_impl_device *device) static void remove_busy_resource(struct resource_data *d) { + struct pw_impl_device *device = d->device; + struct impl *impl = SPA_CONTAINER_OF(device, struct impl, this); + if (d->end != -1) { + if (d->pi && d->data.cache) { + pw_param_update(&impl->param_list, &impl->pending_list); + d->pi->user = 1; + d->pi = NULL; + } spa_hook_remove(&d->listener); d->end = -1; pw_impl_client_set_busy(d->resource->client, false); @@ -242,11 +267,18 @@ static const struct pw_resource_events resource_events = { static void result_device_params(void *data, int seq, int res, uint32_t type, const void *result) { struct result_device_params_data *d = data; + struct impl *impl = d->impl; + pw_log_debug(NAME" %p: type %d", impl, type); + switch (type) { case SPA_RESULT_TYPE_DEVICE_PARAMS: { const struct spa_result_device_params *r = result; 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); + pw_param_add(&impl->pending_list, r->id, r->param); + } break; } default: @@ -265,26 +297,73 @@ int pw_impl_device_for_each_param(struct pw_impl_device *device, void *data) { int res; - struct result_device_params_data user_data = { data, callback }; + struct impl *impl = SPA_CONTAINER_OF(device, struct impl, this); + struct result_device_params_data user_data = { impl, data, callback, seq, false }; struct spa_hook listener; + struct spa_param_info *pi; static const struct spa_device_events device_events = { SPA_VERSION_DEVICE_EVENTS, .result = result_device_params, }; + pi = pw_param_info_find(device->info.params, device->info.n_params, param_id); + if (pi == NULL) + return -ENOENT; + if (max == 0) max = UINT32_MAX; - pw_log_debug(NAME" %p: params id:%d (%s) index:%u max:%u", device, param_id, + pw_log_debug(NAME" %p: params id:%d (%s) index:%u max:%u cached:%d", device, param_id, spa_debug_type_find_name(spa_type_param, param_id), - index, max); + index, max, pi->user); - spa_zero(listener); - spa_device_add_listener(device->device, &listener, - &device_events, &user_data); - res = spa_device_enum_params(device->device, seq, - param_id, index, max, filter); - spa_hook_remove(&listener); + if (pi->user == 1) { + struct pw_param *p; + uint8_t buffer[1024]; + struct spa_pod_builder b = { 0 }; + struct spa_result_device_params result; + uint32_t count = 0; + bool found = false; + + result.id = param_id; + result.next = 0; + + spa_list_for_each(p, &impl->param_list, link) { + result.index = result.next++; + if (p->id != param_id) + continue; + + found = true; + + if (result.index < index) + continue; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + if (spa_pod_filter(&b, &result.param, p->param, filter) != 0) + continue; + + pw_log_debug(NAME " %p: %d param %u", device, seq, result.index); + result_device_params(&user_data, seq, 0, SPA_RESULT_TYPE_DEVICE_PARAMS, &result); + + if (++count == max) + break; + } + res = found ? 0 : -ENOENT; + } else { + user_data.cache = impl->cache_params && filter == NULL; + + spa_zero(listener); + spa_device_add_listener(device->device, &listener, + &device_events, &user_data); + res = spa_device_enum_params(device->device, seq, + param_id, index, max, filter); + spa_hook_remove(&listener); + + if (!SPA_RESULT_IS_ASYNC(res) && user_data.cache) { + pw_param_update(&impl->param_list, &impl->pending_list); + pi->user = 1; + } + } return res; } @@ -304,11 +383,10 @@ static void result_device_params_async(void *data, int seq, int res, uint32_t ty pw_log_debug(NAME" %p: async result %d %d (%d/%d)", d->device, res, seq, d->seq, d->end); - if (seq == d->end) - remove_busy_resource(d); if (seq == d->seq) result_device_params(&d->data, d->orig_seq, res, type, result); - + if (seq == d->end) + remove_busy_resource(d); } static int device_enum_params(void *object, int seq, uint32_t id, uint32_t start, uint32_t num, @@ -317,6 +395,7 @@ static int device_enum_params(void *object, int seq, uint32_t id, uint32_t start struct resource_data *data = object; struct pw_resource *resource = data->resource; struct pw_impl_device *device = data->device; + struct impl *impl = SPA_CONTAINER_OF(device, struct impl, this); struct pw_impl_client *client = resource->client; int res; static const struct spa_device_events device_events = { @@ -333,11 +412,15 @@ static int device_enum_params(void *object, int seq, uint32_t id, uint32_t start spa_debug_type_find_name(spa_type_param, id)); } else if (SPA_RESULT_IS_ASYNC(res)) { pw_impl_client_set_busy(client, true); + data->data.impl = impl; data->data.data = data; data->data.callback = reply_param; + data->data.cache = impl->cache_params && filter == NULL; if (data->end == -1) spa_device_add_listener(device->device, &data->listener, &device_events, data); + data->pi = pw_param_info_find(device->info.params, + device->info.n_params, id); data->orig_seq = seq; data->seq = res; data->end = spa_device_sync(device->device, res); @@ -634,8 +717,12 @@ 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, + device, info->flags, info->change_mask); + if (info->change_mask & SPA_DEVICE_CHANGE_MASK_PROPS) { update_properties(device, info->props); } @@ -646,16 +733,22 @@ static void device_info(void *data, const struct spa_device_info *info) device->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(device->params)); for (i = 0; i < device->info.n_params; i++) { + uint32_t id = info->params[i].id; + pw_log_debug(NAME" %p: param %d id:%d (%s) %08x:%08x", device, i, - info->params[i].id, - spa_debug_type_find_name(spa_type_param, info->params[i].id), + id, spa_debug_type_find_name(spa_type_param, id), device->info.params[i].flags, info->params[i].flags); - if (device->info.params[i].flags != info->params[i].flags && - info->params[i].flags & SPA_PARAM_INFO_READ) - changed_ids[n_changed_ids++] = info->params[i].id; + if (device->info.params[i].flags == info->params[i].flags) + 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; + + if (info->params[i].flags & SPA_PARAM_INFO_READ) + changed_ids[n_changed_ids++] = id; } } emit_info_changed(device); diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index 61965a825..79173feba 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -52,7 +53,11 @@ struct impl { int last_error; + struct spa_list param_list; + struct spa_list pending_list; + unsigned int pause_on_idle:1; + unsigned int cache_params:1; }; #define pw_node_resource(r,m,v,...) pw_resource_call(r,struct pw_node_events,m,v,__VA_ARGS__) @@ -814,6 +819,11 @@ static void check_properties(struct pw_impl_node *node) else impl->pause_on_idle = true; + if ((str = pw_properties_get(node->properties, PW_KEY_NODE_CACHE_PARAMS))) + impl->cache_params = pw_properties_parse_bool(str); + else + impl->cache_params = true; + if ((str = pw_properties_get(node->properties, PW_KEY_NODE_DRIVER))) driver = pw_properties_parse_bool(str); else @@ -1071,6 +1081,9 @@ struct pw_impl_node *pw_context_create_node(struct pw_context *context, goto error_exit; } + spa_list_init(&impl->param_list); + spa_list_init(&impl->pending_list); + this = &impl->this; this->context = context; this->name = strdup("node"); @@ -1229,6 +1242,7 @@ 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; @@ -1256,16 +1270,22 @@ static void node_info(void *data, const struct spa_node_info *info) node->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(node->params)); for (i = 0; i < node->info.n_params; i++) { + uint32_t id = info->params[i].id; + pw_log_debug(NAME" %p: param %d id:%d (%s) %08x:%08x", node, i, - info->params[i].id, - spa_debug_type_find_name(spa_type_param, info->params[i].id), + id, spa_debug_type_find_name(spa_type_param, id), node->info.params[i].flags, info->params[i].flags); - if (node->info.params[i].flags != info->params[i].flags && - info->params[i].flags & SPA_PARAM_INFO_READ) - changed_ids[n_changed_ids++] = info->params[i].id; + if (node->info.params[i].flags == info->params[i].flags) + 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; + + if (info->params[i].flags & SPA_PARAM_INFO_READ) + changed_ids[n_changed_ids++] = id; } } emit_info_changed(node, flags_changed); @@ -1686,6 +1706,9 @@ void pw_impl_node_destroy(struct pw_impl_node *node) pw_work_queue_destroy(impl->work); + pw_param_clear(&impl->param_list, SPA_ID_INVALID); + pw_param_clear(&impl->pending_list, SPA_ID_INVALID); + pw_map_clear(&node->input_port_map); pw_map_clear(&node->output_port_map); @@ -1719,22 +1742,28 @@ int pw_impl_node_for_each_port(struct pw_impl_node *node, } struct result_node_params_data { + struct impl *impl; void *data; int (*callback) (void *data, int seq, uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param); int seq; + unsigned int cache:1; }; static void result_node_params(void *data, int seq, int res, uint32_t type, const void *result) { struct result_node_params_data *d = data; + struct impl *impl = d->impl; switch (type) { case SPA_RESULT_TYPE_NODE_PARAMS: { const struct spa_result_node_params *r = result; - if (d->seq == seq) + if (d->seq == seq) { d->callback(d->data, seq, r->id, r->index, r->next, r->param); + if (d->cache) + pw_param_add(&impl->pending_list, r->id, r->param); + } break; } default: @@ -1753,27 +1782,73 @@ int pw_impl_node_for_each_param(struct pw_impl_node *node, void *data) { int res; - struct result_node_params_data user_data = { data, callback, seq }; + struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); + struct result_node_params_data user_data = { impl, data, callback, seq, false }; struct spa_hook listener; + struct spa_param_info *pi; static const struct spa_node_events node_events = { SPA_VERSION_NODE_EVENTS, .result = result_node_params, }; + pi = pw_param_info_find(node->info.params, node->info.n_params, param_id); + if (pi == NULL) + return -ENOENT; + if (max == 0) max = UINT32_MAX; - pw_log_debug(NAME" %p: params id:%d (%s) index:%u max:%u", node, param_id, + pw_log_debug(NAME" %p: params id:%d (%s) index:%u max:%u cached:%d", node, param_id, spa_debug_type_find_name(spa_type_param, param_id), - index, max); + index, max, pi->user); - spa_zero(listener); - spa_node_add_listener(node->node, &listener, &node_events, &user_data); - res = spa_node_enum_params(node->node, seq, - param_id, index, max, - filter); - spa_hook_remove(&listener); + if (pi->user == 1) { + struct pw_param *p; + uint8_t buffer[1024]; + struct spa_pod_builder b = { 0 }; + struct spa_result_node_params result; + uint32_t count = 0; + bool found = false; + result.id = param_id; + result.next = 0; + + spa_list_for_each(p, &impl->param_list, link) { + result.index = result.next++; + if (p->id != param_id) + continue; + + found = true; + + if (result.index < index) + continue; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + if (spa_pod_filter(&b, &result.param, p->param, filter) != 0) + continue; + + pw_log_debug(NAME " %p: %d param %u", node, seq, result.index); + result_node_params(&user_data, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result); + + if (++count == max) + break; + } + res = found ? 0 : -ENOENT; + } else { + user_data.cache = impl->cache_params && filter == NULL; + + spa_zero(listener); + spa_node_add_listener(node->node, &listener, &node_events, &user_data); + res = spa_node_enum_params(node->node, seq, + param_id, index, max, + filter); + spa_hook_remove(&listener); + + if (user_data.cache) { + pw_param_update(&impl->param_list, &impl->pending_list); + pi->user = 1; + } + } return res; } diff --git a/src/pipewire/impl-port.c b/src/pipewire/impl-port.c index 7dc4182e4..88498ae29 100644 --- a/src/pipewire/impl-port.c +++ b/src/pipewire/impl-port.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "pipewire/impl.h" #include "pipewire/private.h" @@ -41,6 +42,11 @@ struct impl { struct pw_impl_port this; struct spa_node mix_node; /**< mix node implementation */ + + struct spa_list param_list; + struct spa_list pending_list; + + unsigned int cache_params:1; }; #define pw_port_resource(r,m,v,...) pw_resource_call(r,struct pw_port_events,m,v,__VA_ARGS__) @@ -338,8 +344,12 @@ 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, + port, info->flags, info->change_mask); + if (info->change_mask & SPA_PORT_CHANGE_MASK_FLAGS) { port->spa_flags = info->flags; } @@ -357,11 +367,22 @@ static void update_info(struct pw_impl_port *port, const struct spa_port_info *i port->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(port->params)); for (i = 0; i < port->info.n_params; i++) { - if (port->info.params[i].flags != info->params[i].flags && - info->params[i].flags & SPA_PARAM_INFO_READ) - changed_ids[n_changed_ids++] = info->params[i].id; + uint32_t id = info->params[i].id; + pw_log_debug(NAME" %p: param %d id:%d (%s) %08x:%08x", port, i, + id, spa_debug_type_find_name(spa_type_param, id), + port->info.params[i].flags, info->params[i].flags); + + if (port->info.params[i].flags == info->params[i].flags) + 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; + + if (info->params[i].flags & SPA_PARAM_INFO_READ) + changed_ids[n_changed_ids++] = id; } } @@ -387,6 +408,10 @@ struct pw_impl_port *pw_context_create_port( if (impl == NULL) return NULL; + spa_list_init(&impl->param_list); + spa_list_init(&impl->pending_list); + impl->cache_params = true; + this = &impl->this; pw_log_debug(NAME" %p: new %s %d", this, pw_direction_as_string(direction), port_id); @@ -994,6 +1019,7 @@ static void pw_impl_port_remove(struct pw_impl_port *port) void pw_impl_port_destroy(struct pw_impl_port *port) { + struct impl *impl = SPA_CONTAINER_OF(port, struct impl, this); struct pw_control *control; pw_log_debug(NAME" %p: destroy", port); @@ -1024,6 +1050,9 @@ void pw_impl_port_destroy(struct pw_impl_port *port) pw_buffers_clear(&port->mix_buffers); free((void*)port->error); + pw_param_clear(&impl->param_list, SPA_ID_INVALID); + pw_param_clear(&impl->pending_list, SPA_ID_INVALID); + pw_map_clear(&port->mix_port_map); pw_properties_free(port->properties); @@ -1032,22 +1061,28 @@ void pw_impl_port_destroy(struct pw_impl_port *port) } struct result_port_params_data { + struct impl *impl; void *data; int (*callback) (void *data, int seq, uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param); int seq; + unsigned int cache:1; }; static void result_port_params(void *data, int seq, int res, uint32_t type, const void *result) { struct result_port_params_data *d = data; + struct impl *impl = d->impl; switch (type) { case SPA_RESULT_TYPE_NODE_PARAMS: { const struct spa_result_node_params *r = result; - if (d->seq == seq) + if (d->seq == seq) { d->callback(d->data, seq, r->id, r->index, r->next, r->param); + if (d->cache) + pw_param_add(&impl->pending_list, r->id, r->param); + } break; } default: @@ -1066,28 +1101,75 @@ int pw_impl_port_for_each_param(struct pw_impl_port *port, void *data) { 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 = { data, callback, seq }; + struct result_port_params_data user_data = { impl, data, callback, seq, false }; struct spa_hook listener; + struct spa_param_info *pi; static const struct spa_node_events node_events = { SPA_VERSION_NODE_EVENTS, .result = result_port_params, }; + pi = pw_param_info_find(port->info.params, port->info.n_params, param_id); + if (pi == NULL) + return -ENOENT; + if (max == 0) max = UINT32_MAX; - pw_log_debug(NAME" %p: params id:%d (%s) index:%u max:%u", port, param_id, + pw_log_debug(NAME" %p: params id:%d (%s) index:%u max:%u cached:%d", port, param_id, spa_debug_type_find_name(spa_type_param, param_id), - index, max); + index, max, pi->user); - spa_zero(listener); - spa_node_add_listener(node->node, &listener, &node_events, &user_data); - res = spa_node_port_enum_params(node->node, seq, - port->direction, port->port_id, - param_id, index, max, - filter); - spa_hook_remove(&listener); + if (pi->user == 1) { + struct pw_param *p; + uint8_t buffer[1024]; + struct spa_pod_builder b = { 0 }; + struct spa_result_node_params result; + uint32_t count = 0; + bool found = false; + + result.id = param_id; + result.next = 0; + + spa_list_for_each(p, &impl->param_list, link) { + result.index = result.next++; + if (p->id != param_id) + continue; + + found = true; + + if (result.index < index) + continue; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + if (spa_pod_filter(&b, &result.param, p->param, filter) != 0) + continue; + + pw_log_debug(NAME " %p: %d param %u", port, seq, result.index); + result_port_params(&user_data, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result); + + if (++count == max) + break; + } + res = found ? 0 : -ENOENT; + } else { + user_data.cache = filter == NULL; + + spa_zero(listener); + spa_node_add_listener(node->node, &listener, &node_events, &user_data); + res = spa_node_port_enum_params(node->node, seq, + port->direction, port->port_id, + param_id, index, max, + filter); + spa_hook_remove(&listener); + + if (user_data.cache) { + pw_param_update(&impl->param_list, &impl->pending_list); + pi->user = 1; + } + } pw_log_debug(NAME" %p: res %d: (%s)", port, res, spa_strerror(res)); return res; diff --git a/src/pipewire/keys.h b/src/pipewire/keys.h index 392ba2ab4..88c9ee12f 100644 --- a/src/pipewire/keys.h +++ b/src/pipewire/keys.h @@ -142,6 +142,7 @@ extern "C" { #define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect" /**< don't reconnect this node */ #define PW_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< process even when unlinked */ #define PW_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< pause the node when idle */ +#define PW_KEY_NODE_CACHE_PARAMS "node.cache-params" /**< cache the node params */ #define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph */ #define PW_KEY_NODE_STREAM "node.stream" /**< node is a stream, the server side should * add a converter */ @@ -155,6 +156,7 @@ extern "C" { #define PW_KEY_PORT_TERMINAL "port.terminal" /**< if this port consumes the data */ #define PW_KEY_PORT_CONTROL "port.control" /**< if this port is a control port */ #define PW_KEY_PORT_MONITOR "port.monitor" /**< if this port is a monitor port */ +#define PW_KEY_PORT_CACHE_PARAMS "port.cache-params" /**< cache the node port params */ /** link properties */ #define PW_KEY_LINK_ID "link.id" /**< a link id */ @@ -202,6 +204,7 @@ extern "C" { * roles (see PW_KEY_MEDIA_ROLE) this device * is particularly well suited for, due to * latency, quality or form factor. */ +#define PW_KEY_DEVICE_CACHE_PARAMS "device.cache-params" /**< cache the device spa params */ /** module properties */ #define PW_KEY_MODULE_ID "module.id" /**< the module id */ diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 6e8531c7c..044bcbcf9 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -84,6 +84,73 @@ static inline bool ratelimit_test(struct ratelimit *r, uint64_t now) #define MAX_PARAMS 32 +struct pw_param { + uint32_t id; + struct spa_list link; + 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; + 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 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); + } +} + +static inline struct spa_param_info *pw_param_info_find(struct spa_param_info info[], + uint32_t n_info, uint32_t id) +{ + uint32_t i; + for (i = 0; i < n_info; i++) { + if (info[i].id == id) + return &info[i]; + } + return NULL; +} + #define pw_protocol_emit_destroy(p) spa_hook_list_call(&p->listener_list, struct pw_protocol_events, destroy, 0) struct pw_protocol {