Index: chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.591
diff -u -r1.591 chan_sip.c
--- chan_sip.c	13 Dec 2004 15:26:26 -0000	1.591
+++ chan_sip.c	14 Dec 2004 18:07:46 -0000
@@ -151,6 +151,8 @@
 
 static int global_rtpholdtimeout = 0;
 
+static int global_rtpkeepalive = 0;
+
 static int global_trustrpid = 0;	/* Trust RPID headers? Default off. */
 
 static int global_progressinband = 0;
@@ -345,8 +347,10 @@
 	int initid;				/* Auto-congest ID if appropriate */
 	int autokillid;				/* Auto-kill ID */
 	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 */
 
 	int subscribed;				/* Is this call a subscription?  */
     	int stateid;
@@ -452,6 +456,7 @@
 	int capability;			/* Codec capability */
 	int rtptimeout;
 	int rtpholdtimeout;
+	int rtpkeepalive;
 	int insecure;			/* Do we want to authenticate this peer? */
 #ifdef OSP_SUPPORT
 	int ospauth;			/* Allow OSP Authentication */
@@ -1809,6 +1814,7 @@
 					transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, 0);
 					p->progress = 1;
 				}
+				time(&p->lastrtptx);
 				res =  ast_rtp_write(p->rtp, frame);
 			}
 			ast_mutex_unlock(&p->lock);
@@ -1821,6 +1827,7 @@
 					transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, 0);
 					p->progress = 1;
 				}
+				time(&p->lastrtptx);
 				res =  ast_rtp_write(p->vrtp, frame);
 			}
 			ast_mutex_unlock(&p->lock);
@@ -2328,6 +2335,7 @@
 #endif
 	p->rtptimeout = global_rtptimeout;
 	p->rtpholdtimeout = global_rtpholdtimeout;
+	p->rtpkeepalive = global_rtpkeepalive;
 	p->capability = global_capability;
 	if (p->dtmfmode & SIP_DTMF_RFC2833)
 		p->noncodeccapability |= AST_RTP_DTMF;
@@ -2618,6 +2626,7 @@
 
 	/* Update our last rtprx when we receive an SDP, too */
 	time(&p->lastrtprx);
+	time(&p->lastrtptx);
 
 	/* Get codec and RTP info from SDP */
 	if (strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
@@ -3491,6 +3500,7 @@
 	}
 	/* Update lastrtprx when we send our SDP */
 	time(&p->lastrtprx);
+	time(&p->lastrtptx);
 	return 0;
 }
 
@@ -7909,6 +7919,19 @@
 	int lastpeernum = -1;
 	int curpeernum;
 	int reloading;
+	struct ast_frame f = { AST_FRAME_NULL };
+	char rtpdata[10];
+
+	/* Create an empty voice frame for keepalive */
+	memset(rtpdata, 255, 10);
+	f.frametype = AST_FRAME_VOICE;
+	f.subclass = AST_RTP_CN;
+	f.data = rtpdata;
+	f.datalen = 10;
+	f.samples = 10;
+	f.offset = AST_FRIENDLY_OFFSET;
+	f.mallocd = 0;
+	f.src = "RTPKeepAlive";
 
 	/* Add an I/O event to our UDP socket */
 	if (sipsock > -1) 
@@ -7935,8 +7958,13 @@
 		sip = iflist;
 		while(sip) {
 			ast_mutex_lock(&sip->lock);
-			if (sip->rtp && sip->owner && (sip->owner->_state == AST_STATE_UP) && sip->lastrtprx && (sip->rtptimeout || sip->rtpholdtimeout) && !sip->redirip.sin_addr.s_addr) {
-				if (t > sip->lastrtprx + sip->rtptimeout) {
+			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 */
+					time(&sip->lastrtptx);
+					ast_rtp_write(sip->rtp, &f);
+				}
+				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);
@@ -8443,6 +8471,7 @@
 	peer->nat = global_nat;
 	peer->rtptimeout = global_rtptimeout;
 	peer->rtpholdtimeout = global_rtpholdtimeout;
+	peer->rtpkeepalive = global_rtpkeepalive;
 	peer->selfdestruct = 1;
 	peer->dynamic = 1;
 	peer->trustrpid = global_trustrpid;
@@ -8520,6 +8549,7 @@
 		peer->canreinvite = global_canreinvite;
 		peer->rtptimeout = global_rtptimeout;
 		peer->rtpholdtimeout = global_rtpholdtimeout;
+		peer->rtpkeepalive = global_rtpkeepalive;
 		peer->dtmfmode = global_dtmfmode;
 		peer->promiscredir = global_promiscredir;
 		peer->trustrpid = global_trustrpid;
@@ -8659,6 +8689,11 @@
 					ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d.  Using default.\n", v->value, v->lineno);
 					peer->rtpholdtimeout = global_rtpholdtimeout;
 				}
+			} else if (!strcasecmp(v->name, "rtpkeepalive")) {
+				if ((sscanf(v->value, "%d", &peer->rtpkeepalive) != 1) || (peer->rtpkeepalive < 0)) {
+					ast_log(LOG_WARNING, "'%s' is not a valid RTP keepalive time at line %d.  Using default.\n", v->value, v->lineno);
+					peer->rtpkeepalive = global_rtpkeepalive;
+				}
 			} else if (!strcasecmp(v->name, "qualify")) {
 				if (!strcasecmp(v->value, "no")) {
 					peer->maxms = 0;
@@ -8762,6 +8797,7 @@
 	ourport = DEFAULT_SIP_PORT;
 	global_rtptimeout = 0;
 	global_rtpholdtimeout = 0;
+	global_rtpkeepalive = 0;
 	pedanticsipchecking = 0;
 	global_dtmfmode = SIP_DTMF_RFC2833;
 	global_promiscredir = 0;
@@ -8823,6 +8859,11 @@
 				ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d.  Using default.\n", v->value, v->lineno);
 				global_rtpholdtimeout = 0;
 			}
+		} else if (!strcasecmp(v->name, "rtpkeepalive")) {
+			if ((sscanf(v->value, "%d", &global_rtpkeepalive) != 1) || (global_rtpkeepalive < 0)) {
+				ast_log(LOG_WARNING, "'%s' is not a valid RTP keepalive time at line %d.  Using default.\n", v->value, v->lineno);
+				global_rtpkeepalive = 0;
+			}
 		} else if (!strcasecmp(v->name, "videosupport")) {
 			videosupport = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "compactheaders")) {
@@ -9096,6 +9137,7 @@
 		}
 		/* Reset lastrtprx timer */
 		time(&p->lastrtprx);
+		time(&p->lastrtptx);
 		ast_mutex_unlock(&p->lock);
 		return 0;
 	}
