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