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 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
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