From 2ed62f53d9bb67c754bdfb2e87aa8ebbb3ace768 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 1 Jan 2022 17:41:27 +0100 Subject: [PATCH] spa: allocate ports dynamically So that we don't need to allocate large memory blocks that are mostly unused. See #1840 --- spa/plugins/audioconvert/merger.c | 46 ++++++++++++++++------------- spa/plugins/audioconvert/splitter.c | 19 ++++++++++-- spa/plugins/audiomixer/audiomixer.c | 26 +++++++++++----- spa/plugins/audiomixer/mixer-dsp.c | 33 ++++++++++++++++----- spa/plugins/control/mixer.c | 27 +++++++++++++---- 5 files changed, 107 insertions(+), 44 deletions(-) diff --git a/spa/plugins/audioconvert/merger.c b/spa/plugins/audioconvert/merger.c index 7469a2413..6bdaedbc3 100644 --- a/spa/plugins/audioconvert/merger.c +++ b/spa/plugins/audioconvert/merger.c @@ -160,8 +160,8 @@ struct impl { uint32_t port_count; uint32_t monitor_count; - struct port in_ports[MAX_PORTS]; - struct port out_ports[MAX_PORTS + 1]; + struct port *in_ports[MAX_PORTS]; + struct port *out_ports[MAX_PORTS + 1]; struct spa_audio_info format; unsigned int have_profile:1; @@ -187,8 +187,8 @@ struct impl { #define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < this->port_count) #define CHECK_OUT_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) <= this->monitor_count) #define CHECK_PORT(this,d,p) (CHECK_OUT_PORT(this,d,p) || CHECK_IN_PORT (this,d,p)) -#define GET_IN_PORT(this,p) (&this->in_ports[p]) -#define GET_OUT_PORT(this,p) (&this->out_ports[p]) +#define GET_IN_PORT(this,p) (this->in_ports[p]) +#define GET_OUT_PORT(this,p) (this->out_ports[p]) #define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p)) #define PORT_IS_DSP(d,p) (p != 0 || d != SPA_DIRECTION_OUTPUT) @@ -232,6 +232,15 @@ static int init_port(struct impl *this, enum spa_direction direction, uint32_t p struct port *port = GET_PORT(this, direction, port_id); const char *name; + if (port == NULL) { + port = calloc(1, sizeof(struct port)); + if (port == NULL) + return -errno; + if (direction == SPA_DIRECTION_INPUT) + this->in_ports[port_id] = port; + else + this->out_ports[port_id] = port; + } port->direction = direction; port->id = port_id; @@ -1500,6 +1509,17 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void static int impl_clear(struct spa_handle *handle) { + struct impl *this; + uint32_t i; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + + this = (struct impl *) handle; + + for (i = 0; i < MAX_PORTS; i++) + free(this->in_ports[i]); + for (i = 0; i < MAX_PORTS+1; i++) + free(this->out_ports[i]); return 0; } @@ -1518,7 +1538,6 @@ impl_init(const struct spa_handle_factory *factory, uint32_t n_support) { struct impl *this; - struct port *port; uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); @@ -1564,22 +1583,7 @@ impl_init(const struct spa_handle_factory *factory, this->info.params = this->params; this->info.n_params = N_NODE_PARAMS; - port = GET_OUT_PORT(this, 0); - port->direction = SPA_DIRECTION_OUTPUT; - port->id = 0; - port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | - SPA_PORT_CHANGE_MASK_PARAMS; - port->info = SPA_PORT_INFO_INIT(); - port->info.flags = SPA_PORT_FLAG_DYNAMIC_DATA; - port->params[IDX_EnumFormat] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); - port->params[IDX_Meta] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); - port->params[IDX_IO] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); - port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); - port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); - port->params[IDX_Latency] = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); - port->info.params = port->params; - port->info.n_params = N_PORT_PARAMS; - spa_list_init(&port->queue); + init_port(this, SPA_DIRECTION_OUTPUT, 0, 0); this->volume.cpu_flags = this->cpu_flags; volume_init(&this->volume); diff --git a/spa/plugins/audioconvert/splitter.c b/spa/plugins/audioconvert/splitter.c index 296364fff..8ad3db15a 100644 --- a/spa/plugins/audioconvert/splitter.c +++ b/spa/plugins/audioconvert/splitter.c @@ -118,7 +118,7 @@ struct impl { struct spa_hook_list hooks; struct port in_ports[1]; - struct port out_ports[MAX_PORTS]; + struct port *out_ports[MAX_PORTS]; uint32_t port_count; struct spa_audio_info format; @@ -141,7 +141,7 @@ struct impl { #define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) == 0) #define CHECK_PORT(this,d,p) (CHECK_OUT_PORT(this,d,p) || CHECK_IN_PORT (this,d,p)) #define GET_IN_PORT(this,p) (&this->in_ports[p]) -#define GET_OUT_PORT(this,p) (&this->out_ports[p]) +#define GET_OUT_PORT(this,p) (this->out_ports[p]) #define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p)) static void emit_node_info(struct impl *this, bool full) @@ -172,6 +172,12 @@ static int init_port(struct impl *this, enum spa_direction direction, struct port *port = GET_OUT_PORT(this, port_id); const char *name; + if (port == NULL) { + port = calloc(1, sizeof(struct port)); + if (port == NULL) + return -errno; + this->out_ports[port_id] = port; + } port->direction = direction; port->id = port_id; @@ -1101,6 +1107,15 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void static int impl_clear(struct spa_handle *handle) { + struct impl *this; + uint32_t i; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + + this = (struct impl *) handle; + + for (i = 0; i < MAX_PORTS; i++) + free(this->out_ports[i]); return 0; } diff --git a/spa/plugins/audiomixer/audiomixer.c b/spa/plugins/audiomixer/audiomixer.c index a4b8b924e..579aaac1a 100644 --- a/spa/plugins/audiomixer/audiomixer.c +++ b/spa/plugins/audiomixer/audiomixer.c @@ -118,7 +118,7 @@ struct impl { uint32_t port_count; uint32_t last_port; - struct port in_ports[MAX_PORTS]; + struct port *in_ports[MAX_PORTS]; struct port out_ports[1]; int n_formats; @@ -133,11 +133,12 @@ struct impl { }; -#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !this->in_ports[(p)].valid) -#define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && this->in_ports[(p)].valid) +#define PORT_VALID(p) ((p) != NULL && (p)->valid) +#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !PORT_VALID(this->in_ports[(p)])) +#define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && PORT_VALID(this->in_ports[(p)])) #define CHECK_OUT_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) == 0) #define CHECK_PORT(this,d,p) (CHECK_OUT_PORT(this,d,p) || CHECK_IN_PORT (this,d,p)) -#define GET_IN_PORT(this,p) (&this->in_ports[p]) +#define GET_IN_PORT(this,p) (this->in_ports[p]) #define GET_OUT_PORT(this,p) (&this->out_ports[p]) #define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p)) @@ -218,7 +219,7 @@ static int impl_node_add_listener(void *object, emit_node_info(this, true); emit_port_info(this, GET_OUT_PORT(this, 0), true); for (i = 0; i < this->last_port; i++) { - if (this->in_ports[i].valid) + if (PORT_VALID(this->in_ports[i])) emit_port_info(this, GET_IN_PORT(this, i), true); } @@ -245,6 +246,12 @@ static int impl_node_add_port(void *object, enum spa_direction direction, uint32 spa_return_val_if_fail(CHECK_FREE_IN_PORT(this, direction, port_id), -EINVAL); port = GET_IN_PORT(this, port_id); + if (port == NULL) { + port = calloc(1, sizeof(struct port)); + if (port == NULL) + return -errno; + this->in_ports[port_id] = port; + } port->direction = SPA_DIRECTION_INPUT; port->id = port_id; @@ -301,7 +308,7 @@ impl_node_remove_port(void *object, enum spa_direction direction, uint32_t port_ int i; for (i = this->last_port - 1; i >= 0; i--) - if (GET_IN_PORT (this, i)->valid) + if (PORT_VALID(GET_IN_PORT(this, i))) break; this->last_port = i + 1; @@ -749,13 +756,13 @@ static int impl_node_process(void *object) struct spa_io_buffers *inio = NULL; struct buffer *inb; - if (SPA_UNLIKELY(!inport->valid || + if (SPA_UNLIKELY(!PORT_VALID(inport) || (inio = inport->io) == NULL || inio->buffer_id >= inport->n_buffers || inio->status != SPA_STATUS_HAVE_DATA)) { spa_log_trace_fp(this->log, "%p: skip input idx:%d valid:%d " "io:%p status:%d buf_id:%d n_buffers:%d", this, - i, inport->valid, inio, + i, PORT_VALID(inport), inio, inio ? inio->status : -1, inio ? inio->buffer_id : SPA_ID_INVALID, inport->n_buffers); @@ -841,11 +848,14 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void static int impl_clear(struct spa_handle *handle) { struct impl *this; + uint32_t i; spa_return_val_if_fail(handle != NULL, -EINVAL); this = (struct impl *) handle; + for (i = 0; i < MAX_PORTS; i++) + free(this->in_ports[i]); mix_ops_free(&this->ops); return 0; } diff --git a/spa/plugins/audiomixer/mixer-dsp.c b/spa/plugins/audiomixer/mixer-dsp.c index 2da3e0884..d62a56c7c 100644 --- a/spa/plugins/audiomixer/mixer-dsp.c +++ b/spa/plugins/audiomixer/mixer-dsp.c @@ -117,7 +117,7 @@ struct impl { uint32_t port_count; uint32_t last_port; - struct port in_ports[MAX_PORTS]; + struct port *in_ports[MAX_PORTS]; struct port out_ports[1]; int n_formats; @@ -130,11 +130,12 @@ struct impl { float empty[MAX_SAMPLES + MAX_ALIGN]; }; -#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !this->in_ports[(p)].valid) -#define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && this->in_ports[(p)].valid) +#define PORT_VALID(p) ((p) != NULL && (p)->valid) +#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !PORT_VALID(this->in_ports[(p)])) +#define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && PORT_VALID(this->in_ports[(p)])) #define CHECK_OUT_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) == 0) #define CHECK_PORT(this,d,p) (CHECK_OUT_PORT(this,d,p) || CHECK_IN_PORT (this,d,p)) -#define GET_IN_PORT(this,p) (&this->in_ports[p]) +#define GET_IN_PORT(this,p) (this->in_ports[p]) #define GET_OUT_PORT(this,p) (&this->out_ports[p]) #define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p)) @@ -215,7 +216,7 @@ static int impl_node_add_listener(void *object, emit_node_info(this, true); emit_port_info(this, GET_OUT_PORT(this, 0), true); for (i = 0; i < this->last_port; i++) { - if (this->in_ports[i].valid) + if (PORT_VALID(this->in_ports[i])) emit_port_info(this, GET_IN_PORT(this, i), true); } @@ -242,6 +243,13 @@ static int impl_node_add_port(void *object, enum spa_direction direction, uint32 spa_return_val_if_fail(CHECK_FREE_IN_PORT(this, direction, port_id), -EINVAL); port = GET_IN_PORT (this, port_id); + if (port == NULL) { + port = calloc(1, sizeof(struct port)); + if (port == NULL) + return -errno; + this->in_ports[port_id] = port; + } + port->direction = direction; port->id = port_id; @@ -298,7 +306,7 @@ impl_node_remove_port(void *object, enum spa_direction direction, uint32_t port_ int i; for (i = this->last_port - 1; i >= 0; i--) - if (GET_IN_PORT (this, i)->valid) + if (PORT_VALID(GET_IN_PORT(this, i))) break; this->last_port = i + 1; @@ -695,13 +703,13 @@ static int impl_node_process(void *object) struct spa_io_buffers *inio = NULL; struct buffer *inb; - if (SPA_UNLIKELY(!inport->valid || + if (SPA_UNLIKELY(!PORT_VALID(inport) || (inio = inport->io) == NULL || inio->buffer_id >= inport->n_buffers || inio->status != SPA_STATUS_HAVE_DATA)) { spa_log_trace_fp(this->log, "%p: skip input idx:%d valid:%d " "io:%p status:%d buf_id:%d n_buffers:%d", this, - i, inport->valid, inio, + i, PORT_VALID(inport), inio, inio ? inio->status : -1, inio ? inio->buffer_id : SPA_ID_INVALID, inport->n_buffers); @@ -785,6 +793,15 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void static int impl_clear(struct spa_handle *handle) { + struct impl *this; + uint32_t i; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + + this = (struct impl *) handle; + + for (i = 0; i < MAX_PORTS; i++) + free(this->in_ports[i]); return 0; } diff --git a/spa/plugins/control/mixer.c b/spa/plugins/control/mixer.c index c55e907ce..8d2fab234 100644 --- a/spa/plugins/control/mixer.c +++ b/spa/plugins/control/mixer.c @@ -86,7 +86,7 @@ struct impl { uint32_t port_count; uint32_t last_port; - struct port in_ports[MAX_PORTS]; + struct port *in_ports[MAX_PORTS]; struct port out_ports[1]; int n_formats; @@ -95,11 +95,12 @@ struct impl { unsigned int started:1; }; -#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !this->in_ports[(p)].valid) -#define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && this->in_ports[(p)].valid) +#define PORT_VALID(p) ((p) != NULL && (p)->valid) +#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !PORT_VALID(this->in_ports[(p)])) +#define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && PORT_VALID(this->in_ports[(p)])) #define CHECK_OUT_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) == 0) #define CHECK_PORT(this,d,p) (CHECK_OUT_PORT(this,d,p) || CHECK_IN_PORT (this,d,p)) -#define GET_IN_PORT(this,p) (&this->in_ports[p]) +#define GET_IN_PORT(this,p) (this->in_ports[p]) #define GET_OUT_PORT(this,p) (&this->out_ports[p]) #define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p)) @@ -180,7 +181,7 @@ static int impl_node_add_listener(void *object, emit_node_info(this, true); emit_port_info(this, GET_OUT_PORT(this, 0), true); for (i = 0; i < this->last_port; i++) { - if (this->in_ports[i].valid) + if (PORT_VALID(this->in_ports[i])) emit_port_info(this, GET_IN_PORT(this, i), true); } @@ -207,6 +208,13 @@ static int impl_node_add_port(void *object, enum spa_direction direction, uint32 spa_return_val_if_fail(CHECK_FREE_IN_PORT(this, direction, port_id), -EINVAL); port = GET_IN_PORT (this, port_id); + if (port == NULL) { + port = calloc(1, sizeof(struct port)); + if (port == NULL) + return -errno; + this->in_ports[port_id] = port; + } + port->direction = direction; port->id = port_id; @@ -720,6 +728,15 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void static int impl_clear(struct spa_handle *handle) { + struct impl *this; + uint32_t i; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + + this = (struct impl *) handle; + + for (i = 0; i < MAX_PORTS; i++) + free(this->in_ports[i]); return 0; }