From: Michael Neuhauser Date: Fri, 6 Mar 2020 16:50:00 +0000 (+0100) Subject: chan_psip, res_pjsip_sdp_rtp: ignore rtptimeout if direct-media is active X-Git-Tag: 13.33.0-rc1~46 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0bd1420064261bba2a97d4befd64b09413cbcf6f;p=thirdparty%2Fasterisk.git chan_psip, res_pjsip_sdp_rtp: ignore rtptimeout if direct-media is active Do not hang up a PJSIP channel on RTP timeout if that channel is in a direct-media bridge. Also reset the time of the last received RTP packet when direct-media ends (wait full rtp_timeout period before checking first time after audio came back to Asterisk). ASTERISK-28774 Reported-by: Michael Neuhauser Change-Id: I8b62012be7685849e8fb2b1c5dd39d35313ca2d1 --- diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 0466fd3ded..33c023de9b 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -295,6 +295,14 @@ static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instan ast_sockaddr_setnull(&media->direct_media_addr); changed = 1; if (media->rtp) { + /* Direct media has ended - reset time of last received RTP packet + * to avoid premature RTP timeout. Synchronisation between the + * modification of direct_mdedia_addr+last_rx here and reading the + * values in res_pjsip_sdp_rtp.c:rtp_check_timeout() is provided + * by the channel's lock (which is held while this function is + * executed). + */ + ast_rtp_instance_set_last_rx(media->rtp, time(NULL)); ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 1); ast_channel_set_fd(chan, rtcp_fd, ast_rtp_instance_fd(media->rtp, 1)); } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index b0a9188131..018074c575 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -144,30 +144,53 @@ static int rtp_check_timeout(const void *data) struct ast_sip_session_media *session_media = (struct ast_sip_session_media *)data; struct ast_rtp_instance *rtp = session_media->rtp; int elapsed; + int timeout; struct ast_channel *chan; if (!rtp) { return 0; } - elapsed = time(NULL) - ast_rtp_instance_get_last_rx(rtp); - if (elapsed < ast_rtp_instance_get_timeout(rtp)) { - return (ast_rtp_instance_get_timeout(rtp) - elapsed) * 1000; - } - chan = ast_channel_get_by_name(ast_rtp_instance_get_channel_id(rtp)); if (!chan) { return 0; } - ast_log(LOG_NOTICE, "Disconnecting channel '%s' for lack of RTP activity in %d seconds\n", - ast_channel_name(chan), elapsed); - + /* Get channel lock to make sure that we access a consistent set of values + * (last_rx and direct_media_addr) - the lock is held when values are modified + * (see send_direct_media_request()/check_for_rtp_changes() in chan_pjsip.c). We + * are trying to avoid a situation where direct_media_addr has been reset but the + * last-rx time was not set yet. + */ ast_channel_lock(chan); - ast_channel_hangupcause_set(chan, AST_CAUSE_REQUESTED_CHAN_UNAVAIL); - ast_channel_unlock(chan); + elapsed = time(NULL) - ast_rtp_instance_get_last_rx(rtp); + timeout = ast_rtp_instance_get_timeout(rtp); + if (elapsed < timeout) { + ast_channel_unlock(chan); + ast_channel_unref(chan); + return (timeout - elapsed) * 1000; + } + + /* Last RTP packet was received too long ago + * - disconnect channel unless direct media is in use. + */ + if (!ast_sockaddr_isnull(&session_media->direct_media_addr)) { + ast_debug(3, "Not disconnecting channel '%s' for lack of %s RTP activity in %d seconds " + "since direct media is in use\n", ast_channel_name(chan), + session_media->stream_type, elapsed); + ast_channel_unlock(chan); + ast_channel_unref(chan); + return timeout * 1000; /* recheck later, direct media may have ended then */ + } + + ast_log(LOG_NOTICE, "Disconnecting channel '%s' for lack of %s RTP activity in %d seconds\n", + ast_channel_name(chan), session_media->stream_type, elapsed); + + ast_channel_hangupcause_set(chan, AST_CAUSE_REQUESTED_CHAN_UNAVAIL); ast_softhangup(chan, AST_SOFTHANGUP_DEV); + + ast_channel_unlock(chan); ast_channel_unref(chan); return 0;