]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
wip
authorAnthony Minessale <anthm@freeswitch.org>
Thu, 20 Dec 2012 04:42:03 +0000 (22:42 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Mon, 1 Apr 2013 02:27:14 +0000 (21:27 -0500)
src/include/switch_core_media.h
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
src/switch_core_media.c

index e2ce4dd8194fec7069f170c640e7e6b804f8be7c..c72e453e088e2755736b6f2b4814f18ea5acfa3e 100644 (file)
@@ -43,8 +43,31 @@ typedef enum {
        SM_NDLB_DISABLE_SRTP_AUTH = (1 << 3)
 } switch_core_media_NDLB_t;
 
+typedef enum {
+       SCMF_DISABLE_TRANSCODING = (1 << 0)
+} switch_core_media_flag_t;
+
 struct switch_media_handle_s;
 
+typedef enum {
+       STYPE_INTVAL,
+       STYPE_UINTVAL,
+       STYPE_CHARVAL,
+} scm_type_t;
+
+typedef enum {
+       SCM_INBOUND_CODEC_STRING,
+       SCM_OUTBOUND_CODEC_STRING,
+       SCM_TEST,
+       SCM_MAX
+} scm_param_t;
+
+#define switch_media_get_param_int(_h, _p) *(int *)switch_media_get_param(_h, _p)
+#define switch_media_get_param_uint(_h, _p) *(uint32_t *)switch_media_get_param(_h, _p)
+#define switch_media_get_param_char(_h, _p) (char *)switch_media_get_param(_h, _p)
+
+
+
 
 SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t **smhp, switch_core_session_t *session);
 SWITCH_DECLARE(switch_media_handle_t *) switch_core_session_get_media_handle(switch_core_session_t *session);
@@ -53,6 +76,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_media_handle_ready(switch_co
 SWITCH_DECLARE(void) switch_media_handle_set_ndlb(switch_media_handle_t *smh, switch_core_media_NDLB_t flag);
 SWITCH_DECLARE(void) switch_media_handle_clear_ndlb(switch_media_handle_t *smh, switch_core_media_NDLB_t flag);
 SWITCH_DECLARE(int32_t) switch_media_handle_test_ndlb(switch_media_handle_t *smh, switch_core_media_NDLB_t flag);
+SWITCH_DECLARE(void) switch_media_handle_set_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag);
+SWITCH_DECLARE(void) switch_media_handle_clear_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag);
+SWITCH_DECLARE(int32_t) switch_media_handle_test_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag);
 SWITCH_DECLARE(void) switch_core_session_check_outgoing_crypto(switch_core_session_t *session, const char *sec_var);
 SWITCH_DECLARE(const char *) switch_core_session_local_crypto_key(switch_core_session_t *session, switch_media_type_t type);
 SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_session_t *session, 
