mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-03 09:01:54 -05:00
filter-chain: improve lv2 support
Add support for Worker. Add Options feature. Pass support in plugin load.
This commit is contained in:
parent
c04580a256
commit
8416d66ab3
5 changed files with 183 additions and 46 deletions
|
|
@ -39,7 +39,6 @@
|
|||
#include <spa/utils/string.h>
|
||||
#include <spa/utils/json.h>
|
||||
#include <spa/param/profiler.h>
|
||||
#include <spa/support/cpu.h>
|
||||
#include <spa/debug/pod.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 plugin *hndl;
|
||||
int res = 0;
|
||||
const struct spa_support *support;
|
||||
uint32_t n_support;
|
||||
|
||||
spa_list_for_each(hndl, &impl->plugin_list, link) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
support = pw_context_get_support(impl->context, &n_support);
|
||||
|
||||
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")) {
|
||||
pl = load_ladspa_plugin(path, NULL);
|
||||
pl = load_ladspa_plugin(support, n_support, path, NULL);
|
||||
}
|
||||
#ifdef HAVE_LILV
|
||||
else if (spa_streq(type, "lv2")) {
|
||||
pl = load_lv2_plugin(path, NULL);
|
||||
pl = load_lv2_plugin(support, n_support, path, NULL);
|
||||
}
|
||||
#endif
|
||||
if (pl == NULL)
|
||||
|
|
@ -1280,6 +1282,7 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_
|
|||
sd = dd = NULL;
|
||||
|
||||
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) {
|
||||
pw_log_error("cannot create plugin instance");
|
||||
res = -ENOMEM;
|
||||
|
|
@ -1650,9 +1653,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
struct impl *impl;
|
||||
uint32_t id = pw_global_get_id(pw_impl_module_get_global(module));
|
||||
const char *str;
|
||||
const struct spa_support *support;
|
||||
uint32_t n_support;
|
||||
struct spa_cpu *cpu_iface;
|
||||
int res;
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
props = pw_properties_new_string(args);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
#endif
|
||||
|
||||
#include <spa/utils/json.h>
|
||||
#include <spa/support/cpu.h>
|
||||
|
||||
#include <pipewire/log.h>
|
||||
|
||||
#include "plugin.h"
|
||||
|
|
@ -771,12 +773,11 @@ static struct fc_plugin builtin_plugin = {
|
|||
.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;
|
||||
}
|
||||
|
||||
void init_builtin_plugin(uint32_t cpu_flags)
|
||||
{
|
||||
pffft_select_cpu(cpu_flags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,7 +226,8 @@ exit:
|
|||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/list.h>
|
||||
#include <spa/utils/string.h>
|
||||
#include <spa/support/loop.h>
|
||||
|
||||
#include <pipewire/log.h>
|
||||
#include <pipewire/utils.h>
|
||||
|
|
@ -36,6 +37,9 @@
|
|||
#include <lilv/lilv.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/worker/worker.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/options/options.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/parameters/parameters.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)
|
||||
{
|
||||
URITable *table = (URITable*)handle;
|
||||
char *p;
|
||||
char **p;
|
||||
size_t i = 0;
|
||||
|
||||
pw_array_for_each(p, &table->array) {
|
||||
if (spa_streq(p, uri))
|
||||
return i + 1;
|
||||
i++;
|
||||
if (spa_streq(*p, uri))
|
||||
goto done;
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -87,6 +92,9 @@ struct context {
|
|||
int ref;
|
||||
LilvWorld *world;
|
||||
|
||||
struct spa_loop *data_loop;
|
||||
struct spa_loop *main_loop;
|
||||
|
||||
LilvNode *lv2_InputPort;
|
||||
LilvNode *lv2_OutputPort;
|
||||
LilvNode *lv2_AudioPort;
|
||||
|
|
@ -98,18 +106,25 @@ struct context {
|
|||
LilvNode *powerOf2BlockLength;
|
||||
LilvNode *fixedBlockLength;
|
||||
LilvNode *boundedBlockLength;
|
||||
LilvNode* worker_schedule;
|
||||
LilvNode* worker_iface;
|
||||
|
||||
URITable uri_table;
|
||||
LV2_URID_Map map;
|
||||
LV2_URID_Unmap unmap;
|
||||
LV2_Feature map_feature;
|
||||
LV2_URID_Unmap unmap;
|
||||
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)
|
||||
{
|
||||
if (c->world) {
|
||||
lilv_node_free(c->worker_schedule);
|
||||
lilv_node_free(c->powerOf2BlockLength);
|
||||
lilv_node_free(c->fixedBlockLength);
|
||||
lilv_node_free(c->boundedBlockLength);
|
||||
|
|
@ -133,7 +148,7 @@ static const LV2_Feature buf_size_features[3] = {
|
|||
{ 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;
|
||||
|
||||
|
|
@ -159,6 +174,8 @@ static struct context *context_new(void)
|
|||
c->powerOf2BlockLength = lilv_new_uri(c->world, LV2_BUF_SIZE__powerOf2BlockLength);
|
||||
c->fixedBlockLength = lilv_new_uri(c->world, LV2_BUF_SIZE__fixedBlockLength);
|
||||
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.map = uri_table_map;
|
||||
|
|
@ -168,11 +185,12 @@ static struct context *context_new(void)
|
|||
c->unmap.unmap = uri_table_unmap;
|
||||
c->unmap_feature.URI = LV2_URID_UNMAP_URI;
|
||||
c->unmap_feature.data = &c->unmap;
|
||||
c->features[0] = &c->map_feature;
|
||||
c->features[1] = &c->unmap_feature;
|
||||
c->features[2] = &buf_size_features[0];
|
||||
c->features[3] = &buf_size_features[1];
|
||||
c->features[4] = &buf_size_features[2];
|
||||
|
||||
c->atom_Int = context_map(c, LV2_ATOM__Int);
|
||||
c->atom_Float = context_map(c, LV2_ATOM__Float);
|
||||
|
||||
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;
|
||||
error:
|
||||
|
|
@ -180,10 +198,10 @@ error:
|
|||
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) {
|
||||
_context = context_new();
|
||||
_context = context_new(support, n_support);
|
||||
if (_context == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -210,38 +228,156 @@ struct descriptor {
|
|||
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,
|
||||
unsigned long *SampleRate, int index, const char *config)
|
||||
{
|
||||
struct descriptor *d = (struct descriptor*)desc;
|
||||
struct plugin *p = d->p;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
lilv_instance_activate(instance);
|
||||
struct instance *i = instance;
|
||||
lilv_instance_activate(i->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)
|
||||
{
|
||||
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)
|
||||
|
|
@ -319,7 +455,8 @@ static void lv2_unload(struct fc_plugin *plugin)
|
|||
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;
|
||||
const LilvPlugins *plugins;
|
||||
|
|
@ -328,7 +465,7 @@ struct fc_plugin *load_lv2_plugin(const char *plugin_uri, const char *config)
|
|||
int res;
|
||||
struct plugin *p;
|
||||
|
||||
c = context_ref();
|
||||
c = context_ref(support, n_support);
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <spa/support/plugin.h>
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/list.h>
|
||||
#include <spa/utils/string.h>
|
||||
|
|
@ -93,8 +94,9 @@ static inline void fc_descriptor_free(struct fc_descriptor *desc)
|
|||
desc->free(desc);
|
||||
}
|
||||
|
||||
struct fc_plugin *load_ladspa_plugin(const char *path, const char *config);
|
||||
struct fc_plugin *load_lv2_plugin(const char *path, const char *config);
|
||||
struct fc_plugin *load_builtin_plugin(const char *path, const char *config);
|
||||
|
||||
void init_builtin_plugin(uint32_t cpu_flags);
|
||||
struct fc_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t n_support,
|
||||
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);
|
||||
struct fc_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support,
|
||||
const char *path, const char *config);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue