diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c index e243259ba..7d20af1e9 100644 --- a/pipewire-jack/src/pipewire-jack.c +++ b/pipewire-jack/src/pipewire-jack.c @@ -194,6 +194,7 @@ struct mix { struct spa_list link; struct spa_list port_link; uint32_t id; + uint32_t peer_id; struct port *port; struct spa_io_buffers *io; @@ -347,6 +348,7 @@ struct client { uint32_t buffer_frames; struct spa_fraction latency; + struct spa_list mix; struct spa_list free_mix; uint32_t n_port_pool[2]; @@ -456,6 +458,15 @@ static void init_mix(struct mix *mix, uint32_t mix_id, struct port *port) if (mix_id == SPA_ID_INVALID) port->global_mix = mix; } +static struct mix *find_mix_peer(struct client *c, uint32_t peer_id) +{ + struct mix *mix; + spa_list_for_each(mix, &c->mix, link) { + 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) { @@ -485,6 +496,7 @@ static struct mix *ensure_mix(struct client *c, struct port *port, uint32_t mix_ } mix = spa_list_first(&c->free_mix, struct mix, link); spa_list_remove(&mix->link); + spa_list_append(&c->mix, &mix->link); spa_list_append(&port->mix, &mix->port_link); @@ -520,6 +532,7 @@ static void free_mix(struct client *c, struct mix *mix) spa_list_remove(&mix->port_link); if (mix->id == SPA_ID_INVALID) mix->port->global_mix = NULL; + spa_list_remove(&mix->link); spa_list_append(&c->free_mix, &mix->link); } @@ -2253,6 +2266,35 @@ static int client_node_set_activation(void *object, return res; } +static int client_node_port_set_mix_info(void *object, + enum spa_direction direction, + uint32_t port_id, + uint32_t mix_id, + uint32_t peer_id, + const struct spa_dict *props) +{ + struct client *c = (struct client *) object; + struct port *p = GET_PORT(c, direction, port_id); + struct mix *mix; + int res = 0; + + if (p == NULL || !p->valid) { + res = -EINVAL; + goto exit; + } + + if ((mix = ensure_mix(c, p, mix_id)) == NULL) { + res = -ENOMEM; + goto exit; + } + mix->peer_id = peer_id; + +exit: + if (res < 0) + pw_proxy_error((struct pw_proxy*)c->node, res, spa_strerror(res)); + return res; +} + static const struct pw_client_node_events client_node_events = { PW_VERSION_CLIENT_NODE_EVENTS, .transport = client_node_transport, @@ -2266,6 +2308,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 jack_port_type_id_t string_to_type(const char *port_type) @@ -2960,6 +3003,7 @@ jack_client_t * jack_client_open (const char *client_name, client->sample_rate = (uint32_t)-1; client->latency = SPA_FRACTION(-1, -1); + spa_list_init(&client->mix); spa_list_init(&client->free_mix); init_port_pool(client, SPA_DIRECTION_INPUT); @@ -3928,25 +3972,34 @@ done: return res; } +static struct buffer *get_mix_buffer(struct mix *mix) +{ + struct spa_io_buffers *io; + + io = mix->io; + if (io == NULL || + io->status != SPA_STATUS_HAVE_DATA || + io->buffer_id >= mix->n_buffers) + return NULL; + + return &mix->buffers[io->buffer_id]; +} + static void *get_buffer_input_float(struct port *p, jack_nframes_t frames) { struct mix *mix; struct buffer *b; - struct spa_io_buffers *io; int layer = 0; void *ptr = NULL; spa_list_for_each(mix, &p->mix, port_link) { pw_log_trace_fp(NAME" %p: port %p mix %d.%d get buffer %d", p->client, p, p->id, mix->id, frames); - io = mix->io; - if (io == NULL || - io->status != SPA_STATUS_HAVE_DATA || - io->buffer_id >= mix->n_buffers) + + if ((b = get_mix_buffer(mix)) == NULL) continue; - io->status = SPA_STATUS_NEED_DATA; - b = &mix->buffers[io->buffer_id]; + mix->io->status = SPA_STATUS_NEED_DATA; if (layer++ == 0) ptr = b->datas[0].data; else { @@ -4034,8 +4087,17 @@ void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames) spa_return_val_if_fail(o != NULL, NULL); - if ((p = o->port.port) == NULL) - return NULL; + if ((p = o->port.port) == NULL) { + struct mix *mix; + struct buffer *b; + + if ((mix = find_mix_peer(o->client, o->id)) == NULL) + return NULL; + if ((b = get_mix_buffer(mix)) == NULL) + return NULL; + pw_log_trace("peer mix: %p %d", mix, mix->peer_id); + return b->datas[0].data; + } ptr = p->get_buffer(p, frames); pw_log_trace_fp(NAME" %p: port %p buffer %p empty:%u", p->client, p, ptr, p->empty_out);