[svn-commits] oej: trunk r48200 - in /trunk: ./ channels/ configs/ include/asterisk/ main/

svn-commits at lists.digium.com svn-commits at lists.digium.com
Sat Dec 2 05:05:41 MST 2006


Author: oej
Date: Sat Dec  2 06:05:40 2006
New Revision: 48200

URL: http://svn.digium.com/view/asterisk?view=rev&rev=48200
Log:
- Disable RTP timeouts during T.38 transmission
- Encapsulate RTP timers to the RTP structure, so we have one set for video and one for audio
- Document RTP keepalive configuration option
- Cleanup and document the monitor support function to hangup on RTP timeouts
- Add RTP keepalive to SIP show settings

Imported from 1.4 with modifications for trunk.


Modified:
    trunk/   (props changed)
    trunk/channels/chan_sip.c
    trunk/configs/sip.conf.sample
    trunk/include/asterisk/rtp.h
    trunk/main/rtp.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Modified: trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_sip.c?view=diff&rev=48200&r1=48199&r2=48200
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Sat Dec  2 06:05:40 2006
@@ -961,8 +961,6 @@
 	time_t lastrtprx;			/*!< Last RTP received */
 	time_t lastrtptx;			/*!< Last RTP sent */
 	int rtptimeout;				/*!< RTP timeout time */
-	int rtpholdtimeout;			/*!< RTP timeout when on hold */
-	int rtpkeepalive;			/*!< Send RTP packets for keepalive */
 	struct sockaddr_in recv;		/*!< Received as */
 	struct in_addr ourip;			/*!< Our IP */
 	struct ast_channel *owner;		/*!< Who owns us (if we have an owner) */
@@ -2726,17 +2724,21 @@
 	if (dialog->rtp) {
 		ast_rtp_setdtmf(dialog->rtp, ast_test_flag(&dialog->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
 		ast_rtp_setdtmfcompensate(dialog->rtp, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
+		ast_rtp_set_rtptimeout(dialog->rtp, peer->rtptimeout);
+		ast_rtp_set_rtpholdtimeout(dialog->rtp, peer->rtpholdtimeout);
+		ast_rtp_set_rtpkeepalive(dialog->rtp, peer->rtpkeepalive);
+		/* Set Frame packetization */
+		ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs);
+		dialog->autoframing = peer->autoframing;
 	}
 	if (dialog->vrtp) {
 		ast_rtp_setdtmf(dialog->vrtp, 0);
 		ast_rtp_setdtmfcompensate(dialog->vrtp, 0);
-	}
-
-	/* Set Frame packetization */
-	if (dialog->rtp) {
-		ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs);
-		dialog->autoframing = peer->autoframing;
-	}
+		ast_rtp_set_rtptimeout(dialog->vrtp, peer->rtptimeout);
+		ast_rtp_set_rtpholdtimeout(dialog->vrtp, peer->rtpholdtimeout);
+		ast_rtp_set_rtpkeepalive(dialog->vrtp, peer->rtpkeepalive);
+	}
+
 	ast_string_field_set(dialog, peername, peer->username);
 	ast_string_field_set(dialog, authname, peer->username);
 	ast_string_field_set(dialog, username, peer->username);
@@ -2774,8 +2776,6 @@
 		dialog->noncodeccapability &= ~AST_RTP_DTMF;
 	ast_string_field_set(dialog, context, peer->context);
 	dialog->rtptimeout = peer->rtptimeout;
-	dialog->rtpholdtimeout = peer->rtpholdtimeout;
-	dialog->rtpkeepalive = peer->rtpkeepalive;
 	if (peer->call_limit)
 		ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
 	dialog->maxcallbitrate = peer->maxcallbitrate;
@@ -4299,16 +4299,19 @@
 		ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
 		ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
 		ast_rtp_settos(p->rtp, global_tos_audio);
+		ast_rtp_set_rtptimeout(p->rtp, global_rtptimeout);
+		ast_rtp_set_rtpholdtimeout(p->rtp, global_rtpholdtimeout);
+		ast_rtp_set_rtpkeepalive(p->rtp, global_rtpkeepalive);
 		if (p->vrtp) {
 			ast_rtp_settos(p->vrtp, global_tos_video);
 			ast_rtp_setdtmf(p->vrtp, 0);
 			ast_rtp_setdtmfcompensate(p->vrtp, 0);
+			ast_rtp_set_rtptimeout(p->vrtp, global_rtptimeout);
+			ast_rtp_set_rtpholdtimeout(p->vrtp, global_rtpholdtimeout);
+			ast_rtp_set_rtpkeepalive(p->vrtp, global_rtpkeepalive);
 		}
 		if (p->udptl)
 			ast_udptl_settos(p->udptl, global_tos_audio);
