diff --git a/scripts/multicast/send.pl b/scripts/multicast/send.pl index 047c70d6cb..ed4c84dfe2 100755 --- a/scripts/multicast/send.pl +++ b/scripts/multicast/send.pl @@ -8,8 +8,10 @@ $ip and $port or die "Usage $0: \n"; $socket = new IO::Socket::INET->new( PeerPort => $port, Proto => 'udp', PeerAddr => $ip); - -my $buf = `cat $file`; +open(I, $file); +$/ = undef; +my $buf = ; +close(I); $socket->send("$buf\n"); diff --git a/src/include/switch_caller.h b/src/include/switch_caller.h index 3a1592aadd..0074426482 100644 --- a/src/include/switch_caller.h +++ b/src/include/switch_caller.h @@ -134,7 +134,7 @@ extern "C" { /*! \brief Create a new caller profile object - \param session session associated with the profile (bound by scope) + \param pool memory pool to use \param dialplan name of the dialplan module in use \param caller_id_name caller ID name \param caller_id_number caller ID number @@ -144,7 +144,7 @@ extern "C" { \param destination_number destination number \return a new profile object allocated from the session's memory pool */ - SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_core_session *session, + SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_memory_pool *pool, char *dialplan, char *caller_id_name, char *caller_id_number, diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 347824e696..008b39a112 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -65,6 +65,13 @@ typedef struct { */ SWITCH_DECLARE(switch_channel_state) switch_channel_get_state(switch_channel *channel); +/*! + \brief Determine if a channel is ready for io + \param channel channel to test + \return true if the channel is ready +*/ +SWITCH_DECLARE(unsigned int) switch_channel_ready(switch_channel *channel); + /*! \brief Set the current state of a channel \param channel channel to set state of diff --git a/src/include/switch_core.h b/src/include/switch_core.h index c3fbefa9ee..3b2fc327b3 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -157,6 +157,12 @@ SWITCH_DECLARE(switch_status) switch_core_destroy_memory_pool(switch_memory_pool */ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session); +/*! + \brief determine if the session's state machine is running + \param session the session on which to check +*/ +SWITCH_DECLARE(unsigned int) switch_core_session_runing(switch_core_session *session); + /*! \brief Allocate memory from the main pool with no intention of returning it \param memory the number of bytes to allocate diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 5626f1916e..b9e1b205d3 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -239,6 +239,8 @@ CF_RECV_AUDIO = (1 << 1) - Channel will receive audio CF_ANSWERED = (1 << 2) - Channel is answered CF_OUTBOUND = (1 << 3) - Channel is an outbound channel CF_EARLY_MEDIA = (1 << 4) - Channel is ready for audio before answer +CF_ORIGINATOR = (1 << 5) - Channel is an originator +CF_TRANSFER = (1 << 6) - Channel is being transfered */ @@ -247,7 +249,9 @@ typedef enum { CF_RECV_AUDIO = (1 << 1), CF_ANSWERED = (1 << 2), CF_OUTBOUND = (1 << 3), - CF_EARLY_MEDIA = (1 << 4) + CF_EARLY_MEDIA = (1 << 4), + CF_ORIGINATOR = (1 << 5), + CF_TRANSFER = (1 << 6) } switch_channel_flag; diff --git a/src/mod/applications/mod_bridgecall/mod_bridgecall.c b/src/mod/applications/mod_bridgecall/mod_bridgecall.c index 1a532084ad..3f064020bf 100644 --- a/src/mod/applications/mod_bridgecall/mod_bridgecall.c +++ b/src/mod/applications/mod_bridgecall/mod_bridgecall.c @@ -55,7 +55,7 @@ static void audio_bridge_function(switch_core_session *session, char *data) } caller_caller_profile = switch_channel_get_caller_profile(caller_channel); - caller_profile = switch_caller_profile_new(session, + caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), caller_caller_profile->dialplan, caller_caller_profile->caller_id_name, caller_caller_profile->caller_id_number, diff --git a/src/mod/endpoints/mod_exosip/mod_exosip.c b/src/mod/endpoints/mod_exosip/mod_exosip.c index a2efe4da9c..23d6c30b63 100644 --- a/src/mod/endpoints/mod_exosip/mod_exosip.c +++ b/src/mod/endpoints/mod_exosip/mod_exosip.c @@ -550,7 +550,6 @@ static switch_status exosip_read_frame(switch_core_session *session, switch_fram && tech_pvt->read_frame.datalen == 0) { tech_pvt->read_frame.datalen = jrtp4c_read(tech_pvt->rtp_session, tech_pvt->read_frame.data, sizeof(tech_pvt->read_buf), &payload); - /* RFC2833 ... TBD try harder to honor the duration etc.*/ if (payload == 101) { unsigned char *packet = tech_pvt->read_frame.data; @@ -732,7 +731,6 @@ static switch_status exosip_kill_channel(switch_core_session *session, int sig) tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - switch_clear_flag(tech_pvt, TFLAG_IO); switch_set_flag(tech_pvt, TFLAG_BYE); @@ -1008,7 +1006,7 @@ static switch_status exosip_create_call(eXosip_event_t * event) snprintf(name, sizeof(name), "Exosip/%s-%04x", event->request->from->url->username, rand() & 0xffff); switch_channel_set_name(channel, name); - if ((tech_pvt->caller_profile = switch_caller_profile_new(session, + if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), globals.dialplan, event->request->from->displayname, event->request->from->url->username, diff --git a/src/mod/endpoints/mod_iax/mod_iax.c b/src/mod/endpoints/mod_iax/mod_iax.c index a1952674fb..5168df50a7 100644 --- a/src/mod/endpoints/mod_iax/mod_iax.c +++ b/src/mod/endpoints/mod_iax/mod_iax.c @@ -979,7 +979,7 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void) } - if ((tech_pvt->caller_profile = switch_caller_profile_new(session, + if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), globals.dialplan, iaxevent->ies.calling_name, iaxevent->ies.calling_number, diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 412f3d8d6f..48f251691a 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -808,7 +808,7 @@ static switch_status place_call(char *dest, char *out, size_t outlen) return SWITCH_STATUS_FALSE; } - if ((tech_pvt->caller_profile = switch_caller_profile_new(session, + if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), globals.dialplan, globals.cid_name, globals.cid_num, NULL, NULL, NULL, dest)) != 0) { diff --git a/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c b/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c index e88035e3e7..281dd54422 100644 --- a/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c +++ b/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c @@ -973,7 +973,7 @@ static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri snprintf(ani2str, 5, "%.2d", event->ring.ani2); } - if ((tech_pvt->caller_profile = switch_caller_profile_new(session, + if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), globals.dialplan, "wanpipe fixme", event->ring.callingnum, diff --git a/src/mod/endpoints/mod_woomera/mod_woomera.c b/src/mod/endpoints/mod_woomera/mod_woomera.c index c22d569aab..a605c2286d 100644 --- a/src/mod/endpoints/mod_woomera/mod_woomera.c +++ b/src/mod/endpoints/mod_woomera/mod_woomera.c @@ -1064,7 +1064,7 @@ static void *woomera_channel_thread_run(switch_thread *thread, void *obj) } ip = woomera_message_header(&wmsg, "Remote-Address"); - if ((tech_pvt->caller_profile = switch_caller_profile_new(session, + if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), tech_pvt->profile->dialplan, cid_name, cid_num, ip, NULL, NULL, exten)) != 0) { char name[128]; diff --git a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c index 76104e2361..6bb8408b99 100644 --- a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c +++ b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c @@ -63,6 +63,8 @@ static const char modname[] = "mod_spidermonkey"; static int eval_some_js(char *code, JSContext *cx, JSObject *obj, jsval *rval); +static void session_destroy(JSContext *cx, JSObject *obj); +static JSBool session_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static struct { size_t gStackChunkSize; @@ -86,6 +88,10 @@ typedef enum { TTF_DTMF = (1 << 0) } teletone_flag_t; +typedef enum { + S_HUP = (1 << 0) +} session_flag_t; + struct dtmf_callback_state { struct js_session *session_state; char code_buffer[1024]; @@ -100,6 +106,7 @@ struct js_session { switch_core_session *session; JSContext *cx; JSObject *obj; + switch_memory_pool *pool; unsigned int flags; }; @@ -407,7 +414,7 @@ static JSBool session_recordfile(JSContext *cx, JSObject *obj, uintN argc, jsval switch_ivr_record_file(jss->session, &fh, file_name, dtmf_func, bp, len); *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, cb_state.ret_buffer)); - return (switch_channel_get_state(channel) == CS_EXECUTE) ? JS_TRUE : JS_FALSE; + return (switch_channel_ready(channel)) ? JS_TRUE : JS_FALSE; } static JSBool session_streamfile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) @@ -459,7 +466,7 @@ static JSBool session_streamfile(JSContext *cx, JSObject *obj, uintN argc, jsval switch_ivr_play_file(jss->session, &fh, file_name, timer_name, dtmf_func, bp, len); *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, cb_state.ret_buffer)); - return (switch_channel_get_state(channel) == CS_EXECUTE) ? JS_TRUE : JS_FALSE; + return (switch_channel_ready(channel)) ? JS_TRUE : JS_FALSE; } static JSBool session_speak(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) @@ -520,7 +527,7 @@ static JSBool session_speak(JSContext *cx, JSObject *obj, uintN argc, jsval *arg *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, cb_state.ret_buffer)); - return (switch_channel_get_state(channel) == CS_EXECUTE) ? JS_TRUE : JS_FALSE; + return (switch_channel_ready(channel)) ? JS_TRUE : JS_FALSE; } static JSBool session_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) @@ -566,6 +573,59 @@ static JSBool session_answer(JSContext *cx, JSObject *obj, uintN argc, jsval *ar return JS_TRUE; } +static JSBool session_ready(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + struct js_session *jss = JS_GetPrivate(cx, obj); + switch_channel *channel; + + channel = switch_core_session_get_channel(jss->session); + assert(channel != NULL); + *rval = BOOLEAN_TO_JSVAL( switch_channel_ready(channel) ? JS_TRUE : JS_FALSE ); + + return JS_TRUE; +} + +static JSBool session_wait_for_answer(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + struct js_session *jss = JS_GetPrivate(cx, obj); + switch_channel *channel; + switch_time_t started; + unsigned int elapsed; + channel = switch_core_session_get_channel(jss->session); + assert(channel != NULL); + int32 timeout = 60; + started = switch_time_now(); + + if (argc > 0) { + JS_ValueToInt32(cx, argv[0], &timeout); + } + + for(;;) { + elapsed = (unsigned int)((switch_time_now() - started) / 1000); + if ((int32)elapsed > timeout || switch_channel_test_flag(channel, CF_ANSWERED) || + switch_channel_test_flag(channel, CF_EARLY_MEDIA)) { + break; + } + + switch_yield(1000); + } + + return JS_TRUE; +} + +static JSBool session_hangup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + struct js_session *jss = JS_GetPrivate(cx, obj); + switch_channel *channel; + + channel = switch_core_session_get_channel(jss->session); + assert(channel != NULL); + + switch_channel_hangup(channel); + switch_core_session_kill_channel(jss->session, SWITCH_SIG_KILL); + return JS_TRUE; +} + #ifdef HAVE_CURL struct config_data { @@ -658,7 +718,8 @@ static JSBool js_fetchurl(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* Session Object */ /*********************************************************************************/ enum session_tinyid { - SESSION_NAME, SESSION_STATE + SESSION_NAME, SESSION_STATE, + PROFILE_DIALPLAN, PROFILE_CID_NAME, PROFILE_CID_NUM, PROFILE_IP, PROFILE_ANI, PROFILE_ANI2, PROFILE_DEST }; static JSFunctionSpec session_methods[] = { @@ -667,6 +728,9 @@ static JSFunctionSpec session_methods[] = { {"speak", session_speak, 1}, {"getDigits", session_get_digits, 1}, {"answer", session_answer, 0}, + {"ready", session_ready, 0}, + {"waitForAnswer", session_wait_for_answer, 0}, + {"hangup", session_hangup, 0}, {0} }; @@ -674,6 +738,13 @@ static JSFunctionSpec session_methods[] = { static JSPropertySpec session_props[] = { {"name", SESSION_NAME, JSPROP_READONLY|JSPROP_PERMANENT}, {"state", SESSION_STATE, JSPROP_READONLY|JSPROP_PERMANENT}, + {"dialplan", PROFILE_DIALPLAN, JSPROP_READONLY|JSPROP_PERMANENT}, + {"caller_id_name", PROFILE_CID_NAME, JSPROP_READONLY|JSPROP_PERMANENT}, + {"caller_id_num", PROFILE_CID_NUM, JSPROP_READONLY|JSPROP_PERMANENT}, + {"network_addr", PROFILE_IP, JSPROP_READONLY|JSPROP_PERMANENT}, + {"ani", PROFILE_ANI, JSPROP_READONLY|JSPROP_PERMANENT}, + {"ani2", PROFILE_ANI2, JSPROP_READONLY|JSPROP_PERMANENT}, + {"destination", PROFILE_DEST, JSPROP_READONLY|JSPROP_PERMANENT}, {0} }; @@ -683,11 +754,14 @@ static JSBool session_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval int param = 0; JSBool res = JS_TRUE; switch_channel *channel; + switch_caller_profile *caller_profile; char *name; channel = switch_core_session_get_channel(jss->session); assert(channel != NULL); + caller_profile = switch_channel_get_caller_profile(channel); + name = JS_GetStringBytes(JS_ValueToString(cx, id)); /* numbers are our props anything else is a method */ if (name[0] >= 48 && name[0] <= 57) { @@ -701,7 +775,42 @@ static JSBool session_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, switch_channel_get_name(channel))); break; case SESSION_STATE: - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, switch_channel_state_name(switch_channel_get_state(channel)) )); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, switch_channel_state_name(switch_channel_get_state(channel)))); + break; + case PROFILE_DIALPLAN: + if (caller_profile) { + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, caller_profile->dialplan)); + } + break; + case PROFILE_CID_NAME: + if (caller_profile) { + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, caller_profile->caller_id_name)); + } + break; + case PROFILE_CID_NUM: + if (caller_profile) { + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, caller_profile->caller_id_number)); + } + break; + case PROFILE_IP: + if (caller_profile) { + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, caller_profile->network_addr)); + } + break; + case PROFILE_ANI: + if (caller_profile) { + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, caller_profile->ani)); + } + break; + case PROFILE_ANI2: + if (caller_profile) { + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, caller_profile->ani2)); + } + break; + case PROFILE_DEST: + if (caller_profile) { + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, caller_profile->destination_number)); + } break; default: res = JS_FALSE; @@ -715,7 +824,8 @@ static JSBool session_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval JSClass session_class = { "Session", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, session_getProperty, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, session_destroy, NULL, NULL, NULL, + session_construct }; @@ -752,6 +862,117 @@ static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map return 0; } +/* Session Object */ +/*********************************************************************************/ +static JSBool session_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + switch_memory_pool *pool = NULL; + int need_pool = 1; + if (argc > 2) { + struct js_session *jss = NULL; + JSObject *session_obj; + switch_core_session *session = NULL, *peer_session = NULL; + switch_caller_profile *caller_profile = NULL; + char *channel_type = NULL; + char *dest = NULL; + char *dialplan = NULL; + char *cid_name = ""; + char *cid_num = ""; + char *network_addr = ""; + char *ani = ""; + char *ani2 = ""; + + + if (JS_ValueToObject(cx, argv[0], &session_obj)) { + struct js_session *old_jss = NULL; + if ((old_jss = JS_GetPrivate(cx, session_obj))) { + session = old_jss->session; + pool = switch_core_session_get_pool(session); + need_pool = 0; + } + } + + channel_type = JS_GetStringBytes(JS_ValueToString(cx, argv[1])); + dest = JS_GetStringBytes(JS_ValueToString(cx, argv[2])); + + if (argc > 3) { + dialplan = JS_GetStringBytes(JS_ValueToString(cx, argv[3])); + } + if (argc > 4) { + cid_name = JS_GetStringBytes(JS_ValueToString(cx, argv[4])); + } + if (argc > 5) { + cid_num = JS_GetStringBytes(JS_ValueToString(cx, argv[5])); + } + if (argc > 6) { + network_addr = JS_GetStringBytes(JS_ValueToString(cx, argv[6])); + } + if (argc > 7) { + ani = JS_GetStringBytes(JS_ValueToString(cx, argv[7])); + } + if (argc > 8) { + ani2 = JS_GetStringBytes(JS_ValueToString(cx, argv[8])); + } + + if (need_pool) { + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n"); + return JS_FALSE; + } + } + + caller_profile = switch_caller_profile_new(pool, dialplan, cid_name, cid_num, network_addr, ani, ani2, dest); + if (switch_core_session_outgoing_channel(session, channel_type, caller_profile, &peer_session) == SWITCH_STATUS_SUCCESS) { + jss = switch_core_session_alloc(peer_session, sizeof(*jss)); + jss->session = peer_session; + jss->flags = 0; + jss->cx = cx; + jss->obj = obj; + JS_SetPrivate(cx, obj, jss); + if (need_pool) { + jss->pool = pool; + } + switch_core_session_thread_launch(peer_session); + switch_set_flag(jss, S_HUP); + + return JS_TRUE; + } else { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Create Channel\n"); + } + } else { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Missing Args\n"); + } + + if (need_pool) { + switch_core_destroy_memory_pool(&pool); + } + return JS_FALSE; +} + +static void session_destroy(JSContext *cx, JSObject *obj) +{ + struct js_session *jss; + + if (cx && obj) { + if ((jss = JS_GetPrivate(cx, obj))) { + if (jss->pool) { + switch_core_destroy_memory_pool(&jss->pool); + } + + if (switch_test_flag(jss, S_HUP)) { + switch_channel *channel; + + if (jss->session) { + channel = switch_core_session_get_channel(jss->session); + switch_channel_hangup(channel); + } + } + } + } + + return; +} + /* TeleTone Object */ /*********************************************************************************/ static JSBool teletone_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) @@ -1072,6 +1293,42 @@ static int write_buf(int fd, char *buf) { return 1; } +static JSBool js_bridge(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + struct js_session *jss_a = NULL, *jss_b = NULL; + JSObject *session_obj_a = NULL, *session_obj_b = NULL; + int32 timelimit = 60; + + if (argc > 1) { + if (JS_ValueToObject(cx, argv[0], &session_obj_a)) { + if (!(jss_a = JS_GetPrivate(cx, session_obj_a))) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Find Session [1]\n"); + return JS_FALSE; + } + } + if (JS_ValueToObject(cx, argv[1], &session_obj_b)) { + if (!(jss_b = JS_GetPrivate(cx, session_obj_b))) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Find Session [1]\n"); + return JS_FALSE; + } + } + } + + if (argc > 3) { + if (!JS_ValueToInt32(cx, argv[3], &timelimit)) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Convert to INT\n"); + return JS_FALSE; + } + } + if (!(jss_a && jss_b)) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Failure! %s %s\n", jss_a ? "y" : "n", jss_b ? "y" : "n"); + return JS_FALSE; + } + + switch_ivr_multi_threaded_bridge(jss_a->session, jss_b->session, timelimit, NULL, NULL, NULL); + return JS_TRUE; +} + static JSBool js_email(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char *to = NULL, *from = NULL, *headers, *body = NULL, *file = NULL; @@ -1195,6 +1452,7 @@ static JSFunctionSpec fs_functions[] = { {"console_log", js_log, 2}, {"include", js_include, 1}, {"email", js_email, 2}, + {"bridge", js_bridge, 2}, #ifdef HAVE_CURL {"fetchURL", js_fetchurl, 1}, #endif @@ -1231,6 +1489,40 @@ static int eval_some_js(char *code, JSContext *cx, JSObject *obj, jsval *rval) return res; } +static int env_init(JSContext *cx, JSObject *javascript_object) +{ + + JS_DefineFunctions(cx, javascript_object, fs_functions); + + JS_InitStandardClasses(cx, javascript_object); + + JS_InitClass(cx, + javascript_object, + NULL, + &teletone_class, + teletone_construct, + 3, + teletone_props, + teletone_methods, + teletone_props, + teletone_methods + ); + + JS_InitClass(cx, + javascript_object, + NULL, + &session_class, + session_construct, + 3, + session_props, + session_methods, + session_props, + session_methods + ); + + return 1; +} + static void js_exec(switch_core_session *session, char *data) { char *code, *next, *arg, *nextarg; @@ -1270,28 +1562,14 @@ static void js_exec(switch_core_session *session, char *data) if ((cx = JS_NewContext(globals.rt, globals.gStackChunkSize))) { JS_SetErrorReporter(cx, js_error); if ((javascript_global_object = JS_NewObject(cx, &global_class, NULL, NULL)) && - JS_DefineFunctions(cx, javascript_global_object, fs_functions) && - JS_InitStandardClasses(cx, javascript_global_object) && + env_init(cx, javascript_global_object) && (session_obj = new_js_session(cx, javascript_global_object, session, &jss, "session", flags))) { JS_SetGlobalObject(cx, javascript_global_object); JS_SetPrivate(cx, javascript_global_object, session); res = 0; - JS_InitClass(cx, - javascript_global_object, - NULL, - &teletone_class, - teletone_construct, - 3, - teletone_props, - teletone_methods, - teletone_props, - teletone_methods - ); - - - + do { if ((next = strchr(code, '|'))) { *next = '\0'; @@ -1330,6 +1608,89 @@ static void js_exec(switch_core_session *session, char *data) } } +static void *js_thread_run(switch_thread *thread, void *obj) +{ + JSContext *cx = NULL; + JSObject *javascript_global_object = NULL; + cx = JS_NewContext(globals.rt, globals.gStackChunkSize); + char buf[1024]; + char *code, *next, *arg, *nextarg; + jsval rval; + int x = 0; + char *input_code = obj; + + javascript_global_object = JS_NewObject(cx, &global_class, NULL, NULL); + env_init(cx, javascript_global_object); + code = input_code; + + do { + if ((next = strchr(code, '|'))) { + *next = '\0'; + next++; + } + if ((arg = strchr(code, ':'))) { + int y; + for (y=0;(arg=strchr(arg, ':'));y++) + arg++; + arg = strchr(code, ':'); + *arg = '\0'; + arg++; + snprintf(buf, sizeof(buf), "~var Argv = new Array(%d);", y); + eval_some_js(buf, cx, javascript_global_object, &rval); + snprintf(buf, sizeof(buf), "~var argc = %d", y); + eval_some_js(buf, cx, javascript_global_object, &rval); + do { + if ((nextarg = strchr(arg, ':'))) { + *nextarg = '\0'; + nextarg++; + } + snprintf(buf, sizeof(buf), "~Argv[%d] = \"%s\";", x++, arg); + eval_some_js(buf, cx, javascript_global_object, &rval); + arg = nextarg; + } while (arg); + } + if (!eval_some_js(code, cx, javascript_global_object, &rval)) { + break; + } + code = next; + } while (code); + + if (input_code) { + free(input_code); + } + return NULL; +} + + +static switch_memory_pool *module_pool = NULL; + +static void js_thread_launch(char *text) +{ + switch_thread *thread; + switch_threadattr_t *thd_attr = NULL; + + if (!module_pool) { + if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n"); + return; + } + } + + switch_threadattr_create(&thd_attr, module_pool); + switch_threadattr_detach_set(thd_attr, 1); + switch_thread_create(&thread, thd_attr, js_thread_run, strdup(text), module_pool); +} + + +static switch_status launch_async(char *text, char *out, size_t outlen) +{ + + js_thread_launch(text); + switch_copy_string(out, "OK", outlen); + return SWITCH_STATUS_SUCCESS; +} + + static const switch_application_interface ivrtest_application_interface = { /*.interface_name */ "javascript", /*.application_function */ js_exec, @@ -1337,6 +1698,12 @@ static const switch_application_interface ivrtest_application_interface = { /*.next*/ NULL }; +static struct switch_api_interface js_run_interface = { + /*.interface_name */ "jsrun", + /*.desc */ "run a script", + /*.function */ launch_async, + /*.next */ NULL +}; static switch_loadable_module_interface spidermonkey_module_interface = { /*.module_name */ modname, @@ -1345,7 +1712,7 @@ static switch_loadable_module_interface spidermonkey_module_interface = { /*.dialplan_interface */ NULL, /*.codec_interface */ NULL, /*.application_interface */ &ivrtest_application_interface, - /*.api_interface */ NULL, + /*.api_interface */ &js_run_interface, /*.file_interface */ NULL, /*.speech_interface */ NULL, /*.directory_interface */ NULL diff --git a/src/switch_caller.c b/src/switch_caller.c index 266b1742af..b28afedab6 100644 --- a/src/switch_caller.c +++ b/src/switch_caller.c @@ -31,7 +31,7 @@ */ #include -SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_core_session *session, +SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_memory_pool *pool, char *dialplan, char *caller_id_name, char *caller_id_number, @@ -42,14 +42,14 @@ SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_core_se switch_caller_profile *profile = NULL; - if ((profile = switch_core_session_alloc(session, sizeof(switch_caller_profile))) != 0) { - profile->dialplan = switch_core_session_strdup(session, dialplan); - profile->caller_id_name = switch_core_session_strdup(session, caller_id_name); - profile->caller_id_number = switch_core_session_strdup(session, caller_id_number); - profile->network_addr = switch_core_session_strdup(session, network_addr); - profile->ani = switch_core_session_strdup(session, ani); - profile->ani2 = switch_core_session_strdup(session, ani2); - profile->destination_number = switch_core_session_strdup(session, destination_number); + if ((profile = switch_core_alloc(pool, sizeof(switch_caller_profile))) != 0) { + profile->dialplan = switch_core_strdup(pool, dialplan); + profile->caller_id_name = switch_core_strdup(pool, caller_id_name); + profile->caller_id_number = switch_core_strdup(pool, caller_id_number); + profile->network_addr = switch_core_strdup(pool, network_addr); + profile->ani = switch_core_strdup(pool, ani); + profile->ani2 = switch_core_strdup(pool, ani2); + profile->destination_number = switch_core_strdup(pool, destination_number); } return profile; diff --git a/src/switch_channel.c b/src/switch_channel.c index ee0def55fe..188e7e4734 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -248,6 +248,12 @@ SWITCH_DECLARE(switch_channel_state) switch_channel_get_state(switch_channel *ch return channel->state; } +SWITCH_DECLARE(unsigned int) switch_channel_ready(switch_channel *channel) +{ + assert(channel != NULL); + return (channel->state > CS_RING && channel->state < CS_HANGUP) ? 1 : 0; +} + static const char *state_names[] = { "CS_NEW", "CS_INIT", diff --git a/src/switch_core.c b/src/switch_core.c index 1246212e04..231857aa1a 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -42,6 +42,7 @@ EXTERN_C void xs_init(pTHX); struct switch_core_session { unsigned long id; char name[80]; + int thread_running; switch_memory_pool *pool; switch_channel *channel; switch_thread *thread; @@ -714,9 +715,9 @@ SWITCH_DECLARE(char *) switch_core_session_strdup(switch_core_session *session, assert(session != NULL); assert(session->pool != NULL); - if (!todup) + if (!todup) { return NULL; - + } len = strlen(todup) + 1; if (todup && (duped = apr_palloc(session->pool, len)) != 0) { @@ -731,10 +732,11 @@ SWITCH_DECLARE(char *) switch_core_strdup(switch_memory_pool *pool, char *todup) char *duped = NULL; size_t len; assert(pool != NULL); - assert(todup != NULL); - if (!todup) + if (!todup) { return NULL; + } + len = strlen(todup) + 1; if (todup && (duped = apr_palloc(pool, len)) != 0) { @@ -792,9 +794,11 @@ SWITCH_DECLARE(switch_status) switch_core_session_outgoing_channel(switch_core_s if ((status = endpoint_interface->io_routines->outgoing_channel(session, caller_profile, new_session)) == SWITCH_STATUS_SUCCESS) { - for (ptr = session->event_hooks.outgoing_channel; ptr; ptr = ptr->next) { - if ((status = ptr->outgoing_channel(session, caller_profile, *new_session)) != SWITCH_STATUS_SUCCESS) { - break; + if (session) { + for (ptr = session->event_hooks.outgoing_channel; ptr; ptr = ptr->next) { + if ((status = ptr->outgoing_channel(session, caller_profile, *new_session)) != SWITCH_STATUS_SUCCESS) { + break; + } } } } else { @@ -806,7 +810,7 @@ SWITCH_DECLARE(switch_status) switch_core_session_outgoing_channel(switch_core_s switch_caller_profile *profile = NULL, *peer_profile = NULL, *cloned_profile = NULL; switch_channel *channel = NULL, *peer_channel = NULL; - if ((channel = switch_core_session_get_channel(session)) != 0) { + if (session && (channel = switch_core_session_get_channel(session)) != 0) { profile = switch_channel_get_caller_profile(channel); } if ((peer_channel = switch_core_session_get_channel(*new_session)) != 0) { @@ -820,7 +824,7 @@ SWITCH_DECLARE(switch_status) switch_core_session_outgoing_channel(switch_core_s } } if (peer_profile) { - if ((cloned_profile = switch_caller_profile_clone(session, peer_profile)) != 0) { + if (session && (cloned_profile = switch_caller_profile_clone(session, peer_profile)) != 0) { switch_channel_set_originatee_caller_profile(channel, cloned_profile); } } @@ -1536,7 +1540,7 @@ SWITCH_DECLARE(switch_status) switch_core_new_memory_pool(switch_memory_pool **p return SWITCH_STATUS_MEMERR; } - if ((apr_pool_create(pool, runtime.memory_pool)) != APR_SUCCESS) { + if ((apr_pool_create(pool, runtime.memory_pool)) != SWITCH_STATUS_SUCCESS) { *pool = NULL; return SWITCH_STATUS_MEMERR; } @@ -1574,6 +1578,12 @@ static void switch_core_standard_on_ring(switch_core_session *session) switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Standard RING %s\n", switch_channel_get_name(session->channel)); + + if (switch_channel_test_flag(session->channel, CF_OUTBOUND)) { + switch_channel_set_state(session->channel, CS_TRANSMIT); + return; + } + if ((caller_profile = switch_channel_get_caller_profile(session->channel)) == 0) { switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't get profile!\n"); switch_channel_set_state(session->channel, CS_HANGUP); @@ -1656,6 +1666,11 @@ SWITCH_DECLARE(void) switch_core_session_signal_state_change(switch_core_session switch_thread_cond_signal(session->cond); } +SWITCH_DECLARE(unsigned int) switch_core_session_runing(switch_core_session *session) +{ + return session->thread_running; +} + SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) { switch_channel_state state = CS_NEW, laststate = CS_HANGUP, midstate = CS_DONE; @@ -1679,8 +1694,8 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) */ assert(session != NULL); - - + + session->thread_running = 1; endpoint_interface = session->endpoint_interface; assert(endpoint_interface != NULL); @@ -1943,7 +1958,7 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) switch_thread_cond_wait(session->cond, session->mutex); } } - + session->thread_running = 0; } SWITCH_DECLARE(void) switch_core_session_destroy(switch_core_session **session) @@ -2065,10 +2080,11 @@ SWITCH_DECLARE(void) switch_core_session_thread_launch(switch_core_session *sess switch_threadattr_create(&thd_attr, session->pool); switch_threadattr_detach_set(thd_attr, 1); - if (switch_thread_create(&thread, thd_attr, switch_core_session_thread, session, session->pool) != APR_SUCCESS) { - switch_core_session_destroy(&session); + if (! session->thread_running) { + if (switch_thread_create(&thread, thd_attr, switch_core_session_thread, session, session->pool) != SWITCH_STATUS_SUCCESS) { + switch_core_session_destroy(&session); + } } - } SWITCH_DECLARE(void) switch_core_session_launch_thread(switch_core_session *session, switch_thread_start_t func, @@ -2227,12 +2243,12 @@ SWITCH_DECLARE(switch_status) switch_core_init(char *console) } /* INIT APR and Create the pool context */ - if (apr_initialize() != APR_SUCCESS) { + if (apr_initialize() != SWITCH_STATUS_SUCCESS) { apr_terminate(); return SWITCH_STATUS_MEMERR; } - if (apr_pool_create(&runtime.memory_pool, NULL) != APR_SUCCESS) { + if (apr_pool_create(&runtime.memory_pool, NULL) != SWITCH_STATUS_SUCCESS) { switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Could not allocate memory pool\n"); switch_core_destroy(); return SWITCH_STATUS_MEMERR; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index a1c30f0e55..4a98b88746 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -50,7 +50,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_callback(switch_core_ses return SWITCH_STATUS_GENERR; } - while (switch_channel_get_state(channel) == CS_EXECUTE) { + while(switch_channel_ready(channel)) { switch_frame *read_frame; char dtmf[128]; @@ -105,7 +105,8 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio if (timeout) { started = switch_time_now(); } - while (switch_channel_get_state(channel) == CS_EXECUTE) { + + while(switch_channel_ready(channel)) { switch_frame *read_frame; if (timeout) { @@ -161,7 +162,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio switch_codec codec, *read_codec; char *codec_name; switch_status status = SWITCH_STATUS_SUCCESS; - + if (!fh) { fh = &lfh; } @@ -206,7 +207,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio } - while (switch_channel_get_state(channel) == CS_EXECUTE) { + while(switch_channel_ready(channel)) { size_t len; if (dtmf_callback || buf) { @@ -267,7 +268,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session, int stream_id; switch_status status = SWITCH_STATUS_SUCCESS; switch_file_handle lfh; - + if (!fh) { fh = &lfh; memset(fh, 0, sizeof(lfh)); @@ -332,7 +333,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session, } ilen = samples; - while (switch_channel_get_state(channel) == CS_EXECUTE) { + while(switch_channel_ready(channel)) { int done = 0; int do_speed = 1; int last_speed = -1; @@ -586,8 +587,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session } ilen = len; - while (switch_channel_get_state(channel) == CS_EXECUTE) { - + while(switch_channel_ready(channel)) { if (dtmf_callback || buf) { @@ -667,7 +667,6 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done speaking text\n"); switch_core_codec_destroy(&codec); flags = 0; - switch_core_codec_destroy(&codec); if (timer_name) { /* End the audio absorbing thread */ @@ -798,9 +797,11 @@ static switch_status audio_bridge_on_hangup(switch_core_session *session) 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); - + //switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL); + //switch_core_session_kill_channel(session, SWITCH_SIG_KILL); + if (switch_channel_test_flag(channel, CF_ORIGINATOR) && !switch_channel_test_flag(other_channel, CF_TRANSFER)) { + switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL); + } return SWITCH_STATUS_SUCCESS; } @@ -855,6 +856,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi switch_channel *caller_channel, *peer_channel; time_t start; int stream_id = 0; + switch_frame *read_frame; caller_channel = switch_core_session_get_channel(session); assert(caller_channel != NULL); @@ -895,12 +897,15 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi } time(&start); - while (switch_channel_get_state(caller_channel) == CS_EXECUTE && - switch_channel_get_state(peer_channel) == CS_TRANSMIT && + while (switch_channel_ready(caller_channel) && + switch_channel_ready(peer_channel) && !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_core_session_read_frame(session, &read_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) { + break; + } + switch_yield(1000); } if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) { @@ -913,7 +918,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi 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); + //switch_channel_hangup(peer_channel); if (other_audio_thread.running > 0) { other_audio_thread.running = -1; /* wait for the other audio thread */