[Asterisk-code-review] res pjsip: Add rtp keepalive endpoint option. (asterisk[master])

Joshua Colp asteriskteam at digium.com
Mon Jul 20 15:52:38 CDT 2015


Joshua Colp has submitted this change and it was merged.

Change subject: res_pjsip: Add rtp_keepalive endpoint option.
......................................................................


res_pjsip: Add rtp_keepalive endpoint option.

This adds an "rtp_keepalive" option for PJSIP endpoints. Similar to the
chan_sip option, this specifies an interval, in seconds, at which we
will send RTP comfort noise frames. This can be useful for keeping RTP
sessions alive as well as keeping NAT associations alive during lulls.

ASTERISK-25242 #close
Reported by Mark Michelson

Change-Id: I3b9903d99e35fe5d0b53ecc46df82c750776bc8d
---
M CHANGES
A contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py
M include/asterisk/res_pjsip.h
M include/asterisk/res_pjsip_session.h
M include/asterisk/rtp_engine.h
M main/rtp_engine.c
M res/res_pjsip.c
M res/res_pjsip/pjsip_configuration.c
M res/res_pjsip_sdp_rtp.c
M res/res_pjsip_session.c
M res/res_rtp_asterisk.c
11 files changed, 122 insertions(+), 1 deletion(-)

Approvals:
  Richard Mudgett: Looks good to me, but someone else must approve
  Anonymous Coward #1000019: Verified
  Joshua Colp: Looks good to me, approved



diff --git a/CHANGES b/CHANGES
index cf37e69..53752fb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -195,6 +195,10 @@
   'yes' and g.726 audio is negotiated, forces the codec to be treated as if it
   is AAL2 packed on the channel.
 
+* A new 'rtp_keepalive' endpoint option has been added. This option specifies
+  an interval, in seconds, at which we will send RTP comfort noise packets to
+  the endpoint. This functions identically to chan_sip's "rtpkeepalive" option.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.3.0 to Asterisk 13.4.0 ------------
 ------------------------------------------------------------------------------
