]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
baseline
authorAnthony Minessale <anthm@freeswitch.org>
Tue, 18 Dec 2012 16:50:43 +0000 (10:50 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Mon, 1 Apr 2013 02:27:13 +0000 (21:27 -0500)
Makefile.am
src/include/switch_core_media.h [new file with mode: 0644]
src/mod/endpoints/mod_sofia/Makefile.am
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_glue.c
src/mod/endpoints/mod_sofia/sofia_media.c [new file with mode: 0644]
src/switch_core_media.c [new file with mode: 0644]

index c792e0caf4f9029196919474e22e4fb7a1d0e795..e219f0e9b0449e9dd73dc3ba25bef74de08b2752 100644 (file)
@@ -179,6 +179,7 @@ library_include_HEADERS = \
        src/include/switch_core_event_hook.h \
        src/include/switch_scheduler.h \
        src/include/switch_core.h \
+       src/include/switch_core_media.h \
        src/include/switch_core_db.h \
        src/include/switch_mprintf.h \
        src/include/switch_config.h \
@@ -240,6 +241,7 @@ libfreeswitch_la_SOURCES = \
        src/switch_core_rwlock.c \
        src/switch_core_port_allocator.c \
        src/switch_core.c \
+       src/switch_core_media.c \
        src/switch_scheduler.c \
        src/switch_core_db.c \
        src/switch_dso.c \
diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h
new file mode 100644 (file)
index 0000000..756895b
--- /dev/null
@@ -0,0 +1,51 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * switch_core_media.c -- Core Media
+ *
+ */
+
+#ifndef SWITCH_CORE_H
+#define SWITCH_CORE_H
+
+#include <switch.h>
+
+SWITCH_BEGIN_EXTERN_C
+
+
+SWITCH_END_EXTERN_C
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
index 7828c5eb49e33062b4f82d28a80a7d7a363c1a1e..9d98a976a3460db12487e38a96572c993579a4d3 100644 (file)
@@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua
 SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la
 
 mod_LTLIBRARIES = mod_sofia.la
-mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c rtp.c mod_sofia.h
+mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_media.c sip-dig.c rtp.c mod_sofia.h
 mod_sofia_la_CFLAGS  = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS)
 mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf
 mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http
index de32b2c7c3bfcb201e97f23faa138dcb97f3c666..5b41026526290f7b6c6b63ae4515481d1c8cd8dc 100644 (file)
@@ -1222,6 +1222,9 @@ switch_status_t sofia_init(void);
 void sofia_glue_fire_events(sofia_profile_t *profile);
 void sofia_event_fire(sofia_profile_t *profile, switch_event_t **event);
 void sofia_queue_message(sofia_dispatch_event_t *de);
+switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_session_t *sdp, sdp_media_t *m);
+void find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp);
+void sofia_media_set_sdp_codec_string(switch_core_session_t *session, const char *r_sdp);
 
 /* For Emacs:
  * Local Variables:
index 42593e40505d1476de3820db8a29d95f8efea735..1e9b1d8b4101447290cd8169e1d8efce2e80addc 100644 (file)
@@ -5642,8 +5642,6 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
                                                  switch_channel_get_name(channel), nua_callstate_name(ss_state), status);
 
                if (r_sdp) {
-                       sdp_parser_t *parser;
-                       sdp_session_t *sdp;
 
                        if (!(profile->ndlb & PFLAG_NDLB_ALLOW_NONDUP_SDP) || (!zstr(tech_pvt->remote_sdp_str) && !strcmp(tech_pvt->remote_sdp_str, r_sdp))) {
                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Duplicate SDP\n%s\n", r_sdp);
@@ -5653,12 +5651,10 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
                                tech_pvt->remote_sdp_str = switch_core_session_strdup(session, r_sdp);
                                switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
 
-                               if ((sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) && (parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
-                                       if ((sdp = sdp_session(parser))) {
-                                               sofia_glue_set_r_sdp_codec_string(session, sofia_glue_get_codec_string(tech_pvt), sdp);
-                                       }
-                                       sdp_parser_free(parser);
+                               if ((sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND)) {
+                                       sofia_media_set_sdp_codec_string(session, r_sdp);
                                }
+                               
                                sofia_glue_pass_sdp(tech_pvt, (char *) r_sdp);
                        }
                }
index 6e3dde6407658c069f43cab89fc37b795d4e48a4..548e58914b901e3be9b8a225a1beff637fb2336b 100644 (file)
@@ -2790,42 +2790,6 @@ void sofia_glue_do_xfer_invite(switch_core_session_t *session)
        switch_mutex_unlock(tech_pvt->sofia_mutex);
 }
 
-void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt)
-{
-       const char *sdp_str;
-
-       if ((sdp_str = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) {
-               sdp_parser_t *parser;
-               sdp_session_t *sdp;
-               sdp_media_t *m;
-               sdp_connection_t *connection;
-
-               if ((parser = sdp_parse(NULL, sdp_str, (int) strlen(sdp_str), 0))) {
-                       if ((sdp = sdp_session(parser))) {
-                               for (m = sdp->sdp_media; m; m = m->m_next) {
-                                       if (m->m_type != sdp_media_audio || !m->m_port) {
-                                               continue;
-                                       }
-
-                                       connection = sdp->sdp_connection;
-                                       if (m->m_connections) {
-                                               connection = m->m_connections;
-                                       }
-
-                                       if (connection) {
-                                               tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, connection->c_address);
-                                       }
-                                       tech_pvt->proxy_sdp_audio_port = (switch_port_t) m->m_port;
-                                       if (tech_pvt->proxy_sdp_audio_ip && tech_pvt->proxy_sdp_audio_port) {
-                                               break;
-                                       }
-                               }
-                       }
-                       sdp_parser_free(parser);
-               }
-               sofia_glue_tech_set_local_sdp(tech_pvt, sdp_str, SWITCH_TRUE);
-       }
-}
 
 
 #define add_stat(_i, _s)                                                                                               \
@@ -3186,2239 +3150,484 @@ switch_status_t sofia_glue_build_crypto(private_object_t *tech_pvt, int index, s
        return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t sofia_glue_add_crypto(private_object_t *tech_pvt, 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;
 
 
-       if (!switch_rtp_ready(tech_pvt->rtp_session)) {
-               goto bad;
+static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size_t buflen)
+{
+       int codec_ms = ptime;
+       uint32_t map_bit_rate = 0;
+       char ptstr[20] = "";
+       char ratestr[20] = "";
+       char bitstr[20] = "";
+       switch_codec_fmtp_t codec_fmtp = { 0 };
+                                               
+       if (!codec_ms) {
+               codec_ms = switch_default_ptime(map->rm_encoding, map->rm_pt);
        }
 
-       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;
+       map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt);
+                               
+       if (!ptime && !strcasecmp(map->rm_encoding, "g723")) {
+               ptime = codec_ms = 30;
+       }
+                               
+       if (zstr(map->rm_fmtp)) {
+               if (!strcasecmp(map->rm_encoding, "ilbc")) {
+                       ptime = codec_ms = 30;
+                       map_bit_rate = 13330;
                }
-
-               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;
+       } else {
+               if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) {
+                       if (codec_fmtp.bits_per_second) {
+                               map_bit_rate = codec_fmtp.bits_per_second;
                        }
-
-                       p += 7;
-                       switch_b64_decode(p, (char *) key, sizeof(key));
-
-                       if (direction == SWITCH_RTP_CRYPTO_SEND) {
-                               tech_pvt->crypto_send_type = type;
-                               memcpy(tech_pvt->local_raw_key, key, SWITCH_RTP_KEY_LEN);
-                       } else {
-                               tech_pvt->crypto_recv_type = type;
-                               memcpy(tech_pvt->remote_raw_key, key, SWITCH_RTP_KEY_LEN);
+                       if (codec_fmtp.microseconds_per_packet) {
+                               codec_ms = (codec_fmtp.microseconds_per_packet / 1000);
                        }
-                       return SWITCH_STATUS_SUCCESS;
                }
+       }
 
+       if (map->rm_rate) {
+               switch_snprintf(ratestr, sizeof(ratestr), "@%uh", (unsigned int) map->rm_rate);
        }
 
- bad:
+       if (codec_ms) {
+               switch_snprintf(ptstr, sizeof(ptstr), "@%di", codec_ms);
+       }
 
-       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Error!\n");
-       return SWITCH_STATUS_FALSE;
+       if (map_bit_rate) {
+               switch_snprintf(bitstr, sizeof(bitstr), "@%db", map_bit_rate);
+       }
 
-}
+       switch_snprintf(buf + strlen(buf), buflen - strlen(buf), ",%s%s%s%s", map->rm_encoding, ratestr, ptstr, bitstr);
 
+}
 
-switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_flag_t myflags)
+void sofia_glue_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session)
 {
-       const char *err = NULL;
-       const char *val = NULL;
-       switch_rtp_flag_t flags;
-       switch_status_t status = SWITCH_STATUS_SUCCESS;
-       char tmp[50];
-       uint32_t rtp_timeout_sec = tech_pvt->profile->rtp_timeout_sec;
-       uint32_t rtp_hold_timeout_sec = tech_pvt->profile->rtp_hold_timeout_sec;
-       char *timer_name = NULL;
-       const char *var;
-       uint32_t delay = tech_pvt->profile->rtp_digit_delay;
-
-       switch_assert(tech_pvt != NULL);
+       switch_channel_t *aleg_channel;
+       private_object_t *aleg_tech_pvt;
+       switch_channel_t *bleg_channel;
+       private_object_t *bleg_tech_pvt;
 
-       if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
-               return SWITCH_STATUS_FALSE;
+       if (!switch_core_session_compare(aleg_session, bleg_session)) {
+               /* since this digs into channel internals its only compatible with sofia sessions*/
+               return;
        }
 
-       switch_mutex_lock(tech_pvt->sofia_mutex);
+       aleg_channel = switch_core_session_get_channel(aleg_session);
+       aleg_tech_pvt = switch_core_session_get_private(aleg_session);
+       bleg_channel = switch_core_session_get_channel(bleg_session);
+       bleg_tech_pvt = switch_core_session_get_private(bleg_session);
 
-       if (switch_rtp_ready(tech_pvt->rtp_session)) {
-               switch_rtp_reset_media_timer(tech_pvt->rtp_session);
+       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG1, "Deciding whether to pass zrtp-hash between a-leg and b-leg\n");
+       if (!(switch_channel_test_flag(aleg_tech_pvt->channel, CF_ZRTP_PASSTHRU_REQ))) {
+               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG1, "CF_ZRTP_PASSTHRU_REQ not set on a-leg, so not propagating zrtp-hash\n");
+               return;
        }
-
-       if ((var = switch_channel_get_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE)) && switch_true(var)) {
-               sofia_set_flag_locked(tech_pvt, TFLAG_SECURE);
+       if (aleg_tech_pvt->remote_sdp_audio_zrtp_hash) {
+               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing a-leg remote zrtp-hash (audio) to b-leg\n");
+               bleg_tech_pvt->local_sdp_audio_zrtp_hash = switch_core_session_strdup(bleg_tech_pvt->session, aleg_tech_pvt->remote_sdp_audio_zrtp_hash);
+               switch_channel_set_variable(bleg_channel, "l_sdp_audio_zrtp_hash", bleg_tech_pvt->local_sdp_audio_zrtp_hash);
        }
-
-       if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
-               status = SWITCH_STATUS_SUCCESS;
-               goto end;
+       if (aleg_tech_pvt->remote_sdp_video_zrtp_hash) {
+               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing a-leg remote zrtp-hash (video) to b-leg\n");
+               bleg_tech_pvt->local_sdp_video_zrtp_hash = switch_core_session_strdup(bleg_tech_pvt->session, aleg_tech_pvt->remote_sdp_video_zrtp_hash);
+               switch_channel_set_variable(bleg_channel, "l_sdp_video_zrtp_hash", bleg_tech_pvt->local_sdp_video_zrtp_hash);
        }
-
-
-       if (!sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
-               if (switch_rtp_ready(tech_pvt->rtp_session)) {
-                       if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && !switch_rtp_ready(tech_pvt->video_rtp_session)) {
-                               goto video;
-                       }
-
-                       status = SWITCH_STATUS_SUCCESS;
-                       goto end;
-               } 
+       if (bleg_tech_pvt->remote_sdp_audio_zrtp_hash) {
+               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing b-leg remote zrtp-hash (audio) to a-leg\n");
+               aleg_tech_pvt->local_sdp_audio_zrtp_hash = switch_core_session_strdup(aleg_tech_pvt->session, bleg_tech_pvt->remote_sdp_audio_zrtp_hash);
+               switch_channel_set_variable(aleg_channel, "l_sdp_audio_zrtp_hash", aleg_tech_pvt->local_sdp_audio_zrtp_hash);
        }
-
-       if ((status = sofia_glue_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
-               goto end;
+       if (bleg_tech_pvt->remote_sdp_video_zrtp_hash) {
+               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing b-leg remote zrtp-hash (video) to a-leg\n");
+               aleg_tech_pvt->local_sdp_video_zrtp_hash = switch_core_session_strdup(aleg_tech_pvt->session, bleg_tech_pvt->remote_sdp_video_zrtp_hash);
+               switch_channel_set_variable(aleg_channel, "l_sdp_video_zrtp_hash", aleg_tech_pvt->local_sdp_video_zrtp_hash);
        }
+}
 
-
-       if (myflags) {
-               flags = myflags;
-       } else if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
-                          !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
-               flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
+void sofia_glue_pass_zrtp_hash(switch_core_session_t *session)
+{
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       private_object_t *tech_pvt = switch_core_session_get_private(session);
+       switch_core_session_t *other_session;
+       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Deciding whether to pass zrtp-hash between legs\n");
+       if (!(switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU_REQ))) {
+               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "CF_ZRTP_PASSTHRU_REQ not set, so not propagating zrtp-hash\n");
+               return;
+       } else if (!(switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS)) {
+               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "No partner channel found, so not propagating zrtp-hash\n");
+               return;
        } else {
-               flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT);
+               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Found peer channel; propagating zrtp-hash if set\n");
+               sofia_glue_pass_zrtp_hash2(session, other_session);
+               switch_core_session_rwunlock(other_session);
        }
+}
+
+void find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp)
+{
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       private_object_t *tech_pvt = switch_core_session_get_private(session);
+       sdp_media_t *m;
+       sdp_attribute_t *attr;
+       int got_audio = 0, got_video = 0;
 
-       if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_RFC2833)
-               || ((val = switch_channel_get_variable(tech_pvt->channel, "pass_rfc2833")) && switch_true(val))) {
-               sofia_set_flag(tech_pvt, TFLAG_PASS_RFC2833);
+       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Looking for zrtp-hash\n");
+       for (m = sdp->sdp_media; m; m = m->m_next) {
+               if (got_audio && got_video) break;
+               if (m->m_port && ((m->m_type == sdp_media_audio && !got_audio)
+                                                 || (m->m_type == sdp_media_video && !got_video))) {
+                       for (attr = m->m_attributes; attr; attr = attr->a_next) {
+                               if (zstr(attr->a_name)) continue;
+                               if (strcasecmp(attr->a_name, "zrtp-hash") || !(attr->a_value)) continue;
+                               if (m->m_type == sdp_media_audio) {
+                                       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG,
+                                                                         "Found audio zrtp-hash; setting r_sdp_audio_zrtp_hash=%s\n", attr->a_value);
+                                       switch_channel_set_variable(channel, "r_sdp_audio_zrtp_hash", attr->a_value);
+                                       tech_pvt->remote_sdp_audio_zrtp_hash = switch_core_session_strdup(tech_pvt->session, attr->a_value);
+                                       got_audio++;
+                               } else if (m->m_type == sdp_media_video) {
+                                       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG,
+                                                                         "Found video zrtp-hash; setting r_sdp_video_zrtp_hash=%s\n", attr->a_value);
+                                       switch_channel_set_variable(channel, "r_sdp_video_zrtp_hash", attr->a_value);
+                                       tech_pvt->remote_sdp_video_zrtp_hash = switch_core_session_strdup(tech_pvt->session, attr->a_value);
+                                       got_video++;
+                               }
+                               switch_channel_set_flag(channel, CF_ZRTP_HASH);
+                               break;
+                       }
+               }
        }
+}
 
+void sofia_glue_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp)
+{
+       char buf[1024] = { 0 };
+       sdp_media_t *m;
+       sdp_attribute_t *attr;
+       int ptime = 0, dptime = 0;
+       sdp_connection_t *connection;
+       sdp_rtpmap_t *map;
+       short int match = 0;
+       int i;
+       int already_did[128] = { 0 };
+       int num_codecs = 0;
+       char *codec_order[SWITCH_MAX_CODECS];
+       const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 };
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       private_object_t *tech_pvt = switch_core_session_get_private(session);
+       int prefer_sdp = 0;
+       const char *var;
 
-       if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFLUSH)
-               || ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_autoflush")) && switch_true(val))) {
-               flags |= SWITCH_RTP_FLAG_AUTOFLUSH;
+       if ((var = switch_channel_get_variable(channel, "ep_codec_prefer_sdp")) && switch_true(var)) {
+               prefer_sdp = 1;
        }
-
-       if (!(sofia_test_pflag(tech_pvt->profile, PFLAG_REWRITE_TIMESTAMPS) ||
-                 ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_rewrite_timestamps")) && switch_true(val)))) {
-               flags |= SWITCH_RTP_FLAG_RAW_WRITE;
+               
+       if (!zstr(codec_string)) {
+               char *tmp_codec_string;
+               if ((tmp_codec_string = strdup(codec_string))) {
+                       num_codecs = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS);
+                       num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, num_codecs);
+                       switch_safe_free(tmp_codec_string);
+               }
+       } else {
+               num_codecs = switch_loadable_module_get_codecs(codecs, SWITCH_MAX_CODECS);
        }
 
-       if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
-               tech_pvt->cng_pt = 0;
-       } else if (tech_pvt->cng_pt) {
-               flags |= SWITCH_RTP_FLAG_AUTO_CNG;
+       if (!channel || !num_codecs) {
+               return;
        }
 
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-       if (!strcasecmp(tech_pvt->read_impl.iananame, "L16")) {
-               flags |= SWITCH_RTP_FLAG_BYTESWAP;
-       }
-#endif
-       
-       if ((flags & SWITCH_RTP_FLAG_BYTESWAP) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_byteswap")) && switch_true(val)) {
-               flags &= ~SWITCH_RTP_FLAG_BYTESWAP;
+       for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
+               if (zstr(attr->a_name)) {
+                       continue;
+               }
+               if (!strcasecmp(attr->a_name, "ptime")) {
+                       dptime = atoi(attr->a_value);
+                       break;
+               }
        }
 
-       if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
-               //const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
-               //const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
-               char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
-               switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
+       find_zrtp_hash(session, sdp);
+       sofia_glue_pass_zrtp_hash(session);
 
-               if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
-                                                         switch_channel_get_name(tech_pvt->channel));
-                       if (switch_rtp_ready(tech_pvt->rtp_session)) {
-                               if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
-                                                                 "%s Set audio receive payload in Re-INVITE for non-matching dynamic PT to %u\n", 
-                                                                         switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
-                               
-                                       switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
-                               } else {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
-                                                                 "%s Setting audio receive payload in Re-INVITE to %u\n", 
-                                                                         switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
-                                       switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt);
+       for (m = sdp->sdp_media; m; m = m->m_next) {
+               ptime = dptime;
+               if (m->m_type == sdp_media_image && m->m_port) {
+                       switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",t38");
+               } else if (m->m_type == sdp_media_audio && m->m_port) {
+                       for (attr = m->m_attributes; attr; attr = attr->a_next) {
+                               if (zstr(attr->a_name)) {
+                                       continue;
+                               }
+                               if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
+                                       ptime = atoi(attr->a_value);
+                                       break;
                                }
+                       }
+                       connection = sdp->sdp_connection;
+                       if (m->m_connections) {
+                               connection = m->m_connections;
+                       }
 
+                       if (!connection) {
+                               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+                               break;
                        }
