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 
activate(struct dsp_module * module)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 
deactivate(struct dsp_module * module)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 
instantiate(struct dsp_module * module,unsigned long sample_rate)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 
deinstantiate(struct dsp_module * module)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 
connect_port(struct dsp_module * module,unsigned long port,float * data_location)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 
get_delay(struct dsp_module * module)75 static int get_delay(struct dsp_module *module)
76 {
77 	return 0;
78 }
79 
run(struct dsp_module * module,unsigned long sample_count)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 
free_module(struct dsp_module * module)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 
get_properties(struct dsp_module * module)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 
dump(struct dsp_module * module,struct dumper * d)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 
verify_plugin_descriptor(struct plugin * plugin,const LADSPA_Descriptor * desc)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 	ARRAY_ELEMENT_FOREACH (&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 
cras_dsp_module_load_ladspa(struct plugin * plugin)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