diff --git a/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py b/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py
new file mode 100644
index 0000000..5a4f470
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py
@@ -0,0 +1,22 @@
+"""Add RTP keepalive
+
+Revision ID: 498357a710ae
+Revises: 28b8e71e541f
+Create Date: 2015-07-10 16:42:12.244421
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '498357a710ae'
+down_revision = '28b8e71e541f'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+    op.add_column('ps_endpoints', sa.Column('rtp_keepalive', sa.Integer))
+
+
+def downgrade():
+    op.drop_column('ps_endpoints', 'rtp_keepalive')
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index f199b8f..432a168 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -502,6 +502,8 @@
 	enum ast_sip_session_media_encryption encryption;
 	/*! Do we want to optimistically support encryption if possible? */
 	unsigned int encryption_optimistic;
+	/*! Number of seconds between RTP keepalive packets */
+	unsigned int keepalive;
 };
 
 /*!
diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index 9143118..c088d03 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -77,6 +77,8 @@
 	enum ast_sip_session_media_encryption encryption;
 	/*! \brief The media transport in use for this stream */
 	pj_str_t transport;
+	/*! \brief Scheduler ID for RTP keepalive */
+	int keepalive_sched_id;
 	/*! \brief Stream is on hold by remote side */
 	unsigned int remotely_held:1;
 	/*! \brief Stream is on hold by local side */
diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h
index c7f6511..c7a7f1d 100644
--- a/include/asterisk/rtp_engine.h
+++ b/include/asterisk/rtp_engine.h
@@ -2288,6 +2288,22 @@
 		struct ast_rtp_rtcp_report *report,
 		struct ast_json *blob);
 
+/*!
+ * \brief Get the last RTP transmission time
+ *
+ * \param rtp The instance from which to get the last transmission time
+ * \return The last RTP transmission time
+ */
+time_t ast_rtp_instance_get_last_tx(const struct ast_rtp_instance *rtp);
+
+/*!
+ * \brief Set the last RTP transmission time
+ *
+ * \param rtp The instance on which to set the last transmission time
+ * \param time The last transmission time
+ */
+void ast_rtp_instance_set_last_tx(struct ast_rtp_instance *rtp, time_t time);
+
 /*! \addtogroup StasisTopicsAndMessages
  * @{
  */
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 6ae8faf..94bd813 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -190,6 +190,8 @@
 	struct ast_srtp *srtp;
 	/*! Channel unique ID */
 	char channel_uniqueid[AST_MAX_UNIQUEID];
+	/*! Time of last packet sent */
+	time_t last_tx;
 };
 
 /*! List of RTP engines that are currently registered */
@@ -2206,3 +2208,14 @@
 
 	return 0;
 }
+
+
+time_t ast_rtp_instance_get_last_tx(const struct ast_rtp_instance *rtp)
+{
+	return rtp->last_tx;
+}
+
+void ast_rtp_instance_set_last_tx(struct ast_rtp_instance *rtp, time_t time)
+{
+	rtp->last_tx = time;
+}
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 6d7e4f7..fefbff4 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -790,6 +790,14 @@
 						have this accountcode set on it.
 					</para></description>
 				</configOption>
+				<configOption name="rtp_keepalive">
+					<synopsis>Number of seconds between RTP comfort noise keepalive packets.</synopsis>
+					<description><para>
+						At the specified interval, Asterisk will send an RTP comfort noise frame. This may
+						be useful for situations where Asterisk is behind a NAT or firewall and must keep
+						a hole open in order to allow for media to arrive at Asterisk.
+					</para></description>
+				</configOption>
 			</configObject>
 			<configObject name="auth">
 				<synopsis>Authentication type</synopsis>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index d4fa152..f20b031 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1880,6 +1880,7 @@
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_use_received_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_received_transport));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_keepalive", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.rtp.keepalive));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress));
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0);
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index 22c4529..e8654a9 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -107,6 +107,39 @@
 	}
 }
 
+static int send_keepalive(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 keepalive;
+	time_t interval;
+	int send_keepalive;
+
+	if (!rtp) {
+		return 0;
+	}
+
+	keepalive = ast_rtp_instance_get_keepalive(rtp);
+
+	if (!ast_sockaddr_isnull(&session_media->direct_media_addr)) {
+		ast_debug(3, "Not sending RTP keepalive on RTP instance %p since direct media is in use\n", rtp);
+		return keepalive * 1000;
+	}
+
+	interval = time(NULL) - ast_rtp_instance_get_last_tx(rtp);
+	send_keepalive = interval >= keepalive;
+
+	ast_debug(3, "It has been %d seconds since RTP was last sent on instance %p. %sending keepalive\n",
+			(int) interval, rtp, send_keepalive ? "S" : "Not s");
+
+	if (send_keepalive) {
+		ast_rtp_instance_sendcng(rtp, 0);
+		return keepalive * 1000;
+	}
+
+	return (keepalive - interval) * 1000;
+}
+
 /*! \brief Internal function which creates an RTP instance */
 static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, unsigned int ipv6)
 {
@@ -1228,6 +1261,17 @@
 	/* This purposely resets the encryption to the configured in case it gets added later */
 	session_media->encryption = session->endpoint->media.rtp.encryption;
 
+	if (session->endpoint->media.rtp.keepalive > 0 &&
+			stream_to_media_type(session_media->stream_type) == AST_MEDIA_TYPE_AUDIO) {
+		ast_rtp_instance_set_keepalive(session_media->rtp, session->endpoint->media.rtp.keepalive);
+		/* Schedule the initial keepalive early in case this is being used to punch holes through
+		 * a NAT. This way there won't be an awkward delay before media starts flowing in some
+		 * scenarios.
+		 */
+		session_media->keepalive_sched_id = ast_sched_add_variable(sched, 500, send_keepalive,
+			session_media, 1);
+	}
+
 	return 1;
 }
 
@@ -1257,6 +1301,9 @@
 static void stream_destroy(struct ast_sip_session_media *session_media)
 {
 	if (session_media->rtp) {
+		if (session_media->keepalive_sched_id != -1) {
+			AST_SCHED_DEL(sched, session_media->keepalive_sched_id);
+		}
 		ast_rtp_instance_stop(session_media->rtp);
 		ast_rtp_instance_destroy(session_media->rtp);
 	}
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 84c343d..eaf0dc4 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1219,6 +1219,7 @@
 		return CMP_STOP;
 	}
 	session_media->encryption = session->endpoint->media.rtp.encryption;
+	session_media->keepalive_sched_id = -1;
 	/* Safe use of strcpy */
 	strcpy(session_media->stream_type, handler_list->stream_type);
 	ao2_link(session->media, session_media);
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 0a68a2d..53e9b29 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -2166,6 +2166,7 @@
 	void *temp = buf;
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
+	int res;
 
 	*ice = 0;
 
@@ -2184,7 +2185,11 @@
 	}
 #endif
 
-	return ast_sendto(rtcp ? rtp->rtcp->s : rtp->s, temp, len, flags, sa);
+	res = ast_sendto(rtcp ? rtp->rtcp->s : rtp->s, temp, len, flags, sa);
+	if (res > 0) {
+		ast_rtp_instance_set_last_tx(instance, time(NULL));
+	}
+	return res;
 }
 
 static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice)

-- 
To view, visit https://gerrit.asterisk.org/867
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I3b9903d99e35fe5d0b53ecc46df82c750776bc8d
Gerrit-PatchSet: 4
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Mark Michelson <mmichelson at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Mark Michelson <mmichelson at digium.com>
Gerrit-Reviewer: Richard Mudgett <rmudgett at digium.com>



More information about the asterisk-code-review mailing list