-                       goto video;
-               } else {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
-                                                         switch_channel_get_name(tech_pvt->channel),
-                                                         remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
 
-                       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
-                       switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
-                       switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
-               }
-       }
+                       if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND || prefer_sdp) {
+                               for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                                       if (map->rm_pt > 127 || already_did[map->rm_pt]) {
+                                               continue;
+                                       }
 
-       if (!switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
-               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n",
-                                                 switch_channel_get_name(tech_pvt->channel),
-                                                 tech_pvt->local_sdp_audio_ip,
-                                                 tech_pvt->local_sdp_audio_port,
-                                                 tech_pvt->remote_sdp_audio_ip,
-                                                 tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
+                                       for (i = 0; i < num_codecs; i++) {
+                                               const switch_codec_implementation_t *imp = codecs[i];
 
-               if (switch_rtp_ready(tech_pvt->rtp_session)) {
-                       switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
-
-                       if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
-                                                                 "%s Set audio receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
-                               
-                               switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
-                       } else {
-                               switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt);
-                       }
-
-               }
-       }
-
-       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_audio_port);
-       switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->local_sdp_audio_ip);
-       switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
-       switch_channel_set_variable(tech_pvt->channel, SWITCH_ADVERTISED_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
-
-       if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
-               const char *rport = NULL;
-               switch_port_t remote_rtcp_port = 0;
-
-               
-
-               if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port"))) {
-                       remote_rtcp_port = (switch_port_t)atoi(rport);
-               }
-
-               if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port,
-                                                                                 remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
-               } else {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n",
-                                                         tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
-                       if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
-                               !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
-                               /* Reactivate the NAT buster flag. */
-                               switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
-                       }
-               }
-               goto video;
-       }
-
-       if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
-               sofia_glue_tech_proxy_remote_addr(tech_pvt, NULL);
-
-               if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
-                       !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
-                       flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
-               } else {
-                       flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_DATAWAIT);
-               }
-               timer_name = NULL;
-
-               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
-                                                 "PROXY AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
-                                                 switch_channel_get_name(tech_pvt->channel),
-                                                 tech_pvt->local_sdp_audio_ip,
-                                                 tech_pvt->local_sdp_audio_port,
-                                                 tech_pvt->remote_sdp_audio_ip,
-                                                 tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
-
-               if (switch_rtp_ready(tech_pvt->rtp_session)) {
-                       switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
-               }
-
-       } else {
-               timer_name = tech_pvt->profile->timer_name;
-
-               if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) {
-                       timer_name = (char *) var;
-               }
-       }
-
-       if (switch_channel_up(tech_pvt->channel) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
-               tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
-                                                                                          tech_pvt->local_sdp_audio_port,
-                                                                                          tech_pvt->remote_sdp_audio_ip,
-                                                                                          tech_pvt->remote_sdp_audio_port,
-                                                                                          tech_pvt->agreed_pt,
-                                                                                          tech_pvt->read_impl.samples_per_packet,
-                                                                                          tech_pvt->codec_ms * 1000,
-                                                                                          (switch_rtp_flag_t) flags, timer_name, &err, switch_core_session_get_pool(tech_pvt->session));
-       }
-
-       if (switch_rtp_ready(tech_pvt->rtp_session)) {
-               uint8_t vad_in = sofia_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
-               uint8_t vad_out = sofia_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0;
-               uint8_t inb = sofia_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1;
-               uint32_t stun_ping = 0;
-               const char *ssrc;
-
-               if ((ssrc = switch_channel_get_variable(tech_pvt->channel, "rtp_use_ssrc"))) {
-                       uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10);
-                       switch_rtp_set_ssrc(tech_pvt->rtp_session, ssrc_ul);
-               }
-
-
-               switch_channel_set_flag(tech_pvt->channel, CF_FS_RTP);
-
-               switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_pt", "%d", tech_pvt->agreed_pt);
-
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_enable_vad_in")) && switch_true(val)) {
-                       vad_in = 1;
-               }
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_enable_vad_out")) && switch_true(val)) {
-                       vad_out = 1;
-               }
-
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_vad_in")) && switch_true(val)) {
-                       vad_in = 0;
-               }
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_vad_out")) && switch_true(val)) {
-                       vad_out = 0;
-               }
-
-               if ((tech_pvt->stun_flags & STUN_FLAG_SET) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_stun_ping"))) {
-                       int ival = atoi(val);
-
-                       if (ival <= 0) {
-                               if (switch_true(val)) {
-                                       ival = 6;
-                               }
-                       }
-
-                       stun_ping = (ival * tech_pvt->read_impl.samples_per_second) / tech_pvt->read_impl.samples_per_packet;
-               }
-
-               tech_pvt->ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
-               switch_channel_set_variable_printf(tech_pvt->channel, "rtp_use_ssrc", "%u", tech_pvt->ssrc);
-
-               sofia_set_flag(tech_pvt, TFLAG_RTP);
-               sofia_set_flag(tech_pvt, TFLAG_IO);
-
-               if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_IGNORE_MARK_BIT) {
-                       tech_pvt->rtp_bugs |= RTP_BUG_IGNORE_MARK_BIT;
-               }
-
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_manual_rtp_bugs"))) {
-                       sofia_glue_parse_rtp_bugs(&tech_pvt->rtp_bugs, val);
-               }
-
-               switch_rtp_intentional_bugs(tech_pvt->rtp_session, tech_pvt->rtp_bugs | tech_pvt->profile->manual_rtp_bugs);
-
-               if ((vad_in && inb) || (vad_out && !inb)) {
-                       switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING | SWITCH_VAD_FLAG_EVENTS_TALK | SWITCH_VAD_FLAG_EVENTS_NOTALK);
-                       sofia_set_flag(tech_pvt, TFLAG_VAD);
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP Engage VAD for %s ( %s %s )\n",
-                                                         switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : "");
-               }
-
-               if (stun_ping) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Setting stun ping to %s:%d\n", tech_pvt->stun_ip,
-                                                         stun_ping);
-                       switch_rtp_activate_stun_ping(tech_pvt->rtp_session, tech_pvt->stun_ip, tech_pvt->stun_port, stun_ping,
-                                                                                 (tech_pvt->stun_flags & STUN_FLAG_FUNNY) ? 1 : 0);
-               }
-
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec")) || (val = tech_pvt->profile->rtcp_audio_interval_msec)) {
-                       const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port");
-                       switch_port_t remote_port = 0;
-                       if (rport) {
-                               remote_port = (switch_port_t)atoi(rport);
-                       }
-                       if (!strcasecmp(val, "passthru")) {
-                               switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
-                       } else {
-                               int interval = atoi(val);
-                               if (interval < 100 || interval > 5000) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
-                                                                         "Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval);
-                               } else {
-                                       switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval, remote_port);
-                               }
-                       }
-               }
-
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec")) || (val = tech_pvt->profile->jb_msec)) {
-                       int jb_msec = atoi(val);
-                       int maxlen = 0, max_drift = 0;
-                       char *p, *q;
-                       
-                       if ((p = strchr(val, ':'))) {
-                               p++;
-                               maxlen = atoi(p);
-                               if ((q = strchr(p, ':'))) {
-                                       q++;
-                                       max_drift = abs(atoi(q));
-                               }
-                       }
-
-                       if (jb_msec < 20 || jb_msec > 10000) {
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
-                                                                 "Invalid Jitterbuffer spec [%d] must be between 20 and 10000\n", jb_msec);
-                       } else {
-                               int qlen, maxqlen = 50;
-                               
-                               qlen = jb_msec / (tech_pvt->read_impl.microseconds_per_packet / 1000);
-
-                               if (qlen < 1) {
-                                       qlen = 3;
-                               }
-
-                               if (maxlen) {
-                                       maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000);
-                               }
-
-                               if (maxqlen < qlen) {
-                                       maxqlen = qlen * 5;
-                               }
-                               if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
-                                                                                                         tech_pvt->read_impl.samples_per_packet, 
-                                                                                                         tech_pvt->read_impl.samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), 
-                                                                         SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen);
-                                       switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER);
-                                       if (!switch_false(switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_plc"))) {
-                                               switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER_PLC);
-                                       }
-                               } else {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), 
-                                                                         SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen);
-                               }
-                               
-                       }
-               }
-
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_timeout_sec"))) {
-                       int v = atoi(val);
-                       if (v >= 0) {
-                               rtp_timeout_sec = v;
-                       }
-               }
-
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_hold_timeout_sec"))) {
-                       int v = atoi(val);
-                       if (v >= 0) {
-                               rtp_hold_timeout_sec = v;
-                       }
-               }
-
-               if (rtp_timeout_sec) {
-                       tech_pvt->max_missed_packets = (tech_pvt->read_impl.samples_per_second * rtp_timeout_sec) / tech_pvt->read_impl.samples_per_packet;
-
-                       switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
-                       if (!rtp_hold_timeout_sec) {
-                               rtp_hold_timeout_sec = rtp_timeout_sec * 10;
-                       }
-               }
-
-               if (rtp_hold_timeout_sec) {
-                       tech_pvt->max_missed_hold_packets = (tech_pvt->read_impl.samples_per_second * rtp_hold_timeout_sec) / tech_pvt->read_impl.samples_per_packet;
-               }
-
-               if (tech_pvt->te) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", tech_pvt->te);
-                       switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
-                       switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", tech_pvt->te);
-               }
-
-               if (tech_pvt->recv_te) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set 2833 dtmf receive payload to %u\n", tech_pvt->recv_te);
-                       switch_rtp_set_telephony_recv_event(tech_pvt->rtp_session, tech_pvt->recv_te);
-                       switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_recv_payload", "%d", tech_pvt->recv_te);
-               }
-
-               if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
-                                                         "%s Set audio receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
-
-                       switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
-               }
-
-               if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) ||
-                       ((val = switch_channel_get_variable(tech_pvt->channel, "supress_cng")) && switch_true(val)) ||
-                       ((val = switch_channel_get_variable(tech_pvt->channel, "suppress_cng")) && switch_true(val))) {
-                       tech_pvt->cng_pt = 0;
-               }
-
-               if (((val = switch_channel_get_variable(tech_pvt->channel, "rtp_digit_delay")))) {
-                       int delayi = atoi(val);
-                       if (delayi < 0) delayi = 0;
-                       delay = (uint32_t) delayi;
-               }
-
-
-               if (delay) {
-                       switch_rtp_set_interdigit_delay(tech_pvt->rtp_session, delay);
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
-                                                         "%s Set rtp dtmf delay to %u\n", switch_channel_get_name(tech_pvt->channel), delay);
-                       
-               }
-
-               if (tech_pvt->cng_pt && !sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", tech_pvt->cng_pt);
-                       switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
-               }
-
-               if (tech_pvt->remote_crypto_key && sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
-                       sofia_glue_add_crypto(tech_pvt, tech_pvt->remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
-                       switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1, tech_pvt->crypto_type, tech_pvt->local_raw_key,
-                                                                         SWITCH_RTP_KEY_LEN);
-                       switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_RECV, tech_pvt->crypto_tag, tech_pvt->crypto_type, tech_pvt->remote_raw_key,
-                                                                         SWITCH_RTP_KEY_LEN);
-                       switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE, "true");
-               }
-
-
-               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
-               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
-               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
-
-
-               if (switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU)) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "Activating ZRTP PROXY MODE\n");
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Disable NOTIMER_DURING_BRIDGE\n");
-                       sofia_clear_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE);
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Activating audio UDPTL mode\n");
-                       switch_rtp_udptl_mode(tech_pvt->rtp_session);
-               }
-
-
-       video:
-               
-               sofia_glue_check_video_codecs(tech_pvt);
-
-               if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding && tech_pvt->remote_sdp_video_port) {
-                       /******************************************************************************************/
-                       if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
-                               //const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
-                               //const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
-                               char *remote_host = switch_rtp_get_remote_host(tech_pvt->video_rtp_session);
-                               switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->video_rtp_session);
-                               
-
-
-                               if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_video_ip) && remote_port == tech_pvt->remote_sdp_video_port) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params are unchanged for %s.\n",
-                                                                         switch_channel_get_name(tech_pvt->channel));
-                                       goto video_up;
-                               } else {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params changed for %s from %s:%d to %s:%d\n",
-                                                                         switch_channel_get_name(tech_pvt->channel),
-                                                                         remote_host, remote_port, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port);
-                               }
-                       }
-
-                       if (!switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
-                                                                 "VIDEO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n", switch_channel_get_name(tech_pvt->channel),
-                                                                 tech_pvt->local_sdp_audio_ip, tech_pvt->local_sdp_video_port, tech_pvt->remote_sdp_video_ip,
-                                                                 tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
-
-                               if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
-                                       switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
-                               }
-                       }
-                       
-                       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_video_port);
-                       switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
-                       switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp);
-
-
-                       if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
-                               const char *rport = NULL;
-                               switch_port_t remote_rtcp_port = 0;
-
-                               sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
-
-                               if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port"))) {
-                                       remote_rtcp_port = (switch_port_t)atoi(rport);
-                               }
-                               
-                               if (switch_rtp_set_remote_address
-                                       (tech_pvt->video_rtp_session, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port, remote_rtcp_port, SWITCH_TRUE,
-                                        &err) != SWITCH_STATUS_SUCCESS) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err);
-                               } else {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n",
-                                                                         tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port);
-                                       if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
-                                               !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
-                                               /* Reactivate the NAT buster flag. */
-                                               switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
-                                       }
-
-                               }
-                               goto video_up;
-                       }
-
-                       if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
-                               sofia_glue_tech_proxy_remote_addr(tech_pvt, NULL);
-
-                               if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
-                                       !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
-                                       flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
-                               } else {
-                                       flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_DATAWAIT);
-                               }
-                               timer_name = NULL;
-
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
-                                                                 "PROXY VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
-                                                                 switch_channel_get_name(tech_pvt->channel),
-                                                                 tech_pvt->local_sdp_audio_ip,
-                                                                 tech_pvt->local_sdp_video_port,
-                                                                 tech_pvt->remote_sdp_video_ip,
-                                                                 tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
-
-                               if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
-                                       switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
-                               }
-                       } else {
-                               timer_name = tech_pvt->profile->timer_name;
-
-                               if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) {
-                                       timer_name = (char *) var;
-                               }
-                       }
-
-                       /******************************************************************************************/
-
-                       if (tech_pvt->video_rtp_session) {
-                               goto video_up;
-                       }
-
-
-                       if (!tech_pvt->local_sdp_video_port) {
-                               sofia_glue_tech_choose_video_port(tech_pvt, 1);
-                       }
-
-                       if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) &&
-                               !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
-                               flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_RAW_WRITE);
-                       } else {
-                               flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_RAW_WRITE);
-                       }
-
-                       if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
-                               flags |= SWITCH_RTP_FLAG_PROXY_MEDIA;
-                       }
-                       sofia_glue_tech_set_video_codec(tech_pvt, 0);
-
-                       flags &= ~(SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_NOBLOCK);
-                       flags |= SWITCH_RTP_FLAG_VIDEO;
-
-                       tech_pvt->video_rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
-                                                                                                                tech_pvt->local_sdp_video_port,
-                                                                                                                tech_pvt->remote_sdp_video_ip,
-                                                                                                                tech_pvt->remote_sdp_video_port,
-                                                                                                                tech_pvt->video_agreed_pt,
-                                                                                                                1, 90000, (switch_rtp_flag_t) flags, NULL, &err, switch_core_session_get_pool(tech_pvt->session));
-
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
-                                                         switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
-                                                         switch_channel_get_name(tech_pvt->channel),
-                                                         tech_pvt->local_sdp_audio_ip,
-                                                         tech_pvt->local_sdp_video_port,
-                                                         tech_pvt->remote_sdp_video_ip,
-                                                         tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt,
-                                                         0, switch_rtp_ready(tech_pvt->video_rtp_session) ? "SUCCESS" : err);
-
-
-                       if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
-                               switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
-                       }
-
-                       if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
-                               const char *ssrc;
-                               switch_channel_set_flag(tech_pvt->channel, CF_VIDEO);
-                               if ((ssrc = switch_channel_get_variable(tech_pvt->channel, "rtp_use_video_ssrc"))) {
-                                       uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10);
-                                       switch_rtp_set_ssrc(tech_pvt->video_rtp_session, ssrc_ul);
-                               }
-
-
-
-                               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_manual_video_rtp_bugs"))) {
-                                       sofia_glue_parse_rtp_bugs(&tech_pvt->video_rtp_bugs, val);
-                               }
-                               
-                               switch_rtp_intentional_bugs(tech_pvt->video_rtp_session, tech_pvt->video_rtp_bugs | tech_pvt->profile->manual_video_rtp_bugs);
-
-                               if (tech_pvt->video_recv_pt != tech_pvt->video_agreed_pt) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
-                                                                         "%s Set video receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->video_recv_pt);
-                                       switch_rtp_set_recv_pt(tech_pvt->video_rtp_session, tech_pvt->video_recv_pt);
-                               }
-
-                               switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_pt", "%d", tech_pvt->video_agreed_pt);
-                               tech_pvt->video_ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
-                               switch_channel_set_variable_printf(tech_pvt->channel, "rtp_use_video_ssrc", "%u", tech_pvt->ssrc);
-
-
-                               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec"))
-                                       || (val = tech_pvt->profile->rtcp_audio_interval_msec)) {
-                                       const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port");
-                                       switch_port_t remote_port = 0;
-                                       if (rport) {
-                                               remote_port = (switch_port_t)atoi(rport);
-                                       }
-                                       if (!strcasecmp(val, "passthru")) {
-                                               switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
-                                       } else {
-                                               int interval = atoi(val);
-                                               if (interval < 100 || interval > 5000) {
-                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
-                                                                                         "Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval);
-                                               } else {
-                                                       switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval, remote_port);
-                                               }
-                                       }
-                               }
-                               if (switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU)) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Activating video UDPTL mode\n");
-                                       switch_rtp_udptl_mode(tech_pvt->video_rtp_session);
-                               }
-
-                       } else {
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
-                               switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-                               goto end;
-                       }
-               }
-
-       } else {
-               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
-               switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-               sofia_clear_flag_locked(tech_pvt, TFLAG_IO);
-               status = SWITCH_STATUS_FALSE;
-               goto end;
-       }
-
- video_up:
-
-       sofia_set_flag(tech_pvt, TFLAG_IO);
-       status = SWITCH_STATUS_SUCCESS;
-
- end:
-
-       sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
-       switch_core_recovery_track(tech_pvt->session);
-
-       switch_mutex_unlock(tech_pvt->sofia_mutex);
-
-       return status;
-
-}
-
-static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size_t buflen)
-{
-       int codec_ms = ptime;
-       uint32_t map_bit_rate = 0;
-       char ptstr[20] = "";
-       char ratestr[20] = "";
-       char bitstr[20] = "";
-       switch_codec_fmtp_t codec_fmtp = { 0 };
-                                               
-       if (!codec_ms) {
-               codec_ms = switch_default_ptime(map->rm_encoding, map->rm_pt);
-       }
-
-       map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt);
-                               
-       if (!ptime && !strcasecmp(map->rm_encoding, "g723")) {
-               ptime = codec_ms = 30;
-       }
-                               
-       if (zstr(map->rm_fmtp)) {
-               if (!strcasecmp(map->rm_encoding, "ilbc")) {
-                       ptime = codec_ms = 30;
-                       map_bit_rate = 13330;
-               }
-       } else {
-               if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) {
-                       if (codec_fmtp.bits_per_second) {
-                               map_bit_rate = codec_fmtp.bits_per_second;
-                       }
-                       if (codec_fmtp.microseconds_per_packet) {
-                               codec_ms = (codec_fmtp.microseconds_per_packet / 1000);
-                       }
-               }
-       }
-
-       if (map->rm_rate) {
-               switch_snprintf(ratestr, sizeof(ratestr), "@%uh", (unsigned int) map->rm_rate);
-       }
-
-       if (codec_ms) {
-               switch_snprintf(ptstr, sizeof(ptstr), "@%di", codec_ms);
-       }
-
-       if (map_bit_rate) {
-               switch_snprintf(bitstr, sizeof(bitstr), "@%db", map_bit_rate);
-       }
-
-       switch_snprintf(buf + strlen(buf), buflen - strlen(buf), ",%s%s%s%s", map->rm_encoding, ratestr, ptstr, bitstr);
-
-}
-
-void sofia_glue_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session)
-{
-       switch_channel_t *aleg_channel;
-       private_object_t *aleg_tech_pvt;
-       switch_channel_t *bleg_channel;
-       private_object_t *bleg_tech_pvt;
-
-       if (!switch_core_session_compare(aleg_session, bleg_session)) {
-               /* since this digs into channel internals its only compatible with sofia sessions*/
-               return;
-       }
-
-       aleg_channel = switch_core_session_get_channel(aleg_session);
-       aleg_tech_pvt = switch_core_session_get_private(aleg_session);
-       bleg_channel = switch_core_session_get_channel(bleg_session);
-       bleg_tech_pvt = switch_core_session_get_private(bleg_session);
-
-       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG1, "Deciding whether to pass zrtp-hash between a-leg and b-leg\n");
-       if (!(switch_channel_test_flag(aleg_tech_pvt->channel, CF_ZRTP_PASSTHRU_REQ))) {
-               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG1, "CF_ZRTP_PASSTHRU_REQ not set on a-leg, so not propagating zrtp-hash\n");
-               return;
-       }
-       if (aleg_tech_pvt->remote_sdp_audio_zrtp_hash) {
-               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing a-leg remote zrtp-hash (audio) to b-leg\n");
-               bleg_tech_pvt->local_sdp_audio_zrtp_hash = switch_core_session_strdup(bleg_tech_pvt->session, aleg_tech_pvt->remote_sdp_audio_zrtp_hash);
-               switch_channel_set_variable(bleg_channel, "l_sdp_audio_zrtp_hash", bleg_tech_pvt->local_sdp_audio_zrtp_hash);
-       }
-       if (aleg_tech_pvt->remote_sdp_video_zrtp_hash) {
-               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing a-leg remote zrtp-hash (video) to b-leg\n");
-               bleg_tech_pvt->local_sdp_video_zrtp_hash = switch_core_session_strdup(bleg_tech_pvt->session, aleg_tech_pvt->remote_sdp_video_zrtp_hash);
-               switch_channel_set_variable(bleg_channel, "l_sdp_video_zrtp_hash", bleg_tech_pvt->local_sdp_video_zrtp_hash);
-       }
-       if (bleg_tech_pvt->remote_sdp_audio_zrtp_hash) {
-               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing b-leg remote zrtp-hash (audio) to a-leg\n");
-               aleg_tech_pvt->local_sdp_audio_zrtp_hash = switch_core_session_strdup(aleg_tech_pvt->session, bleg_tech_pvt->remote_sdp_audio_zrtp_hash);
-               switch_channel_set_variable(aleg_channel, "l_sdp_audio_zrtp_hash", aleg_tech_pvt->local_sdp_audio_zrtp_hash);
-       }
-       if (bleg_tech_pvt->remote_sdp_video_zrtp_hash) {
-               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing b-leg remote zrtp-hash (video) to a-leg\n");
-               aleg_tech_pvt->local_sdp_video_zrtp_hash = switch_core_session_strdup(aleg_tech_pvt->session, bleg_tech_pvt->remote_sdp_video_zrtp_hash);
-               switch_channel_set_variable(aleg_channel, "l_sdp_video_zrtp_hash", aleg_tech_pvt->local_sdp_video_zrtp_hash);
-       }
-}
-
-void sofia_glue_pass_zrtp_hash(switch_core_session_t *session)
-{
-       switch_channel_t *channel = switch_core_session_get_channel(session);
-       private_object_t *tech_pvt = switch_core_session_get_private(session);
-       switch_core_session_t *other_session;
-       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Deciding whether to pass zrtp-hash between legs\n");
-       if (!(switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU_REQ))) {
-               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "CF_ZRTP_PASSTHRU_REQ not set, so not propagating zrtp-hash\n");
-               return;
-       } else if (!(switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS)) {
-               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "No partner channel found, so not propagating zrtp-hash\n");
-               return;
-       } else {
-               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Found peer channel; propagating zrtp-hash if set\n");
-               sofia_glue_pass_zrtp_hash2(session, other_session);
-               switch_core_session_rwunlock(other_session);
-       }
-}
-
-static void find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp)
-{
-       switch_channel_t *channel = switch_core_session_get_channel(session);
-       private_object_t *tech_pvt = switch_core_session_get_private(session);
-       sdp_media_t *m;
-       sdp_attribute_t *attr;
-       int got_audio = 0, got_video = 0;
-
-       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Looking for zrtp-hash\n");
-       for (m = sdp->sdp_media; m; m = m->m_next) {
-               if (got_audio && got_video) break;
-               if (m->m_port && ((m->m_type == sdp_media_audio && !got_audio)
-                                                 || (m->m_type == sdp_media_video && !got_video))) {
-                       for (attr = m->m_attributes; attr; attr = attr->a_next) {
-                               if (zstr(attr->a_name)) continue;
-                               if (strcasecmp(attr->a_name, "zrtp-hash") || !(attr->a_value)) continue;
-                               if (m->m_type == sdp_media_audio) {
-                                       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG,
-                                                                         "Found audio zrtp-hash; setting r_sdp_audio_zrtp_hash=%s\n", attr->a_value);
-                                       switch_channel_set_variable(channel, "r_sdp_audio_zrtp_hash", attr->a_value);
-                                       tech_pvt->remote_sdp_audio_zrtp_hash = switch_core_session_strdup(tech_pvt->session, attr->a_value);
-                                       got_audio++;
-                               } else if (m->m_type == sdp_media_video) {
-                                       switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG,
-                                                                         "Found video zrtp-hash; setting r_sdp_video_zrtp_hash=%s\n", attr->a_value);
-                                       switch_channel_set_variable(channel, "r_sdp_video_zrtp_hash", attr->a_value);
-                                       tech_pvt->remote_sdp_video_zrtp_hash = switch_core_session_strdup(tech_pvt->session, attr->a_value);
-                                       got_video++;
-                               }
-                               switch_channel_set_flag(channel, CF_ZRTP_HASH);
-                               break;
-                       }
-               }
-       }
-}
-
-void sofia_glue_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp)
-{
-       char buf[1024] = { 0 };
-       sdp_media_t *m;
-       sdp_attribute_t *attr;
-       int ptime = 0, dptime = 0;
-       sdp_connection_t *connection;
-       sdp_rtpmap_t *map;
-       short int match = 0;
-       int i;
-       int already_did[128] = { 0 };
-       int num_codecs = 0;
-       char *codec_order[SWITCH_MAX_CODECS];
-       const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 };
-       switch_channel_t *channel = switch_core_session_get_channel(session);
-       private_object_t *tech_pvt = switch_core_session_get_private(session);
-       int prefer_sdp = 0;
-       const char *var;
-
-       if ((var = switch_channel_get_variable(channel, "ep_codec_prefer_sdp")) && switch_true(var)) {
-               prefer_sdp = 1;
-       }
-               
-       if (!zstr(codec_string)) {
-               char *tmp_codec_string;
-               if ((tmp_codec_string = strdup(codec_string))) {
-                       num_codecs = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS);
-                       num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, num_codecs);
-                       switch_safe_free(tmp_codec_string);
-               }
-       } else {
-               num_codecs = switch_loadable_module_get_codecs(codecs, SWITCH_MAX_CODECS);
-       }
-
-       if (!channel || !num_codecs) {
-               return;
-       }
-
-       for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
-               if (zstr(attr->a_name)) {
-                       continue;
-               }
-               if (!strcasecmp(attr->a_name, "ptime")) {
-                       dptime = atoi(attr->a_value);
-                       break;
-               }
-       }
-
-       find_zrtp_hash(session, sdp);
-       sofia_glue_pass_zrtp_hash(session);
-
-       for (m = sdp->sdp_media; m; m = m->m_next) {
-               ptime = dptime;
-               if (m->m_type == sdp_media_image && m->m_port) {
-                       switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",t38");
-               } else if (m->m_type == sdp_media_audio && m->m_port) {
-                       for (attr = m->m_attributes; attr; attr = attr->a_next) {
-                               if (zstr(attr->a_name)) {
-                                       continue;
-                               }
-                               if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
-                                       ptime = atoi(attr->a_value);
-                                       break;
-                               }
-                       }
-                       connection = sdp->sdp_connection;
-                       if (m->m_connections) {
-                               connection = m->m_connections;
-                       }
-
-                       if (!connection) {
-                               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
-                               break;
-                       }
-
-                       if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND || prefer_sdp) {
-                               for (map = m->m_rtpmaps; map; map = map->rm_next) {
-                                       if (map->rm_pt > 127 || already_did[map->rm_pt]) {
-                                               continue;
-                                       }
-
-                                       for (i = 0; i < num_codecs; i++) {
-                                               const switch_codec_implementation_t *imp = codecs[i];
-
-                                               if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
-                                                       match = (map->rm_pt == imp->ianacode) ? 1 : 0;
-                                               } else {
-                                                       if (map->rm_encoding) {
-                                                               match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
-                                                       } else {
-                                                               match = 0;
-                                                       }
-                                               }
-
-                                               if (match) {
-                                                       add_audio_codec(map, ptime, buf, sizeof(buf));
-                                                       break;
-                                               }
-                                       
-                                       }
-                               }
-
-                       } else {
-                               for (i = 0; i < num_codecs; i++) {
-                                       const switch_codec_implementation_t *imp = codecs[i];
-                                       if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO || imp->ianacode > 127 || already_did[imp->ianacode]) {
-                                               continue;
-                                       }
-                                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
-                                               if (map->rm_pt > 127 || already_did[map->rm_pt]) {
-                                                       continue;
-                                               }
-
-                                               if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
-                                                       match = (map->rm_pt == imp->ianacode) ? 1 : 0;
-                                               } else {
-                                                       if (map->rm_encoding) {
-                                                               match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
-                                                       } else {
-                                                               match = 0;
-                                                       }
-                                               }
-
-                                               if (match) {
-                                                       add_audio_codec(map, ptime, buf, sizeof(buf));
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
-
-               } else if (m->m_type == sdp_media_video && m->m_port) {
-                       connection = sdp->sdp_connection;
-                       if (m->m_connections) {
-                               connection = m->m_connections;
-                       }
-
-                       if (!connection) {
-                               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
-                               break;
-                       }
-                       for (i = 0; i < num_codecs; i++) {
-                               const switch_codec_implementation_t *imp = codecs[i];
-                               if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) {
-                                       continue;
-                               }
-                               for (map = m->m_rtpmaps; map; map = map->rm_next) {
-                                       if (map->rm_pt > 127 || already_did[map->rm_pt]) {
-                                               continue;
-                                       }
-
-                                       if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
-                                               match = (map->rm_pt == imp->ianacode) ? 1 : 0;
-                                       } else {
-                                               if (map->rm_encoding) {
-                                                       match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
-                                               } else {
-                                                       match = 0;
-                                               }
-                                       }
-
-                                       if (match) {
-                                               if (ptime > 0) {
-                                                       switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate,
-                                                                                       ptime);
-                                               } else {
-                                                       switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate);
-                                               }
-                                               already_did[imp->ianacode] = 1;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       }
-       if (buf[0] == ',') {
-               switch_channel_set_variable(channel, "ep_codec_string", buf + 1);
-       }
-}
-
-switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_sdp)
-{
-       uint8_t match = 0;
-
-       switch_assert(tech_pvt != NULL);
-       switch_assert(r_sdp != NULL);
-
-       if (zstr(r_sdp)) {
-               return SWITCH_STATUS_FALSE;
-       }
-
-       if ((match = sofia_glue_negotiate_sdp(tech_pvt->session, r_sdp))) {
-               if (sofia_glue_tech_choose_port(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
-                       return SWITCH_STATUS_FALSE;
-               }
-               if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
-                       return SWITCH_STATUS_FALSE;
-               }
-               switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA");
-               sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
-               switch_channel_mark_pre_answered(tech_pvt->channel);
-               return SWITCH_STATUS_SUCCESS;
-       }
-
-
-       return SWITCH_STATUS_FALSE;
-}
-
-int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
-{
-       int changed = 0;
-
-       if (sofia_test_flag(tech_pvt, TFLAG_SLA_BARGE) || sofia_test_flag(tech_pvt, TFLAG_SLA_BARGING)) {
-               switch_channel_mark_hold(tech_pvt->channel, sendonly);
-               return 0;
-       }
-
-       if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) {
-               if (!sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
-                       const char *stream;
-                       const char *msg = "hold";
-
-                       if (sofia_test_pflag(tech_pvt->profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
-                               const char *info = switch_channel_get_variable(tech_pvt->channel, "presence_call_info");
-                               if (info) {
-                                       if (switch_stristr("private", info)) {
-                                               msg = "hold-private";
-                                       }
-                               }
-                       }
-
-                       sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-                       switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE);
-                       switch_channel_presence(tech_pvt->channel, "unknown", msg, NULL);
-                       changed = 1;
-
-                       if (tech_pvt->max_missed_hold_packets) {
-                               switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets);
-                       }
-
-                       if (!(stream = switch_channel_get_hold_music(tech_pvt->channel))) {
-                               stream = tech_pvt->profile->hold_music;
-                       }
-
-                       if (stream && strcasecmp(stream, "silence")) {
-                               if (!strcasecmp(stream, "indicate_hold")) {
-                                       switch_channel_set_flag(tech_pvt->channel, CF_SUSPEND);
-                                       switch_channel_set_flag(tech_pvt->channel, CF_HOLD);
-                                       switch_ivr_hold_uuid(switch_channel_get_partner_uuid(tech_pvt->channel), NULL, 0);
-                               } else {
-                                       switch_ivr_broadcast(switch_channel_get_partner_uuid(tech_pvt->channel), stream,
-                                                                                SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY);
-                                       switch_yield(250000);
-                               }
-                       }
-               }
-       } else {
-               if (sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
-                       sofia_set_flag(tech_pvt, TFLAG_SIP_HOLD);
-                       switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE);
-                       changed = 1;
-               }
-
-               sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
-
-               if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
-                       const char *uuid;
-                       switch_core_session_t *b_session;
-
-                       switch_yield(250000);
-
-                       if (tech_pvt->max_missed_packets) {
-                               switch_rtp_reset_media_timer(tech_pvt->rtp_session);
-                               switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
-                       }
-
-                       if ((uuid = switch_channel_get_partner_uuid(tech_pvt->channel)) && (b_session = switch_core_session_locate(uuid))) {
-                               switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
-
-                               if (switch_channel_test_flag(tech_pvt->channel, CF_HOLD)) {
-                                       switch_ivr_unhold(b_session);
-                                       switch_channel_clear_flag(tech_pvt->channel, CF_SUSPEND);
-                                       switch_channel_clear_flag(tech_pvt->channel, CF_HOLD);
-                               } else {
-                                       switch_channel_stop_broadcast(b_channel);
-                                       switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
-                               }
-                               switch_core_session_rwunlock(b_session);
-                       }
-
-                       sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-                       switch_channel_mark_hold(tech_pvt->channel, SWITCH_FALSE);
-                       switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL);
-                       changed = 1;
-               }
-       }
-
-       return changed;
-}
-
-void sofia_glue_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session)
-{
-       switch_channel_t *channel = switch_core_session_get_channel(session);
-       switch_t38_options_t *local_t38_options = switch_channel_get_private(channel, "t38_options");
-
-       switch_assert(t38_options);
-       
-       if (!local_t38_options) {
-               local_t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t));
-       }
-
-       local_t38_options->T38MaxBitRate = t38_options->T38MaxBitRate;
-       local_t38_options->T38FaxFillBitRemoval = t38_options->T38FaxFillBitRemoval;
-       local_t38_options->T38FaxTranscodingMMR = t38_options->T38FaxTranscodingMMR;
-       local_t38_options->T38FaxTranscodingJBIG = t38_options->T38FaxTranscodingJBIG;
-       local_t38_options->T38FaxRateManagement = switch_core_session_strdup(session, t38_options->T38FaxRateManagement);
-       local_t38_options->T38FaxMaxBuffer = t38_options->T38FaxMaxBuffer;
-       local_t38_options->T38FaxMaxDatagram = t38_options->T38FaxMaxDatagram;
-       local_t38_options->T38FaxUdpEC = switch_core_session_strdup(session, t38_options->T38FaxUdpEC);
-       local_t38_options->T38VendorInfo = switch_core_session_strdup(session, t38_options->T38VendorInfo);
-       local_t38_options->remote_ip = switch_core_session_strdup(session, t38_options->remote_ip);
-       local_t38_options->remote_port = t38_options->remote_port;
-
-
-       switch_channel_set_private(channel, "t38_options", local_t38_options);
-
-}
-
-static switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_session_t *sdp, sdp_media_t *m)
-{
-       switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options");
-       sdp_attribute_t *attr;
-
-       if (!t38_options) {
-               t38_options = switch_core_session_alloc(tech_pvt->session, sizeof(switch_t38_options_t));
-
-               // set some default value
-               t38_options->T38FaxVersion = 0;
-               t38_options->T38MaxBitRate = 14400;
-               t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, "transferredTCF");
-               t38_options->T38FaxUdpEC = switch_core_session_strdup(tech_pvt->session, "t38UDPRedundancy");
-               t38_options->T38FaxMaxBuffer = 500;
-               t38_options->T38FaxMaxDatagram = 500;
-       }
-
-       t38_options->remote_port = (switch_port_t)m->m_port;
-
-       if (sdp->sdp_origin) {
-               t38_options->sdp_o_line = switch_core_session_strdup(tech_pvt->session, sdp->sdp_origin->o_username);
-       } else {
-               t38_options->sdp_o_line = "unknown";
-       }
-       
-       if (m->m_connections && m->m_connections->c_address) {
-               t38_options->remote_ip = switch_core_session_strdup(tech_pvt->session, m->m_connections->c_address);
-       } else if (sdp && sdp->sdp_connection && sdp->sdp_connection->c_address) {
-               t38_options->remote_ip = switch_core_session_strdup(tech_pvt->session, sdp->sdp_connection->c_address);
-       }
-
-       for (attr = m->m_attributes; attr; attr = attr->a_next) {
-               if (!strcasecmp(attr->a_name, "T38FaxVersion") && attr->a_value) {
-                       t38_options->T38FaxVersion = (uint16_t) atoi(attr->a_value);
-               } else if (!strcasecmp(attr->a_name, "T38MaxBitRate") && attr->a_value) {
-                       t38_options->T38MaxBitRate = (uint32_t) atoi(attr->a_value);
-               } else if (!strcasecmp(attr->a_name, "T38FaxFillBitRemoval")) {
-                       t38_options->T38FaxFillBitRemoval = switch_safe_atoi(attr->a_value, 1);
-               } else if (!strcasecmp(attr->a_name, "T38FaxTranscodingMMR")) {
-                       t38_options->T38FaxTranscodingMMR = switch_safe_atoi(attr->a_value, 1);
-               } else if (!strcasecmp(attr->a_name, "T38FaxTranscodingJBIG")) {
-                       t38_options->T38FaxTranscodingJBIG = switch_safe_atoi(attr->a_value, 1);
-               } else if (!strcasecmp(attr->a_name, "T38FaxRateManagement") && attr->a_value) {
-                       t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, attr->a_value);
-               } else if (!strcasecmp(attr->a_name, "T38FaxMaxBuffer") && attr->a_value) {
-                       t38_options->T38FaxMaxBuffer = (uint32_t) atoi(attr->a_value);
-               } else if (!strcasecmp(attr->a_name, "T38FaxMaxDatagram") && attr->a_value) {
-                       t38_options->T38FaxMaxDatagram = (uint32_t) atoi(attr->a_value);
-               } else if (!strcasecmp(attr->a_name, "T38FaxUdpEC") && attr->a_value) {
-                       t38_options->T38FaxUdpEC = switch_core_session_strdup(tech_pvt->session, attr->a_value);
-               } else if (!strcasecmp(attr->a_name, "T38VendorInfo") && attr->a_value) {
-                       t38_options->T38VendorInfo = switch_core_session_strdup(tech_pvt->session, attr->a_value);
-               }
-       }
-
-       switch_channel_set_variable(tech_pvt->channel, "has_t38", "true");
-       switch_channel_set_private(tech_pvt->channel, "t38_options", t38_options);
-       switch_channel_set_app_flag_key("T38", tech_pvt->channel, CF_APP_T38);
-
-       switch_channel_execute_on(tech_pvt->channel, "sip_execute_on_image");
-       switch_channel_api_on(tech_pvt->channel, "sip_api_on_image");
-
-       return t38_options;
-}
-
-
-switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt)
-{
-       sdp_media_t *m;
-       sdp_parser_t *parser = NULL;
-       sdp_session_t *sdp;
-
-       if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
-               return SWITCH_STATUS_FALSE;
-       }
-
-       if (!(sdp = sdp_session(parser))) {
-               sdp_parser_free(parser);
-               return SWITCH_STATUS_FALSE;
-       }
-
-       switch_event_create(&(*fmtp), SWITCH_EVENT_REQUEST_PARAMS);
-       switch_event_create(&(*pt), SWITCH_EVENT_REQUEST_PARAMS);
-
-       for (m = sdp->sdp_media; m; m = m->m_next) {
-               if (m->m_proto == sdp_proto_rtp) {
-                       sdp_rtpmap_t *map;
-                       
-                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
-                               if (map->rm_encoding) {
-                                       char buf[25] = "";
-                                       char key[128] = "";
-                                       char *br = NULL;
-
-                                       if (map->rm_fmtp) {
-                                               if ((br = strstr(map->rm_fmtp, "bitrate="))) {
-                                                       br += 8;
+                                               if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
+                                                       match = (map->rm_pt == imp->ianacode) ? 1 : 0;
+                                               } else {
+                                                       if (map->rm_encoding) {
+                                                               match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
+                                                       } else {
+                                                               match = 0;
+                                                       }
                                                }
-                                       }
-
-                                       switch_snprintf(buf, sizeof(buf), "%d", map->rm_pt);
 
-                                       if (br) {
-                                               switch_snprintf(key, sizeof(key), "%s:%s", map->rm_encoding, br);
-                                       } else {
-                                               switch_snprintf(key, sizeof(key), "%s", map->rm_encoding);
-                                       }
+                                               if (match) {
+                                                       add_audio_codec(map, ptime, buf, sizeof(buf));
+                                                       break;
+                                               }
                                        
-                                       switch_event_add_header_string(*pt, SWITCH_STACK_BOTTOM, key, buf);
-
-                                       if (map->rm_fmtp) {
-                                               switch_event_add_header_string(*fmtp, SWITCH_STACK_BOTTOM, key, map->rm_fmtp);
                                        }
                                }
-                       }
-               }
-       }
-       
-       sdp_parser_free(parser);
-
-       return SWITCH_STATUS_SUCCESS;
-       
-}
-
-
-void sofia_glue_proxy_codec(switch_core_session_t *session, const char *r_sdp)
-{
-       sdp_media_t *m;
-       sdp_parser_t *parser = NULL;
-       sdp_session_t *sdp;
-       private_object_t *tech_pvt = switch_core_session_get_private(session);
-       sdp_attribute_t *attr;
-       int ptime = 0, dptime = 0;
-
-       if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
-               return;
-       }
-
-       if (!(sdp = sdp_session(parser))) {
-               sdp_parser_free(parser);
-               return;
-       }
-
-       switch_assert(tech_pvt != NULL);
-
-
-       for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
-               if (zstr(attr->a_name)) {
-                       continue;
-               }
-
-               if (!strcasecmp(attr->a_name, "ptime")) {
-                       dptime = atoi(attr->a_value);
-               }
-       }
-
-
-       for (m = sdp->sdp_media; m; m = m->m_next) {
-
-               ptime = dptime;
-               //maxptime = dmaxptime;
-
-               if (m->m_proto == sdp_proto_rtp) {
-                       sdp_rtpmap_t *map;
-                       for (attr = m->m_attributes; attr; attr = attr->a_next) {
-                               if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
-                                       ptime = atoi(attr->a_value);
-                               } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
-                                       //maxptime = atoi(attr->a_value);               
-                               }
-                       }
-
-                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
-                               tech_pvt->iananame = switch_core_session_strdup(tech_pvt->session, map->rm_encoding);
-                               tech_pvt->rm_rate = map->rm_rate;
-                               tech_pvt->codec_ms = ptime;
-                               sofia_glue_tech_set_codec(tech_pvt, 0);
-                               break;
-                       }
-
-                       break;
-               }
-       }
-
-       sdp_parser_free(parser);
-
-}
-
-switch_t38_options_t *sofia_glue_extract_t38_options(switch_core_session_t *session, const char *r_sdp)
-{
-       sdp_media_t *m;
-       sdp_parser_t *parser = NULL;
-       sdp_session_t *sdp;
-       private_object_t *tech_pvt = switch_core_session_get_private(session);
-       switch_t38_options_t *t38_options = NULL;
-
-       if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
-               return 0;
-       }
-
-       if (!(sdp = sdp_session(parser))) {
-               sdp_parser_free(parser);
-               return 0;
-       }
-
-       switch_assert(tech_pvt != NULL);
-
-       for (m = sdp->sdp_media; m; m = m->m_next) {
-               if (m->m_proto == sdp_proto_udptl && m->m_type == sdp_media_image && m->m_port) {
-                       t38_options = tech_process_udptl(tech_pvt, sdp, m);
-                       break;
-               }
-       }
-
-       sdp_parser_free(parser);
-
-       return t38_options;
-
-}
-
-switch_status_t sofia_glue_get_offered_pt(private_object_t *tech_pvt, const switch_codec_implementation_t *mimp, switch_payload_t *pt)
-{
-       int i = 0;
-
-       for (i = 0; i < tech_pvt->num_codecs; i++) {
-               const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
-
-               if (!strcasecmp(imp->iananame, mimp->iananame)) {
-                       *pt = tech_pvt->ianacodes[i];
-
-                       return SWITCH_STATUS_SUCCESS;
-               }
-       }
-
-       return SWITCH_STATUS_FALSE;
-}
-
-
-uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_sdp)
-{
-       uint8_t match = 0;
-       switch_payload_t best_te = 0, te = 0, cng_pt = 0;
-       private_object_t *tech_pvt = switch_core_session_get_private(session);
-       sdp_media_t *m;
-       sdp_attribute_t *attr;
-       int first = 0, last = 0;
-       int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
-       int sendonly = 0, recvonly = 0;
-       int greedy = 0, x = 0, skip = 0, mine = 0;
-       switch_channel_t *channel = switch_core_session_get_channel(session);
-       const char *val;
-       const char *crypto = NULL;
-       int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0;
-       int scrooge = 0;
-       sdp_parser_t *parser = NULL;
-       sdp_session_t *sdp;
-       int reneg = 1;
-       const switch_codec_implementation_t **codec_array;
-       int total_codecs;
-
-
-       codec_array = tech_pvt->codecs;
-       total_codecs = tech_pvt->num_codecs;
-
-
-       if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
-               return 0;
-       }
-
-       if (!(sdp = sdp_session(parser))) {
-               sdp_parser_free(parser);
-               return 0;
-       }
-
-       switch_assert(tech_pvt != NULL);
-
-       greedy = !!sofia_test_pflag(tech_pvt->profile, PFLAG_GREEDY);
-       scrooge = !!sofia_test_pflag(tech_pvt->profile, PFLAG_SCROOGE);
-
-       if ((val = switch_channel_get_variable(channel, "sip_codec_negotiation"))) {
-               if (!strcasecmp(val, "generous")) {
-                       greedy = 0;
-                       scrooge = 0;
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : generous\n" );
-               } else if (!strcasecmp(val, "greedy")) {
-                       greedy = 1;
-                       scrooge = 0;
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : greedy\n" );
-               } else if (!strcasecmp(val, "scrooge")) {
-                       scrooge = 1;
-                       greedy = 1;
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : scrooge\n" );
-               } else {
-                   switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation ignored invalid value : '%s' \n", val );    
-               }               
-       }
-
-       if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
-
-               if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833) {
-
-                       if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) {
-                               tech_pvt->rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n");
-                       }
-               }
-
-               if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833) {
-                       if (strstr(tech_pvt->origin, "Sonus_UAC")) {
-                               tech_pvt->rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
-                                                                 "Hello,\nI see you have a Sonus!\n"
-                                                                 "FYI, Sonus cannot follow the RFC on the proper way to send DTMF.\n"
-                                                                 "Sadly, my creator had to spend several hours figuring this out so I thought you'd like to know that!\n"
-                                                                 "Don't worry, DTMF will work but you may want to ask them to fix it......\n");
-                       }
-               }
-       }
-
-       if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_liberal_dtmf")) && switch_true(val)) {
-               sofia_set_flag_locked(tech_pvt, TFLAG_LIBERAL_DTMF);
-       }
-
-       if ((m = sdp->sdp_media) && 
-               (m->m_mode == sdp_sendonly || m->m_mode == sdp_inactive || 
-                (m->m_connections && m->m_connections->c_address && !strcmp(m->m_connections->c_address, "0.0.0.0")))) {
-               sendonly = 2;                   /* global sendonly always wins */
-       }
-
-       for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
-               if (zstr(attr->a_name)) {
-                       continue;
-               }
-
-               if (!strcasecmp(attr->a_name, "sendonly")) {
-                       sendonly = 1;
-                       switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "recvonly");
-               } else if (!strcasecmp(attr->a_name, "inactive")) {
-                       sendonly = 1;
-                       switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "inactive");
-               } else if (!strcasecmp(attr->a_name, "recvonly")) {
-                       switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "sendonly");
-                       recvonly = 1;
-
-                       if (switch_rtp_ready(tech_pvt->rtp_session)) {
-                               switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, 0);
-                               tech_pvt->max_missed_hold_packets = 0;
-                               tech_pvt->max_missed_packets = 0;
-                       } else {
-                               switch_channel_set_variable(tech_pvt->channel, "rtp_timeout_sec", "0");
-                               switch_channel_set_variable(tech_pvt->channel, "rtp_hold_timeout_sec", "0");
-                       }
-               } else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendrecv")) {
-                       sendonly = 0;
-               } else if (!strcasecmp(attr->a_name, "ptime")) {
-                       dptime = atoi(attr->a_value);
-               } else if (!strcasecmp(attr->a_name, "maxptime")) {
-                       dmaxptime = atoi(attr->a_value);
-               }
-       }
-
-       if (sendonly != 1 && recvonly != 1) {
-               switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", NULL);
-       }
-
-
-       if (sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_HOLD) ||
-               ((val = switch_channel_get_variable(tech_pvt->channel, "sip_disable_hold")) && switch_true(val))) {
-               sendonly = 0;
-       } else {
-
-               if (!tech_pvt->hold_laps) {
-                       tech_pvt->hold_laps++;
-                       if (sofia_glue_toggle_hold(tech_pvt, sendonly)) {
-                               reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_HOLD);
-                               
-                               if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_hold"))) {
-                                       reneg = switch_true(val);
-                               }
-                       }
-                       
-               }
-       }
-
-       if (reneg) {
-               reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE);
-               
-               if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_reinvite"))) {
-                       reneg = switch_true(val);
-               }
-       }
-
-       if (!reneg && tech_pvt->num_negotiated_codecs) {
-               codec_array = tech_pvt->negotiated_codecs;
-               total_codecs = tech_pvt->num_negotiated_codecs;
-       } else if (reneg) {
-               tech_pvt->num_codecs = 0;
-               sofia_glue_tech_prepare_codecs(tech_pvt);
-               codec_array = tech_pvt->codecs;
-               total_codecs = tech_pvt->num_codecs;
-       }
-
-       if (switch_stristr("T38FaxFillBitRemoval:", r_sdp) || switch_stristr("T38FaxTranscodingMMR:", r_sdp) || 
-               switch_stristr("T38FaxTranscodingJBIG:", r_sdp)) {
-               switch_channel_set_variable(tech_pvt->channel, "t38_broken_boolean", "true");
-       }
 
