diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 272d435068..c01638089f 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -596,7 +596,7 @@ typedef enum { */ - RTP_BUG_IGNORE_MARK_BIT = (1 << 2) + RTP_BUG_IGNORE_MARK_BIT = (1 << 2), /* A Huawei SBC has been discovered that sends the mark bit on every single RTP packet. @@ -606,6 +606,34 @@ typedef enum { */ + + RTP_BUG_SEND_LINEAR_TIMESTAMPS = (1 << 3), + + /* + Our friends at Sonus get real mad when the timestamps are not in perfect sequence even during periods of silence. + With this flag, we will only increment the timestamp when write packets even if they are eons apart. + + */ + + RTP_BUG_START_SEQ_AT_ZERO = (1 << 4), + + /* + Our friends at Sonus also get real mad if the sequence number does not start at 0. + Typically, we set this to a random starting value for your saftey. + This is a security risk you take upon yourself when you enable this flag. + */ + + + RTP_BUG_NEVER_SEND_MARKER = (1 << 5), + + /* + Our friends at Sonus are on a roll, They also get easily dumbfounded by marker bits. + This flag will never send any. Sheesh.... + */ + + + + } switch_rtp_bug_flag_t; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 6978e34ffc..750fb60c15 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -558,6 +558,7 @@ struct sofia_profile { char *user_agent_filter; uint32_t max_registrations_perext; switch_rtp_bug_flag_t auto_rtp_bugs; + switch_rtp_bug_flag_t manual_rtp_bugs; uint32_t ib_calls; uint32_t ob_calls; uint32_t ib_failed_calls; @@ -1035,3 +1036,4 @@ void sofia_glue_proxy_codec(switch_core_session_t *session, const char *r_sdp); switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt); void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl); void sofia_glue_check_dtmf_type(private_object_t *tech_pvt); +void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 7cb4c5b528..e5672061bd 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2220,39 +2220,6 @@ static void parse_domain_tag(sofia_profile_t *profile, switch_xml_t x_domain_tag } } -static void parse_rtp_bugs(sofia_profile_t *profile, const char *str) -{ - - if (switch_stristr("clear", str)) { - profile->auto_rtp_bugs = 0; - } - - if (switch_stristr("CISCO_SKIP_MARK_BIT_2833", str)) { - profile->auto_rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833; - } - - if (switch_stristr("~CISCO_SKIP_MARK_BIT_2833", str)) { - profile->auto_rtp_bugs &= ~RTP_BUG_CISCO_SKIP_MARK_BIT_2833; - } - - if (switch_stristr("SONUS_SEND_INVALID_TIMESTAMP_2833", str)) { - profile->auto_rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; - } - - if (switch_stristr("~SONUS_SEND_INVALID_TIMESTAMP_2833", str)) { - profile->auto_rtp_bugs &= ~RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; - } - - if (switch_stristr("IGNORE_MARK_BIT", str)) { - profile->auto_rtp_bugs |= RTP_BUG_IGNORE_MARK_BIT; - } - - if (switch_stristr("~IGNORE_MARK_BIT", str)) { - profile->auto_rtp_bugs &= ~RTP_BUG_IGNORE_MARK_BIT; - } - -} - switch_status_t reconfig_sofia(sofia_profile_t *profile) { switch_xml_t cfg, xml = NULL, xprofile, profiles, gateways_tag, domain_tag, domains_tag, aliases_tag, alias_tag, settings, param; @@ -2382,7 +2349,9 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) sofia_clear_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER); } } else if (!strcasecmp(var, "auto-rtp-bugs")) { - parse_rtp_bugs(profile, val); + sofia_glue_parse_rtp_bugs(&profile->auto_rtp_bugs, val); + } else if (!strcasecmp(var, "manual-rtp-bugs")) { + sofia_glue_parse_rtp_bugs(&profile->manual_rtp_bugs, val); } else if (!strcasecmp(var, "user-agent-string")) { profile->user_agent = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "auto-restart")) { @@ -3103,7 +3072,9 @@ switch_status_t config_sofia(int reload, char *profile_name) profile->rport_level = 2; } } else if (!strcasecmp(var, "auto-rtp-bugs")) { - parse_rtp_bugs(profile, val); + sofia_glue_parse_rtp_bugs(&profile->auto_rtp_bugs, val); + } else if (!strcasecmp(var, "manual-rtp-bugs")) { + sofia_glue_parse_rtp_bugs(&profile->manual_rtp_bugs, val); } else if (!strcasecmp(var, "dbname")) { profile->dbname = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "presence-hosts")) { diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index fbd270d41b..6e9aacb126 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3106,7 +3106,11 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f tech_pvt->rtp_bugs |= RTP_BUG_IGNORE_MARK_BIT; } - switch_rtp_intentional_bugs(tech_pvt->rtp_session, tech_pvt->rtp_bugs); + 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); @@ -5990,6 +5994,62 @@ void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const } +void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str) +{ + + if (switch_stristr("clear", str)) { + *flag_pole = 0; + } + + if (switch_stristr("CISCO_SKIP_MARK_BIT_2833", str)) { + *flag_pole |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833; + } + + if (switch_stristr("~CISCO_SKIP_MARK_BIT_2833", str)) { + *flag_pole &= ~RTP_BUG_CISCO_SKIP_MARK_BIT_2833; + } + + if (switch_stristr("SONUS_SEND_INVALID_TIMESTAMP_2833", str)) { + *flag_pole |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; + } + + if (switch_stristr("~SONUS_SEND_INVALID_TIMESTAMP_2833", str)) { + *flag_pole &= ~RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; + } + + if (switch_stristr("IGNORE_MARK_BIT", str)) { + *flag_pole |= RTP_BUG_IGNORE_MARK_BIT; + } + + if (switch_stristr("~IGNORE_MARK_BIT", str)) { + *flag_pole &= ~RTP_BUG_IGNORE_MARK_BIT; + } + + if (switch_stristr("SEND_LINEAR_TIMESTAMPS", str)) { + *flag_pole |= RTP_BUG_SEND_LINEAR_TIMESTAMPS; + } + + if (switch_stristr("~SEND_LINEAR_TIMESTAMPS", str)) { + *flag_pole &= ~RTP_BUG_SEND_LINEAR_TIMESTAMPS; + } + + if (switch_stristr("START_SEQ_AT_ZERO", str)) { + *flag_pole |= RTP_BUG_START_SEQ_AT_ZERO; + } + + if (switch_stristr("~START_SEQ_AT_ZERO", str)) { + *flag_pole &= ~RTP_BUG_START_SEQ_AT_ZERO; + } + + if (switch_stristr("NEVER_SEND_MARKER", str)) { + *flag_pole |= RTP_BUG_NEVER_SEND_MARKER; + } + + if (switch_stristr("~NEVER_SEND_MARKER", str)) { + *flag_pole &= ~RTP_BUG_NEVER_SEND_MARKER; + } +} + diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 1792de08b3..f0eead3c42 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -1366,7 +1366,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { switch_sockaddr_info_get(&rtp_session->rtcp_from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool); } - rtp_session->seq = (uint16_t) rand(); + rtp_session->seq = (rtp_session->rtp_bugs & RTP_BUG_START_SEQ_AT_ZERO) ? 0 : (uint16_t) rand(); rtp_session->ssrc = (uint32_t) ((intptr_t) rtp_session + (uint32_t) switch_epoch_time_now(NULL)); rtp_session->send_msg.header.ssrc = htonl(rtp_session->ssrc); @@ -3179,10 +3179,15 @@ static int rtp_common_write(switch_rtp_t *rtp_session, send_msg = &rtp_session->send_msg; send_msg->header.pt = payload; - if (timestamp) { + if (rtp_session->rtp_bugs & RTP_BUG_SEND_LINEAR_TIMESTAMPS) { + rtp_session->ts += rtp_session->samples_per_interval; + if (rtp_session->ts <= rtp_session->last_write_ts && rtp_session->ts > 0) { + rtp_session->ts = rtp_session->last_write_ts + rtp_session->samples_per_interval; + } + } else if (timestamp) { rtp_session->ts = (uint32_t) timestamp; /* Send marker bit if timestamp is lower/same as before (resetted/new timer) */ - if (rtp_session->ts <= rtp_session->last_write_ts) { + if (rtp_session->ts <= rtp_session->last_write_ts && !(rtp_session->rtp_bugs & RTP_BUG_NEVER_SEND_MARKER)) { m++; } } else if (rtp_session->timer.timer_interface) { @@ -3216,8 +3221,8 @@ static int rtp_common_write(switch_rtp_t *rtp_session, rtp_session->cn = 0; m++; } - - send_msg->header.m = m ? 1 : 0; + + send_msg->header.m = (m && !(rtp_session->rtp_bugs & RTP_BUG_NEVER_SEND_MARKER)) ? 1 : 0; memcpy(send_msg->body, data, datalen); bytes = datalen + rtp_header_len; @@ -3287,7 +3292,9 @@ static int rtp_common_write(switch_rtp_t *rtp_session, if (diff >= rtp_session->vad_data.diff_level || ++rtp_session->vad_data.hangunder_hits >= rtp_session->vad_data.hangunder) { switch_set_flag(&rtp_session->vad_data, SWITCH_VAD_FLAG_TALKING); - send_msg->header.m = 1; + if (!(rtp_session->rtp_bugs & RTP_BUG_NEVER_SEND_MARKER)) { + send_msg->header.m = 1; + } rtp_session->vad_data.hangover_hits = rtp_session->vad_data.hangunder_hits = rtp_session->vad_data.cng_count = 0; if (switch_test_flag(&rtp_session->vad_data, SWITCH_VAD_FLAG_EVENTS_TALK)) { switch_event_t *event; @@ -3755,7 +3762,7 @@ SWITCH_DECLARE(int) switch_rtp_write_manual(switch_rtp_t *rtp_session, rtp_session->write_msg.header.seq = htons(++rtp_session->seq); rtp_session->write_msg.header.ts = htonl(ts); rtp_session->write_msg.header.pt = payload; - rtp_session->write_msg.header.m = m ? 1 : 0; + rtp_session->write_msg.header.m = (m && !(rtp_session->rtp_bugs & RTP_BUG_NEVER_SEND_MARKER)) ? 1 : 0; memcpy(rtp_session->write_msg.body, data, datalen); bytes = rtp_header_len + datalen;