[svn-commits] jdixon: branch jdixon/chan_usbradio-1.4 r133438 - /team/jdixon/chan_usbradio-...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Jul 24 08:25:51 CDT 2008


Author: jdixon
Date: Thu Jul 24 08:25:51 2008
New Revision: 133438

URL: http://svn.digium.com/view/asterisk?view=rev&rev=133438
Log:
Upgraded the rtpdir protocol

Modified:
    team/jdixon/chan_usbradio-1.4/channels/chan_rtpdir.c

Modified: team/jdixon/chan_usbradio-1.4/channels/chan_rtpdir.c
URL: http://svn.digium.com/view/asterisk/team/jdixon/chan_usbradio-1.4/channels/chan_rtpdir.c?view=diff&rev=133438&r1=133437&r2=133438
==============================================================================
--- team/jdixon/chan_usbradio-1.4/channels/chan_rtpdir.c (original)
+++ team/jdixon/chan_usbradio-1.4/channels/chan_rtpdir.c Thu Jul 24 08:25:51 2008
@@ -29,7 +29,7 @@
 /*** MODULEINFO
  ***/
 
-/* Version 0.2, 07/10/2008
+/* Version 0.5, 07/24/2008
 
 Channel connection for Asterisk to KI4LKF's RtpDir Echolink/IRLP/app_rpt
 bridging program for Amateur Radio over VOIP.
@@ -40,15 +40,31 @@
 HISPORT is the UDP socket of the RtpDir program 	 
 MYPORT (optional) is the UDP socket that Asterisk listens on for this channel 	 
 
-This protocol sends UDP packets in both directions containing 4 frames
-of 33 byte (160 sample) GSM encoded payload every 80 ms. It indicates
-the presence of signal (PTT/COR) by sending packets, and no signal by
-not sending packets. While not sending packets, it sends a "keep alive"
-packet (a 64 byte packet containing nothing important) to indicate that
-the Asterisk system is still there. The Asterisk System may receive a
-64 byte packet, but will discard it (for testing purposes). The protocol
-is connectionless and is intended to be used to emulate "nailed-up"
-facilities. 
+This protocol sends UDP packets in both directions containing a longword
+(4 byte) packet serial number plus 4 frames of 33 byte (160 sample) GSM
+encoded payload every 80 ms (totalling 136 bytes). It indicates the presence
+of signal (PTT/COR) by sending audio packets, and no signal by not sending 
+audio packets. It also sends non-audio (control packets) which are deliniated
+by the fact that they are less then 136 bytes in length (typically 64) and
+do not have a serial number. The format for the control packets is:
+
+KEEPALIVE (for a keepalive packet)
+DTMF c  (c is a DTMF DIGIT, 1 of 1234567890*#ABCD)
+TEXT some kind text
+
+While not sending audio packets, it sends a "keep alive"
+packet (a 64 byte packet containing "KEEPALIVE") to indicate that
+the Asterisk system is still there. The Asterisk System will also receive
+and handle DTMF packets and ignore all other control packets (for testing
+purposes). The protocol is connectionless and is intended to be used to
+emulate "nailed-up" facilities. 
+
+Serial numbers: On transmit, send new (incremented) serial number with each
+audio paket. On reveive, keep a copy of the last serial number from a valid
+packet. If the next thing you receive is 25 or greater away from the last, then
+reset your last to zero and start the procedure again. If its within 25 and
+greater, its a valid packet, so save the "last heard" and process it. If its
+within 25 and less, then just ignore it.
 
 [Commentary by Jim Dixon]
 Admittedly, this is by no means a fully-robust protocol. By the nature of
@@ -83,6 +99,7 @@
 #include <fcntl.h>
 #include <search.h>
 #include <sys/ioctl.h>
+#include <ctype.h>
 
 #include "asterisk/lock.h"
 #include "asterisk/channel.h"
@@ -99,6 +116,8 @@
 
 #define	BLOCKING_FACTOR 4
 #define	GSM_FRAME_SIZE 33
+#define	REALLY_WACKY_FRAMES 25
+#define	SSO sizeof(unsigned long)
 
 #define QUEUE_OVERLOAD_THRESHOLD 25
 
@@ -110,7 +129,8 @@
 static char context[AST_MAX_EXTENSION] = "default";
 static char type[] = "rtpdir";
 static char keepstr[] = 
-	"I'm a packet that contains absoultely no useful data whatsoever";
+	"KEEPALIVE I'm a packet that contains no useful data whatsoever.";
+
 /* rtpdir creates private structures on demand */
    
 struct rtpdir_rxq {
@@ -129,9 +149,13 @@
 	int rxkey;
 	int keepalive;
 	struct ast_frame fr;			/* "null" frame */
-	char txbuf[GSM_FRAME_SIZE * BLOCKING_FACTOR];
+	char txbuf[(GSM_FRAME_SIZE * BLOCKING_FACTOR) + SSO];
 	int txindex;
 	struct rtpdir_rxq rxq;
+	unsigned long rxseq;
+	unsigned long txseq;
+	unsigned long crxseq;
+	unsigned long ctxseq;
 	struct ast_module_user *u;		/*! for holding a reference to this module */
 };
 
