blob: 2ee153911dbb51d2a9824e85d5c7cc50fa4b4244 [file] [log] [blame]
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <dlfcn.h>
#include <syslog.h>
#include <ladspa.h>
#include "cras_dsp_module.h"
#define PLUGIN_PATH_PREFIX "/usr/lib/ladspa"
#define PLUGIN_PATH_MAX 256
struct ladspa_data {
void *dlopen_handle; /* the handle returned by dlopen() */
const LADSPA_Descriptor *descriptor;
LADSPA_Handle *handle; /* returned by instantiate() */
int activated;
};
static void activate(struct dsp_module *module)
{
struct ladspa_data *data = module->data;
const LADSPA_Descriptor *desc = data->descriptor;
data->activated = 1;
if (!desc->activate)
return;
desc->activate(data->handle);
}
static void deactivate(struct dsp_module *module)
{
struct ladspa_data *data = module->data;
const LADSPA_Descriptor *desc = data->descriptor;
data->activated = 0;
if (!desc->deactivate)
return;
desc->deactivate(data->handle);
}
static int instantiate(struct dsp_module *module, unsigned long sample_rate)
{
struct ladspa_data *data = module->data;
const LADSPA_Descriptor *desc = data->descriptor;
data->handle = desc->instantiate(desc, sample_rate);
if (!data->handle) {
syslog(LOG_ERR, "instantiate failed for %s, rate %ld",
desc->Label, sample_rate);
return -1;
}
return 0;
}
static void deinstantiate(struct dsp_module *module)
{
struct ladspa_data *data = module->data;
const LADSPA_Descriptor *desc = data->descriptor;
if (data->activated)
deactivate(module);
desc->cleanup(data->handle);
data->handle = NULL;
}
static void connect_port(struct dsp_module *module, unsigned long port,
float *data_location)
{
struct ladspa_data *data = module->data;
const LADSPA_Descriptor *desc = data->descriptor;
desc->connect_port(data->handle, port, data_location);
}
static int get_delay(struct dsp_module *module)
{
return 0;
}
static void run(struct dsp_module *module, unsigned long sample_count)
{
struct ladspa_data *data = module->data;
const LADSPA_Descriptor *desc = data->descriptor;
if (!data->activated)
activate(module);
desc->run(data->handle, sample_count);
}
static void free_module(struct dsp_module *module)
{
struct ladspa_data *data = module->data;
if (data->activated)
deactivate(module);
if (data->dlopen_handle) {
dlclose(data->dlopen_handle);
data->dlopen_handle = NULL;
}
free(module->data);
free(module);
}
static int get_properties(struct dsp_module *module)
{
struct ladspa_data *data = module->data;
int properties = 0;
if (LADSPA_IS_INPLACE_BROKEN(data->descriptor->Properties))
properties |= MODULE_INPLACE_BROKEN;
return properties;
}
static void dump(struct dsp_module *module, struct dumper *d)
{
struct ladspa_data *data = module->data;
const LADSPA_Descriptor *descriptor = data->descriptor;
dumpf(d, " LADSPA: dlopen=%p, desc=%p, handle=%p, activated=%d\n",
data->dlopen_handle, data->descriptor, data->handle,
data->activated);
if (descriptor) {
dumpf(d, " Name=%s\n", descriptor->Name);
dumpf(d, " Maker=%s\n", descriptor->Maker);
}
}
static int verify_plugin_descriptor(struct plugin *plugin,
const LADSPA_Descriptor *desc)
{
int i;
struct port *port;
if (desc->PortCount != ARRAY_COUNT(&plugin->ports)) {
syslog(LOG_ERR, "port count mismatch: %s", plugin->title);
return -1;
}
ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) {
LADSPA_PortDescriptor port_desc = desc->PortDescriptors[i];
if ((port->direction == PORT_INPUT) !=
!!(port_desc & LADSPA_PORT_INPUT)) {
syslog(LOG_ERR, "port direction mismatch: %s:%d!",
plugin->title, i);
return -1;
}
if ((port->type == PORT_CONTROL) !=
!!(port_desc & LADSPA_PORT_CONTROL)) {
syslog(LOG_ERR, "port type mismatch: %s:%d!",
plugin->title, i);
return -1;
}
}
return 0;
}
struct dsp_module *cras_dsp_module_load_ladspa(struct plugin *plugin)
{
char path[PLUGIN_PATH_MAX];
int index;
LADSPA_Descriptor_Function desc_func;
struct ladspa_data *data = calloc(1, sizeof(struct ladspa_data));
struct dsp_module *module;
snprintf(path, sizeof(path), "%s/%s", PLUGIN_PATH_PREFIX,
plugin->library);
data->dlopen_handle = dlopen(path, RTLD_NOW);
if (!data->dlopen_handle) {
syslog(LOG_ERR, "cannot open plugin from %s: %s", path,
dlerror());
goto bail;
}
desc_func = (LADSPA_Descriptor_Function)dlsym(data->dlopen_handle,
"ladspa_descriptor");
if (!desc_func) {
syslog(LOG_ERR, "cannot find descriptor function from %s: %s",
path, dlerror());
goto bail;
}
for (index = 0;; index++) {
const LADSPA_Descriptor *desc = desc_func(index);
if (desc == NULL) {
syslog(LOG_ERR, "cannot find label %s from %s",
plugin->label, path);
goto bail;
}
if (strcmp(desc->Label, plugin->label) == 0) {
syslog(LOG_DEBUG, "plugin '%s' loaded from %s",
plugin->label, path);
if (verify_plugin_descriptor(plugin, desc) != 0)
goto bail;
data->descriptor = desc;
break;
}
}
module = calloc(1, sizeof(struct dsp_module));
module->data = data;
module->instantiate = &instantiate;
module->connect_port = &connect_port;
module->get_delay = &get_delay;
module->run = &run;
module->deinstantiate = &deinstantiate;
module->get_properties = &get_properties;
module->free_module = &free_module;
module->dump = &dump;
return module;
bail:
if (data->dlopen_handle)
dlclose(data->dlopen_handle);
free(data);
return NULL;
}