filter-chain: improve lv2 support

Add support for Worker.
Add Options feature.
Pass support in plugin load.
This commit is contained in:
Wim Taymans 2021-12-13 11:28:25 +01:00
parent c04580a256
commit 8416d66ab3
5 changed files with 183 additions and 46 deletions

View file

@ -39,7 +39,6 @@
#include <spa/utils/string.h> #include <spa/utils/string.h>
#include <spa/utils/json.h> #include <spa/utils/json.h>
#include <spa/param/profiler.h> #include <spa/param/profiler.h>
#include <spa/support/cpu.h>
#include <spa/debug/pod.h> #include <spa/debug/pod.h>
#include <pipewire/utils.h> #include <pipewire/utils.h>
@ -739,6 +738,8 @@ static struct plugin *plugin_load(struct impl *impl, const char *type, const cha
struct fc_plugin *pl = NULL; struct fc_plugin *pl = NULL;
struct plugin *hndl; struct plugin *hndl;
int res = 0; int res = 0;
const struct spa_support *support;
uint32_t n_support;
spa_list_for_each(hndl, &impl->plugin_list, link) { spa_list_for_each(hndl, &impl->plugin_list, link) {
if (spa_streq(hndl->type, type) && if (spa_streq(hndl->type, type) &&
@ -747,16 +748,17 @@ static struct plugin *plugin_load(struct impl *impl, const char *type, const cha
return hndl; return hndl;
} }
} }
support = pw_context_get_support(impl->context, &n_support);
if (spa_streq(type, "builtin")) { if (spa_streq(type, "builtin")) {
pl = load_builtin_plugin(path, NULL); pl = load_builtin_plugin(support, n_support, path, NULL);
} }
else if (spa_streq(type, "ladspa")) { else if (spa_streq(type, "ladspa")) {
pl = load_ladspa_plugin(path, NULL); pl = load_ladspa_plugin(support, n_support, path, NULL);
} }
#ifdef HAVE_LILV #ifdef HAVE_LILV
else if (spa_streq(type, "lv2")) { else if (spa_streq(type, "lv2")) {
pl = load_lv2_plugin(path, NULL); pl = load_lv2_plugin(support, n_support, path, NULL);
} }
#endif #endif
if (pl == NULL) if (pl == NULL)
@ -1280,6 +1282,7 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_
sd = dd = NULL; sd = dd = NULL;
for (i = 0; i < n_hndl; i++) { for (i = 0; i < n_hndl; i++) {
pw_log_info("instantiate %s %d", d->name, i);
if ((node->hndl[i] = d->instantiate(d, &impl->rate, i, node->config)) == NULL) { if ((node->hndl[i] = d->instantiate(d, &impl->rate, i, node->config)) == NULL) {
pw_log_error("cannot create plugin instance"); pw_log_error("cannot create plugin instance");
res = -ENOMEM; res = -ENOMEM;
@ -1650,9 +1653,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
struct impl *impl; struct impl *impl;
uint32_t id = pw_global_get_id(pw_impl_module_get_global(module)); uint32_t id = pw_global_get_id(pw_impl_module_get_global(module));
const char *str; const char *str;
const struct spa_support *support;
uint32_t n_support;
struct spa_cpu *cpu_iface;
int res; int res;
PW_LOG_TOPIC_INIT(mod_topic); PW_LOG_TOPIC_INIT(mod_topic);
@ -1663,10 +1663,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
pw_log_debug("module %p: new %s", impl, args); pw_log_debug("module %p: new %s", impl, args);
support = pw_context_get_support(context, &n_support);
cpu_iface = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
init_builtin_plugin(cpu_iface ? spa_cpu_get_flags(cpu_iface) : 0);
if (args) if (args)
props = pw_properties_new_string(args); props = pw_properties_new_string(args);
else else

View file

@ -30,6 +30,8 @@
#endif #endif
#include <spa/utils/json.h> #include <spa/utils/json.h>
#include <spa/support/cpu.h>
#include <pipewire/log.h> #include <pipewire/log.h>
#include "plugin.h" #include "plugin.h"
@ -771,12 +773,11 @@ static struct fc_plugin builtin_plugin = {
.make_desc = builtin_make_desc .make_desc = builtin_make_desc
}; };
struct fc_plugin *load_builtin_plugin(const char *plugin, const char *config) struct fc_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support,
const char *plugin, const char *config)
{ {
struct spa_cpu *cpu_iface;
cpu_iface = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
pffft_select_cpu(cpu_iface ? spa_cpu_get_flags(cpu_iface) : 0);
return &builtin_plugin; return &builtin_plugin;
} }
void init_builtin_plugin(uint32_t cpu_flags)
{
pffft_select_cpu(cpu_flags);
}

View file

@ -226,7 +226,8 @@ exit:
return NULL; return NULL;
} }
struct fc_plugin *load_ladspa_plugin(const char *plugin, const char *config) struct fc_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t n_support,
const char *plugin, const char *config)
{ {
struct fc_plugin *pl = NULL; struct fc_plugin *pl = NULL;

View file

@ -28,6 +28,7 @@
#include <spa/utils/defs.h> #include <spa/utils/defs.h>
#include <spa/utils/list.h> #include <spa/utils/list.h>
#include <spa/utils/string.h> #include <spa/utils/string.h>
#include <spa/support/loop.h>
#include <pipewire/log.h> #include <pipewire/log.h>
#include <pipewire/utils.h> #include <pipewire/utils.h>
@ -36,6 +37,9 @@
#include <lilv/lilv.h> #include <lilv/lilv.h>
#include <lv2/lv2plug.in/ns/ext/atom/atom.h> #include <lv2/lv2plug.in/ns/ext/atom/atom.h>
#include <lv2/lv2plug.in/ns/ext/buf-size/buf-size.h> #include <lv2/lv2plug.in/ns/ext/buf-size/buf-size.h>
#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
#include "lv2/lv2plug.in/ns/ext/options/options.h"
#include "lv2/lv2plug.in/ns/ext/parameters/parameters.h"
#include "plugin.h" #include "plugin.h"
@ -61,17 +65,18 @@ static void uri_table_destroy(URITable *table)
static LV2_URID uri_table_map(LV2_URID_Map_Handle handle, const char *uri) static LV2_URID uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
{ {
URITable *table = (URITable*)handle; URITable *table = (URITable*)handle;
char *p; char **p;
size_t i = 0; size_t i = 0;
pw_array_for_each(p, &table->array) { pw_array_for_each(p, &table->array) {
if (spa_streq(p, uri))
return i + 1;
i++; i++;
if (spa_streq(*p, uri))
goto done;
} }
pw_array_add_ptr(&table->array, strdup(uri)); pw_array_add_ptr(&table->array, strdup(uri));
return pw_array_get_len(&table->array, char*); i = pw_array_get_len(&table->array, char*);
done:
return i;
} }
static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
@ -87,6 +92,9 @@ struct context {
int ref; int ref;
LilvWorld *world; LilvWorld *world;
struct spa_loop *data_loop;
struct spa_loop *main_loop;
LilvNode *lv2_InputPort; LilvNode *lv2_InputPort;
LilvNode *lv2_OutputPort; LilvNode *lv2_OutputPort;
LilvNode *lv2_AudioPort; LilvNode *lv2_AudioPort;
@ -98,18 +106,25 @@ struct context {
LilvNode *powerOf2BlockLength; LilvNode *powerOf2BlockLength;
LilvNode *fixedBlockLength; LilvNode *fixedBlockLength;
LilvNode *boundedBlockLength; LilvNode *boundedBlockLength;
LilvNode* worker_schedule;
LilvNode* worker_iface;
URITable uri_table; URITable uri_table;
LV2_URID_Map map; LV2_URID_Map map;
LV2_URID_Unmap unmap;
LV2_Feature map_feature; LV2_Feature map_feature;
LV2_URID_Unmap unmap;
LV2_Feature unmap_feature; LV2_Feature unmap_feature;
const LV2_Feature *features[5];
LV2_URID atom_Int;
LV2_URID atom_Float;
}; };
#define context_map(c,uri) ((c)->map.map((c)->map.handle,(uri)))
static void context_free(struct context *c) static void context_free(struct context *c)
{ {
if (c->world) { if (c->world) {
lilv_node_free(c->worker_schedule);
lilv_node_free(c->powerOf2BlockLength); lilv_node_free(c->powerOf2BlockLength);
lilv_node_free(c->fixedBlockLength); lilv_node_free(c->fixedBlockLength);
lilv_node_free(c->boundedBlockLength); lilv_node_free(c->boundedBlockLength);
@ -133,7 +148,7 @@ static const LV2_Feature buf_size_features[3] = {
{ LV2_BUF_SIZE__boundedBlockLength, NULL }, { LV2_BUF_SIZE__boundedBlockLength, NULL },
}; };
static struct context *context_new(void) static struct context *context_new(const struct spa_support *support, uint32_t n_support)
{ {
struct context *c; struct context *c;
@ -159,6 +174,8 @@ static struct context *context_new(void)
c->powerOf2BlockLength = lilv_new_uri(c->world, LV2_BUF_SIZE__powerOf2BlockLength); c->powerOf2BlockLength = lilv_new_uri(c->world, LV2_BUF_SIZE__powerOf2BlockLength);
c->fixedBlockLength = lilv_new_uri(c->world, LV2_BUF_SIZE__fixedBlockLength); c->fixedBlockLength = lilv_new_uri(c->world, LV2_BUF_SIZE__fixedBlockLength);
c->boundedBlockLength = lilv_new_uri(c->world, LV2_BUF_SIZE__boundedBlockLength); c->boundedBlockLength = lilv_new_uri(c->world, LV2_BUF_SIZE__boundedBlockLength);
c->worker_schedule = lilv_new_uri(c->world, LV2_WORKER__schedule);
c->worker_iface = lilv_new_uri(c->world, LV2_WORKER__interface);
c->map.handle = &c->uri_table; c->map.handle = &c->uri_table;
c->map.map = uri_table_map; c->map.map = uri_table_map;
@ -168,11 +185,12 @@ static struct context *context_new(void)
c->unmap.unmap = uri_table_unmap; c->unmap.unmap = uri_table_unmap;
c->unmap_feature.URI = LV2_URID_UNMAP_URI; c->unmap_feature.URI = LV2_URID_UNMAP_URI;
c->unmap_feature.data = &c->unmap; c->unmap_feature.data = &c->unmap;
c->features[0] = &c->map_feature;
c->features[1] = &c->unmap_feature; c->atom_Int = context_map(c, LV2_ATOM__Int);
c->features[2] = &buf_size_features[0]; c->atom_Float = context_map(c, LV2_ATOM__Float);
c->features[3] = &buf_size_features[1];
c->features[4] = &buf_size_features[2]; c->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
c->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
return c; return c;
error: error:
@ -180,10 +198,10 @@ error:
return NULL; return NULL;
} }
static struct context *context_ref(void) static struct context *context_ref(const struct spa_support *support, uint32_t n_support)
{ {
if (_context == NULL) { if (_context == NULL) {
_context = context_new(); _context = context_new(support, n_support);
if (_context == NULL) if (_context == NULL)
return NULL; return NULL;
} }
@ -210,38 +228,156 @@ struct descriptor {
struct plugin *p; struct plugin *p;
}; };
struct instance {
struct descriptor *desc;
LilvInstance *instance;
LV2_Worker_Schedule work_schedule;
LV2_Feature work_schedule_feature;
LV2_Options_Option options[6];
LV2_Feature options_feature;
const LV2_Feature *features[7];
const LV2_Worker_Interface *work_iface;
int32_t block_length;
};
static int
do_respond(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
size_t size, void *user_data)
{
struct instance *i = (struct instance*)user_data;
i->work_iface->work_response(i->instance->lv2_handle, size, data);
return 0;
}
/** Called by the plugin to respond to non-RT work. */
static LV2_Worker_Status
work_respond(LV2_Worker_Respond_Handle handle, uint32_t size, const void *data)
{
struct instance *i = (struct instance*)handle;
struct context *c = i->desc->p->c;
spa_loop_invoke(c->data_loop, do_respond, 1, data, size, false, i);
return LV2_WORKER_SUCCESS;
}
static int
do_schedule(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
size_t size, void *user_data)
{
struct instance *i = (struct instance*)user_data;
i->work_iface->work(i->instance->lv2_handle, work_respond, i, size, data);
return 0;
}
/** Called by the plugin to schedule non-RT work. */
static LV2_Worker_Status
work_schedule(LV2_Worker_Schedule_Handle handle, uint32_t size, const void *data)
{
struct instance *i = (struct instance*)handle;
struct context *c = i->desc->p->c;
spa_loop_invoke(c->main_loop, do_schedule, 1, data, size, false, i);
return LV2_WORKER_SUCCESS;
}
static void *lv2_instantiate(const struct fc_descriptor *desc, static void *lv2_instantiate(const struct fc_descriptor *desc,
unsigned long *SampleRate, int index, const char *config) unsigned long *SampleRate, int index, const char *config)
{ {
struct descriptor *d = (struct descriptor*)desc; struct descriptor *d = (struct descriptor*)desc;
struct plugin *p = d->p; struct plugin *p = d->p;
struct context *c = p->c; struct context *c = p->c;
return lilv_plugin_instantiate(p->p, *SampleRate, c->features); struct instance *i;
uint32_t n_features = 0;
static const int32_t min_block_length = 1;
static const int32_t max_block_length = 8192;
static const int32_t seq_size = 32768;
float fsample_rate = *SampleRate;
i = calloc(1, sizeof(*i));
if (i == NULL)
return NULL;
i->block_length = 1024;
i->desc = d;
i->features[n_features++] = &c->map_feature;
i->features[n_features++] = &c->unmap_feature;
i->features[n_features++] = &buf_size_features[0];
i->features[n_features++] = &buf_size_features[1];
i->features[n_features++] = &buf_size_features[2];
if (lilv_plugin_has_feature(p->p, c->worker_schedule)) {
i->work_schedule.handle = i;
i->work_schedule.schedule_work = work_schedule;
i->work_schedule_feature.URI = LV2_WORKER__schedule;
i->work_schedule_feature.data = &i->work_schedule;
i->features[n_features++] = &i->work_schedule_feature;
}
i->options[0] = (LV2_Options_Option) { LV2_OPTIONS_INSTANCE, 0,
context_map(c, LV2_BUF_SIZE__minBlockLength), sizeof(int32_t),
c->atom_Int, &min_block_length };
i->options[1] = (LV2_Options_Option) { LV2_OPTIONS_INSTANCE, 0,
context_map(c, LV2_BUF_SIZE__maxBlockLength), sizeof(int32_t),
c->atom_Int, &max_block_length };
i->options[2] = (LV2_Options_Option) { LV2_OPTIONS_INSTANCE, 0,
context_map(c, LV2_BUF_SIZE__sequenceSize), sizeof(int32_t),
c->atom_Int, &seq_size };
i->options[3] = (LV2_Options_Option) { LV2_OPTIONS_INSTANCE, 0,
context_map(c, "http://lv2plug.in/ns/ext/buf-size#nominalBlockLength"), sizeof(int32_t),
c->atom_Int, &i->block_length },
i->options[4] = (LV2_Options_Option) { LV2_OPTIONS_INSTANCE, 0,
context_map(c, LV2_PARAMETERS__sampleRate), sizeof(float),
c->atom_Float, &fsample_rate };
i->options[5] = (LV2_Options_Option) { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, NULL };
i->options_feature.URI = LV2_OPTIONS__options;
i->options_feature.data = i->options;
i->features[n_features++] = &i->options_feature;
i->instance = lilv_plugin_instantiate(p->p, *SampleRate, i->features);
if (i->instance == NULL) {
free(i);
return NULL;
}
if (lilv_plugin_has_extension_data(p->p, c->worker_iface)) {
i->work_iface = (const LV2_Worker_Interface*)
lilv_instance_get_extension_data(i->instance, LV2_WORKER__interface);
}
return i;
} }
static void lv2_cleanup(void *instance) static void lv2_cleanup(void *instance)
{ {
lilv_instance_free(instance); struct instance *i = instance;
lilv_instance_free(i->instance);
free(i);
} }
static void lv2_connect_port(void *instance, unsigned long port, float *data) static void lv2_connect_port(void *instance, unsigned long port, float *data)
{ {
lilv_instance_connect_port(instance, port, data); struct instance *i = instance;
lilv_instance_connect_port(i->instance, port, data);
} }
static void lv2_activate(void *instance) static void lv2_activate(void *instance)
{ {
lilv_instance_activate(instance); struct instance *i = instance;
lilv_instance_activate(i->instance);
} }
static void lv2_deactivate(void *instance) static void lv2_deactivate(void *instance)
{ {
lilv_instance_deactivate(instance); struct instance *i = instance;
lilv_instance_deactivate(i->instance);
} }
static void lv2_run(void *instance, unsigned long SampleCount) static void lv2_run(void *instance, unsigned long SampleCount)
{ {
lilv_instance_run(instance, SampleCount); struct instance *i = instance;
lilv_instance_run(i->instance, SampleCount);
if (i->work_iface != NULL && i->work_iface->end_run != NULL)
i->work_iface->end_run(i->instance);
} }
static void lv2_free(struct fc_descriptor *desc) static void lv2_free(struct fc_descriptor *desc)
@ -319,7 +455,8 @@ static void lv2_unload(struct fc_plugin *plugin)
free(p); free(p);
} }
struct fc_plugin *load_lv2_plugin(const char *plugin_uri, const char *config) struct fc_plugin *load_lv2_plugin(const struct spa_support *support, uint32_t n_support,
const char *plugin_uri, const char *config)
{ {
struct context *c; struct context *c;
const LilvPlugins *plugins; const LilvPlugins *plugins;
@ -328,7 +465,7 @@ struct fc_plugin *load_lv2_plugin(const char *plugin_uri, const char *config)
int res; int res;
struct plugin *p; struct plugin *p;
c = context_ref(); c = context_ref(support, n_support);
if (c == NULL) if (c == NULL)
return NULL; return NULL;

View file

@ -28,6 +28,7 @@
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
#include <spa/support/plugin.h>
#include <spa/utils/defs.h> #include <spa/utils/defs.h>
#include <spa/utils/list.h> #include <spa/utils/list.h>
#include <spa/utils/string.h> #include <spa/utils/string.h>
@ -93,8 +94,9 @@ static inline void fc_descriptor_free(struct fc_descriptor *desc)
desc->free(desc); desc->free(desc);
} }
struct fc_plugin *load_ladspa_plugin(const char *path, const char *config); struct fc_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t n_support,
struct fc_plugin *load_lv2_plugin(const char *path, const char *config); const char *path, const char *config);
struct fc_plugin *load_builtin_plugin(const char *path, const char *config); struct fc_plugin *load_lv2_plugin(const struct spa_support *support, uint32_t n_support,
const char *path, const char *config);
void init_builtin_plugin(uint32_t cpu_flags); struct fc_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support,
const char *path, const char *config);