-		p->rtptimeout = global_rtptimeout;
-		p->rtpholdtimeout = global_rtpholdtimeout;
-		p->rtpkeepalive = global_rtpkeepalive;
 		p->maxcallbitrate = default_maxcallbitrate;
 	}
 
@@ -10427,6 +10430,7 @@
 	ast_cli(fd, "  T1 minimum:             %d\n", global_t1min);
 	ast_cli(fd, "  Relax DTMF:             %s\n", global_relaxdtmf ? "Yes" : "No");
 	ast_cli(fd, "  Compact SIP headers:    %s\n", compactheaders ? "Yes" : "No");
+	ast_cli(fd, "  RTP Keepalive:          %d %s\n", global_rtpkeepalive, global_rtpkeepalive ? "" : "(Disabled)" );
 	ast_cli(fd, "  RTP Timeout:            %d %s\n", global_rtptimeout, global_rtptimeout ? "" : "(Disabled)" );
 	ast_cli(fd, "  RTP Hold Timeout:       %d %s\n", global_rtpholdtimeout, global_rtpholdtimeout ? "" : "(Disabled)");
 	ast_cli(fd, "  MWI NOTIFY mime type:   %s\n", default_notifymime);
@@ -11823,6 +11827,9 @@
 				if (bridgepvt->udptl) {
 					if (p->t38.state == T38_PEER_REINVITE) {
 						sip_handle_t38_reinvite(bridgepeer, p, 0);
+						ast_rtp_set_rtptimers_onhold(p->rtp);
+						if (p->vrtp)
+							ast_rtp_set_rtptimers_onhold(p->vrtp);	/* Turn off RTP timers while we send fax */
 					} else if (p->t38.state == T38_DISABLED && bridgepeer && (bridgepvt->t38.state == T38_ENABLED)) {
 						ast_log(LOG_WARNING, "RTP re-inivte after T38 session not handled yet !\n");
 						/* Insted of this we should somehow re-invite the other side of the bridge to RTP */
@@ -14912,52 +14919,66 @@
 
 
 /*! \brief helper function for the monitoring thread */
-static void check_rtp_timeout(struct sip_pvt *sip, time_t t)
-{
-	if (sip->rtp && sip->owner &&
-	    (sip->owner->_state == AST_STATE_UP) &&
-	    !sip->redirip.sin_addr.s_addr) {
-		if (sip->lastrtptx &&
-		    sip->rtpkeepalive &&
-		    (t > sip->lastrtptx + sip->rtpkeepalive)) {
-			/* Need to send an empty RTP packet */
-			sip->lastrtptx = time(NULL);
-			ast_rtp_sendcng(sip->rtp, 0);
-		}
-		if (sip->lastrtprx &&
-		    (sip->rtptimeout || sip->rtpholdtimeout) &&
-		    (t > sip->lastrtprx + sip->rtptimeout)) {
-			/* Might be a timeout now -- see if we're on hold */
-			struct sockaddr_in sin;
-			ast_rtp_get_peer(sip->rtp, &sin);
-			if (sin.sin_addr.s_addr || 
-			    (sip->rtpholdtimeout && 
-			     (t > sip->lastrtprx + sip->rtpholdtimeout))) {
-				/* Needs a hangup */
-				if (sip->rtptimeout) {
-					while (sip->owner && ast_channel_trylock(sip->owner)) {
-						sip_pvt_unlock(sip);
-						usleep(1);
-						sip_pvt_lock(sip);
-					}
-					if (sip->owner) {
-						if (!(ast_rtp_get_bridged(sip->rtp))) {
-							ast_log(LOG_NOTICE,
-								"Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
-								sip->owner->name,
-								(long) (t - sip->lastrtprx));
-							/* Issue a softhangup */
-							ast_softhangup_nolock(sip->owner, AST_SOFTHANGUP_DEV);
-						} else
-							ast_log(LOG_NOTICE, "'%s' will not be disconnected in %ld seconds because it is directly bridged to another RTP stream\n", sip->owner->name, (long) (t - sip->lastrtprx));
-						ast_channel_unlock(sip->owner);
-						/* forget the timeouts for this call, since a hangup
-						   has already been requested and we don't want to
-						   repeatedly request hangups
-						*/
-						sip->rtptimeout = 0;
-						sip->rtpholdtimeout = 0;
-					}
+static void check_rtp_timeout(struct sip_pvt *dialog, time_t t)
+{
+	/* If we have no RTP or no active owner, no need to check timers */
+	if (!dialog->rtp || !dialog->owner)
+		return;
+	/* If the call is not in UP state or redirected outside Asterisk, no need to check timers */
+	if (dialog->owner->_state != AST_STATE_UP || dialog->redirip.sin_addr.s_addr)
+		return;
+
+	/* If we have no timers set, return now */
+	if (ast_rtp_get_rtpkeepalive(dialog->rtp) == 0 || (ast_rtp_get_rtptimeout(dialog->rtp) == 0 && ast_rtp_get_rtpholdtimeout(dialog->rtp) == 0))
+		return;
+
+	/* Check AUDIO RTP keepalives */
+	if (dialog->lastrtptx && ast_rtp_get_rtpkeepalive(dialog->rtp) &&
+		    (t > dialog->lastrtptx + ast_rtp_get_rtpkeepalive(dialog->rtp))) {
+		/* Need to send an empty RTP packet */
+		dialog->lastrtptx = time(NULL);
+		ast_rtp_sendcng(dialog->rtp, 0);
+	}
+
+	/*! \todo Check video RTP keepalives
+
+		Do we need to move the lastrtptx to the RTP structure to have one for audio and one
+		for video? It really does belong to the RTP structure.
+	*/
+
+	/* Check AUDIO RTP timers */
+	if (dialog->lastrtprx && (ast_rtp_get_rtptimeout(dialog->rtp) || ast_rtp_get_rtpholdtimeout(dialog->rtp)) &&
+		    (t > dialog->lastrtprx + ast_rtp_get_rtptimeout(dialog->rtp))) {
+
+		/* Might be a timeout now -- see if we're on hold */
+		struct sockaddr_in sin;
+		ast_rtp_get_peer(dialog->rtp, &sin);
+		if (sin.sin_addr.s_addr || (ast_rtp_get_rtpholdtimeout(dialog->rtp) &&
+		     (t > dialog->lastrtprx + ast_rtp_get_rtpholdtimeout(dialog->rtp)))) {
+			/* Needs a hangup */
+			if (dialog->rtptimeout) {
+				while (dialog->owner && ast_channel_trylock(dialog->owner)) {
+					sip_pvt_unlock(dialog);
+					usleep(1);
+					sip_pvt_lock(dialog);
+				}
+				if (!(ast_rtp_get_bridged(dialog->rtp))) {
+					ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
+						dialog->owner->name, (long) (t - dialog->lastrtprx));
+					/* Issue a softhangup */
+					ast_softhangup_nolock(dialog->owner, AST_SOFTHANGUP_DEV);
+				} else
+					ast_log(LOG_NOTICE, "'%s' will not be disconnected in %ld seconds because it is directly bridged to another RTP stream\n", dialog->owner->name, (long) (t - dialog->lastrtprx));
+				ast_channel_unlock(dialog->owner);
+				/* forget the timeouts for this call, since a hangup
+				   has already been requested and we don't want to
+				   repeatedly request hangups
+				*/
+				ast_rtp_set_rtptimeout(dialog->rtp, 0);
+				ast_rtp_set_rtpholdtimeout(dialog->rtp, 0);
+				if (dialog->vrtp) {
+					ast_rtp_set_rtptimeout(dialog->vrtp, 0);
+					ast_rtp_set_rtpholdtimeout(dialog->vrtp, 0);
 				}
 			}
 		}
@@ -14971,7 +14992,7 @@
 static void *do_monitor(void *data)
 {
 	int res;
-	struct sip_pvt *sip;
+	struct sip_pvt *dialog;
 	struct sip_peer *peer = NULL;
 	time_t t;
 	int fastrestart = FALSE;
@@ -14999,6 +15020,7 @@
 			if (sipsock > -1)
 				sipsock_read_id = ast_io_change(io, sipsock_read_id, sipsock, NULL, 0, NULL);
 		}
+
 		/* Check for dialogs needing to be killed */
 		dialoglist_lock();
 restartsearch:		
@@ -15007,18 +15029,20 @@
 		   of time since the last time we did it (when MWI is being sent, we can
 		   get back to this point every millisecond or less)
 		*/
-		for (sip = dialoglist; !fastrestart && sip; sip = sip->next) {
-			sip_pvt_lock(sip);
+		for (dialog = dialoglist; !fastrestart && dialog; dialog = dialog->next) {
+			sip_pvt_lock(dialog);
 			/* Check RTP timeouts and kill calls if we have a timeout set and do not get RTP */
-			check_rtp_timeout(sip, t);
+			check_rtp_timeout(dialog, t);
 			/* If we have sessions that needs to be destroyed, do it now */
-			if (ast_test_flag(&sip->flags[0], SIP_NEEDDESTROY) && !sip->packets &&
-			    !sip->owner) {
-				sip_pvt_unlock(sip);
-				__sip_destroy(sip, TRUE, FALSE);
+			/* Check if we have outstanding requests not responsed to or an active call
+				- if that's the case, wait with destruction */
+			if (ast_test_flag(&dialog->flags[0], SIP_NEEDDESTROY) && !dialog->packets &&
+			    !dialog->owner) {
+				sip_pvt_unlock(dialog);
+				__sip_destroy(dialog, TRUE, FALSE);
 				goto restartsearch;
 			}
-			sip_pvt_unlock(sip);
+			sip_pvt_unlock(dialog);
 		}
 		dialoglist_unlock();
 
@@ -15027,7 +15051,8 @@
 		res = ast_sched_wait(sched);
 		if ((res < 0) || (res > 1000))
 			res = 1000;
-		/* If we might need to send more mailboxes, don't wait long at all.*/
+
+		/* If we might need to send more mailbox notifications, don't wait long at all.*/
 		if (fastrestart)
 			res = 1;
 		res = ast_io_wait(io, res);

Modified: trunk/configs/sip.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/sip.conf.sample?view=diff&rev=48200&r1=48199&r2=48200
==============================================================================
--- trunk/configs/sip.conf.sample (original)
+++ trunk/configs/sip.conf.sample Sat Dec  2 06:05:40 2006
@@ -95,12 +95,6 @@
 ;language=en			; Default language setting for all users/peers
 				; This may also be set for individual users/peers
 ;relaxdtmf=yes			; Relax dtmf handling
-;rtptimeout=60			; Terminate call if 60 seconds of no RTP or RTCP activity
-				; when we're not on hold. This is to be able to hangup
-				; a call in the case of a phone disappearing from the net,
-				; like a powerloss or grandma tripping over a cable.
-;rtpholdtimeout=300		; Terminate call if 300 seconds of no RTP or RTCP activity
-				; when we're on hold (must be > rtptimeout)
 ;trustrpid = no			; If Remote-Party-ID should be trusted
 ;sendrpid = yes			; If Remote-Party-ID should be sent
 ;progressinband=never		; If we should generate in-band ringing always
@@ -162,6 +156,21 @@
 ;
 ;regcontext=sipregistrations
 ;
+;--------------------------- RTP timers ----------------------------------------------------
+; These timers are currently used for both audio and video streams. The RTP timeouts
+; are only applied to the audio channel.
+; The settings are settable in the global section as well as per device
+;
+;rtptimeout=60			; Terminate call if 60 seconds of no RTP or RTCP activity
+				; on the audio channel
+				; when we're not on hold. This is to be able to hangup
+				; a call in the case of a phone disappearing from the net,
+				; like a powerloss or grandma tripping over a cable.
+;rtpholdtimeout=300		; Terminate call if 300 seconds of no RTP or RTCP activity
+				; on the audio channel
+				; when we're on hold (must be > rtptimeout)
+;rtpkeepalive=<secs>		; Send keepalives in the RTP stream to keep NAT open
+				; (default is off - zero)
 ;--------------------------- SIP DEBUGGING ---------------------------------------------------
 ;sipdebug = yes			; Turn on SIP debugging by default, from
 				; the moment the channel loads this configuration
@@ -206,8 +215,9 @@
 ;
 ; This setting is available in the [general] section as well as in device configurations.
 ; Setting this to yes, enables T.38 fax (UDPTL) passthrough on SIP to SIP calls, provided
-; both parties have T38 support enabled in their Asterisk configuration (either general or
-; peer/user/friend sections)
+; both parties have T38 support enabled in their Asterisk configuration 
+; This has to be enabled in the general section for all devices to work. You can then
+; disable it on a per device basis. 
 ;
 ; t38pt_udptl = yes            ; Default false
 ;

Modified: trunk/include/asterisk/rtp.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/rtp.h?view=diff&rev=48200&r1=48199&r2=48200
==============================================================================
--- trunk/include/asterisk/rtp.h (original)
+++ trunk/include/asterisk/rtp.h Sat Dec  2 06:05:40 2006
@@ -219,6 +219,21 @@
 
 int ast_rtp_codec_getformat(int pt);
 
+/*! \brief Set rtp timeout */
+void ast_rtp_set_rtptimeout(struct ast_rtp *rtp, int timeout);
+/*! \brief Set rtp hold timeout */
+void ast_rtp_set_rtpholdtimeout(struct ast_rtp *rtp, int timeout);
+/*! \brief set RTP keepalive interval */
+void ast_rtp_set_rtpkeepalive(struct ast_rtp *rtp, int period);
+/*! \brief Get RTP keepalive interval */
+int ast_rtp_get_rtpkeepalive(struct ast_rtp *rtp);
+/*! \brief Get rtp hold timeout */
+int ast_rtp_get_rtpholdtimeout(struct ast_rtp *rtp);
+/*! \brief Get rtp timeout */
+int ast_rtp_get_rtptimeout(struct ast_rtp *rtp);
+/* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
+void ast_rtp_set_rtptimers_onhold(struct ast_rtp *rtp);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: trunk/main/rtp.c
URL: http://svn.digium.com/view/asterisk/trunk/main/rtp.c?view=diff&rev=48200&r1=48199&r2=48200
==============================================================================
--- trunk/main/rtp.c (original)
+++ trunk/main/rtp.c Sat Dec  2 06:05:40 2006
@@ -128,6 +128,11 @@
 	double rxtransit;               /*!< Relative transit time for previous packet */
 	int lasttxformat;
 	int lastrxformat;
+
+	int rtptimeout;			/*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
+	int rtpholdtimeout;		/*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
+	int rtpkeepalive;		/*!< Send RTP comfort noice packets for keepalive */
+
 	/* DTMF Reception Variables */
 	char resp;
 	unsigned int lasteventendseqn;
@@ -519,6 +524,53 @@
 	* Look in RFC 3550 Section A.7 for an example*/
 	interval = rtcpinterval;
 	return interval;
+}
+
+/* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
+void ast_rtp_set_rtptimers_onhold(struct ast_rtp *rtp)
+{
+	rtp->rtptimeout = (-1) * rtp->rtptimeout;
+	rtp->rtpholdtimeout = (-1) * rtp->rtpholdtimeout;
+}
+
+/*! \brief Set rtp timeout */
+void ast_rtp_set_rtptimeout(struct ast_rtp *rtp, int timeout)
+{
+	rtp->rtptimeout = timeout;
+}
+
+/*! \brief Set rtp hold timeout */
+void ast_rtp_set_rtpholdtimeout(struct ast_rtp *rtp, int timeout)
+{
+	rtp->rtpholdtimeout = timeout;
+}
+
+/*! \brief set RTP keepalive interval */
+void ast_rtp_set_rtpkeepalive(struct ast_rtp *rtp, int period)
+{
+	rtp->rtpkeepalive = period;
+}
+
+/*! \brief Get rtp timeout */
+int ast_rtp_get_rtptimeout(struct ast_rtp *rtp)
+{
+	if (rtp->rtptimeout < 0)	/* We're not checking, but remembering the setting (during T.38 transmission) */
+		return 0;
+	return rtp->rtptimeout;
+}
+
+/*! \brief Get rtp hold timeout */
+int ast_rtp_get_rtpholdtimeout(struct ast_rtp *rtp)
+{
+	if (rtp->rtptimeout < 0)	/* We're not checking, but remembering the setting (during T.38 transmission) */
+		return 0;
+	return rtp->rtpholdtimeout;
+}
+
+/*! \brief Get RTP keepalive interval */
+int ast_rtp_get_rtpkeepalive(struct ast_rtp *rtp)
+{
+	return rtp->rtpkeepalive;
 }
 
 void ast_rtp_set_data(struct ast_rtp *rtp, void *data)



More information about the svn-commits mailing list