-       find_zrtp_hash(session, sdp);
-       sofia_glue_pass_zrtp_hash(session);
-
-       for (m = sdp->sdp_media; m; m = m->m_next) {
-               sdp_connection_t *connection;
-               switch_core_session_t *other_session;
-
-               ptime = dptime;
-               maxptime = dmaxptime;
-
-               if (m->m_proto == sdp_proto_srtp) {
-                       got_savp++;
-               } else if (m->m_proto == sdp_proto_rtp) {
-                       got_avp++;
-               } else if (m->m_proto == sdp_proto_udptl) {
-                       got_udptl++;
-               }
-
-               if (got_udptl && m->m_type == sdp_media_image && m->m_port) {
-                       switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m);
-
-                       if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_NEGOTIATED)) {
-                               match = 1;
-                               goto done;
-                       }
-
-                       if (switch_true(switch_channel_get_variable(channel, "refuse_t38"))) {
-                               switch_channel_clear_app_flag_key("T38", tech_pvt->channel, CF_APP_T38);
-                               match = 0;
-                               goto done;
                        } else {
-                               const char *var = switch_channel_get_variable(channel, "t38_passthru");
-                               int pass = sofia_test_pflag(tech_pvt->profile, PFLAG_T38_PASSTHRU);
-
-
-                               if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38)) {
-                                       sofia_set_flag(tech_pvt, TFLAG_NOREPLY);
-                               }
-
-                               if (var) {
-                                       if (!(pass = switch_true(var))) {
-                                               if (!strcasecmp(var, "once")) {
-                                                       pass = 2;
-                                               }
-                                       }
-                               }
-
-                               if ((pass == 2 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU)) || 
-                                       !sofia_test_flag(tech_pvt, TFLAG_REINVITE) ||
-                                       switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || 
-                                       switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) || 
-                                       !switch_rtp_ready(tech_pvt->rtp_session)) {
-                                       pass = 0;
-                               }
-                               
-                               if (pass && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
-                                       private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
-                                       switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
-                                       switch_core_session_message_t *msg;
-                                       char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
-                                       switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
-                                       char tmp[32] = "";
-
-                                       if (switch_true(switch_channel_get_variable(tech_pvt->channel, "t38_broken_boolean")) && 
-                                               switch_true(switch_channel_get_variable(tech_pvt->channel, "t38_pass_broken_boolean"))) {
-                                               switch_channel_set_variable(other_channel, "t38_broken_boolean", "true");
-                                       }
-                                       
-                                       tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, t38_options->remote_ip);
-                                       tech_pvt->remote_sdp_audio_port = t38_options->remote_port;
-
-                                       if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
-                                                                                 switch_channel_get_name(tech_pvt->channel));
-                                       } else {
-                                               const char *err = NULL;
-
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
-                                                                                 switch_channel_get_name(tech_pvt->channel),
-                                                                                 remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
-                                               
-                                               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
-                                               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
-                                               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
-
-                                               if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip,
-                                                                                                                 tech_pvt->remote_sdp_audio_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
-                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
-                                                       switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
-                                               }
-                                               
+                               for (i = 0; i < num_codecs; i++) {
+                                       const switch_codec_implementation_t *imp = codecs[i];
+                                       if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO || imp->ianacode > 127 || already_did[imp->ianacode]) {
+                                               continue;
                                        }
