mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -05:00
client-node: store mix in pw_map so that they are not copied
struct mix contain pointers to themselves (see do_port_use_buffers) and cannot be copied by value, so they should not be stored in pw_array. Store them in pw_map instead.
This commit is contained in:
parent
44bfeaac6e
commit
7f5f88c04a
1 changed files with 73 additions and 46 deletions
|
|
@ -49,7 +49,6 @@ struct buffer {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mix {
|
struct mix {
|
||||||
unsigned int valid:1;
|
|
||||||
uint32_t mix_id;
|
uint32_t mix_id;
|
||||||
struct port *port;
|
struct port *port;
|
||||||
uint32_t peer_id;
|
uint32_t peer_id;
|
||||||
|
|
@ -79,7 +78,7 @@ struct port {
|
||||||
unsigned int removed:1;
|
unsigned int removed:1;
|
||||||
unsigned int destroyed:1;
|
unsigned int destroyed:1;
|
||||||
|
|
||||||
struct pw_array mix;
|
struct pw_map mix;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct impl {
|
struct impl {
|
||||||
|
|
@ -191,42 +190,62 @@ do_port_use_buffers(struct impl *impl,
|
||||||
|
|
||||||
static struct mix *find_mix(struct port *p, uint32_t mix_id)
|
static struct mix *find_mix(struct port *p, uint32_t mix_id)
|
||||||
{
|
{
|
||||||
struct mix *mix;
|
if (mix_id == SPA_ID_INVALID)
|
||||||
|
mix_id = 0;
|
||||||
|
else
|
||||||
|
mix_id++;
|
||||||
|
|
||||||
|
return pw_map_lookup(&p->mix, mix_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mix *create_mix(struct port *p, uint32_t mix_id)
|
||||||
|
{
|
||||||
|
struct mix *mix = NULL;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (mix_id == SPA_ID_INVALID)
|
if (mix_id == SPA_ID_INVALID)
|
||||||
mix_id = 0;
|
mix_id = 0;
|
||||||
else
|
else
|
||||||
mix_id++;
|
mix_id++;
|
||||||
|
|
||||||
len = pw_array_get_len(&p->mix, struct mix);
|
if (pw_map_lookup(&p->mix, mix_id) != NULL) {
|
||||||
if (mix_id >= len) {
|
errno = EEXIST;
|
||||||
size_t need = sizeof(struct mix) * (mix_id + 1 - len);
|
|
||||||
void *ptr = pw_array_add(&p->mix, need);
|
|
||||||
if (ptr == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
memset(ptr, 0, need);
|
|
||||||
}
|
}
|
||||||
mix = pw_array_get_unchecked(&p->mix, mix_id, struct mix);
|
|
||||||
return mix;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mix_init(struct mix *mix, struct port *p, uint32_t mix_id)
|
/* pad map size */
|
||||||
{
|
for (len = pw_map_get_size(&p->mix); len < mix_id; ++len)
|
||||||
mix->valid = true;
|
if ((res = pw_map_insert_at(&p->mix, len, NULL)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
mix = calloc(1, sizeof(struct mix));
|
||||||
|
if (mix == NULL)
|
||||||
|
return NULL;
|
||||||
|
if ((res = pw_map_insert_at(&p->mix, mix_id, mix)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
mix->mix_id = mix_id;
|
mix->mix_id = mix_id;
|
||||||
mix->port = p;
|
mix->port = p;
|
||||||
mix->n_buffers = 0;
|
mix->n_buffers = 0;
|
||||||
|
return mix;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(mix);
|
||||||
|
errno = -res;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mix *create_mix(struct impl *impl, struct port *p, uint32_t mix_id)
|
static void free_mix(struct port *p, struct mix *mix)
|
||||||
{
|
{
|
||||||
struct mix *mix;
|
if (mix == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if ((mix = find_mix(p, mix_id)) == NULL || mix->valid)
|
/* never realloc so it's safe to call from pw_map_foreach */
|
||||||
return NULL;
|
if (mix->mix_id < pw_map_get_size(&p->mix))
|
||||||
mix_init(mix, p, mix_id);
|
pw_map_insert_at(&p->mix, mix->mix_id, NULL);
|
||||||
return mix;
|
|
||||||
|
free(mix);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_data(struct impl *impl, struct spa_data *d)
|
static void clear_data(struct impl *impl, struct spa_data *d)
|
||||||
|
|
@ -280,11 +299,10 @@ static void mix_clear(struct impl *impl, struct mix *mix)
|
||||||
{
|
{
|
||||||
struct port *port = mix->port;
|
struct port *port = mix->port;
|
||||||
|
|
||||||
if (!mix->valid)
|
|
||||||
return;
|
|
||||||
do_port_use_buffers(impl, port->direction, port->id,
|
do_port_use_buffers(impl, port->direction, port->id,
|
||||||
mix->mix_id, 0, NULL, 0);
|
mix->mix_id, 0, NULL, 0);
|
||||||
mix->valid = false;
|
|
||||||
|
free_mix(port, mix);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int impl_node_enum_params(void *object, int seq,
|
static int impl_node_enum_params(void *object, int seq,
|
||||||
|
|
@ -498,21 +516,25 @@ do_update_port(struct impl *impl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mix_clear_cb(void *item, void *data)
|
||||||
|
{
|
||||||
|
if (item)
|
||||||
|
mix_clear(data, item);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clear_port(struct impl *impl, struct port *port)
|
clear_port(struct impl *impl, struct port *port)
|
||||||
{
|
{
|
||||||
struct mix *mix;
|
|
||||||
|
|
||||||
spa_log_debug(impl->log, "%p: clear port %p", impl, port);
|
spa_log_debug(impl->log, "%p: clear port %p", impl, port);
|
||||||
|
|
||||||
do_update_port(impl, port,
|
do_update_port(impl, port,
|
||||||
PW_CLIENT_NODE_PORT_UPDATE_PARAMS |
|
PW_CLIENT_NODE_PORT_UPDATE_PARAMS |
|
||||||
PW_CLIENT_NODE_PORT_UPDATE_INFO, 0, NULL, NULL);
|
PW_CLIENT_NODE_PORT_UPDATE_INFO, 0, NULL, NULL);
|
||||||
|
|
||||||
pw_array_for_each(mix, &port->mix)
|
pw_map_for_each(&port->mix, mix_clear_cb, impl);
|
||||||
mix_clear(impl, mix);
|
pw_map_clear(&port->mix);
|
||||||
pw_array_clear(&port->mix);
|
pw_map_init(&port->mix, 0, 2);
|
||||||
pw_array_init(&port->mix, sizeof(struct mix) * 2);
|
|
||||||
|
|
||||||
pw_map_insert_at(&impl->ports[port->direction], port->id, NULL);
|
pw_map_insert_at(&impl->ports[port->direction], port->id, NULL);
|
||||||
|
|
||||||
|
|
@ -606,6 +628,13 @@ impl_node_port_enum_params(void *object, int seq,
|
||||||
return found ? 0 : -ENOENT;
|
return found ? 0 : -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int clear_buffers_cb(void *item, void *data)
|
||||||
|
{
|
||||||
|
if (item)
|
||||||
|
clear_buffers(data, item);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
impl_node_port_set_param(void *object,
|
impl_node_port_set_param(void *object,
|
||||||
enum spa_direction direction, uint32_t port_id,
|
enum spa_direction direction, uint32_t port_id,
|
||||||
|
|
@ -614,7 +643,6 @@ impl_node_port_set_param(void *object,
|
||||||
{
|
{
|
||||||
struct impl *impl = object;
|
struct impl *impl = object;
|
||||||
struct port *port;
|
struct port *port;
|
||||||
struct mix *mix;
|
|
||||||
|
|
||||||
spa_return_val_if_fail(impl != NULL, -EINVAL);
|
spa_return_val_if_fail(impl != NULL, -EINVAL);
|
||||||
|
|
||||||
|
|
@ -626,10 +654,9 @@ impl_node_port_set_param(void *object,
|
||||||
direction, port_id,
|
direction, port_id,
|
||||||
spa_debug_type_find_name(spa_type_param, id), id);
|
spa_debug_type_find_name(spa_type_param, id), id);
|
||||||
|
|
||||||
if (id == SPA_PARAM_Format) {
|
if (id == SPA_PARAM_Format)
|
||||||
pw_array_for_each(mix, &port->mix)
|
pw_map_for_each(&port->mix, clear_buffers_cb, impl);
|
||||||
clear_buffers(impl, mix);
|
|
||||||
}
|
|
||||||
if (impl->resource == NULL)
|
if (impl->resource == NULL)
|
||||||
return param == NULL ? 0 : -EIO;
|
return param == NULL ? 0 : -EIO;
|
||||||
|
|
||||||
|
|
@ -658,7 +685,7 @@ static int do_port_set_io(struct impl *impl,
|
||||||
if (port == NULL)
|
if (port == NULL)
|
||||||
return data == NULL ? 0 : -EINVAL;
|
return data == NULL ? 0 : -EINVAL;
|
||||||
|
|
||||||
if ((mix = find_mix(port, mix_id)) == NULL || !mix->valid)
|
if ((mix = find_mix(port, mix_id)) == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
old = pw_mempool_find_tag(impl->client_pool, tag, sizeof(tag));
|
old = pw_mempool_find_tag(impl->client_pool, tag, sizeof(tag));
|
||||||
|
|
@ -731,7 +758,7 @@ do_port_use_buffers(struct impl *impl,
|
||||||
if (direction == SPA_DIRECTION_OUTPUT)
|
if (direction == SPA_DIRECTION_OUTPUT)
|
||||||
mix_id = SPA_ID_INVALID;
|
mix_id = SPA_ID_INVALID;
|
||||||
|
|
||||||
if ((mix = find_mix(p, mix_id)) == NULL || !mix->valid)
|
if ((mix = find_mix(p, mix_id)) == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
clear_buffers(impl, mix);
|
clear_buffers(impl, mix);
|
||||||
|
|
@ -1019,7 +1046,7 @@ static int client_node_port_buffers(void *data,
|
||||||
if (direction == SPA_DIRECTION_OUTPUT)
|
if (direction == SPA_DIRECTION_OUTPUT)
|
||||||
mix_id = SPA_ID_INVALID;
|
mix_id = SPA_ID_INVALID;
|
||||||
|
|
||||||
if ((mix = find_mix(p, mix_id)) == NULL || !mix->valid)
|
if ((mix = find_mix(p, mix_id)) == NULL)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
|
|
||||||
if (mix->n_buffers != n_buffers)
|
if (mix->n_buffers != n_buffers)
|
||||||
|
|
@ -1383,12 +1410,12 @@ static int port_init_mix(void *data, struct pw_impl_port_mix *mix)
|
||||||
uint32_t idx, pos, len;
|
uint32_t idx, pos, len;
|
||||||
struct pw_memblock *area;
|
struct pw_memblock *area;
|
||||||
|
|
||||||
if ((m = create_mix(impl, port, mix->port.port_id)) == NULL)
|
if ((m = create_mix(port, mix->port.port_id)) == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
mix->id = pw_map_insert_new(&impl->io_map, NULL);
|
mix->id = pw_map_insert_new(&impl->io_map, NULL);
|
||||||
if (mix->id == SPA_ID_INVALID) {
|
if (mix->id == SPA_ID_INVALID) {
|
||||||
m->valid = false;
|
free_mix(port, m);
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1422,7 +1449,7 @@ static int port_init_mix(void *data, struct pw_impl_port_mix *mix)
|
||||||
return 0;
|
return 0;
|
||||||
no_mem:
|
no_mem:
|
||||||
pw_map_remove(&impl->io_map, mix->id);
|
pw_map_remove(&impl->io_map, mix->id);
|
||||||
m->valid = false;
|
free_mix(port, m);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1435,7 +1462,7 @@ static int port_release_mix(void *data, struct pw_impl_port_mix *mix)
|
||||||
pw_log_debug("%p: remove mix id:%d io:%p",
|
pw_log_debug("%p: remove mix id:%d io:%p",
|
||||||
impl, mix->id, mix->io);
|
impl, mix->id, mix->io);
|
||||||
|
|
||||||
if ((m = find_mix(port, mix->port.port_id)) == NULL || !m->valid)
|
if ((m = find_mix(port, mix->port.port_id)) == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (impl->resource && impl->resource->version >= 4)
|
if (impl->resource && impl->resource->version >= 4)
|
||||||
|
|
@ -1444,7 +1471,7 @@ static int port_release_mix(void *data, struct pw_impl_port_mix *mix)
|
||||||
mix->port.port_id, SPA_ID_INVALID, NULL);
|
mix->port.port_id, SPA_ID_INVALID, NULL);
|
||||||
|
|
||||||
pw_map_remove(&impl->io_map, mix->id);
|
pw_map_remove(&impl->io_map, mix->id);
|
||||||
m->valid = false;
|
free_mix(port, m);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1571,12 +1598,12 @@ static void node_port_init(void *data, struct pw_impl_port *port)
|
||||||
p->direction = port->direction;
|
p->direction = port->direction;
|
||||||
p->id = port->port_id;
|
p->id = port->port_id;
|
||||||
p->impl = impl;
|
p->impl = impl;
|
||||||
pw_array_init(&p->mix, sizeof(struct mix) * 2);
|
pw_map_init(&p->mix, 2, 2);
|
||||||
p->mix_node.iface = SPA_INTERFACE_INIT(
|
p->mix_node.iface = SPA_INTERFACE_INIT(
|
||||||
SPA_TYPE_INTERFACE_Node,
|
SPA_TYPE_INTERFACE_Node,
|
||||||
SPA_VERSION_NODE,
|
SPA_VERSION_NODE,
|
||||||
&impl_port_mix, p);
|
&impl_port_mix, p);
|
||||||
create_mix(impl, p, SPA_ID_INVALID);
|
create_mix(p, SPA_ID_INVALID);
|
||||||
|
|
||||||
pw_map_insert_at(&impl->ports[p->direction], p->id, p);
|
pw_map_insert_at(&impl->ports[p->direction], p->id, p);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue