From 181b543b0ca349a8a081eab141ed7077467cedea Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 5 Jan 2011 16:25:07 -0600 Subject: [PATCH] add auto-jitterbuffer-msec param and auto-disable the jitterbuffer when briding to another channel who also has a jitterbuffer so both legs will disable during a bridge --- conf/sip_profiles/internal.xml | 3 +++ src/include/switch_channel.h | 1 + src/include/switch_rtp.h | 1 + src/include/switch_types.h | 2 ++ src/mod/endpoints/mod_sofia/mod_sofia.c | 22 ++++++++++++++++-- src/mod/endpoints/mod_sofia/mod_sofia.h | 2 ++ src/mod/endpoints/mod_sofia/sofia.c | 10 ++++++++ src/mod/endpoints/mod_sofia/sofia_glue.c | 29 ++++++++++++++++++------ src/switch_channel.c | 18 +++++++++++++++ src/switch_ivr_bridge.c | 2 +- src/switch_rtp.c | 27 +++++++++++++++++++--- 11 files changed, 104 insertions(+), 13 deletions(-) diff --git a/conf/sip_profiles/internal.xml b/conf/sip_profiles/internal.xml index 3e756a85c0..d09ca79dce 100644 --- a/conf/sip_profiles/internal.xml +++ b/conf/sip_profiles/internal.xml @@ -337,6 +337,9 @@ A completed transaction is kept around for the duration of T4 in order to catch late responses. The T4 is the maximum duration for the messages to stay in the network and the duration of SIP timer K. --> + + + diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index ee9b397d2a..368b8950e4 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -344,6 +344,7 @@ SWITCH_DECLARE(void) switch_channel_set_cap_value(switch_channel_t *channel, swi SWITCH_DECLARE(void) switch_channel_clear_cap(switch_channel_t *channel, switch_channel_cap_t cap); SWITCH_DECLARE(uint32_t) switch_channel_test_cap(switch_channel_t *channel, switch_channel_cap_t cap); +SWITCH_DECLARE(uint32_t) switch_channel_test_cap_partner(switch_channel_t *channel, switch_channel_cap_t cap); /*! \brief Set given flag(s) on a given channel's bridge partner diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index a161d2ac0e..27dacc7c18 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -237,6 +237,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t * SWITCH_DECLARE(switch_status_t) switch_rtp_debug_jitter_buffer(switch_rtp_t *rtp_session, const char *name); SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t *rtp_session); +SWITCH_DECLARE(switch_status_t) switch_rtp_pause_jitter_buffer(switch_rtp_t *rtp_session, switch_bool_t pause); /*! \brief Set an RTP Flag diff --git a/src/include/switch_types.h b/src/include/switch_types.h index d3aacca634..98ac804308 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1035,6 +1035,8 @@ typedef enum { CC_MEDIA_ACK = 1, CC_BYPASS_MEDIA, CC_PROXY_MEDIA, + CC_JITTERBUFFER, + CC_FS_RTP, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ CC_FLAG_MAX } switch_channel_cap_t; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index f7ce6fac76..a0bcdbdbd1 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1346,7 +1346,13 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi char *p; const char *s; - if (!strncasecmp(msg->string_arg, "debug:", 6)) { + if (!strcasecmp(msg->string_arg, "pause")) { + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_TRUE); + goto end; + } else if (!strcasecmp(msg->string_arg, "resume")) { + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_FALSE); + goto end; + } else if (!strncasecmp(msg->string_arg, "debug:", 6)) { s = msg->string_arg + 6; if (s && !strcmp(s, "off")) { s = NULL; @@ -1426,10 +1432,16 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi { sofia_glue_tech_simplify(tech_pvt); - + if (switch_rtp_ready(tech_pvt->rtp_session)) { const char *val; int ok = 0; + + if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER) && switch_channel_test_cap_partner(tech_pvt->channel, CC_FS_RTP)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "%s PAUSE Jitterbuffer\n", switch_channel_get_name(channel)); + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_TRUE); + } if (sofia_test_flag(tech_pvt, TFLAG_PASS_RFC2833) && switch_channel_test_flag_partner(channel, CF_FS_RTP)) { switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833); @@ -1455,6 +1467,12 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (switch_rtp_ready(tech_pvt->rtp_session)) { const char *val; int ok = 0; + + if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "%s RESUME Jitterbuffer\n", switch_channel_get_name(channel)); + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_FALSE); + } if (switch_rtp_test_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s deactivate passthru 2833 mode.\n", diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index e1b1ff71e3..df267967fa 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -501,6 +501,7 @@ struct sofia_profile { char *challenge_realm; char *rtcp_audio_interval_msec; char *rtcp_video_interval_msec; + char *jb_msec; sofia_cid_type_t cid_type; sofia_dtmf_t dtmf_type; int auto_restart; @@ -1050,3 +1051,4 @@ void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const void sofia_glue_check_dtmf_type(private_object_t *tech_pvt); void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str); char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sofia_nat_parse_t *np); +void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 61ede0c5c4..99c18cbaaa 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2351,6 +2351,11 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { sofia_clear_pflag(profile, PFLAG_DISABLE_HOLD); } + } else if (!strcasecmp(var, "auto-jitterbuffer-msec")) { + int msec = atoi(val); + if (msec > 19) { + profile->jb_msec = switch_core_strdup(profile->pool, val); + } } else if (!strcasecmp(var, "sip-trace")) { if (switch_true(val)) { sofia_set_flag(profile, TFLAG_TPORT_LOG); @@ -3089,6 +3094,11 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_DISABLE_HOLD); } + } else if (!strcasecmp(var, "auto-jitterbuffer-msec")) { + int msec = atoi(val); + if (msec > 19) { + profile->jb_msec = switch_core_strdup(profile->pool, val); + } } else if (!strcasecmp(var, "dtmf-type")) { if (!strcasecmp(val, "rfc2833")) { profile->dtmf_type = DTMF_2833; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index f4ec094b9e..6b8521b10e 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -832,6 +832,8 @@ void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t * switch_channel_set_cap(tech_pvt->channel, CC_MEDIA_ACK); switch_channel_set_cap(tech_pvt->channel, CC_BYPASS_MEDIA); switch_channel_set_cap(tech_pvt->channel, CC_PROXY_MEDIA); + switch_channel_set_cap(tech_pvt->channel, CC_JITTERBUFFER); + switch_channel_set_cap(tech_pvt->channel, CC_FS_RTP); switch_core_session_set_private(session, tech_pvt); @@ -3152,8 +3154,8 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f } } - if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec"))) { - int len = atoi(val); + 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; char *p; @@ -3162,13 +3164,13 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f maxlen = atoi(p); } - if (len < 20 || len > 10000) { + 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", len); + "Invalid Jitterbuffer spec [%d] must be between 20 and 10000\n", jb_msec); } else { int qlen, maxqlen = 50; - qlen = len / (tech_pvt->read_impl.microseconds_per_packet / 1000); + qlen = jb_msec / (tech_pvt->read_impl.microseconds_per_packet / 1000); if (maxlen) { maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000); @@ -3178,11 +3180,11 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f tech_pvt->read_impl.samples_per_packet, tech_pvt->read_impl.samples_per_second) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), - SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", len, qlen); + SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen); switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), - SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", len, qlen); + SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen); } } @@ -6065,6 +6067,19 @@ void sofia_glue_tech_simplify(private_object_t *tech_pvt) } } +void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on) +{ + switch_core_session_message_t *msg; + msg = switch_core_session_alloc(session, sizeof(*msg)); + MESSAGE_STAMP_FFL(msg); + msg->message_id = SWITCH_MESSAGE_INDICATE_JITTER_BUFFER; + msg->string_arg = switch_core_session_strdup(session, on ? "pause" : "resume"); + msg->from = __FILE__; + + switch_core_session_queue_message(session, msg); +} + + void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl) { switch_core_session_message_t *msg; diff --git a/src/switch_channel.c b/src/switch_channel.c index e5d30ee5d5..672c47d38b 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -1261,6 +1261,24 @@ SWITCH_DECLARE(uint32_t) switch_channel_test_cap(switch_channel_t *channel, swit return channel->caps[cap] ? 1 : 0; } +SWITCH_DECLARE(uint32_t) switch_channel_test_cap_partner(switch_channel_t *channel, switch_channel_cap_t cap) +{ + const char *uuid; + int r = 0; + + switch_assert(channel != NULL); + + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) { + switch_core_session_t *session; + if ((session = switch_core_session_locate(uuid))) { + r = switch_channel_test_cap(switch_core_session_get_channel(session), cap); + switch_core_session_rwunlock(session); + } + } + + return r; +} + SWITCH_DECLARE(char *) switch_channel_get_flag_string(switch_channel_t *channel) { switch_stream_handle_t stream = { 0 }; diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 7448125788..6f84de3893 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -1142,7 +1142,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) || switch_channel_test_flag(peer_channel, CF_RING_READY)) { const char *app, *data; - + switch_channel_set_state(peer_channel, CS_CONSUME_MEDIA); if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) { diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 73c2f45009..41d5fc98dd 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -242,6 +242,7 @@ struct switch_rtp { switch_time_t send_time; switch_byte_t auto_adj_used; + uint8_t pause_jb; }; struct switch_rtcp_senderinfo { @@ -1640,6 +1641,26 @@ static void jb_callback(stfu_instance_t *i, void *udata) } +SWITCH_DECLARE(switch_status_t) switch_rtp_pause_jitter_buffer(switch_rtp_t *rtp_session, switch_bool_t pause) +{ + + if (!switch_rtp_ready(rtp_session) || !rtp_session->jb) { + return SWITCH_STATUS_FALSE; + } + + if (!!pause == !!rtp_session->pause_jb) { + return SWITCH_STATUS_FALSE; + } + + if (rtp_session->pause_jb && !pause) { + stfu_n_reset(rtp_session->jb); + } + + rtp_session->pause_jb = pause ? 1 : 0; + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t *rtp_session) { @@ -2174,7 +2195,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t ts = ntohl(rtp_session->recv_msg.header.ts); if (*bytes && (!rtp_session->recv_te || rtp_session->recv_msg.header.pt != rtp_session->recv_te) && - ts && !rtp_session->jb && ts == rtp_session->last_cng_ts) { + ts && !rtp_session->jb && !rtp_session->pause_jb && ts == rtp_session->last_cng_ts) { /* we already sent this frame..... */ *bytes = 0; return SWITCH_STATUS_SUCCESS; @@ -2204,7 +2225,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t rtp_session->last_read_ts = ts; - if (rtp_session->jb && rtp_session->recv_msg.header.version == 2 && *bytes) { + if (rtp_session->jb && !rtp_session->pause_jb && rtp_session->recv_msg.header.version == 2 && *bytes) { if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO) && !(rtp_session->rtp_bugs & RTP_BUG_IGNORE_MARK_BIT)) { stfu_n_reset(rtp_session->jb); @@ -2217,7 +2238,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t status = SWITCH_STATUS_FALSE; } - if (rtp_session->jb && !rtp_session->checked_jb) { + if (rtp_session->jb && !rtp_session->pause_jb && !rtp_session->checked_jb) { if ((jb_frame = stfu_n_read_a_frame(rtp_session->jb))) { memcpy(rtp_session->recv_msg.body, jb_frame->data, jb_frame->dlen);