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