Home | History | Annotate | Download | only in server
      1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #include <dlfcn.h>
      7 #include <syslog.h>
      8 #include <ladspa.h>
      9 
     10 #include "cras_dsp_module.h"
     11 
     12 #define PLUGIN_PATH_PREFIX "/usr/lib/ladspa"
     13 #define PLUGIN_PATH_MAX 256
     14 
     15 struct ladspa_data {
     16 	void *dlopen_handle;  /* the handle returned by dlopen() */
     17 	const LADSPA_Descriptor *descriptor;
     18 	LADSPA_Handle *handle;	/* returned by instantiate() */
     19 	int activated;
     20 };
     21 
     22 static void activate(struct dsp_module *module)
     23 {
     24 	struct ladspa_data *data = module->data;
     25 	const LADSPA_Descriptor *desc = data->descriptor;
     26 	data->activated = 1;
     27 	if (!desc->activate)
     28 		return;
     29 	desc->activate(data->handle);
     30 }
     31 
     32 static void deactivate(struct dsp_module *module)
     33 {
     34 	struct ladspa_data *data = module->data;
     35 	const LADSPA_Descriptor *desc = data->descriptor;
     36 	data->activated = 0;
     37 	if (!desc->deactivate)
     38 		return;
     39 	desc->deactivate(data->handle);
     40 }
     41 
     42 static int instantiate(struct dsp_module *module, unsigned long sample_rate)
     43 {
     44 	struct ladspa_data *data = module->data;
     45 	const LADSPA_Descriptor *desc = data->descriptor;
     46 
     47 	data->handle = desc->instantiate(desc, sample_rate);
     48 	if (!data->handle) {
     49 		syslog(LOG_ERR, "instantiate failed for %s, rate %ld",
     50 		       desc->Label, sample_rate);
     51 		return -1;
     52 	}
     53 	return 0;
     54 }
     55 
     56 static void deinstantiate(struct dsp_module *module)
     57 {
     58 	struct ladspa_data *data = module->data;
     59 	const LADSPA_Descriptor *desc = data->descriptor;
     60 
     61 	if (data->activated)
     62 		deactivate(module);
     63 	desc->cleanup(data->handle);
     64 	data->handle = NULL;
     65 }
     66 
     67 static void connect_port(struct dsp_module *module, unsigned long port,
     68 			     float *data_location)
     69 {
     70 	struct ladspa_data *data = module->data;
     71 	const LADSPA_Descriptor *desc = data->descriptor;
     72 	desc->connect_port(data->handle, port, data_location);
     73 }
     74 
     75 static int get_delay(struct dsp_module *module)
     76 {
     77 	return 0;
     78 }
     79 
     80 static void run(struct dsp_module *module, unsigned long sample_count)
     81 {
     82 	struct ladspa_data *data = module->data;
     83 	const LADSPA_Descriptor *desc = data->descriptor;
     84 
     85 	if (!data->activated)
     86 		activate(module);
     87 	desc->run(data->handle, sample_count);
     88 }
     89 
     90 static void free_module(struct dsp_module *module)
     91 {
     92 	struct ladspa_data *data = module->data;
     93 	if (data->activated)
     94 		deactivate(module);
     95 	if (data->dlopen_handle) {
     96 		dlclose(data->dlopen_handle);
     97 		data->dlopen_handle = NULL;
     98 	}
     99 	free(module->data);
    100 	free(module);
    101 }
    102 
    103 static int get_properties(struct dsp_module *module)
    104 {
    105 	struct ladspa_data *data = module->data;
    106 	int properties = 0;
    107 	if (LADSPA_IS_INPLACE_BROKEN(data->descriptor->Properties))
    108 		properties |= MODULE_INPLACE_BROKEN;
    109 	return properties;
    110 }
    111 
    112 static void dump(struct dsp_module *module, struct dumper *d)
    113 {
    114 	struct ladspa_data *data = module->data;
    115 	const LADSPA_Descriptor *descriptor = data->descriptor;
    116 
    117 	dumpf(d, "  LADSPA: dlopen=%p, desc=%p, handle=%p, activated=%d\n",
    118 	      data->dlopen_handle, data->descriptor, data->handle,
    119 	      data->activated);
    120 	if (descriptor) {
    121 		dumpf(d, "   Name=%s\n", descriptor->Name);
    122 		dumpf(d, "   Maker=%s\n", descriptor->Maker);
    123 	}
    124 }
    125 
    126 static int verify_plugin_descriptor(struct plugin *plugin,
    127 				    const LADSPA_Descriptor *desc)
    128 {
    129 	int i;
    130 	struct port *port;
    131 
    132 	if (desc->PortCount != ARRAY_COUNT(&plugin->ports)) {
    133 		syslog(LOG_ERR, "port count mismatch: %s", plugin->title);
    134 		return -1;
    135 	}
    136 
    137 	FOR_ARRAY_ELEMENT(&plugin->ports, i, port) {
    138 		LADSPA_PortDescriptor port_desc = desc->PortDescriptors[i];
    139 		if ((port->direction == PORT_INPUT) !=
    140 		    !!(port_desc & LADSPA_PORT_INPUT)) {
    141 			syslog(LOG_ERR, "port direction mismatch: %s:%d!",
    142 			       plugin->title, i);
    143 			return -1;
    144 		}
    145 
    146 		if ((port->type == PORT_CONTROL) !=
    147 		    !!(port_desc & LADSPA_PORT_CONTROL)) {
    148 			syslog(LOG_ERR, "port type mismatch: %s:%d!",
    149 			       plugin->title, i);
    150 			return -1;
    151 		}
    152 	}
    153 
    154 	return 0;
    155 }
    156 
    157 struct dsp_module *cras_dsp_module_load_ladspa(struct plugin *plugin)
    158 {
    159 	char path[PLUGIN_PATH_MAX];
    160 	int index;
    161 	LADSPA_Descriptor_Function desc_func;
    162 	struct ladspa_data *data = calloc(1, sizeof(struct ladspa_data));
    163 	struct dsp_module *module;
    164 
    165 	snprintf(path, sizeof(path), "%s/%s", PLUGIN_PATH_PREFIX,
    166 		 plugin->library);
    167 
    168 	data->dlopen_handle = dlopen(path, RTLD_NOW);
    169 	if (!data->dlopen_handle) {
    170 		syslog(LOG_ERR, "cannot open plugin from %s: %s", path,
    171 		       dlerror());
    172 		goto bail;
    173 	}
    174 
    175 	desc_func = (LADSPA_Descriptor_Function)dlsym(data->dlopen_handle,
    176 						      "ladspa_descriptor");
    177 
    178 	if (!desc_func) {
    179 		syslog(LOG_ERR, "cannot find descriptor function from %s: %s",
    180 		       path, dlerror());
    181 		goto bail;
    182 	}
    183 
    184 	for (index = 0; ; index++) {
    185 		const LADSPA_Descriptor *desc = desc_func(index);
    186 		if (desc == NULL) {
    187 			syslog(LOG_ERR, "cannot find label %s from %s",
    188 			       plugin->label, path);
    189 			goto bail;
    190 		}
    191 		if (strcmp(desc->Label, plugin->label) == 0) {
    192 			syslog(LOG_DEBUG, "plugin '%s' loaded from %s",
    193 			       plugin->label, path);
    194 			if (verify_plugin_descriptor(plugin, desc) != 0)
    195 				goto bail;
    196 			data->descriptor = desc;
    197 			break;
    198 		}
    199 	}
    200 
    201 	module = calloc(1, sizeof(struct dsp_module));
    202 	module->data = data;
    203 	module->instantiate = &instantiate;
    204 	module->connect_port = &connect_port;
    205 	module->get_delay = &get_delay;
    206 	module->run = &run;
    207 	module->deinstantiate = &deinstantiate;
    208 	module->get_properties = &get_properties;
    209 	module->free_module = &free_module;
    210 	module->dump = &dump;
    211 	return module;
    212 bail:
    213 	if (data->dlopen_handle)
    214 		dlclose(data->dlopen_handle);
    215 	free(data);
    216 	return NULL;
    217 }
    218