@@ -64,6 +90,10 @@ SWITCH_DECLARE(void) switch_core_session_get_recovery_crypto_key(switch_core_ses
 
 SWITCH_DECLARE(void) switch_core_media_set_rtp_session(switch_core_session_t *session, switch_media_type_t type, switch_rtp_t *rtp_session);
 
+SWITCH_DECLARE(void) switch_media_set_param(switch_media_handle_t *smh, scm_param_t param, ...);
+SWITCH_DECLARE(void *) switch_media_get_param(switch_media_handle_t *smh, scm_param_t param);
+SWITCH_DECLARE(const char *)switch_core_media_get_codec_string(switch_core_session_t *session);
+
 SWITCH_END_EXTERN_C
 #endif
 /* For Emacs:
index d4879ebf41cab69545e8565a9e879057e86ef32d..389212a81e203fca6ac5674986851d3d621cfdb8 100644 (file)
@@ -611,6 +611,7 @@ struct sofia_profile {
        uint8_t pflags[PFLAG_MAX];
        unsigned int mflags;
        unsigned int ndlb;
+       unsigned int media_flags;
        uint32_t max_calls;
        uint32_t nonce_ttl;
        nua_t *nua;
index 8c762cc9cf65af5e6d0f9a760222ed15351d3714..5e7c02ba037d04e83965dbd2baf64ef4bec61377 100644 (file)
@@ -4251,7 +4251,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
                                                }
                                        } else if (!strcasecmp(var, "disable-transcoding")) {
                                                if (switch_true(val)) {
-                                                       sofia_set_pflag(profile, PFLAG_DISABLE_TRANSCODING);
+                                                       profile->media_flags |= SCMF_DISABLE_TRANSCODING;
+                                               } else {
+                                                       profile->media_flags &= ~SCMF_DISABLE_TRANSCODING;
                                                }
                                        } else if (!strcasecmp(var, "rtp-rewrite-timestamps")) {
                                                if (switch_true(val)) {
index b6f45778ebb6a81333a2220cf3f7d02e35bc089e..f36551a2696e8485825640e5bd3bc1cde8e10835 100644 (file)
@@ -281,7 +281,12 @@ void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t *
 
        switch_media_handle_create(&tech_pvt->media_handle, session);
        switch_media_handle_set_ndlb(tech_pvt->media_handle, tech_pvt->profile->ndlb);
+       switch_media_handle_set_media_flag(tech_pvt->media_handle, tech_pvt->profile->media_flags);
        
+       switch_media_set_param(tech_pvt->media_handle, SCM_INBOUND_CODEC_STRING, profile->inbound_codec_string);
+       switch_media_set_param(tech_pvt->media_handle, SCM_OUTBOUND_CODEC_STRING, profile->inbound_codec_string);
+
+
        switch_core_session_set_private(session, tech_pvt);
 
        if (channame) {
index c8cabf1d5569c9f7b8bf79191797bdece7b18841..c8618e1b6bdd51250d8051305064983d9bebb98e 100644 (file)
@@ -848,7 +848,7 @@ uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_
 
                                if (mimp) {
                                        char tmp[50];
-                                       const char *mirror = switch_channel_get_variable(tech_pvt->channel, "sip_mirror_remote_audio_codec_payload");
+                                       const char *mirror = switch_channel_get_variable(tech_pvt->channel, "rtp_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);
@@ -874,7 +874,7 @@ uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_
                                        }
                                        
                                        switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->audio_recv_pt);
-                                       switch_channel_set_variable(tech_pvt->channel, "sip_audio_recv_pt", tmp);
+                                       switch_channel_set_variable(tech_pvt->channel, "rtp_audio_recv_pt", tmp);
                                        
                                }
                                
@@ -1768,7 +1768,7 @@ void sofia_media_set_sdp_codec_string(switch_core_session_t *session, const char
        if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
 
                if ((sdp = sdp_session(parser))) {
-                       sofia_media_set_r_sdp_codec_string(session, sofia_media_get_codec_string(tech_pvt), sdp);
+                       sofia_media_set_r_sdp_codec_string(session, switch_core_media_get_codec_string(tech_pvt->session), sdp);
                }
 
                sdp_parser_free(parser);
@@ -1903,6 +1903,7 @@ switch_status_t sofia_media_tech_set_codec(private_object_t *tech_pvt, int force
                        switch_yield(tech_pvt->read_impl.microseconds_per_packet);
                        switch_core_codec_destroy(&tech_pvt->read_codec);
                        switch_core_codec_destroy(&tech_pvt->write_codec);
+                       switch_channel_audio_sync(tech_pvt->channel);
                } else {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_impl.iananame);
                        switch_goto_status(SWITCH_STATUS_SUCCESS, end);
@@ -2996,27 +2997,6 @@ void sofia_media_set_local_sdp(private_object_t *tech_pvt, const char *ip, switc
        switch_safe_free(buf);
 }
 
-const char *sofia_media_get_codec_string(private_object_t *tech_pvt)
-{
-       const char *preferred = NULL, *fallback = NULL;
-       
-       if (!(preferred = switch_channel_get_variable(tech_pvt->channel, "absolute_codec_string"))) {
-               preferred = switch_channel_get_variable(tech_pvt->channel, "codec_string");
-       }
-       
-       if (!preferred) {
-               if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
-                       preferred = tech_pvt->profile->outbound_codec_string;
-                       fallback = tech_pvt->profile->inbound_codec_string;
-               } else {
-                       preferred = tech_pvt->profile->inbound_codec_string;
-                       fallback = tech_pvt->profile->outbound_codec_string;
-               }
-       }
-
-       return !zstr(preferred) ? preferred : fallback;
-}
-
 void sofia_media_tech_prepare_codecs(private_object_t *tech_pvt)
 {
        const char *abs, *codec_string = NULL;
@@ -3045,7 +3025,7 @@ void sofia_media_tech_prepare_codecs(private_object_t *tech_pvt)
        }
 
        if (!(codec_string = switch_channel_get_variable(tech_pvt->channel, "codec_string"))) {
-               codec_string = sofia_media_get_codec_string(tech_pvt);
+               codec_string = switch_core_media_get_codec_string(tech_pvt->session);
        }
 
        if (codec_string && *codec_string == '=') {
@@ -3067,12 +3047,11 @@ void sofia_media_tech_prepare_codecs(private_object_t *tech_pvt)
  ready:
 
        if (codec_string) {
-               char *tmp_codec_string;
-               if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) {
-                       tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS);
-                       tech_pvt->num_codecs =
-                               switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, SWITCH_MAX_CODECS, tech_pvt->codec_order, tech_pvt->codec_order_last);
-               }
+               char *tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string);
+               tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS);
+               tech_pvt->num_codecs =
+                       switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, SWITCH_MAX_CODECS, tech_pvt->codec_order, tech_pvt->codec_order_last);
+               
        } else {
                tech_pvt->num_codecs = switch_loadable_module_get_codecs(tech_pvt->codecs, sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0]));
        }
@@ -3080,6 +3059,7 @@ void sofia_media_tech_prepare_codecs(private_object_t *tech_pvt)
 
 }
 
+
 void sofia_media_check_video_codecs(private_object_t *tech_pvt)
 {
        if (tech_pvt->num_codecs && !sofia_test_flag(tech_pvt, TFLAG_VIDEO)) {
index 81e16768c88e2c4ac6953eee0416bd7cd3ced299..dff04bb2afd8a282aaefe1083f71080963c7c625 100644 (file)
 #include <switch_curl.h>
 #include <errno.h>
 
+typedef union {
+       int32_t intval;
+       uint32_t uintval;
+       char *charval;
+} scm_multi_t;
+
+
+static scm_type_t typemap[SCM_MAX] = {
+       /*SCM_INBOUND_CODEC_STRING*/  STYPE_CHARVAL, 
+       /*SCM_OUTBOUND_CODEC_STRING*/ STYPE_CHARVAL,
+       /*SCM_TEST*/ STYPE_INTVAL
+};
+
 typedef enum {
        SMH_INIT = (1 << 0),
        SMH_READY = (1 << 1)
@@ -59,18 +72,106 @@ typedef struct secure_settings_s {
 
 typedef struct switch_rtp_engine_s {
        switch_secure_settings_t ssec;
-       switch_rtp_t *rtp_session;
+       switch_rtp_t *rtp_session;//tp
+       switch_frame_t read_frame;//tp
        switch_media_type_t type;
 } switch_rtp_engine_t;
 
 
 struct switch_media_handle_s {
        switch_core_session_t *session;
+       switch_channel_t *channel;
        switch_core_media_NDLB_t ndlb;
+       switch_core_media_flag_t media_flags;
        smh_flag_t flags;
        switch_rtp_engine_t engines[SWITCH_MEDIA_TYPE_TOTAL];
+       scm_multi_t params[SCM_MAX];
+       char *codec_order[SWITCH_MAX_CODECS];//tp
+    int codec_order_last;//tp
+    const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];//tp
+    int num_codecs;//tp
+       int payload_space;//tp
 };
 
+SWITCH_DECLARE(void) switch_media_set_param(switch_media_handle_t *smh, scm_param_t param, ...)
+{
+       scm_multi_t *val = &smh->params[param];
+       scm_type_t type = typemap[param];
+       va_list ap;
+
+       va_start(ap, param);
+
+       switch(type) {
+       case STYPE_INTVAL:
+               val->intval = va_arg(ap, int);
+               break;
+       case STYPE_UINTVAL:
+               val->uintval = va_arg(ap, unsigned int);
+               break;
+       case STYPE_CHARVAL:
+               val->charval = switch_core_session_strdup(smh->session, va_arg(ap, char *));
+               break;
+       default:
+               abort();
+       }
+
+       va_end(ap);
+}
+
+SWITCH_DECLARE(void *) switch_media_get_param(switch_media_handle_t *smh, scm_param_t param)
+{
+       scm_multi_t *val = &smh->params[param];
+       scm_type_t type = typemap[param];
+
+       switch(type) {
+       case STYPE_INTVAL:
+               return &val->intval;
+               break;
+       case STYPE_UINTVAL:
+               return &val->uintval;
+               break;
+       case STYPE_CHARVAL:
+               return val->charval;
+               break;
+       default:
+               abort();
+       }
+       
+       return NULL;
+       
+}
+
+#define get_str(_o, _p) _o->params[_p].charval
+
+SWITCH_DECLARE(const char *)switch_core_media_get_codec_string(switch_core_session_t *session)
+{
+       const char *preferred = NULL, *fallback = NULL;
+       switch_media_handle_t *smh;
+
+       if (!(smh = session->media_handle)) {
+               preferred = "PCMU";
+               fallback = "PCMU";
+       } else {
+       
+               if (!(preferred = switch_channel_get_variable(session->channel, "absolute_codec_string"))) {
+                       preferred = switch_channel_get_variable(session->channel, "codec_string");
+               }
+       
+               if (!preferred) {
+                       if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+                               preferred = get_str(smh, SCM_OUTBOUND_CODEC_STRING);
+                               fallback = get_str(smh, SCM_INBOUND_CODEC_STRING);
+
+                       } else {
+                               preferred = get_str(smh, SCM_INBOUND_CODEC_STRING);
+                               fallback = get_str(smh, SCM_OUTBOUND_CODEC_STRING);
+                       }
+               }
+       }
+
+       return !zstr(preferred) ? preferred : fallback;
+}
+
 
 SWITCH_DECLARE(const char *) switch_core_session_local_crypto_key(switch_core_session_t *session, switch_media_type_t type)
 {
@@ -191,6 +292,7 @@ SWITCH_DECLARE(void) switch_core_media_set_rtp_session(switch_core_session_t *se
        if (!session->media_handle) return;
        engine = &session->media_handle->engines[type];
        engine->rtp_session = rtp_session;
+       engine->type = type;
 }
 
 
@@ -346,6 +448,10 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t
                session->media_handle->session = session;
                *smhp = session->media_handle;
                switch_set_flag(session->media_handle, SMH_INIT);
+
+               session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
+               session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
+
                status = SWITCH_STATUS_SUCCESS;
        }
 
