diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index e2ce4dd819..c72e453e08 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -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: diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index d4879ebf41..389212a81e 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -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; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 8c762cc9cf..5e7c02ba03 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -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)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index b6f45778eb..f36551a269 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -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) { diff --git a/src/mod/endpoints/mod_sofia/sofia_media.c b/src/mod/endpoints/mod_sofia/sofia_media.c index c8cabf1d55..c8618e1b6b 100644 --- a/src/mod/endpoints/mod_sofia/sofia_media.c +++ b/src/mod/endpoints/mod_sofia/sofia_media.c @@ -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)) { diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 81e16768c8..dff04bb2af 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -40,6 +40,19 @@ #include #include +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