From 5e521d3532aaeba6da74f4c674856770737ac7f6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 4 Jun 2026 16:53:03 +0200 Subject: [PATCH] filter-graph: pass context to plugins Make it possible to pass context to plugins and nodes in the filter-chain. We can use this to make filters aware of the graph clock or latency, for example. --- spa/include/spa/filter-graph/filter-graph.h | 14 +++++++++++--- spa/plugins/audioconvert/audioconvert.c | 3 ++- spa/plugins/filter-graph/audio-plugin.h | 8 +++++++- spa/plugins/filter-graph/filter-graph.c | 19 ++++++++++++++++--- spa/plugins/filter-graph/plugin_builtin.c | 8 ++++---- spa/plugins/filter-graph/plugin_ebur128.c | 2 +- spa/plugins/filter-graph/plugin_ladspa.c | 2 +- spa/plugins/filter-graph/plugin_lv2.c | 2 +- spa/plugins/filter-graph/plugin_sofa.c | 2 +- src/modules/module-filter-chain.c | 5 ++++- 10 files changed, 48 insertions(+), 17 deletions(-) diff --git a/spa/include/spa/filter-graph/filter-graph.h b/spa/include/spa/filter-graph/filter-graph.h index 481085c5f..d15d5f239 100644 --- a/spa/include/spa/filter-graph/filter-graph.h +++ b/spa/include/spa/filter-graph/filter-graph.h @@ -52,6 +52,12 @@ struct spa_filter_graph_info { struct spa_dict *props; }; +struct spa_filter_graph_ctx { + const char *type; + void *data; + size_t size; +}; + struct spa_filter_graph_events { #define SPA_VERSION_FILTER_GRAPH_EVENTS 0 uint32_t version; @@ -77,7 +83,8 @@ struct spa_filter_graph_methods { int (*get_props) (void *object, struct spa_pod_builder *b, struct spa_pod **props); int (*set_props) (void *object, enum spa_direction direction, const struct spa_pod *props); - int (*activate) (void *object, const struct spa_dict *props); + int (*activate) (void *object, const struct spa_dict *props, + uint32_t n_ctx, const struct spa_filter_graph_ctx ctx[]); int (*deactivate) (void *object); int (*reset) (void *object); @@ -114,10 +121,11 @@ SPA_API_FILTER_GRAPH int spa_filter_graph_set_props(struct spa_filter_graph *obj spa_filter_graph, &object->iface, set_props, 0, direction, props); } -SPA_API_FILTER_GRAPH int spa_filter_graph_activate(struct spa_filter_graph *object, const struct spa_dict *props) +SPA_API_FILTER_GRAPH int spa_filter_graph_activate(struct spa_filter_graph *object, + const struct spa_dict *props, uint32_t n_ctx, const struct spa_filter_graph_ctx ctx[]) { return spa_api_method_r(int, -ENOTSUP, - spa_filter_graph, &object->iface, activate, 0, props); + spa_filter_graph, &object->iface, activate, 0, props, n_ctx, ctx); } SPA_API_FILTER_GRAPH int spa_filter_graph_deactivate(struct spa_filter_graph *object) { diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index ce75e5167..47b068587 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -1278,7 +1278,8 @@ static int setup_filter_graph(struct impl *this, struct filter_graph *g, res = spa_filter_graph_activate(g->graph, &SPA_DICT_ITEMS( SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, rate_str), - SPA_DICT_ITEM("filter-graph.n_inputs", channels ? in_ports : NULL))); + SPA_DICT_ITEM("filter-graph.n_inputs", channels ? in_ports : NULL)), + 0, NULL); g->setup = res >= 0; diff --git a/spa/plugins/filter-graph/audio-plugin.h b/spa/plugins/filter-graph/audio-plugin.h index 1971135bf..72d8af3d2 100644 --- a/spa/plugins/filter-graph/audio-plugin.h +++ b/spa/plugins/filter-graph/audio-plugin.h @@ -51,6 +51,12 @@ struct spa_fga_port { #define SPA_FGA_SUPPORTS_NULL_DATA(x) ((x) & SPA_FGA_PORT_SUPPORTS_NULL_DATA) #define SPA_FGA_IS_PORT_SEQUENCE(x) ((x) & SPA_FGA_PORT_SEQUENCE) +struct spa_fga_ctx { + const char *type; + const void *data; + size_t size; +}; + struct spa_fga_descriptor { const char *name; #define SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA (1ULL << 0) @@ -71,7 +77,7 @@ struct spa_fga_descriptor { void (*control_changed) (void *instance); void (*control_sync) (void *instance); - void (*activate) (void *instance); + void (*activate) (void *instance, uint32_t n_ctx, const struct spa_fga_ctx ctx[]); void (*deactivate) (void *instance); void (*run) (void *instance, unsigned long SampleCount); diff --git a/spa/plugins/filter-graph/filter-graph.c b/spa/plugins/filter-graph/filter-graph.c index b16e1cf13..f361b8194 100644 --- a/spa/plugins/filter-graph/filter-graph.c +++ b/spa/plugins/filter-graph/filter-graph.c @@ -42,6 +42,7 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.filter-graph"); #define MAX_HNDL 64 #define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS +#define MAX_CTX 8u #define DEFAULT_RATE 48000 @@ -227,6 +228,8 @@ struct impl { uint64_t info_all; struct spa_filter_graph_info info; + struct spa_fga_ctx ctx[MAX_CTX]; + uint32_t n_ctx; struct graph graph; @@ -708,7 +711,7 @@ static int impl_reset(void *object) if (d->deactivate) d->deactivate(*hndl->hndl); if (d->activate) - d->activate(*hndl->hndl); + d->activate(*hndl->hndl, impl->n_ctx, impl->ctx); } return 0; } @@ -1627,7 +1630,8 @@ static struct node *sort_next_node(struct graph *graph) static int setup_graph(struct graph *graph); -static int impl_activate(void *object, const struct spa_dict *props) +static int impl_activate(void *object, const struct spa_dict *props, + uint32_t n_ctx, const struct spa_filter_graph_ctx ctx[]) { struct impl *impl = object; struct graph *graph = &impl->graph; @@ -1645,7 +1649,16 @@ static int impl_activate(void *object, const struct spa_dict *props) if (graph->activated) return 0; + if (n_ctx > MAX_CTX) + return -EINVAL; + graph->activated = true; + for (i = 0; i < n_ctx; i++) { + impl->ctx[i].type = ctx[i].type; + impl->ctx[i].data = ctx[i].data; + impl->ctx[i].size = ctx[i].size; + } + impl->n_ctx = n_ctx; rate = spa_dict_lookup(props, SPA_KEY_AUDIO_RATE); impl->rate = rate ? atoi(rate) : DEFAULT_RATE; @@ -1762,7 +1775,7 @@ static int impl_activate(void *object, const struct spa_dict *props) for (i = 0; i < node->n_hndl; i++) { if (d->activate) - d->activate(node->hndl[i]); + d->activate(node->hndl[i], impl->n_ctx, impl->ctx); } } emit_node_control_changed(impl); diff --git a/spa/plugins/filter-graph/plugin_builtin.c b/spa/plugins/filter-graph/plugin_builtin.c index 08904a71a..c5920a226 100644 --- a/spa/plugins/filter-graph/plugin_builtin.c +++ b/spa/plugins/filter-graph/plugin_builtin.c @@ -545,7 +545,7 @@ static void bq_freq_update(struct builtin *impl, int type, float freq, float Q, impl->port[10][0] = impl->a2 = bq->a2; } -static void bq_activate(void * Instance) +static void bq_activate(void * Instance, uint32_t n_ctx, const struct spa_fga_ctx ctx[]) { struct builtin *impl = Instance; if (impl->type == BQ_NONE) { @@ -1285,7 +1285,7 @@ static struct spa_fga_port convolve_ports[] = { }, }; -static void convolver_activate(void * Instance) +static void convolver_activate(void * Instance, uint32_t n_ctx, const struct spa_fga_ctx ctx[]) { struct convolver_impl *impl = Instance; if (impl->port[2] != NULL) @@ -1447,7 +1447,7 @@ static void convolver2_run(void * Instance, unsigned long SampleCount) impl->port[1][0] = impl->latency; } -static void convolver2_activate(void * Instance) +static void convolver2_activate(void * Instance, uint32_t n_ctx, const struct spa_fga_ctx ctx[]) { struct convolver_impl *impl = Instance; if (impl->port[1] != NULL) @@ -1621,7 +1621,7 @@ static void delay_connect_port(void * Instance, unsigned long Port, impl->port[Port] = DataLocation; } -static void delay_activate(void * Instance) +static void delay_activate(void * Instance, uint32_t n_ctx, const struct spa_fga_ctx ctx[]) { struct delay_impl *impl = Instance; if (impl->port[3] != NULL) diff --git a/spa/plugins/filter-graph/plugin_ebur128.c b/spa/plugins/filter-graph/plugin_ebur128.c index d1680a166..d0398f0d8 100644 --- a/spa/plugins/filter-graph/plugin_ebur128.c +++ b/spa/plugins/filter-graph/plugin_ebur128.c @@ -238,7 +238,7 @@ static void ebur128_cleanup(void * Instance) free(impl); } -static void ebur128_activate(void * Instance) +static void ebur128_activate(void * Instance, uint32_t n_ctx, const struct spa_fga_ctx ctx[]) { struct ebur128_impl *impl = Instance; unsigned long max_window; diff --git a/spa/plugins/filter-graph/plugin_ladspa.c b/spa/plugins/filter-graph/plugin_ladspa.c index 44f3ec440..5aed56bd9 100644 --- a/spa/plugins/filter-graph/plugin_ladspa.c +++ b/spa/plugins/filter-graph/plugin_ladspa.c @@ -168,7 +168,7 @@ static const struct spa_fga_descriptor *ladspa_plugin_make_desc(void *plugin, co desc->desc.instantiate = ladspa_instantiate; desc->desc.cleanup = d->cleanup; desc->desc.connect_port = (__typeof__(desc->desc.connect_port))d->connect_port; - desc->desc.activate = d->activate; + desc->desc.activate = (__typeof__(desc->desc.activate))d->activate; desc->desc.deactivate = d->deactivate; desc->desc.run = d->run; diff --git a/spa/plugins/filter-graph/plugin_lv2.c b/spa/plugins/filter-graph/plugin_lv2.c index 14209a7d7..cac5cc221 100644 --- a/spa/plugins/filter-graph/plugin_lv2.c +++ b/spa/plugins/filter-graph/plugin_lv2.c @@ -491,7 +491,7 @@ static void lv2_connect_port(void *instance, unsigned long port, void *data) lilv_instance_connect_port(i->instance, port, data); } -static void lv2_activate(void *instance) +static void lv2_activate(void *instance, uint32_t n_ctx, const struct spa_fga_ctx ctx[]) { struct instance *i = instance; lilv_instance_activate(i->instance); diff --git a/spa/plugins/filter-graph/plugin_sofa.c b/spa/plugins/filter-graph/plugin_sofa.c index 4b3f1cb4f..cb4034396 100644 --- a/spa/plugins/filter-graph/plugin_sofa.c +++ b/spa/plugins/filter-graph/plugin_sofa.c @@ -395,7 +395,7 @@ static void spatializer_control_changed(void * Instance) spatializer_reload(Instance); } -static void spatializer_activate(void * Instance) +static void spatializer_activate(void * Instance, uint32_t n_ctx, const struct spa_fga_ctx ctx[]) { struct spatializer_impl *impl = Instance; impl->port[6][0] = impl->latency; diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index 3f00bbd51..b453136f8 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -1269,6 +1269,8 @@ struct impl { struct spa_handle *handle; struct spa_filter_graph *graph; + struct spa_filter_graph_ctx ctx[3]; + uint32_t n_ctx; struct spa_hook graph_listener; uint32_t n_inputs; uint32_t n_outputs; @@ -1402,7 +1404,8 @@ static int activate_graph(struct impl *impl) snprintf(rate, sizeof(rate), "%lu", impl->rate); res = spa_filter_graph_activate(impl->graph, &SPA_DICT_ITEMS( - SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, rate))); + SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, rate)), + impl->n_ctx, impl->ctx); if (res >= 0) { struct pw_loop *data_loop = pw_stream_get_data_loop(impl->playback);