@@ -357,7 +463,7 @@ SWITCH_DECLARE(void) switch_media_handle_set_ndlb(switch_media_handle_t *smh, sw
 {
        switch_assert(smh);
 
-       smh->flags |= flag;
+       smh->ndlb |= flag;
        
 }
 
@@ -365,13 +471,34 @@ SWITCH_DECLARE(void) switch_media_handle_clear_ndlb(switch_media_handle_t *smh,
 {
        switch_assert(smh);
 
-       smh->flags &= ~flag;
+       smh->ndlb &= ~flag;
 }
 
 SWITCH_DECLARE(int32_t) switch_media_handle_test_ndlb(switch_media_handle_t *smh, switch_core_media_NDLB_t flag)
 {
        switch_assert(smh);
-       return (smh->flags & flag);
+       return (smh->ndlb & flag);
+}
+
+SWITCH_DECLARE(void) switch_media_handle_set_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag)
+{
+       switch_assert(smh);
+
+       smh->media_flags |= flag;
+       
+}
+
+SWITCH_DECLARE(void) switch_media_handle_clear_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag)
+{
+       switch_assert(smh);
+
+       smh->media_flags &= ~flag;
+}
+
+SWITCH_DECLARE(int32_t) switch_media_handle_test_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag)
+{
+       switch_assert(smh);
+       return (smh->media_flags & flag);
 }
 
 SWITCH_DECLARE(switch_status_t) switch_core_session_media_handle_ready(switch_core_session_t *session)