@@ -141,6 +165,10 @@
 static struct ast_frame *rtpdir_xread(struct ast_channel *ast);
 static int rtpdir_xwrite(struct ast_channel *ast, struct ast_frame *frame);
 static int rtpdir_indicate(struct ast_channel *ast, int cond, const void *data, size_t datalen);
+static int rtpdir_digit_begin(struct ast_channel *c, char digit);
+static int rtpdir_digit_end(struct ast_channel *c, char digit, unsigned int duratiion);
+static int rtpdir_text(struct ast_channel *c, const char *text);
+
 
 static const struct ast_channel_tech rtpdir_tech = {
 	.type = type,
@@ -152,6 +180,9 @@
 	.read = rtpdir_xread,
 	.write = rtpdir_xwrite,
 	.indicate = rtpdir_indicate,
+	.send_text = rtpdir_text,
+	.send_digit_begin = rtpdir_digit_begin,
+	.send_digit_end = rtpdir_digit_end,
 };
 
 static int rtpdir_call(struct ast_channel *ast, char *dest, int timeout)
@@ -291,35 +322,55 @@
 	return 0;
 }
 
+static int rtpdir_text(struct ast_channel *ast, const char *text)
+{
+unsigned char	buf[64];
+
+	struct rtpdir_pvt *p = ast->tech_pvt;
+
+	memset(buf,0,sizeof(buf));
+	if ((strlen(text) < 1) || (strlen(text) > 59)) return -1;
+	sprintf((char *)buf,"TEXT %s",text);
+	if (sendto(p->rtpdir,buf,sizeof(buf),0,&p->si_other,sizeof(p->si_other)) == -1)
+		return -1;
+	return 0;
+}
+
+static int rtpdir_digit_begin(struct ast_channel *ast, char digit)
+{
+	return 0;
+}
+
+static int rtpdir_digit_end(struct ast_channel *ast, char digit, unsigned int duratiion)
+{
+unsigned char	buf[64];
+
+	struct rtpdir_pvt *p = ast->tech_pvt;
+
+	memset(buf,0,sizeof(buf));
+	sprintf((char *)buf,"DTMF %c",tolower(digit));
+	if (sendto(p->rtpdir,buf,sizeof(buf),0,&p->si_other,sizeof(p->si_other)) == -1)
+		return -1;
+	return 0;
+}
+
 static struct ast_frame  *rtpdir_xread(struct ast_channel *ast)
 {
+
 	struct rtpdir_pvt *p = ast->tech_pvt;
-	char buf[512];
+	char buf[512 + SSO];
 	struct sockaddr_in si_them;
 	unsigned int themlen;
-	int n,i;
+	unsigned long hseq,seq;
+ 	int n,i,d;
 	struct ast_frame fr;
-	struct rtpdir_rxq *qp;
+        struct rtpdir_rxq *qp;
 
 	themlen = sizeof(struct sockaddr_in);
 	if ((n = recvfrom(p->rtpdir,buf,sizeof(buf),0,&si_them,&themlen)) == -1)
 	{
 		ast_log(LOG_WARNING,"Cannot recvfrom()");
 		return NULL;
-	}
-	if (n < (GSM_FRAME_SIZE * BLOCKING_FACTOR))
-	{
-		p->fr.frametype = 0;
-		p->fr.subclass = 0;
-		p->fr.datalen = 0;
-		p->fr.samples = 0;
-		p->fr.data =  NULL;
-		p->fr.src = type;
-		p->fr.offset = 0;
-		p->fr.mallocd=0;
-		p->fr.delivery.tv_sec = 0;
-		p->fr.delivery.tv_usec = 0;
-		return &p->fr;
 	}
 	if (memcmp(&si_them.sin_addr,&p->si_other.sin_addr,sizeof(si_them.sin_addr)))
 	{
@@ -337,18 +388,122 @@
 		p->fr.delivery.tv_usec = 0;
 		return &p->fr;
 	}
-	for(i = 0; i < BLOCKING_FACTOR; i++)
-	{
+	if (n < 136)
+	{
+		if ((strlen(buf) >= 11) && 
+			(!strncasecmp(buf,"KEEPALIVE",9))) /* if its a keepalive */
+		{
+			p->fr.frametype = 0;
+			p->fr.subclass = 0;
+			p->fr.datalen = 0;
+			p->fr.samples = 0;
+			p->fr.data =  NULL;
+			p->fr.src = type;
+			p->fr.offset = 0;
+			p->fr.mallocd=0;
+			p->fr.delivery.tv_sec = 0;
+			p->fr.delivery.tv_usec = 0;
+			return &p->fr;
+		}
+		if ((strlen(buf) >= 6) && 
+			(!strncasecmp(buf,"DTMF",4))) /* its DTMF */
+		{
+			fr.frametype = AST_FRAME_DTMF_BEGIN;
+			fr.subclass = buf[5];
+			fr.data = 0;
+			fr.datalen = 0;
+			fr.samples = 0;
+			fr.src = type;
+			fr.offset = 0;
+			fr.mallocd=0;
+			fr.delivery.tv_sec = 0;
+			fr.delivery.tv_usec = 0;
+			ast_queue_frame(ast,ast_frdup(&fr));
+			fr.frametype = AST_FRAME_DTMF_END;
+			fr.subclass = buf[5];
+			fr.len = 50;
+			fr.data = 0;
+			fr.datalen = 0;
+			fr.samples = 0;
+			fr.src = type;
+			fr.offset = 0;
+			fr.mallocd=0;
+			fr.delivery.tv_sec = 0;
+			fr.delivery.tv_usec = 0;
+			ast_queue_frame(ast,ast_frdup(&fr));
+			p->fr.frametype = 0;
+			p->fr.subclass = 0;
+			p->fr.datalen = 0;
+			p->fr.samples = 0;
+			p->fr.data =  NULL;
+			p->fr.src = type;
+			p->fr.offset = 0;
+			p->fr.mallocd=0;
+			p->fr.delivery.tv_sec = 0;
+			p->fr.delivery.tv_usec = 0;
+			return &p->fr;
+		}
+		if ((strlen(buf) >= 6) && 
+			(!strncasecmp(buf,"TEXT",4))) /* its DTMF */
+		{
+			int l = strlen(buf);
+
+			fr.frametype = AST_FRAME_TEXT;
+			fr.subclass = 0;
+			fr.data = &buf[5];
+			fr.datalen = l - 5;
+			fr.samples = 0;
+			fr.src = type;
+			fr.offset = 0;
+			fr.mallocd=0;
+			fr.delivery.tv_sec = 0;
+			fr.delivery.tv_usec = 0;
+			return ast_frdup(&fr);
+		}
+		p->fr.frametype = 0;
+		p->fr.subclass = 0;
+		p->fr.datalen = 0;
+		p->fr.samples = 0;
+		p->fr.data =  NULL;
+		p->fr.src = type;
+		p->fr.offset = 0;
+		p->fr.mallocd=0;
+		p->fr.delivery.tv_sec = 0;
+		p->fr.delivery.tv_usec = 0;
+		return &p->fr;
+	}
+	memcpy(&hseq,buf,SSO);
+	seq = ntohl(hseq);
+
+	if (p->rxseq) d = seq - p->rxseq;
+		else d = 0;
+	if ((d < -REALLY_WACKY_FRAMES) ||
+	    (d > REALLY_WACKY_FRAMES))
+	{
+		p->rxseq = 0;
+		ast_log(LOG_NOTICE,"Rx seq no waaay off!! exp=%lu, got=%lud\n",p->rxseq,seq);
+		d = -1;
+	} 
+	else if (d < 0)
+	{
+		ast_log(LOG_NOTICE,"Rx seq no lags behind!! exp=%lu, got=%lu\n",p->rxseq,seq);
+	}
+
+	if (d >= 0)
+	{
+	    p->rxseq = seq;
+	    for(i = 0; i < BLOCKING_FACTOR; i++)
+	    {
 		qp = ast_malloc(sizeof(struct rtpdir_rxq));
 		if (!qp)
 		{
 			ast_log(LOG_NOTICE,"Cannot malloc for qp\n");
 			break;
 		}
-		memcpy(qp->buf,buf + (GSM_FRAME_SIZE * i),GSM_FRAME_SIZE);
+		memcpy(qp->buf,buf + SSO + (GSM_FRAME_SIZE * i),GSM_FRAME_SIZE);
 		insque((struct qelem *) qp,(struct qelem *) p->rxq.qe_back);
-	}
-
+	    }
+	}
 	fr.datalen = 0;
 	fr.samples = 0;
 	fr.frametype = 0;
@@ -369,8 +524,9 @@
 	struct rtpdir_pvt *p = ast->tech_pvt;
 	struct ast_frame fr;
 	struct rtpdir_rxq *qp;
-	char buf[GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET];
 	int n;
+	char buf[GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET + SSO];
+	unsigned long myseq;
 
 	if (ast->_state != AST_STATE_UP) {
 		/* Don't try tos end audio on-hook */
@@ -453,12 +609,17 @@
 	}
 	if (p->txkey || p->txindex) 
 	{
+
 		p->keepalive = KEEPALIVE_TIME;
-		memcpy(&p->txbuf[GSM_FRAME_SIZE * p->txindex++],frame->data,GSM_FRAME_SIZE);
-	}
+		memcpy(&p->txbuf[(GSM_FRAME_SIZE * p->txindex++) + SSO],
+			frame->data,GSM_FRAME_SIZE);
+	}	
 	if (p->txindex >= BLOCKING_FACTOR)
 	{
-		if (sendto(p->rtpdir,p->txbuf,GSM_FRAME_SIZE * BLOCKING_FACTOR,
+		p->txseq++;
+		myseq = htonl(p->txseq);
+		memcpy(p->txbuf,&myseq,SSO);
+		if (sendto(p->rtpdir,p->txbuf,(GSM_FRAME_SIZE * BLOCKING_FACTOR) + SSO,
 			0,&p->si_other,sizeof(p->si_other)) == -1)
 				return -1;
 		p->txindex = 0;




More information about the svn-commits mailing list