From 65a5fa0250bedbe5cb8f9dd0dc6d21017a356b80 Mon Sep 17 00:00:00 2001 From: Torkel Niklasson Date: Fri, 12 Jun 2026 15:44:37 +0200 Subject: [PATCH] audioconvert: allocate port buffers dynamically The port buffer table was embedded in struct port as a fixed array buffers[MAX_BUFFERS] of struct buffer, each holding datas[MAX_DATAS] (MAX_DATAS == SPA_AUDIO_MAX_CHANNELS == 64). This reserved ~17 KB per port regardless of the actual buffer/channel count, multiplied by every active port. Allocate the buffer table and the per-buffer data-pointer pool in a single calloc in port_use_buffers(), sized to the real number of buffers and blocks, and release it in clear_buffers(). free_dir() now clears each port so the allocation (and any mmapped buffer data) is released on node destruction. This mirrors the dynamic-allocation approach already used for the channelmix matrices and preserves a lot of memory in the common low-channel-count case. Co-authored-by: Copilot copilot@github.com --- spa/plugins/audioconvert/audioconvert.c | 35 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index 812ce5ecd..e086c30a7 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -140,7 +140,7 @@ struct buffer { uint32_t flags; struct spa_list link; struct spa_buffer *buf; - void *datas[MAX_DATAS]; + void **datas; }; struct port { @@ -162,7 +162,7 @@ struct port { struct spa_param_info params[N_PORT_PARAMS]; char position[16]; - struct buffer buffers[MAX_BUFFERS]; + struct buffer *buffers; uint32_t n_buffers; struct spa_latency_info latency[2]; @@ -3051,6 +3051,8 @@ static int clear_buffers(struct impl *this, struct port *port) SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_MAPPED); } } + free(port->buffers); + port->buffers = NULL; port->n_buffers = 0; spa_list_init(&port->queue); return 0; @@ -3351,6 +3353,21 @@ impl_node_port_use_buffers(void *object, maxsize = this->quantum_limit * sizeof(float); + if (n_buffers > 0) { + void **datas; + size_t buffers_size = n_buffers * sizeof(struct buffer); + + port->buffers = calloc(1, buffers_size + + n_buffers * port->blocks * sizeof(void*)); + if (port->buffers == NULL) { + res = -errno; + goto error; + } + datas = SPA_PTROFF(port->buffers, buffers_size, void*); + for (i = 0; i < n_buffers; i++) + port->buffers[i].datas = &datas[i * port->blocks]; + } + for (i = 0; i < n_buffers; i++) { struct buffer *b; uint32_t n_datas = buffers[i]->n_datas; @@ -4336,11 +4353,15 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void return 0; } -static void free_dir(struct dir *dir) +static void free_dir(struct impl *this, struct dir *dir) { uint32_t i; - for (i = 0; i < MAX_PORTS; i++) - free(dir->ports[i]); + for (i = 0; i < MAX_PORTS; i++) { + if (dir->ports[i] != NULL) { + clear_buffers(this, dir->ports[i]); + free(dir->ports[i]); + } + } if (dir->conv.free) convert_free(&dir->conv); free(dir->tag); @@ -4355,8 +4376,8 @@ static int impl_clear(struct spa_handle *handle) this = (struct impl *) handle; - free_dir(&this->dir[SPA_DIRECTION_INPUT]); - free_dir(&this->dir[SPA_DIRECTION_OUTPUT]); + free_dir(this, &this->dir[SPA_DIRECTION_INPUT]); + free_dir(this, &this->dir[SPA_DIRECTION_OUTPUT]); free_tmp(this);