@@ -404,6 +531,397 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_clear_media_handle(switch_co
 
 
 
+
+#if 0
+SWITCH_DECLARE(switch_status_t) switch_core_session_read_media_frame(switch_core_session_t *session, switch_frame_t **frame,
+                                                                                                                                        switch_io_flag_t flags, int stream_id, switch_media_type_t type)
+{
+       switch_channel_t *channel;
+       uint32_t sanity = 1000;
+       switch_rtcp_frame_t rtcp_frame;
+       switch_rtp_engine_t *engine;
+
+       if (!session->media_handle) return;
+
+       engine = &session->media_handle->engines[type];
+       channel = switch_core_session_get_channel(session);
+
+
+       switch_assert(tech_pvt != NULL);
+
+
+       tech_pvt->read_frame.datalen = 0;
+       sofia_set_flag_locked(tech_pvt, TFLAG_READING);
+
+       if (sofia_test_flag(tech_pvt, TFLAG_HUP) || sofia_test_flag(tech_pvt, TFLAG_BYE) || !tech_pvt->read_codec.implementation ||
+               !switch_core_codec_ready(&tech_pvt->read_codec)) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       if (sofia_test_flag(tech_pvt, TFLAG_IO)) {
+               switch_status_t status;
+
+               if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
+                       return SWITCH_STATUS_GENERR;
+               }
+
+               switch_assert(tech_pvt->rtp_session != NULL);
+               tech_pvt->read_frame.datalen = 0;
+
+
+               if (sofia_test_flag(tech_pvt, TFLAG_SIMPLIFY) && sofia_test_flag(tech_pvt, TFLAG_GOT_ACK)) {
+                       if (sofia_glue_tech_simplify(tech_pvt)) {
+                               sofia_clear_flag(tech_pvt, TFLAG_SIMPLIFY);
+                       }
+               }
+
+               while (sofia_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
+                       tech_pvt->read_frame.flags = SFF_NONE;
+
+                       status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags);
+                       
+                       if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+                               if (status == SWITCH_STATUS_TIMEOUT) {
+
+                                       if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+                                               sofia_glue_toggle_hold(tech_pvt, 0);
+                                               sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                                               switch_channel_clear_flag(channel, CF_LEG_HOLDING);
+                                       }
+                                       
+                                       if (switch_channel_get_variable(tech_pvt->channel, "execute_on_media_timeout")) {
+                                               *frame = &tech_pvt->read_frame;
+                                               switch_set_flag((*frame), SFF_CNG);
+                                               (*frame)->datalen = tech_pvt->read_impl.encoded_bytes_per_packet;
+                                               memset((*frame)->data, 0, (*frame)->datalen);
+                                               switch_channel_execute_on(tech_pvt->channel, "execute_on_media_timeout");
+                                               return SWITCH_STATUS_SUCCESS;
+                                       }
+
+
+                                       switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_MEDIA_TIMEOUT);
+                               }
+                               return status;
+                       }
+
+                       /* Try to read an RTCP frame, if successful raise an event */
+                       if (switch_rtcp_zerocopy_read_frame(tech_pvt->rtp_session, &rtcp_frame) == SWITCH_STATUS_SUCCESS) {
+                               switch_event_t *event;
+
+                               if (switch_event_create(&event, SWITCH_EVENT_RECV_RTCP_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+                                       char value[30];
+                                       char header[50];
+                                       int i;
+
+                                       char *uuid = switch_core_session_get_uuid(session);
+                                       if (uuid) {
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session));
+                                       }
+
+                                       snprintf(value, sizeof(value), "%.8x", rtcp_frame.ssrc);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SSRC", value);
+
+                                       snprintf(value, sizeof(value), "%u", rtcp_frame.ntp_msw);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Most-Significant-Word", value);
+
+                                       snprintf(value, sizeof(value), "%u", rtcp_frame.ntp_lsw);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Least-Significant-Word", value);
+
+                                       snprintf(value, sizeof(value), "%u", rtcp_frame.timestamp);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Timestamp", value);
+
+                                       snprintf(value, sizeof(value), "%u", rtcp_frame.packet_count);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sender-Packet-Count", value);
+
+                                       snprintf(value, sizeof(value), "%u", rtcp_frame.octect_count);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Octect-Packet-Count", value);
+
+                                       snprintf(value, sizeof(value), "%" SWITCH_SIZE_T_FMT, tech_pvt->read_frame.timestamp);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Last-RTP-Timestamp", value);
+
+                                       snprintf(value, sizeof(value), "%u", tech_pvt->read_frame.rate);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Rate", value);
+
+                                       snprintf(value, sizeof(value), "%" SWITCH_TIME_T_FMT, switch_time_now());
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Capture-Time", value);
+
+                                        // Add sources info
+                                       for (i = 0; i < rtcp_frame.report_count; i++) {
+                                               snprintf(header, sizeof(header), "Source%u-SSRC", i);
+                                               snprintf(value, sizeof(value), "%.8x", rtcp_frame.reports[i].ssrc);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
+                                               snprintf(header, sizeof(header), "Source%u-Fraction", i);
+                                               snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].fraction);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
+                                               snprintf(header, sizeof(header), "Source%u-Lost", i);
+                                               snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].lost);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
+                                               snprintf(header, sizeof(header), "Source%u-Highest-Sequence-Number-Received", i);
+                                               snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].highest_sequence_number_received);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
+                                               snprintf(header, sizeof(header), "Source%u-Jitter", i);
+                                               snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].jitter);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
+                                               snprintf(header, sizeof(header), "Source%u-LSR", i);
+                                               snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].lsr);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
+                                               snprintf(header, sizeof(header), "Source%u-DLSR", i);
+                                               snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].dlsr);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
+                                       }
+
+                                       switch_event_fire(&event);
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "Dispatched RTCP event\n");
+                               }
+                       }
+
+                       /* Fast PASS! */
+                       if (switch_test_flag((&tech_pvt->read_frame), SFF_PROXY_PACKET)) {
+                               sofia_clear_flag_locked(tech_pvt, TFLAG_READING);
+                               *frame = &tech_pvt->read_frame;
+                               return SWITCH_STATUS_SUCCESS;
+                       }
+
+                       if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
+                               switch_dtmf_t dtmf = { 0 };
+                               switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf);
+                               switch_channel_queue_dtmf(channel, &dtmf);
+                       }
+
+                       if (tech_pvt->read_frame.datalen > 0) {
+                               uint32_t bytes = 0;
+                               int frames = 1;
+
+                               if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) {
+                                       if (!tech_pvt->read_codec.implementation || !switch_core_codec_ready(&tech_pvt->read_codec)) {
+                                               *frame = NULL;
+                                               return SWITCH_STATUS_GENERR;
+                                       }
+
+                                       if ((tech_pvt->read_frame.datalen % 10) == 0 &&
+                                               sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING) && tech_pvt->check_frames < MAX_CODEC_CHECK_FRAMES) {
+                                               tech_pvt->check_frames++;
+
+                                               if (!tech_pvt->read_impl.encoded_bytes_per_packet) {
+                                                       tech_pvt->check_frames = MAX_CODEC_CHECK_FRAMES;
+                                                       goto skip;
+                                               }
+
+                                               if (tech_pvt->last_ts && tech_pvt->read_frame.datalen != tech_pvt->read_impl.encoded_bytes_per_packet) {
+                                                       uint32_t codec_ms = (int) (tech_pvt->read_frame.timestamp -
+                                                                                                          tech_pvt->last_ts) / (tech_pvt->read_impl.samples_per_second / 1000);
+
+                                                       if ((codec_ms % 10) != 0 || codec_ms > tech_pvt->read_impl.samples_per_packet * 10) {
+                                                               tech_pvt->last_ts = 0;
+                                                               goto skip;
+                                                       }
+
+
+                                                       if (tech_pvt->last_codec_ms && tech_pvt->last_codec_ms == codec_ms) {
+                                                               tech_pvt->mismatch_count++;
+                                                       }
+
+                                                       tech_pvt->last_codec_ms = codec_ms;
+
+                                                       if (tech_pvt->mismatch_count > MAX_MISMATCH_FRAMES) {
+                                                               if (switch_rtp_ready(tech_pvt->rtp_session) && codec_ms != tech_pvt->codec_ms) {
+                                                                       const char *val;
+                                                                       int rtp_timeout_sec = 0;
+                                                                       int rtp_hold_timeout_sec = 0;
+
+                                                                       if (codec_ms > 120) {   /* yeah right */
+                                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
+                                                                                                                 "Your phone is trying to send timestamps that suggest an increment of %dms per packet\n"
+                                                                                                                 "That seems hard to believe so I am going to go on ahead and um ignore that, mmkay?\n",
+                                                                                                                 (int) codec_ms);
+                                                                               tech_pvt->check_frames = MAX_CODEC_CHECK_FRAMES;
+                                                                               goto skip;
+                                                                       }
+
+                                                                       tech_pvt->read_frame.datalen = 0;
+
+                                                                       if (codec_ms != tech_pvt->codec_ms) {
+                                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
+                                                                                                                 "Asynchronous PTIME not supported, changing our end from %d to %d\n",
+                                                                                                                 (int) tech_pvt->codec_ms,
+                                                                                                                 (int) codec_ms
+                                                                                                                 );
+
+                                                                               switch_channel_set_variable_printf(channel, "sip_h_X-Broken-PTIME", "Adv=%d;Sent=%d",
+                                                                                                                                                  (int) tech_pvt->codec_ms, (int) codec_ms);
+
+                                                                               tech_pvt->codec_ms = codec_ms;
+                                                                       }
+
+                                                                       if (sofia_glue_tech_set_codec(tech_pvt, 2) != SWITCH_STATUS_SUCCESS) {
+                                                                               *frame = NULL;
+                                                                               return SWITCH_STATUS_GENERR;
+                                                                       }
+
+                                                                       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;
+                                                                       }
+
+
+                                                                       tech_pvt->check_frames = 0;
+                                                                       tech_pvt->last_ts = 0;
+
+                                                                       /* inform them of the codec they are actually sending */
+#if 0
+                                                                       if (++tech_pvt->codec_reinvites > 2) {
+                                                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
+                                                                                                                 "Ok, some devices *cough* X-lite *cough*\n"
+                                                                                                                 "seem to continue to lie over and over again so I guess we'll\n"
+                                                                                                                 "leave well-enough alone and let them lie\n");
+                                                                       } else {
+                                                                               sofia_glue_do_invite(session);
+                                                                       }
+#endif
+                                                                       *frame = &tech_pvt->read_frame;
+                                                                       switch_set_flag((*frame), SFF_CNG);
+                                                                       (*frame)->datalen = tech_pvt->read_impl.encoded_bytes_per_packet;
+                                                                       memset((*frame)->data, 0, (*frame)->datalen);
+                                                                       return SWITCH_STATUS_SUCCESS;
+                                                               }
+
+                                                       }
+
+                                               } else {
+                                                       tech_pvt->mismatch_count = 0;
+                                               }
+
+                                               tech_pvt->last_ts = tech_pvt->read_frame.timestamp;
+
+
+                                       } else {
+                                               tech_pvt->mismatch_count = 0;
+                                               tech_pvt->last_ts = 0;
+                                       }
+                                 skip:
+
+                                       if ((bytes = tech_pvt->read_impl.encoded_bytes_per_packet)) {
+                                               frames = (tech_pvt->read_frame.datalen / bytes);
+                                       }
+                                       tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_impl.samples_per_packet);
+
+                                       if (tech_pvt->read_frame.datalen == 0) {
+                                               continue;
+                                       }
+                               }
+                               break;
+                       }
+               }
+       }
+
+       sofia_clear_flag_locked(tech_pvt, TFLAG_READING);
+
+       if (tech_pvt->read_frame.datalen == 0) {
+               *frame = NULL;
+               return SWITCH_STATUS_GENERR;
+       }
+
+       *frame = &tech_pvt->read_frame;
+
+       return SWITCH_STATUS_SUCCESS;
+}
+#endif
+
+
+
+SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *session, switch_bool_t force)
+{
+       const char *abs, *codec_string = NULL;
+       const char *ocodec = NULL;
+       switch_media_handle_t *smh;
+
+       if (!(smh = session->media_handle)) {
+               return;
+       }
+
+       if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) {
+               return;
+       }
+
+       if (force) {
+               smh->num_codecs = 0;
+       }
+
+       if (smh->num_codecs) {
+               return;
+       }
+
+       smh->payload_space = 0;
+
+       switch_assert(smh->session != NULL);
+
+       if ((abs = switch_channel_get_variable(session->channel, "absolute_codec_string"))) {
+               /* inherit_codec == true will implicitly clear the absolute_codec_string 
+                  variable if used since it was the reason it was set in the first place and is no longer needed */
+               if (switch_true(switch_channel_get_variable(session->channel, "inherit_codec"))) {
+                       switch_channel_set_variable(session->channel, "absolute_codec_string", NULL);
+               }
+               codec_string = abs;
+               goto ready;
+       }
+
+       if (!(codec_string = switch_channel_get_variable(session->channel, "codec_string"))) {
+               codec_string = switch_core_media_get_codec_string(smh->session);
+       }
+
+       if (codec_string && *codec_string == '=') {
+               codec_string++;
+               goto ready;
+       }
+
+
+       if ((ocodec = switch_channel_get_variable(session->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
+               if (!codec_string || (smh->media_flags & SCMF_DISABLE_TRANSCODING)) {
+                       codec_string = ocodec;
+               } else {
+                       if (!(codec_string = switch_core_session_sprintf(smh->session, "%s,%s", ocodec, codec_string))) {
+                               codec_string = ocodec;
+                       }
+               }
+       }
+
+ ready:
+
+       if (codec_string) {
+               char *tmp_codec_string = switch_core_session_strdup(smh->session, codec_string);
+               smh->codec_order_last = switch_separate_string(tmp_codec_string, ',', smh->codec_order, SWITCH_MAX_CODECS);
+               smh->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
+       } else {
+               smh->num_codecs = switch_loadable_module_get_codecs(smh->codecs, sizeof(smh->codecs) / sizeof(smh->codecs[0]));
+       }
+}
+
+
+
 /* For Emacs:
  * Local Variables:
  * mode:c