1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  *
28  * mod_ladspa.c -- LADSPA
29  *
30  */
31 #include <switch.h>
32 #include "ladspa.h"
33 #include "utils.h"
34 
35 /* Prototypes */
36 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown);
37 SWITCH_MODULE_RUNTIME_FUNCTION(mod_ladspa_runtime);
38 SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load);
39 
40 /* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
41  * Defines a switch_loadable_module_function_table_t and a static const char[] modname
42  */
43 SWITCH_MODULE_DEFINITION(mod_ladspa, mod_ladspa_load, mod_ladspa_shutdown, NULL);
44 
45 #define MAX_INDEX 256
46 
47 typedef struct {
48 	switch_core_session_t *session;
49 	char *plugin_name;
50 	char *label_name;
51 	void *library_handle;
52 	const LADSPA_Descriptor *ldesc;
53 	LADSPA_Handle handle;
54 	LADSPA_Data config[MAX_INDEX];
55 	int num_idx;
56 	char *str_config[MAX_INDEX];
57 	int str_idx;
58 	uint8_t has_config[MAX_INDEX];
59 	int skip;
60 	LADSPA_Data in_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
61 	LADSPA_Data file_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
62 	LADSPA_Data out_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
63 	LADSPA_Data out_ports[MAX_INDEX];
64 	switch_file_handle_t fh;
65 } switch_ladspa_t;
66 
67 
68 
check_range(const LADSPA_Descriptor * ldesc,int i,LADSPA_Data val)69 int check_range(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data val)
70 {
71 	if (ldesc->PortRangeHints[i].LowerBound && ldesc->PortRangeHints[i].UpperBound &&
72 		(val < ldesc->PortRangeHints[i].LowerBound || val > ldesc->PortRangeHints[i].UpperBound)) {
73 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Param %f out of bounds %f-%f\n",
74 						  val, ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
75 		return 0;
76 	}
77 
78 	return 1;
79 }
80 
find_default(const LADSPA_Descriptor * ldesc,int i,LADSPA_Data * ptr)81 int find_default(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data *ptr)
82 
83 {
84 	LADSPA_Data dftval = 0;
85 	int fail = 0;
86 
87 	LADSPA_PortRangeHintDescriptor port_hint = ldesc->PortRangeHints[i].HintDescriptor;
88 
89 	switch (port_hint & LADSPA_HINT_DEFAULT_MASK) {
90 	case LADSPA_HINT_DEFAULT_NONE:
91 		break;
92 	case LADSPA_HINT_DEFAULT_MINIMUM:
93 		dftval = ldesc->PortRangeHints[i].LowerBound;
94 		break;
95 	case LADSPA_HINT_DEFAULT_LOW:
96 		if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
97 			dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
98 						 * 0.75 + log(ldesc->PortRangeHints[i].UpperBound)
99 						 * 0.25);
100 		} else {
101 			dftval = (ldesc->PortRangeHints[i].LowerBound * 0.75 + ldesc->PortRangeHints[i].UpperBound * 0.25);
102 		}
103 		break;
104 	case LADSPA_HINT_DEFAULT_MIDDLE:
105 		if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
106 			dftval = sqrt(ldesc->PortRangeHints[i].LowerBound * ldesc->PortRangeHints[i].UpperBound);
107 		} else {
108 			dftval = 0.5 * (ldesc->PortRangeHints[i].LowerBound + ldesc->PortRangeHints[i].UpperBound);
109 		}
110 		break;
111 	case LADSPA_HINT_DEFAULT_HIGH:
112 		if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
113 			dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
114 						 * 0.25 + log(ldesc->PortRangeHints[i].UpperBound)
115 						 * 0.75);
116 		} else {
117 			dftval = (ldesc->PortRangeHints[i].LowerBound * 0.25 + ldesc->PortRangeHints[i].UpperBound * 0.75);
118 		}
119 		break;
120 	case LADSPA_HINT_DEFAULT_MAXIMUM:
121 		dftval = ldesc->PortRangeHints[i].UpperBound;
122 		break;
123 	case LADSPA_HINT_DEFAULT_0:
124 		dftval = 0;
125 		break;
126 	case LADSPA_HINT_DEFAULT_1:
127 		dftval = 1;
128 		break;
129 	case LADSPA_HINT_DEFAULT_100:
130 		dftval = 100;
131 		break;
132 	case LADSPA_HINT_DEFAULT_440:
133 		dftval = 440;
134 		break;
135 	default:
136 		fail = 1;
137 		break;
138 	}
139 
140 	if (!fail) {
141 		*ptr = dftval;
142 	}
143 
144 	return !fail;
145 }
146 
dump_info(const LADSPA_Descriptor * ldesc)147 static void dump_info(const LADSPA_Descriptor *ldesc)
148 {
149 	int i = 0;
150 
151 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Name: \"%s\"\n", ldesc->Name);
152 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Label: \"%s\"\n", ldesc->Label);
153 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Unique ID: %lu\n", ldesc->UniqueID);
154 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Maker: \"%s\"\n", ldesc->Maker);
155 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Copyright: \"%s\"\n", ldesc->Copyright);
156 
157 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Must Run Real-Time: ");
158 	if (LADSPA_IS_REALTIME(ldesc->Properties))
159 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
160 	else
161 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
162 
163 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has activate() Function: ");
164 	if (ldesc->activate != NULL)
165 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
166 	else
167 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
168 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has deactivate() Function: ");
169 	if (ldesc->deactivate != NULL)
170 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
171 	else
172 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
173 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has run_adding() Function: ");
174 	if (ldesc->run_adding != NULL)
175 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
176 	else
177 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
178 
179 	if (ldesc->instantiate == NULL)
180 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO INSTANTIATE FUNCTION.\n");
181 	if (ldesc->connect_port == NULL)
182 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CONNECT_PORT FUNCTION.\n");
183 	if (ldesc->run == NULL)
184 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO RUN FUNCTION.\n");
185 	if (ldesc->run_adding != NULL && ldesc->set_run_adding_gain == NULL)
186 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS RUN_ADDING FUNCTION BUT " "NOT SET_RUN_ADDING_GAIN.\n");
187 	if (ldesc->run_adding == NULL && ldesc->set_run_adding_gain != NULL)
188 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS SET_RUN_ADDING_GAIN FUNCTION BUT " "NOT RUN_ADDING.\n");
189 	if (ldesc->cleanup == NULL)
190 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CLEANUP FUNCTION.\n");
191 
192 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Environment: ");
193 	if (LADSPA_IS_HARD_RT_CAPABLE(ldesc->Properties))
194 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal or Hard Real-Time\n");
195 	else
196 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal\n");
197 
198 	if (LADSPA_IS_INPLACE_BROKEN(ldesc->Properties))
199 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "This plugin cannot use in-place processing. " "It will not work with all hosts.\n");
200 
201 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Ports:");
202 
203 	if (ldesc->PortCount == 0)
204 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\tERROR: PLUGIN HAS NO PORTS.\n");
205 
206 	for (i = 0; i < ldesc->PortCount; i++) {
207 		LADSPA_Data dft = 0.0f;
208 		int found = 0;
209 
210 		if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
211 			found = find_default(ldesc, i, &dft);
212 		}
213 
214 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n  \"%s\" ", ldesc->PortNames[i]);
215 
216 		if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i])
217 			&& LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
218 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: INPUT AND OUTPUT");
219 		else if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i]))
220 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "input");
221 		else if (LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
222 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "output");
223 		else
224 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: NEITHER INPUT NOR OUTPUT");
225 
226 		if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])
227 			&& LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
228 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: CONTROL AND AUDIO");
229 		else if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i]))
230 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", control");
231 		else if (LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
232 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", audio");
233 		else
234 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: NEITHER CONTROL NOR AUDIO");
235 
236 		if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
237 			if (found) {
238 				switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n    RANGE: %f-%f DEFAULT: %f\n",
239 								  ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound, dft);
240 			} else {
241 				switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n    RANGE: %f-%f DEFAULT: none.\n",
242 								  ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
243 			}
244 		}
245 
246 
247 
248 	}
249 
250 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n\n");
251 }
252 
253 
254 
255 
256 
ladspa_callback(switch_media_bug_t * bug,void * user_data,switch_abc_type_t type)257 static switch_bool_t ladspa_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
258 {
259 	switch_ladspa_t *pvt = (switch_ladspa_t *) user_data;
260 	//switch_frame_t *frame = NULL;
261 	switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
262 
263 	switch (type) {
264 	case SWITCH_ABC_TYPE_INIT:
265 		{
266 			switch_codec_implementation_t read_impl = { 0 };
267 			LADSPA_PortDescriptor port_desc;
268 			int i = 0, j = 0, k = 0, str_idx = 0;
269 
270 			switch_core_session_get_read_impl(pvt->session, &read_impl);
271 
272 			if (!(pvt->library_handle = loadLADSPAPluginLibrary(pvt->plugin_name))) {
273 				return SWITCH_FALSE;
274 			}
275 
276 			if (!(pvt->ldesc = findLADSPAPluginDescriptor(pvt->library_handle, pvt->plugin_name, pvt->label_name))) {
277 				return SWITCH_FALSE;
278 			}
279 
280 
281 			pvt->handle = pvt->ldesc->instantiate(pvt->ldesc, read_impl.actual_samples_per_second);
282 
283 			dump_info(pvt->ldesc);
284 
285 
286 			for (i = 0; i < pvt->ldesc->PortCount; i++) {
287 				port_desc = pvt->ldesc->PortDescriptors[i];
288 
289 				if (LADSPA_IS_PORT_CONTROL(port_desc) && LADSPA_IS_PORT_INPUT(port_desc)) {
290 					LADSPA_Data dft = 0.0f;
291 					int found = find_default(pvt->ldesc, i, &dft);
292 
293 					if (found && !pvt->has_config[j]) {
294 						pvt->config[j] = dft;
295 						pvt->has_config[j] = 1;
296 					}
297 
298 					if (pvt->has_config[j]) {
299 						if (!check_range(pvt->ldesc, i, pvt->config[j])) {
300 							pvt->config[j] = dft;
301 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_WARNING, "FALLING TO DEFAULT PARAM %d [%s] (%f)\n",
302 											  j+1,
303 											  pvt->ldesc->PortNames[i],
304 											  pvt->config[j]);
305 						}
306 
307 						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "ADDING PARAM %d [%s] (%f)\n",
308 										  j+1,
309 										  pvt->ldesc->PortNames[i],
310 										  pvt->config[j]);
311 						pvt->ldesc->connect_port(pvt->handle, i, &pvt->config[j++]);
312 						usleep(10000);
313 					}
314 				}
315 
316 				if (LADSPA_IS_PORT_INPUT(port_desc) && LADSPA_IS_PORT_AUDIO(port_desc)) {
317 					int mapped = 0;
318 
319 					if (pvt->str_idx && !zstr(pvt->str_config[str_idx])) {
320 
321 						if (!strcasecmp(pvt->str_config[str_idx], "none")) {
322 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT NOTHING to port: %s\n",
323 											  pvt->ldesc->PortNames[i]
324 											  );
325 							mapped = 1;
326 						} else if (!strncasecmp(pvt->str_config[str_idx], "file:", 5)) {
327 							char *file = pvt->str_config[str_idx] + 5;
328 
329 							if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
330 								switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session),
331 												  SWITCH_LOG_ERROR, "CAN'T CONNECT FILE [%s] File already mapped\n", file);
332 							} else {
333 								if (switch_core_file_open(&pvt->fh,
334 														  file,
335 														  read_impl.number_of_channels,
336 														  read_impl.actual_samples_per_second,
337 														  SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
338 									switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot open file: %s\n", file);
339 									return SWITCH_FALSE;
340 								}
341 
342 
343 								switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT FILE [%s] to port: %s\n",
344 												  file,
345 												  pvt->ldesc->PortNames[i]
346 												  );
347 
348 								pvt->ldesc->connect_port(pvt->handle, i, pvt->file_buf);
349 								mapped = 1;
350 							}
351 						}
352 
353 						str_idx++;
354 					}
355 
356 					if (!mapped) {
357 						pvt->ldesc->connect_port(pvt->handle, i, pvt->in_buf);
358 						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT CHANNEL AUDIO to port: %s\n",
359 										  pvt->ldesc->PortNames[i]
360 										  );
361 					}
362 
363 				}
364 
365 				if (LADSPA_IS_PORT_OUTPUT(port_desc)) {
366 					if (LADSPA_IS_PORT_AUDIO(port_desc)) {
367 						pvt->ldesc->connect_port(pvt->handle, i, pvt->out_buf);
368 					} else if (k < MAX_INDEX) {
369 						pvt->ldesc->connect_port(pvt->handle, i, &pvt->out_ports[k++]);
370 					}
371 				}
372 			}
373 		}
374 
375 		break;
376 
377 	case SWITCH_ABC_TYPE_CLOSE:
378 		{
379 
380 			if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
381 				switch_core_file_close(&pvt->fh);
382 			}
383 
384 			if (pvt->handle && pvt->ldesc) {
385 				pvt->ldesc->cleanup(pvt->handle);
386 			}
387 
388 			if (pvt->library_handle) {
389 				unloadLADSPAPluginLibrary(pvt->library_handle);
390 			}
391 		}
392 		break;
393 
394 	case SWITCH_ABC_TYPE_WRITE_REPLACE:
395 	case SWITCH_ABC_TYPE_READ_REPLACE:
396 		{
397 			switch_frame_t *rframe;
398 			int16_t *slin, abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] =  { 0 };
399 			switch_size_t olen = 0;
400 
401 
402 			if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
403 				rframe = switch_core_media_bug_get_read_replace_frame(bug);
404 			} else {
405 				rframe = switch_core_media_bug_get_write_replace_frame(bug);
406 			}
407 
408 			slin = rframe->data;
409 
410 			if (switch_channel_media_ready(channel)) {
411 				switch_short_to_float(slin, pvt->in_buf, rframe->samples);
412 
413 				if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
414 					olen = rframe->samples;
415 					if (switch_core_file_read(&pvt->fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
416 						switch_codec_implementation_t read_impl = { 0 };
417 						char *file = switch_core_session_strdup(pvt->session, pvt->fh.file_path);
418 						switch_core_session_get_read_impl(pvt->session, &read_impl);
419 
420 						switch_core_file_close(&pvt->fh);
421 
422 						if (switch_core_file_open(&pvt->fh,
423 												  file,
424 												  read_impl.number_of_channels,
425 												  read_impl.actual_samples_per_second,
426 												  SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
427 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot open file: %s\n", file);
428 							return SWITCH_FALSE;
429 						}
430 
431 						olen = rframe->samples;
432 						if (switch_core_file_read(&pvt->fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
433 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot READ file: %s\n", file);
434 							return SWITCH_FALSE;
435 						}
436 					}
437 
438 					switch_short_to_float(abuf, pvt->file_buf, olen);
439 				}
440 
441 				pvt->ldesc->run(pvt->handle, rframe->samples);
442 
443 				switch_float_to_short(pvt->out_buf, slin, rframe->samples);
444 			}
445 
446 			if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
447 				switch_core_media_bug_set_read_replace_frame(bug, rframe);
448 			} else {
449 				switch_core_media_bug_set_write_replace_frame(bug, rframe);
450 			}
451 
452 			if (pvt->skip && !--pvt->skip) {
453 				return SWITCH_FALSE;
454 			}
455 
456 		}
457 		break;
458 	case SWITCH_ABC_TYPE_WRITE:
459 	default:
460 		break;
461 	}
462 
463 	return SWITCH_TRUE;
464 }
465 
stop_ladspa_session(switch_core_session_t * session)466 switch_status_t stop_ladspa_session(switch_core_session_t *session)
467 {
468 	switch_media_bug_t *bug;
469 	switch_channel_t *channel = switch_core_session_get_channel(session);
470 
471 	if ((bug = switch_channel_get_private(channel, "ladspa"))) {
472 		switch_channel_set_private(channel, "ladspa", NULL);
473 		switch_core_media_bug_remove(session, &bug);
474 		return SWITCH_STATUS_SUCCESS;
475 	}
476 
477 	return SWITCH_STATUS_FALSE;
478 }
479 
ladspa_session(switch_core_session_t * session,const char * flags,const char * plugin_name,const char * label,const char * params)480 switch_status_t ladspa_session(switch_core_session_t *session, const char *flags, const char *plugin_name, const char *label, const char *params)
481 {
482 	switch_channel_t *channel = switch_core_session_get_channel(session);
483 	switch_media_bug_t *bug;
484 	switch_status_t status;
485 	switch_ladspa_t *pvt = { 0 };
486 	switch_codec_implementation_t read_impl = { 0 };
487 	int i, bflags = SMBF_READ_REPLACE | SMBF_ANSWER_REQ;
488 	char *pstr;
489 	int argc;
490 	char *argv[50];
491 	char *dparams = NULL;
492 
493 	if (zstr(plugin_name)) {
494 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s INVALID PLUGIN\n", switch_channel_get_name(channel));
495 		return SWITCH_STATUS_FALSE;
496 	}
497 
498 	if (zstr(flags)) {
499 		flags = "r";
500 	}
501 
502 	if (strchr(flags, 'w')) {
503 		bflags = SMBF_WRITE_REPLACE;
504 	}
505 
506 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "FLAGS: %s PLUGIN: %s LABEL: %s PARAMS: %s\n",
507 					  flags, plugin_name, label, params);
508 
509 	switch_core_session_get_read_impl(session, &read_impl);
510 
511 	pvt = switch_core_session_alloc(session, sizeof(*pvt));
512 
513    	pvt->session = session;
514 	if (!zstr(label)) {
515 		pvt->label_name = switch_core_session_strdup(session, label);
516 	} else {
517 		char *p;
518 		pvt->label_name = switch_core_session_strdup(session, plugin_name);
519 		if ((p = strrchr(pvt->label_name, '.'))) {
520 			*p = '\0';
521 		}
522 	}
523 
524 	if (strstr(plugin_name, ".so")) {
525 		pvt->plugin_name = switch_core_session_strdup(session, plugin_name);
526 	} else {
527 		pvt->plugin_name = switch_core_session_sprintf(session, "%s.so", plugin_name);
528 	}
529 
530 	dparams = switch_core_session_strdup(session, params);
531 
532 	argc = switch_split(dparams, ' ', argv);
533 
534 	for (i = 0; i < argc; i++) {
535 		if (switch_is_number(argv[i])) {
536 			if (pvt->num_idx < MAX_INDEX) {
537 				pvt->config[pvt->num_idx] = atof(argv[i]);
538 				pvt->has_config[pvt->num_idx] = 1;
539 				pvt->num_idx++;
540 			}
541 		} else {
542 			if (pvt->str_idx < MAX_INDEX) {
543 				pvt->str_config[pvt->str_idx++] = switch_core_session_strdup(session, argv[i]);
544 			}
545 		}
546 	}
547 
548 	if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
549 		return SWITCH_STATUS_FALSE;
550 	}
551 
552 	pstr = switch_core_session_sprintf(session, "%s|%s|%s|%s", flags, plugin_name, label, params);
553 
554 	if ((status = switch_core_media_bug_add(session, "ladspa", pstr,
555                                             ladspa_callback, pvt, 0, bflags | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
556 		return status;
557 	}
558 
559 	switch_channel_set_private(channel, "ladspa", bug);
560 
561 	return SWITCH_STATUS_SUCCESS;
562 }
563 
564 
ladspa_parse(switch_core_session_t * session,const char * data)565 static void ladspa_parse(switch_core_session_t *session, const char *data)
566 {
567 	char *argv[5] = { 0 };
568 	char *lbuf;
569 
570 	if (data) {
571 		lbuf = strdup(data);
572 		switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])));
573 	   	ladspa_session(session, argv[0], argv[1], argv[2], argv[3]);
574 		free(lbuf);
575 	}
576 }
577 
578 #define APP_SYNTAX "<flags>|<plugin>|<label>|<params>"
SWITCH_STANDARD_APP(ladspa_run_function)579 SWITCH_STANDARD_APP(ladspa_run_function)
580 {
581 	ladspa_parse(session, data);
582 }
583 
584 
585 
586 #define API_SYNTAX "<uuid> [start|stop] <flags>|<plugin>|<label>|<params>"
SWITCH_STANDARD_API(ladspa_api)587 SWITCH_STANDARD_API(ladspa_api)
588 {
589 	char *uuid = NULL;
590 	char *data = NULL;
591 	char *p, *action;
592 	switch_core_session_t *ksession = NULL;
593 
594 	if (!cmd) {
595 		stream->write_function(stream, "-ERR Operation Failed\n");
596 		goto done;
597 	}
598 
599 	data = strdup(cmd);
600 
601 	if ((p = strchr(data, ' '))) {
602 		uuid = data;
603 		*p++ = '\0';
604 
605 		if (!(ksession = switch_core_session_locate(uuid))) {
606 			stream->write_function(stream, "-ERR non-existant UUID\n");
607 			goto done;
608 		}
609 
610 		if ((action = strstr(cmd, "stop"))) {
611 			stop_ladspa_session(ksession);
612 			switch_core_session_rwunlock(ksession);
613 			stream->write_function(stream, "+OK\n");
614 			goto done;
615 		} else if ((action = strstr(cmd, "start"))) {
616 			// Advance past 'start' conditional keyword and move on
617 			p += 5 * sizeof(char);
618 			*p++ = '\0';
619 			switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Tried to remove 'start' and now the string is \"%s\"\n", p);
620 		}
621 
622 		ladspa_parse(ksession, p);
623 		stream->write_function(stream, "+OK\n");
624 	} else {
625 		stream->write_function(stream, "-ERR Usage %s\n", API_SYNTAX);
626 	}
627 
628 done:
629 
630 	switch_safe_free(data);
631 
632 	return SWITCH_STATUS_SUCCESS;
633 }
634 
635 
636 /* Macro expands to: switch_status_t mod_ladspa_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load)637 SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load)
638 {
639 	switch_application_interface_t *app_interface;
640 	switch_api_interface_t *api_interface;
641 	char *path = getenv("LADSPA_PATH");
642 
643 	if (zstr(path)) {
644 		if (switch_directory_exists("/usr/lib64/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
645 			setenv("LADSPA_PATH", "/usr/lib64/ladspa/:/usr/local/lib/ladspa", 1);
646 		} else if (switch_directory_exists("/usr/lib/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
647 			setenv("LADSPA_PATH", "/usr/lib/ladspa/:/usr/local/lib/ladspa", 1);
648 		} else if (switch_directory_exists("/usr/local/lib/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
649 			setenv("LADSPA_PATH", "/usr/local/lib/ladspa", 1);
650 		}
651 	}
652 
653 	/* connect my internal structure to the blank pointer passed to me */
654 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
655 
656 	SWITCH_ADD_APP(app_interface, "ladspa_run", "ladspa_run", NULL, ladspa_run_function, APP_SYNTAX, SAF_NONE);
657 	SWITCH_ADD_API(api_interface, "uuid_ladspa", "ladspa", ladspa_api, API_SYNTAX);
658 
659 	switch_console_set_complete("add uuid_ladspa ::console::list_uuid");
660 
661 
662 	/* indicate that the module should continue to be loaded */
663 	return SWITCH_STATUS_SUCCESS;
664 }
665 
666 /*
667   Called when the system shuts down
668   Macro expands to: switch_status_t mod_ladspa_shutdown() */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown)669 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown)
670 {
671 	/* Cleanup dynamically allocated config settings */
672 
673 	return SWITCH_STATUS_SUCCESS;
674 }
675 
676 /* For Emacs:
677  * Local Variables:
678  * mode:c
679  * indent-tabs-mode:t
680  * tab-width:4
681  * c-basic-offset:4
682  * End:
683  * For VIM:
684  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet
685  */
686