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.
This commit is contained in:
Wim Taymans 2026-06-04 16:53:03 +02:00
parent aa075c2a12
commit 5e521d3532
10 changed files with 48 additions and 17 deletions

View file

@ -52,6 +52,12 @@ struct spa_filter_graph_info {
struct spa_dict *props; struct spa_dict *props;
}; };
struct spa_filter_graph_ctx {
const char *type;
void *data;
size_t size;
};
struct spa_filter_graph_events { struct spa_filter_graph_events {
#define SPA_VERSION_FILTER_GRAPH_EVENTS 0 #define SPA_VERSION_FILTER_GRAPH_EVENTS 0
uint32_t version; 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 (*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 (*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 (*deactivate) (void *object);
int (*reset) (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_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, 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) SPA_API_FILTER_GRAPH int spa_filter_graph_deactivate(struct spa_filter_graph *object)
{ {

View file

@ -1278,7 +1278,8 @@ static int setup_filter_graph(struct impl *this, struct filter_graph *g,
res = spa_filter_graph_activate(g->graph, res = spa_filter_graph_activate(g->graph,
&SPA_DICT_ITEMS( &SPA_DICT_ITEMS(
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, rate_str), 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; g->setup = res >= 0;

View file

@ -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_SUPPORTS_NULL_DATA(x) ((x) & SPA_FGA_PORT_SUPPORTS_NULL_DATA)
#define SPA_FGA_IS_PORT_SEQUENCE(x) ((x) & SPA_FGA_PORT_SEQUENCE) #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 { struct spa_fga_descriptor {
const char *name; const char *name;
#define SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA (1ULL << 0) #define SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA (1ULL << 0)
@ -71,7 +77,7 @@ struct spa_fga_descriptor {
void (*control_changed) (void *instance); void (*control_changed) (void *instance);
void (*control_sync) (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 (*deactivate) (void *instance);
void (*run) (void *instance, unsigned long SampleCount); void (*run) (void *instance, unsigned long SampleCount);

View file

@ -42,6 +42,7 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.filter-graph");
#define MAX_HNDL 64 #define MAX_HNDL 64
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS #define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
#define MAX_CTX 8u
#define DEFAULT_RATE 48000 #define DEFAULT_RATE 48000
@ -227,6 +228,8 @@ struct impl {
uint64_t info_all; uint64_t info_all;
struct spa_filter_graph_info info; struct spa_filter_graph_info info;
struct spa_fga_ctx ctx[MAX_CTX];
uint32_t n_ctx;
struct graph graph; struct graph graph;
@ -708,7 +711,7 @@ static int impl_reset(void *object)
if (d->deactivate) if (d->deactivate)
d->deactivate(*hndl->hndl); d->deactivate(*hndl->hndl);
if (d->activate) if (d->activate)
d->activate(*hndl->hndl); d->activate(*hndl->hndl, impl->n_ctx, impl->ctx);
} }
return 0; return 0;
} }
@ -1627,7 +1630,8 @@ static struct node *sort_next_node(struct graph *graph)
static int setup_graph(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 impl *impl = object;
struct graph *graph = &impl->graph; struct graph *graph = &impl->graph;
@ -1645,7 +1649,16 @@ static int impl_activate(void *object, const struct spa_dict *props)
if (graph->activated) if (graph->activated)
return 0; return 0;
if (n_ctx > MAX_CTX)
return -EINVAL;
graph->activated = true; 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); rate = spa_dict_lookup(props, SPA_KEY_AUDIO_RATE);
impl->rate = rate ? atoi(rate) : DEFAULT_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++) { for (i = 0; i < node->n_hndl; i++) {
if (d->activate) if (d->activate)
d->activate(node->hndl[i]); d->activate(node->hndl[i], impl->n_ctx, impl->ctx);
} }
} }
emit_node_control_changed(impl); emit_node_control_changed(impl);

View file

@ -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; 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; struct builtin *impl = Instance;
if (impl->type == BQ_NONE) { 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; struct convolver_impl *impl = Instance;
if (impl->port[2] != NULL) if (impl->port[2] != NULL)
@ -1447,7 +1447,7 @@ static void convolver2_run(void * Instance, unsigned long SampleCount)
impl->port[1][0] = impl->latency; 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; struct convolver_impl *impl = Instance;
if (impl->port[1] != NULL) if (impl->port[1] != NULL)
@ -1621,7 +1621,7 @@ static void delay_connect_port(void * Instance, unsigned long Port,
impl->port[Port] = DataLocation; 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; struct delay_impl *impl = Instance;
if (impl->port[3] != NULL) if (impl->port[3] != NULL)

View file

@ -238,7 +238,7 @@ static void ebur128_cleanup(void * Instance)
free(impl); 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; struct ebur128_impl *impl = Instance;
unsigned long max_window; unsigned long max_window;

View file

@ -168,7 +168,7 @@ static const struct spa_fga_descriptor *ladspa_plugin_make_desc(void *plugin, co
desc->desc.instantiate = ladspa_instantiate; desc->desc.instantiate = ladspa_instantiate;
desc->desc.cleanup = d->cleanup; desc->desc.cleanup = d->cleanup;
desc->desc.connect_port = (__typeof__(desc->desc.connect_port))d->connect_port; 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.deactivate = d->deactivate;
desc->desc.run = d->run; desc->desc.run = d->run;

View file

@ -491,7 +491,7 @@ static void lv2_connect_port(void *instance, unsigned long port, void *data)
lilv_instance_connect_port(i->instance, port, 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; struct instance *i = instance;
lilv_instance_activate(i->instance); lilv_instance_activate(i->instance);

View file

@ -395,7 +395,7 @@ static void spatializer_control_changed(void * Instance)
spatializer_reload(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; struct spatializer_impl *impl = Instance;
impl->port[6][0] = impl->latency; impl->port[6][0] = impl->latency;

View file

@ -1269,6 +1269,8 @@ struct impl {
struct spa_handle *handle; struct spa_handle *handle;
struct spa_filter_graph *graph; struct spa_filter_graph *graph;
struct spa_filter_graph_ctx ctx[3];
uint32_t n_ctx;
struct spa_hook graph_listener; struct spa_hook graph_listener;
uint32_t n_inputs; uint32_t n_inputs;
uint32_t n_outputs; uint32_t n_outputs;
@ -1402,7 +1404,8 @@ static int activate_graph(struct impl *impl)
snprintf(rate, sizeof(rate), "%lu", impl->rate); snprintf(rate, sizeof(rate), "%lu", impl->rate);
res = spa_filter_graph_activate(impl->graph, &SPA_DICT_ITEMS( 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) { if (res >= 0) {
struct pw_loop *data_loop = pw_stream_get_data_loop(impl->playback); struct pw_loop *data_loop = pw_stream_get_data_loop(impl->playback);