diff --git a/conf/vanilla/autoload_configs/dingaling.conf.xml b/conf/vanilla/autoload_configs/dingaling.conf.xml index e68c8b4b44..dd6c9a5da1 100644 --- a/conf/vanilla/autoload_configs/dingaling.conf.xml +++ b/conf/vanilla/autoload_configs/dingaling.conf.xml @@ -1,7 +1,7 @@ - + diff --git a/conf/vanilla/jingle_profiles/client.xml b/conf/vanilla/jingle_profiles/client.xml index cac70692e8..20a8dd809d 100644 --- a/conf/vanilla/jingle_profiles/client.xml +++ b/conf/vanilla/jingle_profiles/client.xml @@ -28,5 +28,9 @@ + + + + diff --git a/libs/libdingaling/src/libdingaling.c b/libs/libdingaling/src/libdingaling.c index 0b11411ffd..e2b32a0637 100644 --- a/libs/libdingaling/src/libdingaling.c +++ b/libs/libdingaling/src/libdingaling.c @@ -27,8 +27,11 @@ * * libdingaling.c -- Main Library Code * + * QMOD: XMPP Video Signaling + Presentation (video-v1 & camera-v1) + * */ + #ifndef _MSC_VER #include #include @@ -157,8 +160,10 @@ struct ldl_session { char *login; ldl_payload_t payloads[LDL_MAX_PAYLOADS]; unsigned int payload_len; - ldl_candidate_t candidates[LDL_MAX_CANDIDATES]; - unsigned int candidate_len; + /*! \brief Transport candidates, organized per type */ + ldl_candidate_t candidates[LDL_TPORT_MAX][LDL_MAX_CANDIDATES]; + /*! \brief Length of the candidate list, per transport type */ + unsigned int candidate_len[LDL_TPORT_MAX]; apr_pool_t *pool; apr_hash_t *variables; apr_time_t created; @@ -181,6 +186,8 @@ typedef struct ldl_feature ldl_feature_t; #define FEATURE_VERSION "jabber:iq:version" #define FEATURE_VCARD "vcard-temp" #define FEATURE_VOICE "http://www.google.com/xmpp/protocol/voice/v1" +#define FEATURE_VIDEO "http://www.google.com/xmpp/protocol/video/v1" +#define FEATURE_CAMERA "http://www.google.com/xmpp/protocol/camera/v1" #define FEATURE_LAST "jabber:iq:last" static ldl_feature_t FEATURES[] = { @@ -189,6 +196,8 @@ static ldl_feature_t FEATURES[] = { { FEATURE_VERSION, on_disco_default }, { FEATURE_VCARD, on_vcard}, { FEATURE_VOICE, on_disco_default }, + { FEATURE_VIDEO, on_disco_default }, + { FEATURE_CAMERA, on_disco_default }, { FEATURE_LAST, on_disco_default }, { NULL, NULL} }; @@ -253,7 +262,6 @@ static unsigned int next_id(void) return globals.id++; } - static char *iks_name_nons(iks *x) { char *r = iks_name(x); @@ -296,7 +304,7 @@ ldl_status ldl_session_destroy(ldl_session_t **session_p) apr_hash_t *hash = session->handle->sessions; if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Destroyed Session %s\n", session->id); + globals.logger(DL_LOG_CRIT, "Destroyed Session %s\n", session->id); } if (session->id) { @@ -322,7 +330,7 @@ ldl_status ldl_session_create(ldl_session_t **session_p, ldl_handle_t *handle, c ldl_session_t *session = NULL; if (!(session = apr_palloc(handle->pool, sizeof(ldl_session_t)))) { - globals.logger(DL_LOG_DEBUG, "Memory ERROR!\n"); + globals.logger(DL_LOG_CRIT, "Memory ERROR!\n"); *session_p = NULL; return LDL_STATUS_MEMERR; } @@ -352,7 +360,7 @@ ldl_status ldl_session_create(ldl_session_t **session_p, ldl_handle_t *handle, c if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Created Session %s\n", id); + globals.logger(DL_LOG_CRIT, "Created Session %s\n", id); } return LDL_STATUS_SUCCESS; @@ -374,21 +382,22 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, if (!session) { if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Non-Existent Session %s!\n", id); + globals.logger(DL_LOG_CRIT, "Non-Existent Session %s!\n", id); } return LDL_STATUS_MEMERR; } if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Message for Session %s\n", id); + globals.logger(DL_LOG_CRIT, "Message for Session %s\n", id); } while(xml) { char *type = NULL; iks *tag; - if (iks_type(xml)!=IKS_CDATA) + if (iks_type(xml) != IKS_CDATA) { type = xtype ? xtype : iks_find_attrib(xml, "type"); + } if (type) { @@ -429,18 +438,28 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, char *name = iks_find_attrib(itag, "name"); char *id = iks_find_attrib(itag, "id"); char *rate = iks_find_attrib(itag, "clockrate"); + char *ptime = iks_find_attrib(itag, "ptime"); if (name && id) { session->payloads[session->payload_len].name = apr_pstrdup(session->pool, name); session->payloads[session->payload_len].id = atoi(id); + if (ptime) { + session->payloads[session->payload_len].ptime = atoi(ptime); + } else { + session->payloads[session->payload_len].ptime = 20; + } if (rate) { session->payloads[session->payload_len].rate = atoi(rate); } else { - session->payloads[session->payload_len].rate = 8000; + if (!strncasecmp(iks_name(itag), "vid", 3)) { + session->payloads[session->payload_len].rate = 90000; + } else { + session->payloads[session->payload_len].rate = 8000; + } } session->payload_len++; if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Add Payload [%s] id='%s'\n", name, id); + globals.logger(DL_LOG_CRIT, "Add Payload [%s] id='%s'\n", name, id); } } } @@ -462,27 +481,46 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, tag = iks_child(tag); } - while(tag) { + for (;tag;tag = iks_next_tag(tag)) { if (!strcasecmp(iks_name_nons(tag), "info_element")) { char *name = iks_find_attrib(tag, "name"); char *value = iks_find_attrib(tag, "value"); if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Info Element [%s]=[%s]\n", name, value); + globals.logger(DL_LOG_CRIT, "Info Element [%s]=[%s]\n", name, value); } ldl_session_set_value(session, name, value); - } else if (!strcasecmp(iks_name_nons(tag), "candidate") && session->candidate_len < LDL_MAX_CANDIDATES) { + } else if (!strcasecmp(iks_name_nons(tag), "candidate") /*&& session->candidate_len < LDL_MAX_CANDIDATES*/) { char *key; double pref = 0.0; int index = -1; + ldl_transport_type_t tport; + unsigned int *candidate_len = NULL; + ldl_candidate_t (*candidates)[LDL_MAX_CANDIDATES] = NULL; + if ((key = iks_find_attrib(tag, "preference"))) { unsigned int x; + pref = strtod(key, NULL); - for (x = 0; x < session->candidate_len; x++) { - if (session->candidates[x].pref == pref) { + /* Check what kind of candidate this is */ + if ((key = iks_find_attrib(tag, "name")) && ((tport = ldl_transport_type_parse(key)) != LDL_TPORT_MAX)) { + candidates = &(session->candidates[tport]); + candidate_len = &(session->candidate_len[tport]); + } else { + globals.logger(DL_LOG_WARNING, "No such transport type: %s\n", key); + continue; + } + + if (*candidate_len >= LDL_MAX_CANDIDATES) { + globals.logger(DL_LOG_WARNING, "Too many %s candidates\n", key); + continue; + } + + for (x = 0; x < *candidate_len; x++) { + if ((*candidates)[x].pref == pref) { if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Duplicate Pref!\n"); + globals.logger(DL_LOG_CRIT, "Duplicate Pref! Updating...\n"); } index = x; break; @@ -491,44 +529,44 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, } if (index < 0) { - index = session->candidate_len++; + index = (*candidate_len)++; } - session->candidates[index].pref = pref; + (*candidates)[index].pref = pref; if (tid) { - session->candidates[index].tid = apr_pstrdup(session->pool, tid); + (*candidates)[index].tid = apr_pstrdup(session->pool, tid); } if ((key = iks_find_attrib(tag, "name"))) { - session->candidates[index].name = apr_pstrdup(session->pool, key); + (*candidates)[index].name = apr_pstrdup(session->pool, key); } if ((key = iks_find_attrib(tag, "type"))) { - session->candidates[index].type = apr_pstrdup(session->pool, key); + (*candidates)[index].type = apr_pstrdup(session->pool, key); } if ((key = iks_find_attrib(tag, "protocol"))) { - session->candidates[index].protocol = apr_pstrdup(session->pool, key); + (*candidates)[index].protocol = apr_pstrdup(session->pool, key); } if ((key = iks_find_attrib(tag, "username"))) { - session->candidates[index].username = apr_pstrdup(session->pool, key); + (*candidates)[index].username = apr_pstrdup(session->pool, key); } if ((key = iks_find_attrib(tag, "password"))) { - session->candidates[index].password = apr_pstrdup(session->pool, key); + (*candidates)[index].password = apr_pstrdup(session->pool, key); } if ((key = iks_find_attrib(tag, "address"))) { - session->candidates[index].address = apr_pstrdup(session->pool, key); + (*candidates)[index].address = apr_pstrdup(session->pool, key); } if ((key = iks_find_attrib(tag, "port"))) { - session->candidates[index].port = (uint16_t)atoi(key); + (*candidates)[index].port = (uint16_t)atoi(key); } - if (!session->candidates[index].type) { - session->candidates[index].type = apr_pstrdup(session->pool, "stun"); + if (!(*candidates)[index].type) { + (*candidates)[index].type = apr_pstrdup(session->pool, "stun"); } if (globals.debug) { - globals.logger(DL_LOG_DEBUG, + globals.logger(DL_LOG_CRIT, "New Candidate %d\n" "name=%s\n" "type=%s\n" @@ -538,19 +576,18 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, "address=%s\n" "port=%d\n" "pref=%0.2f\n", - session->candidate_len, - session->candidates[index].name, - session->candidates[index].type, - session->candidates[index].protocol, - session->candidates[index].username, - session->candidates[index].password, - session->candidates[index].address, - session->candidates[index].port, - session->candidates[index].pref + *candidate_len, + (*candidates)[index].name, + (*candidates)[index].type, + (*candidates)[index].protocol, + (*candidates)[index].username, + (*candidates)[index].password, + (*candidates)[index].address, + (*candidates)[index].port, + (*candidates)[index].pref ); } } - tag = iks_next_tag(tag); } } else if (!strcasecmp(type, "terminate")) { dl_signal = LDL_SIGNAL_TERMINATE; @@ -569,6 +606,301 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, return LDL_STATUS_SUCCESS; } + +static ldl_status parse_jingle_code(ldl_handle_t *handle, iks *xml, char *to, char *from, char *type) +{ + ldl_session_t *session = NULL; + ldl_signal_t dl_signal = LDL_SIGNAL_NONE; + char *initiator = iks_find_attrib(xml, "initiator"); + char *msg = NULL; + char *id = iks_find_attrib(xml, "sid"); + char *action = iks_find_attrib(xml, "action"); + iks *tag; + + + if (!strcasecmp(type, "error")) { + action = type; + } + + + if (!(id && action)) { + globals.logger(DL_LOG_CRIT, "missing required params\n"); + return LDL_STATUS_FALSE; + } + + if (!(session = apr_hash_get(handle->sessions, id, APR_HASH_KEY_STRING))) { + ldl_session_create(&session, handle, id, from, to, LDL_FLAG_NONE); + if (!session) { + return LDL_STATUS_MEMERR; + } + } + + if (!session) { + if (globals.debug) { + globals.logger(DL_LOG_CRIT, "Non-Existent Session %s!\n", id); + } + return LDL_STATUS_MEMERR; + } + + if (globals.debug) { + globals.logger(DL_LOG_CRIT, "Message for Session %s\n", id); + } + + + if (action) { + + if (!strcasecmp(action, "redirect")) { + apr_hash_t *hash = session->handle->sessions; + char *p = to; + if ((p = strchr(to, ':'))) { + p++; + } else { + p = to; + } + + + apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL); + apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL); + session->them = apr_pstrdup(session->pool, p); + apr_hash_set(handle->sessions, session->them, APR_HASH_KEY_STRING, session); + apr_hash_set(handle->sessions, session->id, APR_HASH_KEY_STRING, session); + + dl_signal = LDL_SIGNAL_REDIRECT; + } else if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "session-accept")) { + + dl_signal = LDL_SIGNAL_INITIATE; + + if (!strcasecmp(action, "session-accept")) { + msg = "accept"; + } + + if (!session->initiator && initiator) { + session->initiator = apr_pstrdup(session->pool, initiator); + } + tag = iks_child (xml); + + while(tag) { + + if (!strcasecmp(iks_name_nons(tag), "content")) { + iks *dtag = iks_child (tag); + char key[512]; + + if (!strcasecmp(iks_name_nons(dtag), "description")) { + iks *itag = iks_child (dtag); + char *name = iks_find_attrib(tag, "name"); + char *media = iks_find_attrib(dtag, "media"); + + if (globals.debug) { + globals.logger(DL_LOG_CRIT, "Found description of type '%s' media type '%s'\n", name, media); + + } + + while(itag) { + if (!strcasecmp(iks_name_nons(itag), "rtcp-mux")) { + snprintf(key, sizeof(key), "%s:rtcp-mux", media); + ldl_session_set_value(session, key, "true"); + } + + if (!strcasecmp(iks_name_nons(itag), "encryption")) { + iks *etag = iks_child (itag); + + while(etag) { + char *suite = iks_find_attrib(etag, "crypto-suite"); + char *params = iks_find_attrib(etag, "key-params"); + char *tag = iks_find_attrib(etag, "tag"); + char val[512]; + + if (suite && params && tag) { + snprintf(key, sizeof(key), "%s:crypto:%s", media, tag); + snprintf(val, sizeof(val), "%s %s %s", tag, suite, params); + + ldl_session_set_value(session, key, val); + } + + etag = iks_next_tag(etag); + } + } + + + if (!strcasecmp(iks_name_nons(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, "clockrate"); + + if (name && id) { + session->payloads[session->payload_len].name = apr_pstrdup(session->pool, name); + session->payloads[session->payload_len].id = atoi(id); + if (rate) { + session->payloads[session->payload_len].rate = atoi(rate); + } else { + if (!strcasecmp(media, "video")) { + session->payloads[session->payload_len].rate = 90000; + } else { + session->payloads[session->payload_len].rate = 8000; + } + } + session->payload_len++; + + if (globals.debug) { + globals.logger(DL_LOG_CRIT, "Add Payload [%s] id='%s'\n", name, id); + } + } + } + itag = iks_next_tag(itag); + } + + } + } + + tag = iks_next_tag(tag); + } + } else if (!strcasecmp(action, "transport-accept")) { + dl_signal = LDL_SIGNAL_TRANSPORT_ACCEPT; + } else if (!strcasecmp(action, "reject")) { + dl_signal = LDL_SIGNAL_REJECT; + } else if (!strcasecmp(action, "transport-info")) { + + tag = iks_child (xml); + + while(tag) { + + if (!strcasecmp(iks_name_nons(tag), "content")) { + iks *ttag = iks_child (tag); + + dl_signal = LDL_SIGNAL_CANDIDATES; + + id = action; + + if (ttag && !strcasecmp(iks_name_nons(ttag), "transport")) { + ttag = iks_child(ttag); + } + + for (;ttag;ttag = iks_next_tag(ttag)) { + if (!strcasecmp(iks_name_nons(ttag), "info_element")) { + char *name = iks_find_attrib(ttag, "name"); + char *value = iks_find_attrib(ttag, "value"); + if (globals.debug) { + globals.logger(DL_LOG_CRIT, "Info Element [%s]=[%s]\n", name, value); + } + ldl_session_set_value(session, name, value); + + } else if (!strcasecmp(iks_name_nons(ttag), "candidate")) { + char *key; + double pref = 0.0; + int index = -1; + ldl_transport_type_t tport; + unsigned int *candidate_len = NULL; + ldl_candidate_t (*candidates)[LDL_MAX_CANDIDATES] = NULL; + + if ((key = iks_find_attrib(ttag, "preference"))) { + unsigned int x; + + pref = strtod(key, NULL); + + /* Check what kind of candidate this is */ + if ((key = iks_find_attrib(ttag, "name")) && ((tport = ldl_transport_type_parse(key)) != LDL_TPORT_MAX)) { + candidates = &(session->candidates[tport]); + candidate_len = &(session->candidate_len[tport]); + } else { + globals.logger(DL_LOG_WARNING, "No such transport type: %s\n", key); + continue; + } + + if (*candidate_len >= LDL_MAX_CANDIDATES) { + globals.logger(DL_LOG_WARNING, "Too many %s candidates\n", key); + continue; + } + + for (x = 0; x < *candidate_len; x++) { + if ((*candidates)[x].pref == pref) { + if (globals.debug) { + globals.logger(DL_LOG_CRIT, "Duplicate Pref!\n"); + } + index = x; + break; + } + } + } + + if (index < 0) { + index = (*candidate_len)++; + } + + (*candidates)[index].pref = pref; + + if ((key = iks_find_attrib(ttag, "name"))) { + (*candidates)[index].name = apr_pstrdup(session->pool, key); + } + if ((key = iks_find_attrib(ttag, "type"))) { + (*candidates)[index].type = apr_pstrdup(session->pool, key); + } + if ((key = iks_find_attrib(ttag, "protocol"))) { + (*candidates)[index].protocol = apr_pstrdup(session->pool, key); + } + if ((key = iks_find_attrib(ttag, "username"))) { + (*candidates)[index].username = apr_pstrdup(session->pool, key); + } + if ((key = iks_find_attrib(ttag, "password"))) { + (*candidates)[index].password = apr_pstrdup(session->pool, key); + } + if ((key = iks_find_attrib(ttag, "address"))) { + (*candidates)[index].address = apr_pstrdup(session->pool, key); + } + if ((key = iks_find_attrib(ttag, "port"))) { + (*candidates)[index].port = (uint16_t)atoi(key); + } + + if (!(*candidates)[index].type) { + (*candidates)[index].type = apr_pstrdup(session->pool, "stun"); + } + + + if (globals.debug) { + globals.logger(DL_LOG_CRIT, + "New Candidate %d\n" + "name=%s\n" + "type=%s\n" + "protocol=%s\n" + "username=%s\n" + "password=%s\n" + "address=%s\n" + "port=%d\n" + "pref=%0.2f\n", + *candidate_len, + (*candidates)[index].name, + (*candidates)[index].type, + (*candidates)[index].protocol, + (*candidates)[index].username, + (*candidates)[index].password, + (*candidates)[index].address, + (*candidates)[index].port, + (*candidates)[index].pref + ); + } + } + } + } + + tag = iks_next_tag(tag); + } + } else if (!strcasecmp(action, "session-terminate")) { + dl_signal = LDL_SIGNAL_TERMINATE; + } else if (!strcasecmp(action, "error")) { + dl_signal = LDL_SIGNAL_ERROR; + } + } + + + + if (handle->session_callback && dl_signal) { + handle->session_callback(handle, session, dl_signal, to, from, id, msg); + } + + return LDL_STATUS_SUCCESS; +} + + + const char *marker = "TRUE"; @@ -601,12 +933,12 @@ static int on_disco_default(void *user_data, ikspak *pak) } if (pak->subtype == IKS_TYPE_RESULT) { - globals.logger(DL_LOG_DEBUG, "FixME!!! node=[%s]\n", node?node:""); + globals.logger(DL_LOG_CRIT, "FixME!!! node=[%s]\n", node?node:""); } else if (pak->subtype == IKS_TYPE_GET) { if ((iq = iks_new("iq"))) { int all = 0; - iks_insert_attrib(iq, "from", iks_find_attrib(pak->x, "to")); + iks_insert_attrib(iq, "from", handle->login); if (pak->from) { iks_insert_attrib(iq, "to", pak->from->full); } @@ -673,7 +1005,7 @@ static int on_disco_default(void *user_data, ikspak *pak) } if (!send) { - globals.logger(DL_LOG_DEBUG, "Memory Error!\n"); + globals.logger(DL_LOG_CRIT, "Memory Error!\n"); } } @@ -838,12 +1170,12 @@ static void do_presence(ldl_handle_t *handle, char *from, char *to, char *type, char buf[512]; iks *tag; - if (from && !strchr(from, '/')) { + if (!strchr(from, '/')) { snprintf(buf, sizeof(buf), "%s/talk", from); from = buf; } - if (ldl_test_flag(handle, LDL_FLAG_COMPONENT) && from && to && ldl_jid_domcmp(from, to)) { + if (ldl_test_flag(handle, LDL_FLAG_COMPONENT) && ldl_jid_domcmp(from, to)) { globals.logger(DL_LOG_ERR, "Refusal to send presence from and to the same domain in component mode [%s][%s]\n", from, to); return; } @@ -890,7 +1222,7 @@ static void do_presence(ldl_handle_t *handle, char *from, char *to, char *type, if ((tag = iks_insert(pres, "c"))) { iks_insert_attrib(tag, "node", "http://www.freeswitch.org/xmpp/client/caps"); iks_insert_attrib(tag, "ver", LDL_CAPS_VER); - iks_insert_attrib(tag, "ext", "sidebar voice-v1"); + iks_insert_attrib(tag, "ext", "sidebar voice-v1 video-v1 camera-v1"); iks_insert_attrib(tag, "client", "libdingaling"); iks_insert_attrib(tag, "xmlns", "http://jabber.org/protocol/caps"); } @@ -970,7 +1302,7 @@ static void cancel_retry(ldl_handle_t *handle, char *id) apr_thread_mutex_lock(handle->lock); if ((packet_node = apr_hash_get(handle->retry_hash, id, APR_HASH_KEY_STRING))) { if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Cancel packet %s\n", packet_node->id); + globals.logger(DL_LOG_CRIT, "Cancel packet %s\n", packet_node->id); } packet_node->retries = 0; } @@ -989,6 +1321,30 @@ static iks* working_find(iks *tag, const char *name) return NULL; } +static iks* working_find_nons(iks *tag, const char *name) +{ + while(tag) { + char *a = iks_name(tag); + char *b = (char *)name; + char *p; + + if ((p = strchr(a, ':'))) { + a = p+1; + } + + if ((p = strchr(b, ':'))) { + b = p+1; + } + + if (!strcasecmp(a,b)) { + return tag; + } + tag = iks_next_tag(tag); + } + + return NULL; +} + static int on_commands(void *user_data, ikspak *pak) { ldl_handle_t *handle = user_data; @@ -999,6 +1355,8 @@ static int on_commands(void *user_data, ikspak *pak) uint8_t is_result = strcasecmp(type, "result") ? 0 : 1; uint8_t is_error = strcasecmp(type, "error") ? 0 : 1; iks *xml, *xsession, *xerror = NULL, *xredir = NULL; + iks *xjingle; + xml = iks_child (pak->x); @@ -1062,8 +1420,21 @@ static int on_commands(void *user_data, ikspak *pak) } } - - if ((xsession = working_find(xml, "ses:session")) || (xsession = working_find(xml, "session"))) { + + + if ((handle->flags & LDL_FLAG_JINGLE) && (xjingle = working_find_nons(xml, "jin:jingle"))) { + if (parse_jingle_code(handle, xjingle, to, from, type) == LDL_STATUS_SUCCESS) { + iks *reply; + if ((reply = iks_make_iq(IKS_TYPE_RESULT, NULL))) { + iks_insert_attrib(reply, "to", from); + iks_insert_attrib(reply, "from", to); + iks_insert_attrib(reply, "id", iqid); + apr_queue_push(handle->queue, reply); + reply = NULL; + } + } + + } else if ((xsession = working_find_nons(xml, "ses:session"))) { char *id; id = iks_find_attrib(xsession, "id"); @@ -1102,7 +1473,7 @@ static int on_result(void *user_data, ikspak *pak) ctag = iks_insert(msg, "c"); iks_insert_attrib(ctag, "node", "http://www.freeswitch.org/xmpp/client/caps"); iks_insert_attrib(ctag, "ver", "1.0.0.1"); - iks_insert_attrib(ctag, "ext", "sidebar voice-v1"); + iks_insert_attrib(ctag, "ext", "sidebar voice-v1 video-v1"); iks_insert_attrib(ctag, "client", "libdingaling"); iks_insert_attrib(ctag, "xmlns", "http://jabber.org/protocol/caps"); @@ -1239,7 +1610,7 @@ static int on_stream(ldl_handle_t *handle, int type, iks *node) if (iks_has_tls()) { iks_start_tls(handle->parser); } else { - globals.logger(DL_LOG_DEBUG, "TLS NOT SUPPORTED IN THIS BUILD!\n"); + globals.logger(DL_LOG_WARNING, "TLS NOT SUPPORTED IN THIS BUILD!\n"); } } break; @@ -1284,19 +1655,19 @@ static int on_stream(ldl_handle_t *handle, int type, iks *node) apr_queue_push(handle->queue, x); x = NULL; } else { - globals.logger(DL_LOG_DEBUG, "Memory ERROR!\n"); + globals.logger(DL_LOG_CRIT, "Memory ERROR!\n"); break; } } } } else if (node && strcmp("failure", iks_name_nons(node)) == 0) { - globals.logger(DL_LOG_DEBUG, "sasl authentication failed\n"); + globals.logger(DL_LOG_CRIT, "sasl authentication failed\n"); if (handle->session_callback) { handle->session_callback(handle, NULL, LDL_SIGNAL_LOGIN_FAILURE, "user", "core", "Login Failure", handle->login); } } else if (node && strcmp("success", iks_name_nons(node)) == 0) { - globals.logger(DL_LOG_DEBUG, "XMPP server connected\n"); + globals.logger(DL_LOG_NOTICE, "XMPP server connected\n"); iks_send_header(handle->parser, handle->acc->server); ldl_set_flag_locked(handle, LDL_FLAG_CONNECTED); if (handle->session_callback) { @@ -1308,7 +1679,7 @@ static int on_stream(ldl_handle_t *handle, int type, iks *node) if (handle->session_callback) { handle->session_callback(handle, NULL, LDL_SIGNAL_LOGIN_SUCCESS, "user", "core", "Login Success", handle->login); } - globals.logger(DL_LOG_DEBUG, "XMPP authenticated\n"); + globals.logger(DL_LOG_NOTICE, "XMPP authenticated\n"); ldl_set_flag_locked(handle, LDL_FLAG_AUTHORIZED); } if (node) { @@ -1360,18 +1731,20 @@ static int on_msg(void *user_data, ikspak *pak) static int on_error(void *user_data, ikspak * pak) { - globals.logger(DL_LOG_DEBUG, "authorization failed\n"); + globals.logger(DL_LOG_ERR, "authorization failed\n"); return IKS_FILTER_EAT; } static void on_log(ldl_handle_t *handle, const char *data, size_t size, int is_incoming) { + if (globals.debug) { if (is_incoming) { globals.logger(DL_LOG_INFO, "+xml:%s%s:%s", iks_is_secure(handle->parser) ? "Sec" : "", is_incoming ? "RECV" : "SEND", data); } else { globals.logger(DL_LOG_NOTICE, "+xml:%s%s:%s", iks_is_secure(handle->parser) ? "Sec" : "", is_incoming ? "RECV" : "SEND", data); } + } } @@ -1443,11 +1816,7 @@ static ldl_queue_t ldl_flush_queue(ldl_handle_t *handle, int done) while(apr_queue_trypop(handle->queue, &pop) == APR_SUCCESS) { if (pop) { msg = (iks *) pop; - if (!done) { - if (iks_send(handle->parser, msg) != IKS_OK) { - globals.logger(DL_LOG_DEBUG, "Failed sending data!\n"); - }; - }; + if (!done) iks_send(handle->parser, msg); iks_delete(msg); pop = NULL; sent_data = LDL_QUEUE_SENT; @@ -1458,7 +1827,7 @@ static ldl_queue_t ldl_flush_queue(ldl_handle_t *handle, int done) len = apr_queue_size(handle->retry_queue); if (globals.debug && len) { - globals.logger(DL_LOG_DEBUG, "Processing %u packets in retry queue\n", len); + globals.logger(DL_LOG_CRIT, "Processing %u packets in retry queue\n", len); } pop = NULL; @@ -1475,18 +1844,16 @@ static ldl_queue_t ldl_flush_queue(ldl_handle_t *handle, int done) if (packet_node->retries > 0) { packet_node->retries--; if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Sending packet %s (%d left)\n", packet_node->id, packet_node->retries); + globals.logger(DL_LOG_CRIT, "Sending packet %s (%d left)\n", packet_node->id, packet_node->retries); } - if (iks_send(handle->parser, packet_node->xml) != IKS_OK) { - globals.logger(DL_LOG_DEBUG, "Failed trying re-sending data!\n"); - }; + iks_send(handle->parser, packet_node->xml); packet_node->next = now + 5000000; sent_data = LDL_QUEUE_SENT; } } if (packet_node->retries == 0 || done) { if (globals.debug) { - globals.logger(DL_LOG_DEBUG, "Discarding packet %s\n", packet_node->id); + globals.logger(DL_LOG_CRIT, "Discarding packet %s\n", packet_node->id); } apr_hash_set(handle->retry_hash, packet_node->id, APR_HASH_KEY_STRING, NULL); iks_delete(packet_node->xml); @@ -1505,8 +1872,8 @@ static ldl_queue_t ldl_flush_queue(ldl_handle_t *handle, int done) static void xmpp_connect(ldl_handle_t *handle, char *jabber_id, char *pass) { - int count_ka = LDL_KEEPALIVE_TIMEOUT; - time_t tstart, tnow; + int timeout_ka = LDL_KEEPALIVE_TIMEOUT; + int count_ka = timeout_ka; while (ldl_test_flag((&globals), LDL_FLAG_READY) && ldl_test_flag(handle, LDL_FLAG_RUNNING)) { int e; @@ -1537,8 +1904,6 @@ static void xmpp_connect(ldl_handle_t *handle, char *jabber_id, char *pass) j_setup_filter(handle); - globals.logger(DL_LOG_DEBUG, "xmpp connecting\n"); - e = iks_connect_via(handle->parser, handle->server ? handle->server : handle->acc->server, handle->port ? handle->port : IKS_JABBER_PORT, @@ -1548,27 +1913,31 @@ static void xmpp_connect(ldl_handle_t *handle, char *jabber_id, char *pass) case IKS_OK: break; case IKS_NET_NODNS: - globals.logger(DL_LOG_DEBUG, "hostname lookup failed\n"); + globals.logger(DL_LOG_CRIT, "hostname lookup failed\n"); microsleep(1000); goto fail; case IKS_NET_NOCONN: - globals.logger(DL_LOG_DEBUG, "connection failed\n"); + globals.logger(DL_LOG_CRIT, "connection failed\n"); microsleep(1000); goto fail; default: - globals.logger(DL_LOG_DEBUG, "io error 1 %d\n", e); + globals.logger(DL_LOG_CRIT, "io error 1 %d\n", e); microsleep(1000); goto fail; } handle->counter = opt_timeout; - if ((tstart = time(NULL)) == -1) { - globals.logger(DL_LOG_DEBUG, "error determining connection time"); - } while (ldl_test_flag((&globals), LDL_FLAG_READY) && ldl_test_flag(handle, LDL_FLAG_RUNNING)) { e = iks_recv(handle->parser, 1); + if (count_ka-- <= 0) { + if( iks_send_raw(handle->parser, " ") == IKS_OK) { + count_ka = timeout_ka; + globals.logger(DL_LOG_DEBUG, "Sent keep alive signal\n"); + } + } + if (handle->loop_callback) { if (handle->loop_callback(handle) != LDL_STATUS_SUCCESS) { ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING); @@ -1585,51 +1954,31 @@ static void xmpp_connect(ldl_handle_t *handle, char *jabber_id, char *pass) } if (IKS_OK != e || ldl_test_flag(handle, LDL_FLAG_BREAK)) { - globals.logger(DL_LOG_DEBUG, "io error 2 %d retry in %d second(s)", e, ++handle->fail_count); - if ((tnow = time(NULL)) == -1) { - globals.logger(DL_LOG_DEBUG, "error deterniming io error time"); - } - if (difftime(tnow, tstart) > 30) { - /* this is a new error situation: reset counter */ - globals.logger(DL_LOG_DEBUG, "resetting fail count"); - handle->fail_count = 1; - } + globals.logger(DL_LOG_DEBUG, "io error 2 %d retry in %d second(s)\n", e, ++handle->fail_count); microsleep(1000 * handle->fail_count); goto fail; } if (ldl_test_flag(handle, LDL_FLAG_RUNNING)) { - if (ldl_flush_queue(handle, 0) == LDL_QUEUE_SENT) { - count_ka = LDL_KEEPALIVE_TIMEOUT; - } - } + ldl_flush_queue(handle, 0); + } handle->counter--; if (!ldl_test_flag(handle, LDL_FLAG_CONNECTED)) { if (IKS_NET_TLSFAIL == e) { - globals.logger(DL_LOG_DEBUG, "tls handshake failed\n"); + globals.logger(DL_LOG_CRIT, "tls handshake failed\n"); microsleep(500); break; } if (handle->counter == 0) { - globals.logger(DL_LOG_DEBUG, "network timeout\n"); - microsleep(500); - break; - } - } - - if (count_ka-- <= 0) { - if( iks_send_raw(handle->parser, " ") == IKS_OK) { - globals.logger(DL_LOG_DEBUG, "Sent keep alive signal"); - count_ka = LDL_KEEPALIVE_TIMEOUT; - } else { - globals.logger(DL_LOG_DEBUG, "Failed sending keep alive signal"); + globals.logger(DL_LOG_CRIT, "network timeout\n"); microsleep(500); break; } } + microsleep(100); } fail: @@ -1657,7 +2006,7 @@ static void xmpp_connect(ldl_handle_t *handle, char *jabber_id, char *pass) static void add_elements(ldl_session_t *session, iks *tag) { apr_hash_index_t *hi; - + return; for (hi = apr_hash_first(session->pool, session->variables); hi; hi = apr_hash_next(hi)) { void *val = NULL; const void *key = NULL; @@ -1672,6 +2021,42 @@ static void add_elements(ldl_session_t *session, iks *tag) } } + +static iks *ldl_set_jingle_tag(ldl_session_t *session, iks *iq, char *action) +{ + iks *jin = iks_insert (iq, "jin:jingle"); + iks_insert_attrib(jin, "xmlns:jin", "urn:xmpp:jingle:1"); + iks_insert_attrib(jin, "action", action); + iks_insert_attrib(jin, "sid", session->id); + //iks_insert_attrib(jin, "initiator", session->initiator ? session->initiator : session->them); + + return jin; +} + +static ldl_status new_jingle_iq(ldl_session_t *session, iks **iqp, iks **jinp, unsigned int *id, char *action) +{ + iks *iq , *jin; + unsigned int myid; + char idbuf[80]; + + myid = next_id(); + snprintf(idbuf, sizeof(idbuf), "%u", myid); + iq = iks_new("iq"); + iks_insert_attrib(iq, "xmlns", "jabber:client"); + iks_insert_attrib(iq, "from", session->login); + iks_insert_attrib(iq, "to", session->them); + iks_insert_attrib(iq, "type", "set"); + iks_insert_attrib(iq, "id", idbuf); + + jin = ldl_set_jingle_tag(session, iq, action); + + *jinp = jin; + *iqp = iq; + *id = myid; + return LDL_STATUS_SUCCESS; +} + + static ldl_status new_session_iq(ldl_session_t *session, iks **iqp, iks **sessp, unsigned int *id, char *type) { iks *iq, *sess; @@ -1973,6 +2358,11 @@ unsigned int ldl_session_terminate(ldl_session_t *session) apr_hash_t *hash = session->handle->sessions; new_session_iq(session, &iq, &sess, &id, "terminate"); + + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + ldl_set_jingle_tag(session, iq, "session-terminate"); + } + schedule_packet(session->handle, id, iq, LDL_RETRY); if (session->id) { @@ -1998,6 +2388,12 @@ unsigned int ldl_session_transport(ldl_session_t *session, unsigned int x, id = 0; + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + return ldl_session_candidates(session, candidates, clen); + } + + + for (x = 0; x < clen; x++) { char buf[512]; iq = NULL; @@ -2005,13 +2401,13 @@ unsigned int ldl_session_transport(ldl_session_t *session, 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 = sess; - if (0) add_elements(session, tag); + //if (0) add_elements(session, tag); tag = iks_insert(tag, "transport"); iks_insert_attrib(tag, "xmlns", "http://www.google.com/transport/p2p"); + //iks_insert_attrib(tag, "xmlns", "urn:xmpp:jingle:transports:raw-udp:1"); tag = iks_insert(tag, "candidate"); @@ -2047,7 +2443,6 @@ unsigned int ldl_session_transport(ldl_session_t *session, schedule_packet(session->handle, id, iq, LDL_RETRY); } - return id; } @@ -2056,23 +2451,103 @@ unsigned int ldl_session_candidates(ldl_session_t *session, unsigned int clen) { - iks *iq, *sess, *tag; - unsigned int x, id = 0; + iks *iq = NULL, *sess = NULL, *tag = NULL; + unsigned int x = 0, id = 0; + unsigned int pass = 0; + iks *jingle = NULL, *jin_content = NULL, *p_trans = NULL; + const char *tname = ""; + const char *type = ""; + + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + + + new_jingle_iq(session, &iq, &jingle, &id, "transport-info"); + + for (pass = 0; pass < 2; pass++) { + + if (pass == 0) { + type = "rtp"; + tname = "audio"; + } else { + type = "video_rtp"; + tname = "video"; + } + + jin_content = iks_insert(jingle, "jin:content"); + iks_insert_attrib(jin_content, "name", tname); + iks_insert_attrib(jin_content, "creator", "initiator"); + + for (x = 0; x < clen; x++) { + char buf[512]; + + if (strcasecmp(candidates[x].name, type)) { + continue; + } + + p_trans = iks_insert(jin_content, "p:transport"); + iks_insert_attrib(p_trans, "xmlns:p", "http://www.google.com/transport/p2p"); + + + + tag = iks_insert(p_trans, "candidate"); + + if (candidates[x].name) { + iks_insert_attrib(tag, "name", candidates[x].name); + } + if (candidates[x].address) { + iks_insert_attrib(tag, "address", candidates[x].address); + } + if (candidates[x].port) { + snprintf(buf, sizeof(buf), "%u", candidates[x].port); + iks_insert_attrib(tag, "port", buf); + } + if (candidates[x].username) { + iks_insert_attrib(tag, "username", candidates[x].username); + } + if (candidates[x].password) { + iks_insert_attrib(tag, "password", candidates[x].password); + } + if (candidates[x].pref) { + snprintf(buf, sizeof(buf), "%0.1f", candidates[x].pref); + iks_insert_attrib(tag, "preference", buf); + } + if (candidates[x].protocol) { + iks_insert_attrib(tag, "protocol", candidates[x].protocol); + } + if (candidates[x].type) { + iks_insert_attrib(tag, "type", candidates[x].type); + } + + iks_insert_attrib(tag, "network", "0"); + iks_insert_attrib(tag, "generation", "0"); + } + } + + + schedule_packet(session->handle, id, iq, LDL_RETRY); + + iq = NULL; + sess = NULL; + tag = NULL; + x = 0; + id = 0; + } + + + new_session_iq(session, &iq, &sess, &id, "candidates"); + add_elements(session, sess); + for (x = 0; x < clen; x++) { char buf[512]; - iq = NULL; - sess = NULL; - id = 0; + //iq = NULL; + //sess = NULL; + //id = 0; - new_session_iq(session, &iq, &sess, &id, "candidates"); - //tag = iks_insert(sess, "transport"); - //iks_insert_attrib(tag, "xmlns", "http://www.google.com/transport/p2p"); - tag = sess; + tag = iks_insert(sess, "ses:candidate"); + - add_elements(session, tag); - tag = iks_insert(tag, "ses:candidate"); if (candidates[x].name) { iks_insert_attrib(tag, "name", candidates[x].name); @@ -2103,9 +2578,10 @@ 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; } @@ -2192,11 +2668,11 @@ char *ldl_handle_disco(ldl_handle_t *handle, char *id, char *from, char *buf, un iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info"); } else { iks_delete(iq); - globals.logger(DL_LOG_DEBUG, "Memory ERROR!\n"); + globals.logger(DL_LOG_CRIT, "Memory ERROR!\n"); return NULL; } } else { - globals.logger(DL_LOG_DEBUG, "Memory ERROR!\n"); + globals.logger(DL_LOG_CRIT, "Memory ERROR!\n"); return NULL; } @@ -2236,42 +2712,274 @@ char *ldl_handle_disco(ldl_handle_t *handle, char *id, char *from, char *buf, un } + unsigned int ldl_session_describe(ldl_session_t *session, - ldl_payload_t *payloads, - unsigned int plen, - ldl_description_t description) + ldl_payload_t *payloads, + unsigned int plen, + ldl_description_t description, unsigned int *audio_ssrc, unsigned int *video_ssrc, + ldl_crypto_data_t *audio_crypto_data, ldl_crypto_data_t *video_crypto_data) { - iks *iq, *sess, *tag, *payload, *tp; + iks *iq; + iks *sess, *payload = NULL, *tag = NULL;//, *u = NULL; + unsigned int x, id; - + int video_call = 0; + int compat = 1; + //char *vid_mux = ldl_session_get_value(session, "video:rtcp-mux"); + //char *aud_mux = ldl_session_get_value(session, "audio:rtcp-mux"); + char tmp[80]; + iks *jpayload = NULL, *tp = NULL; + iks *jingle, *jin_audio, *jin_audio_desc = NULL, *jin_video = NULL, *jin_video_desc = NULL, *crypto; - new_session_iq(session, &iq, &sess, &id, description == LDL_DESCRIPTION_ACCEPT ? "accept" : "initiate"); - tag = iks_insert(sess, "pho:description"); - iks_insert_attrib(tag, "xmlns:pho", "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, "pho:payload-type"); - iks_insert_attrib(payload, "xmlns:pho", "http://www.google.com/session/phone"); - sprintf(idbuf, "%d", payloads[x].id); - iks_insert_attrib(payload, "id", idbuf); - iks_insert_attrib(payload, "name", payloads[x].name); - if (payloads[x].rate) { - sprintf(idbuf, "%d", payloads[x].rate); - iks_insert_attrib(payload, "clockrate", idbuf); + if (!*audio_ssrc) { + *audio_ssrc = (uint32_t) ((intptr_t) session + (uint32_t) time(NULL)); + } + + if (!*video_ssrc) { + *video_ssrc = (uint32_t) ((intptr_t) payloads + (uint32_t) time(NULL)); + } + + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + new_jingle_iq(session, &iq, &jingle, &id, description == LDL_DESCRIPTION_ACCEPT ? "session-accept" : "session-initiate"); + iks_insert_attrib(jingle, "initiator", session->initiator ? session->initiator : session->them); + + if (compat) { + sess = iks_insert (iq, "ses:session"); + iks_insert_attrib(sess, "xmlns:ses", "http://www.google.com/session"); + + iks_insert_attrib(sess, "type", description == LDL_DESCRIPTION_ACCEPT ? "accept" : "initiate"); + iks_insert_attrib(sess, "id", session->id); + iks_insert_attrib(sess, "initiator", session->initiator ? session->initiator : session->them); } - if (payloads[x].bps) { - sprintf(idbuf, "%d", payloads[x].bps); - iks_insert_attrib(payload, "bitrate", idbuf); + + } else { + new_session_iq(session, &iq, &sess, &id, description == LDL_DESCRIPTION_ACCEPT ? "accept" : "initiate"); + } + + + /* Check if this is a video call */ + for (x = 0; x < plen; x++) { + if (payloads[x].type == LDL_PAYLOAD_VIDEO) { + video_call = 1; + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + jin_video = iks_insert(jingle, "jin:content"); + iks_insert_attrib(jin_video, "name", "video"); + iks_insert_attrib(jin_video, "creator", "initiator"); + //iks_insert_attrib(jin_video, "senders", "both"); + jin_video_desc = iks_insert(jin_video, "rtp:description"); + iks_insert_attrib(jin_video_desc, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1"); + iks_insert_attrib(jin_video_desc, "media", "video"); + snprintf(tmp, sizeof(tmp), "%u", *video_ssrc); + iks_insert_attrib(jin_video_desc, "ssrc", tmp); + tp = iks_insert(jin_video, "p:transport"); + iks_insert_attrib(tp, "xmlns:p", "http://www.google.com/transport/p2p"); + + } + + break; } } + + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + jin_audio = iks_insert(jingle, "jin:content"); + iks_insert_attrib(jin_audio, "name", "audio"); + iks_insert_attrib(jin_audio, "creator", "initiator"); + //iks_insert_attrib(jin_audio, "senders", "both"); + jin_audio_desc = iks_insert(jin_audio, "rtp:description"); + iks_insert_attrib(jin_audio_desc, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1"); + iks_insert_attrib(jin_audio_desc, "media", "audio"); + snprintf(tmp, sizeof(tmp), "%u", *audio_ssrc); + iks_insert_attrib(jin_audio_desc, "ssrc", tmp); + tp = iks_insert(jin_audio, "p:transport"); + iks_insert_attrib(tp, "xmlns:p", "http://www.google.com/transport/p2p"); + } + + if (compat) { + + if (video_call) { + tag = iks_insert(sess, "vid:description"); + iks_insert_attrib(tag, "xmlns:vid", "http://www.google.com/session/video"); + } else { + tag = iks_insert(sess, "pho:description"); + iks_insert_attrib(tag, "xmlns:pho", "http://www.google.com/session/phone"); + } + + if (video_call) { + + for (x = 0; x < plen; x++) { + char idbuf[80]; + + if (payloads[x].type != LDL_PAYLOAD_VIDEO) { + continue; + } + + sprintf(idbuf, "%d", payloads[x].id); + + + payload = iks_insert(tag, "vid:payload-type"); + + iks_insert_attrib(payload, "id", idbuf); + iks_insert_attrib(payload, "name", payloads[x].name); + + if (payloads[x].type == LDL_PAYLOAD_VIDEO && video_call) { + if (payloads[x].width) { + sprintf(idbuf, "%d", payloads[x].width); + iks_insert_attrib(payload, "width", idbuf); + } + if (payloads[x].height) { + sprintf(idbuf, "%d", payloads[x].height); + iks_insert_attrib(payload, "height", idbuf); + } + if (payloads[x].framerate) { + sprintf(idbuf, "%d", payloads[x].framerate); + iks_insert_attrib(payload, "framerate", idbuf); + } + } + + } + + + //if (vid_mux) { + // iks_insert(tag, "rtcp-mux"); + //} + + //payload = iks_insert(tag, "vid:src-id"); + //iks_insert_cdata(payload, "123456789", 0); + + + //iks_insert_attrib(payload, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1"); + //iks_insert(payload, "vid:usage"); + } + } + + for (x = 0; x < plen; x++) { + char idbuf[80]; + + if (payloads[x].type == LDL_PAYLOAD_VIDEO && !video_call) { + continue; + } + + sprintf(idbuf, "%d", payloads[x].id); + + if (payloads[x].type == LDL_PAYLOAD_AUDIO) { + + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + char ratebuf[80]; + char buf[80]; + iks *param; + + jpayload = iks_insert(jin_audio_desc, "rtp:payload-type"); + iks_insert_attrib(jpayload, "id", idbuf); + sprintf(ratebuf, "%d", payloads[x].rate); + iks_insert_attrib(jpayload, "name", payloads[x].name); + iks_insert_attrib(jpayload, "clockrate", ratebuf); + param = iks_insert(jpayload, "rtp:parameter"); + iks_insert_attrib(param, "name", "bitrate"); + sprintf(buf, "%d", payloads[x].bps); + iks_insert_attrib(param, "value", buf); + + sprintf(buf, "%d", payloads[x].ptime); + iks_insert_attrib(jpayload, "ptime", ratebuf); + iks_insert_attrib(jpayload, "maxptime", ratebuf); + + } + + } else if (payloads[x].type == LDL_PAYLOAD_VIDEO && video_call) { + + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + char buf[80]; + iks *param; + + jpayload = iks_insert(jin_video_desc, "rtp:payload-type"); + iks_insert_attrib(jpayload, "id", idbuf); + iks_insert_attrib(jpayload, "name", payloads[x].name); + param = iks_insert(jpayload, "rtp:parameter"); + iks_insert_attrib(param, "name", "width"); + sprintf(buf, "%d", payloads[x].width); + iks_insert_attrib(param, "value", buf); + + + param = iks_insert(jpayload, "rtp:parameter"); + iks_insert_attrib(param, "name", "height"); + sprintf(buf, "%d", payloads[x].height); + iks_insert_attrib(param, "value", buf); + + param = iks_insert(jpayload, "rtp:parameter"); + iks_insert_attrib(param, "name", "framerate"); + sprintf(buf, "%d", payloads[x].framerate); + iks_insert_attrib(param, "value", buf); + + } + } + + if (compat) { + + if (payloads[x].type == LDL_PAYLOAD_AUDIO) { + + payload = iks_insert(tag, "pho:payload-type"); + + iks_insert_attrib(payload, "id", idbuf); + iks_insert_attrib(payload, "name", payloads[x].name); + + if (payloads[x].rate) { + sprintf(idbuf, "%d", payloads[x].rate); + iks_insert_attrib(payload, "clockrate", idbuf); + } + + if (payloads[x].bps) { + sprintf(idbuf, "%d", payloads[x].bps); + iks_insert_attrib(payload, "bitrate", idbuf); + } + + iks_insert_attrib(payload, "xmlns:pho", "http://www.google.com/session/phone"); + } + } + //if (payloads[x].id == 34) payloads[x].id = 98; /* XXX */ + + } + + if ((session->handle->flags & LDL_FLAG_JINGLE)) { + if (jin_video_desc && video_crypto_data) { + payload = iks_insert(jin_video_desc, "rtp:encryption"); + crypto = iks_insert(payload, "rtp:crypto"); + iks_insert_attrib(crypto, "crypto-suite", video_crypto_data->suite); + iks_insert_attrib(crypto, "key-params", video_crypto_data->key); + iks_insert_attrib(crypto, "tag", video_crypto_data->tag); + } + + + if (jin_audio_desc && audio_crypto_data) { + payload = iks_insert(jin_audio_desc, "rtp:encryption"); + crypto = iks_insert(payload, "rtp:crypto"); + iks_insert_attrib(crypto, "crypto-suite", audio_crypto_data->suite); + iks_insert_attrib(crypto, "key-params", audio_crypto_data->key); + iks_insert_attrib(crypto, "tag", audio_crypto_data->tag); + } + } + + //if (aud_mux) { + // iks_insert(tag, "rtcp-mux"); + //} + + //payload = iks_insert(tag, "pho:src-id"); + //iks_insert_cdata(payload, "987654321", 0); + //iks_insert_attrib(payload, "xmlns:pho", "http://www.google.com/session/phone"); + + //payload = iks_insert(tag, "rtp:encryption"); + //iks_insert_attrib(payload, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1"); + //u = iks_insert(payload, "pho:usage"); + //iks_insert_attrib(u, "xmlns:pho", "http://www.google.com/session/phone"); + +#if 0 if (description == LDL_DESCRIPTION_INITIATE) { tp = iks_insert (sess, "transport"); iks_insert_attrib(tp, "xmlns", "http://www.google.com/transport/p2p"); } - +#endif + + schedule_packet(session->handle, id, iq, LDL_RETRY); return id; @@ -2282,11 +2990,13 @@ ldl_state_t ldl_session_get_state(ldl_session_t *session) return session->state; } -ldl_status ldl_session_get_candidates(ldl_session_t *session, ldl_candidate_t **candidates, unsigned int *len) +ldl_status ldl_session_get_candidates(ldl_session_t *session, ldl_transport_type_t tport, ldl_candidate_t **candidates, unsigned int *len) { + assert(tport < LDL_TPORT_MAX); + if (session->candidate_len) { - *candidates = session->candidates; - *len = session->candidate_len; + *candidates = session->candidates[tport]; + *len = session->candidate_len[tport]; return LDL_STATUS_SUCCESS; } else { *candidates = NULL; @@ -2332,7 +3042,7 @@ ldl_status ldl_global_init(int debug) memset(&globals, 0, sizeof(globals)); if (apr_pool_create(&globals.memory_pool, NULL) != LDL_STATUS_SUCCESS) { - globals.logger(DL_LOG_DEBUG, "Could not allocate memory pool\n"); + globals.logger(DL_LOG_CRIT, "Could not allocate memory pool\n"); return LDL_STATUS_MEMERR; } diff --git a/libs/libdingaling/src/libdingaling.h b/libs/libdingaling/src/libdingaling.h index 6cf8bd846b..e76be86ecf 100644 --- a/libs/libdingaling/src/libdingaling.h +++ b/libs/libdingaling/src/libdingaling.h @@ -28,6 +28,7 @@ * libdingaling.h -- Main Header File * */ + /*! \file libdingaling.h \brief Main Header File */ @@ -60,12 +61,18 @@ extern "C" { #endif #define LDL_HANDLE_QLEN 2000 -#define LDL_MAX_CANDIDATES 10 +#define LDL_MAX_CANDIDATES 25 #define LDL_MAX_PAYLOADS 50 #define LDL_RETRY 3 #define IKS_NS_COMPONENT "jabber:component:accept" -/* period between keep alive signals in 1sec units*/ -#define LDL_KEEPALIVE_TIMEOUT 300 +/* period between keep alive signals in 0.1sec units*/ +#define LDL_KEEPALIVE_TIMEOUT 6000 + +typedef struct ldl_crypto_data_s { + char *tag; + char *suite; + char *key; +} ldl_crypto_data_t; /*! \brief A structure to store a jingle candidate */ struct ldl_candidate { @@ -90,19 +97,89 @@ struct ldl_candidate { }; typedef struct ldl_candidate ldl_candidate_t; -/*! \brief A structure to store a jingle payload */ +typedef enum { + LDL_PAYLOAD_AUDIO, + LDL_PAYLOAD_VIDEO +} ldl_payload_type_t; + +/*! \brief A structure to store a jingle audio payload */ struct ldl_payload { + /*! the type of the payload */ + ldl_payload_type_t type; /*! the iana name of the payload type */ char *name; /*! the iana id of the payload type */ unsigned int id; + + /* Audio */ + /*! the transfer rate of the payload type */ unsigned int rate; /*! the bits per second of the payload type */ unsigned int bps; + + /* Video */ + + /*! the width of the video payload type */ + unsigned int width; + /*! the width of the video payload type */ + unsigned int height; + /*! the framerate of the video payload type */ + unsigned int framerate; + + unsigned int ptime; }; typedef struct ldl_payload ldl_payload_t; + +enum ldl_transport_type { + LDL_TPORT_RTP, + LDL_TPORT_VIDEO_RTP, + LDL_TPORT_RTCP, + LDL_TPORT_VIDEO_RTCP, + + /* Nothing below that line */ + LDL_TPORT_MAX +}; +typedef enum ldl_transport_type ldl_transport_type_t; + +static inline const char *ldl_transport_type_str(ldl_transport_type_t type) +{ + static const char *name[] = { "rtp", "video_rtp", "rtcp", "video_rtcp" }; + return type >= LDL_TPORT_MAX ? NULL : name[type]; +} + +static inline ldl_transport_type_t ldl_transport_type_parse(const char *type) { + if (!strcasecmp(type, "rtp")) { + return LDL_TPORT_RTP; + } else if (!strcasecmp(type, "rtcp")) { + return LDL_TPORT_RTCP; + } else if (!strcasecmp(type, "video_rtp")) { + return LDL_TPORT_VIDEO_RTP; + } else if (!strcasecmp(type, "video_rtcp")) { + return LDL_TPORT_VIDEO_RTCP; + } else { + return LDL_TPORT_MAX; + } +} + +#if 0 +/*! \brief A structure to store a jingle video payload */ +struct ldl_vpayload { + /*! the iana name of the video payload type */ + char *name; + /*! the iana id of the video payload type */ + unsigned int id; + /*! the width of the video payload type */ + unsigned int width; + /*! the width of the video payload type */ + unsigned int height; + /*! the framerate of the video payload type */ + unsigned int framerate; +}; +typedef struct ldl_vpayload ldl_vpayload_t; +#endif + struct ldl_handle; typedef struct ldl_handle ldl_handle_t; @@ -132,7 +209,8 @@ typedef enum { LDL_FLAG_SASL_MD5 = (1 << 12), LDL_FLAG_COMPONENT = (1 << 13), LDL_FLAG_OUTBOUND = (1 << 14), - LDL_FLAG_GATEWAY = (1 << 15) + LDL_FLAG_GATEWAY = (1 << 15), + LDL_FLAG_JINGLE = (1 << 16) } ldl_user_flag_t; typedef enum { @@ -514,9 +592,10 @@ unsigned int ldl_session_transport(ldl_session_t *session, \return the message_id of the generated xmpp request */ unsigned int ldl_session_describe(ldl_session_t *session, - ldl_payload_t *payloads, - unsigned int plen, - ldl_description_t description); + ldl_payload_t *payloads, + unsigned int plen, + ldl_description_t description, unsigned int *audio_ssrc, unsigned int *video_ssrc, + ldl_crypto_data_t *audio_crypto_data, ldl_crypto_data_t *video_crypto_data); /*! @@ -530,11 +609,12 @@ ldl_state_t ldl_session_get_state(ldl_session_t *session); /*! \brief get the candidates \param session the session + \param tport type of transport (rtp,rtcp,video_rtp,video_rtcp,etc.) \param candidates pointer to point at array of the candidates \param len the resulting len of the array pointer \return success or failure */ -ldl_status ldl_session_get_candidates(ldl_session_t *session, ldl_candidate_t **candidates, unsigned int *len); +ldl_status ldl_session_get_candidates(ldl_session_t *session, ldl_transport_type_t tport, ldl_candidate_t **candidates, unsigned int *len); /*! \brief get the payloads diff --git a/src/mod/endpoints/mod_dingaling/Makefile b/src/mod/endpoints/mod_dingaling/Makefile index f2ac13bb7a..c56dc228cb 100644 --- a/src/mod/endpoints/mod_dingaling/Makefile +++ b/src/mod/endpoints/mod_dingaling/Makefile @@ -9,7 +9,7 @@ IKS_LA=$(IKS_DIR)/src/libiksemel.la DING_DIR=$(BASE)/libs/libdingaling LOCAL_CFLAGS += -I$(DING_DIR)/src -I$(BASE)/libs/iksemel/include LOCAL_OBJS=$(DING_DIR)/src/libdingaling.o $(DING_DIR)/src/sha1.o $(IKS_LA) -LOCAL_SOURCES=$(DING_DIR)/src/libdingaling.c $(DING_DIR)/src/sha1.c +LOCAL_SOURCES=$(DING_DIR)/src/libdingaling.c $(DING_DIR)/src/sha1.c $(DING_DIR)/src/libdingaling.h LOCAL_LDFLAGS=$(LIBGNUTLS_LIBS) include $(BASE)/build/modmake.rules diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index 735a68efc7..6bf84be1f2 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -33,8 +33,11 @@ #include #include +#define MDL_RTCP_DUR 5000 #define DL_CAND_WAIT 10000000 #define DL_CAND_INITIAL_WAIT 2000000 +//#define DL_CAND_WAIT 2000000 +//#define DL_CAND_INITIAL_WAIT 5000000 #define DL_EVENT_LOGIN_SUCCESS "dingaling::login_success" #define DL_EVENT_LOGIN_FAILURE "dingaling::login_failure" @@ -79,7 +82,8 @@ typedef enum { TFLAG_TERM = (1 << 21), TFLAG_TRANSPORT_ACCEPT = (1 << 22), TFLAG_READY = (1 << 23), - TFLAG_NAT_MAP = (1 << 24) + TFLAG_NAT_MAP = (1 << 24), + TFLAG_SECURE = (1 << 25) } TFLAGS; typedef enum { @@ -144,47 +148,103 @@ struct mdl_profile { }; typedef struct mdl_profile mdl_profile_t; -struct private_object { - unsigned int flags; +/*! \brief The required components to setup a jingle transport */ +typedef struct mdl_transport { + char *remote_ip; + switch_port_t remote_port; + + switch_port_t local_port; /*!< The real local port */ + switch_port_t adv_local_port; + unsigned int ssrc; + + char local_user[17]; + char local_pass[17]; + char *remote_user; + char *remote_pass; + int ptime; + int payload_count; + int restart_rtp; + switch_codec_t read_codec; switch_codec_t write_codec; + switch_frame_t read_frame; + + uint32_t codec_rate; + char *codec_name; + + switch_payload_t codec_num; + switch_payload_t r_codec_num; + + char *stun_ip; + uint16_t stun_port; + + switch_rtp_t *rtp_session; + ldl_transport_type_t type; + + int total; + int accepted; + + int ready; + + int codec_index; + + int vid_width; + int vid_height; + int vid_rate; + + switch_byte_t has_crypto; + int crypto_tag; + unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN]; + unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN]; + switch_rtp_crypto_key_type_t crypto_send_type; + switch_rtp_crypto_key_type_t crypto_recv_type; + switch_rtp_crypto_key_type_t crypto_type; + + char *local_crypto_key; + char *remote_crypto_key; + + ldl_crypto_data_t *local_crypto_data; + +} mdl_transport_t; + + +struct private_object { + unsigned int flags; mdl_profile_t *profile; switch_core_session_t *session; + switch_channel_t *channel; + switch_caller_profile_t *caller_profile; unsigned short samprate; switch_mutex_t *mutex; const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS]; unsigned int num_codecs; - int codec_index; - switch_rtp_t *rtp_session; + + mdl_transport_t transports[LDL_TPORT_MAX+1]; + ldl_session_t *dlsession; - char *remote_ip; - switch_port_t local_port; - switch_port_t adv_local_port; - switch_port_t remote_port; - char local_user[17]; - char local_pass[17]; - char *remote_user; + char *us; char *them; unsigned int cand_id; unsigned int desc_id; unsigned int dc; + uint32_t timestamp_send; int32_t timestamp_recv; uint32_t last_read; - char *codec_name; - switch_payload_t codec_num; - switch_payload_t r_codec_num; - uint32_t codec_rate; + switch_time_t next_desc; switch_time_t next_cand; - char *stun_ip; + char *recip; char *dnis; - uint16_t stun_port; switch_mutex_t *flag_mutex; + + int read_count; + + }; struct rfc2833_digit { @@ -744,8 +804,12 @@ static void terminate_session(switch_core_session_t **session, int line, switch_ tech_pvt = switch_core_session_get_private(*session); - if (tech_pvt && tech_pvt->profile && tech_pvt->profile->ip && tech_pvt->local_port) { - switch_rtp_release_port(tech_pvt->profile->ip, tech_pvt->local_port); + if (tech_pvt && tech_pvt->profile && tech_pvt->profile->ip && tech_pvt->transports[LDL_TPORT_RTP].local_port) { + switch_rtp_release_port(tech_pvt->profile->ip, tech_pvt->transports[LDL_TPORT_RTP].local_port); + } + + if (tech_pvt && tech_pvt->profile && tech_pvt->profile->ip && tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port) { + switch_rtp_release_port(tech_pvt->profile->ip, tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port); } if (!switch_core_session_running(*session) && (!tech_pvt || !switch_test_flag(tech_pvt, TFLAG_READY))) { @@ -811,16 +875,35 @@ static void dl_logger(char *file, const char *func, int line, int level, char *f static int get_codecs(struct private_object *tech_pvt) { + char *codec_string = NULL; + const char *var; + char *codec_order[SWITCH_MAX_CODECS]; + int codec_order_last; + char **codec_order_p = NULL; + + switch_assert(tech_pvt != NULL); switch_assert(tech_pvt->session != NULL); if (!tech_pvt->num_codecs) { - if (globals.codec_string) { + + if ((var = switch_channel_get_variable(tech_pvt->channel, "absolute_codec_string"))) { + codec_string = (char *)var; + codec_order_last = switch_separate_string(codec_string, ',', codec_order, SWITCH_MAX_CODECS); + codec_order_p = codec_order; + } else { + codec_string = globals.codec_string; + codec_order_last = globals.codec_order_last; + codec_order_p = globals.codec_order; + } + + if (codec_string) { if ((tech_pvt->num_codecs = switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, - SWITCH_MAX_CODECS, globals.codec_order, globals.codec_order_last)) <= 0) { + SWITCH_MAX_CODECS, codec_order_p, codec_order_last)) <= 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO codecs?\n"); return 0; } + } else if (((tech_pvt->num_codecs = switch_loadable_module_get_codecs(tech_pvt->codecs, SWITCH_MAX_CODECS))) <= 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO codecs?\n"); return 0; @@ -864,76 +947,246 @@ static void handle_thread_launch(ldl_handle_t *handle) } -static int activate_rtp(struct private_object *tech_pvt) +switch_status_t mdl_build_crypto(struct private_object *tech_pvt, ldl_transport_type_t ttype, + int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction) +{ + unsigned char b64_key[512] = ""; + const char *type_str; + unsigned char *key; + char *p; + + + if (!switch_test_flag(tech_pvt, TFLAG_SECURE)) { + return SWITCH_STATUS_SUCCESS; + } + + + if (type == AES_CM_128_HMAC_SHA1_80) { + type_str = SWITCH_RTP_CRYPTO_KEY_80; + } else { + type_str = SWITCH_RTP_CRYPTO_KEY_32; + } + + if (direction == SWITCH_RTP_CRYPTO_SEND) { + key = tech_pvt->transports[ttype].local_raw_key; + } else { + key = tech_pvt->transports[ttype].remote_raw_key; + + } + + switch_rtp_get_random(key, SWITCH_RTP_KEY_LEN); + switch_b64_encode(key, SWITCH_RTP_KEY_LEN, b64_key, sizeof(b64_key)); + p = strrchr((char *) b64_key, '='); + + while (p && *p && *p == '=') { + *p-- = '\0'; + } + + tech_pvt->transports[ttype].local_crypto_key = switch_core_session_sprintf(tech_pvt->session, "%d %s inline:%s", index, type_str, b64_key); + tech_pvt->transports[ttype].local_crypto_data = switch_core_session_alloc(tech_pvt->session, sizeof(ldl_crypto_data_t)); + tech_pvt->transports[ttype].local_crypto_data->tag = switch_core_session_sprintf(tech_pvt->session, "%d", index); + tech_pvt->transports[ttype].local_crypto_data->suite = switch_core_session_strdup(tech_pvt->session, type_str); + tech_pvt->transports[ttype].local_crypto_data->key = switch_core_session_sprintf(tech_pvt->session, "inline:%s", (char *)b64_key); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Local Key [%s]\n", tech_pvt->transports[ttype].local_crypto_key); + + tech_pvt->transports[ttype].crypto_type = AES_CM_128_NULL_AUTH; + + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t mdl_add_crypto(struct private_object *tech_pvt, + ldl_transport_type_t ttype, const char *key_str, switch_rtp_crypto_direction_t direction) +{ + unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN]; + switch_rtp_crypto_key_type_t type; + char *p; + + + p = strchr(key_str, ' '); + + if (p && *p && *(p + 1)) { + p++; + if (!strncasecmp(p, SWITCH_RTP_CRYPTO_KEY_32, strlen(SWITCH_RTP_CRYPTO_KEY_32))) { + type = AES_CM_128_HMAC_SHA1_32; + } else if (!strncasecmp(p, SWITCH_RTP_CRYPTO_KEY_80, strlen(SWITCH_RTP_CRYPTO_KEY_80))) { + type = AES_CM_128_HMAC_SHA1_80; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p); + goto bad; + } + + p = strchr(p, ' '); + if (p && *p && *(p + 1)) { + p++; + if (strncasecmp(p, "inline:", 7)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p); + goto bad; + } + + p += 7; + switch_b64_decode(p, (char *) key, sizeof(key)); + + if (direction == SWITCH_RTP_CRYPTO_SEND) { + tech_pvt->transports[ttype].crypto_send_type = type; + memcpy(tech_pvt->transports[ttype].local_raw_key, key, SWITCH_RTP_KEY_LEN); + } else { + tech_pvt->transports[ttype].crypto_recv_type = type; + memcpy(tech_pvt->transports[ttype].remote_raw_key, key, SWITCH_RTP_KEY_LEN); + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_NOTICE, + "%s Setting %s crypto key\n", ldl_transport_type_str(ttype), switch_core_session_get_name(tech_pvt->session)); + tech_pvt->transports[ttype].has_crypto++; + + + return SWITCH_STATUS_SUCCESS; + } + + } + + bad: + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Error!\n"); + return SWITCH_STATUS_FALSE; + +} + +static void try_secure(struct private_object *tech_pvt, ldl_transport_type_t ttype) +{ + + if (!switch_test_flag(tech_pvt, TFLAG_SECURE)) { + return; + } + + + //if (tech_pvt->transports[ttype].crypto_type) { + switch_rtp_add_crypto_key(tech_pvt->transports[ttype].rtp_session, + SWITCH_RTP_CRYPTO_SEND, 1, tech_pvt->transports[ttype].crypto_type, + tech_pvt->transports[ttype].local_raw_key, SWITCH_RTP_KEY_LEN); + + + switch_rtp_add_crypto_key(tech_pvt->transports[ttype].rtp_session, + SWITCH_RTP_CRYPTO_RECV, tech_pvt->transports[ttype].crypto_tag, + tech_pvt->transports[ttype].crypto_type, + tech_pvt->transports[ttype].remote_raw_key, SWITCH_RTP_KEY_LEN); + + switch_channel_set_variable(tech_pvt->channel, "jingle_secure_audio_confirmed", "true"); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_NOTICE, + "%s %s crypto confirmed\n", ldl_transport_type_str(ttype), switch_core_session_get_name(tech_pvt->session)); + + //} + +} + + + +static int activate_audio_rtp(struct private_object *tech_pvt) { switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session); const char *err; - int ms = 0; + int ms = tech_pvt->transports[LDL_TPORT_RTP].ptime; switch_rtp_flag_t flags; + int locked = 0; + int r = 1; - if (switch_rtp_ready(tech_pvt->rtp_session)) { + + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_RTP].rtp_session)) { return 1; } - if (!(tech_pvt->remote_ip && tech_pvt->remote_port)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "No valid candidates received!\n"); + if (!(tech_pvt->transports[LDL_TPORT_RTP].remote_ip && tech_pvt->transports[LDL_TPORT_RTP].remote_port)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "No valid rtp candidates received!\n"); return 0; } - if (switch_core_codec_init(&tech_pvt->read_codec, - tech_pvt->codec_name, - NULL, - tech_pvt->codec_rate, - ms, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Can't load codec?\n"); - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return 0; + if (switch_core_codec_ready(&tech_pvt->transports[LDL_TPORT_RTP].read_codec)) { + locked = 1; + switch_mutex_lock(tech_pvt->transports[LDL_TPORT_RTP].read_codec.mutex); + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_RTP].rtp_session)) { + switch_rtp_kill_socket(tech_pvt->transports[LDL_TPORT_RTP].rtp_session); + switch_rtp_destroy(&tech_pvt->transports[LDL_TPORT_RTP].rtp_session); + } + + + } else { + if (switch_core_codec_init(&tech_pvt->transports[LDL_TPORT_RTP].read_codec, + tech_pvt->transports[LDL_TPORT_RTP].codec_name, + NULL, + tech_pvt->transports[LDL_TPORT_RTP].codec_rate, + ms, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Can't load codec?\n"); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + r = 0; + goto end; + } + tech_pvt->transports[LDL_TPORT_RTP].read_frame.rate = tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->samples_per_second; + tech_pvt->transports[LDL_TPORT_RTP].read_frame.codec = &tech_pvt->transports[LDL_TPORT_RTP].read_codec; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Read Codec to %s@%d\n", + tech_pvt->transports[LDL_TPORT_RTP].codec_name, (int) tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->samples_per_second); + + if (switch_core_codec_init(&tech_pvt->transports[LDL_TPORT_RTP].write_codec, + tech_pvt->transports[LDL_TPORT_RTP].codec_name, + NULL, + tech_pvt->transports[LDL_TPORT_RTP].codec_rate, + ms, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Can't load codec?\n"); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + r = 0; + goto end; + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Write Codec to %s@%d\n", + tech_pvt->transports[LDL_TPORT_RTP].codec_name, (int) tech_pvt->transports[LDL_TPORT_RTP].write_codec.implementation->samples_per_second); + + switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->transports[LDL_TPORT_RTP].read_codec); + switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->transports[LDL_TPORT_RTP].write_codec); } - tech_pvt->read_frame.rate = tech_pvt->read_codec.implementation->samples_per_second; - tech_pvt->read_frame.codec = &tech_pvt->read_codec; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Read Codec to %s@%d\n", - tech_pvt->codec_name, (int) tech_pvt->read_codec.implementation->samples_per_second); - - if (switch_core_codec_init(&tech_pvt->write_codec, - tech_pvt->codec_name, - NULL, - tech_pvt->codec_rate, - ms, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Can't load codec?\n"); - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return 0; - } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Write Codec to %s@%d\n", - tech_pvt->codec_name, (int) tech_pvt->write_codec.implementation->samples_per_second); - - switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec); - switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec); - - if (globals.auto_nat && tech_pvt->profile->local_network && !switch_check_network_list_ip(tech_pvt->remote_ip, tech_pvt->profile->local_network)) { + if (globals.auto_nat && tech_pvt->profile->local_network && !switch_check_network_list_ip(tech_pvt->transports[LDL_TPORT_RTP].remote_ip, tech_pvt->profile->local_network)) { switch_port_t external_port = 0; - switch_nat_add_mapping((switch_port_t) tech_pvt->local_port, SWITCH_NAT_UDP, &external_port, SWITCH_FALSE); + switch_nat_add_mapping((switch_port_t) tech_pvt->transports[LDL_TPORT_RTP].local_port, SWITCH_NAT_UDP, &external_port, SWITCH_FALSE); if (external_port) { - tech_pvt->adv_local_port = external_port; + tech_pvt->transports[LDL_TPORT_RTP].adv_local_port = external_port; switch_set_flag(tech_pvt, TFLAG_NAT_MAP); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "NAT mapping returned 0. Run freeswitch with -nonat since it's not working right.\n"); } } - if (tech_pvt->adv_local_port != tech_pvt->local_port) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "SETUP RTP %s:%d(%d) -> %s:%d\n", tech_pvt->profile->ip, - tech_pvt->local_port, tech_pvt->adv_local_port, tech_pvt->remote_ip, tech_pvt->remote_port); + if (tech_pvt->transports[LDL_TPORT_RTP].adv_local_port != tech_pvt->transports[LDL_TPORT_RTP].local_port) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "SETUP AUDIO RTP %s:%d(%d) -> %s:%d codec: %s(%d) %dh %di\n", + tech_pvt->profile->ip, + tech_pvt->transports[LDL_TPORT_RTP].local_port, + tech_pvt->transports[LDL_TPORT_RTP].adv_local_port, + tech_pvt->transports[LDL_TPORT_RTP].remote_ip, + tech_pvt->transports[LDL_TPORT_RTP].remote_port, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->iananame, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->ianacode, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->samples_per_packet, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->microseconds_per_packet + + ); } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), 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); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "SETUP AUDIO RTP %s:%d -> %s:%d codec: %s(%d) %dh %di\n", + tech_pvt->profile->ip, + tech_pvt->transports[LDL_TPORT_RTP].local_port, + tech_pvt->transports[LDL_TPORT_RTP].remote_ip, + tech_pvt->transports[LDL_TPORT_RTP].remote_port, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->iananame, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->ianacode, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->samples_per_packet, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->microseconds_per_packet + ); } flags = SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_GOOGLEHACK | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_RAW_WRITE | SWITCH_RTP_FLAG_AUTO_CNG; @@ -947,128 +1200,390 @@ static int activate_rtp(struct private_object *tech_pvt) flags &= ~SWITCH_RTP_FLAG_AUTOADJ; } - if (!(tech_pvt->rtp_session = switch_rtp_new(tech_pvt->profile->ip, - tech_pvt->local_port, - tech_pvt->remote_ip, - tech_pvt->remote_port, - tech_pvt->codec_num, - tech_pvt->read_codec.implementation->samples_per_packet, - tech_pvt->read_codec.implementation->microseconds_per_packet, - flags, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session)))) { + if (!(tech_pvt->transports[LDL_TPORT_RTP].rtp_session = switch_rtp_new(tech_pvt->profile->ip, + tech_pvt->transports[LDL_TPORT_RTP].local_port, + tech_pvt->transports[LDL_TPORT_RTP].remote_ip, + tech_pvt->transports[LDL_TPORT_RTP].remote_port, + tech_pvt->transports[LDL_TPORT_RTP].codec_num, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->samples_per_packet, + tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->microseconds_per_packet, + flags, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session)))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "RTP ERROR %s\n", err); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return 0; + r = 0; + goto end; } 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; uint8_t inb = switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1; - switch_rtp_activate_ice(tech_pvt->rtp_session, tech_pvt->remote_user, tech_pvt->local_user); + + switch_rtp_set_ssrc(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, tech_pvt->transports[LDL_TPORT_RTP].ssrc); + + if (tech_pvt->transports[LDL_TPORT_RTCP].remote_port) { + switch_rtp_activate_rtcp(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, MDL_RTCP_DUR, + tech_pvt->transports[LDL_TPORT_RTCP].remote_port); + + } + + try_secure(tech_pvt, LDL_TPORT_RTP); + + switch_rtp_activate_ice(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, + tech_pvt->transports[LDL_TPORT_RTP].remote_user, + tech_pvt->transports[LDL_TPORT_RTP].local_user, + tech_pvt->transports[LDL_TPORT_RTP].remote_pass); + if ((vad_in && inb) || (vad_out && !inb)) { - if (switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING) != SWITCH_STATUS_SUCCESS) { + if (switch_rtp_enable_vad(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, tech_pvt->session, &tech_pvt->transports[LDL_TPORT_RTP].read_codec, SWITCH_VAD_FLAG_TALKING) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "VAD ERROR %s\n", err); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return 0; + r = 0; + goto end; } switch_set_flag_locked(tech_pvt, TFLAG_VAD); } - switch_rtp_set_cng_pt(tech_pvt->rtp_session, 13); - switch_rtp_set_telephony_event(tech_pvt->rtp_session, 101); + //switch_rtp_set_cng_pt(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, 13); + switch_rtp_set_telephony_event(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, 101); + + if (tech_pvt->transports[LDL_TPORT_RTCP].remote_port) { + switch_rtp_activate_rtcp_ice(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, + tech_pvt->transports[LDL_TPORT_RTCP].remote_user, + tech_pvt->transports[LDL_TPORT_RTCP].local_user, + tech_pvt->transports[LDL_TPORT_RTCP].remote_pass); + + } + + + } - return 1; + end: + + if (locked) { + switch_mutex_unlock(tech_pvt->transports[LDL_TPORT_RTP].read_codec.mutex); + } + + return r; +} + + +static int activate_video_rtp(struct private_object *tech_pvt) +{ + switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session); + const char *err; + int ms = 0; + switch_rtp_flag_t flags; + int r = 1, locked = 0; + + + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session)) { + r = 1; goto end; + } + + if (!(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_ip && tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_port)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "No valid video_rtp candidates received!\n"); + r = 0; goto end; + } + + if (zstr(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_name)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "No valid video_rtp codecs received!\n"); + r = 0; goto end; + } + + if (switch_core_codec_ready(&tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec)) { + locked = 1; + switch_mutex_lock(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.mutex); + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session)) { + switch_rtp_kill_socket(tech_pvt->transports[LDL_TPORT_RTP].rtp_session); + switch_rtp_destroy(&tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session); + } + + + + + + } else { + if (switch_core_codec_init(&tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_name, + NULL, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_rate, + ms, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Can't load codec?\n"); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + r = 0; goto end; + } + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame.rate = tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->samples_per_second; + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame.codec = &tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Read Codec to %s@%d\n", + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_name, (int) tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->samples_per_second); + + if (switch_core_codec_init(&tech_pvt->transports[LDL_TPORT_VIDEO_RTP].write_codec, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_name, + NULL, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_rate, + ms, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Can't load codec?\n"); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + r = 0; goto end; + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Write Codec to %s@%d\n", + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_name, (int) tech_pvt->transports[LDL_TPORT_VIDEO_RTP].write_codec.implementation->samples_per_second); + + switch_core_session_set_video_read_codec(tech_pvt->session, &tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec); + switch_core_session_set_video_write_codec(tech_pvt->session, &tech_pvt->transports[LDL_TPORT_VIDEO_RTP].write_codec); + } + + if (globals.auto_nat && tech_pvt->profile->local_network && !switch_check_network_list_ip(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_ip, tech_pvt->profile->local_network)) { + switch_port_t external_port = 0; + switch_nat_add_mapping((switch_port_t) tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port, SWITCH_NAT_UDP, &external_port, SWITCH_FALSE); + + if (external_port) { + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].adv_local_port = external_port; + switch_set_flag(tech_pvt, TFLAG_NAT_MAP); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "NAT mapping returned 0. Run freeswitch with -nonat since it's not working right.\n"); + } + } + + + if (tech_pvt->transports[LDL_TPORT_VIDEO_RTP].adv_local_port != tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "SETUP VIDEO RTP %s:%d(%d) -> %s:%d codec: %s(%d) %dh %di\n", + tech_pvt->profile->ip, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].adv_local_port, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_ip, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_port, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->iananame, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->ianacode, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->samples_per_packet, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->microseconds_per_packet + + ); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "SETUP VIDEO RTP %s:%d -> %s:%d codec: %s(%d) %dh %di\n", + tech_pvt->profile->ip, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_ip, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_port, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->iananame, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->ianacode, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->samples_per_packet, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation->microseconds_per_packet + ); + } + + + flags = SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_GOOGLEHACK | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_RAW_WRITE | SWITCH_RTP_FLAG_VIDEO; + + + if (switch_true(switch_channel_get_variable(channel, "disable_rtp_auto_adjust"))) { + flags &= ~SWITCH_RTP_FLAG_AUTOADJ; + } + + if (!(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session = switch_rtp_new(tech_pvt->profile->ip, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_ip, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_port, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_num, + 1, + 90000, + flags, NULL, &err, switch_core_session_get_pool(tech_pvt->session)))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "RTP ERROR %s\n", err); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + r = 0; goto end; + } else { + switch_rtp_set_ssrc(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session, tech_pvt->transports[LDL_TPORT_VIDEO_RTP].ssrc); + + if (tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].remote_port) { + switch_rtp_activate_rtcp(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session, MDL_RTCP_DUR, + tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].remote_port); + } + try_secure(tech_pvt, LDL_TPORT_VIDEO_RTP); + + + switch_rtp_activate_ice(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_user, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_user, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].remote_pass); + switch_channel_set_flag(channel, CF_VIDEO); + //switch_rtp_set_default_payload(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session, tech_pvt->transports[LDL_TPORT_VIDEO_RTP].r_codec_num); + + + if (tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].remote_port) { + + switch_rtp_activate_rtcp_ice(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session, + tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].remote_user, + tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].local_user, + tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].remote_pass); + } + + + + } + + end: + if (locked) { + switch_mutex_unlock(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.mutex); + } + + return r; } -static int do_candidates(struct private_object *tech_pvt, int force) +static int activate_rtp(struct private_object *tech_pvt) +{ + int r = 0; + + if (tech_pvt->transports[LDL_TPORT_RTP].ready) { + r += activate_audio_rtp(tech_pvt); + } + + if (tech_pvt->transports[LDL_TPORT_VIDEO_RTP].ready) { + r += activate_video_rtp(tech_pvt); + } + + return r; +} + + +static int do_tport_candidates(struct private_object *tech_pvt, ldl_transport_type_t ttype, ldl_candidate_t *cand, int force) { switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session); + char *advip = tech_pvt->profile->extip ? tech_pvt->profile->extip : tech_pvt->profile->ip; + char *err = NULL, *address = NULL; + + if (!force && tech_pvt->transports[ttype].ready) { + return 0; + } + + if (switch_test_flag(tech_pvt, TFLAG_LANADDR)) { + advip = tech_pvt->profile->ip; + } + address = advip; + + if(address && !strncasecmp(address, "host:", 5)) { + address = address + 5; + } + + memset(cand, 0, sizeof(*cand)); + switch_stun_random_string(tech_pvt->transports[ttype].local_user, 16, NULL); + switch_stun_random_string(tech_pvt->transports[ttype].local_pass, 16, NULL); + + cand->port = tech_pvt->transports[ttype].adv_local_port; + cand->address = address; + + if (!strncasecmp(advip, "stun:", 5)) { + char *stun_ip = advip + 5; + + if (tech_pvt->transports[ttype].stun_ip) { + cand->address = tech_pvt->transports[ttype].stun_ip; + cand->port = tech_pvt->transports[ttype].stun_port; + } else { + if (!stun_ip) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Stun Failed! NO STUN SERVER!\n"); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return 0; + } + + cand->address = tech_pvt->profile->ip; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Stun Lookup Local %s:%d\n", cand->address, + cand->port); + if (switch_stun_lookup + (&cand->address, &cand->port, stun_ip, SWITCH_STUN_DEFAULT_PORT, &err, + switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Stun Failed! %s:%d [%s]\n", stun_ip, + SWITCH_STUN_DEFAULT_PORT, err); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return 0; + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "Stun Success %s:%d\n", cand->address, cand->port); + } + cand->type = "stun"; + tech_pvt->transports[ttype].stun_ip = switch_core_session_strdup(tech_pvt->session, cand->address); + tech_pvt->transports[ttype].stun_port = cand->port; + } else { + cand->type = "local"; + } + + cand->name = (char *)ldl_transport_type_str(ttype); + cand->username = tech_pvt->transports[ttype].local_user; + cand->password = tech_pvt->transports[ttype].local_pass; + cand->pref = 1; + cand->protocol = "udp"; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, + "Send %s Candidate %s:%d [%s]\n", ldl_transport_type_str(ttype), cand->address, cand->port, + cand->username); + + + + tech_pvt->transports[ttype].ready = 1; + + return 1; +} + + +static int do_candidates(struct private_object *tech_pvt, int force) +{ + ldl_candidate_t cand[4] = {{0}}; + int idx = 0; if (switch_test_flag(tech_pvt, TFLAG_DO_CAND)) { return 1; } tech_pvt->next_cand += DL_CAND_WAIT; - if (switch_test_flag(tech_pvt, TFLAG_BYE)) { + if (switch_test_flag(tech_pvt, TFLAG_BYE) || !tech_pvt->dlsession) { return 0; } switch_set_flag_locked(tech_pvt, TFLAG_DO_CAND); - if (force || !switch_test_flag(tech_pvt, TFLAG_RTP_READY)) { - ldl_candidate_t cand[1]; - char *advip = tech_pvt->profile->extip ? tech_pvt->profile->extip : tech_pvt->profile->ip; - char *err = NULL, *address = NULL; - - memset(cand, 0, sizeof(cand)); - switch_stun_random_string(tech_pvt->local_user, 16, NULL); - switch_stun_random_string(tech_pvt->local_pass, 16, NULL); - - if (switch_test_flag(tech_pvt, TFLAG_LANADDR)) { - advip = tech_pvt->profile->ip; - } - address = advip; - - if(address && !strncasecmp(address, "host:", 5)) { - address = address + 5; - } - - cand[0].port = tech_pvt->adv_local_port; - cand[0].address = address; - - if (!strncasecmp(advip, "stun:", 5)) { - char *stun_ip = advip + 5; - - if (tech_pvt->stun_ip) { - cand[0].address = tech_pvt->stun_ip; - cand[0].port = tech_pvt->stun_port; - } else { - if (!stun_ip) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Stun Failed! NO STUN SERVER!\n"); - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return 0; - } - - cand[0].address = tech_pvt->profile->ip; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Stun Lookup Local %s:%d\n", cand[0].address, - cand[0].port); - if (switch_stun_lookup - (&cand[0].address, &cand[0].port, stun_ip, SWITCH_STUN_DEFAULT_PORT, &err, - switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Stun Failed! %s:%d [%s]\n", stun_ip, - SWITCH_STUN_DEFAULT_PORT, err); - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return 0; - } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "Stun Success %s:%d\n", cand[0].address, cand[0].port); - } - cand[0].type = "stun"; - tech_pvt->stun_ip = switch_core_session_strdup(tech_pvt->session, cand[0].address); - tech_pvt->stun_port = cand[0].port; - } else { - cand[0].type = "local"; - } - - cand[0].name = "rtp"; - cand[0].username = tech_pvt->local_user; - cand[0].password = tech_pvt->local_pass; - cand[0].pref = 1; - cand[0].protocol = "udp"; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Send Candidate %s:%d [%s]\n", cand[0].address, cand[0].port, - cand[0].username); + idx += do_tport_candidates(tech_pvt, LDL_TPORT_RTP, &cand[idx], force); + idx += do_tport_candidates(tech_pvt, LDL_TPORT_RTCP, &cand[idx], force); + idx += do_tport_candidates(tech_pvt, LDL_TPORT_VIDEO_RTP, &cand[idx], force); + idx += do_tport_candidates(tech_pvt, LDL_TPORT_VIDEO_RTCP, &cand[idx], force); + if (idx && cand[0].name) { if (ldl_session_gateway(tech_pvt->dlsession) && switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - tech_pvt->cand_id = ldl_session_transport(tech_pvt->dlsession, cand, 1); + tech_pvt->cand_id = ldl_session_transport(tech_pvt->dlsession, cand, idx); } else { - tech_pvt->cand_id = ldl_session_candidates(tech_pvt->dlsession, cand, 1); + tech_pvt->cand_id = ldl_session_candidates(tech_pvt->dlsession, cand, idx); } + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Accepted %u of %u rtp candidates.\n", + tech_pvt->transports[LDL_TPORT_RTP].accepted, tech_pvt->transports[LDL_TPORT_RTP].total); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Accepted %u of %u rtcp candidates.\n", + tech_pvt->transports[LDL_TPORT_RTCP].accepted, tech_pvt->transports[LDL_TPORT_RTCP].total); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Accepted %u of %u video_rtp candidates\n", + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].accepted, tech_pvt->transports[LDL_TPORT_VIDEO_RTP].total); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Accepted %u of %u video_rctp candidates\n", + tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].accepted, tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].total); + + + + if ((tech_pvt->transports[LDL_TPORT_RTP].ready && tech_pvt->transports[LDL_TPORT_RTCP].ready)) { switch_set_flag_locked(tech_pvt, TFLAG_TRANSPORT); switch_set_flag_locked(tech_pvt, TFLAG_RTP_READY); } + + switch_clear_flag_locked(tech_pvt, TFLAG_DO_CAND); return 1; + } + + + static char *lame(char *in) { if (!strncasecmp(in, "ilbc", 4)) { @@ -1078,25 +1593,124 @@ static char *lame(char *in) } } + +static void setup_codecs(struct private_object *tech_pvt) +{ + ldl_payload_t payloads[LDL_MAX_PAYLOADS] = { {0} }; + int idx = 0, i = 0; + int dft_audio = -1, dft_video = -1; + + memset(payloads, 0, sizeof(payloads)); + + for (idx = 0; idx < tech_pvt->num_codecs && (dft_audio == -1 || dft_video == -1); idx++) { + if (dft_audio < 0 && tech_pvt->codecs[idx]->codec_type == SWITCH_CODEC_TYPE_AUDIO) { + dft_audio = idx; + } + if (dft_video < 0 && tech_pvt->codecs[idx]->codec_type == SWITCH_CODEC_TYPE_VIDEO) { + dft_video = idx; + } + } + + if (dft_audio == -1 && dft_video == -1) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Cannot find a codec.\n"); + return; + } + + idx = 0; + + payloads[0].type = LDL_TPORT_RTP; + if (tech_pvt->transports[LDL_TPORT_RTP].codec_index < 0) { + if (dft_audio > -1) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Don't have my audio codec yet here's one\n"); + tech_pvt->transports[LDL_TPORT_RTP].codec_name = lame(tech_pvt->codecs[dft_audio]->iananame); + tech_pvt->transports[LDL_TPORT_RTP].codec_num = tech_pvt->codecs[dft_audio]->ianacode; + tech_pvt->transports[LDL_TPORT_RTP].codec_rate = tech_pvt->codecs[dft_audio]->samples_per_second; + tech_pvt->transports[LDL_TPORT_RTP].r_codec_num = tech_pvt->codecs[dft_audio]->ianacode; + tech_pvt->transports[LDL_TPORT_RTP].codec_index = dft_audio; + + payloads[0].name = lame(tech_pvt->codecs[dft_audio]->iananame); + payloads[0].id = tech_pvt->codecs[dft_audio]->ianacode; + payloads[0].rate = tech_pvt->codecs[dft_audio]->samples_per_second; + payloads[0].bps = tech_pvt->codecs[dft_audio]->bits_per_second; + payloads[0].ptime = tech_pvt->codecs[dft_audio]->microseconds_per_packet / 1000; + idx++; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Don't have an audio codec.\n"); + } + } else { + payloads[0].name = lame(tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_RTP].codec_index]->iananame); + payloads[0].id = tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_RTP].codec_index]->ianacode; + payloads[0].rate = tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_RTP].codec_index]->samples_per_second; + payloads[0].bps = tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_RTP].codec_index]->bits_per_second; + payloads[0].ptime = tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_RTP].codec_index]->microseconds_per_packet / 1000; + idx++; + } + + + payloads[1].type = LDL_TPORT_VIDEO_RTP; + if (tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_index < 0) { + if (dft_video > -1) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Don't have my video codec yet here's one\n"); + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_name = lame(tech_pvt->codecs[dft_video]->iananame); + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_num = tech_pvt->codecs[dft_video]->ianacode; + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_rate = tech_pvt->codecs[dft_video]->samples_per_second; + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].r_codec_num = tech_pvt->codecs[dft_video]->ianacode; + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_index = dft_video; + + payloads[1].name = lame(tech_pvt->codecs[dft_video]->iananame); + payloads[1].id = tech_pvt->codecs[dft_video]->ianacode; + payloads[1].rate = tech_pvt->codecs[dft_video]->samples_per_second; + payloads[1].bps = tech_pvt->codecs[dft_video]->bits_per_second; + payloads[1].width = 600; + payloads[1].height = 400; + payloads[1].framerate = 30; + + idx++; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Don't have video codec.\n"); + } + } else { + payloads[1].name = lame(tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_index]->iananame); + payloads[1].id = tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_index]->ianacode; + payloads[1].rate = tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_index]->samples_per_second; + payloads[1].bps = tech_pvt->codecs[tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_index]->bits_per_second; + idx++; + } + + for(i = 0; i < idx; i++) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Send Describe [%s@%d]\n", payloads[i].name, payloads[i].rate); + } + + + if (!payloads[1].id) { + switch_rtp_release_port(tech_pvt->profile->ip, tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port); + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port = 0; + } + + + tech_pvt->desc_id = ldl_session_describe(tech_pvt->dlsession, payloads, idx, + switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ? LDL_DESCRIPTION_INITIATE : LDL_DESCRIPTION_ACCEPT, + &tech_pvt->transports[LDL_TPORT_RTP].ssrc, &tech_pvt->transports[LDL_TPORT_VIDEO_RTP].ssrc, + tech_pvt->transports[LDL_TPORT_RTP].local_crypto_data, + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_crypto_data); + + +} + static int do_describe(struct private_object *tech_pvt, int force) { - ldl_payload_t payloads[5]; if (!tech_pvt->session) { return 0; } - if (switch_test_flag(tech_pvt, TFLAG_DO_DESC)) { - return 1; - } - tech_pvt->next_desc += DL_CAND_WAIT; if (switch_test_flag(tech_pvt, TFLAG_BYE)) { return 0; } - memset(payloads, 0, sizeof(payloads)); + switch_set_flag_locked(tech_pvt, TFLAG_DO_CAND); if (!get_codecs(tech_pvt)) { terminate_session(&tech_pvt->session, __LINE__, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); @@ -1107,31 +1721,7 @@ static int do_describe(struct private_object *tech_pvt, int force) if (force || !switch_test_flag(tech_pvt, TFLAG_CODEC_READY)) { - if (tech_pvt->codec_index < 0) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), 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->codec_rate = tech_pvt->codecs[0]->samples_per_second; - 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[tech_pvt->codec_index]->samples_per_second; - payloads[0].bps = tech_pvt->codecs[tech_pvt->codec_index]->bits_per_second; - } - - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), 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); + setup_codecs(tech_pvt); switch_set_flag_locked(tech_pvt, TFLAG_CODEC_READY); } switch_clear_flag_locked(tech_pvt, TFLAG_DO_CAND); @@ -1167,8 +1757,8 @@ static switch_status_t negotiate_media(switch_core_session_t *session) while (!(switch_test_flag(tech_pvt, TFLAG_CODEC_READY) && switch_test_flag(tech_pvt, TFLAG_RTP_READY) && - switch_test_flag(tech_pvt, TFLAG_ANSWER) && switch_test_flag(tech_pvt, TFLAG_TRANSPORT_ACCEPT) && - tech_pvt->remote_ip && tech_pvt->remote_port && switch_test_flag(tech_pvt, TFLAG_TRANSPORT))) { + switch_test_flag(tech_pvt, TFLAG_ANSWER) && switch_test_flag(tech_pvt, TFLAG_TRANSPORT_ACCEPT) && //tech_pvt->read_count && + tech_pvt->transports[LDL_TPORT_RTP].remote_ip && tech_pvt->transports[LDL_TPORT_RTP].remote_port && switch_test_flag(tech_pvt, TFLAG_TRANSPORT))) { now = switch_micro_time_now(); elapsed = (unsigned int) ((now - started) / 1000); @@ -1195,10 +1785,20 @@ static switch_status_t negotiate_media(switch_core_session_t *session) switch_clear_flag_locked(tech_pvt, TFLAG_IO); goto done; } + if (switch_test_flag(tech_pvt, TFLAG_BYE) || !switch_test_flag(tech_pvt, TFLAG_IO)) { goto done; } - switch_cond_next(); + + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_RTP].rtp_session)) { + switch_rtp_ping(tech_pvt->transports[LDL_TPORT_RTP].rtp_session); + } + + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session)) { + switch_rtp_ping(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session); + } + + switch_yield(20000); } if (switch_channel_down(channel) || switch_test_flag(tech_pvt, TFLAG_BYE)) { @@ -1219,6 +1819,9 @@ static switch_status_t negotiate_media(switch_core_session_t *session) } ret = SWITCH_STATUS_SUCCESS; + switch_channel_audio_sync(channel); + + goto done; out: @@ -1241,7 +1844,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session) tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); - tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN; + tech_pvt->transports[LDL_TPORT_RTP].read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN; switch_set_flag(tech_pvt, TFLAG_READY); @@ -1295,23 +1898,37 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session) tech_pvt = switch_core_session_get_private(session); if (tech_pvt) { - if (tech_pvt->rtp_session) { - switch_rtp_destroy(&tech_pvt->rtp_session); + if (tech_pvt->transports[LDL_TPORT_RTP].rtp_session) { + switch_rtp_destroy(&tech_pvt->transports[LDL_TPORT_RTP].rtp_session); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "NUKE RTP\n"); - tech_pvt->rtp_session = NULL; + tech_pvt->transports[LDL_TPORT_RTP].rtp_session = NULL; + } + + if (tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session) { + switch_rtp_destroy(&tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "NUKE RTP\n"); + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session = NULL; } if (switch_test_flag(tech_pvt, TFLAG_NAT_MAP)) { - switch_nat_del_mapping((switch_port_t) tech_pvt->adv_local_port, SWITCH_NAT_UDP); + switch_nat_del_mapping((switch_port_t) tech_pvt->transports[LDL_TPORT_RTP].adv_local_port, SWITCH_NAT_UDP); switch_clear_flag(tech_pvt, TFLAG_NAT_MAP); } - if (switch_core_codec_ready(&tech_pvt->read_codec)) { - switch_core_codec_destroy(&tech_pvt->read_codec); + if (switch_core_codec_ready(&tech_pvt->transports[LDL_TPORT_RTP].read_codec)) { + switch_core_codec_destroy(&tech_pvt->transports[LDL_TPORT_RTP].read_codec); } - if (switch_core_codec_ready(&tech_pvt->write_codec)) { - switch_core_codec_destroy(&tech_pvt->write_codec); + if (switch_core_codec_ready(&tech_pvt->transports[LDL_TPORT_RTP].write_codec)) { + switch_core_codec_destroy(&tech_pvt->transports[LDL_TPORT_RTP].write_codec); + } + + if (switch_core_codec_ready(&tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec)) { + switch_core_codec_destroy(&tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec); + } + + if (switch_core_codec_ready(&tech_pvt->transports[LDL_TPORT_RTP].write_codec)) { + switch_core_codec_destroy(&tech_pvt->transports[LDL_TPORT_RTP].write_codec); } if (tech_pvt->dlsession) { @@ -1340,8 +1957,12 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); - if (tech_pvt->profile->ip && tech_pvt->local_port) { - switch_rtp_release_port(tech_pvt->profile->ip, tech_pvt->local_port); + if (tech_pvt->profile->ip && tech_pvt->transports[LDL_TPORT_RTP].local_port) { + switch_rtp_release_port(tech_pvt->profile->ip, tech_pvt->transports[LDL_TPORT_RTP].local_port); + } + + if (tech_pvt->profile->ip && tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port) { + switch_rtp_release_port(tech_pvt->profile->ip, tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port); } switch_clear_flag_locked(tech_pvt, TFLAG_IO); @@ -1382,13 +2003,13 @@ static switch_status_t channel_kill_channel(switch_core_session_t *session, int switch_clear_flag_locked(tech_pvt, TFLAG_VOICE); switch_set_flag_locked(tech_pvt, TFLAG_BYE); - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_rtp_kill_socket(tech_pvt->rtp_session); + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_RTP].rtp_session)) { + switch_rtp_kill_socket(tech_pvt->transports[LDL_TPORT_RTP].rtp_session); } break; case SWITCH_SIG_BREAK: - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK); + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_RTP].rtp_session)) { + switch_rtp_set_flag(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, SWITCH_RTP_FLAG_BREAK); } break; } @@ -1421,7 +2042,7 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, const s switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "DTMF [%c]\n", dtmf->digit); - return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, dtmf); + return switch_rtp_queue_rfc2833(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, dtmf); } @@ -1434,7 +2055,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch tech_pvt = (struct private_object *) switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); - while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) { + while (!(tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation && switch_rtp_ready(tech_pvt->transports[LDL_TPORT_RTP].rtp_session))) { if (switch_channel_ready(channel)) { switch_yield(10000); } else { @@ -1443,7 +2064,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch } - tech_pvt->read_frame.datalen = 0; + tech_pvt->transports[LDL_TPORT_RTP].read_frame.datalen = 0; switch_set_flag_locked(tech_pvt, TFLAG_READING); #if 0 @@ -1457,23 +2078,25 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch if (switch_test_flag(tech_pvt, TFLAG_IO)) { - switch_status_t status; - - switch_assert(tech_pvt->rtp_session != NULL); - tech_pvt->read_frame.datalen = 0; + //switch_status_t status; + + switch_assert(tech_pvt->transports[LDL_TPORT_RTP].rtp_session != NULL); + tech_pvt->transports[LDL_TPORT_RTP].read_frame.datalen = 0; - while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) { - tech_pvt->read_frame.flags = SFF_NONE; + while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->transports[LDL_TPORT_RTP].read_frame.datalen == 0) { + tech_pvt->transports[LDL_TPORT_RTP].read_frame.flags = SFF_NONE; - status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags); - if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { - return SWITCH_STATUS_FALSE; + switch_rtp_zerocopy_read_frame(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, &tech_pvt->transports[LDL_TPORT_RTP].read_frame, flags); + + tech_pvt->read_count++; +#if 0 + if (tech_pvt->read_count == 1 && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + setup_codecs(tech_pvt); } +#endif - - - //payload = tech_pvt->read_frame.payload; + //payload = tech_pvt->transports[LDL_TPORT_RTP].read_frame.payload; #if 0 elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000); @@ -1489,22 +2112,22 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch return SWITCH_STATUS_BREAK; } #endif - if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { + if (switch_rtp_has_dtmf(tech_pvt->transports[LDL_TPORT_RTP].rtp_session)) { switch_dtmf_t dtmf = { 0 }; - switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf); + switch_rtp_dequeue_dtmf(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, &dtmf); switch_channel_queue_dtmf(channel, &dtmf); } - if (tech_pvt->read_frame.datalen > 0) { + if (tech_pvt->transports[LDL_TPORT_RTP].read_frame.datalen > 0) { size_t bytes = 0; int frames = 1; - if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) { - if ((bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_packet)) { - frames = (tech_pvt->read_frame.datalen / bytes); + if (!switch_test_flag((&tech_pvt->transports[LDL_TPORT_RTP].read_frame), SFF_CNG)) { + if ((bytes = tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->encoded_bytes_per_packet)) { + frames = (tech_pvt->transports[LDL_TPORT_RTP].read_frame.datalen / bytes); } - tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_codec.implementation->samples_per_packet); + tech_pvt->transports[LDL_TPORT_RTP].read_frame.samples = (int) (frames * tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->samples_per_packet); } break; } @@ -1513,12 +2136,12 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch switch_clear_flag_locked(tech_pvt, TFLAG_READING); - if (tech_pvt->read_frame.datalen == 0) { - *frame = NULL; - return SWITCH_STATUS_GENERR; + if (tech_pvt->transports[LDL_TPORT_RTP].read_frame.datalen == 0) { + switch_set_flag((&tech_pvt->transports[LDL_TPORT_RTP].read_frame), SFF_CNG); + tech_pvt->transports[LDL_TPORT_RTP].read_frame.datalen = 2; } - *frame = &tech_pvt->read_frame; + *frame = &tech_pvt->transports[LDL_TPORT_RTP].read_frame; return SWITCH_STATUS_SUCCESS; } @@ -1533,7 +2156,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc tech_pvt = (struct private_object *) switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); - while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) { + while (!(tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation && switch_rtp_ready(tech_pvt->transports[LDL_TPORT_RTP].rtp_session))) { if (switch_channel_ready(channel)) { switch_yield(10000); } else { @@ -1541,7 +2164,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc } } - if (!switch_core_codec_ready(&tech_pvt->read_codec) || !tech_pvt->read_codec.implementation) { + if (!switch_core_codec_ready(&tech_pvt->transports[LDL_TPORT_RTP].read_codec) || !tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation) { return SWITCH_STATUS_GENERR; } @@ -1552,13 +2175,13 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc switch_set_flag_locked(tech_pvt, TFLAG_WRITING); if (!switch_test_flag(frame, SFF_CNG)) { - if (tech_pvt->read_codec.implementation->encoded_bytes_per_packet) { - bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_packet; + if (tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->encoded_bytes_per_packet) { + bytes = tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->encoded_bytes_per_packet; frames = ((int) frame->datalen / bytes); } else frames = 1; - samples = frames * tech_pvt->read_codec.implementation->samples_per_packet; + samples = frames * tech_pvt->transports[LDL_TPORT_RTP].read_codec.implementation->samples_per_packet; } #if 0 printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n", @@ -1567,8 +2190,8 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc #endif tech_pvt->timestamp_send += samples; - //switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send); - if (switch_rtp_write_frame(tech_pvt->rtp_session, frame) < 0) { + //switch_rtp_write_frame(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, frame, tech_pvt->timestamp_send); + if (switch_rtp_write_frame(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, frame) < 0) { status = SWITCH_STATUS_GENERR; } @@ -1576,6 +2199,74 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc return status; } + +static switch_status_t channel_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) +{ + struct private_object *tech_pvt = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + //int payload = 0; + //switch_status_t status; + + tech_pvt = (struct private_object *) switch_core_session_get_private(session); + switch_assert(tech_pvt != NULL); + + if (!switch_test_flag(tech_pvt, TFLAG_IO)) { + return SWITCH_STATUS_GENERR; + } + + while (!(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation && switch_rtp_ready(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session))) { + if (switch_channel_ready(channel)) { + switch_yield(10000); + } else { + return SWITCH_STATUS_GENERR; + } + } + + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame.datalen = 0; + + while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame.datalen == 0) { + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame.flags = SFF_NONE; + switch_rtp_zerocopy_read_frame(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session, &tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame, flags); + } + + + if (tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame.datalen == 0) { + switch_set_flag((&tech_pvt->transports[LDL_TPORT_RTP].read_frame), SFF_CNG); + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame.datalen = 2; + } + + *frame = &tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_frame; + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +{ + struct private_object *tech_pvt = (struct private_object *)switch_core_session_get_private(session); + switch_channel_t *channel = switch_core_session_get_channel(session); + int wrote = 0; + + switch_assert(tech_pvt != NULL); + + while (!(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].read_codec.implementation && switch_rtp_ready(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session))) { + if (switch_channel_ready(channel)) { + switch_yield(10000); + } else { + return SWITCH_STATUS_GENERR; + } + } + + if (!switch_test_flag(tech_pvt, TFLAG_IO)) { + return SWITCH_STATUS_SUCCESS; + } + + if (!switch_test_flag(frame, SFF_CNG)) { + wrote = switch_rtp_write_frame(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].rtp_session, frame); + } + + return wrote > 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_GENERR; +} + static switch_status_t channel_answer_channel(switch_core_session_t *session) { struct private_object *tech_pvt; @@ -1603,10 +2294,13 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s channel_answer_channel(session); break; case SWITCH_MESSAGE_INDICATE_BRIDGE: - rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_STICK); + rtp_flush_read_buffer(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, SWITCH_RTP_FLUSH_STICK); break; case SWITCH_MESSAGE_INDICATE_UNBRIDGE: - rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_UNSTICK); + rtp_flush_read_buffer(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, SWITCH_RTP_FLUSH_UNSTICK); + break; + case SWITCH_MESSAGE_INDICATE_STUN_ERROR: + //switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_NORMAL_CLEARING); break; default: break; @@ -1654,12 +2348,15 @@ switch_state_handler_table_t dingaling_event_handlers = { switch_io_routines_t dingaling_io_routines = { /*.outgoing_channel */ channel_outgoing_channel, - /*.read_frame */ channel_read_frame, + /*.transports[LDL_TPORT_RTP].read_frame */ channel_read_frame, /*.write_frame */ channel_write_frame, /*.kill_channel */ channel_kill_channel, /*.send_dtmf */ channel_send_dtmf, /*.receive_message */ channel_receive_message, - /*.receive_event */ channel_receive_event + /*.receive_event */ channel_receive_event, + /*.state_change */ NULL, + /*.read_video_frame */ channel_read_video_frame, + /*.write_video_frame */ channel_write_video_frame }; @@ -1688,6 +2385,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi char *p, *u, ubuf[512] = "", *user = NULL, *f_cid_msg = NULL; const char *cid_msg = NULL; ldl_user_flag_t flags = LDL_FLAG_OUTBOUND; + const char *var; switch_copy_string(workspace, outbound_profile->destination_number, sizeof(workspace)); profile_name = workspace; @@ -1781,13 +2479,30 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi channel = switch_core_session_get_channel(*new_session); switch_core_session_set_private(*new_session, tech_pvt); tech_pvt->session = *new_session; - tech_pvt->codec_index = -1; - if (!(tech_pvt->local_port = switch_rtp_request_port(mdl_profile->ip))) { + tech_pvt->channel = switch_core_session_get_channel(tech_pvt->session); + tech_pvt->transports[LDL_TPORT_RTP].codec_index = -1; + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_index = -1; + + mdl_build_crypto(tech_pvt, LDL_TPORT_RTP, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); + mdl_build_crypto(tech_pvt, LDL_TPORT_VIDEO_RTP, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); + + if (!(tech_pvt->transports[LDL_TPORT_RTP].local_port = switch_rtp_request_port(mdl_profile->ip))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "No RTP port available!\n"); terminate_session(new_session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } - tech_pvt->adv_local_port = tech_pvt->local_port; + tech_pvt->transports[LDL_TPORT_RTP].adv_local_port = tech_pvt->transports[LDL_TPORT_RTP].local_port; + tech_pvt->transports[LDL_TPORT_RTCP].adv_local_port = tech_pvt->transports[LDL_TPORT_RTP].local_port + 1; + if (!(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port = switch_rtp_request_port(mdl_profile->ip))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "No RTP port available!\n"); + terminate_session(new_session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].adv_local_port = tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port; + tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].adv_local_port = tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port + 1; + + + tech_pvt->recip = switch_core_session_strdup(*new_session, full_id); if (dnis) { tech_pvt->dnis = switch_core_session_strdup(*new_session, dnis); @@ -1854,6 +2569,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ldl_session_set_value(dlsession, "caller_id_name", outbound_profile->caller_id_name); ldl_session_set_value(dlsession, "caller_id_number", outbound_profile->caller_id_number); tech_pvt->dlsession = dlsession; + + if ((var = switch_event_get_header(var_event, "absolute_codec_string"))) { + switch_channel_set_variable(channel, "absolute_codec_string", var); + } + if (!get_codecs(tech_pvt)) { terminate_session(new_session, __LINE__, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL); return SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL; @@ -2117,6 +2837,8 @@ static void set_profile_val(mdl_profile_t *profile, char *var, char *val) } else if (val && !strcasecmp(val, "md5")) { profile->user_flags |= LDL_FLAG_SASL_MD5; } + } else if (!strcasecmp(var, "use-jingle") && !zstr(val)) { + profile->user_flags |= LDL_FLAG_JINGLE; } else if (!strcasecmp(var, "exten") && !zstr(val)) { profile->exten = switch_core_strdup(module_pool, val); } else if (!strcasecmp(var, "context") && !zstr(val)) { @@ -2757,6 +3479,308 @@ static void do_vcard(ldl_handle_t *handle, char *to, char *from, char *id) switch_safe_free(xmlstr); } +static switch_status_t parse_candidates(ldl_session_t *dlsession, switch_core_session_t *session, ldl_transport_type_t ttype, const char *subject) +{ + + ldl_candidate_t *candidates; + unsigned int len = 0; + unsigned int x, choice = 0, ok = 0; + uint8_t lanaddr = 0; + struct private_object *tech_pvt = NULL; + switch_status_t status = LDL_STATUS_SUCCESS; + + if (!(tech_pvt = switch_core_session_get_private(session))) { + return SWITCH_STATUS_FALSE; + } + + if (ldl_session_get_candidates(dlsession, ttype, &candidates, &len) != LDL_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Candidate Error!\n"); + switch_set_flag(tech_pvt, TFLAG_BYE); + switch_clear_flag(tech_pvt, TFLAG_IO); + status = LDL_STATUS_FALSE; + goto end; + } + + + tech_pvt->transports[ttype].total = len; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%u %s candidates\n", len, ldl_transport_type_str(ttype)); + + if (tech_pvt->profile->acl_count) { + for (x = 0; x < len; x++) { + uint32_t y = 0; + + if (strcasecmp(candidates[x].protocol, "udp")) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d has an unsupported protocol!\n", + candidates[x].address, candidates[x].port); + continue; + } + + for (y = 0; y < tech_pvt->profile->acl_count; y++) { + + if (switch_check_network_list_ip(candidates[x].address, tech_pvt->profile->acl[y])) { + choice = x; + ok = 1; + } + + if (ok) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d PASS ACL %s\n", + candidates[x].address, candidates[x].port, tech_pvt->profile->acl[y]); + goto end_candidates; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d FAIL ACL %s\n", + candidates[x].address, candidates[x].port, tech_pvt->profile->acl[y]); + } + } + } + } else { + for (x = 0; x < len; x++) { + + + if (tech_pvt->profile->lanaddr) { + lanaddr = strncasecmp(candidates[x].address, tech_pvt->profile->lanaddr, strlen(tech_pvt->profile->lanaddr)) ? 0 : 1; + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s candidates %s:%d\n", + ldl_transport_type_str(ttype), candidates[x].address, + candidates[x].port); + + + // 192.0.0.0 - 192.0.127.255 is marked as reserved, should we filter all of them? + if (!strcasecmp(candidates[x].protocol, "udp") && + (!strcasecmp(candidates[x].type, "local") || !strcasecmp(candidates[x].type, "stun") || !strcasecmp(candidates[x].type, "drelay")) && + ((tech_pvt->profile->lanaddr && + lanaddr) || (strncasecmp(candidates[x].address, "10.", 3) && + strncasecmp(candidates[x].address, "192.168.", 8) && + strncasecmp(candidates[x].address, "127.", 4) && + strncasecmp(candidates[x].address, "255.", 4) && + strncasecmp(candidates[x].address, "0.", 2) && + strncasecmp(candidates[x].address, "1.", 2) && + strncasecmp(candidates[x].address, "2.", 2) && + strncasecmp(candidates[x].address, "172.16.", 7) && + strncasecmp(candidates[x].address, "172.17.", 7) && + strncasecmp(candidates[x].address, "172.18.", 7) && + strncasecmp(candidates[x].address, "172.19.", 7) && + strncasecmp(candidates[x].address, "172.2", 5) && + strncasecmp(candidates[x].address, "172.30.", 7) && + strncasecmp(candidates[x].address, "172.31.", 7) && + strncasecmp(candidates[x].address, "192.0.2.", 8) && strncasecmp(candidates[x].address, "169.254.", 8) + ))) { + choice = x; + ok = 1; + } + } + } + + + end_candidates: + + if (ok) { + ldl_payload_t payloads[5]; + char *key; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "Acceptable %s Candidate %s:%d\n", ldl_transport_type_str(ttype), candidates[choice].address, candidates[choice].port); + + + if (tech_pvt->transports[ttype].accepted) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already Accepted [%s:%d]\n", + tech_pvt->transports[ttype].remote_ip, tech_pvt->transports[ttype].remote_port); + goto end; + } + + + if (tech_pvt->transports[ttype].remote_ip) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already picked an IP [%s]\n", tech_pvt->transports[ttype].remote_ip); + goto end; + } + + + memset(payloads, 0, sizeof(payloads)); + + tech_pvt->transports[ttype].accepted++; + + if (ttype == LDL_TPORT_VIDEO_RTP) { + if ((key = ldl_session_get_value(dlsession, "video:crypto:1"))) { + mdl_add_crypto(tech_pvt, ttype, key, SWITCH_RTP_CRYPTO_RECV); + } else { + tech_pvt->transports[ttype].crypto_type = 0; + } + } else if (ttype == LDL_TPORT_RTP) { + if ((key = ldl_session_get_value(dlsession, "audio:crypto:1"))) { + mdl_add_crypto(tech_pvt, ttype, key, SWITCH_RTP_CRYPTO_RECV); + } else { + tech_pvt->transports[ttype].crypto_type = 0; + } + } + + if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + switch_set_flag_locked(tech_pvt, TFLAG_TRANSPORT_ACCEPT); + //ldl_session_accept_candidate(dlsession, &candidates[choice]); + } + + if (!strcasecmp(subject, "candidates")) { + //switch_set_flag_locked(tech_pvt, TFLAG_TRANSPORT_ACCEPT); + switch_set_flag_locked(tech_pvt, TFLAG_ANSWER); + } + + if (lanaddr) { + switch_set_flag_locked(tech_pvt, TFLAG_LANADDR); + } + + if (!get_codecs(tech_pvt)) { + terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + status = LDL_STATUS_FALSE; + goto end; + } + + + tech_pvt->transports[ttype].remote_ip = switch_core_session_strdup(session, candidates[choice].address); + ldl_session_set_ip(dlsession, tech_pvt->transports[ttype].remote_ip); + tech_pvt->transports[ttype].remote_port = candidates[choice].port; + tech_pvt->transports[ttype].remote_user = switch_core_session_strdup(session, candidates[choice].username); + tech_pvt->transports[ttype].remote_pass = switch_core_session_strdup(session, candidates[choice].password); + + if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + if (!do_candidates(tech_pvt, 0)) { + terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + status = LDL_STATUS_FALSE; + + goto end; + } + } + + if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND) && (ttype == LDL_TPORT_VIDEO_RTP || ttype == LDL_TPORT_VIDEO_RTP) && + tech_pvt->transports[ttype].accepted == 1 && (1||switch_test_flag(tech_pvt, TFLAG_RTP_READY))) { + + if (ttype == LDL_TPORT_VIDEO_RTP) { + activate_video_rtp(tech_pvt); + } + + if (ttype == LDL_TPORT_VIDEO_RTP) { + activate_audio_rtp(tech_pvt); + } + + tech_pvt->transports[ttype].restart_rtp++; + } + + + status = LDL_STATUS_SUCCESS; + } + + end: + + return status; + +} + + +static ldl_status parse_payloads_type(ldl_session_t *dlsession, switch_core_session_t *session, + ldl_transport_type_t ttype, ldl_payload_t *payloads, unsigned int len) +{ + struct private_object *tech_pvt = NULL; + switch_status_t status = LDL_STATUS_SUCCESS; + unsigned int x, y; + int match = 0; + + tech_pvt = switch_core_session_get_private(session); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%u payloads\n", len); + for (x = 0; x < len; x++) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Available Payload %s %u\n", payloads[x].name, + payloads[x].id); + for (y = 0; y < tech_pvt->num_codecs; y++) { + char *name = tech_pvt->codecs[y]->iananame; + + if ((ttype == LDL_TPORT_VIDEO_RTP && tech_pvt->codecs[y]->codec_type != SWITCH_CODEC_TYPE_VIDEO) || + (ttype == LDL_TPORT_RTP && tech_pvt->codecs[y]->codec_type != SWITCH_CODEC_TYPE_AUDIO)) { + continue; + } + + if (!strncasecmp(name, "ilbc", 4)) { + name = "ilbc"; + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "compare %s %d/%d to %s %d/%d\n", + payloads[x].name, payloads[x].id, payloads[x].rate, + name, tech_pvt->codecs[y]->ianacode, tech_pvt->codecs[y]->samples_per_second); + + if (tech_pvt->codecs[y]->ianacode > 95) { + match = strcasecmp(name, payloads[x].name) ? 0 : 1; + } else { + match = (payloads[x].id == tech_pvt->codecs[y]->ianacode) ? 1 : 0; + } + + if (match && payloads[x].rate == tech_pvt->codecs[y]->samples_per_second) { + tech_pvt->transports[ttype].codec_index = y; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Choosing %s Payload index %u %s %u\n", + ldl_transport_type_str(ttype), + y, + payloads[x].name, payloads[x].id); + tech_pvt->transports[ttype].codec_name = tech_pvt->codecs[y]->iananame; + tech_pvt->transports[ttype].codec_num = tech_pvt->codecs[y]->ianacode; + tech_pvt->transports[ttype].r_codec_num = (switch_payload_t) (payloads[x].id); + tech_pvt->transports[ttype].codec_rate = payloads[x].rate; + tech_pvt->transports[ttype].ptime = payloads[x].ptime; + tech_pvt->transports[ttype].payload_count++; + + if (ttype == LDL_TPORT_VIDEO_RTP) { + tech_pvt->transports[ttype].vid_width = payloads[x].width; + tech_pvt->transports[ttype].vid_height = payloads[x].height; + tech_pvt->transports[ttype].vid_rate = payloads[x].framerate; + } + + if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + + + if (!do_describe(tech_pvt, 0)) { + terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + status = LDL_STATUS_FALSE; + goto done; + } + } + status = LDL_STATUS_SUCCESS; + goto done; + } + } + } + + done: + + return status; + +} + +static ldl_status parse_payloads(ldl_session_t *dlsession, switch_core_session_t *session, ldl_payload_t *payloads, unsigned int len) +{ + int match = 0; + struct private_object *tech_pvt = NULL; + ldl_status status; + + tech_pvt = switch_core_session_get_private(session); + + + if ((status = parse_payloads_type(dlsession, session, LDL_TPORT_RTP, payloads, len)) == LDL_STATUS_SUCCESS) { + match++; + } + + if (tech_pvt->transports[LDL_TPORT_VIDEO_RTP].ready) { + if ((status = parse_payloads_type(dlsession, session, LDL_TPORT_VIDEO_RTP, payloads, len)) == LDL_STATUS_SUCCESS) { + match++; + } + } + + if (!match && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + if (!do_describe(tech_pvt, 0)) { + terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + status = LDL_STATUS_FALSE; + } + } + + + return status; + +} + + static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsession, ldl_signal_t dl_signal, char *to, char *from, char *subject, char *msg) { @@ -3060,15 +4084,35 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi tech_pvt->dlsession = dlsession; tech_pvt->session = session; - tech_pvt->codec_index = -1; + tech_pvt->channel = switch_core_session_get_channel(session); + tech_pvt->transports[LDL_TPORT_RTP].codec_index = -1; + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].codec_index = -1; tech_pvt->profile = profile; - if (!(tech_pvt->local_port = switch_rtp_request_port(profile->ip))) { + + + mdl_build_crypto(tech_pvt, LDL_TPORT_RTP, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); + mdl_build_crypto(tech_pvt, LDL_TPORT_VIDEO_RTP, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); + + if (!(tech_pvt->transports[LDL_TPORT_RTP].local_port = switch_rtp_request_port(profile->ip))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "No RTP port available!\n"); terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); status = LDL_STATUS_FALSE; goto done; } - tech_pvt->adv_local_port = tech_pvt->local_port; + tech_pvt->transports[LDL_TPORT_RTP].adv_local_port = tech_pvt->transports[LDL_TPORT_RTP].local_port; + tech_pvt->transports[LDL_TPORT_RTCP].adv_local_port = tech_pvt->transports[LDL_TPORT_RTP].local_port + 1; + + if (!(tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port = switch_rtp_request_port(profile->ip))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "No RTP port available!\n"); + terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + status = LDL_STATUS_FALSE; + goto done; + } + tech_pvt->transports[LDL_TPORT_VIDEO_RTP].adv_local_port = tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port; + tech_pvt->transports[LDL_TPORT_VIDEO_RTCP].adv_local_port = tech_pvt->transports[LDL_TPORT_VIDEO_RTP].local_port + 1; + + + switch_set_flag_locked(tech_pvt, TFLAG_ANSWER); tech_pvt->recip = switch_core_session_strdup(session, from); if (!(exten = ldl_session_get_value(dlsession, "dnis"))) { @@ -3205,8 +4249,8 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi p++; } switch_set_flag_locked(tech_pvt, TFLAG_DTMF); - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK); + if (switch_rtp_ready(tech_pvt->transports[LDL_TPORT_RTP].rtp_session)) { + switch_rtp_set_flag(tech_pvt->transports[LDL_TPORT_RTP].rtp_session, SWITCH_RTP_FLAG_BREAK); } } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SESSION MSG [%s]\n", msg); @@ -3252,10 +4296,9 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi if (dl_signal) { ldl_payload_t *payloads; unsigned int len = 0; - int match = 0; - + if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - if (!strcasecmp(msg, "accept")) { + if (msg && !strcasecmp(msg, "accept")) { switch_set_flag_locked(tech_pvt, TFLAG_ANSWER); switch_set_flag_locked(tech_pvt, TFLAG_TRANSPORT_ACCEPT); if (!do_candidates(tech_pvt, 0)) { @@ -3266,7 +4309,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi } } - if (tech_pvt->codec_index > -1) { + if (tech_pvt->transports[LDL_TPORT_RTP].codec_index > -1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already decided on a codec\n"); break; } @@ -3278,55 +4321,9 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi goto done; } - if (ldl_session_get_payloads(dlsession, &payloads, &len) == LDL_STATUS_SUCCESS) { - unsigned int x, y; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%u payloads\n", len); - for (x = 0; x < len; x++) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Available Payload %s %u\n", payloads[x].name, - payloads[x].id); - for (y = 0; y < tech_pvt->num_codecs; y++) { - char *name = tech_pvt->codecs[y]->iananame; - - if (!strncasecmp(name, "ilbc", 4)) { - name = "ilbc"; - } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "compare %s %d/%d to %s %d/%d\n", - payloads[x].name, payloads[x].id, payloads[x].rate, - name, tech_pvt->codecs[y]->ianacode, tech_pvt->codecs[y]->samples_per_second); - if (tech_pvt->codecs[y]->ianacode > 95) { - match = strcasecmp(name, payloads[x].name) ? 0 : 1; - } else { - match = (payloads[x].id == tech_pvt->codecs[y]->ianacode) ? 1 : 0; - } - - if (match && payloads[x].rate == tech_pvt->codecs[y]->samples_per_second) { - tech_pvt->codec_index = y; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), 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 = (switch_payload_t) (payloads[x].id); - tech_pvt->codec_rate = payloads[x].rate; - if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - if (!do_describe(tech_pvt, 0)) { - terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - status = LDL_STATUS_FALSE; - goto done; - } - } - status = LDL_STATUS_SUCCESS; - goto done; - } - } - } - if (!match && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - if (!do_describe(tech_pvt, 0)) { - terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - status = LDL_STATUS_FALSE; - goto done; - } - } + status = parse_payloads(dlsession, session, payloads, len); + goto done; } } @@ -3334,141 +4331,14 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi break; case LDL_SIGNAL_CANDIDATES: if (dl_signal) { - ldl_candidate_t *candidates; - unsigned int len = 0; - unsigned int x, choice = 0, ok = 0; - uint8_t lanaddr = 0; - - if (ldl_session_get_candidates(dlsession, &candidates, &len) != LDL_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Candidate Error!\n"); - switch_set_flag(tech_pvt, TFLAG_BYE); - switch_clear_flag(tech_pvt, TFLAG_IO); - status = LDL_STATUS_FALSE; - goto done; - } - - - if (tech_pvt->remote_ip) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already picked an IP [%s]\n", tech_pvt->remote_ip); - break; - } - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%u candidates\n", len); - - if (profile->acl_count) { - for (x = 0; x < len; x++) { - uint32_t y = 0; - - if (strcasecmp(candidates[x].protocol, "udp")) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d has an unsupported protocol!\n", - candidates[x].address, candidates[x].port); - continue; - } - - for (y = 0; y < profile->acl_count; y++) { - - if (switch_check_network_list_ip(candidates[x].address, profile->acl[y])) { - choice = x; - ok = 1; - } - - if (ok) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d PASS ACL %s\n", - candidates[x].address, candidates[x].port, profile->acl[y]); - goto end_candidates; - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d FAIL ACL %s\n", - candidates[x].address, candidates[x].port, profile->acl[y]); - } - } - } - } else { - for (x = 0; x < len; x++) { - - if (profile->lanaddr) { - lanaddr = strncasecmp(candidates[x].address, profile->lanaddr, strlen(profile->lanaddr)) ? 0 : 1; - } - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidates %s:%d\n", candidates[x].address, - candidates[x].port); - - // 192.0.0.0 - 192.0.127.255 is marked as reserved, should we filter all of them? - if (!strcasecmp(candidates[x].protocol, "udp") && - (!strcasecmp(candidates[x].type, "local") || !strcasecmp(candidates[x].type, "stun")) && - ((profile->lanaddr && - lanaddr) || (strncasecmp(candidates[x].address, "10.", 3) && - strncasecmp(candidates[x].address, "192.168.", 8) && - strncasecmp(candidates[x].address, "127.", 4) && - strncasecmp(candidates[x].address, "255.", 4) && - strncasecmp(candidates[x].address, "0.", 2) && - strncasecmp(candidates[x].address, "1.", 2) && - strncasecmp(candidates[x].address, "2.", 2) && - strncasecmp(candidates[x].address, "172.16.", 7) && - strncasecmp(candidates[x].address, "172.17.", 7) && - strncasecmp(candidates[x].address, "172.18.", 7) && - strncasecmp(candidates[x].address, "172.19.", 7) && - strncasecmp(candidates[x].address, "172.2", 5) && - strncasecmp(candidates[x].address, "172.30.", 7) && - strncasecmp(candidates[x].address, "172.31.", 7) && - strncasecmp(candidates[x].address, "192.0.2.", 8) && strncasecmp(candidates[x].address, "169.254.", 8) - ))) { - choice = x; - ok = 1; - } - } - } - - end_candidates: - - if (ok) { - ldl_payload_t payloads[5]; - - memset(payloads, 0, sizeof(payloads)); - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "Acceptable Candidate %s:%d\n", candidates[choice].address, candidates[choice].port); - - if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - switch_set_flag_locked(tech_pvt, TFLAG_TRANSPORT_ACCEPT); - //ldl_session_accept_candidate(dlsession, &candidates[choice]); - } - - if (!strcasecmp(subject, "candidates")) { - //switch_set_flag_locked(tech_pvt, TFLAG_TRANSPORT_ACCEPT); - switch_set_flag_locked(tech_pvt, TFLAG_ANSWER); - } - - if (lanaddr) { - switch_set_flag_locked(tech_pvt, TFLAG_LANADDR); - } - - if (!get_codecs(tech_pvt)) { - terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - status = LDL_STATUS_FALSE; - goto done; - } - - - tech_pvt->remote_ip = switch_core_session_strdup(session, candidates[choice].address); - ldl_session_set_ip(dlsession, tech_pvt->remote_ip); - tech_pvt->remote_port = candidates[choice].port; - tech_pvt->remote_user = switch_core_session_strdup(session, candidates[choice].username); - - - if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - if (!do_candidates(tech_pvt, 0)) { - terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - status = LDL_STATUS_FALSE; - goto done; - } - } - - status = LDL_STATUS_SUCCESS; - } - - goto done; + status = SWITCH_STATUS_SUCCESS; + status = parse_candidates(dlsession, session, LDL_TPORT_RTP, subject); + status = parse_candidates(dlsession, session, LDL_TPORT_VIDEO_RTP, subject); + status = parse_candidates(dlsession, session, LDL_TPORT_RTCP, subject); + status = parse_candidates(dlsession, session, LDL_TPORT_VIDEO_RTCP, subject); } + break; case LDL_SIGNAL_REJECT: if (channel) {