From b23d88758647098aa3db9cd3ca602f38515b3f65 Mon Sep 17 00:00:00 2001 From: Brian West Date: Wed, 13 Feb 2019 17:48:54 -0600 Subject: [PATCH] FS-11654: [core] add media_timeout, media_hold_timeout and video vs audio variants --- src/include/switch_rtp.h | 1 + .../mod_conference/conference_utils.c | 9 ++ src/mod/endpoints/mod_sofia/sofia.c | 4 + src/switch_core_media.c | 104 +++++++++++++++++- src/switch_rtp.c | 75 ++++++++++++- 5 files changed, 184 insertions(+), 9 deletions(-) diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 12f0626ccf..f9d116a672 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -278,6 +278,7 @@ SWITCH_DECLARE(char *) switch_rtp_get_remote_host(switch_rtp_t *rtp_session); SWITCH_DECLARE(switch_port_t) switch_rtp_get_remote_port(switch_rtp_t *rtp_session); SWITCH_DECLARE(void) switch_rtp_reset_media_timer(switch_rtp_t *rtp_session); SWITCH_DECLARE(void) switch_rtp_set_max_missed_packets(switch_rtp_t *rtp_session, uint32_t max); +SWITCH_DECLARE(void) switch_rtp_set_media_timeout(switch_rtp_t *rtp_session, uint32_t ms); SWITCH_DECLARE(switch_status_t) switch_rtp_udptl_mode(switch_rtp_t *rtp_session); SWITCH_DECLARE(void) switch_rtp_reset(switch_rtp_t *rtp_session); diff --git a/src/mod/applications/mod_conference/conference_utils.c b/src/mod/applications/mod_conference/conference_utils.c index 22de5ce6c3..48716cc269 100644 --- a/src/mod/applications/mod_conference/conference_utils.c +++ b/src/mod/applications/mod_conference/conference_utils.c @@ -368,15 +368,24 @@ void conference_utils_member_set_flag_locked(conference_member_t *member, member switch_mutex_unlock(member->flag_mutex); } +static void check_cleared_flag(conference_member_t *member, member_flag_t flag) +{ + if (flag == MFLAG_RUNNING && member->session) { + switch_core_session_kill_channel(member->session, SWITCH_SIG_BREAK); + } +} + void conference_utils_member_clear_flag(conference_member_t *member, member_flag_t flag) { member->flags[flag] = 0; + check_cleared_flag(member, flag); } void conference_utils_member_clear_flag_locked(conference_member_t *member, member_flag_t flag) { switch_mutex_lock(member->flag_mutex); member->flags[flag] = 0; switch_mutex_unlock(member->flag_mutex); + check_cleared_flag(member, flag); } switch_bool_t conference_utils_member_test_flag(conference_member_t *member, member_flag_t flag) { diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index f3200328b8..b2f100a5e5 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -5195,11 +5195,15 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) int v = atoi(val); if (v >= 0) { profile->rtp_timeout_sec = v; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "rtp-timeout-sec deprecated use media_timeout variable.\n"); } } else if (!strcasecmp(var, "rtp-hold-timeout-sec") && !zstr(val)) { int v = atoi(val); if (v >= 0) { profile->rtp_hold_timeout_sec = v; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "rtp-hold-timeout-sec deprecated use media_hold_timeout variable.\n"); } } else if (!strcasecmp(var, "disable-transfer")) { if (switch_true(val)) { diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 2b026f03fd..ca4f2389ba 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -131,6 +131,8 @@ typedef struct switch_rtp_engine_s { uint8_t codec_reinvites; uint32_t max_missed_packets; uint32_t max_missed_hold_packets; + uint32_t media_timeout; + uint32_t media_hold_timeout; uint32_t ssrc; uint32_t remote_ssrc; switch_port_t remote_rtcp_port; @@ -2815,6 +2817,45 @@ static void *get_rtt_payload(void *data, switch_size_t datalen, switch_payload_t } //? + +static void check_media_timeout_params(switch_core_session_t *session, switch_rtp_engine_t *engine) +{ + switch_media_type_t type = engine->type; + const char *val; + + if ((val = switch_channel_get_variable(session->channel, "media_hold_timeout"))) { + engine->media_hold_timeout = atoi(val); + } + + if ((val = switch_channel_get_variable(session->channel, "media_timeout"))) { + engine->media_timeout = atoi(val); + } + + if (type == SWITCH_MEDIA_TYPE_VIDEO) { + if ((val = switch_channel_get_variable(session->channel, "media_hold_timeout_video"))) { + engine->media_hold_timeout = atoi(val); + } + + if ((val = switch_channel_get_variable(session->channel, "media_timeout_video"))) { + engine->media_timeout = atoi(val); + } + } else { + + if ((val = switch_channel_get_variable(session->channel, "media_hold_timeout_audio"))) { + engine->media_hold_timeout = atoi(val); + } + + if ((val = switch_channel_get_variable(session->channel, "media_timeout_audio"))) { + engine->media_timeout = atoi(val); + } + } + + if (switch_rtp_ready(engine->rtp_session) && engine->media_timeout) { + switch_rtp_set_media_timeout(engine->rtp_session, engine->media_timeout); + } + +} + SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id, switch_media_type_t type) { @@ -2924,9 +2965,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session engine->reset_codec = 0; if (switch_rtp_ready(engine->rtp_session)) { + + check_media_timeout_params(session, engine); + if (type == SWITCH_MEDIA_TYPE_VIDEO) { switch_core_media_set_video_codec(session, 1); } else { + if (switch_core_media_set_codec(session, 1, smh->mparams->codec_flags) != SWITCH_STATUS_SUCCESS) { *frame = NULL; switch_goto_status(SWITCH_STATUS_GENERR, end); @@ -2937,6 +2982,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session if ((val = switch_channel_get_variable(session->channel, "rtp_timeout_sec"))) { int v = atoi(val); if (v >= 0) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "rtp_timeout_sec deprecated use media_timeout variable.\n"); rtp_timeout_sec = v; } } @@ -2944,6 +2991,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session if ((val = switch_channel_get_variable(session->channel, "rtp_hold_timeout_sec"))) { int v = atoi(val); if (v >= 0) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "rtp_hold_timeout_sec deprecated use media_timeout variable.\n"); rtp_hold_timeout_sec = v; } } @@ -5300,11 +5349,17 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch_channel_set_variable(session->channel, "media_audio_mode", "sendonly"); recvonly = 1; + a_engine->media_timeout = 0; + a_engine->media_hold_timeout = 0; + if (switch_rtp_ready(a_engine->rtp_session)) { switch_rtp_set_max_missed_packets(a_engine->rtp_session, 0); a_engine->max_missed_hold_packets = 0; a_engine->max_missed_packets = 0; + switch_rtp_set_media_timeout(a_engine->rtp_session, a_engine->media_timeout); } else { + switch_channel_set_variable(session->channel, "media_timeout_audio", "0"); + switch_channel_set_variable(session->channel, "media_hold_timeout_audio", "0"); switch_channel_set_variable(session->channel, "rtp_timeout_sec", "0"); switch_channel_set_variable(session->channel, "rtp_hold_timeout_sec", "0"); } @@ -6483,6 +6538,15 @@ SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_hold_packets); } + if (a_engine->media_hold_timeout) { + switch_rtp_set_media_timeout(a_engine->rtp_session, a_engine->media_hold_timeout); + } + + if (v_engine->media_hold_timeout) { + switch_rtp_set_media_timeout(v_engine->rtp_session, v_engine->media_hold_timeout); + } + + if (!(stream = switch_channel_get_hold_music(session->channel))) { stream = "local_stream://moh"; } @@ -6543,9 +6607,24 @@ SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session switch_ivr_bg_media(switch_core_session_get_uuid(session), SMF_REBRIDGE, SWITCH_FALSE, SWITCH_TRUE, 200); } - if (a_engine->max_missed_packets && a_engine->rtp_session) { + if (a_engine->rtp_session) { switch_rtp_reset_media_timer(a_engine->rtp_session); - switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_packets); + + if (a_engine->max_missed_packets) { + switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_packets); + } + + if (a_engine->media_hold_timeout) { + switch_rtp_set_media_timeout(a_engine->rtp_session, a_engine->media_timeout); + } + } + + if (v_engine->rtp_session) { + switch_rtp_reset_media_timer(v_engine->rtp_session); + + if (v_engine->media_hold_timeout) { + switch_rtp_set_media_timeout(v_engine->rtp_session, v_engine->media_timeout); + } } if (b_channel) { @@ -8469,6 +8548,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi if (switch_rtp_ready(a_engine->rtp_session)) { switch_rtp_reset_media_timer(a_engine->rtp_session); + check_media_timeout_params(session, a_engine); + check_media_timeout_params(session, v_engine); } if (a_engine->crypto_type != CRYPTO_INVALID) { @@ -8702,6 +8783,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi switch_rtp_set_remote_ssrc(a_engine->rtp_session, a_engine->remote_ssrc); } + check_media_timeout_params(session, a_engine); + switch_channel_set_flag(session->channel, CF_FS_RTP); switch_channel_set_variable_printf(session->channel, "rtp_use_pt", "%d", a_engine->cur_payload_map->pt); @@ -8855,6 +8938,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi if ((val = switch_channel_get_variable(session->channel, "rtp_timeout_sec"))) { int v = atoi(val); if (v >= 0) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "rtp_timeout_sec deprecated use media_timeout variable.\n"); smh->mparams->rtp_timeout_sec = v; } } @@ -8862,6 +8947,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi if ((val = switch_channel_get_variable(session->channel, "rtp_hold_timeout_sec"))) { int v = atoi(val); if (v >= 0) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "rtp_hold_timeout_sec deprecated use media_hold_timeout variable.\n"); smh->mparams->rtp_hold_timeout_sec = v; } } @@ -9450,6 +9537,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi switch_rtp_set_remote_ssrc(v_engine->rtp_session, v_engine->remote_ssrc); } + check_media_timeout_params(session, v_engine); + if (v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].ready) { gen_ice(session, SWITCH_MEDIA_TYPE_VIDEO, NULL, 0); @@ -12432,6 +12521,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se { if (a_engine && a_engine->rtp_session) { switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_hold_packets); + switch_rtp_set_media_timeout(a_engine->rtp_session, a_engine->media_hold_timeout); + } + + if (v_engine && v_engine->rtp_session) { + switch_rtp_set_media_timeout(v_engine->rtp_session, v_engine->media_hold_timeout); } } break; @@ -12440,6 +12534,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se { if (a_engine && a_engine->rtp_session) { switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_packets); + switch_rtp_set_media_timeout(a_engine->rtp_session, a_engine->media_timeout); + } + + if (v_engine && v_engine->rtp_session) { + switch_rtp_set_media_timeout(v_engine->rtp_session, v_engine->media_timeout); } } break; @@ -16135,4 +16234,3 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess * For VIM: * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: */ - diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 2b06c448d4..e4ae3a329b 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -435,6 +435,8 @@ struct switch_rtp { switch_jb_t *vbw; uint32_t max_missed_packets; uint32_t missed_count; + switch_time_t last_media; + uint32_t media_timeout; rtp_msg_t write_msg; switch_rtp_crypto_key_t *crypto_keys[SWITCH_RTP_CRYPTO_MAX]; int reading; @@ -2869,6 +2871,18 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s return status; } +SWITCH_DECLARE(void) switch_rtp_set_media_timeout(switch_rtp_t *rtp_session, uint32_t ms) +{ + if (!switch_rtp_ready(rtp_session) || rtp_session->flags[SWITCH_RTP_FLAG_UDPTL]) { + return; + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, + "%s MEDIA TIMEOUT %s set to %u", switch_core_session_get_name(rtp_session->session), rtp_type(rtp_session), ms); + rtp_session->media_timeout = ms; + switch_rtp_reset_media_timer(rtp_session); +} + SWITCH_DECLARE(void) switch_rtp_set_max_missed_packets(switch_rtp_t *rtp_session, uint32_t max) { if (!switch_rtp_ready(rtp_session) || rtp_session->flags[SWITCH_RTP_FLAG_UDPTL]) { @@ -2937,6 +2951,7 @@ SWITCH_DECLARE(void) switch_rtp_reset(switch_rtp_t *rtp_session) SWITCH_DECLARE(void) switch_rtp_reset_media_timer(switch_rtp_t *rtp_session) { rtp_session->missed_count = 0; + rtp_session->last_media = switch_micro_time_now(); } SWITCH_DECLARE(char *) switch_rtp_get_remote_host(switch_rtp_t *rtp_session) @@ -5632,6 +5647,10 @@ static switch_size_t do_flush(switch_rtp_t *rtp_session, int force, switch_size_ if (bytes) { int do_cng = 0; + if (rtp_session->media_timeout) { + rtp_session->last_media = switch_micro_time_now(); + } + /* Make sure to handle RFC2833 packets, even if we're flushing the packets */ if (bytes > rtp_header_len && rtp_session->recv_msg.header.version == 2 && rtp_session->recv_msg.header.pt == rtp_session->recv_te) { rtp_session->last_rtp_hdr = rtp_session->recv_msg.header; @@ -5803,6 +5822,10 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t /* version 2 probably rtp, zrtp cookie present means zrtp */ rtp_session->has_rtp = (rtp_session->recv_msg.header.version == 2 || ntohl(*(int *)(b+4)) == ZRTP_MAGIC_COOKIE); + if (rtp_session->media_timeout) { + rtp_session->last_media = switch_micro_time_now(); + } + if ((*b >= 20) && (*b <= 64)) { if (rtp_session->dtls) { rtp_session->dtls->bytes = *bytes; @@ -7087,6 +7110,31 @@ static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t return status; } +static void check_timeout(switch_rtp_t *rtp_session) +{ + + switch_time_t now = switch_micro_time_now(); + uint32_t elapsed = 0; + + if (now >= rtp_session->last_media) { + elapsed = (now - rtp_session->last_media) / 1000; + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG10, + "%s MEDIA TIMEOUT %s %d/%d", switch_core_session_get_name(rtp_session->session), rtp_type(rtp_session), + elapsed, rtp_session->media_timeout); + + if (elapsed > rtp_session->media_timeout) { + + if (rtp_session->session) { + switch_channel_t *channel = switch_core_session_get_channel(rtp_session->session); + + switch_channel_execute_on(channel, "execute_on_media_timeout"); + switch_channel_hangup(channel, SWITCH_CAUSE_MEDIA_TIMEOUT); + } + } +} + static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type, payload_map_t **pmapP, switch_frame_flag_t *flags, switch_io_flag_t io_flags) { @@ -7293,6 +7341,10 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, pt); + if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && poll_status != SWITCH_STATUS_SUCCESS && rtp_session->media_timeout && rtp_session->last_media) { + check_timeout(rtp_session); + } + if (!rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && rtp_session->dtmf_data.out_digit_dur > 0) { return_cng_frame(); } @@ -7332,9 +7384,15 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ !rtp_session->flags[SWITCH_RTP_FLAG_UDPTL]) { if (bytes && status == SWITCH_STATUS_SUCCESS) { rtp_session->missed_count = 0; - } else if (++rtp_session->missed_count >= rtp_session->max_missed_packets) { - ret = -2; - goto end; + } else { + if (rtp_session->media_timeout && rtp_session->last_media) { + check_timeout(rtp_session); + } else { + if (++rtp_session->missed_count >= rtp_session->max_missed_packets) { + ret = -2; + goto end; + } + } } } @@ -7385,7 +7443,9 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ rtp_session->missed_count += (poll_sec * 1000) / (rtp_session->ms_per_packet ? rtp_session->ms_per_packet / 1000 : 20); bytes = 0; - if (rtp_session->max_missed_packets) { + if (rtp_session->media_timeout && rtp_session->last_media) { + check_timeout(rtp_session); + } else if (rtp_session->max_missed_packets) { if (rtp_session->missed_count >= rtp_session->max_missed_packets) { ret = -2; goto end; @@ -7743,7 +7803,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ result_continue: timer_check: - if (rtp_session->flags[SWITCH_RTP_FLAG_MUTE]) { + if (!rtp_session->media_timeout && rtp_session->flags[SWITCH_RTP_FLAG_MUTE]) { do_cng++; } @@ -7784,6 +7844,10 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "%s %s timeout\n", rtp_session_name(rtp_session), rtp_type(rtp_session)); + if (rtp_session->media_timeout && rtp_session->last_media) { + check_timeout(rtp_session); + } + if (rtp_session->stats.inbound.error_log) { rtp_session->stats.inbound.error_log->flaws++; } @@ -9165,4 +9229,3 @@ SWITCH_DECLARE(void *) switch_rtp_get_private(switch_rtp_t *rtp_session) * For VIM: * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: */ -