-
-                                       
-
-                                       sofia_glue_copy_t38_options(t38_options, other_session);
-
-                                       sofia_set_flag(tech_pvt, TFLAG_T38_PASSTHRU);
-                                       sofia_set_flag(other_tech_pvt, TFLAG_T38_PASSTHRU);
-
-                                       msg = switch_core_session_alloc(other_session, sizeof(*msg));
-                                       msg->message_id = SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA;
-                                       msg->from = __FILE__;
-                                       msg->string_arg = switch_core_session_strdup(other_session, r_sdp);
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing T38 req to other leg.\n%s\n", r_sdp);
-                                       switch_core_session_queue_message(other_session, msg);
-                                       switch_core_session_rwunlock(other_session);
-                               }
-                       }
-
-
-                       /* do nothing here, mod_fax will trigger a response (if it's listening =/) */
-                       match = 1;
-                       goto done;
-               } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) {
-                       sdp_rtpmap_t *map;
-
-                       for (attr = m->m_attributes; attr; attr = attr->a_next) {
-
-                               if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
-                                       switch_channel_set_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port", attr->a_value);
-                               } else if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
-                                       ptime = atoi(attr->a_value);
-                               } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
-                                       maxptime = atoi(attr->a_value);
-                               } else if (!got_crypto && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) {
-                                       int crypto_tag;
-
-                                       if (!(tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_CRYPTO_IN_AVP) && 
-                                               !switch_true(switch_channel_get_variable(tech_pvt->channel, "sip_allow_crypto_in_avp"))) {
-                                               if (m->m_proto != sdp_proto_srtp) {
-                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "a=crypto in RTP/AVP, refer to rfc3711\n");
-                                                       match = 0;
-                                                       goto done;
+                                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                                               if (map->rm_pt > 127 || already_did[map->rm_pt]) {
+                                                       continue;
                                                }
-                                       }
 
-                                       crypto = attr->a_value;
-                                       crypto_tag = atoi(crypto);
-
-                                       if (tech_pvt->remote_crypto_key && switch_rtp_ready(tech_pvt->rtp_session)) {
-                                               /* Compare all the key. The tag may remain the same even if key changed */
-                                               if (crypto && !strcmp(crypto, tech_pvt->remote_crypto_key)) {
-                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Existing key is still valid.\n");
+                                               if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
+                                                       match = (map->rm_pt == imp->ianacode) ? 1 : 0;
                                                } else {
-                                                       const char *a = switch_stristr("AES", tech_pvt->remote_crypto_key);
-                                                       const char *b = switch_stristr("AES", crypto);
-
-                                                       /* Change our key every time we can */
-                                                       
-                                                       if (sofia_test_flag(tech_pvt, TFLAG_CRYPTO_RECOVER)) {
-                                                               sofia_clear_flag(tech_pvt, TFLAG_CRYPTO_RECOVER);
-                                                       } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
-                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_32);
-                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
-                                                               switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt->crypto_type,
-                                                                                                                 tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN);
-                                                       } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
-                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_80);
-                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
-                                                               switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt->crypto_type,
-                                                                                                                 tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN);
-                                                       } else {
-                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n");
-                                                       }
-
-                                                       if (a && b && !strncasecmp(a, b, 23)) {
-                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Change Remote key to [%s]\n", crypto);
-                                                               tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto);
-                                                               switch_channel_set_variable(tech_pvt->channel, "srtp_remote_audio_crypto_key", crypto);
-                                                               tech_pvt->crypto_tag = crypto_tag;
-                                                               
-                                                               if (switch_rtp_ready(tech_pvt->rtp_session) && sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
-                                                                       sofia_glue_add_crypto(tech_pvt, tech_pvt->remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
-                                                                       switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_RECV, tech_pvt->crypto_tag,
-                                                                                                                         tech_pvt->crypto_type, tech_pvt->remote_raw_key, SWITCH_RTP_KEY_LEN);
-                                                               }
-                                                               got_crypto++;
+                                                       if (map->rm_encoding) {
+                                                               match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
                                                        } else {
-                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ignoring unacceptable key\n");
+                                                               match = 0;
                                                        }
                                                }
-                                       } else if (!switch_rtp_ready(tech_pvt->rtp_session)) {
-                                               tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto);
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set Remote Key [%s]\n", tech_pvt->remote_crypto_key);
-                                               switch_channel_set_variable(tech_pvt->channel, "srtp_remote_audio_crypto_key", crypto);
-                                               tech_pvt->crypto_tag = crypto_tag;
-                                               got_crypto++;
-
-                                               if (zstr(tech_pvt->local_crypto_key)) {
-                                                       if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
-                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_32);
-                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
-                                                       } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
-                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_80);
-                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
-                                                       } else {
-                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n");
-                                                       }
+
+                                               if (match) {
+                                                       add_audio_codec(map, ptime, buf, sizeof(buf));
+                                                       break;
                                                }
                                        }
                                }
                        }
 
