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

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sun Aug 31 15:21:49 CDT 2008


Author: jdixon
Date: Sun Aug 31 15:21:48 2008
New Revision: 140551

URL: http://svn.digium.com/view/asterisk?view=rev&rev=140551
Log:
Add this file new

Added:
    team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_irlp.c   (with props)

Added: team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_irlp.c
URL: http://svn.digium.com/view/asterisk/team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_irlp.c?view=auto&rev=140551
==============================================================================
--- team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_irlp.c (added)
+++ team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_irlp.c Sun Aug 31 15:21:48 2008
@@ -1,0 +1,1034 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Copyright (C) 2008, Scott Lawson/KI4LKF
+ * ScottLawson/KI4LKF <ham44865 at yahoo.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief irlp channel driver for Asterisk
+ * 
+ * \author Scott Lawson/KI4LKF <ham44865 at yahoo.com>
+ *
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+ ***/
+
+/* Version 0.2, 08/31/2008
+irlp channel driver for Asterisk/app_rpt.
+This is a first attempt.
+
+How to use this driver:
+You must follow the instructions listed in the README file
+for rtpDir/rtpDir_tm bridge before using this driver.
+In other words, you must install the rtpDir_* scripts
+(included in the rtpDir bridge package)
+onto your local IRLP node, before using this driver.
+
+You will use this driver to connect to IRLP adpcm refXXXX reflectors.
+To connect to IRLP stnXXXX nodes or IRLP gsm refXXXX reflectors, 
+use the irlpgsm driver.
+
+Lets say you know the adpcm IRLP reflector that you wish to connect 
+this driver to, and lets assume it is IRLP reflector refXXX5
+and lets assume that the IRLP reflector refXXX5 which is channel 5,
+uses adpcm codec.
+
+Using the above example, the port to use for this driver would be 
+(5 * 2) + 2074 = 2084
+So in the rxchannel specification in /etc/asterisk/rpt.conf
+under a node stanza, you will have this:
+
+   rxchannel=irlp/0.0.0.0:2084
+
+and of course, this driver will open/lock UDP
+ports 2084(audio),2085(control)
+
+If the linux box is protected by a NAT router,
+leave the IP address as 0.0.0.0,
+do not use 127.0.0.1
+
+You must also make sure that the IRLP ispeaker starts with:
+   
+   /home/irlp/bin/ispeaker -f127.0.0.1 -P2174
+
+You must also make sure that the IRLP imike starts with:
+
+   /home/irlp/bin/imike -F 127.0.0.1:2084
+
+(Take a look at 5198.sh or 5198_tm.sh in rtpDir/rtpDir_tm 
+packages to see how imike and ispeaker are started)
+
+You should start imike and ispeaker manually, after you
+have modified your IRLP node according to the instructions listed 
+in the README file for rtpDir/rtpDir_tm bridge and after
+you have started the IRLP node with rc.irlp script.
+
+This driver and rtpDir/rtpDir_tm bridge
+might compete for the same port(s), so set irlpEnable=no in
+the config file for rtpDir/rtpDir_tm bridge or use different port(s)
+in this driver or rtpDir/rtpDir_tm bridge.
+
+It would be better to have written all this code 
+in C++ instead of C, but Asterisk wants C only.
+
+*/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <search.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/logger.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/options.h"
+#include "asterisk/utils.h"
+#include "asterisk/app.h"
+
+#define	MAX_RXKEY_TIME 4
+
+/* 50 * 10 * 20ms iax2 = 10,000ms = 10 seconds heartbeat */
+#define	KEEPALIVE_TIME 50 * 10
+#define QUEUE_OVERLOAD_THRESHOLD_AST 25
+
+#define ADPCM_BLOCKING_FACTOR 6
+#define ADPCM_FRAME_SIZE 80
+
+#define GSM_BLOCKING_FACTOR 10
+#define GSM_FRAME_SIZE 33
+
+#define IRLP_IP_SIZE 15
+#define IRLP_CALL_SIZE 15
+#define IRLP_NODE_SIZE 7
+#define IRLP_HEADER_INFO_SIZE 24
+#define IRLP_ADPCM_STATE_INFO_SIZE 3
+
+#define	LARGEST_PACKET_SIZE 1024
+#define	IRLP_ROOT "/home/irlp/local"
+
+enum {IRLP_ISADPCM,IRLP_ISGSM} ;
+
+struct irlp_audio
+{
+   int compression;
+   char sendinghost[IRLP_IP_SIZE + 1];
+   struct
+   {
+      int buffer_len;
+      char buffer_val[LARGEST_PACKET_SIZE];
+   } buffer;
+};
+
+struct adpcm_state {
+   short       valprev;
+   char        index; 
+};
+
+struct irlp_rxqast {
+	struct irlp_rxqast *qe_forw;
+	struct irlp_rxqast *qe_back;
+        short int len;
+	char buf[1];
+};
+
+struct irlp_pvt {
+        int audio_sock;
+        int ctrl_sock;
+	struct ast_channel *owner;
+	char app[16];		
+	char stream[80];
+	int proto;
+	char txkey;
+	int rxkey;
+	int keepalive;
+	struct ast_frame fr;	
+	int txindex;
+	struct irlp_rxqast rxqast;
+	char *outbuf_old;
+	int rxlen;
+	int rxidx;
+	struct ast_module_user *u;
+};
+
+/*
+   The remote IRLP node
+*/ 
+static char remote_irlp_node_ip[IRLP_IP_SIZE + 1];
+
+/* 
+   This is your local IRLP node and
+   some config values.
+   Maybe save that into a config struct
+*/
+static char mycall[IRLP_CALL_SIZE + 1];
+static char mynode[IRLP_NODE_SIZE + 1];
+static short rtcptimeout = 10;
+static short localispeakerport = 2174;
+
+static int audio_sock = -1;
+static int ctrl_sock = -1;
+static uint16_t audio_port = 2084;
+static uint16_t ctrl_port = 2085;
+
+static char *config = "irlp.conf";
+
+static const char tdesc[] = "irlp channel driver by KI4LKF";
+static int prefformat = AST_FORMAT_ADPCM;
+static char context[AST_MAX_EXTENSION] = "default";
+static char type[] = "irlp";
+
+#ifdef OLD_ASTERISK
+#define ast_free free
+#define ast_malloc malloc
+#endif
+
+static struct ast_channel *irlp_request(const char *type, int format, void *data, int *cause);
+static int irlp_call(struct ast_channel *ast, char *dest, int timeout);
+static int irlp_hangup(struct ast_channel *ast);
+static struct ast_frame *irlp_xread(struct ast_channel *ast);
+static int irlp_xwrite(struct ast_channel *ast, struct ast_frame *frame);
+static int irlp_indicate(struct ast_channel *ast, int cond, const void *data, size_t datalen);
+static int irlp_digit_begin(struct ast_channel *c, char digit);
+static int irlp_digit_end(struct ast_channel *c, char digit, unsigned int duratiion);
+static int irlp_text(struct ast_channel *c, const char *text);
+
+static int is_rtcp_bye(unsigned char *p, int len);
+static int is_valid_rtcp(unsigned char *p, int len);
+
+static const struct ast_channel_tech irlp_tech = {
+	.type = type,
+	.description = tdesc,
+	.capabilities = AST_FORMAT_ADPCM | AST_FORMAT_GSM,
+	.requester = irlp_request,
+	.call = irlp_call,
+	.hangup = irlp_hangup,
+	.read = irlp_xread,
+	.write = irlp_xwrite,
+	.indicate = irlp_indicate,
+	.send_text = irlp_text,
+	.send_digit_begin = irlp_digit_begin,
+	.send_digit_end = irlp_digit_end,
+};
+
+static char *irlp_read_file(char *basename,char *fname)
+{
+char s[200],*str;
+FILE *fp;
+int  len;
+struct stat mystat;
+
+	snprintf(s,sizeof(s) - 1,"%s/%s",basename,fname);
+	fp = fopen(s,"r");
+	if (!fp) return(NULL);
+	if (fstat(fileno(fp),&mystat) == -1) 
+	{
+		fclose(fp);
+		return NULL;
+	}
+	len = mystat.st_size;
+	str = malloc(len + 1);
+	if (!str)
+	{
+		ast_log(LOG_ERROR,"Cant malloc");
+		fclose(fp);
+		return NULL;
+	}
+	if (fread(str,1,len,fp) != len)
+	{
+		fclose(fp);
+		return NULL;
+	}
+	fclose(fp);
+	str[len] = 0;
+	return(str);
+}
+
+static int is_rtcp_bye(unsigned char *p, int len)
+{
+    unsigned char *end;
+    int sawbye = 0;
+
+    if ((((p[0] >> 6) & 3) != 2 && ((p[0] >> 6) & 3) != 1) ||
+        ((p[0] & 0x20) != 0) ||
+        ((p[1] != 200) && (p[1] != 201)))
+      return 0;
+
+    end = p + len;
+
+    do {
+        if (p[1] == 203)
+            sawbye = 1;
+
+        p += (ntohs(*((short *) (p + 2))) + 1) * 4;
+    } while (p < end && (((p[0] >> 6) & 3) == 2));
+
+    return sawbye;
+}
+
+static int is_valid_rtcp(unsigned char *p, int len)
+{
+   unsigned char *end;
+
+    if (len < 4)
+       return 0;
+
+    if (((((p[0] >> 6) & 3) != 2) &&
+        ((((p[0] >> 6) & 3) != 1))) ||
+        ((p[0] & 0x20) != 0) ||
+        ((p[1] != 200) && (p[1] != 201)))
+      return 0;
+
+    end = p + len;
+
+    do {
+        p += (((p[2] << 8) | p[3]) + 1) * 4;
+    } while (p < end && (((p[0] >> 6) & 3) == 2));
+
+    return (p == end)?1:0;
+}
+
+static int irlp_call(struct ast_channel *ast, char *dest, int timeout)
+{
+	struct irlp_pvt *p;
+
+	p = ast->tech_pvt;
+
+	if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
+		ast_log(LOG_WARNING, "irlp_call called on %s, neither down nor reserved\n", ast->name);
+		return -1;
+	}
+	/* When we call, it just works, really, there's no destination...  Just
+	   ring the phone and wait for someone to answer */
+	if (option_debug)
+		ast_log(LOG_DEBUG, "Calling %s on %s\n", dest, ast->name);
+
+	ast_setstate(ast,AST_STATE_UP);
+	return 0;
+}
+
+static void irlp_destroy(struct irlp_pvt *p)
+{
+	if (p->audio_sock) {
+                close(p->audio_sock);
+                p->audio_sock = -1;
+        }
+
+        if (p->ctrl_sock) {
+                close(p->ctrl_sock);
+                p->ctrl_sock = -1;
+        }
+
+	ast_module_user_remove(p->u);
+	ast_free(p);
+}
+
+static struct irlp_pvt *irlp_alloc(void *data)
+{
+	struct irlp_pvt *p;
+	/* int flags = 0; */
+	char stream[256];
+	struct sockaddr_in si_me;
+        
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(myip);
+		AST_APP_ARG(myport);
+	);
+
+	if (ast_strlen_zero(data)) return NULL;
+
+	AST_NONSTANDARD_APP_ARGS(args,data,':');
+
+	if ((!args.myip) || (!args.myip[0])) args.myip = "127.0.0.1";
+	if ((!args.myport) || (!args.myport[0]))  args.myport = "2074";
+
+	p = ast_malloc(sizeof(struct irlp_pvt));
+	if (p) {
+		memset(p, 0, sizeof(struct irlp_pvt));
+		
+		sprintf(stream,"%s:%d",args.myip,atoi(args.myport));
+		strcpy(p->stream,stream);
+		p->rxqast.qe_forw = &p->rxqast;
+		p->rxqast.qe_back = &p->rxqast;
+
+		if ((p->audio_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
+			ast_log(LOG_WARNING, 
+                                "Unable to create new socket for irlp audio connection\n");
+			ast_free(p);
+			return(NULL);
+		}
+		
+		if ((p->ctrl_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
+			ast_log(LOG_WARNING, 
+                                "Unable to create new socket for irlp control connection\n");
+                        close(p->audio_sock);
+                        p->audio_sock = -1;
+			ast_free(p);
+			return(NULL);
+		}
+		memset((char *) &si_me, 0, sizeof(si_me));
+		si_me.sin_family = AF_INET;
+                if (strcmp(args.myip,"0.0.0.0") == 0)
+                   si_me.sin_addr.s_addr = htonl(INADDR_ANY);
+                else
+		   si_me.sin_addr.s_addr = inet_addr(args.myip);
+                audio_port = atoi(args.myport);
+ 		si_me.sin_port = htons(audio_port);               
+		if (bind(p->audio_sock, &si_me, sizeof(si_me))==-1) {
+			ast_log(LOG_WARNING, "Unable to bind port for irlp audio connection\n");
+                        close(p->ctrl_sock); p->ctrl_sock = -1;
+                        close(p->audio_sock); p->audio_sock = -1;
+			ast_free(p);
+			return(NULL);
+
+		}
+                ctrl_port = audio_port + 1;
+		si_me.sin_port = htons(ctrl_port);
+		if (bind(p->ctrl_sock, &si_me, sizeof(si_me))==-1) {
+			ast_log(LOG_WARNING, "Unable to bind port for irlp control connection\n");
+                        close(p->ctrl_sock); p->ctrl_sock = -1;
+                        close(p->audio_sock); p->audio_sock = -1;
+			ast_free(p);
+			return(NULL);
+
+		}
+                fcntl(p->audio_sock,F_SETFL,O_NONBLOCK);
+                fcntl(p->ctrl_sock,F_SETFL,O_NONBLOCK);
+                audio_sock = p->audio_sock;
+                ctrl_sock = p->ctrl_sock;
+	}
+	return p;
+}
+
+static int irlp_hangup(struct ast_channel *ast)
+{
+	struct irlp_pvt *p;
+	p = ast->tech_pvt;
+	if (option_debug)
+		ast_log(LOG_DEBUG, "irlp_hangup(%s)\n", ast->name);
+	if (!ast->tech_pvt) {
+		ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
+		return 0;
+	}
+	irlp_destroy(p);
+	ast->tech_pvt = NULL;
+	ast_setstate(ast, AST_STATE_DOWN);
+	return 0;
+}
+
+static int irlp_indicate(struct ast_channel *ast, int cond, const void *data, size_t datalen)
+{
+	struct irlp_pvt *p = ast->tech_pvt;
+
+	switch (cond) {
+		case AST_CONTROL_RADIO_KEY:
+			p->txkey = 1;
+			break;
+		case AST_CONTROL_RADIO_UNKEY:
+			p->txkey = 0;
+			break;
+		case AST_CONTROL_HANGUP:
+			return -1;
+		default:
+			return 0;
+	}
+
+	return 0;
+}
+
+static int irlp_text(struct ast_channel *ast, const char *text)
+{
+	return 0;
+}
+
+static int irlp_digit_begin(struct ast_channel *ast, char digit)
+{
+	return 0;
+}
+
+static int irlp_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	return 0;
+}
+
+static struct ast_frame  *irlp_xread(struct ast_channel *ast)
+{
+
+	struct irlp_pvt *p = ast->tech_pvt;
+	char buf[LARGEST_PACKET_SIZE + 1];
+	struct sockaddr_in sin;
+        struct irlp_rxqast *qpast;
+        char ip[IRLP_IP_SIZE + 1],*cp;
+	int i;
+        socklen_t fromlen;
+	ssize_t recvlen;
+        size_t len;
+
+	len = 0;
+        ioctl(p->ctrl_sock,FIONREAD,&len);
+        if (len > 0) {
+           fromlen = sizeof(struct sockaddr_in);
+           recvlen = recvfrom(p->ctrl_sock,
+                                  buf,
+                                  LARGEST_PACKET_SIZE,
+                                  0,
+                                  (struct sockaddr *)&sin,&fromlen);
+           if (recvlen > 0) {
+              buf[recvlen] = '\0';
+#ifdef  OLD_ASTERISK
+              ast_inet_ntoa(ip,IRLP_IP_SIZE,sin.sin_addr);
+#else
+              strncpy(ip,ast_inet_ntoa(sin.sin_addr),IRLP_IP_SIZE);
+#endif
+              if (is_valid_rtcp((unsigned char *)buf,recvlen)) {
+                 if (!is_rtcp_bye((unsigned char *)buf,recvlen)) {
+                    if (strncmp(ip, "127.0.0.1",IRLP_IP_SIZE) != 0) {
+                       if (strncmp(remote_irlp_node_ip, ip, IRLP_IP_SIZE) != 0) { 
+                          strncpy(remote_irlp_node_ip, ip, IRLP_IP_SIZE);
+		          p->proto = IRLP_ISADPCM;
+			  cp = irlp_read_file(IRLP_ROOT,"codec");
+			  if (!strncasecmp(cp,"GSM",3))
+			  {
+				  p->proto = IRLP_ISGSM;
+			          ast->nativeformats = AST_FORMAT_GSM;
+				  ast_log(LOG_NOTICE,"irlp channel format set to GSM\n");
+			  }
+			  else 
+			  {
+			          ast->nativeformats = AST_FORMAT_ADPCM;
+				  ast_log(LOG_NOTICE,"irlp channel format set to ADPCM\n");
+			  }
+			  ast_set_read_format(ast,ast->readformat);
+			  ast_set_write_format(ast,ast->writeformat);
+                          ast_log(LOG_NOTICE,"irlp node connected from %s\n", ip);
+                       }
+                    }
+                 } 
+                 else {
+                    if (strncmp(ip, remote_irlp_node_ip, IRLP_IP_SIZE) == 0) {
+                       remote_irlp_node_ip[0] = '\0'; 
+		       p->proto = IRLP_ISADPCM;
+		       ast->nativeformats = AST_FORMAT_ADPCM;
+		       ast_set_read_format(ast,ast->readformat);
+		       ast_set_write_format(ast,ast->writeformat);
+                       ast_log(LOG_NOTICE, "received IRLP bye from %s\n",ip);
+                    }
+                 }
+              }
+           }
+	}
+	
+        len = 0;
+        ioctl(p->audio_sock,FIONREAD,&len);
+        if (len > 0)
+	{
+           fromlen = sizeof(struct sockaddr_in);
+           recvlen = recvfrom(p->audio_sock,
+                              buf,
+                              LARGEST_PACKET_SIZE,
+                              0,
+                              (struct sockaddr *)&sin,&fromlen);
+           if (recvlen > 0)
+	     {
+              buf[recvlen] = '\0';
+#ifdef  OLD_ASTERISK
+              ast_inet_ntoa(ip,IRLP_IP_SIZE,sin.sin_addr);
+#else
+              strncpy(ip,ast_inet_ntoa(sin.sin_addr),IRLP_IP_SIZE);
+#endif
+	      i = p->proto;
+              len = ntohl(((struct irlp_audio *)buf)->buffer.buffer_len); 
+              if (((struct irlp_audio *)buf)->compression == htonl(0x200 | 0x40000000))
+	      {
+		  i = IRLP_ISADPCM;
+                  ast->nativeformats = AST_FORMAT_ADPCM;
+		  ast_set_read_format(ast,ast->readformat);
+		  ast_set_write_format(ast,ast->writeformat);
+	      }
+              if (((struct irlp_audio *)buf)->compression == htonl(0x20 | 0x40000000))
+	      {
+		  i = IRLP_ISGSM;
+                  ast->nativeformats = AST_FORMAT_GSM;
+		  ast_set_read_format(ast,ast->readformat);
+		  ast_set_write_format(ast,ast->writeformat);
+	      }
+              if (((strncmp(ip, remote_irlp_node_ip, IRLP_IP_SIZE) == 0) ||
+                   (strncmp(ip, "127.0.0.1", IRLP_IP_SIZE) == 0)) &&
+                   (len > IRLP_ADPCM_STATE_INFO_SIZE) &&
+                   ((recvlen - IRLP_HEADER_INFO_SIZE) == len)) {
+
+		 if (p->proto != i)
+		 {
+			if (i == IRLP_ISADPCM)
+				ast_log(LOG_NOTICE,"Proto changed to <ADPCM>\n");
+			else
+				ast_log(LOG_NOTICE,"Proto changed to <GSM>\n");
+		 }
+		 p->proto = i;
+
+
+                 qpast = ast_malloc(sizeof(struct irlp_rxqast) + len);
+                 if (!qpast) {
+                    ast_log(LOG_NOTICE,"Cannot malloc for qpast\n");
+                    return NULL;
+                 }
+		 if (p->proto == IRLP_ISADPCM)
+		 {
+	                 qpast->len = len;
+	                 memcpy(qpast->buf,((struct irlp_audio *)buf)->buffer.buffer_val,len);
+		 }
+		 else
+		 {
+	                 qpast->len = len - 2;
+	                 memcpy(qpast->buf,((struct irlp_audio *)buf)->buffer.buffer_val + 2,len);
+		 }
+                 insque((struct qelem *)qpast,(struct qelem *)p->rxqast.qe_back);
+
+                 if (strncmp(ip, "127.0.0.1", IRLP_IP_SIZE) == 0) {
+                    if (remote_irlp_node_ip[0] != '\0') {
+                       sin.sin_family = AF_INET;
+                       sin.sin_addr.s_addr = inet_addr(remote_irlp_node_ip);
+                       sin.sin_port = htons(audio_port);
+                       sendto(p->audio_sock,buf,recvlen,
+                               0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+                    }
+                 } else {
+                    sin.sin_family = AF_INET;
+                    sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+                    sin.sin_port = htons(localispeakerport); 
+                    sendto(p->audio_sock,buf,recvlen,
+                           0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+                 }
+              }
+           }
+        }
+  
+        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;
+}
+
+static int irlp_xwrite(struct ast_channel *ast, struct ast_frame *frame)
+{
+        struct sockaddr_in sin;
+	struct irlp_pvt *p = ast->tech_pvt;
+	struct ast_frame fr;
+	struct irlp_rxqast *qpast;
+	int n,i,len,gotone,dosync,blocking_factor,frame_size,frame_samples;
+        char outbuf[ADPCM_FRAME_SIZE + AST_FRIENDLY_OFFSET + 3]; /* turns out that ADPCM is larger */
+        struct irlp_audio irlp_audio_packet;
+        static char tx_buf[(ADPCM_BLOCKING_FACTOR * ADPCM_FRAME_SIZE) + 3]; /* turns out the ADPCM is larger */
+	char *outbuf_new,*cp;
+        unsigned char *dp;
+
+	if (ast->_state != AST_STATE_UP) 
+           return 0;
+
+	if (frame->frametype != AST_FRAME_VOICE) 
+           return 0;
+
+	frame_samples = 160;
+	if (p->proto == IRLP_ISGSM)
+	{
+		blocking_factor = GSM_BLOCKING_FACTOR;
+		frame_size = GSM_FRAME_SIZE;
+	}
+	else
+	{
+		blocking_factor = ADPCM_BLOCKING_FACTOR;
+		frame_size = ADPCM_FRAME_SIZE;
+	}
+        /* IRLP to Asterisk */
+	if (p->rxqast.qe_forw != &p->rxqast) {
+		for(n = 0,qpast = p->rxqast.qe_forw; qpast != &p->rxqast; qpast = qpast->qe_forw) {
+			n++;
+		}
+		if (n > QUEUE_OVERLOAD_THRESHOLD_AST) {
+			while(p->rxqast.qe_forw != &p->rxqast) {
+				qpast = p->rxqast.qe_forw;
+				remque((struct qelem *)qpast);
+				ast_free(qpast);
+			}
+			if (p->outbuf_old) ast_free(p->outbuf_old);
+			p->rxlen = 0;
+			p->rxidx = 0;
+			if (p->rxkey) p->rxkey = 1;
+		} else {		
+			if (!p->rxkey) {
+				fr.datalen = 0;
+				fr.samples = 0;
+				fr.frametype = AST_FRAME_CONTROL;
+				fr.subclass = AST_CONTROL_RADIO_KEY;
+				fr.data =  0;
+				fr.src = type;
+				fr.offset = 0;
+				fr.mallocd=0;
+				fr.delivery.tv_sec = 0;
+				fr.delivery.tv_usec = 0;
+				ast_queue_frame(ast,&fr);
+			} 
+		}
+	}
+	outbuf_new = NULL;
+	len = 0;
+	gotone = 0;
+	dosync = 0;
+	if ((p->rxqast.qe_forw != &p->rxqast) &&
+	    ((p->rxlen - p->rxidx) < frame_size))
+	{
+		qpast = p->rxqast.qe_forw;
+		remque((struct qelem *)qpast);
+		len = qpast->len;
+		outbuf_new = malloc(len);
+		if (!outbuf_new)
+		{
+			ast_log(LOG_ERROR,"Cannot Malloc");
+			return -1;
+		}
+		memcpy(outbuf_new,qpast->buf,len);
+		ast_free(qpast);
+		if (p->proto == IRLP_ISADPCM) len -= 3;
+		i = (p->rxlen - p->rxidx);
+		if ((p->proto == IRLP_ISADPCM) && (!p->rxidx) &&
+			(len >= frame_size)) dosync = len;
+		/* if something to output */
+		if ((len + i) >= frame_size)
+		{
+			if (i && p->outbuf_old)
+			{
+				memcpy(outbuf + AST_FRIENDLY_OFFSET,
+					p->outbuf_old + p->rxidx,i);
+				ast_free(p->outbuf_old);
+			}
+			memcpy(outbuf + i + AST_FRIENDLY_OFFSET,
+				outbuf_new,frame_size - i);
+			p->rxlen = len;
+			p->rxidx = frame_size - i;
+			p->outbuf_old = outbuf_new;
+			gotone = 1;
+		} 
+		else
+		{
+			cp = malloc((p->rxlen - p->rxidx) + len);
+			if (!cp)
+			{
+				ast_log(LOG_ERROR,"Cannot Malloc");
+				return -1;
+			}
+			if (p->rxlen) memcpy(cp,p->outbuf_old + p->rxidx,i);
+			memcpy(cp + i,outbuf_new,len);
+			p->rxlen = len + i;
+			p->rxidx = 0;
+			free(outbuf_new);
+			outbuf_new = NULL;
+			free(p->outbuf_old);
+			p->outbuf_old = cp;
+		}
+	}
+	else if ((p->rxlen - p->rxidx) >= frame_size)
+	{
+		memcpy(outbuf + AST_FRIENDLY_OFFSET,
+			p->outbuf_old + p->rxidx,frame_size);
+		p->rxidx += frame_size;
+		gotone = 1;
+	}
+	if (gotone)
+	{
+ 		p->rxkey = MAX_RXKEY_TIME;
+		fr.datalen = frame_size;
+		fr.samples = frame_samples;
+		if ((p->proto == IRLP_ISADPCM) && dosync)
+		{
+			fr.datalen += 3;
+			memcpy(outbuf + AST_FRIENDLY_OFFSET + frame_size,
+				outbuf_new + dosync,3);
+		}
+		fr.frametype = AST_FRAME_VOICE;
+		if (p->proto == IRLP_ISADPCM)
+		{
+			fr.subclass = AST_FORMAT_ADPCM;
+		}
+		else
+		{
+			fr.subclass = AST_FORMAT_GSM;
+		}
+		fr.data =  outbuf + AST_FRIENDLY_OFFSET;
+		fr.src = type;
+		fr.offset = AST_FRIENDLY_OFFSET;
+		fr.mallocd=0;
+		fr.delivery.tv_sec = 0;
+		fr.delivery.tv_usec = 0;
+		ast_queue_frame(ast,&fr);
+	}
+	if (p->rxkey == 1) {
+		fr.datalen = 0;
+		fr.samples = 0;
+		fr.frametype = AST_FRAME_CONTROL;
+		fr.subclass = AST_CONTROL_RADIO_UNKEY;
+		fr.data =  0;
+		fr.src = type;
+		fr.offset = 0;
+		fr.mallocd=0;
+		fr.delivery.tv_sec = 0;
+		fr.delivery.tv_usec = 0;
+		ast_queue_frame(ast,&fr);
+
+		if (p->outbuf_old) ast_free(p->outbuf_old);
+		p->rxlen = 0;
+		p->rxidx = 0;
+	} 
+	if (p->rxkey) p->rxkey--;
+
+	i = AST_FORMAT_ADPCM;
+	if (p->proto == IRLP_ISGSM) i = AST_FORMAT_GSM;
+
+        /* Asterisk to IRLP */
+        if (!(frame->subclass & i)) {
+             ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
+             return 0;
+        }
+	cp = frame->data;
+        if (p->txkey || p->txindex)  {
+             p->keepalive = KEEPALIVE_TIME;
+	     if ((p->proto == IRLP_ISADPCM) && (!p->txindex))
+		 memcpy(tx_buf + (frame_size * 
+		    blocking_factor),cp + frame_size,3);
+             memcpy(tx_buf + (frame_size * p->txindex++), 
+                    frame->data,frame_size);
+        }     
+
+        if (p->txindex >= blocking_factor) { 
+
+           dp = (unsigned char *)irlp_audio_packet.buffer.buffer_val;
+	   if (p->proto == IRLP_ISADPCM)
+	   {
+	           irlp_audio_packet.compression = htonl(0x200 | 0x40000000);
+	   }
+	   else
+	   {
+	           irlp_audio_packet.compression = htonl(0x20 | 0x40000000);
+	   }
+           snprintf(irlp_audio_packet.sendinghost,IRLP_IP_SIZE,
+                     "%s-%s",mynode,mycall);
+
+	   if (p->proto == IRLP_ISADPCM)
+	   {
+		memcpy((char *)dp,tx_buf,(blocking_factor * frame_size) + 3);
+	        irlp_audio_packet.buffer.buffer_len = htonl((blocking_factor * 
+			frame_size) + 3);
+	   }
+	   else
+	   {
+		memcpy((char *)dp + 2,tx_buf,blocking_factor * frame_size);
+	        irlp_audio_packet.buffer.buffer_len = htonl((blocking_factor * 
+			frame_size) + 2);
+                *((uint16_t *)dp) = htons(1600);
+	   }
+
+           if (remote_irlp_node_ip[0] != '\0') {
+              sin.sin_family = AF_INET;
+              sin.sin_addr.s_addr = inet_addr(remote_irlp_node_ip);
+              sin.sin_port = htons(audio_port);
+
+	      if (p->proto == IRLP_ISADPCM)
+	      {
+                  sendto(p->audio_sock,(char *)&irlp_audio_packet,507,
+                      0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+	      }
+	      else
+	      {
+                  sendto(p->audio_sock,(char *)&irlp_audio_packet,356,
+                      0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+	      }
+           }
+           sin.sin_family = AF_INET;
+           sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+           sin.sin_port = htons(localispeakerport);
+
+	   if (p->proto == IRLP_ISADPCM)
+	   {
+               sendto(p->audio_sock,(char *)&irlp_audio_packet,507,
+                  0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+	   }
+	   else
+	   {
+               sendto(p->audio_sock,(char *)&irlp_audio_packet,356,
+                  0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+	   }
+           p->txindex = 0;
+        }
+
+	if (p->txkey) return 0;
+	if (p->keepalive--) return 0;
+	p->keepalive = KEEPALIVE_TIME;
+
+        /* 
+           If you made changes to this driver to
+           make it run on an IRLP reflector channel,
+           you must create and transmit keepalive packets.
+           No need to send keepalive heartbeats if
+           you are running this driver on an IRLP stnXXXX node.
+        */
+	return 0;
+}
+
+static struct ast_channel *irlp_new(struct irlp_pvt *i, int state)
+{
+	struct ast_channel *tmp;
+	tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, 0, "irlp/%s", i->stream);
+	if (tmp) {
+		tmp->tech = &irlp_tech;
+                tmp->fds[0] = i->audio_sock;
+                tmp->fds[1] = i->ctrl_sock;
+		tmp->nativeformats = prefformat;
+		tmp->rawreadformat = prefformat;
+		tmp->rawwriteformat = prefformat;
+		tmp->writeformat = prefformat;
+		tmp->readformat = prefformat;
+		if (state == AST_STATE_RING)
+			tmp->rings = 1;
+		tmp->tech_pvt = i;
+		ast_copy_string(tmp->context, context, sizeof(tmp->context));
+		ast_copy_string(tmp->exten, "s",  sizeof(tmp->exten));
+		ast_string_field_set(tmp, language, "");
+		i->owner = tmp;
+		i->u = ast_module_user_add(tmp);
+		if (state != AST_STATE_DOWN) {
+			if (ast_pbx_start(tmp)) {
+				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
+				ast_hangup(tmp);
+			}
+		}
+	} else
+		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
+	return tmp;
+}
+
+
+static struct ast_channel *irlp_request(const char *type, int format, void *data, int *cause)
+{
+	int oldformat;
+	struct irlp_pvt *p;
+	struct ast_channel *tmp = NULL;
+	
+	oldformat = format;
+	format &= (AST_FORMAT_ADPCM | AST_FORMAT_GSM);
+	if (!format) {
+		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
+		return NULL;
+	}
+	p = irlp_alloc(data);
+	if (p) {
+		tmp = irlp_new(p, AST_STATE_DOWN);
+		if (!tmp)
+			irlp_destroy(p);
+	}
+	return tmp;
+}
+
+static int unload_module(void)
+{
+	/* First, take us out of the channel loop */
+	ast_channel_unregister(&irlp_tech);
+	return 0;
+}
+
+static int load_module(void)
+{
+	struct ast_config *cfg = NULL;
+        char *val = NULL;
+
+#ifdef  NEW_ASTERISK
+        struct ast_flags zeroflag = {0};
+#endif
+
+#ifdef  NEW_ASTERISK
+        if (!(cfg = ast_config_load(config,zeroflag))) {
+#else
+        if (!(cfg = ast_config_load(config))) {
+#endif
+                ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
+                return AST_MODULE_LOAD_DECLINE;
+        }
+
+        /* some of these values can be copied from /home/irlp/custom/environment */
+        val = (char *)ast_variable_retrieve(cfg,"general","rtcptimeout");
+        if (!val)
+           rtcptimeout = 15;
+        else
+           rtcptimeout = atoi(val);
+
+        val = (char *)ast_variable_retrieve(cfg,"general","call");
+        if (!val)
+           strncpy(mycall,"stnXXXX",IRLP_CALL_SIZE);
+        else
+           strncpy(mycall,val,IRLP_CALL_SIZE);
+
+        val = (char *)ast_variable_retrieve(cfg,"general","node");
+        if (!val)
+           strncpy(mynode,"stnXXXX",IRLP_NODE_SIZE);
+        else
+           strncpy(mynode,val,IRLP_NODE_SIZE);
+
+        val = (char *)ast_variable_retrieve(cfg,"general","localispeakerport");
+        if (!val)
+           localispeakerport = 2174;
+        else
+           localispeakerport = atoi(val);
+
+        /* initialize local and remote IRLP node */
+        remote_irlp_node_ip[0] = '\0'; 
+
+        ast_config_destroy(cfg);
+        cfg = NULL; 
+
+	/* Make sure we can register our channel type */
+	if (ast_channel_register(&irlp_tech)) {
+		ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
+                return AST_MODULE_LOAD_DECLINE;
+	}
+
+	return 0;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "irlp channel driver");

Propchange: team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_irlp.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_irlp.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_irlp.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the svn-commits mailing list