[asterisk-commits] mjordan: branch 11 r382573 - /branches/11/res/res_rtp_asterisk.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Mar 7 08:58:26 CST 2013


Author: mjordan
Date: Thu Mar  7 08:58:23 2013
New Revision: 382573

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382573
Log:
Add a 'secret' probation strictrtp mode to handle delayed changes in RTP source

Often, Asterisk may realize that a change in the source of an RTP stream is
about to occur and ask that the RTP engine reset it's lock on the current RTP
source. In certain scenarios, it may take awhile for the new remote system to
send RTP packets, while the old remote system may continue providing RTP during
that time period. This causes Asterisk to re-lock onto the old source, thereby
rejecting the new source when the old source stops sending RTP and the new
source begins.

This patch prevents that by having a constant secondary, 'secret' probation
mode enabled when an RTP source has been chosen. RTP packets from other sources
are always considered, but never chosen unless the current RTP source stops
sending RTP.

Review: https://reviewboard.asterisk.org/r/2364

(closes issue AST-1124)
Reported by: John Bigelow
Tested by: John Bigelow

(closes issue AST-1125)
Reported by: John Bigelow
Tested by: John Bigelow


Modified:
    branches/11/res/res_rtp_asterisk.c

Modified: branches/11/res/res_rtp_asterisk.c
URL: http://svnview.digium.com/svn/asterisk/branches/11/res/res_rtp_asterisk.c?view=diff&rev=382573&r1=382572&r2=382573
==============================================================================
--- branches/11/res/res_rtp_asterisk.c (original)
+++ branches/11/res/res_rtp_asterisk.c Thu Mar  7 08:58:23 2013
@@ -172,6 +172,12 @@
 
 #define COMPONENT_RTP 1
 #define COMPONENT_RTCP 2
+
+/*! \brief RTP learning mode tracking information */
+struct rtp_learning_info {
+	int max_seq;	/*!< The highest sequence number received */
+	int packets;	/*!< The number of remaining packets before the source is accepted */
+};
 
 /*! \brief RTP session description */
 struct ast_rtp {
@@ -243,8 +249,8 @@
 	 * Learning mode values based on pjmedia's probation mode.  Many of these values are redundant to the above,
 	 * but these are in place to keep learning mode sequence values sealed from their normal counterparts.
 	 */
-	uint16_t learning_max_seq;		/*!< Highest sequence number heard */
-	int learning_probation;		/*!< Sequential packets untill source is valid */
+	struct rtp_learning_info rtp_source_learn;	/* Learning mode track for the expected RTP source */
+	struct rtp_learning_info alt_source_learn;	/* Learning mode tracking for a new RTP source after one has been chosen */
 
 	struct rtp_red *red;
 
@@ -1024,7 +1030,7 @@
 #endif
 };
 
-static void rtp_learning_seq_init(struct ast_rtp *rtp, uint16_t seq);
+static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq);
 
 static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
 {
@@ -1035,7 +1041,7 @@
 	}
 
 	rtp->strict_rtp_state = STRICT_RTP_LEARN;
-	rtp_learning_seq_init(rtp, (uint16_t)rtp->seqno);
+	rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno);
 }
 
 static void ast_rtp_on_ice_rx_data(pj_ice_sess *ice, unsigned comp_id, unsigned transport_id, void *pkt, pj_size_t size, const pj_sockaddr_t *src_addr, unsigned src_addr_len)
@@ -1595,13 +1601,13 @@
  * \brief Initializes sequence values and probation for learning mode.
  * \note This is an adaptation of pjmedia's pjmedia_rtp_seq_init function.
  *
- * \param rtp pointer to rtp struct used with the received rtp packet.
- * \param seq sequence number read from the rtp header
+ * \param info The learning information to track
+ * \param seq sequence number read from the rtp header to initialize the information with
  */
-static void rtp_learning_seq_init(struct ast_rtp *rtp, uint16_t seq)
-{
-	rtp->learning_max_seq = seq - 1;
-	rtp->learning_probation = learning_min_sequential;
+static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq)
+{
+	info->max_seq = seq - 1;
+	info->packets = learning_min_sequential;
 }
 
 /*!
@@ -1609,29 +1615,23 @@
  * \brief Updates sequence information for learning mode and determines if probation/learning mode should remain in effect.
  * \note This function was adapted from pjmedia's pjmedia_rtp_seq_update function.
  *
- * \param rtp pointer to rtp struct used with the received rtp packet.
+ * \param info Structure tracking the learning progress of some address
  * \param seq sequence number read from the rtp header
- * \return boolean value indicating if probation mode is active at the end of the function
+ * \retval 0 if probation mode should exit for this address
+ * \retval non-zero if probation mode should continue
  */