-                       if (got_crypto && !got_avp) {
-                               switch_channel_set_variable(tech_pvt->channel, SOFIA_CRYPTO_MANDATORY_VARIABLE, "true");
-                               switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE, "true");
-                       }
-
+               } else if (m->m_type == sdp_media_video && m->m_port) {
                        connection = sdp->sdp_connection;
                        if (m->m_connections) {
                                connection = m->m_connections;
                        }
 
                        if (!connection) {
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
-                               match = 0;
+                               switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
                                break;
                        }
-
-               greed:
-                       x = 0;
-
-                       if (tech_pvt->rm_encoding && !(sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF))) {     // && !sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
-                               char *remote_host = tech_pvt->remote_sdp_audio_ip;
-                               switch_port_t remote_port = tech_pvt->remote_sdp_audio_port;
-                               int same = 0;
-
-                               if (switch_rtp_ready(tech_pvt->rtp_session)) {
-                                       remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
-                                       remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
-                               }
-
-                               for (map = m->m_rtpmaps; map; map = map->rm_next) {
-                                       if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
-                                               match = (map->rm_pt == tech_pvt->pt) ? 1 : 0;
-                                       } else {
-                                               match = strcasecmp(switch_str_nil(map->rm_encoding), tech_pvt->iananame) ? 0 : 1;
-                                       }
-
-                                       if (match && connection->c_address && remote_host && !strcmp(connection->c_address, remote_host) && m->m_port == remote_port) {
-                                               same = 1;
-                                       } else {
-                                               same = 0;
-                                               break;
-                                       }
-                               }
-
-                               if (same) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
-                                                                         "Our existing sdp is still good [%s %s:%d], let's keep it.\n",
-                                                                         tech_pvt->rm_encoding, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
-                                       got_audio = 1;
-                               } else {
-                                       match = 0;
-                                       got_audio = 0;
-                               }
-                       }
-
-                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
-                               int32_t i;
-                               uint32_t near_rate = 0;
-                               const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
-                               const char *rm_encoding;
-                               uint32_t map_bit_rate = 0;
-                               int codec_ms = 0;
-                               switch_codec_fmtp_t codec_fmtp = { 0 };
-
-                               if (x++ < skip) {
-                                       continue;
-                               }
-
-                               if (!(rm_encoding = map->rm_encoding)) {
-                                       rm_encoding = "";
-                               }
-
-                               if (!strcasecmp(rm_encoding, "telephone-event")) {
-                                       if (!best_te || map->rm_rate == tech_pvt->rm_rate) {
-                                               best_te = (switch_payload_t) map->rm_pt;
-                                       }
-                               }
-                               
-                               if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && !cng_pt && !strcasecmp(rm_encoding, "CN")) {
-                                       cng_pt = (switch_payload_t) map->rm_pt;
-                                       if (tech_pvt->rtp_session) {
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
-                                               switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
-                                       }
-                               }
-
-                               if (match) {
+                       for (i = 0; i < num_codecs; i++) {
+                               const switch_codec_implementation_t *imp = codecs[i];
+                               if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) {
                                        continue;
                                }
-
-                               if (greedy) {
-                                       first = mine;
-                                       last = first + 1;
-                               } else {
-                                       first = 0;
-                                       last = tech_pvt->num_codecs;
-                               }
-
-                               codec_ms = ptime;
-
-                               if (maxptime && (!codec_ms || codec_ms > maxptime)) {
-                                       codec_ms = maxptime;
-                               }
-
-                               if (!codec_ms) {
-                                       codec_ms = switch_default_ptime(rm_encoding, map->rm_pt);
-                               }
-
-                               map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt);
-                               
-                               if (!ptime && !strcasecmp(map->rm_encoding, "g723")) {
-                                       codec_ms = 30;
-                               }
-                               
-                               if (zstr(map->rm_fmtp)) {
-                                       if (!strcasecmp(map->rm_encoding, "ilbc")) {
-                                               codec_ms = 30;
-                                               map_bit_rate = 13330;
-                                       }
-                               } else {
-                                       if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) {
-                                               if (codec_fmtp.bits_per_second) {
-                                                       map_bit_rate = codec_fmtp.bits_per_second;
-                                               }
-                                               if (codec_fmtp.microseconds_per_packet) {
-                                                       codec_ms = (codec_fmtp.microseconds_per_packet / 1000);
-                                               }
-                                       }
-                               }
-
-                               
-                               for (i = first; i < last && i < total_codecs; i++) {
-                                       const switch_codec_implementation_t *imp = codec_array[i];
-                                       uint32_t bit_rate = imp->bits_per_second;
-                                       uint32_t codec_rate = imp->samples_per_second;
-                                       if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+                               for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                                       if (map->rm_pt > 127 || already_did[map->rm_pt]) {
                                                continue;
                                        }
 
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n",
-                                                                         rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate,
-                                                                         imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate);
                                        if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
                                                match = (map->rm_pt == imp->ianacode) ? 1 : 0;
                                        } else {
-                                               match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
-                                       }
-
-                                       if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) {
-                                               /* if a bit rate is specified and doesn't match, this is not a codec match, except for ILBC */
-                                               match = 0;
+                                               if (map->rm_encoding) {
+                                                       match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
+                                               } else {
+                                                       match = 0;
+                                               }
                                        }
 
-                                       if (match && map->rm_rate && codec_rate && map->rm_rate != codec_rate && (!strcasecmp(map->rm_encoding, "pcma") || !strcasecmp(map->rm_encoding, "pcmu"))) {
-                                               /* if the sampling rate is specified and doesn't match, this is not a codec match for G.711 */
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sampling rates have to match for G.711\n");
-                                               match = 0;
-                                       }
-                                       
                                        if (match) {
-                                               if (scrooge) {
-                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
-                                                                                         "Bah HUMBUG! Sticking with %s@%uh@%ui\n",
-                                                                                         imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000);
+                                               if (ptime > 0) {
+                                                       switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate,
+                                                                                       ptime);
                                                } else {
-                                                       if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) {
-                                                               near_rate = map->rm_rate;
-                                                               near_match = imp;
-                                                               match = 0;
-                                                               continue;
-                                                       }
+                                                       switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate);
                                                }
-                                               mimp = imp;
+                                               already_did[imp->ianacode] = 1;
                                                break;
                                        }
                                }
+                       }
+               }
+       }
+       if (buf[0] == ',') {
+               switch_channel_set_variable(channel, "ep_codec_string", buf + 1);
+       }
+}
 
-                               if (!match && near_match) {
-                                       const switch_codec_implementation_t *search[1];
-                                       char *prefs[1];
-                                       char tmp[80];
-                                       int num;
+switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_sdp)
+{
+       uint8_t match = 0;
 
-                                       switch_snprintf(tmp, sizeof(tmp), "%s@%uh@%ui", near_match->iananame, near_rate ? near_rate : near_match->samples_per_second,
-                                                                       codec_ms);
+       switch_assert(tech_pvt != NULL);
+       switch_assert(r_sdp != NULL);
 
-                                       prefs[0] = tmp;
-                                       num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
+       if (zstr(r_sdp)) {
+               return SWITCH_STATUS_FALSE;
+       }
 
-                                       if (num) {
-                                               mimp = search[0];
-                                       } else {
-                                               mimp = near_match;
-                                       }
+       if ((match = sofia_glue_negotiate_sdp(tech_pvt->session, r_sdp))) {
+               if (sofia_glue_tech_choose_port(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+                       return SWITCH_STATUS_FALSE;
+               }
+               if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+                       return SWITCH_STATUS_FALSE;
+               }
+               switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA");
+               sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
+               switch_channel_mark_pre_answered(tech_pvt->channel);
+               return SWITCH_STATUS_SUCCESS;
+       }
 
-                                       if (!maxptime || mimp->microseconds_per_packet / 1000 <= maxptime) {
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Substituting codec %s@%ui@%uh\n",
-                                                                                 mimp->iananame, mimp->microseconds_per_packet / 1000, mimp->samples_per_second);
-                                               match = 1;
-                                       } else {
-                                               mimp = NULL;
-                                               match = 0;
-                                       }
 
-                               }
+       return SWITCH_STATUS_FALSE;
+}
 
-                               if (!match && greedy) {
-                                       skip++;
-                                       continue;
-                               }
+int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
+{
+       int changed = 0;
 
-                               if (mimp) {
-                                       char tmp[50];
-                                       const char *mirror = switch_channel_get_variable(tech_pvt->channel, "sip_mirror_remote_audio_codec_payload");
-
-                                       tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *) map->rm_encoding);
-                                       tech_pvt->iananame = switch_core_session_strdup(session, (char *) mimp->iananame);
-                                       tech_pvt->pt = (switch_payload_t) map->rm_pt;
-                                       tech_pvt->rm_rate = mimp->samples_per_second;
-                                       tech_pvt->codec_ms = mimp->microseconds_per_packet / 1000;
-                                       tech_pvt->bitrate = mimp->bits_per_second;
-                                       tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address);
-                                       tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
-                                       tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port;
-                                       tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt;
-                                       tech_pvt->num_negotiated_codecs = 0;
-                                       tech_pvt->negotiated_codecs[tech_pvt->num_negotiated_codecs++] = mimp;
-                                       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
-                                       switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
-                                       switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
-                                       tech_pvt->audio_recv_pt = (switch_payload_t)map->rm_pt;
-                                       
-                                       if (!switch_true(mirror) && 
-                                               switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && 
-                                               (!sofia_test_flag(tech_pvt, TFLAG_REINVITE) || sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE))) {
-                                               sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->audio_recv_pt);
-                                       }
-                                       
-                                       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->audio_recv_pt);
-                                       switch_channel_set_variable(tech_pvt->channel, "sip_audio_recv_pt", tmp);
-                                       
-                               }
-                               
-                               if (match) {
-                                       if (sofia_glue_tech_set_codec(tech_pvt, 1) == SWITCH_STATUS_SUCCESS) {
-                                               got_audio = 1;
-                                       } else {
-                                               match = 0;
-                                       }
-                               }
-                       }
+       if (sofia_test_flag(tech_pvt, TFLAG_SLA_BARGE) || sofia_test_flag(tech_pvt, TFLAG_SLA_BARGING)) {
+               switch_channel_mark_hold(tech_pvt->channel, sendonly);
+               return 0;
+       }
 
-                       if (!best_te && (sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF))) {
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, 
-                                                                 "No 2833 in SDP. Liberal DTMF mode adding %d as telephone-event.\n", tech_pvt->profile->te);
-                               best_te = tech_pvt->profile->te;
-                       }
+       if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) {
+               if (!sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+                       const char *stream;
+                       const char *msg = "hold";
 
-                       if (best_te) {
-                               if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
-                                       te = tech_pvt->te = (switch_payload_t) best_te;
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", best_te);
-                                       if (tech_pvt->rtp_session) {
-                                               switch_rtp_set_telephony_event(tech_pvt->rtp_session, (switch_payload_t) best_te);
-                                               switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", best_te);
-                                       }
-                               } else {
-                                       te = tech_pvt->recv_te = tech_pvt->te = (switch_payload_t) best_te;
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send/recv payload to %u\n", te);
-                                       if (tech_pvt->rtp_session) {
-                                               switch_rtp_set_telephony_event(tech_pvt->rtp_session, te);
-                                               switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", te);
-                                               switch_rtp_set_telephony_recv_event(tech_pvt->rtp_session, te);
-                                               switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_recv_payload", "%d", te);
+                       if (sofia_test_pflag(tech_pvt->profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
+                               const char *info = switch_channel_get_variable(tech_pvt->channel, "presence_call_info");
+                               if (info) {
+                                       if (switch_stristr("private", info)) {
+                                               msg = "hold-private";
                                        }
                                }
-                       } else {
-                               /* by default, use SIP INFO if 2833 is not in the SDP */
-                               if (!switch_false(switch_channel_get_variable(channel, "sip_info_when_no_2833"))) {
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No 2833 in SDP.  Disable 2833 dtmf and switch to INFO\n");
-                                       switch_channel_set_variable(tech_pvt->channel, "dtmf_type", "info");
-                                       tech_pvt->dtmf_type = DTMF_INFO;
-                                       te = tech_pvt->recv_te = tech_pvt->te = 0;
-                               } else {
-                                       switch_channel_set_variable(tech_pvt->channel, "dtmf_type", "none");
-                                       tech_pvt->dtmf_type = DTMF_NONE;
-                                       te = tech_pvt->recv_te = tech_pvt->te = 0;
-                               }
-                       }
-
-                       
-                       if (!match && greedy && mine < total_codecs) {
-                               mine++;
-                               skip = 0;
-                               goto greed;
                        }
 
-               } else if (m->m_type == sdp_media_video && m->m_port) {
-                       sdp_rtpmap_t *map;
-                       const char *rm_encoding;
-                       const switch_codec_implementation_t *mimp = NULL;
-                       int vmatch = 0, i;
-                       switch_channel_set_variable(tech_pvt->channel, "video_possible", "true");
+                       sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                       switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE);
+                       switch_channel_presence(tech_pvt->channel, "unknown", msg, NULL);
+                       changed = 1;
 
-                       connection = sdp->sdp_connection;
-                       if (m->m_connections) {
-                               connection = m->m_connections;
+                       if (tech_pvt->max_missed_hold_packets) {
+                               switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets);
                        }
 
-                       if (!connection) {
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
-                               match = 0;
-                               break;
+                       if (!(stream = switch_channel_get_hold_music(tech_pvt->channel))) {
+                               stream = tech_pvt->profile->hold_music;
                        }
 
-                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
-
-                               for (attr = m->m_attributes; attr; attr = attr->a_next) {
-                                       if (!strcasecmp(attr->a_name, "framerate") && attr->a_value) {
-                                               //framerate = atoi(attr->a_value);
-                                       }
-                                       if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
-                                               switch_channel_set_variable(tech_pvt->channel, "sip_remote_video_rtcp_port", attr->a_value);
-                                       }
-                               }
-                               if (!(rm_encoding = map->rm_encoding)) {
-                                       rm_encoding = "";
+                       if (stream && strcasecmp(stream, "silence")) {
+                               if (!strcasecmp(stream, "indicate_hold")) {
+                                       switch_channel_set_flag(tech_pvt->channel, CF_SUSPEND);
+                                       switch_channel_set_flag(tech_pvt->channel, CF_HOLD);
+                                       switch_ivr_hold_uuid(switch_channel_get_partner_uuid(tech_pvt->channel), NULL, 0);
+                               } else {
+                                       switch_ivr_broadcast(switch_channel_get_partner_uuid(tech_pvt->channel), stream,
+                                                                                SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY);
+                                       switch_yield(250000);
                                }
+                       }
+               }
+       } else {
+               if (sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+                       sofia_set_flag(tech_pvt, TFLAG_SIP_HOLD);
+                       switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE);
+                       changed = 1;
+               }
 
-                               for (i = 0; i < total_codecs; i++) {
-                                       const switch_codec_implementation_t *imp = codec_array[i];
-
-                                       if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
-                                               continue;
-                                       }
-
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d]/[%s:%d]\n",
-                                                                         rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
-                                       if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
-                                               vmatch = (map->rm_pt == imp->ianacode) ? 1 : 0;
-                                       } else {
-                                               vmatch = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
-                                       }
+               sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
 
+               if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+                       const char *uuid;
+                       switch_core_session_t *b_session;
 
-                                       if (vmatch && (map->rm_rate == imp->samples_per_second)) {
-                                               mimp = imp;
-                                               break;
-                                       } else {
-                                               vmatch = 0;
-                                       }
-                               }
+                       switch_yield(250000);
 
-                               if (mimp) {
-                                       if ((tech_pvt->video_rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) {
-                                               char tmp[50];
-                                               const char *mirror = switch_channel_get_variable(tech_pvt->channel, "sip_mirror_remote_video_codec_payload");
-
-                                               tech_pvt->video_pt = (switch_payload_t) map->rm_pt;
-                                               tech_pvt->video_rm_rate = map->rm_rate;
-                                               tech_pvt->video_codec_ms = mimp->microseconds_per_packet / 1000;
-                                               tech_pvt->remote_sdp_video_ip = switch_core_session_strdup(session, (char *) connection->c_address);
-                                               tech_pvt->video_rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
-                                               tech_pvt->remote_sdp_video_port = (switch_port_t) m->m_port;
-                                               tech_pvt->video_agreed_pt = (switch_payload_t) map->rm_pt;
-                                               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_video_port);
-                                               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
-                                               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp);
-                                               switch_channel_set_variable(tech_pvt->channel, "sip_video_fmtp", tech_pvt->video_rm_fmtp);
-                                               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->video_agreed_pt);
-                                               switch_channel_set_variable(tech_pvt->channel, "sip_video_pt", tmp);
-                                               sofia_glue_check_video_codecs(tech_pvt);
-
-                                               tech_pvt->video_recv_pt = (switch_payload_t)map->rm_pt;
-                                               
-                                               if (!switch_true(mirror) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
-                                                       sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->video_recv_pt);
-                                               }
+                       if (tech_pvt->max_missed_packets) {
+                               switch_rtp_reset_media_timer(tech_pvt->rtp_session);
+                               switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
+                       }
 
-                                               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->video_recv_pt);
-                                               switch_channel_set_variable(tech_pvt->channel, "sip_video_recv_pt", tmp);
-                                               if (!match && vmatch) match = 1;
+                       if ((uuid = switch_channel_get_partner_uuid(tech_pvt->channel)) && (b_session = switch_core_session_locate(uuid))) {
+                               switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
 
-                                               break;
-                                       } else {
-                                               vmatch = 0;
-                                       }
+                               if (switch_channel_test_flag(tech_pvt->channel, CF_HOLD)) {
+                                       switch_ivr_unhold(b_session);
+                                       switch_channel_clear_flag(tech_pvt->channel, CF_SUSPEND);
+                                       switch_channel_clear_flag(tech_pvt->channel, CF_HOLD);
+                               } else {
+                                       switch_channel_stop_broadcast(b_channel);
+                                       switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
                                }
+                               switch_core_session_rwunlock(b_session);
                        }
+
+                       sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                       switch_channel_mark_hold(tech_pvt->channel, SWITCH_FALSE);
+                       switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL);
+                       changed = 1;
                }
        }
 
- done:
+       return changed;
+}
+
+void sofia_glue_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session)
+{
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       switch_t38_options_t *local_t38_options = switch_channel_get_private(channel, "t38_options");
 
-       if (parser) {
-               sdp_parser_free(parser);
+       switch_assert(t38_options);
+       
+       if (!local_t38_options) {
+               local_t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t));
        }
 
-       tech_pvt->cng_pt = cng_pt;
-       sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
+       local_t38_options->T38MaxBitRate = t38_options->T38MaxBitRate;
+       local_t38_options->T38FaxFillBitRemoval = t38_options->T38FaxFillBitRemoval;
+       local_t38_options->T38FaxTranscodingMMR = t38_options->T38FaxTranscodingMMR;
+       local_t38_options->T38FaxTranscodingJBIG = t38_options->T38FaxTranscodingJBIG;
+       local_t38_options->T38FaxRateManagement = switch_core_session_strdup(session, t38_options->T38FaxRateManagement);
+       local_t38_options->T38FaxMaxBuffer = t38_options->T38FaxMaxBuffer;
+       local_t38_options->T38FaxMaxDatagram = t38_options->T38FaxMaxDatagram;
+       local_t38_options->T38FaxUdpEC = switch_core_session_strdup(session, t38_options->T38FaxUdpEC);
+       local_t38_options->T38VendorInfo = switch_core_session_strdup(session, t38_options->T38VendorInfo);
+       local_t38_options->remote_ip = switch_core_session_strdup(session, t38_options->remote_ip);
+       local_t38_options->remote_port = t38_options->remote_port;
+
+
+       switch_channel_set_private(channel, "t38_options", local_t38_options);
 
-       return match;
 }
 
 /* map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 */
