[asterisk-commits] jdixon: branch jdixon/chan_usbradio-1.4 r133438 - /team/jdixon/chan_usbradio-...
SVN commits to the Asterisk project
asterisk-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 asterisk-commits
mailing list