unsigned int buflen,
unsigned int maxdigits,
const char *terminators,
- char *terminator);
+ char *terminator,
+ unsigned int timeout,
+ unsigned int poll_channel);
/*!
\brief play a file from the disk to the session
unsigned int buflen);
+/*!
+ \brief Speak given text with given tts engine
+ \param session the session to speak on
+ \param voice_name the desired voice
+ \param timer_name optional timer to use for async behaviour
+ \param rate the sample rate
+ \param dtmf_callback code to execute if any dtmf is dialed during the audio
+ \param text the text to speak
+ \param buf an option data pointer to pass to the callback or a string to put encountered digits in
+ \param buflen the len of buf
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session,
char *tts_name,
char *voice_name,
void *buf,
unsigned int buflen);
+/*!
+ \brief Bridge Audio from one session to another
+ \param session one session
+ \param peer_session the other session
+ \param timelimit maximum number of seconds to wait for both channels to be answered
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_session *session,
+ switch_core_session *peer_session,
+ unsigned int timelimit);
+
/** @} */
#ifdef __cplusplus
static const char modname[] = "mod_bridgecall";
-struct audio_bridge_data {
- switch_core_session *session_a;
- switch_core_session *session_b;
- int running;
-};
-
-static void *audio_bridge_thread(switch_thread *thread, void *obj)
-{
- struct switch_core_thread_session *data = obj;
- int *stream_id_p;
- int stream_id = 0, ans_a = 0, ans_b = 0;
-
- switch_channel *chan_a, *chan_b;
- switch_frame *read_frame;
- switch_core_session *session_a, *session_b;
-
- session_a = data->objs[0];
- session_b = data->objs[1];
-
- stream_id_p = data->objs[2];
- if (stream_id_p) {
- stream_id = *stream_id_p;
- }
-
- chan_a = switch_core_session_get_channel(session_a);
- chan_b = switch_core_session_get_channel(session_b);
-
-
- ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
- ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
-
-
- while (data->running > 0) {
- switch_channel_state b_state = switch_channel_get_state(chan_b);
-
- switch (b_state) {
- case CS_HANGUP:
- data->running = -1;
- continue;
- break;
- default:
- break;
- }
-
- /* If this call is running on early media and it answers for real, pass it along... */
- if (!ans_b && switch_channel_test_flag(chan_a, CF_ANSWERED)) {
- if (!switch_channel_test_flag(chan_b, CF_ANSWERED)) {
- switch_channel_answer(chan_b);
- }
- ans_b++;
- }
-
- if (!ans_a && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
- if (!switch_channel_test_flag(chan_a, CF_ANSWERED)) {
- switch_channel_answer(chan_a);
- }
- ans_a++;
- }
-
- /* if 1 channel has DTMF pass it to the other */
- if (switch_channel_has_dtmf(chan_a)) {
- char dtmf[128];
- switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
- switch_core_session_send_dtmf(session_b, dtmf);
- }
-
- /* read audio from 1 channel and write it to the other */
- if (switch_core_session_read_frame(session_a, &read_frame, -1, stream_id) == SWITCH_STATUS_SUCCESS
- && read_frame->datalen) {
- if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
- switch_console_printf(SWITCH_CHANNEL_CONSOLE, "write: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_b));
- data->running = -1;
- }
- } else {
- switch_console_printf(SWITCH_CHANNEL_CONSOLE, "read: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_a));
- data->running = -1;
- }
-
- }
- switch_channel_hangup(chan_b);
- data->running = 0;
-
- return NULL;
-}
-
-
-static switch_status audio_bridge_on_hangup(switch_core_session *session)
-{
- switch_core_session *other_session;
- switch_channel *channel = NULL, *other_channel = NULL;
-
- channel = switch_core_session_get_channel(session);
- assert(channel != NULL);
-
- other_session = switch_channel_get_private(channel);
- assert(other_session != NULL);
-
- other_channel = switch_core_session_get_channel(other_session);
- assert(other_channel != NULL);
-
- switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM HANGUP %s kill %s\n", switch_channel_get_name(channel),
- switch_channel_get_name(other_channel));
-
- switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL);
- switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status audio_bridge_on_ring(switch_core_session *session)
-{
- switch_channel *channel = NULL;
-
- channel = switch_core_session_get_channel(session);
- assert(channel != NULL);
-
- switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM RING\n");
-
- /* put the channel in a passive state so we can loop audio to it */
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
- switch_channel_set_state(channel, CS_TRANSMIT);
- return SWITCH_STATUS_FALSE;
- }
-
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static const switch_state_handler_table audio_bridge_peer_state_handlers = {
- /*.on_init */ NULL,
- /*.on_ring */ audio_bridge_on_ring,
- /*.on_execute */ NULL,
- /*.on_hangup */ audio_bridge_on_hangup,
- /*.on_loopback */ NULL,
- /*.on_transmit */ NULL
-};
-
-static const switch_state_handler_table audio_bridge_caller_state_handlers = {
- /*.on_init */ NULL,
- /*.on_ring */ NULL,
- /*.on_execute */ NULL,
- /*.on_hangup */ audio_bridge_on_hangup,
- /*.on_loopback */ NULL,
- /*.on_transmit */ NULL
-};
-
static void audio_bridge_function(switch_core_session *session, char *data)
{
- switch_channel *caller_channel, *peer_channel;
+ switch_channel *caller_channel;
switch_core_session *peer_session;
switch_caller_profile *caller_profile, *caller_caller_profile;
char chan_type[128] = { '\0' }, *chan_data;
- int timelimit = 60; /* probably a useful option to pass in when there's time */
+ unsigned int timelimit = 60; /* probably a useful option to pass in when there's time */
caller_channel = switch_core_session_get_channel(session);
assert(caller_channel != NULL);
if (switch_core_session_outgoing_channel(session, chan_type, caller_profile, &peer_session) !=
SWITCH_STATUS_SUCCESS) {
- switch_console_printf(SWITCH_CHANNEL_CONSOLE, "DOH!\n");
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Create Outgoing Channel!\n");
switch_channel_hangup(caller_channel);
return;
} else {
- struct switch_core_thread_session this_audio_thread, other_audio_thread;
- time_t start;
- int stream_id = 0;
-
- peer_channel = switch_core_session_get_channel(peer_session);
- memset(&other_audio_thread, 0, sizeof(other_audio_thread));
- memset(&this_audio_thread, 0, sizeof(this_audio_thread));
- other_audio_thread.objs[0] = session;
- other_audio_thread.objs[1] = peer_session;
- other_audio_thread.objs[2] = &stream_id;
- other_audio_thread.running = 5;
-
- this_audio_thread.objs[0] = peer_session;
- this_audio_thread.objs[1] = session;
- this_audio_thread.objs[2] = &stream_id;
- this_audio_thread.running = 2;
-
-
- switch_channel_set_private(caller_channel, peer_session);
- switch_channel_set_private(peer_channel, session);
- switch_channel_add_state_handler(caller_channel, &audio_bridge_caller_state_handlers);
- switch_channel_add_state_handler(peer_channel, &audio_bridge_peer_state_handlers);
- switch_core_session_thread_launch(peer_session);
-
- for (;;) {
- int state = switch_channel_get_state(peer_channel);
- if (state > CS_RING) {
- break;
- }
- switch_yield(1000);
- }
-
- time(&start);
- while (switch_channel_get_state(caller_channel) == CS_EXECUTE &&
- switch_channel_get_state(peer_channel) == CS_TRANSMIT &&
- !switch_channel_test_flag(peer_channel, CF_ANSWERED) &&
- !switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) &&
- ((time(NULL) - start) < timelimit)) {
- switch_yield(20000);
- }
-
- if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
- switch_channel_answer(caller_channel);
- }
-
- if (switch_channel_test_flag(peer_channel, CF_ANSWERED) ||
- switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
-
- switch_core_session_launch_thread(session, audio_bridge_thread, (void *) &other_audio_thread);
- audio_bridge_thread(NULL, (void *) &this_audio_thread);
-
- switch_channel_hangup(peer_channel);
- if (other_audio_thread.running > 0) {
- other_audio_thread.running = -1;
- /* wait for the other audio thread */
- while (other_audio_thread.running) {
- switch_yield(1000);
- }
- }
-
-
- }
+ switch_ivr_multi_threaded_bridge(session, peer_session, timelimit);
}
-
- switch_channel_hangup(caller_channel);
- switch_channel_hangup(peer_channel);
}
}
}
- if (switch_ivr_collect_digits_count(session, buf, sizeof(buf), 10, "#*", &term) != SWITCH_STATUS_SUCCESS) {
+ if (switch_ivr_collect_digits_count(session, buf, sizeof(buf), 10, "#*", &term, 10000, 1) != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(channel);
break;
}
int refresh;
struct iax_event *iaxevent = NULL;
switch_event *s_event;
- load_config();
+ if (load_config() != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_TERM;
+ }
if (globals.debug) {
iax_enable_debug();
depends:
MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) mozilla --prefix=$(PREFIX)
+ MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install curl-7.15.2.tar.gz --prefix=$(PREFIX)
$(MODNAME).so: $(MODNAME).c
$(CC) $(CFLAGS) -fPIC -c $(MODNAME).c -o $(MODNAME).o
* mod_spidermonkey.c -- Javascript Module
*
*/
+#define HAVE_CURL
+
#include "jstypes.h"
#include "jsarena.h"
#include "jsutil.h"
#include "jsscript.h"
#include <libteletone.h>
#include <switch.h>
+#ifdef HAVE_CURL
+#include <curl/curl.h>
+#endif
#ifdef _MSC_VER
#pragma warning(disable: 4311)
} globals;
-//extern JSClass global_class;
static JSClass global_class = {
"Global", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
char *tts_name = NULL;
char *voice_name = NULL;
char *text = NULL;
+ char *dtmf_callback = NULL;
switch_codec *codec;
- char buf[10] = "";
void *bp = NULL;
int len = 0;
- //switch_dtmf_callback_function dtmf_func = NULL;
+ struct dtmf_callback_state cb_state = {0};
+ switch_dtmf_callback_function dtmf_func = NULL;
channel = switch_core_session_get_channel(jss->session);
assert(channel != NULL);
text = JS_GetStringBytes(JS_ValueToString(cx, argv[2]));
}
if (argc > 3) {
- bp = buf;
- len = sizeof(buf);
+ dtmf_callback = JS_GetStringBytes(JS_ValueToString(cx, argv[3]));
+ if (switch_strlen_zero(dtmf_callback)) {
+ dtmf_callback = NULL;
+ } else {
+ memset(&cb_state, 0, sizeof(cb_state));
+ switch_copy_string(cb_state.code_buffer, dtmf_callback, sizeof(cb_state.code_buffer));
+ cb_state.code_buffer_len = strlen(cb_state.code_buffer);
+ cb_state.session_state = jss;
+ dtmf_func = js_dtmf_callback;
+ bp = &cb_state;
+ len = sizeof(cb_state);
+ }
}
if (!tts_name && text) {
voice_name && strlen(voice_name) ? voice_name : NULL,
NULL,
codec->implementation->samples_per_second,
- NULL,
+ dtmf_func,
text,
bp,
len);
- if(len) {
- *rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
- }
- return JS_TRUE;
-
+
+ *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, cb_state.ret_buffer));
+
+ return (switch_channel_get_state(channel) == CS_EXECUTE) ? JS_TRUE : JS_FALSE;
}
static JSBool session_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
char *terminators = NULL;
char *buf;
int digits;
-
+ int32 timeout = 5000;
+ int32 poll_chan = 1;
+
+
if (argc > 0) {
char term;
digits = atoi(JS_GetStringBytes(JS_ValueToString(cx, argv[0])));
if (argc > 1) {
terminators = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
}
+ if (argc > 2) {
+ JS_ValueToInt32(cx, argv[2], &timeout);
+ }
+ if (argc > 3) {
+ JS_ValueToInt32(cx, argv[3], &poll_chan);
+ }
buf = switch_core_session_alloc(jss->session, digits);
- switch_ivr_collect_digits_count(jss->session, buf, digits, digits, terminators, &term);
+ switch_ivr_collect_digits_count(jss->session, buf, digits, digits, terminators, &term, timeout, poll_chan ? SWITCH_TRUE : SWITCH_FALSE);
*rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
return JS_TRUE;
}
return JS_TRUE;
}
+#ifdef HAVE_CURL
+
+struct config_data {
+ JSContext *cx;
+ JSObject *obj;
+ char *name;
+};
+
+static size_t realtime_callback(void *ptr, size_t size, size_t nmemb, void *data)
+{
+ register int realsize = size * nmemb;
+ char *line, lineb[2048], *nextline = NULL, *val = NULL, *p = NULL;
+ jsval rval;
+ struct config_data *config_data = data;
+ char code[256];
+
+ if (config_data->name) {
+ switch_copy_string(lineb, (char *) ptr, sizeof(lineb));
+ line = lineb;
+ while (line) {
+ if ((nextline = strchr(line, '\n'))) {
+ *nextline = '\0';
+ nextline++;
+ }
+
+ if ((val = strchr(line, '='))) {
+ *val = '\0';
+ val++;
+ if (val[0] == '>') {
+ *val = '\0';
+ val++;
+ }
+
+ for (p = line; p && *p == ' '; p++);
+ line = p;
+ for (p=line+strlen(line)-1;*p == ' '; p--)
+ *p = '\0';
+ for (p = val; p && *p == ' '; p++);
+ val = p;
+ for (p=val+strlen(val)-1;*p == ' '; p--)
+ *p = '\0';
+
+ snprintf(code, sizeof(code), "~%s[\"%s\"] = \"%s\"", config_data->name, line, val);
+ eval_some_js(code, config_data->cx, config_data->obj, &rval);
+
+ }
+
+ line = nextline;
+ }
+ }
+ return realsize;
+
+}
+
+
+static JSBool js_fetchurl(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *url = NULL, *name = NULL;
+ CURL *curl_handle = NULL;
+ struct config_data config_data;
+
+ if ( argc > 0 && (url = JS_GetStringBytes(JS_ValueToString(cx, argv[0])))) {
+ if (argc > 1)
+ name = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
+ curl_global_init(CURL_GLOBAL_ALL);
+ curl_handle = curl_easy_init();
+ if (!strncasecmp(url, "https", 5)) {
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+ config_data.cx = cx;
+ config_data.obj = obj;
+ if (name)
+ config_data.name = name;
+ curl_easy_setopt(curl_handle, CURLOPT_URL, url);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, realtime_callback);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&config_data);
+ curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "asterisk-js/1.0");
+ curl_easy_perform(curl_handle);
+ curl_easy_cleanup(curl_handle);
+ } else {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Error!\n");
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+#endif
+
/* Session Object */
/*********************************************************************************/
enum session_tinyid {
write_frame.samples = write_frame.datalen / 2;
for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
-
if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Bad Write\n");
break;
}
}
- switch_core_thread_session_end(&thread_session);
+ if (tto->timer) {
+ switch_core_thread_session_end(&thread_session);
+ }
return JS_TRUE;
}
return JS_FALSE;
}
+static JSBool js_include(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *code;
+ if ( argc > 0 && (code = JS_GetStringBytes(JS_ValueToString(cx, argv[0])))) {
+ eval_some_js(code, cx, obj, rval);
+ return JS_TRUE;
+ }
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Invalid Arguements\n");
+ return JS_FALSE;
+}
+
+#define B64BUFFLEN 1024
+static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int write_buf(int fd, char *buf) {
+
+ size_t len = strlen(buf);
+ if (fd && write(fd, buf, len) != len) {
+ close(fd);
+ return 0;
+ }
+
+ return 1;
+}
+
+static JSBool js_email(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *to = NULL, *from = NULL, *headers, *body = NULL, *file = NULL;
+ char *bound = "XXXX_boundary_XXXX";
+ char filename[80], buf[B64BUFFLEN];
+ int fd = 0, ifd = 0;
+ int x=0, y=0, bytes=0, ilen=0;
+ unsigned int b=0, l=0;
+ unsigned char in[B64BUFFLEN];
+ unsigned char out[B64BUFFLEN+512];
+ char *path = NULL;
+
+
+ if (
+ argc > 3 &&
+ (from = JS_GetStringBytes(JS_ValueToString(cx, argv[0]))) &&
+ (to = JS_GetStringBytes(JS_ValueToString(cx, argv[1]))) &&
+ (headers = JS_GetStringBytes(JS_ValueToString(cx, argv[2]))) &&
+ (body = JS_GetStringBytes(JS_ValueToString(cx, argv[3])))
+ ) {
+ if ( argc > 4)
+ file = JS_GetStringBytes(JS_ValueToString(cx, argv[4]));
+
+
+ snprintf(filename, 80, "/tmp/mail.%ld", switch_time_now());
+
+ if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644))) {
+ if (file) {
+ path = file;
+ if ((ifd = open(path, O_RDONLY)) < 1) {
+ return JS_FALSE;
+ }
+
+ snprintf(buf, B64BUFFLEN, "MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"%s\"\n", bound);
+ if (!write_buf(fd, buf)) {
+ return JS_FALSE;
+ }
+ }
+
+ if (!write_buf(fd, headers))
+ return JS_FALSE;
+
+ if (!write_buf(fd, "\n\n"))
+ return JS_FALSE;
+
+ if (file) {
+ snprintf(buf, B64BUFFLEN, "--%s\nContent-Type: text/plain\n\n", bound);
+ if (!write_buf(fd, buf))
+ return JS_FALSE;
+ }
+
+ if (!write_buf(fd, body))
+ return JS_FALSE;
+
+ if (file) {
+ snprintf(buf, B64BUFFLEN, "\n\n--%s\nContent-Type: application/octet-stream\nContent-Transfer-Encoding: base64\nContent-Description: Sound attachment.\nContent-Disposition: attachment; filename=\"%s\"\n\n", bound, file);
+ if (!write_buf(fd, buf))
+ return JS_FALSE;
+
+ while((ilen=read(ifd, in, B64BUFFLEN))) {
+ for (x=0;x<ilen;x++) {
+ b = (b<<8) + in[x];
+ l += 8;
+ while (l >= 6) {
+ out[bytes++] = c64[(b>>(l-=6))%64];
+ if (++y!=72)
+ continue;
+ out[bytes++] = '\n';
+ y=0;
+ }
+ }
+ if (write(fd, &out, bytes) != bytes) {
+ return -1;
+ } else
+ bytes=0;
+
+ }
+
+ if (l > 0)
+ out[bytes++] = c64[((b%16)<<(6-l))%64];
+ if (l != 0) while (l < 6)
+ out[bytes++] = '=', l += 2;
+
+ if (write(fd, &out, bytes) != bytes) {
+ return -1;
+ }
+
+ }
+
+
+
+ if (file) {
+ snprintf(buf, B64BUFFLEN, "\n\n--%s--\n.\n", bound);
+ if (!write_buf(fd, buf))
+ return JS_FALSE;
+ }
+ }
+
+ if (fd)
+ close(fd);
+ if (ifd)
+ close(ifd);
+
+ snprintf(buf, B64BUFFLEN, "/bin/cat %s | /usr/sbin/sendmail -tf \"%s\" %s", filename, from, to);
+ system(buf);
+ unlink(filename);
+
+
+ if (file) {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Emailed file [%s] to [%s]\n", filename, to);
+ } else {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Emailed data to [%s]\n", to);
+ }
+ return JS_TRUE;
+ }
+
+
+ return JS_FALSE;
+}
static JSFunctionSpec fs_functions[] = {
{"console_log", js_log, 2},
+ {"include", js_include, 1},
+ {"email", js_email, 2},
+#ifdef HAVE_CURL
+ {"fetchURL", js_fetchurl, 1},
+#endif
{0}
};
unsigned int buflen,
unsigned int maxdigits,
const char *terminators,
- char *terminator)
+ char *terminator,
+ unsigned int timeout,
+ unsigned int poll_channel
+ )
{
unsigned int i = 0, x = (unsigned int) strlen(buf);
switch_channel *channel;
switch_status status = SWITCH_STATUS_SUCCESS;
-
+ switch_time_t started = 0;
+ unsigned int elapsed;
+
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
*terminator = '\0';
- for (i = 0 ; i < x; i++) {
- if (strchr(terminators, buf[i])) {
- *terminator = buf[i];
- return SWITCH_STATUS_SUCCESS;
+ if (terminators) {
+ for (i = 0 ; i < x; i++) {
+ if (strchr(terminators, buf[i])) {
+ *terminator = buf[i];
+ return SWITCH_STATUS_SUCCESS;
+ }
}
}
+ if (timeout) {
+ started = switch_time_now();
+ }
while (switch_channel_get_state(channel) == CS_EXECUTE) {
switch_frame *read_frame;
+ if (timeout) {
+ elapsed = (switch_time_now() - started) / 1000;
+ if (elapsed >= timeout) {
+ break;
+ }
+ }
+
if (switch_channel_has_dtmf(channel)) {
char dtmf[128];
switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf));
}
}
}
-
- if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
- break;
+ if (poll_channel) {
+ if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
+ break;
+ }
+ } else {
+ switch_yield(1000);
}
}
}
}
- switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done playing file\n");
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done speaking text\n");
switch_core_codec_destroy(&codec);
flags = 0;
switch_core_codec_destroy(&codec);
}
+/* Bridge Related Stuff*/
+/*********************************************************************************/
+struct audio_bridge_data {
+ switch_core_session *session_a;
+ switch_core_session *session_b;
+ int running;
+};
+
+static void *audio_bridge_thread(switch_thread *thread, void *obj)
+{
+ struct switch_core_thread_session *data = obj;
+ int *stream_id_p;
+ int stream_id = 0, ans_a = 0, ans_b = 0;
+
+ switch_channel *chan_a, *chan_b;
+ switch_frame *read_frame;
+ switch_core_session *session_a, *session_b;
+
+ session_a = data->objs[0];
+ session_b = data->objs[1];
+
+ stream_id_p = data->objs[2];
+ if (stream_id_p) {
+ stream_id = *stream_id_p;
+ }
+
+ chan_a = switch_core_session_get_channel(session_a);
+ chan_b = switch_core_session_get_channel(session_b);
+
+
+ ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
+ ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
+
+
+ while (data->running > 0) {
+ switch_channel_state b_state = switch_channel_get_state(chan_b);
+
+ switch (b_state) {
+ case CS_HANGUP:
+ data->running = -1;
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ /* If this call is running on early media and it answers for real, pass it along... */
+ if (!ans_b && switch_channel_test_flag(chan_a, CF_ANSWERED)) {
+ if (!switch_channel_test_flag(chan_b, CF_ANSWERED)) {
+ switch_channel_answer(chan_b);
+ }
+ ans_b++;
+ }
+
+ if (!ans_a && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
+ if (!switch_channel_test_flag(chan_a, CF_ANSWERED)) {
+ switch_channel_answer(chan_a);
+ }
+ ans_a++;
+ }
+
+ /* if 1 channel has DTMF pass it to the other */
+ if (switch_channel_has_dtmf(chan_a)) {
+ char dtmf[128];
+ switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
+ switch_core_session_send_dtmf(session_b, dtmf);
+ }
+
+ /* read audio from 1 channel and write it to the other */
+ if (switch_core_session_read_frame(session_a, &read_frame, -1, stream_id) == SWITCH_STATUS_SUCCESS
+ && read_frame->datalen) {
+ if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "write: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_b));
+ data->running = -1;
+ }
+ } else {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "read: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_a));
+ data->running = -1;
+ }
+
+ }
+ switch_channel_hangup(chan_b);
+ data->running = 0;
+
+ return NULL;
+}
+
+
+static switch_status audio_bridge_on_hangup(switch_core_session *session)
+{
+ switch_core_session *other_session;
+ switch_channel *channel = NULL, *other_channel = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ other_session = switch_channel_get_private(channel);
+ assert(other_session != NULL);
+
+ other_channel = switch_core_session_get_channel(other_session);
+ assert(other_channel != NULL);
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM HANGUP %s kill %s\n", switch_channel_get_name(channel),
+ switch_channel_get_name(other_channel));
+
+ switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL);
+ switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status audio_bridge_on_ring(switch_core_session *session)
+{
+ switch_channel *channel = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM RING\n");
+
+ /* put the channel in a passive state so we can loop audio to it */
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ switch_channel_set_state(channel, CS_TRANSMIT);
+ return SWITCH_STATUS_FALSE;
+ }
+
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static const switch_state_handler_table audio_bridge_peer_state_handlers = {
+ /*.on_init */ NULL,
+ /*.on_ring */ audio_bridge_on_ring,
+ /*.on_execute */ NULL,
+ /*.on_hangup */ audio_bridge_on_hangup,
+ /*.on_loopback */ NULL,
+ /*.on_transmit */ NULL
+};
+
+static const switch_state_handler_table audio_bridge_caller_state_handlers = {
+ /*.on_init */ NULL,
+ /*.on_ring */ NULL,
+ /*.on_execute */ NULL,
+ /*.on_hangup */ audio_bridge_on_hangup,
+ /*.on_loopback */ NULL,
+ /*.on_transmit */ NULL
+};
+
+SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_session *session,
+ switch_core_session *peer_session,
+ unsigned int timelimit)
+{
+ struct switch_core_thread_session this_audio_thread, other_audio_thread;
+ switch_channel *caller_channel, *peer_channel;
+ time_t start;
+ int stream_id = 0;
+
+ caller_channel = switch_core_session_get_channel(session);
+ assert(caller_channel != NULL);
+
+ peer_channel = switch_core_session_get_channel(peer_session);
+ assert(peer_channel != NULL);
+
+ memset(&other_audio_thread, 0, sizeof(other_audio_thread));
+ memset(&this_audio_thread, 0, sizeof(this_audio_thread));
+ other_audio_thread.objs[0] = session;
+ other_audio_thread.objs[1] = peer_session;
+ other_audio_thread.objs[2] = &stream_id;
+ other_audio_thread.running = 5;
+
+ this_audio_thread.objs[0] = peer_session;
+ this_audio_thread.objs[1] = session;
+ this_audio_thread.objs[2] = &stream_id;
+ this_audio_thread.running = 2;
+
+
+ switch_channel_set_private(caller_channel, peer_session);
+ switch_channel_set_private(peer_channel, session);
+ switch_channel_add_state_handler(caller_channel, &audio_bridge_caller_state_handlers);
+ switch_channel_add_state_handler(peer_channel, &audio_bridge_peer_state_handlers);
+ switch_core_session_thread_launch(peer_session);
+
+ for (;;) {
+ int state = switch_channel_get_state(peer_channel);
+ if (state > CS_RING) {
+ break;
+ }
+ switch_yield(1000);
+ }
+
+ time(&start);
+ while (switch_channel_get_state(caller_channel) == CS_EXECUTE &&
+ switch_channel_get_state(peer_channel) == CS_TRANSMIT &&
+ !switch_channel_test_flag(peer_channel, CF_ANSWERED) &&
+ !switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) &&
+ ((time(NULL) - start) < timelimit)) {
+ switch_yield(20000);
+ }
+
+ if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
+ switch_channel_answer(caller_channel);
+ }
+
+ if (switch_channel_test_flag(peer_channel, CF_ANSWERED) ||
+ switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
+
+ switch_core_session_launch_thread(session, audio_bridge_thread, (void *) &other_audio_thread);
+ audio_bridge_thread(NULL, (void *) &this_audio_thread);
+
+ switch_channel_hangup(peer_channel);
+ if (other_audio_thread.running > 0) {
+ other_audio_thread.running = -1;
+ /* wait for the other audio thread */
+ while (other_audio_thread.running) {
+ switch_yield(1000);
+ }
+ }
+
+
+ }
+ return SWITCH_STATUS_SUCCESS;
+}