diff --git a/src/mod/endpoints/mod_sofia/sofia_media.c b/src/mod/endpoints/mod_sofia/sofia_media.c
new file mode 100644 (file)
index 0000000..d392d85
--- /dev/null
@@ -0,0 +1,1865 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ *
+ *
+ * sofia_media.c -- SOFIA SIP Endpoint (sofia media code)
+ *
+ */
+#include "mod_sofia.h"
+
+
+switch_status_t sofia_glue_get_offered_pt(private_object_t *tech_pvt, const switch_codec_implementation_t *mimp, switch_payload_t *pt)
+{
+       int i = 0;
+
+       for (i = 0; i < tech_pvt->num_codecs; i++) {
+               const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+
+               if (!strcasecmp(imp->iananame, mimp->iananame)) {
+                       *pt = tech_pvt->ianacodes[i];
+
+                       return SWITCH_STATUS_SUCCESS;
+               }
+       }
+
+       return SWITCH_STATUS_FALSE;
+}
+
+
+void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt)
+{
+       const char *sdp_str;
+
+       if ((sdp_str = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) {
+               sdp_parser_t *parser;
+               sdp_session_t *sdp;
+               sdp_media_t *m;
+               sdp_connection_t *connection;
+
+               if ((parser = sdp_parse(NULL, sdp_str, (int) strlen(sdp_str), 0))) {
+                       if ((sdp = sdp_session(parser))) {
+                               for (m = sdp->sdp_media; m; m = m->m_next) {
+                                       if (m->m_type != sdp_media_audio || !m->m_port) {
+                                               continue;
+                                       }
+
+                                       connection = sdp->sdp_connection;
+                                       if (m->m_connections) {
+                                               connection = m->m_connections;
+                                       }
+
+                                       if (connection) {
+                                               tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, connection->c_address);
+                                       }
+                                       tech_pvt->proxy_sdp_audio_port = (switch_port_t) m->m_port;
+                                       if (tech_pvt->proxy_sdp_audio_ip && tech_pvt->proxy_sdp_audio_port) {
+                                               break;
+                                       }
+                               }
+                       }
+                       sdp_parser_free(parser);
+               }
+               sofia_glue_tech_set_local_sdp(tech_pvt, sdp_str, SWITCH_TRUE);
+       }
+}
+
+
+
+switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt)
+{
+       sdp_media_t *m;
+       sdp_parser_t *parser = NULL;
+       sdp_session_t *sdp;
+
+       if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       if (!(sdp = sdp_session(parser))) {
+               sdp_parser_free(parser);
+               return SWITCH_STATUS_FALSE;
+       }
+
+       switch_event_create(&(*fmtp), SWITCH_EVENT_REQUEST_PARAMS);
+       switch_event_create(&(*pt), SWITCH_EVENT_REQUEST_PARAMS);
+
+       for (m = sdp->sdp_media; m; m = m->m_next) {
+               if (m->m_proto == sdp_proto_rtp) {
+                       sdp_rtpmap_t *map;
+                       
+                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                               if (map->rm_encoding) {
+                                       char buf[25] = "";
+                                       char key[128] = "";
+                                       char *br = NULL;
+
+                                       if (map->rm_fmtp) {
+                                               if ((br = strstr(map->rm_fmtp, "bitrate="))) {
+                                                       br += 8;
+                                               }
+                                       }
+
+                                       switch_snprintf(buf, sizeof(buf), "%d", map->rm_pt);
+
+                                       if (br) {
+                                               switch_snprintf(key, sizeof(key), "%s:%s", map->rm_encoding, br);
+                                       } else {
+                                               switch_snprintf(key, sizeof(key), "%s", map->rm_encoding);
+                                       }
+                                       
+                                       switch_event_add_header_string(*pt, SWITCH_STACK_BOTTOM, key, buf);
+
+                                       if (map->rm_fmtp) {
+                                               switch_event_add_header_string(*fmtp, SWITCH_STACK_BOTTOM, key, map->rm_fmtp);
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       sdp_parser_free(parser);
+
+       return SWITCH_STATUS_SUCCESS;
+       
+}
+
+
+void sofia_glue_proxy_codec(switch_core_session_t *session, const char *r_sdp)
+{
+       sdp_media_t *m;
+       sdp_parser_t *parser = NULL;
+       sdp_session_t *sdp;
+       private_object_t *tech_pvt = switch_core_session_get_private(session);
+       sdp_attribute_t *attr;
+       int ptime = 0, dptime = 0;
+
+       if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+               return;
+       }
+
+       if (!(sdp = sdp_session(parser))) {
+               sdp_parser_free(parser);
+               return;
+       }
+
+       switch_assert(tech_pvt != NULL);
+
+
+       for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
+               if (zstr(attr->a_name)) {
+                       continue;
+               }
+
+               if (!strcasecmp(attr->a_name, "ptime")) {
+                       dptime = atoi(attr->a_value);
+               }
+       }
+
+
+       for (m = sdp->sdp_media; m; m = m->m_next) {
+
+               ptime = dptime;
+               //maxptime = dmaxptime;
+
+               if (m->m_proto == sdp_proto_rtp) {
+                       sdp_rtpmap_t *map;
+                       for (attr = m->m_attributes; attr; attr = attr->a_next) {
+                               if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
+                                       ptime = atoi(attr->a_value);
+                               } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
+                                       //maxptime = atoi(attr->a_value);               
+                               }
+                       }
+
+                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                               tech_pvt->iananame = switch_core_session_strdup(tech_pvt->session, map->rm_encoding);
+                               tech_pvt->rm_rate = map->rm_rate;
+                               tech_pvt->codec_ms = ptime;
+                               sofia_glue_tech_set_codec(tech_pvt, 0);
+                               break;
+                       }
+
+                       break;
+               }
+       }
+
+       sdp_parser_free(parser);
+
+}
+
+switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_session_t *sdp, sdp_media_t *m)
+{
+       switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options");
+       sdp_attribute_t *attr;
+
+       if (!t38_options) {
+               t38_options = switch_core_session_alloc(tech_pvt->session, sizeof(switch_t38_options_t));
+
+               // set some default value
+               t38_options->T38FaxVersion = 0;
+               t38_options->T38MaxBitRate = 14400;
+               t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, "transferredTCF");
+               t38_options->T38FaxUdpEC = switch_core_session_strdup(tech_pvt->session, "t38UDPRedundancy");
+               t38_options->T38FaxMaxBuffer = 500;
+               t38_options->T38FaxMaxDatagram = 500;
+       }
+
+       t38_options->remote_port = (switch_port_t)m->m_port;
+
+       if (sdp->sdp_origin) {
+               t38_options->sdp_o_line = switch_core_session_strdup(tech_pvt->session, sdp->sdp_origin->o_username);
+       } else {
+               t38_options->sdp_o_line = "unknown";
+       }
+       
+       if (m->m_connections && m->m_connections->c_address) {
+               t38_options->remote_ip = switch_core_session_strdup(tech_pvt->session, m->m_connections->c_address);
+       } else if (sdp && sdp->sdp_connection && sdp->sdp_connection->c_address) {
+               t38_options->remote_ip = switch_core_session_strdup(tech_pvt->session, sdp->sdp_connection->c_address);
+       }
+
+       for (attr = m->m_attributes; attr; attr = attr->a_next) {
+               if (!strcasecmp(attr->a_name, "T38FaxVersion") && attr->a_value) {
+                       t38_options->T38FaxVersion = (uint16_t) atoi(attr->a_value);
+               } else if (!strcasecmp(attr->a_name, "T38MaxBitRate") && attr->a_value) {
+                       t38_options->T38MaxBitRate = (uint32_t) atoi(attr->a_value);
+               } else if (!strcasecmp(attr->a_name, "T38FaxFillBitRemoval")) {
+                       t38_options->T38FaxFillBitRemoval = switch_safe_atoi(attr->a_value, 1);
+               } else if (!strcasecmp(attr->a_name, "T38FaxTranscodingMMR")) {
+                       t38_options->T38FaxTranscodingMMR = switch_safe_atoi(attr->a_value, 1);
+               } else if (!strcasecmp(attr->a_name, "T38FaxTranscodingJBIG")) {
+                       t38_options->T38FaxTranscodingJBIG = switch_safe_atoi(attr->a_value, 1);
+               } else if (!strcasecmp(attr->a_name, "T38FaxRateManagement") && attr->a_value) {
+                       t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, attr->a_value);
+               } else if (!strcasecmp(attr->a_name, "T38FaxMaxBuffer") && attr->a_value) {
+                       t38_options->T38FaxMaxBuffer = (uint32_t) atoi(attr->a_value);
+               } else if (!strcasecmp(attr->a_name, "T38FaxMaxDatagram") && attr->a_value) {
+                       t38_options->T38FaxMaxDatagram = (uint32_t) atoi(attr->a_value);
+               } else if (!strcasecmp(attr->a_name, "T38FaxUdpEC") && attr->a_value) {
+                       t38_options->T38FaxUdpEC = switch_core_session_strdup(tech_pvt->session, attr->a_value);
+               } else if (!strcasecmp(attr->a_name, "T38VendorInfo") && attr->a_value) {
+                       t38_options->T38VendorInfo = switch_core_session_strdup(tech_pvt->session, attr->a_value);
+               }
+       }
+
+       switch_channel_set_variable(tech_pvt->channel, "has_t38", "true");
+       switch_channel_set_private(tech_pvt->channel, "t38_options", t38_options);
+       switch_channel_set_app_flag_key("T38", tech_pvt->channel, CF_APP_T38);
+
+       switch_channel_execute_on(tech_pvt->channel, "sip_execute_on_image");
+       switch_channel_api_on(tech_pvt->channel, "sip_api_on_image");
+
+       return t38_options;
+}
+
+
+
+
+switch_t38_options_t *sofia_glue_extract_t38_options(switch_core_session_t *session, const char *r_sdp)
+{
+       sdp_media_t *m;
+       sdp_parser_t *parser = NULL;
+       sdp_session_t *sdp;
+       private_object_t *tech_pvt = switch_core_session_get_private(session);
+       switch_t38_options_t *t38_options = NULL;
+
+       if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+               return 0;
+       }
+
+       if (!(sdp = sdp_session(parser))) {
+               sdp_parser_free(parser);
+               return 0;
+       }
+
+       switch_assert(tech_pvt != NULL);
+
+       for (m = sdp->sdp_media; m; m = m->m_next) {
+               if (m->m_proto == sdp_proto_udptl && m->m_type == sdp_media_image && m->m_port) {
+                       t38_options = tech_process_udptl(tech_pvt, sdp, m);
+                       break;
+               }
+       }
+
+       sdp_parser_free(parser);
+
+       return t38_options;
+
+}
+
+switch_status_t sofia_glue_add_crypto(private_object_t *tech_pvt, 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;
+
+
+       if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+               goto bad;
+       }
+
+       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->crypto_send_type = type;
+                               memcpy(tech_pvt->local_raw_key, key, SWITCH_RTP_KEY_LEN);
+                       } else {
+                               tech_pvt->crypto_recv_type = type;
+                               memcpy(tech_pvt->remote_raw_key, key, SWITCH_RTP_KEY_LEN);
+                       }
+                       return SWITCH_STATUS_SUCCESS;
+               }
+
+       }
+
+ bad:
+
+       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Error!\n");
+       return SWITCH_STATUS_FALSE;
+
+}
+
+
+
+uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_sdp)
+{
+       uint8_t match = 0;
+       switch_payload_t best_te = 0, te = 0, cng_pt = 0;
+       private_object_t *tech_pvt = switch_core_session_get_private(session);
+       sdp_media_t *m;
+       sdp_attribute_t *attr;
+       int first = 0, last = 0;
+       int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
+       int sendonly = 0, recvonly = 0;
+       int greedy = 0, x = 0, skip = 0, mine = 0;
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       const char *val;
+       const char *crypto = NULL;
+       int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0;
+       int scrooge = 0;
+       sdp_parser_t *parser = NULL;
+       sdp_session_t *sdp;
+       int reneg = 1;
+       const switch_codec_implementation_t **codec_array;
+       int total_codecs;
+
+
+       codec_array = tech_pvt->codecs;
+       total_codecs = tech_pvt->num_codecs;
+
+
+       if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+               return 0;
+       }
+
+       if (!(sdp = sdp_session(parser))) {
+               sdp_parser_free(parser);
+               return 0;
+       }
+
+       switch_assert(tech_pvt != NULL);
+
+       greedy = !!sofia_test_pflag(tech_pvt->profile, PFLAG_GREEDY);
+       scrooge = !!sofia_test_pflag(tech_pvt->profile, PFLAG_SCROOGE);
+
+       if ((val = switch_channel_get_variable(channel, "sip_codec_negotiation"))) {
+               if (!strcasecmp(val, "generous")) {
+                       greedy = 0;
+                       scrooge = 0;
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : generous\n" );
+               } else if (!strcasecmp(val, "greedy")) {
+                       greedy = 1;
+                       scrooge = 0;
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : greedy\n" );
+               } else if (!strcasecmp(val, "scrooge")) {
+                       scrooge = 1;
+                       greedy = 1;
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : scrooge\n" );
+               } else {
+                   switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation ignored invalid value : '%s' \n", val );    
+               }               
+       }
+
+       if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
+
+               if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833) {
+
+                       if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) {
+                               tech_pvt->rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n");
+                       }
+               }
+
+               if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833) {
+                       if (strstr(tech_pvt->origin, "Sonus_UAC")) {
+                               tech_pvt->rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
+                                                                 "Hello,\nI see you have a Sonus!\n"
+                                                                 "FYI, Sonus cannot follow the RFC on the proper way to send DTMF.\n"
+                                                                 "Sadly, my creator had to spend several hours figuring this out so I thought you'd like to know that!\n"
+                                                                 "Don't worry, DTMF will work but you may want to ask them to fix it......\n");
+                       }
+               }
+       }
+
+       if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_liberal_dtmf")) && switch_true(val)) {
+               sofia_set_flag_locked(tech_pvt, TFLAG_LIBERAL_DTMF);
+       }
+
+       if ((m = sdp->sdp_media) && 
+               (m->m_mode == sdp_sendonly || m->m_mode == sdp_inactive || 
+                (m->m_connections && m->m_connections->c_address && !strcmp(m->m_connections->c_address, "0.0.0.0")))) {
+               sendonly = 2;                   /* global sendonly always wins */
+       }
+
+       for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
+               if (zstr(attr->a_name)) {
+                       continue;
+               }
+
+               if (!strcasecmp(attr->a_name, "sendonly")) {
+                       sendonly = 1;
+                       switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "recvonly");
+               } else if (!strcasecmp(attr->a_name, "inactive")) {
+                       sendonly = 1;
+                       switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "inactive");
+               } else if (!strcasecmp(attr->a_name, "recvonly")) {
+                       switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "sendonly");
+                       recvonly = 1;
+
+                       if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                               switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, 0);
+                               tech_pvt->max_missed_hold_packets = 0;
+                               tech_pvt->max_missed_packets = 0;
+                       } else {
+                               switch_channel_set_variable(tech_pvt->channel, "rtp_timeout_sec", "0");
+                               switch_channel_set_variable(tech_pvt->channel, "rtp_hold_timeout_sec", "0");
+                       }
+               } else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendrecv")) {
+                       sendonly = 0;
+               } else if (!strcasecmp(attr->a_name, "ptime")) {
+                       dptime = atoi(attr->a_value);
+               } else if (!strcasecmp(attr->a_name, "maxptime")) {
+                       dmaxptime = atoi(attr->a_value);
+               }
+       }
+
+       if (sendonly != 1 && recvonly != 1) {
+               switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", NULL);
+       }
+
+
+       if (sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_HOLD) ||
+               ((val = switch_channel_get_variable(tech_pvt->channel, "sip_disable_hold")) && switch_true(val))) {
+               sendonly = 0;
+       } else {
+
+               if (!tech_pvt->hold_laps) {
+                       tech_pvt->hold_laps++;
+                       if (sofia_glue_toggle_hold(tech_pvt, sendonly)) {
+                               reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_HOLD);
+                               
+                               if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_hold"))) {
+                                       reneg = switch_true(val);
+                               }
+                       }
+                       
+               }
+       }
+
+       if (reneg) {
+               reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE);
+               
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_reinvite"))) {
+                       reneg = switch_true(val);
+               }
+       }
+
+       if (!reneg && tech_pvt->num_negotiated_codecs) {
+               codec_array = tech_pvt->negotiated_codecs;
+               total_codecs = tech_pvt->num_negotiated_codecs;
+       } else if (reneg) {
+               tech_pvt->num_codecs = 0;
+               sofia_glue_tech_prepare_codecs(tech_pvt);
+               codec_array = tech_pvt->codecs;
+               total_codecs = tech_pvt->num_codecs;
+       }
+
+       if (switch_stristr("T38FaxFillBitRemoval:", r_sdp) || switch_stristr("T38FaxTranscodingMMR:", r_sdp) || 
+               switch_stristr("T38FaxTranscodingJBIG:", r_sdp)) {
+               switch_channel_set_variable(tech_pvt->channel, "t38_broken_boolean", "true");
+       }
+
+       find_zrtp_hash(session, sdp);
+       sofia_glue_pass_zrtp_hash(session);
+
+       for (m = sdp->sdp_media; m; m = m->m_next) {
+               sdp_connection_t *connection;
+               switch_core_session_t *other_session;
+
+               ptime = dptime;
+               maxptime = dmaxptime;
+
+               if (m->m_proto == sdp_proto_srtp) {
+                       got_savp++;
+               } else if (m->m_proto == sdp_proto_rtp) {
+                       got_avp++;
+               } else if (m->m_proto == sdp_proto_udptl) {
+                       got_udptl++;
+               }
+
+               if (got_udptl && m->m_type == sdp_media_image && m->m_port) {
+                       switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m);
+
+                       if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_NEGOTIATED)) {
+                               match = 1;
+                               goto done;
+                       }
+
+                       if (switch_true(switch_channel_get_variable(channel, "refuse_t38"))) {
+                               switch_channel_clear_app_flag_key("T38", tech_pvt->channel, CF_APP_T38);
+                               match = 0;
+                               goto done;
+                       } else {
+                               const char *var = switch_channel_get_variable(channel, "t38_passthru");
+                               int pass = sofia_test_pflag(tech_pvt->profile, PFLAG_T38_PASSTHRU);
+
+
+                               if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38)) {
+                                       sofia_set_flag(tech_pvt, TFLAG_NOREPLY);
+                               }
+
+                               if (var) {
+                                       if (!(pass = switch_true(var))) {
+                                               if (!strcasecmp(var, "once")) {
+                                                       pass = 2;
+                                               }
+                                       }
+                               }
+
+                               if ((pass == 2 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU)) || 
+                                       !sofia_test_flag(tech_pvt, TFLAG_REINVITE) ||
+                                       switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || 
+                                       switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) || 
+                                       !switch_rtp_ready(tech_pvt->rtp_session)) {
+                                       pass = 0;
+                               }
+                               
+                               if (pass && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
+                                       private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
+                                       switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
+                                       switch_core_session_message_t *msg;
+                                       char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
+                                       switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
+                                       char tmp[32] = "";
+
+                                       if (switch_true(switch_channel_get_variable(tech_pvt->channel, "t38_broken_boolean")) && 
+                                               switch_true(switch_channel_get_variable(tech_pvt->channel, "t38_pass_broken_boolean"))) {
+                                               switch_channel_set_variable(other_channel, "t38_broken_boolean", "true");
+                                       }
+                                       
+                                       tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, t38_options->remote_ip);
+                                       tech_pvt->remote_sdp_audio_port = t38_options->remote_port;
+
+                                       if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
+                                                                                 switch_channel_get_name(tech_pvt->channel));
+                                       } else {
+                                               const char *err = NULL;
+
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
+                                                                                 switch_channel_get_name(tech_pvt->channel),
+                                                                                 remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+                                               
+                                               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+                                               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+                                               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
+
+                                               if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip,
+                                                                                                                 tech_pvt->remote_sdp_audio_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
+                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
+                                                       switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
+                                               }
+                                               
+                                       }
+
+                                       
+
+                                       sofia_glue_copy_t38_options(t38_options, other_session);
+
+                                       sofia_set_flag(tech_pvt, TFLAG_T38_PASSTHRU);
+                                       sofia_set_flag(other_tech_pvt, TFLAG_T38_PASSTHRU);
+
+                                       msg = switch_core_session_alloc(other_session, sizeof(*msg));
+                                       msg->message_id = SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA;
+                                       msg->from = __FILE__;
+                                       msg->string_arg = switch_core_session_strdup(other_session, r_sdp);
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing T38 req to other leg.\n%s\n", r_sdp);
+                                       switch_core_session_queue_message(other_session, msg);
+                                       switch_core_session_rwunlock(other_session);
+                               }
+                       }
+
+
+                       /* do nothing here, mod_fax will trigger a response (if it's listening =/) */
+                       match = 1;
+                       goto done;
+               } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) {
+                       sdp_rtpmap_t *map;
+
+                       for (attr = m->m_attributes; attr; attr = attr->a_next) {
+
+                               if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
+                                       switch_channel_set_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port", attr->a_value);
+                               } else if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
+                                       ptime = atoi(attr->a_value);
+                               } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
+                                       maxptime = atoi(attr->a_value);
+                               } else if (!got_crypto && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) {
+                                       int crypto_tag;
+
+                                       if (!(tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_CRYPTO_IN_AVP) && 
+                                               !switch_true(switch_channel_get_variable(tech_pvt->channel, "sip_allow_crypto_in_avp"))) {
+                                               if (m->m_proto != sdp_proto_srtp) {
+                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "a=crypto in RTP/AVP, refer to rfc3711\n");
+                                                       match = 0;
+                                                       goto done;
+                                               }
+                                       }
+
+                                       crypto = attr->a_value;
+                                       crypto_tag = atoi(crypto);
+
+                                       if (tech_pvt->remote_crypto_key && switch_rtp_ready(tech_pvt->rtp_session)) {
+                                               /* Compare all the key. The tag may remain the same even if key changed */
+                                               if (crypto && !strcmp(crypto, tech_pvt->remote_crypto_key)) {
+                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Existing key is still valid.\n");
+                                               } else {
+                                                       const char *a = switch_stristr("AES", tech_pvt->remote_crypto_key);
+                                                       const char *b = switch_stristr("AES", crypto);
+
+                                                       /* Change our key every time we can */
+                                                       
+                                                       if (sofia_test_flag(tech_pvt, TFLAG_CRYPTO_RECOVER)) {
+                                                               sofia_clear_flag(tech_pvt, TFLAG_CRYPTO_RECOVER);
+                                                       } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
+                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_32);
+                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
+                                                               switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt->crypto_type,
+                                                                                                                 tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN);
+                                                       } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
+                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_80);
+                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
+                                                               switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt->crypto_type,
+                                                                                                                 tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN);
+                                                       } else {
+                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n");
+                                                       }
+
+                                                       if (a && b && !strncasecmp(a, b, 23)) {
+                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Change Remote key to [%s]\n", crypto);
+                                                               tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto);
+                                                               switch_channel_set_variable(tech_pvt->channel, "srtp_remote_audio_crypto_key", crypto);
+                                                               tech_pvt->crypto_tag = crypto_tag;
+                                                               
+                                                               if (switch_rtp_ready(tech_pvt->rtp_session) && sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
+                                                                       sofia_glue_add_crypto(tech_pvt, tech_pvt->remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
+                                                                       switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_RECV, tech_pvt->crypto_tag,
+                                                                                                                         tech_pvt->crypto_type, tech_pvt->remote_raw_key, SWITCH_RTP_KEY_LEN);
+                                                               }
+                                                               got_crypto++;
+                                                       } else {
+                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ignoring unacceptable key\n");
+                                                       }
+                                               }
+                                       } else if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+                                               tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto);
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set Remote Key [%s]\n", tech_pvt->remote_crypto_key);
+                                               switch_channel_set_variable(tech_pvt->channel, "srtp_remote_audio_crypto_key", crypto);
+                                               tech_pvt->crypto_tag = crypto_tag;
+                                               got_crypto++;
+
+                                               if (zstr(tech_pvt->local_crypto_key)) {
+                                                       if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
+                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_32);
+                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
+                                                       } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
+                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_80);
+                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
+                                                       } else {
+                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n");
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (got_crypto && !got_avp) {
+                               switch_channel_set_variable(tech_pvt->channel, SOFIA_CRYPTO_MANDATORY_VARIABLE, "true");
+                               switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE, "true");
+                       }
+
+                       connection = sdp->sdp_connection;
+                       if (m->m_connections) {
+                               connection = m->m_connections;
+                       }
+
+                       if (!connection) {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+                               match = 0;
+                               break;
+                       }
+
+               greed:
+                       x = 0;
+
+                       if (tech_pvt->rm_encoding && !(sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF))) {     // && !sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+                               char *remote_host = tech_pvt->remote_sdp_audio_ip;
+                               switch_port_t remote_port = tech_pvt->remote_sdp_audio_port;
+                               int same = 0;
+
+                               if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                                       remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
+                                       remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
+                               }
+
+                               for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                                       if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
+                                               match = (map->rm_pt == tech_pvt->pt) ? 1 : 0;
+                                       } else {
+                                               match = strcasecmp(switch_str_nil(map->rm_encoding), tech_pvt->iananame) ? 0 : 1;
+                                       }
+
+                                       if (match && connection->c_address && remote_host && !strcmp(connection->c_address, remote_host) && m->m_port == remote_port) {
+                                               same = 1;
+                                       } else {
+                                               same = 0;
+                                               break;
+                                       }
+                               }
+
+                               if (same) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+                                                                         "Our existing sdp is still good [%s %s:%d], let's keep it.\n",
+                                                                         tech_pvt->rm_encoding, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+                                       got_audio = 1;
+                               } else {
+                                       match = 0;
+                                       got_audio = 0;
+                               }
+                       }
+
+                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                               int32_t i;
+                               uint32_t near_rate = 0;
+                               const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
+                               const char *rm_encoding;
+                               uint32_t map_bit_rate = 0;
+                               int codec_ms = 0;
+                               switch_codec_fmtp_t codec_fmtp = { 0 };
+
+                               if (x++ < skip) {
+                                       continue;
+                               }
+
+                               if (!(rm_encoding = map->rm_encoding)) {
+                                       rm_encoding = "";
+                               }
+
+                               if (!strcasecmp(rm_encoding, "telephone-event")) {
+                                       if (!best_te || map->rm_rate == tech_pvt->rm_rate) {
+                                               best_te = (switch_payload_t) map->rm_pt;
+                                       }
+                               }
+                               
+                               if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && !cng_pt && !strcasecmp(rm_encoding, "CN")) {
+                                       cng_pt = (switch_payload_t) map->rm_pt;
+                                       if (tech_pvt->rtp_session) {
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
+                                               switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
+                                       }
+                               }
+
+                               if (match) {
+                                       continue;
+                               }
+
+                               if (greedy) {
+                                       first = mine;
+                                       last = first + 1;
+                               } else {
+                                       first = 0;
+                                       last = tech_pvt->num_codecs;
+                               }
+
+                               codec_ms = ptime;
+
+                               if (maxptime && (!codec_ms || codec_ms > maxptime)) {
+                                       codec_ms = maxptime;
+                               }
+
+                               if (!codec_ms) {
+                                       codec_ms = switch_default_ptime(rm_encoding, map->rm_pt);
+                               }
+
+                               map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt);
+                               
+                               if (!ptime && !strcasecmp(map->rm_encoding, "g723")) {
+                                       codec_ms = 30;
+                               }
+                               
+                               if (zstr(map->rm_fmtp)) {
+                                       if (!strcasecmp(map->rm_encoding, "ilbc")) {
+                                               codec_ms = 30;
+                                               map_bit_rate = 13330;
+                                       }
+                               } else {
+                                       if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) {
+                                               if (codec_fmtp.bits_per_second) {
+                                                       map_bit_rate = codec_fmtp.bits_per_second;
+                                               }
+                                               if (codec_fmtp.microseconds_per_packet) {
+                                                       codec_ms = (codec_fmtp.microseconds_per_packet / 1000);
+                                               }
+                                       }
+                               }
+
+                               
+                               for (i = first; i < last && i < total_codecs; i++) {
+                                       const switch_codec_implementation_t *imp = codec_array[i];
+                                       uint32_t bit_rate = imp->bits_per_second;
+                                       uint32_t codec_rate = imp->samples_per_second;
+                                       if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+                                               continue;
+                                       }
+
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n",
+                                                                         rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate,
+                                                                         imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate);
+                                       if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
+                                               match = (map->rm_pt == imp->ianacode) ? 1 : 0;
+                                       } else {
+                                               match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
+                                       }
+
+                                       if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) {
+                                               /* if a bit rate is specified and doesn't match, this is not a codec match, except for ILBC */
+                                               match = 0;
+                                       }
+
+                                       if (match && map->rm_rate && codec_rate && map->rm_rate != codec_rate && (!strcasecmp(map->rm_encoding, "pcma") || !strcasecmp(map->rm_encoding, "pcmu"))) {
+                                               /* if the sampling rate is specified and doesn't match, this is not a codec match for G.711 */
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sampling rates have to match for G.711\n");
+                                               match = 0;
+                                       }
+                                       
+                                       if (match) {
+                                               if (scrooge) {
+                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+                                                                                         "Bah HUMBUG! Sticking with %s@%uh@%ui\n",
+                                                                                         imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000);
+                                               } else {
+                                                       if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) {
+                                                               near_rate = map->rm_rate;
+                                                               near_match = imp;
+                                                               match = 0;
+                                                               continue;
+                                                       }
+                                               }
+                                               mimp = imp;
+                                               break;
+                                       }
+                               }
+
+                               if (!match && near_match) {
+                                       const switch_codec_implementation_t *search[1];
+                                       char *prefs[1];
+                                       char tmp[80];
+                                       int num;
+
+                                       switch_snprintf(tmp, sizeof(tmp), "%s@%uh@%ui", near_match->iananame, near_rate ? near_rate : near_match->samples_per_second,
+                                                                       codec_ms);
+
+                                       prefs[0] = tmp;
+                                       num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
+
+                                       if (num) {
+                                               mimp = search[0];
+                                       } else {
+                                               mimp = near_match;
+                                       }
+
+                                       if (!maxptime || mimp->microseconds_per_packet / 1000 <= maxptime) {
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Substituting codec %s@%ui@%uh\n",
+                                                                                 mimp->iananame, mimp->microseconds_per_packet / 1000, mimp->samples_per_second);
+                                               match = 1;
+                                       } else {
+                                               mimp = NULL;
+                                               match = 0;
+                                       }
+
+                               }
+
+                               if (!match && greedy) {
+                                       skip++;
+                                       continue;
+                               }
+
+                               if (mimp) {
+                                       char tmp[50];
+                                       const char *mirror = switch_channel_get_variable(tech_pvt->channel, "sip_mirror_remote_audio_codec_payload");
+
+                                       tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *) map->rm_encoding);
+                                       tech_pvt->iananame = switch_core_session_strdup(session, (char *) mimp->iananame);
+                                       tech_pvt->pt = (switch_payload_t) map->rm_pt;
+                                       tech_pvt->rm_rate = mimp->samples_per_second;
+                                       tech_pvt->codec_ms = mimp->microseconds_per_packet / 1000;
+                                       tech_pvt->bitrate = mimp->bits_per_second;
+                                       tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address);
+                                       tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
+                                       tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port;
+                                       tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt;
+                                       tech_pvt->num_negotiated_codecs = 0;
+                                       tech_pvt->negotiated_codecs[tech_pvt->num_negotiated_codecs++] = mimp;
+                                       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+                                       switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+                                       switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
+                                       tech_pvt->audio_recv_pt = (switch_payload_t)map->rm_pt;
+                                       
+                                       if (!switch_true(mirror) && 
+                                               switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && 
+                                               (!sofia_test_flag(tech_pvt, TFLAG_REINVITE) || sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE))) {
+                                               sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->audio_recv_pt);
+                                       }
+                                       
+                                       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->audio_recv_pt);
+                                       switch_channel_set_variable(tech_pvt->channel, "sip_audio_recv_pt", tmp);
+                                       
+                               }
+                               
+                               if (match) {
+                                       if (sofia_glue_tech_set_codec(tech_pvt, 1) == SWITCH_STATUS_SUCCESS) {
+                                               got_audio = 1;
+                                       } else {
+                                               match = 0;
+                                       }
+                               }
+                       }
+
+                       if (!best_te && (sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF))) {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, 
+                                                                 "No 2833 in SDP. Liberal DTMF mode adding %d as telephone-event.\n", tech_pvt->profile->te);
+                               best_te = tech_pvt->profile->te;
+                       }
+
+                       if (best_te) {
+                               if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+                                       te = tech_pvt->te = (switch_payload_t) best_te;
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", best_te);
+                                       if (tech_pvt->rtp_session) {
+                                               switch_rtp_set_telephony_event(tech_pvt->rtp_session, (switch_payload_t) best_te);
+                                               switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", best_te);
+                                       }
+                               } else {
+                                       te = tech_pvt->recv_te = tech_pvt->te = (switch_payload_t) best_te;
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send/recv payload to %u\n", te);
+                                       if (tech_pvt->rtp_session) {
+                                               switch_rtp_set_telephony_event(tech_pvt->rtp_session, te);
+                                               switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", te);
+                                               switch_rtp_set_telephony_recv_event(tech_pvt->rtp_session, te);
+                                               switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_recv_payload", "%d", te);
+                                       }
+                               }
+                       } else {
+                               /* by default, use SIP INFO if 2833 is not in the SDP */
+                               if (!switch_false(switch_channel_get_variable(channel, "sip_info_when_no_2833"))) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No 2833 in SDP.  Disable 2833 dtmf and switch to INFO\n");
+                                       switch_channel_set_variable(tech_pvt->channel, "dtmf_type", "info");
+                                       tech_pvt->dtmf_type = DTMF_INFO;
+                                       te = tech_pvt->recv_te = tech_pvt->te = 0;
+                               } else {
+                                       switch_channel_set_variable(tech_pvt->channel, "dtmf_type", "none");
+                                       tech_pvt->dtmf_type = DTMF_NONE;
+                                       te = tech_pvt->recv_te = tech_pvt->te = 0;
+                               }
+                       }
+
+                       
+                       if (!match && greedy && mine < total_codecs) {
+                               mine++;
+                               skip = 0;
+                               goto greed;
+                       }
+
+               } else if (m->m_type == sdp_media_video && m->m_port) {
+                       sdp_rtpmap_t *map;
+                       const char *rm_encoding;
+                       const switch_codec_implementation_t *mimp = NULL;
+                       int vmatch = 0, i;
+                       switch_channel_set_variable(tech_pvt->channel, "video_possible", "true");
+
+                       connection = sdp->sdp_connection;
+                       if (m->m_connections) {
+                               connection = m->m_connections;
+                       }
+
+                       if (!connection) {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+                               match = 0;
+                               break;
+                       }
+
+                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
+
+                               for (attr = m->m_attributes; attr; attr = attr->a_next) {
+                                       if (!strcasecmp(attr->a_name, "framerate") && attr->a_value) {
+                                               //framerate = atoi(attr->a_value);
+                                       }
+                                       if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
+                                               switch_channel_set_variable(tech_pvt->channel, "sip_remote_video_rtcp_port", attr->a_value);
+                                       }
+                               }
+                               if (!(rm_encoding = map->rm_encoding)) {
+                                       rm_encoding = "";
+                               }
+
+                               for (i = 0; i < total_codecs; i++) {
+                                       const switch_codec_implementation_t *imp = codec_array[i];
+
+                                       if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+                                               continue;
+                                       }
+
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d]/[%s:%d]\n",
+                                                                         rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
+                                       if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
+                                               vmatch = (map->rm_pt == imp->ianacode) ? 1 : 0;
+                                       } else {
+                                               vmatch = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
+                                       }
+
+
+                                       if (vmatch && (map->rm_rate == imp->samples_per_second)) {
+                                               mimp = imp;
+                                               break;
+                                       } else {
+                                               vmatch = 0;
+                                       }
+                               }
+
+                               if (mimp) {
+                                       if ((tech_pvt->video_rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) {
+                                               char tmp[50];
+                                               const char *mirror = switch_channel_get_variable(tech_pvt->channel, "sip_mirror_remote_video_codec_payload");
+
+                                               tech_pvt->video_pt = (switch_payload_t) map->rm_pt;
+                                               tech_pvt->video_rm_rate = map->rm_rate;
+                                               tech_pvt->video_codec_ms = mimp->microseconds_per_packet / 1000;
+                                               tech_pvt->remote_sdp_video_ip = switch_core_session_strdup(session, (char *) connection->c_address);
+                                               tech_pvt->video_rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
+                                               tech_pvt->remote_sdp_video_port = (switch_port_t) m->m_port;
+                                               tech_pvt->video_agreed_pt = (switch_payload_t) map->rm_pt;
+                                               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_video_port);
+                                               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+                                               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp);
+                                               switch_channel_set_variable(tech_pvt->channel, "sip_video_fmtp", tech_pvt->video_rm_fmtp);
+                                               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->video_agreed_pt);
+                                               switch_channel_set_variable(tech_pvt->channel, "sip_video_pt", tmp);
+                                               sofia_glue_check_video_codecs(tech_pvt);
+
+                                               tech_pvt->video_recv_pt = (switch_payload_t)map->rm_pt;
+                                               
+                                               if (!switch_true(mirror) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+                                                       sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->video_recv_pt);
+                                               }
+
+                                               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->video_recv_pt);
+                                               switch_channel_set_variable(tech_pvt->channel, "sip_video_recv_pt", tmp);
+                                               if (!match && vmatch) match = 1;
+
+                                               break;
+                                       } else {
+                                               vmatch = 0;
+                                       }
+                               }
+                       }
+               }
+       }
+
+ done:
+
+       if (parser) {
+               sdp_parser_free(parser);
+       }
+
+       tech_pvt->cng_pt = cng_pt;
+       sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
+
+       return match;
+}
+
+
+switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_flag_t myflags)
+{
+       const char *err = NULL;
+       const char *val = NULL;
+       switch_rtp_flag_t flags;
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+       char tmp[50];
+       uint32_t rtp_timeout_sec = tech_pvt->profile->rtp_timeout_sec;
+       uint32_t rtp_hold_timeout_sec = tech_pvt->profile->rtp_hold_timeout_sec;
+       char *timer_name = NULL;
+       const char *var;
+       uint32_t delay = tech_pvt->profile->rtp_digit_delay;
+
+       switch_assert(tech_pvt != NULL);
+
+       if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       switch_mutex_lock(tech_pvt->sofia_mutex);
+
+       if (switch_rtp_ready(tech_pvt->rtp_session)) {
+               switch_rtp_reset_media_timer(tech_pvt->rtp_session);
+       }
+
+       if ((var = switch_channel_get_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE)) && switch_true(var)) {
+               sofia_set_flag_locked(tech_pvt, TFLAG_SECURE);
+       }
+
+       if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
+               status = SWITCH_STATUS_SUCCESS;
+               goto end;
+       }
+
+
+       if (!sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+               if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                       if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && !switch_rtp_ready(tech_pvt->video_rtp_session)) {
+                               goto video;
+                       }
+
+                       status = SWITCH_STATUS_SUCCESS;
+                       goto end;
+               } 
+       }
+
+       if ((status = sofia_glue_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+               goto end;
+       }
+
+
+       if (myflags) {
+               flags = myflags;
+       } else if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+                          !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+               flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
+       } else {
+               flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT);
+       }
+
+       if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_RFC2833)
+               || ((val = switch_channel_get_variable(tech_pvt->channel, "pass_rfc2833")) && switch_true(val))) {
+               sofia_set_flag(tech_pvt, TFLAG_PASS_RFC2833);
+       }
+
+
+       if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFLUSH)
+               || ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_autoflush")) && switch_true(val))) {
+               flags |= SWITCH_RTP_FLAG_AUTOFLUSH;
+       }
+
+       if (!(sofia_test_pflag(tech_pvt->profile, PFLAG_REWRITE_TIMESTAMPS) ||
+                 ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_rewrite_timestamps")) && switch_true(val)))) {
+               flags |= SWITCH_RTP_FLAG_RAW_WRITE;
+       }
+
+       if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
+               tech_pvt->cng_pt = 0;
+       } else if (tech_pvt->cng_pt) {
+               flags |= SWITCH_RTP_FLAG_AUTO_CNG;
+       }
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+       if (!strcasecmp(tech_pvt->read_impl.iananame, "L16")) {
+               flags |= SWITCH_RTP_FLAG_BYTESWAP;
+       }
+#endif
+       
+       if ((flags & SWITCH_RTP_FLAG_BYTESWAP) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_byteswap")) && switch_true(val)) {
+               flags &= ~SWITCH_RTP_FLAG_BYTESWAP;
+       }
+
+       if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+               //const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
+               //const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
+               char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
+               switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
+
+               if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
+                                                         switch_channel_get_name(tech_pvt->channel));
+                       if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                               if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
+                                                                 "%s Set audio receive payload in Re-INVITE for non-matching dynamic PT to %u\n", 
+                                                                         switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
+                               
+                                       switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
+                                                                 "%s Setting audio receive payload in Re-INVITE to %u\n", 
+                                                                         switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
+                                       switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt);
+                               }
+
+                       }
+                       goto video;
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
+                                                         switch_channel_get_name(tech_pvt->channel),
+                                                         remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+
+                       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+                       switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+                       switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
+               }
+       }
+
+       if (!switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n",
+                                                 switch_channel_get_name(tech_pvt->channel),
+                                                 tech_pvt->local_sdp_audio_ip,
+                                                 tech_pvt->local_sdp_audio_port,
+                                                 tech_pvt->remote_sdp_audio_ip,
+                                                 tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
+
+               if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                       switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
+
+                       if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
+                                                                 "%s Set audio receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
+                               
+                               switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
+                       } else {
+                               switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt);
+                       }
+
+               }
+       }
+
+       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_audio_port);
+       switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->local_sdp_audio_ip);
+       switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+       switch_channel_set_variable(tech_pvt->channel, SWITCH_ADVERTISED_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+
+       if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+               const char *rport = NULL;
+               switch_port_t remote_rtcp_port = 0;
+
+               
+
+               if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port"))) {
+                       remote_rtcp_port = (switch_port_t)atoi(rport);
+               }
+
+               if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port,
+                                                                                 remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n",
+                                                         tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+                       if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+                               !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+                               /* Reactivate the NAT buster flag. */
+                               switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+                       }
+               }
+               goto video;
+       }
+
+       if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+               sofia_glue_tech_proxy_remote_addr(tech_pvt, NULL);
+
+               if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+                       !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+                       flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
+               } else {
+                       flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_DATAWAIT);
+               }
+               timer_name = NULL;
+
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
+                                                 "PROXY AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
+                                                 switch_channel_get_name(tech_pvt->channel),
+                                                 tech_pvt->local_sdp_audio_ip,
+                                                 tech_pvt->local_sdp_audio_port,
+                                                 tech_pvt->remote_sdp_audio_ip,
+                                                 tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
+
+               if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                       switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
+               }
+
+       } else {
+               timer_name = tech_pvt->profile->timer_name;
+
+               if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) {
+                       timer_name = (char *) var;
+               }
+       }
+
+       if (switch_channel_up(tech_pvt->channel) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+               tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
+                                                                                          tech_pvt->local_sdp_audio_port,
+                                                                                          tech_pvt->remote_sdp_audio_ip,
+                                                                                          tech_pvt->remote_sdp_audio_port,
+                                                                                          tech_pvt->agreed_pt,
+                                                                                          tech_pvt->read_impl.samples_per_packet,
+                                                                                          tech_pvt->codec_ms * 1000,
+                                                                                          (switch_rtp_flag_t) flags, timer_name, &err, switch_core_session_get_pool(tech_pvt->session));
+       }
+
+       if (switch_rtp_ready(tech_pvt->rtp_session)) {
+               uint8_t vad_in = sofia_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
+               uint8_t vad_out = sofia_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0;
+               uint8_t inb = sofia_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1;
+               uint32_t stun_ping = 0;
+               const char *ssrc;
+
+               if ((ssrc = switch_channel_get_variable(tech_pvt->channel, "rtp_use_ssrc"))) {
+                       uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10);
+                       switch_rtp_set_ssrc(tech_pvt->rtp_session, ssrc_ul);
+               }
+
+
+               switch_channel_set_flag(tech_pvt->channel, CF_FS_RTP);
+
+               switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_pt", "%d", tech_pvt->agreed_pt);
+
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_enable_vad_in")) && switch_true(val)) {
+                       vad_in = 1;
+               }
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_enable_vad_out")) && switch_true(val)) {
+                       vad_out = 1;
+               }
+
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_vad_in")) && switch_true(val)) {
+                       vad_in = 0;
+               }
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_vad_out")) && switch_true(val)) {
+                       vad_out = 0;
+               }
+
+               if ((tech_pvt->stun_flags & STUN_FLAG_SET) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_stun_ping"))) {
+                       int ival = atoi(val);
+
+                       if (ival <= 0) {
+                               if (switch_true(val)) {
+                                       ival = 6;
+                               }
+                       }
+
+                       stun_ping = (ival * tech_pvt->read_impl.samples_per_second) / tech_pvt->read_impl.samples_per_packet;
+               }
+
+               tech_pvt->ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
+               switch_channel_set_variable_printf(tech_pvt->channel, "rtp_use_ssrc", "%u", tech_pvt->ssrc);
+
+               sofia_set_flag(tech_pvt, TFLAG_RTP);
+               sofia_set_flag(tech_pvt, TFLAG_IO);
+
+               if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_IGNORE_MARK_BIT) {
+                       tech_pvt->rtp_bugs |= RTP_BUG_IGNORE_MARK_BIT;
+               }
+
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_manual_rtp_bugs"))) {
+                       sofia_glue_parse_rtp_bugs(&tech_pvt->rtp_bugs, val);
+               }
+
+               switch_rtp_intentional_bugs(tech_pvt->rtp_session, tech_pvt->rtp_bugs | tech_pvt->profile->manual_rtp_bugs);
+
+               if ((vad_in && inb) || (vad_out && !inb)) {
+                       switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING | SWITCH_VAD_FLAG_EVENTS_TALK | SWITCH_VAD_FLAG_EVENTS_NOTALK);
+                       sofia_set_flag(tech_pvt, TFLAG_VAD);
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP Engage VAD for %s ( %s %s )\n",
+                                                         switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : "");
+               }
+
+               if (stun_ping) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Setting stun ping to %s:%d\n", tech_pvt->stun_ip,
+                                                         stun_ping);
+                       switch_rtp_activate_stun_ping(tech_pvt->rtp_session, tech_pvt->stun_ip, tech_pvt->stun_port, stun_ping,
+                                                                                 (tech_pvt->stun_flags & STUN_FLAG_FUNNY) ? 1 : 0);
+               }
+
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec")) || (val = tech_pvt->profile->rtcp_audio_interval_msec)) {
+                       const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port");
+                       switch_port_t remote_port = 0;
+                       if (rport) {
+                               remote_port = (switch_port_t)atoi(rport);
+                       }
+                       if (!strcasecmp(val, "passthru")) {
+                               switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
+                       } else {
+                               int interval = atoi(val);
+                               if (interval < 100 || interval > 5000) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
+                                                                         "Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval);
+                               } else {
+                                       switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval, remote_port);
+                               }
+                       }
+               }
+
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec")) || (val = tech_pvt->profile->jb_msec)) {
+                       int jb_msec = atoi(val);
+                       int maxlen = 0, max_drift = 0;
+                       char *p, *q;
+                       
+                       if ((p = strchr(val, ':'))) {
+                               p++;
+                               maxlen = atoi(p);
+                               if ((q = strchr(p, ':'))) {
+                                       q++;
+                                       max_drift = abs(atoi(q));
+                               }
+                       }
+
+                       if (jb_msec < 20 || jb_msec > 10000) {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
+                                                                 "Invalid Jitterbuffer spec [%d] must be between 20 and 10000\n", jb_msec);
+                       } else {
+                               int qlen, maxqlen = 50;
+                               
+                               qlen = jb_msec / (tech_pvt->read_impl.microseconds_per_packet / 1000);
+
+                               if (qlen < 1) {
+                                       qlen = 3;
+                               }
+
+                               if (maxlen) {
+                                       maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000);
+                               }
+
+                               if (maxqlen < qlen) {
+                                       maxqlen = qlen * 5;
+                               }
+                               if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
+                                                                                                         tech_pvt->read_impl.samples_per_packet, 
+                                                                                                         tech_pvt->read_impl.samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), 
+                                                                         SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen);
+                                       switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER);
+                                       if (!switch_false(switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_plc"))) {
+                                               switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER_PLC);
+                                       }
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), 
+                                                                         SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen);
+                               }
+                               
+                       }
+               }
+
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_timeout_sec"))) {
+                       int v = atoi(val);
+                       if (v >= 0) {
+                               rtp_timeout_sec = v;
+                       }
+               }
+
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_hold_timeout_sec"))) {
+                       int v = atoi(val);
+                       if (v >= 0) {
+                               rtp_hold_timeout_sec = v;
+                       }
+               }
+
+               if (rtp_timeout_sec) {
+                       tech_pvt->max_missed_packets = (tech_pvt->read_impl.samples_per_second * rtp_timeout_sec) / tech_pvt->read_impl.samples_per_packet;
+
+                       switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
+                       if (!rtp_hold_timeout_sec) {
+                               rtp_hold_timeout_sec = rtp_timeout_sec * 10;
+                       }
+               }
+
+               if (rtp_hold_timeout_sec) {
+                       tech_pvt->max_missed_hold_packets = (tech_pvt->read_impl.samples_per_second * rtp_hold_timeout_sec) / tech_pvt->read_impl.samples_per_packet;
+               }
+
+               if (tech_pvt->te) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", tech_pvt->te);
+                       switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
+                       switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", tech_pvt->te);
+               }
+
+               if (tech_pvt->recv_te) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set 2833 dtmf receive payload to %u\n", tech_pvt->recv_te);
+                       switch_rtp_set_telephony_recv_event(tech_pvt->rtp_session, tech_pvt->recv_te);
+                       switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_recv_payload", "%d", tech_pvt->recv_te);
+               }
+
+               if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
+                                                         "%s Set audio receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
+
+                       switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
+               }
+
+               if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) ||
+                       ((val = switch_channel_get_variable(tech_pvt->channel, "supress_cng")) && switch_true(val)) ||
+                       ((val = switch_channel_get_variable(tech_pvt->channel, "suppress_cng")) && switch_true(val))) {
+                       tech_pvt->cng_pt = 0;
+               }
+
+               if (((val = switch_channel_get_variable(tech_pvt->channel, "rtp_digit_delay")))) {
+                       int delayi = atoi(val);
+                       if (delayi < 0) delayi = 0;
+                       delay = (uint32_t) delayi;
+               }
+
+
+               if (delay) {
+                       switch_rtp_set_interdigit_delay(tech_pvt->rtp_session, delay);
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
+                                                         "%s Set rtp dtmf delay to %u\n", switch_channel_get_name(tech_pvt->channel), delay);
+                       
+               }
+
+               if (tech_pvt->cng_pt && !sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", tech_pvt->cng_pt);
+                       switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
+               }
+
+               if (tech_pvt->remote_crypto_key && sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
+                       sofia_glue_add_crypto(tech_pvt, tech_pvt->remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
+                       switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1, tech_pvt->crypto_type, tech_pvt->local_raw_key,
+                                                                         SWITCH_RTP_KEY_LEN);
+                       switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_RECV, tech_pvt->crypto_tag, tech_pvt->crypto_type, tech_pvt->remote_raw_key,
+                                                                         SWITCH_RTP_KEY_LEN);
+                       switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE, "true");
+               }
+
+
+               switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+               switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
+
+
+               if (switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU)) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "Activating ZRTP PROXY MODE\n");
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Disable NOTIMER_DURING_BRIDGE\n");
+                       sofia_clear_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE);
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Activating audio UDPTL mode\n");
+                       switch_rtp_udptl_mode(tech_pvt->rtp_session);
+               }
+
+
+       video:
+               
+               sofia_glue_check_video_codecs(tech_pvt);
+
+               if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding && tech_pvt->remote_sdp_video_port) {
+                       /******************************************************************************************/
+                       if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+                               //const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
+                               //const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
+                               char *remote_host = switch_rtp_get_remote_host(tech_pvt->video_rtp_session);
+                               switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->video_rtp_session);
+                               
+
+
+                               if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_video_ip) && remote_port == tech_pvt->remote_sdp_video_port) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params are unchanged for %s.\n",
+                                                                         switch_channel_get_name(tech_pvt->channel));
+                                       goto video_up;
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params changed for %s from %s:%d to %s:%d\n",
+                                                                         switch_channel_get_name(tech_pvt->channel),
+                                                                         remote_host, remote_port, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port);
+                               }
+                       }
+
+                       if (!switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
+                                                                 "VIDEO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n", switch_channel_get_name(tech_pvt->channel),
+                                                                 tech_pvt->local_sdp_audio_ip, tech_pvt->local_sdp_video_port, tech_pvt->remote_sdp_video_ip,
+                                                                 tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
+
+                               if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+                                       switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
+                               }
+                       }
+                       
+                       switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_video_port);
+                       switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+                       switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp);
+
+
+                       if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+                               const char *rport = NULL;
+                               switch_port_t remote_rtcp_port = 0;
+
+                               sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
+
+                               if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port"))) {
+                                       remote_rtcp_port = (switch_port_t)atoi(rport);
+                               }
+                               
+                               if (switch_rtp_set_remote_address
+                                       (tech_pvt->video_rtp_session, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port, remote_rtcp_port, SWITCH_TRUE,
+                                        &err) != SWITCH_STATUS_SUCCESS) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err);
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n",
+                                                                         tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port);
+                                       if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+                                               !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+                                               /* Reactivate the NAT buster flag. */
+                                               switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+                                       }
+
+                               }
+                               goto video_up;
+                       }
+
+                       if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+                               sofia_glue_tech_proxy_remote_addr(tech_pvt, NULL);
+
+                               if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+                                       !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+                                       flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
+                               } else {
+                                       flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_DATAWAIT);
+                               }
+                               timer_name = NULL;
+
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
+                                                                 "PROXY VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
+                                                                 switch_channel_get_name(tech_pvt->channel),
+                                                                 tech_pvt->local_sdp_audio_ip,
+                                                                 tech_pvt->local_sdp_video_port,
+                                                                 tech_pvt->remote_sdp_video_ip,
+                                                                 tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
+
+                               if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+                                       switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
+                               }
+                       } else {
+                               timer_name = tech_pvt->profile->timer_name;
+
+                               if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) {
+                                       timer_name = (char *) var;
+                               }
+                       }
+
+                       /******************************************************************************************/
+
+                       if (tech_pvt->video_rtp_session) {
+                               goto video_up;
+                       }
+
+
+                       if (!tech_pvt->local_sdp_video_port) {
+                               sofia_glue_tech_choose_video_port(tech_pvt, 1);
+                       }
+
+                       if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) &&
+                               !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+                               flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_RAW_WRITE);
+                       } else {
+                               flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_RAW_WRITE);
+                       }
+
+                       if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+                               flags |= SWITCH_RTP_FLAG_PROXY_MEDIA;
+                       }
+                       sofia_glue_tech_set_video_codec(tech_pvt, 0);
+
+                       flags &= ~(SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_NOBLOCK);
+                       flags |= SWITCH_RTP_FLAG_VIDEO;
+
+                       tech_pvt->video_rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
+                                                                                                                tech_pvt->local_sdp_video_port,
+                                                                                                                tech_pvt->remote_sdp_video_ip,
+                                                                                                                tech_pvt->remote_sdp_video_port,
+                                                                                                                tech_pvt->video_agreed_pt,
+                                                                                                                1, 90000, (switch_rtp_flag_t) flags, NULL, &err, switch_core_session_get_pool(tech_pvt->session));
+
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
+                                                         switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
+                                                         switch_channel_get_name(tech_pvt->channel),
+                                                         tech_pvt->local_sdp_audio_ip,
+                                                         tech_pvt->local_sdp_video_port,
+                                                         tech_pvt->remote_sdp_video_ip,
+                                                         tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt,
+                                                         0, switch_rtp_ready(tech_pvt->video_rtp_session) ? "SUCCESS" : err);
+
+
+                       if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+                               switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
+                       }
+
+                       if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+                               const char *ssrc;
+                               switch_channel_set_flag(tech_pvt->channel, CF_VIDEO);
+                               if ((ssrc = switch_channel_get_variable(tech_pvt->channel, "rtp_use_video_ssrc"))) {
+                                       uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10);
+                                       switch_rtp_set_ssrc(tech_pvt->video_rtp_session, ssrc_ul);
+                               }
+
+
+
+                               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_manual_video_rtp_bugs"))) {
+                                       sofia_glue_parse_rtp_bugs(&tech_pvt->video_rtp_bugs, val);
+                               }
+                               
+                               switch_rtp_intentional_bugs(tech_pvt->video_rtp_session, tech_pvt->video_rtp_bugs | tech_pvt->profile->manual_video_rtp_bugs);
+
+                               if (tech_pvt->video_recv_pt != tech_pvt->video_agreed_pt) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
+                                                                         "%s Set video receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->video_recv_pt);
+                                       switch_rtp_set_recv_pt(tech_pvt->video_rtp_session, tech_pvt->video_recv_pt);
+                               }
+
+                               switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_pt", "%d", tech_pvt->video_agreed_pt);
+                               tech_pvt->video_ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
+                               switch_channel_set_variable_printf(tech_pvt->channel, "rtp_use_video_ssrc", "%u", tech_pvt->ssrc);
+
+
+                               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec"))
+                                       || (val = tech_pvt->profile->rtcp_audio_interval_msec)) {
+                                       const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port");
+                                       switch_port_t remote_port = 0;
+                                       if (rport) {
+                                               remote_port = (switch_port_t)atoi(rport);
+                                       }
+                                       if (!strcasecmp(val, "passthru")) {
+                                               switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
+                                       } else {
+                                               int interval = atoi(val);
+                                               if (interval < 100 || interval > 5000) {
+                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
+                                                                                         "Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval);
+                                               } else {
+                                                       switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval, remote_port);
+                                               }
+                                       }
+                               }
+                               if (switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU)) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Activating video UDPTL mode\n");
+                                       switch_rtp_udptl_mode(tech_pvt->video_rtp_session);
+                               }
+
+                       } else {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
+                               switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                               goto end;
+                       }
+               }
+
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
+               switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+               sofia_clear_flag_locked(tech_pvt, TFLAG_IO);
+               status = SWITCH_STATUS_FALSE;
+               goto end;
+       }
+
+ video_up:
+
+       sofia_set_flag(tech_pvt, TFLAG_IO);
+       status = SWITCH_STATUS_SUCCESS;
+
+ end:
+
+       sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
+       switch_core_recovery_track(tech_pvt->session);
+
+       switch_mutex_unlock(tech_pvt->sofia_mutex);
+
+       return status;
+
+}
+
+
+
+void sofia_media_set_sdp_codec_string(switch_core_session_t *session, const char *r_sdp)
+{
+       sdp_parser_t *parser;
+       sdp_session_t *sdp;
+       private_object_t *tech_pvt = switch_core_session_get_private(session);
+
+       if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+
+               if ((sdp = sdp_session(parser))) {
+                       sofia_glue_set_r_sdp_codec_string(session, sofia_glue_get_codec_string(tech_pvt), sdp);
+               }
+
+               sdp_parser_free(parser);
+       }
+
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
new file mode 100644 (file)
index 0000000..e3527ed
--- /dev/null
@@ -0,0 +1,59 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * switch_core_media.c -- Core Media
+ *
+ */
+
+
+
+#include <switch.h>
+#include <switch_ssl.h>
+#include <switch_stun.h>
+#include <switch_nat.h>
+#include <switch_version.h>
+#include "private/switch_core_pvt.h"
+#include <switch_curl.h>
+#include <errno.h>
+
+
+
+
+
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */