diff --git a/conf/dialplan/default/ladspa.xml b/conf/dialplan/default/ladspa.xml
new file mode 100644
index 0000000000..926c31a87a
--- /dev/null
+++ b/conf/dialplan/default/ladspa.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/applications/mod_ladspa/Makefile b/src/mod/applications/mod_ladspa/Makefile
new file mode 100644
index 0000000000..1a77c52a0d
--- /dev/null
+++ b/src/mod/applications/mod_ladspa/Makefile
@@ -0,0 +1,5 @@
+BASE=../../../..
+
+LOCAL_OBJS += load.o
+include $(BASE)/build/modmake.rules
+
diff --git a/src/mod/applications/mod_ladspa/load.c b/src/mod/applications/mod_ladspa/load.c
new file mode 100644
index 0000000000..652ecfa0f2
--- /dev/null
+++ b/src/mod/applications/mod_ladspa/load.c
@@ -0,0 +1,173 @@
+/* load.c
+
+ Free software by Richard W.E. Furse. Do with as you will. No
+ warranty. */
+
+/*****************************************************************************/
+
+#include
+#include
+#include
+#include
+
+/*****************************************************************************/
+
+#include "ladspa.h"
+#include "utils.h"
+#include "inttypes.h"
+#include "switch.h"
+/*****************************************************************************/
+
+/* This function provides a wrapping of dlopen(). When the filename is
+ not an absolute path (i.e. does not begin with / character), this
+ routine will search the LADSPA_PATH for the file. */
+static void *dlopenLADSPA(const char *pcFilename, int iFlag)
+{
+
+ char *pcBuffer;
+ const char *pcEnd;
+ const char *pcLADSPAPath;
+ const char *pcStart;
+ int iEndsInSO;
+ int iNeedSlash;
+ size_t iFilenameLength;
+ void *pvResult;
+
+ iFilenameLength = strlen(pcFilename);
+ pvResult = NULL;
+
+ if (pcFilename[0] == '/') {
+
+ /* The filename is absolute. Assume the user knows what he/she is
+ doing and simply dlopen() it. */
+
+ pvResult = dlopen(pcFilename, iFlag);
+ if (pvResult != NULL)
+ return pvResult;
+
+ } else {
+
+ /* If the filename is not absolute then we wish to check along the
+ LADSPA_PATH path to see if we can find the file there. We do
+ NOT call dlopen() directly as this would find plugins on the
+ LD_LIBRARY_PATH, whereas the LADSPA_PATH is the correct place
+ to search. */
+
+ pcLADSPAPath = getenv("LADSPA_PATH");
+
+ if (pcLADSPAPath) {
+
+ pcStart = pcLADSPAPath;
+ while (*pcStart != '\0') {
+ pcEnd = pcStart;
+ while (*pcEnd != ':' && *pcEnd != '\0')
+ pcEnd++;
+
+ pcBuffer = malloc(iFilenameLength + 2 + (pcEnd - pcStart));
+ if (pcEnd > pcStart)
+ strncpy(pcBuffer, pcStart, pcEnd - pcStart);
+ iNeedSlash = 0;
+ if (pcEnd > pcStart)
+ if (*(pcEnd - 1) != '/') {
+ iNeedSlash = 1;
+ pcBuffer[pcEnd - pcStart] = '/';
+ }
+ strcpy(pcBuffer + iNeedSlash + (pcEnd - pcStart), pcFilename);
+
+ pvResult = dlopen(pcBuffer, iFlag);
+
+ free(pcBuffer);
+ if (pvResult != NULL)
+ return pvResult;
+
+ pcStart = pcEnd;
+ if (*pcStart == ':')
+ pcStart++;
+ }
+ }
+ }
+
+ /* As a last ditch effort, check if filename does not end with
+ ".so". In this case, add this suffix and recurse. */
+ iEndsInSO = 0;
+ if (iFilenameLength > 3)
+ iEndsInSO = (strcmp(pcFilename + iFilenameLength - 3, ".so") == 0);
+ if (!iEndsInSO) {
+ pcBuffer = malloc(iFilenameLength + 4);
+ strcpy(pcBuffer, pcFilename);
+ strcat(pcBuffer, ".so");
+ pvResult = dlopenLADSPA(pcBuffer, iFlag);
+ free(pcBuffer);
+ }
+
+ if (pvResult != NULL)
+ return pvResult;
+
+ /* If nothing has worked, then at least we can make sure we set the
+ correct error message - and this should correspond to a call to
+ dlopen() with the actual filename requested. The dlopen() manual
+ page does not specify whether the first or last error message
+ will be kept when multiple calls are made to dlopen(). We've
+ covered the former case - now we can handle the latter by calling
+ dlopen() again here. */
+ return dlopen(pcFilename, iFlag);
+}
+
+/*****************************************************************************/
+
+void *loadLADSPAPluginLibrary(const char *pcPluginFilename)
+{
+
+ void *pvPluginHandle;
+
+ pvPluginHandle = dlopenLADSPA(pcPluginFilename, RTLD_NOW);
+ if (!pvPluginHandle) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load plugin \"%s\": %s\n", pcPluginFilename, dlerror());
+ }
+
+ return pvPluginHandle;
+}
+
+/*****************************************************************************/
+
+void unloadLADSPAPluginLibrary(void *pvLADSPAPluginLibrary)
+{
+ dlclose(pvLADSPAPluginLibrary);
+}
+
+/*****************************************************************************/
+
+const LADSPA_Descriptor *findLADSPAPluginDescriptor(void *pvLADSPAPluginLibrary, const char *pcPluginLibraryFilename, const char *pcPluginLabel)
+{
+
+ const LADSPA_Descriptor *psDescriptor;
+ LADSPA_Descriptor_Function pfDescriptorFunction;
+ unsigned long lPluginIndex;
+
+ dlerror();
+ pfDescriptorFunction = (LADSPA_Descriptor_Function) (intptr_t)dlsym(pvLADSPAPluginLibrary, "ladspa_descriptor");
+ if (!pfDescriptorFunction) {
+ const char *pcError = dlerror();
+ if (pcError) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Unable to find ladspa_descriptor() function in plugin "
+ "library file \"%s\": %s.\n" "Are you sure this is a LADSPA plugin file?\n", pcPluginLibraryFilename, pcError);
+ return NULL;
+ }
+ }
+
+ for (lPluginIndex = 0;; lPluginIndex++) {
+ psDescriptor = pfDescriptorFunction(lPluginIndex);
+ if (psDescriptor == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Unable to find label \"%s\" in plugin library file \"%s\".\n", pcPluginLabel, pcPluginLibraryFilename);
+ return NULL;
+ }
+ if (strcmp(psDescriptor->Label, pcPluginLabel) == 0)
+ return psDescriptor;
+ }
+}
+
+/*****************************************************************************/
+
+/* EOF */
diff --git a/src/mod/applications/mod_ladspa/mod_ladspa.c b/src/mod/applications/mod_ladspa/mod_ladspa.c
new file mode 100644
index 0000000000..871d203646
--- /dev/null
+++ b/src/mod/applications/mod_ladspa/mod_ladspa.c
@@ -0,0 +1,579 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2011, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II
+ *
+ * mod_ladspa.c -- LADSPA
+ *
+ */
+#include
+#include "ladspa.h"
+#include "utils.h"
+
+/* Prototypes */
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown);
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_ladspa_runtime);
+SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load);
+
+/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
+ * Defines a switch_loadable_module_function_table_t and a static const char[] modname
+ */
+SWITCH_MODULE_DEFINITION(mod_ladspa, mod_ladspa_load, mod_ladspa_shutdown, NULL);
+
+#define MAX_INDEX 256
+
+typedef struct {
+ switch_core_session_t *session;
+ char *plugin_name;
+ char *label_name;
+ void *library_handle;
+ const LADSPA_Descriptor *ldesc;
+ LADSPA_Handle handle;
+ LADSPA_Data config[MAX_INDEX];
+ uint8_t has_config[MAX_INDEX];
+ int skip;
+ LADSPA_Data in_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+ LADSPA_Data out_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+ LADSPA_Data out_ports[MAX_INDEX];
+} switch_ladspa_t;
+
+
+
+int check_range(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data val)
+{
+ if (ldesc->PortRangeHints[i].LowerBound && ldesc->PortRangeHints[i].UpperBound &&
+ (val < ldesc->PortRangeHints[i].LowerBound || val > ldesc->PortRangeHints[i].UpperBound)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Param %f out of bounds %f-%f\n",
+ val, ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
+ return 0;
+ }
+
+ return 1;
+}
+
+int find_default(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data *ptr)
+
+{
+ LADSPA_Data dftval = 0;
+ int fail = 0;
+
+ LADSPA_PortRangeHintDescriptor port_hint = ldesc->PortRangeHints[i].HintDescriptor;
+
+ switch (port_hint & LADSPA_HINT_DEFAULT_MASK) {
+ case LADSPA_HINT_DEFAULT_NONE:
+ break;
+ case LADSPA_HINT_DEFAULT_MINIMUM:
+ dftval = ldesc->PortRangeHints[i].LowerBound;
+ break;
+ case LADSPA_HINT_DEFAULT_LOW:
+ if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
+ dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
+ * 0.75 + log(ldesc->PortRangeHints[i].UpperBound)
+ * 0.25);
+ } else {
+ dftval = (ldesc->PortRangeHints[i].LowerBound * 0.75 + ldesc->PortRangeHints[i].UpperBound * 0.25);
+ }
+ break;
+ case LADSPA_HINT_DEFAULT_MIDDLE:
+ if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
+ dftval = sqrt(ldesc->PortRangeHints[i].LowerBound * ldesc->PortRangeHints[i].UpperBound);
+ } else {
+ dftval = 0.5 * (ldesc->PortRangeHints[i].LowerBound + ldesc->PortRangeHints[i].UpperBound);
+ }
+ break;
+ case LADSPA_HINT_DEFAULT_HIGH:
+ if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
+ dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
+ * 0.25 + log(ldesc->PortRangeHints[i].UpperBound)
+ * 0.75);
+ } else {
+ dftval = (ldesc->PortRangeHints[i].LowerBound * 0.25 + ldesc->PortRangeHints[i].UpperBound * 0.75);
+ }
+ break;
+ case LADSPA_HINT_DEFAULT_MAXIMUM:
+ dftval = ldesc->PortRangeHints[i].UpperBound;
+ break;
+ case LADSPA_HINT_DEFAULT_0:
+ dftval = 0;
+ break;
+ case LADSPA_HINT_DEFAULT_1:
+ dftval = 1;
+ break;
+ case LADSPA_HINT_DEFAULT_100:
+ dftval = 100;
+ break;
+ case LADSPA_HINT_DEFAULT_440:
+ dftval = 440;
+ break;
+ default:
+ fail = 1;
+ break;
+ }
+
+ if (!fail) {
+ *ptr = dftval;
+ }
+
+ return !fail;
+}
+
+static void dump_info(const LADSPA_Descriptor *ldesc)
+{
+ int i = 0;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Name: \"%s\"\n", ldesc->Name);
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Label: \"%s\"\n", ldesc->Label);
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Unique ID: %lu\n", ldesc->UniqueID);
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Maker: \"%s\"\n", ldesc->Maker);
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Copyright: \"%s\"\n", ldesc->Copyright);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Must Run Real-Time: ");
+ if (LADSPA_IS_REALTIME(ldesc->Properties))
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
+
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has activate() Function: ");
+ if (ldesc->activate != NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has deactivate() Function: ");
+ if (ldesc->deactivate != NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has run_adding() Function: ");
+ if (ldesc->run_adding != NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
+
+ if (ldesc->instantiate == NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO INSTANTIATE FUNCTION.\n");
+ if (ldesc->connect_port == NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CONNECT_PORT FUNCTION.\n");
+ if (ldesc->run == NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO RUN FUNCTION.\n");
+ if (ldesc->run_adding != NULL && ldesc->set_run_adding_gain == NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS RUN_ADDING FUNCTION BUT " "NOT SET_RUN_ADDING_GAIN.\n");
+ if (ldesc->run_adding == NULL && ldesc->set_run_adding_gain != NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS SET_RUN_ADDING_GAIN FUNCTION BUT " "NOT RUN_ADDING.\n");
+ if (ldesc->cleanup == NULL)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CLEANUP FUNCTION.\n");
+
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Environment: ");
+ if (LADSPA_IS_HARD_RT_CAPABLE(ldesc->Properties))
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal or Hard Real-Time\n");
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal\n");
+
+ if (LADSPA_IS_INPLACE_BROKEN(ldesc->Properties))
+ 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");
+
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Ports:");
+
+ if (ldesc->PortCount == 0)
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\tERROR: PLUGIN HAS NO PORTS.\n");
+
+ for (i = 0; i < ldesc->PortCount; i++) {
+ LADSPA_Data dft = 0.0f;
+ int found = 0;
+
+ if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
+ found = find_default(ldesc, i, &dft);
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n \"%s\" ", ldesc->PortNames[i]);
+
+ if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i])
+ && LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: INPUT AND OUTPUT");
+ else if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i]))
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "input");
+ else if (LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "output");
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: NEITHER INPUT NOR OUTPUT");
+
+ if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])
+ && LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: CONTROL AND AUDIO");
+ else if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i]))
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", control");
+ else if (LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", audio");
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: NEITHER CONTROL NOR AUDIO");
+
+ if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
+ if (found) {
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: %f\n",
+ ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound, dft);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: none.\n",
+ ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
+ }
+ }
+
+
+
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n\n");
+}
+
+
+
+
+
+static switch_bool_t ladspa_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
+{
+ switch_ladspa_t *pvt = (switch_ladspa_t *) user_data;
+ //switch_frame_t *frame = NULL;
+ switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
+
+ switch (type) {
+ case SWITCH_ABC_TYPE_INIT:
+ {
+ switch_codec_implementation_t read_impl = { 0 };
+ LADSPA_PortDescriptor port_desc;
+ int i = 0, j = 0, k = 0;
+
+ switch_core_session_get_read_impl(pvt->session, &read_impl);
+
+ if (!(pvt->library_handle = loadLADSPAPluginLibrary(pvt->plugin_name))) {
+ return SWITCH_FALSE;
+ }
+
+ if (!(pvt->ldesc = findLADSPAPluginDescriptor(pvt->library_handle, pvt->plugin_name, pvt->label_name))) {
+ return SWITCH_FALSE;
+ }
+
+
+ pvt->handle = pvt->ldesc->instantiate(pvt->ldesc, read_impl.actual_samples_per_second);
+
+ dump_info(pvt->ldesc);
+
+
+ for (i = 0; i < pvt->ldesc->PortCount; i++) {
+ port_desc = pvt->ldesc->PortDescriptors[i];
+
+ if (LADSPA_IS_PORT_CONTROL(port_desc) && LADSPA_IS_PORT_INPUT(port_desc)) {
+ LADSPA_Data dft = 0.0f;
+ int found = find_default(pvt->ldesc, i, &dft);
+
+ if (found && !pvt->has_config[j]) {
+ pvt->config[j] = dft;
+ pvt->has_config[j] = 1;
+ }
+
+ if (pvt->has_config[j]) {
+ if (!check_range(pvt->ldesc, i, pvt->config[j])) {
+ pvt->config[j] = dft;
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_WARNING, "FALLING TO DEFAULT PARAM %d [%s] (%f)\n",
+ j+1,
+ pvt->ldesc->PortNames[i],
+ pvt->config[j]);
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "ADDING PARAM %d [%s] (%f)\n",
+ j+1,
+ pvt->ldesc->PortNames[i],
+ pvt->config[j]);
+ pvt->ldesc->connect_port(pvt->handle, i, &pvt->config[j++]);
+ usleep(10000);
+ }
+ }
+
+ if (LADSPA_IS_PORT_INPUT(port_desc) && LADSPA_IS_PORT_AUDIO(port_desc)) {
+ pvt->ldesc->connect_port(pvt->handle, i, pvt->in_buf);
+ }
+
+ if (LADSPA_IS_PORT_OUTPUT(port_desc)) {
+ if (LADSPA_IS_PORT_AUDIO(port_desc)) {
+ pvt->ldesc->connect_port(pvt->handle, i, pvt->out_buf);
+ } else if (k < MAX_INDEX) {
+ pvt->ldesc->connect_port(pvt->handle, i, &pvt->out_ports[k++]);
+ }
+ }
+ }
+ }
+
+ break;
+
+ case SWITCH_ABC_TYPE_CLOSE:
+ {
+
+ if (pvt->handle && pvt->ldesc) {
+ pvt->ldesc->cleanup(pvt->handle);
+ }
+
+ if (pvt->library_handle) {
+ unloadLADSPAPluginLibrary(pvt->library_handle);
+ }
+ }
+ break;
+
+ case SWITCH_ABC_TYPE_WRITE_REPLACE:
+ case SWITCH_ABC_TYPE_READ_REPLACE:
+ {
+ switch_frame_t *rframe;
+ int16_t *slin;
+
+ if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
+ rframe = switch_core_media_bug_get_read_replace_frame(bug);
+ } else {
+ rframe = switch_core_media_bug_get_write_replace_frame(bug);
+ }
+
+ slin = rframe->data;
+
+ if (switch_channel_media_ready(channel)) {
+ switch_short_to_float(slin, pvt->in_buf, rframe->samples);
+ pvt->ldesc->run(pvt->handle, rframe->samples);
+ switch_float_to_short(pvt->out_buf, slin, rframe->samples);
+ }
+
+ if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
+ switch_core_media_bug_set_read_replace_frame(bug, rframe);
+ } else {
+ switch_core_media_bug_set_write_replace_frame(bug, rframe);
+ }
+
+ if (pvt->skip && !--pvt->skip) {
+ return SWITCH_FALSE;
+ }
+
+ }
+ break;
+ case SWITCH_ABC_TYPE_WRITE:
+ default:
+ break;
+ }
+
+ return SWITCH_TRUE;
+}
+
+switch_status_t stop_ladspa_session(switch_core_session_t *session)
+{
+ switch_media_bug_t *bug;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ if ((bug = switch_channel_get_private(channel, "ladspa"))) {
+ switch_channel_set_private(channel, "ladspa", NULL);
+ switch_core_media_bug_remove(session, &bug);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ return SWITCH_STATUS_FALSE;
+}
+
+switch_status_t ladspa_session(switch_core_session_t *session, const char *flags, const char *plugin_name, const char *label, const char *params)
+{
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ switch_media_bug_t *bug;
+ switch_status_t status;
+ switch_ladspa_t *pvt = { 0 };
+ switch_codec_implementation_t read_impl = { 0 };
+ int i, bflags = SMBF_READ_REPLACE | SMBF_ANSWER_REQ;
+ char *pstr;
+ int argc;
+ char *argv[50];
+ char *dparams = NULL;
+
+ if (zstr(plugin_name)) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s INVALID PLUGIN\n", switch_channel_get_name(channel));
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (zstr(flags)) {
+ flags = "r";
+ }
+
+ if (strchr(flags, 'w')) {
+ bflags = SMBF_WRITE_REPLACE;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "FLAGS: %s PLUGIN: %s LABEL: %s PARAMS: %s\n",
+ flags, plugin_name, label, params);
+
+ switch_core_session_get_read_impl(session, &read_impl);
+
+ pvt = switch_core_session_alloc(session, sizeof(*pvt));
+
+ pvt->session = session;
+ if (!zstr(label)) {
+ pvt->label_name = switch_core_session_strdup(session, label);
+ } else {
+ char *p;
+ pvt->label_name = switch_core_session_strdup(session, plugin_name);
+ if ((p = strrchr(pvt->label_name, '.'))) {
+ *p = '\0';
+ }
+ }
+
+ if (strstr(plugin_name, ".so")) {
+ pvt->plugin_name = switch_core_session_strdup(session, plugin_name);
+ } else {
+ pvt->plugin_name = switch_core_session_sprintf(session, "%s.so", plugin_name);
+ }
+
+ dparams = switch_core_session_strdup(session, params);
+
+ argc = switch_split(dparams, ' ', argv);
+
+ for (i = 0; i < argc; i++) {
+ pvt->config[i] = atof(argv[i]);
+ pvt->has_config[i] = 1;
+ }
+
+ if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ pstr = switch_core_session_sprintf(session, "%s|%s|%s|%s", flags, plugin_name, label, params);
+
+ if ((status = switch_core_media_bug_add(session, "ladspa", pstr,
+ ladspa_callback, pvt, 0, bflags | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
+ return status;
+ }
+
+ switch_channel_set_private(channel, "ladspa", bug);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+static void ladspa_parse(switch_core_session_t *session, const char *data)
+{
+ char *argv[5] = { 0 };
+ int argc;
+ char *lbuf;
+
+ if (data) {
+ lbuf = strdup(data);
+ argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])));
+ ladspa_session(session, argv[0], argv[1], argv[2], argv[3]);
+ free(lbuf);
+ }
+}
+
+#define APP_SYNTAX "||