[asterisk-commits] jdixon: branch jdixon/chan_usbradio-1.4 r141664 - /team/jdixon/chan_usbradio-...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sat Sep 6 21:41:56 CDT 2008
Author: jdixon
Date: Sat Sep 6 21:41:55 2008
New Revision: 141664
URL: http://svn.digium.com/view/asterisk?view=rev&rev=141664
Log:
Added chan_irlp.c
Added:
team/jdixon/chan_usbradio-1.4/channels/chan_irlp.c (with props)
Added: team/jdixon/chan_usbradio-1.4/channels/chan_irlp.c
URL: http://svn.digium.com/view/asterisk/team/jdixon/chan_usbradio-1.4/channels/chan_irlp.c?view=auto&rev=141664
==============================================================================
--- team/jdixon/chan_usbradio-1.4/channels/chan_irlp.c (added)
+++ team/jdixon/chan_usbradio-1.4/channels/chan_irlp.c Sat Sep 6 21:41:55 2008
@@ -1,0 +1,1383 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Copyright (C) 2008, Scott Lawson/KI4LKF
+ * ScottLawson/KI4LKF <ham44865 at yahoo.com>
+ * Jim Dixon, WB6NIL <jim at lambdatel.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>
+ * \author Jim Dixon, WB6NIL <jim at lambdatel.com>
+ *
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+ ***/
+
+/* Version 0.7, 9/4/2008
+irlp channel driver for Asterisk/app_rpt.
+
+I wish to thank the following people for the immeasurable amount of
+very high-quality assistance they have provided me, without which this
+project would have been impossible:
+
+Scott, KI4LKF
+Skip, WB6YMH
+Randy, KC6HUR
+Steve, N4IRS
+Eric, KA6UAI for putting up with a few miserable days of
+ testing using his on-the-air repeater
+*/
+
+#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"
+#include "asterisk/translate.h"
+#include "asterisk/cli.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"
+#define IRLP_RESET "su - repeater /tmp/irlpwrap /home/irlp/custom/irlp_fullreset"
+#define IRLP_END "su - repeater /tmp/irlpwrap /home/irlp/scripts/end &"
+#define IRLP_CALL_REFL "su - repeater /tmp/irlpwrap /home/irlp/scripts/connect_to_reflector ref%04d &"
+#define IRLP_CALL "su - repeater /tmp/irlpwrap /home/irlp/scripts/call stn%04d &"
+#define IRLP_WRAPPER "echo '#! /bin/sh\n\n. /home/irlp/custom/environment\n" \
+ "exec $1 $2 $3 $4 $5 $6\n' > /tmp/irlpwrap ; chown repeater /tmp/irlpwrap ; chmod 755 /tmp/irlpwrap"
+#define IRLP_AST_PLAYFILE "rpt playback %s /home/irlp/astrun/astplay"
+#define IRLP_PLAY_FILE "/home/irlp/astrun/astplay.pcm"
+#define IRLP_DTMF_FIFO "/home/irlp/astrun/dtmf_fifo"
+#define IRLP_MAKE_FIFO "(/bin/mknod /home/irlp/astrun/dtmf_fifo p;" \
+ "chown repeater /home/irlp/astrun/dtmf_fifo) > /dev/null 2>&1"
+#define IRLP_SEND_DTMF "su - repeater /tmp/irlpwrap \"/home/irlp/scripts/fifoecho stn%04d dtmfregen %s\""
+
+enum {IRLP_NOPROTO,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 {
+ struct ast_channel *owner;
+ char app[16];
+ char txkey;
+ int rxkey;
+ int keepalive;
+ struct ast_frame fr;
+ 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 char astnode[20];
+static char astnode1[20];
+static short rtcptimeout = 10;
+static short localispeakerport = 2174;
+static int radmode = 0;
+static int nodenum = 0;
+static int audio_sock = -1;
+static int ctrl_sock = -1;
+static int tx_audio_port = 0;
+static int alt_audio_sock = -1;
+static int alt_ctrl_sock = -1;
+static uint16_t audio_port_cfg = 2084;
+static uint16_t audio_port;
+static uint16_t ctrl_port;
+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";
+static pthread_t irlp_reader_thread;
+static int run_forever = 1;
+static int proto = IRLP_NOPROTO;
+static int in_node = 0;
+static int txindex;
+static struct irlp_rxqast rxqast;
+static char *outbuf_old;
+static int rxlen;
+static int rxidx;
+static int ready = 0;
+static struct ast_channel *curcall = NULL;
+AST_MUTEX_DEFINE_STATIC(irlplock);
+static char stream[256];
+static int nullfd = -1;
+static int dfd = -1;
+static int playing = 0;
+static unsigned int xcount = 0;
+static char havedtmf = 0;
+static char irlp_dtmf_string[64];
+
+#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 struct irlp_pvt *irlp_alloc(void *data);
+static int is_rtcp_bye(unsigned char *p, int len);
+static int is_valid_rtcp(unsigned char *p, int len);
+static struct ast_channel *irlp_new(struct irlp_pvt *i, int state);
+
+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,
+};
+
+void static reset_stuff(void)
+{
+
+ if (alt_audio_sock != -1) close(alt_audio_sock);
+ alt_audio_sock = -1;
+ if (alt_ctrl_sock != -1) close(alt_ctrl_sock);
+ alt_ctrl_sock = -1;
+ proto = IRLP_NOPROTO;
+ in_node = 0;
+ nodenum = 0;
+ txindex = 0;
+ ready = 0;
+ rxqast.qe_forw = &rxqast;
+ rxqast.qe_back = &rxqast;
+ remote_irlp_node_ip[0] = 0;
+ tx_audio_port = audio_port_cfg;
+ audio_port = audio_port_cfg;
+ ctrl_port = audio_port + 1;
+ havedtmf = 0;
+ memset(irlp_dtmf_string,0,sizeof(irlp_dtmf_string));
+ if (curcall)
+ {
+ curcall->nativeformats = AST_FORMAT_ADPCM;
+ ast_set_read_format(curcall,curcall->readformat);
+ ast_set_write_format(curcall,curcall->writeformat);
+ }
+ return;
+}
+
+
+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 do_new_call(void)
+{
+
+ struct irlp_pvt *p;
+
+ p = irlp_alloc((void *)"");
+ if (!p)
+ {
+ ast_log(LOG_ERROR,"Cannot alloc irlp channel\n");
+ return -1;
+ }
+ curcall = irlp_new(p,AST_STATE_RINGING);
+ if (!curcall)
+ {
+ ast_log(LOG_ERROR,"Cannot alloc irlp channel\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int irlp_call(struct ast_channel *ast, char *dest, int timeout)
+{
+ struct irlp_pvt *p;
+ char *cp,str[100];
+
+ 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;
+ }
+ cp = irlp_read_file(IRLP_ROOT,"active");
+ if (cp && *cp)
+ {
+ ast_safe_system(IRLP_END);
+ usleep(10000);
+ }
+ if (cp) free(cp);
+ if ((!radmode) && nodenum)
+ {
+ if (nodenum >= 9000)
+ snprintf(str,sizeof(str) - 1,IRLP_CALL_REFL,nodenum);
+ else
+ snprintf(str,sizeof(str) - 1,IRLP_CALL,nodenum);
+ ast_safe_system(str);
+ usleep(10000);
+ }
+
+ ast_setstate(ast,(radmode) ? AST_STATE_UP : AST_STATE_RINGING);
+ return 0;
+}
+
+static void irlp_destroy(struct irlp_pvt *p)
+{
+ reset_stuff();
+ curcall = NULL;
+ ast_module_user_remove(p->u);
+ ast_free(p);
+}
+
+static void process_codec_file(struct ast_channel *ast)
+{
+ char *cp;
+
+ if (!ready) return;
+ cp = irlp_read_file(IRLP_ROOT,"codec");
+ if (cp)
+ {
+ if (!strncasecmp(cp,"GSM",3))
+ {
+ if (proto == IRLP_NOPROTO)
+ ast_log(LOG_NOTICE,"irlp channel format set to GSM\n");
+ else if (proto != IRLP_ISGSM)
+ ast_log(LOG_NOTICE,"irlp channel format changed to GSM\n");
+ proto = IRLP_ISGSM;
+ ast->nativeformats = AST_FORMAT_GSM;
+ }
+ else
+ {
+ if (proto == IRLP_NOPROTO)
+ ast_log(LOG_NOTICE,"irlp channel format set to ADPCM\n");
+ else if (proto != IRLP_ISADPCM)
+ ast_log(LOG_NOTICE,"irlp channel format changed to GSM\n");
+ proto = IRLP_ISADPCM;
+ ast->nativeformats = AST_FORMAT_ADPCM;
+ }
+ ast_set_read_format(ast,ast->readformat);
+ ast_set_write_format(ast,ast->writeformat);
+ free(cp);
+ }
+ return;
+}
+
+
+static void *irlp_reader(void *nothing)
+{
+
+ fd_set fds[3];
+ struct timeval tmout;
+ int i,myaud,myctl,x,was_outbound;
+
+ char buf[LARGEST_PACKET_SIZE + 1];
+ struct sockaddr_in sin;
+ struct irlp_rxqast *qpast;
+ char ip[IRLP_IP_SIZE + 1],*cp;
+ socklen_t fromlen;
+ ssize_t recvlen;
+ size_t len;
+ struct stat statbuf;
+ static int play_outbound = 0;
+
+ ast_log(LOG_NOTICE, "IRLP reader thread started.\n");
+ while(run_forever)
+ {
+ if ((proto == IRLP_NOPROTO) && curcall) process_codec_file(curcall);
+ i = ((stat(IRLP_PLAY_FILE,&statbuf) != -1));
+ if (i != playing)
+ {
+ char mystr[60];
+
+ if (!playing)
+ {
+ was_outbound = 0;
+ if (((curcall != NULL)) != play_outbound)
+ {
+ was_outbound = play_outbound;
+ play_outbound = ((curcall != NULL));
+ }
+ snprintf(mystr,sizeof(mystr) - 1,
+ IRLP_AST_PLAYFILE,(play_outbound ||
+ was_outbound) ? astnode1 : astnode);
+ ast_cli_command(nullfd,mystr);
+ }
+ playing = i;
+ }
+ myaud = (alt_audio_sock != -1) ? alt_audio_sock : audio_sock;
+ myctl = (alt_ctrl_sock != -1) ? alt_ctrl_sock : ctrl_sock;
+ FD_ZERO(fds);
+ FD_SET(myaud,fds);
+ FD_SET(myctl,fds);
+ x = myaud;
+ if (myctl > x) x = myctl;
+ tmout.tv_sec = 0;
+ tmout.tv_usec = 50000;
+ i = select(x + 1,fds,NULL,NULL,&tmout);
+ if (i == 0)
+ {
+ continue;
+ }
+ if (i < 0)
+ {
+ ast_log(LOG_ERROR,"Error in select()\n");
+ break;
+ }
+ if (FD_ISSET(myctl,fds)) /* if a ctrl packet */
+ {
+ fromlen = sizeof(struct sockaddr_in);
+ recvlen = recvfrom(myctl,
+ 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);
+ cp = irlp_read_file(IRLP_ROOT,"active");
+ if (cp && (strlen(cp) > 3))
+ {
+ if (cp[strlen(cp) - 1] == '\n')
+ cp[strlen(cp) - 1] = 0;
+ in_node = atoi(cp + 3);
+ ast_log(LOG_NOTICE,"irlp node connected from %s node %s\n",ip,cp + 3);
+ if (!curcall) do_new_call();
+ if ((!ready) && curcall)
+ {
+ struct ast_frame fr;
+
+ fr.datalen = 0;
+ fr.samples = 0;
+ fr.frametype = AST_FRAME_CONTROL;
+ fr.subclass = AST_CONTROL_ANSWER;
+ 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(curcall,&fr);
+ }
+ ready = 1;
+ if (curcall && (proto == IRLP_NOPROTO)) process_codec_file(curcall);
+ } else ast_log(LOG_NOTICE,"irlp node connected from %s\n", ip);
+ if (cp) free(cp);
+ }
+ }
+ }
+ else
+ {
+ if (strncmp(ip, remote_irlp_node_ip, IRLP_IP_SIZE) == 0)
+ {
+ reset_stuff();
+ if ((!radmode) && curcall) ast_softhangup(curcall,AST_SOFTHANGUP_DEV);
+ ast_log(LOG_NOTICE, "received IRLP bye from %s\n",ip);
+ }
+ }
+ }
+ }
+ }
+ if (FD_ISSET(myaud,fds)) /* if a audio packet */
+ {
+ fromlen = sizeof(struct sockaddr_in);
+ recvlen = recvfrom(myaud,
+ 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
+ len = ntohl(((struct irlp_audio *)buf)->buffer.buffer_len);
+ 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 (((struct irlp_audio *)buf)->compression == htonl(0x200 | 0x40000000))
+ {
+ if (proto == IRLP_NOPROTO)
+ ast_log(LOG_NOTICE,"irlp channel format set to ADPCM\n");
+ else if (proto != IRLP_ISADPCM)
+ ast_log(LOG_NOTICE,"irlp channel format changed to GSM\n");
+ proto = IRLP_ISADPCM;
+ if (curcall)
+ {
+
+ curcall->nativeformats = AST_FORMAT_ADPCM;
+ ast_set_read_format(curcall,curcall->readformat);
+ ast_set_write_format(curcall,curcall->writeformat);
+ }
+ }
+ if (((struct irlp_audio *)buf)->compression == htonl(0x20 | 0x40000000))
+ {
+ if (proto == IRLP_NOPROTO)
+ ast_log(LOG_NOTICE,"irlp channel format set to GSM\n");
+ else if (proto != IRLP_ISGSM)
+ ast_log(LOG_NOTICE,"irlp channel format changed to GSM\n");
+ proto = IRLP_ISGSM;
+ if (curcall)
+ {
+ curcall->nativeformats = AST_FORMAT_GSM;
+ ast_set_read_format(curcall,curcall->readformat);
+ ast_set_write_format(curcall,curcall->writeformat);
+ }
+ }
+ qpast = ast_malloc(sizeof(struct irlp_rxqast) + len);
+ if (!qpast)
+ {
+ ast_log(LOG_NOTICE,"Cannot malloc for qpast\n");
+ break;
+ }
+ if (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 *)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(tx_audio_port);
+ sendto((alt_audio_sock != -1) ? alt_audio_sock : 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(audio_sock,buf,recvlen,
+ 0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+ }
+ }
+ }
+ }
+ }
+ ast_mutex_unlock(&irlplock);
+ if (run_forever)
+ {
+ ast_cli_command(nullfd,"rpt restart");
+ }
+ run_forever = 0;
+ ast_log(LOG_NOTICE, "IRLP read thread exited.\n");
+ pthread_exit(NULL);
+}
+
+
+static struct irlp_pvt *irlp_alloc(void *data)
+{
+ struct irlp_pvt *p;
+ struct sockaddr_in si_me;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(astnode);
+ AST_APP_ARG(nodenum);
+ );
+
+ args.nodenum = NULL;
+ args.astnode = NULL;
+ if (!ast_strlen_zero(data))
+ AST_NONSTANDARD_APP_ARGS(args,data,'/');
+
+ p = ast_malloc(sizeof(struct irlp_pvt));
+ if (p) {
+ memset(p, 0, sizeof(struct irlp_pvt));
+ nodenum = 0;
+ rxqast.qe_forw = &rxqast;
+ rxqast.qe_back = &rxqast;
+ sprintf(stream,"%d",audio_port);
+ tx_audio_port = audio_port_cfg;
+ if ((!radmode) && args.astnode && *args.astnode)
+ {
+ strncpy(astnode1,args.astnode,sizeof(astnode1) - 1);
+ }
+ if ((!radmode) && args.nodenum && *args.nodenum)
+ {
+ nodenum = atoi(args.nodenum);
+ if ((nodenum < 1000) || (nodenum > 9999))
+ {
+ ast_log(LOG_ERROR,"Requested node number %s invalid\n",args.nodenum);
+ ast_free(p);
+ return NULL;
+ }
+ if (nodenum >= 9000) tx_audio_port += (2 * (nodenum % 10));
+ }
+
+ if (tx_audio_port != audio_port)
+ {
+ if ((alt_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 ((alt_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(alt_audio_sock);
+ alt_audio_sock = -1;
+ ast_free(p);
+ return(NULL);
+ }
+ memset((char *) &si_me, 0, sizeof(si_me));
+ si_me.sin_family = AF_INET;
+ si_me.sin_addr.s_addr = htonl(INADDR_ANY);
+ si_me.sin_port = htons(tx_audio_port);
+ if (bind(alt_audio_sock, &si_me, sizeof(si_me))==-1)
+ {
+ ast_log(LOG_WARNING, "Unable to bind port for irlp audio connection\n");
+ close(alt_ctrl_sock); alt_ctrl_sock = -1;
+ close(alt_audio_sock); alt_audio_sock = -1;
+ ast_free(p);
+ return(NULL);
+ }
+ si_me.sin_port = htons(tx_audio_port + 1);
+ if (bind(alt_ctrl_sock, &si_me, sizeof(si_me))==-1) {
+ ast_log(LOG_WARNING, "Unable to bind port for irlp control connection\n");
+ close(alt_ctrl_sock); alt_ctrl_sock = -1;
+ close(alt_audio_sock); alt_audio_sock = -1;
+ ast_free(p);
+ return(NULL);
+ }
+ fcntl(alt_audio_sock,F_SETFL,O_NONBLOCK);
+ fcntl(alt_ctrl_sock,F_SETFL,O_NONBLOCK);
+ }
+ }
+ 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;
+ }
+ reset_stuff();
+ ast_safe_system(IRLP_END);
+ irlp_destroy(p);
+ ast->tech_pvt = NULL;
+ ast_setstate(ast, AST_STATE_DOWN);
+ curcall = 0;
+ 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)
+{
+int destnode,hisnode,seqno,i;
+char c;
+
+ struct irlp_pvt *p = ast->tech_pvt;
+
+ if (!p->txkey) return(0);
+ if (text[0] != 'D') return 0;
+ if (sscanf(text + 2,"%d %d %d %c",&destnode,&hisnode,&seqno,&c) != 4) return(0);
+ if (destnode != (in_node + 40000)) return(0);
+ if (c == '*') c = 'S';
+ if (c == '#') c = 'P';
+ i = strlen(irlp_dtmf_string);
+ if (i < (sizeof(irlp_dtmf_string) - 1))
+ {
+ irlp_dtmf_string[i + 1] = 0;
+ irlp_dtmf_string[i] = c;
+ }
+ 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;
+
+ 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,recvlen;
+ 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,c,str[200];
+ unsigned char *dp;
+ static int lasttx = 0;
+
+ if (ast->_state != AST_STATE_UP)
+ return 0;
+
+ if (frame->frametype != AST_FRAME_VOICE)
+ return 0;
+
+ if (proto == IRLP_NOPROTO) return 0;
+
+ if ((xcount++ & 3) == 0) /* every 80 ms */
+ {
+ struct ast_frame fr;
+
+ fr.datalen = 0;
+ fr.samples = 0;
+ fr.frametype = AST_FRAME_DTMF_END;
+ fr.subclass = havedtmf;
+ fr.len = 80;
+ fr.data = 0;
+ fr.src = type;
+ fr.offset = 0;
+ fr.mallocd=0;
+ fr.delivery.tv_sec = 0;
+ fr.delivery.tv_usec = 0;
+ if (havedtmf)
+ {
+ if (curcall) ast_queue_frame(curcall,&fr);
+ ast_log(LOG_NOTICE,"Got DTMF %c on IRLP\n",havedtmf);
+ havedtmf = 0;
+ }
+ else
+ {
+ recvlen = read(dfd,&c,1);
+ if ((recvlen > 0) && strchr("0123456789SPABCD",c))
+ {
+
+ if (c == 'S') c = '*';
+ if (c == 'P') c = '#';
+
+ fr.len = 0;
+ fr.subclass = c;
+ fr.frametype = AST_FRAME_DTMF_BEGIN;
+ if (curcall) ast_queue_frame(curcall,&fr);
+ havedtmf = c;
+ }
+ }
+ }
+ frame_samples = 160;
+ if (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 (rxqast.qe_forw != &rxqast) {
+ for(n = 0,qpast = rxqast.qe_forw; qpast != &rxqast; qpast = qpast->qe_forw) {
+ n++;
+ }
+ if (n > QUEUE_OVERLOAD_THRESHOLD_AST) {
+ while(rxqast.qe_forw != &rxqast) {
+ qpast = rxqast.qe_forw;
+ remque((struct qelem *)qpast);
+ ast_free(qpast);
+ }
+ if (outbuf_old) ast_free(outbuf_old);
+ rxlen = 0;
+ 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 ((rxqast.qe_forw != &rxqast) &&
+ ((rxlen - rxidx) < frame_size))
+ {
+ qpast = 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 (proto == IRLP_ISADPCM) len -= 3;
+ i = (rxlen - rxidx);
+ if ((proto == IRLP_ISADPCM) && (!rxidx) &&
+ (len >= frame_size)) dosync = len;
+ /* if something to output */
+ if ((len + i) >= frame_size)
+ {
+ if (i && outbuf_old)
+ {
+ memcpy(outbuf + AST_FRIENDLY_OFFSET,
+ outbuf_old + rxidx,i);
+ ast_free(outbuf_old);
+ }
+ memcpy(outbuf + i + AST_FRIENDLY_OFFSET,
+ outbuf_new,frame_size - i);
+ rxlen = len;
+ rxidx = frame_size - i;
+ outbuf_old = outbuf_new;
+ gotone = 1;
+ }
+ else
+ {
+ cp = malloc((rxlen - rxidx) + len);
+ if (!cp)
+ {
+ ast_log(LOG_ERROR,"Cannot Malloc");
+ return -1;
+ }
+ if (rxlen) memcpy(cp,outbuf_old + rxidx,i);
+ memcpy(cp + i,outbuf_new,len);
+ rxlen = len + i;
+ rxidx = 0;
+ free(outbuf_new);
+ outbuf_new = NULL;
+ free(outbuf_old);
+ outbuf_old = cp;
+ }
+ }
+ else if ((rxlen - rxidx) >= frame_size)
+ {
+ memcpy(outbuf + AST_FRIENDLY_OFFSET,
+ outbuf_old + rxidx,frame_size);
+ rxidx += frame_size;
+ gotone = 1;
+ }
+ if (gotone)
+ {
+ p->rxkey = MAX_RXKEY_TIME;
+ fr.datalen = frame_size;
+ fr.samples = frame_samples;
+ if ((proto == IRLP_ISADPCM) && dosync)
+ {
+ fr.datalen += 3;
+ memcpy(outbuf + AST_FRIENDLY_OFFSET + frame_size,
+ outbuf_new + dosync,3);
+ }
+ fr.frametype = AST_FRAME_VOICE;
+ if (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 (outbuf_old) ast_free(outbuf_old);
+ rxlen = 0;
+ rxidx = 0;
+ }
+ if (p->rxkey) p->rxkey--;
+
+ if (lasttx != p->txkey)
+ {
+ lasttx = p->txkey;
+ if ((!p->txkey) && irlp_dtmf_string[0])
+ {
+ sprintf(str,IRLP_SEND_DTMF,in_node,irlp_dtmf_string);
+ ast_safe_system(str);
+ ast_log(LOG_NOTICE,"Sent DTMF %s to IRLP\n",irlp_dtmf_string);
+ }
+ irlp_dtmf_string[0] = 0;
+ }
+
+ if (!p->txkey) return(0);
+
+ i = AST_FORMAT_ADPCM;
+ if (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 || txindex) {
+ p->keepalive = KEEPALIVE_TIME;
+ if ((proto == IRLP_ISADPCM) && (!txindex))
+ memcpy(tx_buf + (frame_size *
+ blocking_factor),cp + frame_size,3);
+ memcpy(tx_buf + (frame_size * txindex++),
+ frame->data,frame_size);
+ }
+
+ if (txindex >= blocking_factor) {
+
+ dp = (unsigned char *)irlp_audio_packet.buffer.buffer_val;
+ if (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,
+ "stn%s-%s",mynode,mycall);
+
+ if (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(tx_audio_port);
+
+ if (proto == IRLP_ISADPCM)
+ {
+ sendto((alt_audio_sock != -1) ? alt_audio_sock : audio_sock,(char *)&irlp_audio_packet,507,
+ 0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+ }
+ else
+ {
+ sendto((alt_audio_sock != -1) ? alt_audio_sock : 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 (proto == IRLP_ISADPCM)
+ {
+ sendto(audio_sock,(char *)&irlp_audio_packet,507,
+ 0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+ }
+ else
+ {
+ sendto(audio_sock,(char *)&irlp_audio_packet,356,
+ 0,(struct sockaddr *)&sin,sizeof(struct sockaddr));
+ }
+ 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;
+ char tmpstr[30];
+
+ tmp = ast_channel_alloc(1, state, 0, 0, "", astnode, context, 0, "irlp/%s", stream);
+ if (tmp) {
+ tmp->tech = &irlp_tech;
+ 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, astnode, sizeof(tmp->exten));
+ ast_string_field_set(tmp, language, "");
+ sprintf(tmpstr,"4%04u",(in_node) ? in_node : atoi(mynode));
+ ast_set_callerid(tmp,tmpstr,NULL,NULL);
+ 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;
+
+ if (curcall)
+ {
+ ast_log(LOG_NOTICE,"Channel is busy!\n");
+ return 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;
+ }
+ unlink(IRLP_PLAY_FILE);
+ ast_safe_system(IRLP_RESET);
+ usleep(10000);
+ reset_stuff();
+ p = irlp_alloc(data);
+ if (p) {
+ tmp = irlp_new(p, AST_STATE_DOWN);
+ if (!tmp)
+ irlp_destroy(p);
+ }
+ curcall = tmp;
+ return tmp;
+}
+
+static int unload_module(void)
+{
+ run_forever = 0;
+ usleep(100000);
+ if (audio_sock != -1) close(audio_sock);
+ audio_sock = -1;
+ if (ctrl_sock != -1) close(ctrl_sock);
+ ctrl_sock = -1;
+ if (alt_audio_sock != -1) close(alt_audio_sock);
+ alt_audio_sock = -1;
+ if (alt_ctrl_sock != -1) close(alt_ctrl_sock);
+ alt_ctrl_sock = -1;
+ if (nullfd != -1) close(nullfd);
+ if (dfd != -1) close(dfd);
+ /* 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;
+ pthread_attr_t attr;
+ struct sockaddr_in si_me;
+
+
+#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;
+ }
+
+ ast_safe_system(IRLP_WRAPPER);
+
+ /* 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,"XXXX",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);
+
+ val = (char *)ast_variable_retrieve(cfg,"general","radmode");
+ if (val) radmode = ast_true(val);
+
+ val = (char *)ast_variable_retrieve(cfg,"general","audioport");
+ if (!val)
+ audio_port_cfg = 2074;
+ else
+ audio_port_cfg = atoi(val);
+
+ val = (char *)ast_variable_retrieve(cfg,"general","astnode");
+ if (!val)
+ astnode[0] = 0;
+ else
+ strncpy(astnode,val,sizeof(astnode) - 1);
+
+ val = (char *)ast_variable_retrieve(cfg,"general","context");
+ if (!val)
+ context[0] = 0;
+ else
+ strncpy(context,val,sizeof(context) - 1);
+
+ /* initialize local and remote IRLP node */
+ reset_stuff();
+ curcall = 0;
+
+ ast_config_destroy(cfg);
+
+ ast_safe_system(IRLP_RESET);
+ usleep(10000);
+
+ audio_port = audio_port_cfg;
+ if ((audio_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
+ {
+ ast_log(LOG_WARNING,
+ "Unable to create new socket for irlp audio connection\n");
+ return -1;
+ }
+
+ if ((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(audio_sock);
+ return -1;
+ }
+ memset((char *) &si_me, 0, sizeof(si_me));
+ si_me.sin_family = AF_INET;
+ si_me.sin_addr.s_addr = htonl(INADDR_ANY);
+ si_me.sin_port = htons(audio_port);
+ if (bind(audio_sock, &si_me, sizeof(si_me))==-1)
+ {
+ ast_log(LOG_WARNING, "Unable to bind port for irlp audio connection\n");
+ close(ctrl_sock); ctrl_sock = -1;
+ close(audio_sock); audio_sock = -1;
+ return -1;
+ }
+ ctrl_port = audio_port + 1;
+ si_me.sin_port = htons(ctrl_port);
+ if (bind(ctrl_sock, &si_me, sizeof(si_me))==-1)
+ {
+ ast_log(LOG_WARNING, "Unable to bind port for irlp control connection\n");
+ close(ctrl_sock); ctrl_sock = -1;
+ close(audio_sock); audio_sock = -1;
+ }
+ fcntl(audio_sock,F_SETFL,O_NONBLOCK);
+ fcntl(ctrl_sock,F_SETFL,O_NONBLOCK);
+ nullfd = open("/dev/null",O_RDWR);
+
+ ast_safe_system(IRLP_MAKE_FIFO);
+ dfd = open(IRLP_DTMF_FIFO,O_RDONLY | O_NONBLOCK);
+ if (dfd == -1)
+ {
+ ast_log(LOG_ERROR,"Cannot open FIFO for DTMF!!\n");
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ ast_safe_system(IRLP_RESET);
+ unlink(IRLP_PLAY_FILE);
+
+ usleep(100000);
+ cfg = NULL;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ ast_pthread_create(&irlp_reader_thread,&attr,irlp_reader,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/channels/chan_irlp.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/jdixon/chan_usbradio-1.4/channels/chan_irlp.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/jdixon/chan_usbradio-1.4/channels/chan_irlp.c
[... 3 lines stripped ...]
More information about the asterisk-commits
mailing list