diff --git a/libs/libdingaling/src/libdingaling.c b/libs/libdingaling/src/libdingaling.c index 9e8bb4762e..cbb95bbe83 100644 --- a/libs/libdingaling/src/libdingaling.c +++ b/libs/libdingaling/src/libdingaling.c @@ -190,6 +190,11 @@ char *ldl_session_get_id(ldl_session_t *session) return session->id; } +void ldl_session_send_msg(ldl_session_t *session, char *subject, char *body) +{ + ldl_handle_send_msg(session->handle, session->them, subject, body); +} + ldl_status ldl_session_destroy(ldl_session_t **session_p) { ldl_session_t *session = *session_p; @@ -277,7 +282,7 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, while(xml) { char *type = xtype ? xtype : iks_find_attrib(xml, "type"); iks *tag; - + if (type) { if (!strcasecmp(type, "initiate") || !strcasecmp(type, "accept")) { @@ -298,7 +303,7 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, if (!strcasecmp(iks_name(itag), "payload-type") && session->payload_len < LDL_MAX_PAYLOADS) { char *name = iks_find_attrib(itag, "name"); char *id = iks_find_attrib(itag, "id"); - char *rate = iks_find_attrib(itag, "rate"); + char *rate = iks_find_attrib(itag, "clockrate"); if (name && id) { session->payloads[session->payload_len].name = apr_pstrdup(session->pool, name); session->payloads[session->payload_len].id = atoi(id); @@ -317,10 +322,15 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, } tag = iks_next_tag(tag); } - } else if (!strcasecmp(type, "candidates")) { + } else if (!strcasecmp(type, "transport-info")) { + char *tid = iks_find_attrib(xml, "id"); signal = LDL_SIGNAL_CANDIDATES; tag = iks_child (xml); + if (tag && !strcasecmp(iks_name(tag), "transport")) { + tag = iks_child(tag); + } + while(tag) { if (!strcasecmp(iks_name(tag), "info_element")) { char *name = iks_find_attrib(tag, "name"); @@ -354,6 +364,11 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, } session->candidates[index].pref = pref; + + if (tid) { + session->candidates[index].tid = apr_pstrdup(session->pool, tid); + } + if ((key = iks_find_attrib(tag, "name"))) { session->candidates[index].name = apr_pstrdup(session->pool, key); } @@ -427,8 +442,8 @@ static int on_presence(void *user_data, ikspak *pak) struct ldl_buffer *buffer; size_t x; - iks *msg = iks_make_s10n (IKS_TYPE_SUBSCRIBED, from, "Ding A Ling...."); - apr_queue_push(handle->queue, msg); + //iks *msg = iks_make_s10n (IKS_TYPE_SUBSCRIBED, from, "Ding A Ling...."); + //apr_queue_push(handle->queue, msg); apr_cpystrn(id, from, sizeof(id)); @@ -1087,6 +1102,31 @@ void *ldl_session_get_private(ldl_session_t *session) return session->private_data; } +void ldl_session_accept_candidate(ldl_session_t *session, ldl_candidate_t *candidate) +{ + iks *iq, *sess, *tp; + unsigned int myid; + char idbuf[80]; + myid = next_id(); + snprintf(idbuf, sizeof(idbuf), "%u", myid); + + iq = iks_new("iq"); + iks_insert_attrib(iq, "type", "set"); + iks_insert_attrib(iq, "id", idbuf); + iks_insert_attrib(iq, "from", session->handle->login); + iks_insert_attrib(iq, "to", session->them); + sess = iks_insert (iq, "session"); + iks_insert_attrib(sess, "xmlns", "http://www.google.com/session"); + iks_insert_attrib(sess, "type", "transport-accept"); + iks_insert_attrib(sess, "id", candidate->tid); + iks_insert_attrib(sess, "xmlns", "http://www.google.com/session"); + iks_insert_attrib(sess, "initiator", session->initiator ? session->initiator : session->them); + tp = iks_insert (sess, "transport"); + iks_insert_attrib(tp, "xmlns", "http://www.google.com/transport/p2p"); + + apr_queue_push(session->handle->queue, iq); +} + void *ldl_handle_get_private(ldl_handle_t *handle) { return handle->private_info; @@ -1128,18 +1168,27 @@ unsigned int ldl_session_terminate(ldl_session_t *session) } + unsigned int ldl_session_candidates(ldl_session_t *session, - ldl_candidate_t *candidates, - unsigned int clen) + ldl_candidate_t *candidates, + unsigned int clen) { iks *iq, *sess, *tag; unsigned int x, id; - new_session_iq(session, &iq, &sess, &id, "candidates"); + for (x = 0; x < clen; x++) { char buf[512]; - tag = iks_insert(sess, "candidate"); + iq = NULL; + sess = NULL; + id = 0; + + new_session_iq(session, &iq, &sess, &id, "transport-info"); + tag = iks_insert(sess, "transport"); + iks_insert_attrib(tag, "xmlns", "http://www.google.com/transport/p2p"); + tag = iks_insert(tag, "candidate"); + if (candidates[x].name) { iks_insert_attrib(tag, "name", candidates[x].name); } @@ -1169,13 +1218,13 @@ unsigned int ldl_session_candidates(ldl_session_t *session, iks_insert_attrib(tag, "network", "0"); iks_insert_attrib(tag, "generation", "0"); + schedule_packet(session->handle, id, iq, LDL_RETRY); } - schedule_packet(session->handle, id, iq, LDL_RETRY); + return id; } - char *ldl_handle_probe(ldl_handle_t *handle, char *id, char *buf, unsigned int len) { iks *pres, *msg; @@ -1232,13 +1281,14 @@ unsigned int ldl_session_describe(ldl_session_t *session, unsigned int plen, ldl_description_t description) { - iks *iq, *sess, *tag, *payload; + iks *iq, *sess, *tag, *payload, *tp; unsigned int x, id; new_session_iq(session, &iq, &sess, &id, description == LDL_DESCRIPTION_ACCEPT ? "accept" : "initiate"); tag = iks_insert(sess, "description"); iks_insert_attrib(tag, "xmlns", "http://www.google.com/session/phone"); + iks_insert_attrib(tag, "xml:lang", "en"); for (x = 0; x < plen; x++) { char idbuf[80]; payload = iks_insert(tag, "payload-type"); @@ -1249,10 +1299,19 @@ unsigned int ldl_session_describe(ldl_session_t *session, iks_insert_attrib(payload, "name", payloads[x].name); if (payloads[x].rate) { sprintf(idbuf, "%d", payloads[x].rate); - iks_insert_attrib(payload, "rate", idbuf); + iks_insert_attrib(payload, "clockrate", idbuf); + } + if (payloads[x].bps) { + sprintf(idbuf, "%d", payloads[x].bps); + iks_insert_attrib(payload, "bitrate", idbuf); } } + if (description == LDL_DESCRIPTION_INITIATE) { + tp = iks_insert (sess, "transport"); + iks_insert_attrib(tp, "xmlns", "http://www.google.com/transport/p2p"); + } + schedule_packet(session->handle, id, iq, LDL_RETRY); return id; diff --git a/libs/libdingaling/src/libdingaling.h b/libs/libdingaling/src/libdingaling.h index 2261cabb4f..7c925c371e 100644 --- a/libs/libdingaling/src/libdingaling.h +++ b/libs/libdingaling/src/libdingaling.h @@ -53,6 +53,8 @@ extern "C" { /*! \brief A structure to store a jingle candidate */ struct ldl_candidate { + /*! the transport id of the candidate */ + char *tid; /*! the name of the candidate */ char *name; /*! the type of the candidate */ @@ -80,6 +82,8 @@ struct ldl_payload { unsigned int id; /*! the transfer rate of the payload type */ unsigned int rate; + /*! the bits per second of the payload type */ + unsigned int bps; }; typedef struct ldl_payload ldl_payload_t; @@ -286,6 +290,13 @@ void ldl_session_set_private(ldl_session_t *session, void *private_data); */ void *ldl_session_get_private(ldl_session_t *session); +/*! + \brief Accept a candidate + \param session the session to accept on + \param candidate the candidate to accept +*/ +void ldl_session_accept_candidate(ldl_session_t *session, ldl_candidate_t *candidate); + /*! \brief Set a custom logger \param logger the logger function @@ -316,6 +327,14 @@ unsigned int ldl_session_terminate(ldl_session_t *session); */ void *ldl_handle_get_private(ldl_handle_t *handle); +/*! + \brief Send a message to a session + \param session the session handle + \param to the message recipiant + \param subject optional subject + \param body body of the message +*/ +void ldl_session_send_msg(ldl_session_t *session, char *subject, char *body); /*! \brief Send a message diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 5639ca0768..b8df0906fb 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -443,6 +443,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_receive_message(switch_core_ */ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_event(switch_core_session_t *session, switch_event_t **event); + +/*! + \brief Indicate the number of waiting events on a session + \param session the session to check + \return the number of events +*/ +SWITCH_DECLARE(int32_t) switch_core_session_event_count(switch_core_session_t *session); + /*! \brief DE-Queue an event on a given session \param session the session to de-queue the message on diff --git a/src/include/switch_event.h b/src/include/switch_event.h index cd9678418f..a5a386cca4 100644 --- a/src/include/switch_event.h +++ b/src/include/switch_event.h @@ -155,6 +155,13 @@ SWITCH_DECLARE(switch_status_t) switch_event_set_priority(switch_event_t *event, */ SWITCH_DECLARE(char *) switch_event_get_header(switch_event_t *event, char *header_name); +/*! + \brief Retrieve the body value from an event + \param event the event to read the body from + \return the value of the body or NULL +*/ +SWITCH_DECLARE(char *) switch_event_get_body(switch_event_t *event); + /*! \brief Add a header to an event \param event the event to add the header to diff --git a/src/mod/codecs/mod_speex/mod_speex.c b/src/mod/codecs/mod_speex/mod_speex.c index 42ad6d5f83..815c1af298 100644 --- a/src/mod/codecs/mod_speex/mod_speex.c +++ b/src/mod/codecs/mod_speex/mod_speex.c @@ -271,7 +271,7 @@ static const switch_codec_implementation_t speex_32k_implementation = { /*.ianacode */ 102, /*.iananame */ "speex", /*.samples_per_second */ 32000, - /*.bits_per_second */ 512000, + /*.bits_per_second */ 256000, /*.nanoseconds_per_frame */ 20000, /*.samples_per_frame */ 640, /*.bytes_per_frame */ 1280, @@ -289,8 +289,8 @@ static const switch_codec_implementation_t speex_16k_implementation = { /*.codec_type */ SWITCH_CODEC_TYPE_AUDIO, /*.ianacode */ 100, /*.iananame */ "speex", - /*.samples_per_second */ 16000, - /*.bits_per_second */ 256000, + /*.samples_per_second */ 22000, + /*.bits_per_second */ 128000, /*.nanoseconds_per_frame */ 20000, /*.samples_per_frame */ 320, /*.bytes_per_frame */ 640, @@ -310,11 +310,11 @@ static const switch_codec_implementation_t speex_8k_implementation = { /*.ianacode */ 97, /*.iananame */ "speex", /*.samples_per_second */ 8000, - /*.bits_per_second */ 128000, + /*.bits_per_second */ 11000, /*.nanoseconds_per_frame */ 20000, /*.samples_per_frame */ 160, /*.bytes_per_frame */ 320, - /*.encoded_bytes_per_frame */ 0, + /*.encoded_bytes_per_frame */ 28, /*.number_of_channels */ 1, /*.pref_frames_per_packet */ 1, /*.max_frames_per_packet */ 1, diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index fa2bb2f384..14b5b6d077 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -134,6 +134,7 @@ struct private_object { uint32_t last_read; char *codec_name; switch_payload_t codec_num; + switch_payload_t r_codec_num; switch_time_t next_desc; switch_time_t next_cand; char *stun_ip; @@ -244,7 +245,7 @@ static int activate_rtp(struct private_object *tech_pvt) switch_rtp_flag_t flags; if (tech_pvt->rtp_session) { - return 0; + return 1; } if (!strncasecmp(tech_pvt->codec_name, "ilbc", 4)) { @@ -260,7 +261,7 @@ static int activate_rtp(struct private_object *tech_pvt) NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Can't load codec?\n"); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return -1; + return 0; } tech_pvt->read_frame.rate = tech_pvt->read_codec.implementation->samples_per_second; tech_pvt->read_frame.codec = &tech_pvt->read_codec; @@ -276,7 +277,7 @@ static int activate_rtp(struct private_object *tech_pvt) NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Can't load codec?\n"); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return -1; + return 0; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set Write Codec to %s\n", tech_pvt->codec_name); @@ -287,6 +288,7 @@ static int activate_rtp(struct private_object *tech_pvt) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SETUP RTP %s:%d -> %s:%d\n", tech_pvt->profile->ip, tech_pvt->local_port, tech_pvt->remote_ip, tech_pvt->remote_port); flags = SWITCH_RTP_FLAG_GOOGLEHACK | SWITCH_RTP_FLAG_AUTOADJ; + //flags = SWITCH_RTP_FLAG_AUTOADJ; if (switch_test_flag(tech_pvt->profile, TFLAG_TIMER)) { flags |= SWITCH_RTP_FLAG_USE_TIMER; @@ -304,7 +306,7 @@ static int activate_rtp(struct private_object *tech_pvt) &err, switch_core_session_get_pool(tech_pvt->session)))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP ERROR %s\n", err); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return -1; + return 0; } else { uint8_t vad_in = switch_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0; uint8_t vad_out = switch_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0; @@ -316,7 +318,7 @@ static int activate_rtp(struct private_object *tech_pvt) } } - return 0; + return 1; } @@ -444,18 +446,23 @@ static int do_describe(struct private_object *tech_pvt, int force) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Don't have my codec yet here's one\n"); tech_pvt->codec_name = lame(tech_pvt->codecs[0]->iananame); tech_pvt->codec_num = tech_pvt->codecs[0]->ianacode; + tech_pvt->r_codec_num = tech_pvt->codecs[0]->ianacode; tech_pvt->codec_index = 0; payloads[0].name = lame(tech_pvt->codecs[0]->iananame); payloads[0].id = tech_pvt->codecs[0]->ianacode; + payloads[0].rate = tech_pvt->codecs[0]->samples_per_second; + payloads[0].bps = tech_pvt->codecs[0]->bits_per_second; } else { payloads[0].name = lame(tech_pvt->codecs[tech_pvt->codec_index]->iananame); payloads[0].id = tech_pvt->codecs[tech_pvt->codec_index]->ianacode; + payloads[0].rate = tech_pvt->codecs[0]->samples_per_second; + payloads[0].bps = tech_pvt->codecs[0]->bits_per_second; } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send Describe [%s]\n", payloads[0].name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send Describe [%s@%d]\n", payloads[0].name, payloads[0].rate); tech_pvt->desc_id = ldl_session_describe(tech_pvt->dlsession, payloads, 1, switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ? LDL_DESCRIPTION_INITIATE : LDL_DESCRIPTION_ACCEPT); switch_set_flag_locked(tech_pvt, TFLAG_CODEC_READY); @@ -499,7 +506,7 @@ static void *SWITCH_THREAD_FUNC negotiate_thread_run(switch_thread_t *thread, vo elapsed = (unsigned int)((now - started) / 1000); if (switch_channel_get_state(channel) >= CS_HANGUP || switch_test_flag(tech_pvt, TFLAG_BYE)) { - return NULL; + goto out; } @@ -528,10 +535,12 @@ static void *SWITCH_THREAD_FUNC negotiate_thread_run(switch_thread_t *thread, vo } if (switch_channel_get_state(channel) >= CS_HANGUP || switch_test_flag(tech_pvt, TFLAG_BYE)) { - return NULL; + goto out; } - activate_rtp(tech_pvt); + if (!activate_rtp(tech_pvt)) { + goto out; + } if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { do_candidates(tech_pvt, 0); @@ -542,6 +551,13 @@ static void *SWITCH_THREAD_FUNC negotiate_thread_run(switch_thread_t *thread, vo } switch_channel_set_state(channel, CS_INIT); return NULL; + + out: + if (!switch_core_session_runing(tech_pvt->session)) { + channel_on_hangup(tech_pvt->session); + switch_core_session_destroy(&tech_pvt->session); + } + return NULL; } @@ -920,6 +936,33 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s return SWITCH_STATUS_SUCCESS; } + +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event) +{ + switch_channel_t *channel; + struct private_object *tech_pvt; + char *subject, *body; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + + if (!(body = switch_event_get_body(event))) { + body = ""; + } + + if (!(subject = switch_event_get_header(event, "subject"))) { + subject = "None"; + } + + ldl_session_send_msg(tech_pvt->dlsession, subject, body); + + return SWITCH_STATUS_SUCCESS; +} + static const switch_state_handler_table_t channel_event_handlers = { /*.on_init */ channel_on_init, /*.on_ring */ channel_on_ring, @@ -938,7 +981,8 @@ static const switch_io_routines_t channel_io_routines = { /*.waitfor_read */ channel_waitfor_read, /*.waitfor_write */ channel_waitfor_write, /*.send_dtmf */ channel_send_dtmf, - /*.receive_message*/ channel_receive_message + /*.receive_message*/ channel_receive_message, + /*.receive_event*/ channel_receive_event }; static const switch_endpoint_interface_t channel_endpoint_interface = { @@ -1531,7 +1575,9 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi if (*msg == '+') { switch_channel_queue_dtmf(channel, msg + 1); switch_set_flag_locked(tech_pvt, TFLAG_DTMF); - switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK); + if (tech_pvt->rtp_session) { + switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK); + } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SESSION MSG [%s]\n", msg); } @@ -1594,11 +1640,12 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi match = (payloads[x].id == tech_pvt->codecs[y]->ianacode) ? 1 : 0; } - if (match) { + if (match && payloads[x].rate == tech_pvt->codecs[y]->samples_per_second) { tech_pvt->codec_index = y; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing Payload index %u %s %u\n", y, payloads[x].name, payloads[x].id); tech_pvt->codec_name = tech_pvt->codecs[y]->iananame; tech_pvt->codec_num = tech_pvt->codecs[y]->ianacode; + tech_pvt->r_codec_num = payloads[x].id; if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { do_describe(tech_pvt, 0); } @@ -1663,7 +1710,9 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Acceptable Candidate %s:%d\n", candidates[x].address, candidates[x].port); - + if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + ldl_session_accept_candidate(dlsession, &candidates[x]); + } if (!(exten = ldl_session_get_value(dlsession, "dnis"))) { exten = profile->exten; @@ -1719,10 +1768,13 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi ldl_session_set_ip(dlsession, tech_pvt->remote_ip); tech_pvt->remote_port = candidates[x].port; tech_pvt->remote_user = switch_core_session_strdup(session, candidates[x].username); + if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { do_candidates(tech_pvt, 0); } + + switch_set_flag_locked(tech_pvt, TFLAG_TRANSPORT); return LDL_STATUS_SUCCESS; diff --git a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c index 72acdea955..6836691a6a 100644 --- a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c +++ b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c @@ -149,6 +149,262 @@ struct db_obj { }; +/* Event Object */ +/*********************************************************************************/ +static JSBool event_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if (argc > 0) { + switch_event_t *event; + switch_event_types_t etype; + char *ename = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + + if (switch_name_event(ename, &etype) != SWITCH_STATUS_SUCCESS) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + if (etype == SWITCH_EVENT_CUSTOM) { + char *subclass_name; + if (argc < 1) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + subclass_name = JS_GetStringBytes(JS_ValueToString(cx, argv[1])); + if (switch_event_create_subclass(&event, etype, subclass_name) != SWITCH_STATUS_SUCCESS) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + } else { + if (!switch_event_create(&event, etype) != SWITCH_STATUS_SUCCESS) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + } + + JS_SetPrivate(cx, obj, event); + return JS_TRUE; + } + + return JS_FALSE; +} + +static void event_destroy(JSContext *cx, JSObject *obj) +{ + switch_event_t *event = JS_GetPrivate(cx, obj); + + if (event) { + switch_event_destroy(&event); + } +} + +static JSBool event_add_header(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + switch_event_t *event = JS_GetPrivate(cx, obj); + + if (!event) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + if (argc > 1) { + char *hname = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + char *hval = JS_GetStringBytes(JS_ValueToString(cx, argv[1])); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, hname, hval); + *rval = BOOLEAN_TO_JSVAL( JS_TRUE ); + return JS_TRUE; + } + + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; +} + +static JSBool event_get_header(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + switch_event_t *event = JS_GetPrivate(cx, obj); + + if (!event) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + if (argc > 0) { + char *hname = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + char *val = switch_event_get_header(event, hname); + *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, val)); + return JS_TRUE; + } + + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; +} + +static JSBool event_add_body(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + switch_event_t *event = JS_GetPrivate(cx, obj); + + if (!event) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + if (argc > 0) { + char *body = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + switch_event_add_body(event, body); + *rval = BOOLEAN_TO_JSVAL( JS_TRUE ); + return JS_TRUE; + } + + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; +} + +static JSBool event_get_body(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + switch_event_t *event = JS_GetPrivate(cx, obj); + + if (!event) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, switch_event_get_body(event))); + + return JS_TRUE; +} + +static JSBool event_serialize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + switch_event_t *event = JS_GetPrivate(cx, obj); + char buf[1024]; + uint8_t isxml = 0; + + if (!event) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + if (argc > 0) { + char *arg = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + if (!strcasecmp(arg, "xml")) { + isxml++; + } + } + + if (isxml) { + switch_xml_t xml; + char *xmlstr; + if ((xml = switch_event_xmlize(event, NULL))) { + xmlstr = switch_xml_toxml(xml); + *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, xmlstr)); + switch_xml_free(xml); + free(xmlstr); + } else { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + } + } else { + switch_event_serialize(event, buf, sizeof(buf), NULL); + *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, buf)); + } + + return JS_TRUE; +} + +static JSBool event_fire(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + switch_event_t *event = JS_GetPrivate(cx, obj); + + if (event) { + switch_event_fire(&event); + JS_SetPrivate(cx, obj, NULL); + *rval = BOOLEAN_TO_JSVAL( JS_TRUE ); + return JS_TRUE; + } + + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; +} + +static JSBool event_destroy_(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + switch_event_t *event = JS_GetPrivate(cx, obj); + + if (event) { + switch_event_destroy(&event); + JS_SetPrivate(cx, obj, NULL); + *rval = BOOLEAN_TO_JSVAL( JS_TRUE ); + return JS_TRUE; + } + + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; +} + + + +enum event_tinyid { + EVENT_READY +}; + +static JSFunctionSpec event_methods[] = { + {"addHeader", event_add_header, 1}, + {"getHeader", event_get_header, 1}, + {"addBody", event_add_body, 1}, + {"getBody", event_get_body, 1}, + {"serialize", event_serialize, 0}, + {"fire", event_fire, 0}, + {"destroy", event_destroy_, 0}, + {0} +}; + + +static JSPropertySpec event_props[] = { + {"ready", EVENT_READY, JSPROP_READONLY|JSPROP_PERMANENT}, + {0} +}; + + +static JSBool event_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSBool res = JS_TRUE; + switch_event_t *event = JS_GetPrivate(cx, obj); + char *name; + int param = 0; + + if (!event) { + *vp = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + + name = JS_GetStringBytes(JS_ValueToString(cx, id)); + /* numbers are our props anything else is a method */ + if (name[0] >= 48 && name[0] <= 57) { + param = atoi(name); + } else { + return JS_TRUE; + } + + switch(param) { + case EVENT_READY: + *vp = BOOLEAN_TO_JSVAL( JS_TRUE ); + break; + } + + return res; +} + +JSClass event_class = { + "Event", JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, event_getProperty, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, event_destroy, NULL, NULL, NULL, + event_construct +}; + + + + static void js_error(JSContext *cx, const char *message, JSErrorReport *report) { if (message) { @@ -681,6 +937,52 @@ static JSBool session_execute(JSContext *cx, JSObject *obj, uintN argc, jsval *a return JS_TRUE; } +static JSBool session_get_event(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + struct js_session *jss = JS_GetPrivate(cx, obj); + switch_event_t *event; + + if (switch_core_session_dequeue_event(jss->session, &event) == SWITCH_STATUS_SUCCESS) { + JSObject *Event; + if ((Event = JS_DefineObject(cx, obj, "Event", &event_class, NULL, 0))) { + if ((JS_SetPrivate(cx, Event, event) && + JS_DefineProperties(cx, Event, event_props) && + JS_DefineFunctions(cx, Event, event_methods))) { + *rval = OBJECT_TO_JSVAL ( Event ); + return JS_TRUE; + } + } + } + + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + +} + +static JSBool session_send_event(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + struct js_session *jss = JS_GetPrivate(cx, obj); + switch_event_t *event; + JSObject *Event; + + if (argc > 0) { + if (JS_ValueToObject(cx, argv[0], &Event)) { + if ((event = JS_GetPrivate(cx, Event))) { + if (switch_core_session_receive_event(jss->session, &event) != SWITCH_STATUS_SUCCESS) { + *rval = BOOLEAN_TO_JSVAL( JS_FALSE ); + return JS_TRUE; + } + + JS_SetPrivate(cx, Event, NULL); + } + } + } + + *rval = BOOLEAN_TO_JSVAL( JS_TRUE ); + return JS_TRUE; + +} + static JSBool session_hangup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { @@ -845,6 +1147,7 @@ static JSBool js_fetchurl_file(JSContext *cx, JSObject *obj, uintN argc, jsval * } #endif + /* Session Object */ /*********************************************************************************/ enum session_tinyid { @@ -860,6 +1163,8 @@ static JSFunctionSpec session_methods[] = { {"answer", session_answer, 0}, {"ready", session_ready, 0}, {"waitForAnswer", session_wait_for_answer, 0}, + {"getEvent", session_get_event, 0}, + {"sendEvent", session_send_event, 0}, {"hangup", session_hangup, 0}, {"execute", session_execute, 0}, {0} @@ -2126,6 +2431,18 @@ static int env_init(JSContext *cx, JSObject *javascript_object) db_methods ); + JS_InitClass(cx, + javascript_object, + NULL, + &event_class, + event_construct, + 3, + event_props, + event_methods, + event_props, + event_methods + ); + return 1; } diff --git a/src/switch_core.c b/src/switch_core.c index b23d0681ea..6f9a1be7a9 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1174,6 +1174,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_event(switch_core_sess return status; } +SWITCH_DECLARE(int32_t) switch_core_session_event_count(switch_core_session_t *session) +{ + if (session->event_queue) { + return (int32_t) switch_queue_size(session->event_queue); + } + + return -1; +} + SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_event(switch_core_session_t *session, switch_event_t **event) { diff --git a/src/switch_event.c b/src/switch_event.c index 9db2fc9f0c..dc09b1ae66 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -393,6 +393,15 @@ SWITCH_DECLARE(char *) switch_event_get_header(switch_event_t *event, char *head return NULL; } +SWITCH_DECLARE(char *) switch_event_get_body(switch_event_t *event) +{ + if (event) { + return event->body; + } + + return NULL; +} + SWITCH_DECLARE(switch_status_t) switch_event_add_header(switch_event_t *event, switch_stack_t stack, char *header_name, char *fmt, ...) { @@ -623,7 +632,7 @@ SWITCH_DECLARE(switch_xml_t) switch_event_xmlize(switch_event_t *event, char *fm switch_xml_t xbody = NULL; add_xml_header(xml, "Content-Length", blena, off++); - if ((xbody = switch_xml_add_child_d(xml, "body", 0))) { + if ((xbody = switch_xml_add_child_d(xml, "body", off++))) { switch_xml_set_txt_d(xbody, body); } } diff --git a/src/switch_xml.c b/src/switch_xml.c index f18a55d28a..ae3c53f118 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -1012,7 +1012,7 @@ static char *switch_xml_toxml_r(switch_xml_t xml, char **s, switch_size_t *len, char *txt = (xml->parent) ? xml->parent->txt : ""; switch_size_t off = 0; uint32_t lcount = 0; - + // parent character content up to this tag *s = switch_xml_ampencode(txt + start, xml->off - start, s, len, max, 0); @@ -1045,11 +1045,13 @@ static char *switch_xml_toxml_r(switch_xml_t xml, char **s, switch_size_t *len, switch_xml_ampencode(attr[i][j + 1], 0, s, len, max, 1); *len += sprintf(*s + *len, "\""); } - *len += sprintf(*s + *len, xml->child ? ">\n" : "/>\n"); + + *len += sprintf(*s + *len, (xml->child || xml->txt) ? ">" : "/>\n"); if (xml->child) { (*count)++; *s = switch_xml_toxml_r(xml->child, s, len, max, 0, attr, count); + } else { *s = switch_xml_ampencode(xml->txt, 0, s, len, max, 0); //data } @@ -1058,10 +1060,10 @@ static char *switch_xml_toxml_r(switch_xml_t xml, char **s, switch_size_t *len, *s = realloc(*s, *max += SWITCH_XML_BUFSIZE); - if (xml->child) { - for (lcount = 0; lcount < *count; lcount++) { - *len += sprintf(*s + *len, "%s", XML_INDENT); // indent - } + if (xml->child || xml->txt) { + //for (lcount = 0; lcount < *count; lcount++) { + //*len += sprintf(*s + *len, "%s", XML_INDENT); // indent + //} *len += sprintf(*s + (*len), "\n", xml->name); // close tag }