From 1ce94628ee3cb43e8b108387151391dab0a269bb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jun 2023 20:09:29 +0200 Subject: [PATCH] client-node: rework mix_info Use the port_set_mix_info to add and remove mix info information to the client. Previously it was impossible to clean up mix_info. With this change we can also simplify the jack peer port detection. Because the mix info is always sent before the link appears we can simply look up the info when the link appears. --- pipewire-jack/src/pipewire-jack.c | 83 +++++++++----------- src/modules/module-client-node/client-node.c | 16 ++-- src/modules/module-client-node/remote-node.c | 58 ++++++++++---- 3 files changed, 90 insertions(+), 67 deletions(-) diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c index e0b8e4452..1ec1d4a61 100644 --- a/pipewire-jack/src/pipewire-jack.c +++ b/pipewire-jack/src/pipewire-jack.c @@ -142,7 +142,6 @@ struct object { uint32_t dst_serial; bool src_ours; bool dst_ours; - bool is_complete; struct port *our_input; struct port *our_output; } port_link; @@ -541,6 +540,17 @@ static struct mix *find_mix_peer(struct client *c, uint32_t peer_id) return NULL; } +static struct mix *find_port_peer(struct port *port, uint32_t peer_id) +{ + struct mix *mix; + spa_list_for_each(mix, &port->mix, port_link) { + pw_log_info("%p %d %d", port, mix->peer_id, peer_id); + if (mix->peer_id == peer_id) + return mix; + } + return NULL; +} + static struct mix *find_mix(struct client *c, struct port *port, uint32_t mix_id) { struct mix *mix; @@ -2766,8 +2776,6 @@ static int client_node_port_set_mix_info(void *data, struct client *c = (struct client *) data; struct port *p = GET_PORT(c, direction, port_id); struct mix *mix; - struct object *l; - uint32_t src, dst; int res = 0; if (p == NULL || !p->valid) { @@ -2775,40 +2783,21 @@ static int client_node_port_set_mix_info(void *data, goto exit; } - if ((mix = ensure_mix(c, p, mix_id)) == NULL) { - res = -ENOMEM; - goto exit; - } - mix->peer_id = peer_id; + mix = find_mix(c, p, mix_id); - if (direction == SPA_DIRECTION_INPUT) { - src = peer_id; - dst = p->object->id; - } else { - src = p->object->id; - dst = peer_id; - } - - if ((l = find_link(c, src, dst)) != NULL) { - if (direction == SPA_DIRECTION_INPUT) - mix->peer_port = l->port_link.our_output; - else - mix->peer_port = l->port_link.our_input; - - pw_log_debug("peer port %p %p %p", mix->peer_port, - l->port_link.our_output, l->port_link.our_input); - - if (!l->port_link.is_complete) { - l->port_link.is_complete = true; - pw_log_info("%p: our link %u/%u -> %u/%u completed", c, - l->port_link.src, l->port_link.src_serial, - l->port_link.dst, l->port_link.dst_serial); - queue_notify(c, NOTIFY_TYPE_CONNECT, l, 1, NULL); - queue_notify(c, NOTIFY_TYPE_GRAPH, NULL, 0, NULL); - emit_callbacks(c); + if (peer_id == SPA_ID_INVALID) { + if (mix == NULL) { + res = -ENOENT; + goto exit; } + free_mix(c, mix); + } else { + if (mix != NULL) { + res = -EEXIST; + goto exit; + } + mix = create_mix(c, p, mix_id, peer_id); } - exit: if (res < 0) pw_proxy_error((struct pw_proxy*)c->node, res, spa_strerror(res)); @@ -3366,7 +3355,16 @@ static void registry_event_global(void *data, uint32_t id, if (o->port_link.dst_ours) o->port_link.our_input = p->port.port; - o->port_link.is_complete = !o->port_link.src_ours && !o->port_link.dst_ours; + if (o->port_link.our_input != NULL && + o->port_link.our_output != NULL) { + struct mix *mix; + mix = find_port_peer(o->port_link.our_output, o->port_link.dst); + if (mix != NULL) + mix->peer_port = o->port_link.our_input; + mix = find_port_peer(o->port_link.our_input, o->port_link.src); + if (mix != NULL) + mix->peer_port = o->port_link.our_output; + } pw_log_debug("%p: add link %d %u/%u->%u/%u", c, id, o->port_link.src, o->port_link.src_serial, o->port_link.dst, o->port_link.dst_serial); @@ -3427,14 +3425,11 @@ static void registry_event_global(void *data, uint32_t id, break; case INTERFACE_Link: - pw_log_info("%p: link %u %u/%u -> %u/%u added complete:%d", c, + pw_log_info("%p: link %u %u/%u -> %u/%u added", c, o->id, o->port_link.src, o->port_link.src_serial, - o->port_link.dst, o->port_link.dst_serial, - o->port_link.is_complete); - if (o->port_link.is_complete) { - queue_notify(c, NOTIFY_TYPE_CONNECT, o, 1, NULL); - queue_notify(c, NOTIFY_TYPE_GRAPH, NULL, 0, NULL); - } + o->port_link.dst, o->port_link.dst_serial); + queue_notify(c, NOTIFY_TYPE_CONNECT, o, 1, NULL); + queue_notify(c, NOTIFY_TYPE_GRAPH, NULL, 0, NULL); break; } emit_callbacks(c); @@ -3482,13 +3477,11 @@ static void registry_event_global_remove(void *data, uint32_t id) queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, o, 0, NULL); break; case INTERFACE_Link: - if (o->port_link.is_complete && - find_type(c, o->port_link.src, INTERFACE_Port, true) != NULL && + if (find_type(c, o->port_link.src, INTERFACE_Port, true) != NULL && find_type(c, o->port_link.dst, INTERFACE_Port, true) != NULL) { pw_log_info("%p: link %u %u/%u -> %u/%u removed", c, o->id, o->port_link.src, o->port_link.src_serial, o->port_link.dst, o->port_link.dst_serial); - o->port_link.is_complete = false; queue_notify(c, NOTIFY_TYPE_CONNECT, o, 0, NULL); queue_notify(c, NOTIFY_TYPE_GRAPH, NULL, 0, NULL); } else { diff --git a/src/modules/module-client-node/client-node.c b/src/modules/module-client-node/client-node.c index cb6a993ea..64c82fe3c 100644 --- a/src/modules/module-client-node/client-node.c +++ b/src/modules/module-client-node/client-node.c @@ -1408,6 +1408,11 @@ static int port_init_mix(void *data, struct pw_impl_port_mix *mix) m->peer_id = mix->peer_id; + if (impl->resource && impl->resource->version >= 4) + pw_client_node_resource_port_set_mix_info(impl->resource, + mix->port.direction, mix->p->port_id, + mix->port.port_id, mix->peer_id, NULL); + pw_log_debug("%p: init mix id:%d io:%p base:%p", impl, mix->id, mix->io, area->map->ptr); @@ -1430,6 +1435,11 @@ static int port_release_mix(void *data, struct pw_impl_port_mix *mix) if ((m = find_mix(port, mix->port.port_id)) == NULL || !m->valid) return -EINVAL; + if (impl->resource && impl->resource->version >= 4) + pw_client_node_resource_port_set_mix_info(impl->resource, + mix->port.direction, mix->p->port_id, + mix->port.port_id, SPA_ID_INVALID, NULL); + pw_map_remove(&impl->io_map, mix->id); m->valid = false; @@ -1515,13 +1525,7 @@ static int impl_mix_port_set_io(void *object, mix->io = data; else mix->io = NULL; - - if (mix->io != NULL && impl->resource && impl->resource->version >= 4) - pw_client_node_resource_port_set_mix_info(impl->resource, - direction, port->port_id, - mix->port.port_id, mix->peer_id, NULL); } - return do_port_set_io(impl, direction, port->port_id, mix->port.port_id, id, data, size); diff --git a/src/modules/module-client-node/remote-node.c b/src/modules/module-client-node/remote-node.c index b3a13d2d0..51e8707eb 100644 --- a/src/modules/module-client-node/remote-node.c +++ b/src/modules/module-client-node/remote-node.c @@ -896,6 +896,47 @@ error_exit: return res; } +static void clear_mix(struct node_data *data, struct mix *mix) +{ + pw_log_debug("port %p: mix clear %d.%d", mix->port, mix->port->port_id, mix->mix_id); + + spa_node_port_set_io(mix->port->mix, mix->mix.port.direction, + mix->mix.port.port_id, SPA_IO_Buffers, NULL, 0); + + spa_list_remove(&mix->link); + + clear_buffers(data, mix); + pw_array_clear(&mix->buffers); + + spa_list_append(&data->free_mix, &mix->link); + pw_impl_port_release_mix(mix->port, &mix->mix); +} + +static int client_node_port_set_mix_info(void *_data, + enum spa_direction direction, uint32_t port_id, + uint32_t mix_id, uint32_t peer_id, const struct spa_dict *props) +{ + struct node_data *data = _data; + struct mix *mix; + + pw_log_debug("%p: %d:%d:%d peer:%d", data, direction, port_id, mix_id, peer_id); + + mix = find_mix(data, direction, port_id, mix_id); + + if (peer_id == SPA_ID_INVALID) { + if (mix == NULL) + return -EINVAL; + clear_mix(data, mix); + } else { + if (mix != NULL) + return -EEXIST; + mix = create_mix(data, direction, port_id, mix_id, peer_id); + if (mix == NULL) + return -errno; + } + return 0; +} + static const struct pw_client_node_events client_node_events = { PW_VERSION_CLIENT_NODE_EVENTS, .transport = client_node_transport, @@ -909,6 +950,7 @@ static const struct pw_client_node_events client_node_events = { .port_use_buffers = client_node_port_use_buffers, .port_set_io = client_node_port_set_io, .set_activation = client_node_set_activation, + .port_set_mix_info = client_node_port_set_mix_info, }; static void do_node_init(struct node_data *data) @@ -934,22 +976,6 @@ static void do_node_init(struct node_data *data) } } -static void clear_mix(struct node_data *data, struct mix *mix) -{ - pw_log_debug("port %p: mix clear %d.%d", mix->port, mix->port->port_id, mix->mix_id); - - spa_node_port_set_io(mix->port->mix, mix->mix.port.direction, - mix->mix.port.port_id, SPA_IO_Buffers, NULL, 0); - - spa_list_remove(&mix->link); - - clear_buffers(data, mix); - pw_array_clear(&mix->buffers); - - spa_list_append(&data->free_mix, &mix->link); - pw_impl_port_release_mix(mix->port, &mix->mix); -} - static void clean_node(struct node_data *d) { struct mix *mix;