Newer
Older
/*
* Asterisk -- A telephony toolkit for Linux.
*
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <stdio.h>
#include <string.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/config.h>
#include <asterisk/logger.h>
#include <asterisk/module.h>
#include <asterisk/pbx.h>
#include <asterisk/options.h>
#include <asterisk/file.h>
#include <asterisk/ulaw.h>
#include <asterisk/cdr.h>
#include <asterisk/parking.h>
#include <asterisk/app.h>
#include <asterisk/dsp.h>
#include <asterisk/term.h>
#include <sys/signal.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/zaptel.h>
#include <math.h>
#include <tonezone.h>
#ifdef ZAPATA_R2
#include <libmfcr2.h>
#endif
/*
XXX
XXX We definitely need to lock the private structure in zt_read and such
XXX
*/
/*
* Define ZHONE_HACK to cause us to go off hook and then back on hook when
* the user hangs up to reset the state machine so ring works properly.
* This is used to be able to support kewlstart by putting the zhone in
* groundstart mode since their forward disconnect supervision is entirely
* broken even though their documentation says it isn't and their support
* is entirely unwilling to provide any assistance with their channel banks
* even though their web site says they support their products for life.
*/
/* Typically, how many rings before we should send Caller*ID */
#define DEFAULT_CIDRINGS 1
#define AST_LAW(p) (((p)->law == ZT_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
static char *desc = "Zapata Telephony"
" w/PRI"
#endif
#ifdef ZAPATA_R2
" w/R2"
#endif
;
static char *tdesc = "Zapata Telephony Driver"
#ifdef ZAPATA_PRI
" w/PRI"
#endif
#ifdef ZAPATA_R2
" w/R2"
static char *type = "Zap";
static char *typecompat = "Tor"; /* Retain compatibility with chan_tor */
static char *config = "zapata.conf";
#define SIG_EM ZT_SIG_EM
#define SIG_EMWINK (0x10000 | ZT_SIG_EM)
#define SIG_FEATD (0x20000 | ZT_SIG_EM)
#define SIG_FEATDMF (0x40000 | ZT_SIG_EM)
#define SIG_FEATB (0x80000 | ZT_SIG_EM)
#define SIG_E911 (0x100000 | ZT_SIG_EM)
#define SIG_FXSLS ZT_SIG_FXSLS
#define SIG_FXSGS ZT_SIG_FXSGS
#define SIG_FXSKS ZT_SIG_FXSKS
#define SIG_FXOLS ZT_SIG_FXOLS
#define SIG_FXOGS ZT_SIG_FXOGS
#define SIG_FXOKS ZT_SIG_FXOKS
#define SIG_PRI ZT_SIG_CLEAR
#define SIG_SFWINK (0x10000 | ZT_SIG_SF)
#define SIG_SF_FEATD (0x20000 | ZT_SIG_SF)
#define SIG_SF_FEATDMF (0x40000 | ZT_SIG_SF)
#define SIG_SF_FEATB (0x80000 | ZT_SIG_SF)
#define RESET_INTERVAL 3600 /* How often (in seconds) to reset unused channels */
#define CHAN_PSEUDO -2
static char context[AST_MAX_EXTENSION] = "default";
static char callerid[256] = "";
static char language[MAX_LANGUAGE] = "";
static int usedistinctiveringdetection = 0;
static int zaptrcallerid = 0;
static unsigned int cur_group = 0;
static unsigned int cur_callergroup = 0;
static unsigned int cur_pickupgroup = 0;
static int immediate = 0;
static int stripmsd = 0;
static int callwaiting = 0;
static int callwaitingcallerid = 0;
static int hidecallerid = 0;
Martin Pycko
committed
static int restrictcid = 0;
Martin Pycko
committed
static int use_callingpres = 0;
static int threewaycalling = 0;
static int transfer = 0;
static float rxgain = 0.0;
static float txgain = 0.0;
static int tonezone = -1;
static int echotraining;
static int amaflags = 0;
static int adsi = 0;
#ifdef ZAPATA_PRI
static int minunused = 2;
static int minidle = 0;
static char idleext[AST_MAX_EXTENSION];
static char idledial[AST_MAX_EXTENSION];
/* Wait up to 16 seconds for first digit (FXO logic) */
static int firstdigittimeout = 16000;
/* How long to wait for following digits (FXO logic) */
static int gendigittimeout = 8000;
/* How long to wait for an extra digit, if there is an ambiguous match */
static int matchdigittimeout = 3000;
static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
/* Protect the interface list (of zt_pvt's) */
static ast_mutex_t iflock = AST_MUTEX_INITIALIZER;
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it's doing something critical. */
static ast_mutex_t monlock = AST_MUTEX_INITIALIZER;
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use. */
static pthread_t monitor_thread = 0;
static int restart_monitor(void);
static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
static int zt_sendtext(struct ast_channel *c, char *text);
static inline int zt_get_event(int fd)
{
/* Avoid the silly zt_getevent which ignores a bunch of events */
int j;
if (ioctl(fd, ZT_GETEVENT, &j) == -1) return -1;
return j;
}
static inline int zt_wait_event(int fd)
{
/* Avoid the silly zt_waitevent which ignores a bunch of events */
int i,j=0;
i = ZT_IOMUX_SIGEVENT;
if (ioctl(fd, ZT_IOMUX, &i) == -1) return -1;
if (ioctl(fd, ZT_GETEVENT, &j) == -1) return -1;
return j;
}
/* Chunk size to read -- we use 20ms chunks to make things happy. */
#define READ_SIZE 160
#define MASK_AVAIL (1 << 0) /* Channel available for PRI use */
#define MASK_INUSE (1 << 1) /* Channel currently in use */
#define CALLWAITING_SILENT_SAMPLES ( (300 * 8) / READ_SIZE) /* 300 ms */
#define CALLWAITING_REPEAT_SAMPLES ( (10000 * 8) / READ_SIZE) /* 300 ms */
#define CIDCW_EXPIRE_SAMPLES ( (500 * 8) / READ_SIZE) /* 500 ms */
#define MIN_MS_SINCE_FLASH ( (2000) ) /* 2000 ms */
#ifdef ZAPATA_R2
static int r2prot = -1;
#endif
#ifdef ZAPATA_PRI
struct zt_pri {
pthread_t master; /* Thread of master */
ast_mutex_t lock; /* Mutex */
char idleext[AST_MAX_EXTENSION]; /* Where to idle extra calls */
char idlecontext[AST_MAX_EXTENSION]; /* What context to use for idle */
char idledial[AST_MAX_EXTENSION]; /* What to dial before dumping */
int minunused; /* Min # of channels to keep empty */
int minidle; /* Min # of "idling" calls to keep active */
int nodetype; /* Node type */
int switchtype; /* Type of switch to emulate */
int dchannel; /* What channel the dchannel is on */
int channels; /* Num of chans in span (31 or 24) */
struct pri *pri;
int debug;
int fd;
int up;
int offset;
int span;
int resetting;
int resetchannel;
time_t lastreset;
struct zt_pvt *pvt[32]; /* Member channel pvt structs */
struct zt_channel *chan[32]; /* Channels on each line */
};
static struct zt_pri pris[NUM_SPANS];
static int pritype = PRI_CPE;
#if 0
#define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
#else
#define DEFAULT_PRI_DEBUG 0
#endif
static inline void pri_rel(struct zt_pri *pri)
{
ast_mutex_unlock(&pri->lock);
#define SUB_REAL 0 /* Active call */
#define SUB_CALLWAIT 1 /* Call-Waiting call on hold */
#define SUB_THREEWAY 2 /* Three-way call */
static struct zt_distRings drings;
struct distRingData {
int ring[3];
};
struct ringContextData {
char contextData[AST_MAX_EXTENSION];
};
struct zt_distRings {
struct distRingData ringnum[3];
struct ringContextData ringContext[3];
};
static char *subnames[] = {
"Real",
"Callwait",
"Threeway"
};
struct zt_subchannel {
int zfd;
struct ast_channel *owner;
int chan;
short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
struct ast_frame f; /* One frame for each channel. How did this ever work before? */
int needringing;
int needbusy;
int needcongestion;
int needcallerid;
int needanswer;
int linear;
int inthreeway;
};
#define CONF_USER_REAL (1 << 0)
#define CONF_USER_THIRDCALL (1 << 1)
#define MAX_SLAVES 4
ast_mutex_t lock;
struct ast_channel *owner; /* Our current active owner (if applicable) */
/* Up to three channels can be associated with this call */
struct zt_subchannel sub_unused; /* Just a safety precaution */
struct zt_subchannel subs[3]; /* Sub-channels */
struct zt_confinfo saveconf; /* Saved conference info */
struct zt_pvt *slaves[MAX_SLAVES]; /* Slave to us (follows our conferencing) */
struct zt_pvt *master; /* Master to us (we follow their conferencing) */
int inconference; /* If our real should be in the conference */
int radio; /* radio type */
int firstradio; /* first radio flag */
int tonezone; /* tone zone for this chan, or -1 for default */
struct zt_pvt *prev; /* Prev channel in list */
int usedistinctiveringdetection;
char exten[AST_MAX_EXTENSION];
char language[MAX_LANGUAGE];
Martin Pycko
committed
char *origcallerid; /* malloced original callerid */
unsigned int group;
int confno; /* Our conference */
int confusers; /* Who is using our conference */
int propconfno; /* Propagated conference number */
unsigned int callgroup;
unsigned int pickupgroup;
int immediate; /* Answer before getting digits? */
int channel; /* Channel Number */
int span; /* Span number */
int dialing;
int use_callerid; /* Whether or not to use caller id on this channel */
int hidecallerid;
int permhidecallerid; /* Whether to hide our outgoing caller ID or not */
Martin Pycko
committed
int restrictcid; /* Whether restrict the callerid -> only send ANI */
int use_callingpres; /* Whether to use the callingpres the calling switch sends */
int callingpres; /* The value of callling presentation that we're going to use when placing a PRI call */
int callwaitingrepeat; /* How many samples to wait before repeating call waiting */
int cidcwexpire; /* When to expire our muting for CID/CW */
unsigned char *cidspill;
int cidpos;
int cidlen;
int ringt;
int stripmsd;
int callwaiting;
int callwaitcas;
int callwaitrings;
int echocancel;
int echotraining;
int echobreak;
char echorest[10];
int permcallwaiting;
int callwaitingcallerid;
int threewaycalling;
int transfer;
Mark Spencer
committed
struct timeval flashtime; /* Last flash-hook time */
int cref; /* Call reference number */
ZT_DIAL_OPERATION dop;
int destroy;
int ignoredtmf;
int inalarm;
char accountcode[20]; /* Account code */
int amaflags; /* AMA Flags */
char didtdd; /* flag to say its done it once */
struct tdd_state *tdd; /* TDD flag */
int adsi;
int cancallforward;
char call_forward[AST_MAX_EXTENSION];
char mailbox[AST_MAX_EXTENSION];
int confirmanswer; /* Wait for '#' to confirm answer */
int distinctivering; /* Which distinctivering to use */
int cidrings; /* Which ring to deliver CID on */
int faxhandled; /* Has a fax tone already been handled? */
int pulsedial; /* whether a pulse dial phone is detected */
int dtmfrelax; /* whether to run in relaxed DTMF mode */
Martin Pycko
committed
int fake_event;
int zaptrcallerid; /* should we use the callerid from incoming call on zap transfer or not */
#ifdef ZAPATA_PRI
struct zt_pri *pri;
q931_call *call;
#ifdef PRI_EVENT_PROCEEDING
int proceeding;
#endif
int setup_ack; /* wheter we received SETUP_ACKNOWLEDGE or not */
#endif
#ifdef ZAPATA_R2
int r2prot;
mfcr2_t *r2;
int hasr2call;
int r2blocked;
int sigchecked;
} *iflist = NULL, *ifend = NULL;
Martin Pycko
committed
struct zt_pvt *round_robin[32];
#ifdef ZAPATA_PRI
static inline int pri_grab(struct zt_pvt *pvt, struct zt_pri *pri)
{
int res;
/* Grab the lock first */
do {
res = ast_mutex_trylock(&pri->lock);
ast_mutex_unlock(&pvt->lock);
/* Release the lock and try again */
usleep(1);
ast_mutex_lock(&pvt->lock);
}
} while(res);
/* Then break the select */
pthread_kill(pri->master, SIGURG);
return 0;
}
#endif
#define NUM_CADENCE_MAX 25
static int num_cadence = 4;
static int user_has_defined_cadences = 0;
static struct zt_ring_cadence cadences[NUM_CADENCE_MAX] = {
{ { 125, 125, 2000, 4000 } }, /* Quick chirp followed by normal ring */
{ { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /* British style ring */
{ { 125, 125, 125, 125, 125, 4000 } }, /* Three short bursts */
{ { 1000, 500, 2500, 5000 } }, /* Long ring */
};
int receivedRingT; /* Used to find out what ringtone we are on */
/* cidrings says in which pause to transmit the cid information, where the first pause
* is 1, the second pause is 2 and so on.
*/
static int cidrings[NUM_CADENCE_MAX] = {
2, /* Right after first long ring */
4, /* Right after long part */
3, /* After third chirp */
2, /* Second spell */
};
#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
Martin Pycko
committed
#ifdef ZAPATA_PRI
{
switch(cause) {
case PRI_CAUSE_USER_BUSY:
return AST_CAUSE_BUSY;
case PRI_CAUSE_NORMAL_CLEARING:
return AST_CAUSE_NORMAL;
case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
case PRI_CAUSE_REQUESTED_CHAN_UNAVAIL:
return AST_CAUSE_CONGESTION;
case PRI_CAUSE_UNALLOCATED:
case PRI_CAUSE_NUMBER_CHANGED:
return AST_CAUSE_UNALLOCATED;
default:
return AST_CAUSE_FAILURE;
}
/* never reached */
return 0;
}
Martin Pycko
committed
/* translate between ast cause and PRI */
static int hangup_cause2pri(int cause)
{
switch(cause) {
case AST_CAUSE_BUSY:
return PRI_CAUSE_USER_BUSY;
case AST_CAUSE_NORMAL:
default:
return PRI_CAUSE_NORMAL_CLEARING;
}
/* never reached */
return 0;
}
#endif
static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok)
if (p->subs[0].owner == ast)
res = 0;
else if (p->subs[1].owner == ast)
res = 1;
else if (p->subs[2].owner == ast)
res = 2;
else {
res = -1;
if (!nullok)
ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
}
return res;
}
static void swap_subs(struct zt_pvt *p, int a, int b)
{
int tchan;
int tinthreeway;
struct ast_channel *towner;
struct ast_frame null = { AST_FRAME_NULL, };
ast_log(LOG_DEBUG, "Swapping %d and %d\n", a, b);
tchan = p->subs[a].chan;
towner = p->subs[a].owner;
tinthreeway = p->subs[a].inthreeway;
p->subs[a].chan = p->subs[b].chan;
p->subs[a].owner = p->subs[b].owner;
p->subs[a].inthreeway = p->subs[b].inthreeway;
p->subs[b].chan = tchan;
p->subs[b].owner = towner;
p->subs[b].inthreeway = tinthreeway;
if (p->subs[a].owner) {
ast_queue_frame(p->subs[a].owner, &null, 0);
}
if (p->subs[b].owner) {
ast_queue_frame(p->subs[b].owner, &null, 0);
}
}
static int zt_open(char *fn)
{
int fd;
int isnum;
int chan = 0;
int bs;
int x;
isnum = 1;
for (x=0;x<strlen(fn);x++) {
if (!isdigit(fn[x])) {
isnum = 0;
break;
}
}
if (isnum) {
chan = atoi(fn);
if (chan < 1) {
ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
return -1;
}
fn = "/dev/zap/channel";
fd = open(fn, O_RDWR | O_NONBLOCK);
if (fd < 0) {
ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
}
if (chan) {
if (ioctl(fd, ZT_SPECIFY, &chan)) {
x = errno;
close(fd);
errno = x;
ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
bs = READ_SIZE;
if (ioctl(fd, ZT_SET_BLOCKSIZE, &bs) == -1) return -1;
return fd;
}
static void zt_close(int fd)
{
close(fd);
}
int zt_setlinear(int zfd, int linear)
{
int res;
res = ioctl(zfd, ZT_SETLINEAR, &linear);
if (res)
return res;
int res;
res = ioctl(zfd, ZT_SETLAW, &law);
if (res)
return res;
return 0;
}
static int alloc_sub(struct zt_pvt *p, int x)
{
ZT_BUFFERINFO bi;
int res;
if (p->subs[x].zfd < 0) {
p->subs[x].zfd = zt_open("/dev/zap/pseudo");
if (p->subs[x].zfd > -1) {
res = ioctl(p->subs[x].zfd, ZT_GET_BUFINFO, &bi);
if (!res) {
bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
res = ioctl(p->subs[x].zfd, ZT_SET_BUFINFO, &bi);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d\n", x);
}
} else
ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d\n", x);
if (ioctl(p->subs[x].zfd, ZT_CHANNO, &p->subs[x].chan) == 1) {
ast_log(LOG_WARNING,"Unable to get channel number for pseudo channel on FD %d\n",p->subs[x].zfd);
zt_close(p->subs[x].zfd);
p->subs[x].zfd = -1;
return -1;
}
if (option_debug)
ast_log(LOG_DEBUG, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].zfd, p->subs[x].chan);
return 0;
} else
ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
return -1;
}
ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
return -1;
}
static int unalloc_sub(struct zt_pvt *p, int x)
{
if (!x) {
ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
return -1;
}
ast_log(LOG_DEBUG, "Released sub %d of channel %d\n", x, p->channel);
if (p->subs[x].zfd > -1) {
zt_close(p->subs[x].zfd);
}
p->subs[x].zfd = -1;
p->subs[x].linear = 0;
p->subs[x].chan = 0;
p->subs[x].owner = NULL;
p->subs[x].inthreeway = 0;
memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
return 0;
}
static int zt_digit(struct ast_channel *ast, char digit)
{
ZT_DIAL_OPERATION zo;
struct zt_pvt *p;
index = zt_get_index(ast, p, 0);
if (index == SUB_REAL) {
#ifdef PRI_EVENT_SETUP_ACK
if (p->sig == SIG_PRI && ast->_state == AST_STATE_DIALING && p->setup_ack && !p->proceeding) {
#else
#ifdef PRI_EVENT_PROCEEDING
if (p->sig == SIG_PRI && ast->_state == AST_STATE_DIALING && !p->proceeding) {
#else
if (p->sig == SIG_PRI && ast->_state == AST_STATE_DIALING) {
#endif
if (!pri_grab(p, p->pri))
pri_information(p->pri->pri,p->call,digit);
else
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
pri_rel(p->pri);
} else {
zo.op = ZT_DIAL_OP_APPEND;
zo.dialstr[0] = 'T';
zo.dialstr[1] = digit;
zo.dialstr[2] = 0;
if ((res = ioctl(p->subs[SUB_REAL].zfd, ZT_DIAL, &zo)))
ast_log(LOG_WARNING, "Couldn't dial digit %c\n", digit);
else
p->dialing = 1;
}
return res;
}
static char *events[] = {
"No event",
"On hook",
"Ring/Answered",
"Wink/Flash",
"Alarm",
"No more alarm",
"HDLC Abort",
"HDLC Overrun",
"HDLC Bad FCS",
"Dial Complete",
"Ringer On",
"Ringer Off",
"Hook Transition Complete",
"Bits Changed",
"Pulse Start"
static struct {
int alarm;
char *name;
} alarms[] = {
{ ZT_ALARM_RED, "Red Alarm" },
{ ZT_ALARM_YELLOW, "Yellow Alarm" },
{ ZT_ALARM_BLUE, "Blue Alarm" },
{ ZT_ALARM_RECOVER, "Recovering" },
{ ZT_ALARM_LOOPBACK, "Loopback" },
{ ZT_ALARM_NOTOPEN, "Not Open" },
{ ZT_ALARM_NONE, "None" },
};
static char *alarm2str(int alarm)
{
int x;
for (x=0;x<sizeof(alarms) / sizeof(alarms[0]); x++) {
if (alarms[x].alarm & alarm)
return alarms[x].name;
}
return alarm ? "Unknown Alarm" : "No Alarm";
}
static char *event2str(int event)
{
static char buf[256];
return events[event];
sprintf(buf, "Event %d", event);
return buf;
}
#ifdef ZAPATA_R2
static int str2r2prot(char *swtype)
{
if (!strcasecmp(swtype, "ar"))
return MFCR2_PROT_ARGENTINA;
/*endif*/
if (!strcasecmp(swtype, "cn"))
return MFCR2_PROT_CHINA;
/*endif*/
if (!strcasecmp(swtype, "kr"))
return MFCR2_PROT_KOREA;
/*endif*/
return -1;
}
#endif
static char *sig2str(int sig)
{
static char buf[256];
switch(sig) {
case SIG_EM:
return "E & M Immediate";
case SIG_EMWINK:
return "E & M Wink";
case SIG_FEATD:
return "Feature Group D (DTMF)";
case SIG_FEATDMF:
return "Feature Group D (MF)";
case SIG_FEATB:
return "Feature Group B (MF)";
case SIG_E911:
return "E911 (MF)";
case SIG_FXSLS:
return "FXS Loopstart";
case SIG_FXSGS:
return "FXS Groundstart";
case SIG_FXSKS:
return "FXS Kewlstart";
case SIG_FXOLS:
return "FXO Loopstart";
case SIG_FXOGS:
return "FXO Groundstart";
case SIG_FXOKS:
return "FXO Kewlstart";
case SIG_PRI:
return "PRI Signalling";
return "SF (Tone) Signalling Immediate";
case SIG_SFWINK:
return "SF (Tone) Signalling Wink";
case SIG_SF_FEATD:
return "SF (Tone) Signalling with Feature Group D (DTMF)";
case SIG_SF_FEATDMF:
return "SF (Tone) Signalling with Feature Group D (MF)";
case SIG_SF_FEATB:
return "SF (Tone) Signalling with Feature Group B (MF)";
snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
static int conf_add(struct zt_pvt *p, struct zt_subchannel *c, int index, int slavechannel)
/* If the conference already exists, and we're already in it
don't bother doing anything */
ZT_CONFINFO zi;
memset(&zi, 0, sizeof(zi));
zi.chan = 0;
if (slavechannel > 0) {
/* If we have only one slave, do a digital mon */
zi.confmode = ZT_CONF_DIGITALMON;
zi.confno = slavechannel;
} else {
if (!index) {
/* Real-side and pseudo-side both participate in conference */
zi.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER |
ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
} else
zi.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
zi.confno = p->confno;
if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
return 0;
if (c->zfd < 0)
return 0;
if (ioctl(c->zfd, ZT_SETCONF, &zi)) {
ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d\n", c->zfd, zi.confmode, zi.confno);
if (slavechannel < 1) {
p->confno = zi.confno;
}
memcpy(&c->curconf, &zi, sizeof(c->curconf));
ast_log(LOG_DEBUG, "Added %d to conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
static int isourconf(struct zt_pvt *p, struct zt_subchannel *c)
{
/* If they're listening to our channel, they're ours */
if ((p->channel == c->curconf.confno) && (c->curconf.confmode == ZT_CONF_DIGITALMON))
return 1;
/* If they're a talker on our (allocated) conference, they're ours */
if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & ZT_CONF_TALKER))
return 1;
return 0;
}
static int conf_del(struct zt_pvt *p, struct zt_subchannel *c, int index)
if (/* Can't delete if there's no zfd */
(c->zfd < 0) ||
/* Don't delete from the conference if it's not our conference */
/* Don't delete if we don't think it's conferenced at all (implied) */
) return 0;
memset(&zi, 0, sizeof(zi));
zi.chan = 0;
zi.confno = 0;
zi.confmode = 0;
if (ioctl(c->zfd, ZT_SETCONF, &zi)) {
ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
ast_log(LOG_DEBUG, "Removed %d from conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
memcpy(&c->curconf, &zi, sizeof(c->curconf));
static int isslavenative(struct zt_pvt *p, struct zt_pvt **out)
{
int x;
int useslavenative;
struct zt_pvt *slave = NULL;
/* Start out optimistic */
useslavenative = 1;
/* Update conference state in a stateless fashion */
for (x=0;x<3;x++) {
/* Any three-way calling makes slave native mode *definitely* out
of the question */