jack: use port_set_mix_info

Use the port_set_mix_info event to get the id of the peer port for the
mixer input.

When asked for the buffer of one of those peer ports, we can get it from
the mixer input buffers.

Fixes #1471
This commit is contained in:
Wim Taymans 2021-08-03 17:39:14 +02:00
parent bba8c5daa3
commit 99359c3998
1 changed files with 71 additions and 9 deletions

View File

@ -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);