seq: rework port handling

Dynamically allocate ports as we need them.
Use port lists to iterate active ports.
This commit is contained in:
Wim Taymans 2025-07-30 17:32:02 +02:00
parent 8f45cfcbc9
commit 6d07eaea1f
3 changed files with 102 additions and 71 deletions

View file

@ -294,13 +294,9 @@ static void emit_port_info(struct seq_state *this, struct seq_port *port, bool f
static void emit_stream_info(struct seq_state *this, struct seq_stream *stream, bool full)
{
uint32_t i;
for (i = 0; i < MAX_PORTS; i++) {
struct seq_port *port = &stream->ports[i];
if (port->valid)
emit_port_info(this, port, full);
}
struct seq_port *port;
spa_list_for_each(port, &stream->port_list, link)
emit_port_info(this, port, full);
}
static int
@ -353,11 +349,9 @@ static int impl_node_sync(void *object, int seq)
static struct seq_port *find_port(struct seq_state *state,
struct seq_stream *stream, const snd_seq_addr_t *addr)
{
uint32_t i;
for (i = 0; i < stream->last_port; i++) {
struct seq_port *port = &stream->ports[i];
if (port->valid &&
port->addr.client == addr->client &&
struct seq_port *port;
spa_list_for_each(port, &stream->port_list, link) {
if (port->addr.client == addr->client &&
port->addr.port == addr->port)
return port;
}
@ -366,32 +360,36 @@ static struct seq_port *find_port(struct seq_state *state,
static struct seq_port *alloc_port(struct seq_state *state, struct seq_stream *stream)
{
struct seq_port *port;
uint32_t i;
for (i = 0; i < MAX_PORTS; i++) {
struct seq_port *port = &stream->ports[i];
if (!port->valid) {
port->id = i;
port->direction = stream->direction;
port->valid = true;
if (stream->last_port < i + 1)
stream->last_port = i + 1;
return port;
}
if (stream->ports[i] == NULL)
break;
}
return NULL;
if (i == MAX_PORTS)
return NULL;
if (!spa_list_is_empty(&state->free_list)) {
port = spa_list_first(&state->free_list, struct seq_port, link);
spa_list_remove(&port->link);
} else {
port = calloc(1, sizeof(struct seq_port));
if (port == NULL)
return NULL;
}
port->id = i;
port->direction = stream->direction;
stream->ports[i] = port;
spa_list_append(&stream->port_list, &port->link);
return port;
}
static void free_port(struct seq_state *state, struct seq_stream *stream, struct seq_port *port)
{
port->valid = false;
if (port->id + 1 == stream->last_port) {
int i;
for (i = stream->last_port - 1; i >= 0; i--)
if (stream->ports[i].valid)
break;
stream->last_port = i + 1;
}
stream->ports[port->id] = NULL;
spa_list_remove(&port->link);
spa_list_append(&state->free_list, &port->link);
spa_node_emit_port_info(&state->hooks,
port->direction, port->id, NULL);
@ -751,6 +749,36 @@ impl_node_port_use_buffers(void *object,
return 0;
}
struct io_info {
struct seq_state *state;
struct seq_port *port;
void *data;
size_t size;
};
static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq,
const void *data, size_t size, void *user_data)
{
struct io_info *info = user_data;
struct seq_port *port = info->port;
struct seq_stream *stream = &info->state->streams[port->direction];
if (info->data == NULL || info->size < sizeof(struct spa_io_buffers)) {
port->io = NULL;
if (port->mixing) {
spa_list_remove(&port->mix_link);
port->mixing = false;
}
} else {
port->io = info->data;
if (!port->mixing) {
spa_list_append(&stream->mix_list, &port->mix_link);
port->mixing = true;
}
}
return 0;
}
static int
impl_node_port_set_io(void *object,
enum spa_direction direction,
@ -760,19 +788,25 @@ impl_node_port_set_io(void *object,
{
struct seq_state *this = object;
struct seq_port *port;
struct io_info info;
spa_return_val_if_fail(this != NULL, -EINVAL);
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
port = GET_PORT(this, direction, port_id);
info.state = this;
info.port = port;
info.data = data;
info.size = size;
spa_log_debug(this->log, "%p: io %d.%d %d %p %zd", this,
direction, port_id, id, data, size);
switch (id) {
case SPA_IO_Buffers:
port->io = data;
spa_loop_locked(this->data_loop,
do_port_set_io, SPA_ID_INVALID, NULL, 0, &info);
break;
default:
return -ENOENT;