]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
chan_psip, res_pjsip_sdp_rtp: ignore rtptimeout if direct-media is active
authorMichael Neuhauser <mike@firmix.at>
Fri, 6 Mar 2020 16:50:00 +0000 (17:50 +0100)
committerGeorge Joseph <gjoseph@digium.com>
Fri, 20 Mar 2020 15:17:00 +0000 (10:17 -0500)
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

channels/chan_pjsip.c
res/res_pjsip_sdp_rtp.c

index 0466fd3ded3f6b3335a7c46ca9715e16065ffb0d..33c023de9bbf23e36e606026e5a6be4591ddae1f 100644 (file)
@@ -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));
                }
index b0a918813122049d8fe6a4848199d82577255500..018074c57516c440addac7638f5b20c84cf0e742 100644 (file)
@@ -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;