-static int rtp_learning_rtp_seq_update(struct ast_rtp *rtp, uint16_t seq)
-{
-	int probation = 1;
-
-	ast_debug(1, "%p -- probation = %d, seq = %d\n", rtp, rtp->learning_probation, seq);
-
-	if (seq == rtp->learning_max_seq + 1) {
+static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq)
+{
+	if (seq == info->max_seq + 1) {
 		/* packet is in sequence */
-		rtp->learning_probation--;
-		rtp->learning_max_seq = seq;
-		if (rtp->learning_probation == 0) {
-			probation = 0;
-		}
+		info->packets--;
 	} else {
-		rtp->learning_probation = learning_min_sequential - 1;
-		rtp->learning_max_seq = seq;
-	}
-
-	return probation;
+		/* Sequence discontinuity; reset */
+		info->packets = learning_min_sequential - 1;
+	}
+	info->max_seq = seq;
+
+	return (info->packets == 0);
 }
 
 static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_sockaddr *addr, int port, int component,
@@ -1722,7 +1722,8 @@
 	rtp->seqno = ast_random() & 0xffff;
 	rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
 	if (strictrtp) {
-		rtp_learning_seq_init(rtp, (uint16_t)rtp->seqno);
+		rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno);
+		rtp_learning_seq_init(&rtp->alt_source_learn, (uint16_t)rtp->seqno);
 	}
 
 	/* Create a new socket for us to listen on and use */
@@ -3514,33 +3515,42 @@
 
 	/* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */
 	if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {
-		ast_debug(1, "%p -- start learning mode pass with addr = %s\n", rtp, ast_sockaddr_stringify(&addr));
+		ast_debug(1, "%p -- Probation learning mode pass with source address %s\n", rtp, ast_sockaddr_stringify(&addr));
 		/* For now, we always copy the address. */
 		ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
 
 		/* Send the rtp and the seqno from header to rtp_learning_rtp_seq_update to see whether we can exit or not*/
-		if (rtp_learning_rtp_seq_update(rtp, ntohl(rtpheader[0]))) {
-			ast_debug(1, "%p -- Condition for learning hasn't exited, so reject the frame.\n", rtp);
+		if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {
+			ast_debug(1, "%p -- Probation at seq %d with %d to go; discarding frame\n",
+				rtp, rtp->rtp_source_learn.max_seq, rtp->rtp_source_learn.packets);
 			return &ast_null_frame;
 		}
 
-		ast_debug(1, "%p -- Probation Ended. Set strict_rtp_state to STRICT_RTP_CLOSED with address %s\n", rtp, ast_sockaddr_stringify(&addr));
+		ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));
 		rtp->strict_rtp_state = STRICT_RTP_CLOSED;
-	} else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
-		if (ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
-			/* Hmm, not the strict addres. Perhaps we're getting audio from the alternate? */
+	}
+	if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
+		if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
+			/* Always reset the alternate learning source */
+			rtp_learning_seq_init(&rtp->alt_source_learn, seqno);
+		} else {
+			/* Hmm, not the strict address. Perhaps we're getting audio from the alternate? */
 			if (!ast_sockaddr_cmp(&rtp->alt_rtp_address, &addr)) {
 				/* ooh, we did! You're now the new expected address, son! */
 				ast_sockaddr_copy(&rtp->strict_rtp_address,
 						  &addr);
-			} else  {
-				const char *real_addr = ast_strdupa(ast_sockaddr_stringify(&addr));
-				const char *expected_addr = ast_strdupa(ast_sockaddr_stringify(&rtp->strict_rtp_address));
-
-				ast_debug(1, "Received RTP packet from %s, dropping due to strict RTP protection. Expected it to be from %s\n",
-						real_addr, expected_addr);
-
-				return &ast_null_frame;
+			} else {
+				/* Start trying to learn from the new address. If we pass a probationary period with
+				 * it, that means we've stopped getting RTP from the original source and we should
+				 * switch to it.
+				 */
+				if (rtp_learning_rtp_seq_update(&rtp->alt_source_learn, seqno)) {
+					ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n",
+							rtp, ast_sockaddr_stringify(&addr), rtp->alt_source_learn.packets);
+					return &ast_null_frame;
+				}
+				ast_verb(4, "%p -- Switching RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));
+				ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
 			}
 		}
 	}
@@ -3920,7 +3930,7 @@
 
 	if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN) {
 		rtp->strict_rtp_state = STRICT_RTP_LEARN;
-		rtp_learning_seq_init(rtp, rtp->seqno);
+		rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno);
 	}
 
 	return;




More information about the asterisk-commits mailing list