diff --git a/conf/default_context.xml b/conf/default_context.xml index 2efe1bc827..6fb482cc55 100644 --- a/conf/default_context.xml +++ b/conf/default_context.xml @@ -19,6 +19,23 @@ + + + + + + + + + + + diff --git a/src/mod/applications/mod_bridgecall/mod_bridgecall.c b/src/mod/applications/mod_bridgecall/mod_bridgecall.c index 884bbb7ec3..dc455bcc93 100644 --- a/src/mod/applications/mod_bridgecall/mod_bridgecall.c +++ b/src/mod/applications/mod_bridgecall/mod_bridgecall.c @@ -36,98 +36,8 @@ static const char modname[] = "mod_bridgecall"; -static void audio_bridge_function(switch_core_session_t *session, char *data) -{ - switch_channel_t *caller_channel; - switch_core_session_t *peer_session = NULL; - unsigned int timelimit = 60; - char *var; - uint8_t no_media_bridge = 0; - switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; - uint8_t do_continue = 0; - if (switch_strlen_zero(data)) { - return; - } - caller_channel = switch_core_session_get_channel(session); - assert(caller_channel != NULL); - - if ((var = switch_channel_get_variable(caller_channel, "call_timeout"))) { - timelimit = atoi(var); - } - - if ((var = switch_channel_get_variable(caller_channel, "continue_on_fail"))) { - do_continue = switch_true(var); - } - - if (switch_channel_test_flag(caller_channel, CF_BYPASS_MEDIA) - || ((var = switch_channel_get_variable(caller_channel, SWITCH_BYPASS_MEDIA_VARIABLE)) && switch_true(var))) { - if (!switch_channel_test_flag(caller_channel, CF_ANSWERED) - && !switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA)) { - switch_channel_set_flag(caller_channel, CF_BYPASS_MEDIA); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel is already up, delaying point-to-point mode 'till both legs are up.\n"); - no_media_bridge = 1; - } - } - - if (switch_ivr_originate(session, &peer_session, &cause, data, timelimit, NULL, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Originate Failed. Cause: %s\n", switch_channel_cause2str(cause)); - if (!do_continue && cause != SWITCH_CAUSE_NO_ANSWER) { - /* All Causes besides NO_ANSWER terminate the originating session unless continue_on_fail is set. - We will pass the fail cause on when we hangup. */ - switch_channel_hangup(caller_channel, cause); - } - /* Otherwise.. nobody answered. Go back to the dialplan instructions in case there was more to do. */ - return; - } else { - if (no_media_bridge) { - switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session); - switch_frame_t *read_frame; - /* SIP won't let us redir media until the call has been answered #$^#%& so we will proxy any early media until they do */ - while (switch_channel_ready(caller_channel) && switch_channel_ready(peer_channel) - && !switch_channel_test_flag(peer_channel, CF_ANSWERED)) { - switch_status_t status = switch_core_session_read_frame(peer_session, &read_frame, -1, 0); - uint8_t bad = 1; - - if (SWITCH_READ_ACCEPTABLE(status) - && switch_core_session_write_frame(session, read_frame, -1, 0) == SWITCH_STATUS_SUCCESS) { - bad = 0; - } - if (bad) { - switch_channel_hangup(caller_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - switch_channel_hangup(peer_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - goto end; - } - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Redirecting media to point-to-point mode.\n"); - switch_ivr_nomedia(switch_core_session_get_uuid(session), SMF_FORCE); - switch_ivr_nomedia(switch_core_session_get_uuid(peer_session), SMF_FORCE); - switch_ivr_signal_bridge(session, peer_session); - } else { - if (switch_channel_test_flag(caller_channel, CF_BYPASS_MEDIA)) { - switch_ivr_signal_bridge(session, peer_session); - } else { - switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL); - } - } - end: - if (peer_session) { - switch_core_session_rwunlock(peer_session); - } - } -} - -static const switch_application_interface_t bridge_application_interface = { - /*.interface_name */ "bridge", - /*.application_function */ audio_bridge_function, - /* long_desc */ "Bridge the audio between two sessions", - /* short_desc */ "Bridge Audio", - /* syntax */ "", - /* flags */ SAF_SUPPORT_NOMEDIA -}; static const switch_loadable_module_interface_t mod_bridgecall_module_interface = { /*.module_name = */ modname, diff --git a/src/mod/applications/mod_soundtouch/Makefile b/src/mod/applications/mod_soundtouch/Makefile new file mode 100644 index 0000000000..b4b3a6633e --- /dev/null +++ b/src/mod/applications/mod_soundtouch/Makefile @@ -0,0 +1,19 @@ + +VERSION=soundtouch-1.3.1 +DIRECTORY=$(switch_srcdir)/libs/$(VERSION) +LA=$(DIRECTORY)/source/SoundTouch/.libs/libSoundTouch.a + +BASE=../../../.. +LOCAL_CFLAGS += -I$(DIRECTORY)/include -DINTEGER_SAMPLES +LOCAL_LIBADD=$(LA) +DEFAULT_ARGS=--prefix=$(PREFIX) --disable-shared --with-pic + +include /usr/src/freeswitch.trunk/build/modmake.rules + +$(DIRECTORY): + $(GETLIB) $(VERSION).tar.gz + cd $(DIRECTORY) && ./configure $(DEFAULT_ARGS) --enable-integer-samples + +$(LA): $(DIRECTORY) + cd $(DIRECTORY) && $(MAKE) + $(TOUCH_TARGET) diff --git a/src/mod/applications/mod_soundtouch/mod_soundtouch.cpp b/src/mod/applications/mod_soundtouch/mod_soundtouch.cpp new file mode 100644 index 0000000000..d0248f5070 --- /dev/null +++ b/src/mod/applications/mod_soundtouch/mod_soundtouch.cpp @@ -0,0 +1,340 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, 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_soundtouch.c -- Example of writeable media bugs + * + */ + +#include +#include +#include +using namespace soundtouch; +using namespace std; + + +#include +#define STSTART 1024 * 2 +#define STBLOCK 1024 + +static const char modname[] = "mod_soundtouch"; + +struct soundtouch_helper { + SoundTouch *st; + switch_core_session_t *session; + int send; + float pitch; + float octaves; + float semi; + float rate; + float tempo; + int literal; +}; + +static switch_status_t on_dtmf(switch_core_session_t *session, const char *dtmf) +{ + + switch_media_bug_t *bug; + switch_channel_t *channel = switch_core_session_get_channel(session); + + if ((bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_soundtouch_"))) { + struct soundtouch_helper *sth = (struct soundtouch_helper *) switch_core_media_bug_get_user_data(bug); + + if (sth) { + const char *p; + + if (sth->literal) { + sth->literal = 0; + return SWITCH_STATUS_SUCCESS; + } + + for (p = dtmf; p && *p; p++) { + if (sth->literal) { + sth->literal = 0; + return SWITCH_STATUS_SUCCESS; + } + + switch(*p) { + case '*': + sth->literal++; + break; + case '3': + sth->semi += .5; + sth->st->setPitchSemiTones(sth->semi); + sth->st->flush(); + break; + case '2': + sth->semi = 0; + sth->st->setPitchSemiTones(sth->semi); + sth->st->flush(); + break; + case '1': + sth->semi -= .5; + sth->st->setPitchSemiTones(sth->semi); + sth->st->flush(); + break; + + case '6': + sth->pitch += .2; + sth->st->setPitch(sth->pitch); + sth->st->flush(); + break; + case '5': + sth->pitch = 1; + sth->st->setPitch(sth->pitch); + sth->st->flush(); + break; + case '4': + sth->pitch -= .2; + if (sth->pitch <= 0) { + sth->pitch = .2; + } + sth->st->setPitch(sth->pitch); + sth->st->flush(); + break; + + case '9': + sth->octaves += .2; + sth->st->setPitchOctaves(sth->octaves); + sth->st->flush(); + break; + case '8': + sth->octaves = 0; + sth->st->setPitchOctaves(sth->octaves); + sth->st->flush(); + break; + case '7': + sth->octaves -= .2; + sth->st->setPitchOctaves(sth->octaves); + sth->st->flush(); + break; + + + case '0': + sth->octaves = 0; + sth->st->setPitchOctaves(sth->octaves); + sth->pitch = 1; + sth->st->setPitch(sth->pitch); + sth->semi = 0; + sth->st->setPitchSemiTones(sth->semi); + sth->st->flush(); + + } + + } + } + + return SWITCH_STATUS_FALSE; + } + return SWITCH_STATUS_SUCCESS; +} + + +static switch_bool_t soundtouch_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) +{ + struct soundtouch_helper *sth = (struct soundtouch_helper *) user_data; + + switch (type) { + case SWITCH_ABC_TYPE_INIT: + { + switch_codec_t *read_codec = switch_core_session_get_read_codec(sth->session); + sth->st = new SoundTouch(); + sth->st->setSampleRate(read_codec->implementation->samples_per_second); + sth->st->setChannels(read_codec->implementation->number_of_channels); + + sth->st->setSetting(SETTING_USE_QUICKSEEK, 1); + sth->st->setSetting(SETTING_USE_AA_FILTER, 1); + + if (sth->semi) { + sth->st->setPitchSemiTones(sth->semi); + } + + if (sth->pitch) { + sth->st->setPitch(sth->pitch); + } + + if (sth->octaves) { + sth->st->setPitchOctaves(sth->octaves); + } + + if (sth->rate) { + sth->st->setRate(sth->rate); + } + + if (sth->tempo) { + sth->st->setRate(sth->tempo); + } + + if (sth->send) { + switch_core_event_hook_add_send_dtmf(sth->session, on_dtmf); + } else { + switch_core_event_hook_add_recv_dtmf(sth->session, on_dtmf); + } + } + break; + case SWITCH_ABC_TYPE_CLOSE: + { + delete sth->st; + if (sth->send) { + switch_core_event_hook_remove_send_dtmf(sth->session, on_dtmf); + } else { + switch_core_event_hook_remove_recv_dtmf(sth->session, on_dtmf); + } + } + break; + case SWITCH_ABC_TYPE_READ: + case SWITCH_ABC_TYPE_WRITE: + break; + case SWITCH_ABC_TYPE_WRITE_REPLACE: + { + switch_frame_t *frame; + + assert(sth != NULL); + assert(sth->st != NULL); + + frame = switch_core_media_bug_get_replace_frame(bug); + sth->st->putSamples((SAMPLETYPE *)frame->data, frame->samples); + + if (sth->st->numSamples() >= frame->samples * 2) { + frame->samples = sth->st->receiveSamples((SAMPLETYPE *)frame->data, frame->samples); + frame->datalen = frame->samples * 2; + } else { + memset(frame->data, 0, frame->datalen); + } + + switch_core_media_bug_set_replace_frame(bug, frame); + + + } + default: + break; + } + + return SWITCH_TRUE; +} + +static void soundtouch_start_function(switch_core_session_t *session, char *data) +{ + switch_media_bug_t *bug; + switch_status_t status; + switch_channel_t *channel = switch_core_session_get_channel(session); + struct soundtouch_helper *sth; + char *argv[6]; + int argc; + char *lbuf = NULL; + int x; + + if (switch_channel_get_private(channel, "_soundtouch_")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n"); + return; + } + + sth = (struct soundtouch_helper *) switch_core_session_alloc(session, sizeof(*sth)); + assert(sth != NULL); + + + if (data && (lbuf = switch_core_session_strdup(session, data)) + && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { + if (!strcasecmp(argv[0], "send") && argc >= 1) { + sth->send = 1; + } else { + sth->send = 0; + } + + for(x = 1; x < argc; x++) { + if (strchr(argv[x], 'p')) { + if ((sth->pitch = atof(argv[x]) < 0)) { + sth->pitch = 0; + } + } else if (strchr(argv[x], 'r')) { + sth->rate = atof(argv[x]); + } else if (strchr(argv[x], 'o')) { + sth->octaves = atof(argv[x]); + } else if (strchr(argv[x], 's')) { + sth->semi = atof(argv[x]); + } else if (strchr(argv[x], 't')) { + if ((sth->tempo = atof(argv[x]) < 0)) { + sth->tempo = 0; + } + } + } + } + + + sth->session = session; + + if ((status = switch_core_media_bug_add(session, soundtouch_callback, sth, 0, SMBF_WRITE_REPLACE, &bug)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failure!\n"); + return; + } + + switch_channel_set_private(channel, "_soundtouch_", bug); + +} +static const switch_application_interface_t soundtouch_application_interface = { + /*.interface_name */ "soundtouch", + /*.application_function */ soundtouch_start_function, + /* long_desc */ "Alter the audio stream", + /* short_desc */ "Alter the audio stream", + /* syntax */ "[send|recv] [-]s [.]p", + /* flags */ SAF_NONE, + /* next*/ + +}; + +static switch_loadable_module_interface_t soundtouch_module_interface = { + /*.module_name */ modname, + /*.endpoint_interface */ NULL, + /*.timer_interface */ NULL, + /*.dialplan_interface */ NULL, + /*.codec_interface */ NULL, + /*.application_interface */ &soundtouch_application_interface, + /*.api_interface */ NULL, + /*.file_interface */ NULL, + /*.speech_interface */ NULL, + /*.directory_interface */ NULL +}; + + +SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) +{ + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = &soundtouch_module_interface; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:nil + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */