Newer
Older
/*
* Asterisk -- A telephony toolkit for Linux.
*
* VoiceTronix Interface driver
*
* Copyright (C) 2003, Paul Bagyenda
* Paul Bagyenda <bagyenda@dsmagic.com>
* Copyright (C) 2004, Ben Kramer
* Ben Kramer <ben@voicetronix.com.au>
* Daniel Bichara <daniel@bichara.com.br> - Brazilian CallerID detection (c)2004
*
* Welber Silveira - welberms@magiclink.com.br - (c)2004
* Copying CLID string to propper structure after detection
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
extern "C" {
#include <stdio.h>
#include <string.h>
#include <asterisk/lock.h>
#include <asterisk/utils.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/callerid.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 <assert.h>
#define DEFAULT_GAIN 0
#define DEFAULT_ECHO_CANCEL 1
#define VPB_SAMPLES 160
#define VPB_MAX_BUF VPB_SAMPLES*4 + AST_FRIENDLY_OFFSET
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static char *desc = "VoiceTronix V6PCI/V12PCI/V4PCI API Support";
static char *type = "vpb";
static char *tdesc = "Standard VoiceTronix API Driver";
static char *config = "vpb.conf";
/* Default context for dialtone mode */
static char context[AST_MAX_EXTENSION] = "default";
/* Default language */
static char language[MAX_LANGUAGE] = "";
static int usecnt =0;
static int gruntdetect_timeout = 3600000; /* Grunt detect timeout is 1hr. */
static const int prefformat = AST_FORMAT_SLINEAR;
AST_MUTEX_DEFINE_STATIC(usecnt_lock);
/* Protect the interface list (of vpb_pvt's) */
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it's doing something critical. */
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use. */
static int mthreadactive = -1; /* Flag for monitoring monitorthread.*/
static int restart_monitor(void);
/* The private structures of the VPB channels are
linked for selecting outgoing channels */
#define MODE_DIALTONE 1
#define MODE_IMMEDIATE 2
#define MODE_FXO 3
/* These are the tones that are played to the user */
#define TONES_AU
#ifdef TONES_AU
static VPB_TONE Dialtone = {440, 440, 440, -10, -10, -10, 5000, 0 };
static VPB_TONE Busytone = {470, 0, 0, -10, -100, -100, 5000, 0 };
static VPB_TONE Ringbacktone = {400, 50, 440, -10, -10, -10, 1400, 800 };
#endif
/*
#define TONES_USA
#ifdef TONES_USA
static VPB_TONE Dialtone = {425, 0, 0, -16, -100, -100, 10000, 0};
static VPB_TONE Busytone = {425, 0, 0, -10, -100, -100, 500, 500};
static VPB_TONE Ringbacktone = {400, 425, 450, -20, -20, -20, 1000, 1000};
#endif
*/
/* grunt tone defn's */
static VPB_DETECT toned_grunt = { 3, VPB_GRUNT, 1, 2000, 3000, 0, 0, -40, 0, 0, 0, 40, { { VPB_DELAY, 1000, 0, 0 }, { VPB_RISING, 0, 40, 0 }, { 0, 100, 0, 0 } } };
static VPB_DETECT toned_ungrunt = { 2, VPB_GRUNT, 1, 2000, 1, 0, 0, -40, 0, 0, 30, 40, { { 0, 0, 0, 0 } } };
/* Use loop drop detection */
static int UseLoopDrop=1;
/* To use or not to use Native bridging */
static int UseNativeBridge=1;
/* Use Asterisk Indication or VPB */
static int use_ast_ind=0;
#define TIMER_PERIOD_RINGBACK 2000
#define TIMER_PERIOD_BUSY 700
#define VPB_EVENTS_ALL (VPB_MRING|VPB_MDIGIT|VPB_MDTMF|VPB_MTONEDETECT|VPB_MTIMEREXP|VPB_MPLAY_UNDERFLOW \
|VPB_MRECORD_OVERFLOW|VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
|VPB_MRING_OFF|VPB_MDROP|VPB_MSTATION_FLASH)
#define VPB_EVENTS_NODROP (VPB_MRING|VPB_MDIGIT|VPB_MDTMF|VPB_MTONEDETECT|VPB_MTIMEREXP|VPB_MPLAY_UNDERFLOW \
|VPB_MRECORD_OVERFLOW|VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
|VPB_MRING_OFF|VPB_MSTATION_FLASH)
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#define VPB_EVENTS_NODTMF (VPB_MRING|VPB_MDIGIT|VPB_MTONEDETECT|VPB_MTIMEREXP|VPB_MPLAY_UNDERFLOW \
|VPB_MRECORD_OVERFLOW|VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
|VPB_MRING_OFF|VPB_MDROP|VPB_MSTATION_FLASH)
#define VPB_EVENTS_STAT (VPB_MRING|VPB_MDIGIT|VPB_MDTMF|VPB_MTONEDETECT|VPB_MTIMEREXP|VPB_MPLAY_UNDERFLOW \
|VPB_MRECORD_OVERFLOW|VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
|VPB_MRING_OFF|VPB_MSTATION_FLASH)
// Dialing parameters for Australia
//#define DIAL_WITH_CALL_PROGRESS
VPB_TONE_MAP DialToneMap[] = { { VPB_BUSY_AUST, VPB_CALL_DISCONNECT, 0 },
{ VPB_DIAL, VPB_CALL_DIALTONE, 0 },
{ VPB_RINGBACK_308, VPB_CALL_RINGBACK, 0 },
{ VPB_BUSY_AUST, VPB_CALL_BUSY, 0 },
{ VPB_GRUNT, VPB_CALL_GRUNT, 0 },
{ 0, 0, 1 } };
#define VPB_DIALTONE_WAIT 2000 /* Wait up to 2s for a dialtone */
#define VPB_RINGWAIT 4000 /* Wait up to 4s for ring tone after dialing */
#define VPB_CONNECTED_WAIT 4000 /* If no ring tone detected for 4s then consider call connected */
#define TIMER_PERIOD_NOANSWER 120000 /* Let it ring for 120s before deciding theres noone there */
#define MAX_BRIDGES_V4PCI 2
#define MAX_BRIDGES_V12PCI 128
/* port states */
#define VPB_STATE_ONHOOK 0
#define VPB_STATE_OFFHOOK 1
#define VPB_STATE_DIALLING 2
#define VPB_STATE_JOINED 3
#define VPB_STATE_GETDTMF 4
#define VPB_STATE_PLAYDIAL 5
#define VPB_STATE_PLAYBUSY 6
#define VPB_STATE_PLAYRING 7
typedef struct {
int inuse;
struct ast_channel *c0, *c1, **rc;
struct ast_frame **fo;
int flags;
ast_mutex_t lock;
pthread_cond_t cond;
int endbridge;
static vpb_bridge_t * bridges;
static int max_bridges = MAX_BRIDGES_V4PCI;
AST_MUTEX_DEFINE_STATIC(bridge_lock);
vpb_model_unknown = 0,
vpb_model_v4pci,
vpb_model_v12pci
ast_mutex_t owner_lock; /* Protect blocks that expect ownership to remain the same */
struct ast_channel *owner; /* Channel who owns us, possibly NULL */
int golock; /* Got owner lock ? */
int mode; /* fxo/imediate/dialtone*/
int handle; /* Handle for vpb interface */
int state; /* used to keep port state (internal to driver) */
int group; /* Which group this port belongs to */
char dev[256]; /* Device name, eg vpb/1-1 */
vpb_model_t vpb_model; /* card model */
struct ast_frame f, fr; /* Asterisk frame interface */
char buf[VPB_MAX_BUF]; /* Static buffer for reading frames */
float txgain, rxgain; /* Hardware gain control */
float txswgain, rxswgain; /* Software gain control */
int wantdtmf; /* Waiting for DTMF. */
char context[AST_MAX_EXTENSION]; /* The context for this channel */
char ext[AST_MAX_EXTENSION]; /* DTMF buffer for the ext[ens] */
char language[MAX_LANGUAGE]; /* language being used */
char callerid[AST_MAX_EXTENSION]; /* CallerId used for directly connected phone */
int brcallerpos; /* Brazilian CallerID detection */
int lastoutput; /* Holds the last Audio format output'ed */
int lastinput; /* Holds the last Audio format input'ed */
void *busy_timer; /* Void pointer for busy vpb_timer */
int busy_timer_id; /* unique timer ID for busy timer */
void *ringback_timer; /* Void pointer for ringback vpb_timer */
int ringback_timer_id; /* unique timer ID for ringback timer */
double lastgrunt; /* time stamp (secs since epoc) of last grunt event */
ast_mutex_t lock; /* This one just protects bridge ptr below */
vpb_bridge_t *bridge;
int stopreads; /* Stop reading...*/
int read_state; /* Read state */
int chuck_count; /* a count of packets weve chucked away!*/
pthread_t readthread; /* For monitoring read channel. One per owned channel. */
ast_mutex_t record_lock; /* This one prevents reentering a record_buf block */
ast_mutex_t play_lock; /* This one prevents reentering a play_buf block */
ast_mutex_t play_dtmf_lock;
char play_dtmf[16];
struct vpb_pvt *next; /* Next channel in list */
static struct ast_channel *vpb_new(struct vpb_pvt *i, int state, char *context);
static void *do_chanreads(void *pvt);
// Can't get vpb_bridge() working on v4pci without either a horrible
// high pitched feedback noise or bad hiss noise depending on gain settings
// Get asterisk to do the bridging
#define BAD_V4PCI_BRIDGE
// This one enables a half duplex bridge which may be required to prevent high pitched
// feedback when getting asterisk to do the bridging and when using certain gain settings.
//#define HALF_DUPLEX_BRIDGE
/* This is the Native bridge code, which Asterisk will try before using its own bridging code */
static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
{
struct vpb_pvt *p0 = (struct vpb_pvt *)c0->pvt->pvt;
struct vpb_pvt *p1 = (struct vpb_pvt *)c1->pvt->pvt;
int i, res;
struct ast_channel *cs[3];
struct ast_channel *who;
int to = -1;
struct ast_frame *f;
cs[0] = c0;
cs[1] = c1;
#ifdef BAD_V4PCI_BRIDGE
if(p0->vpb_model==vpb_model_v4pci)
return -2;
#endif
ast_mutex_lock(&p0->lock);
ast_mutex_lock(&p1->lock);
/* Bridge channels, check if we can. I believe we always can, so find a slot.*/
ast_mutex_lock(&bridge_lock); {
for (i = 0; i < max_bridges; i++)
if (!bridges[i].inuse)
break;
if (i < max_bridges) {
bridges[i].inuse = 1;
bridges[i].endbridge = 0;
bridges[i].flags = flags;
bridges[i].rc = rc;
bridges[i].fo = fo;
bridges[i].c0 = c0;
bridges[i].c1 = c1;
}
} ast_mutex_unlock(&bridge_lock);
if (i == max_bridges) {
ast_log(LOG_WARNING, "vpb_bridge: Failed to bridge %s and %s!\n", c0->name, c1->name);
ast_mutex_unlock(&p0->lock);
ast_mutex_unlock(&p1->lock);
/* Set bridge pointers. You don't want to take these locks while holding bridge lock.*/
ast_mutex_lock(&p0->lock); {
p0->bridge = &bridges[i];
} ast_mutex_unlock(&p0->lock);
ast_mutex_lock(&p1->lock); {
p1->bridge = &bridges[i];
} ast_mutex_unlock(&p1->lock);
if (option_verbose>1)
ast_verbose(VERBOSE_PREFIX_2 "vpb_bridge: Bridging call entered with [%s, %s]\n", c0->name, c1->name);
ast_verbose(VERBOSE_PREFIX_2 "vpb_bridge: Starting half-duplex bridge [%s, %s]\n", c0->name, c1->name);
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
int dir = 0;
memset(p0->buf, 0, sizeof p0->buf);
memset(p1->buf, 0, sizeof p1->buf);
vpb_record_buf_start(p0->handle, VPB_ALAW);
vpb_record_buf_start(p1->handle, VPB_ALAW);
vpb_play_buf_start(p0->handle, VPB_ALAW);
vpb_play_buf_start(p1->handle, VPB_ALAW);
while( !bridges[i].endbridge ) {
struct vpb_pvt *from, *to;
if(++dir%2) {
from = p0;
to = p1;
} else {
from = p1;
to = p0;
}
vpb_record_buf_sync(from->handle, from->buf, VPB_SAMPLES);
vpb_play_buf_sync(to->handle, from->buf, VPB_SAMPLES);
}
vpb_record_buf_finish(p0->handle);
vpb_record_buf_finish(p1->handle);
vpb_play_buf_finish(p0->handle);
vpb_play_buf_finish(p1->handle);
if (option_verbose>1)
ast_verbose(VERBOSE_PREFIX_2 "vpb_bridge: Finished half-duplex bridge [%s, %s]\n", c0->name, c1->name);
res = VPB_OK;
#else
res = vpb_bridge(p0->handle, p1->handle, VPB_BRIDGE_ON, i+1 /* resource 1 & 2 only for V4PCI*/ );
if (res == VPB_OK) {
//pthread_cond_wait(&bridges[i].cond, &bridges[i].lock); /* Wait for condition signal. */
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
while( !bridges[i].endbridge ) {
// Are we really ment to be doing nothing ?!?!
who = ast_waitfor_n(cs, 2, &to);
if (!who) {
ast_log(LOG_DEBUG, "vpb_bridge: Empty frame read...\n");
/* check for hangup / whentohangup */
if (ast_check_hangup(c0) || ast_check_hangup(c1))
break;
continue;
}
f = ast_read(who);
if (!f || ((f->frametype == AST_FRAME_DTMF) &&
(((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
*fo = f;
*rc = who;
ast_log(LOG_DEBUG, "vpb_bridge: Got a [%s]\n", f ? "digit" : "hangup");
/*
if ((c0->pvt->pvt == pvt0) && (!c0->_softhangup)) {
if (pr0->set_rtp_peer(c0, NULL, NULL, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
}
if ((c1->pvt->pvt == pvt1) && (!c1->_softhangup)) {
if (pr1->set_rtp_peer(c1, NULL, NULL, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
}
*/
/* That's all we needed */
//return 0;
break;
} else {
if ((f->frametype == AST_FRAME_DTMF) ||
(f->frametype == AST_FRAME_VOICE) ||
(f->frametype == AST_FRAME_VIDEO))
{
/* Forward voice or DTMF frames if they happen upon us */
/* Actually I dont think we want to forward on any frames!
if (who == c0) {
ast_write(c1, f);
} else if (who == c1) {
ast_write(c0, f);
}
*/
}
ast_frfree(f);
}
/* Swap priority not that it's a big deal at this point */
cs[2] = cs[0];
cs[0] = cs[1];
cs[1] = cs[2];
};
vpb_bridge(p0->handle, p1->handle, VPB_BRIDGE_OFF, i+1 /* resource 1 & 2 only for V4PCI*/ );
}
#endif
ast_mutex_lock(&bridge_lock); {
bridges[i].inuse = 0;
} ast_mutex_unlock(&bridge_lock);
if (option_verbose>1)
ast_verbose(VERBOSE_PREFIX_2 "Bridging call done with [%s, %s] => %d\n", c0->name, c1->name, res);
ast_mutex_unlock(&p0->lock);
ast_mutex_unlock(&p1->lock);
}
static double get_time_in_ms()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return ((double)tv.tv_sec*1000)+((double)tv.tv_usec/1000);
}
// Caller ID can be located in different positions between the rings depending on your Telco
// Australian (Telstra) callerid starts 700ms after 1st ring and finishes 1.5s after first ring
// Use ANALYSE_CID to record rings and determine location of callerid
//#define ANALYSE_CID
#define RING_SKIP 600
#define CID_MSECS 1700
static void get_callerid(struct vpb_pvt *p)
{
short buf[CID_MSECS*8]; // 8kHz sampling rate
double cid_record_time;
int rc;
struct ast_channel *owner = p->owner;
void * ws;
char * file="cidsams.wav";
if( ast_mutex_trylock(&p->record_lock) == 0 ) {
char callerid[AST_MAX_EXTENSION] = "";
cid_record_time = get_time_in_ms();
if (option_verbose>3)
ast_verbose(VERBOSE_PREFIX_4 "CID record - start\n");
// Skip any trailing ringtone
vpb_sleep(RING_SKIP);
if (option_verbose>3)
ast_verbose(VERBOSE_PREFIX_4 "CID record - skipped %fms trailing ring\n",
get_time_in_ms() - cid_record_time);
cid_record_time = get_time_in_ms();
// Record bit between the rings which contains the callerid
vpb_record_buf_start(p->handle, VPB_LINEAR);
rc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf));
vpb_record_buf_finish(p->handle);
/*
vpb_wave_open_write(&ws, file, VPB_LINEAR);
vpb_wave_write(ws,(char*)buf,sizeof(buf));
vpb_wave_close_write(ws);
*/
if (option_verbose>3)
ast_verbose(VERBOSE_PREFIX_4 "CID record - recorded %fms between rings\n",
get_time_in_ms() - cid_record_time);
ast_mutex_unlock(&p->record_lock);
if( rc != VPB_OK ) {
ast_log(LOG_ERROR, "Failed to record caller id sample on %s\n", p->dev );
return;
}
VPB_CID *cli_struct = new VPB_CID;
cli_struct->ra_cldn[0]=0;
cli_struct->ra_cn[0]=0;
// This decodes FSK 1200baud type callerid
if ((rc=vpb_cid_decode2(cli_struct, buf, CID_MSECS*8)) == VPB_OK ) {
if (owner->cid.cid_num)
free(owner->cid.cid_num);
owner->cid.cid_num=NULL;
if (owner->cid.cid_name)
free(owner->cid.cid_name);
owner->cid.cid_name=NULL;
if (cli_struct->ra_cldn[0]=='\0'){
owner->cid.cid_num = strdup(cli_struct->cldn);
owner->cid.cid_name = strdup(cli_struct->cn);
if (option_verbose>3)
ast_verbose(VERBOSE_PREFIX_4 "CID record - got [%s] [%s]\n",owner->cid.cid_num,owner->cid.cid_name );
}
else {
ast_log(LOG_ERROR,"CID record - No caller id avalable on %s \n", p->dev);
}
ast_log(LOG_ERROR, "CID record - Failed to decode caller id on %s - %s\n", p->dev, vpb_strerror(rc) );
strncpy(callerid,"unknown", sizeof(callerid) - 1);
delete cli_struct;
ast_log(LOG_ERROR, "CID record - Failed to set record mode for caller id on %s\n", p->dev );
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
static void get_callerid_ast(struct vpb_pvt *p)
{
struct callerid_state *cs;
char buf[1024];
char *name=NULL, *number=NULL;
int flags;
int rc=0,vrc;
int sam_count=0;
struct ast_channel *owner = p->owner;
float old_gain;
int which_cid;
void * ws;
char * file="cidsams.wav";
if(!strcasecmp(p->callerid, "on")) {
if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collected caller ID already\n");
return;
}
else if(!strcasecmp(p->callerid, "v23")) {
which_cid=CID_SIG_V23;
if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID v23[%s/%d]...\n",p->callerid,which_cid);
}
else if(!strcasecmp(p->callerid, "bell")) {
which_cid=CID_SIG_BELL;
if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID bell[%s/%d]...\n",p->callerid,which_cid);
}
else {
if (option_verbose>3)
ast_verbose(VERBOSE_PREFIX_4 "Caller ID disabled\n");
return;
}
if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID type[%s/%d]...\n",p->callerid,which_cid);
// vpb_sleep(RING_SKIP);
// vpb_record_get_gain(p->handle, &old_gain);
cs = callerid_new(which_cid);
if (cs){
// vpb_wave_open_write(&ws, file, VPB_MULAW);
// vpb_record_set_gain(p->handle, 3.0);
// vpb_record_set_hw_gain(p->handle,12.0);
vpb_record_buf_start(p->handle, VPB_MULAW);
while((rc == 0)&&(sam_count<8000*3)){
vrc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf));
if (vrc != VPB_OK)
ast_log(LOG_ERROR, "%s: Caller ID couldnt read audio buffer!\n",p->dev);
rc = callerid_feed(cs,(unsigned char *)buf,sizeof(buf),AST_FORMAT_ULAW);
vpb_wave_write(ws,(char*)buf,sizeof(buf));
sam_count+=sizeof(buf);
if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID samples [%d][%d]...\n",sam_count,rc);
}
vpb_record_buf_finish(p->handle);
// vpb_wave_close_write(ws);
if (rc == 1){
callerid_get(cs, &name, &number, &flags);
if (option_verbose>0)
ast_verbose(VERBOSE_PREFIX_1 "%s: Caller ID name [%s] number [%s] flags [%d]\n",p->dev,name, number,flags);
}
else {
ast_log(LOG_ERROR, "%s: Failed to decode Caller ID \n", p->dev );
}
// vpb_record_set_gain(p->handle, old_gain);
// vpb_record_set_hw_gain(p->handle,6.0);
}
else {
ast_log(LOG_ERROR, "%s: Failed to create Caller ID struct\n", p->dev );
}
if (owner->cid.cid_num) {
free(owner->cid.cid_num);
owner->cid.cid_num = NULL;
}
if (owner->cid.cid_name) {
free(owner->cid.cid_name);
owner->cid.cid_name = NULL;
}
if (number)
ast_shrink_phone_number(number);
if (number && !ast_strlen_zero(number)) {
owner->cid.cid_num = strdup(number);
owner->cid.cid_ani = strdup(number);
}
if (name && !ast_strlen_zero(name))
owner->cid.cid_name = strdup(name);
if (cs)
callerid_free(cs);
}
// Terminate any tones we are presently playing
static void stoptone( int handle)
{
while(vpb_playtone_state(handle)!=VPB_OK){
vpb_tone_terminate(handle);
ret = vpb_get_event_ch_async(handle,&je);
if ((ret == VPB_OK)&&(je.type != VPB_DIALEND)){
if (option_verbose > 3){
ast_verbose(VERBOSE_PREFIX_4 "Stop tone collected a wrong event!![%d]\n",je.type);
static int playtone( int handle, VPB_TONE *tone)
{
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "[%02d]: Playing tone\n", handle);
ret = vpb_playtone_async(handle, tone);
return ret;
static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
{
struct ast_frame f = {AST_FRAME_CONTROL}; /* default is control, Clear rest. */
int endbridge = 0;
int res=0;
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_owned: got event: [%d=>%d]\n",
p->dev, e->type, e->data);
f.src = type;
switch (e->type) {
case VPB_RING:
if (p->mode == MODE_FXO) {
f.subclass = AST_CONTROL_RING;
} else
f.frametype = -1; /* ignore ring on station port. */
break;
case VPB_RING_OFF:
f.frametype = -1;
break;
case VPB_TIMEREXP:
if (e->data == p->busy_timer_id) {
playtone(p->handle,&Busytone);
p->state = VPB_STATE_PLAYBUSY;
vpb_timer_stop(p->busy_timer);
vpb_timer_start(p->busy_timer);
f.frametype = -1;
} else if (e->data == p->ringback_timer_id) {
playtone(p->handle, &Ringbacktone);
vpb_timer_stop(p->ringback_timer);
vpb_timer_start(p->ringback_timer);
f.frametype = -1;
} else {
f.frametype = -1; /* Ignore. */
}
break;
case VPB_DTMF:
if (p->owner->_state == AST_STATE_UP) {
f.frametype = AST_FRAME_DTMF;
f.subclass = e->data;
} else
f.frametype = -1;
break;
case VPB_TONEDETECT:
if (e->data == VPB_BUSY || e->data == VPB_BUSY_308 || e->data == VPB_BUSY_AUST ) {
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_owned: got event: BUSY\n", p->dev);
if (p->owner->_state == AST_STATE_UP) {
f.subclass = AST_CONTROL_HANGUP;
}
else {
f.subclass = AST_CONTROL_BUSY;
}
} else if (e->data == VPB_GRUNT) {
if( ( get_time_in_ms() - p->lastgrunt ) > gruntdetect_timeout ) {
// Nothing heard on line for a very long time
// Timeout connection
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "grunt timeout\n");
ast_log(LOG_NOTICE,"%s: Line hangup due of lack of conversation\n",p->dev);
f.subclass = AST_CONTROL_HANGUP;
} else {
p->lastgrunt = get_time_in_ms();
f.frametype = -1;
}
} else
f.frametype = -1;
break;
case VPB_CALLEND:
#ifdef DIAL_WITH_CALL_PROGRESS
if (e->data == VPB_CALL_CONNECTED)
f.subclass = AST_CONTROL_ANSWER;
else if (e->data == VPB_CALL_NO_DIAL_TONE || e->data == VPB_CALL_NO_RING_BACK)
f.subclass = AST_CONTROL_CONGESTION;
else if (e->data == VPB_CALL_NO_ANSWER || e->data == VPB_CALL_BUSY)
f.subclass = AST_CONTROL_BUSY;
else if (e->data == VPB_CALL_DISCONNECTED)
f.subclass = AST_CONTROL_HANGUP;
#else
ast_log(LOG_NOTICE,"%s: Got call progress callback but blind dialing \n", p->dev);
f.frametype = -1;
#endif
break;
case VPB_STATION_OFFHOOK:
f.subclass = AST_CONTROL_ANSWER;
break;
case VPB_DROP:
if ((p->mode == MODE_FXO)&&(UseLoopDrop)){ /* ignore loop drop on stations */
if (p->owner->_state == AST_STATE_UP)
f.subclass = AST_CONTROL_HANGUP;
else
f.frametype = -1;
}
break;
case VPB_STATION_ONHOOK:
break;
case VPB_STATION_FLASH:
f.subclass = AST_CONTROL_FLASH;
break;
// Called when dialing has finished and ringing starts
// No indication that call has really been answered when using blind dialing
case VPB_DIALEND:
if (p->state < 5){
f.subclass = AST_CONTROL_ANSWER;
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "%s: Dialend\n", p->dev);
} else {
f.frametype = -1;
}
break;
case VPB_PLAY_UNDERFLOW:
f.frametype = -1;
vpb_reset_play_fifo_alarm(p->handle);
break;
case VPB_RECORD_OVERFLOW:
f.frametype = -1;
vpb_reset_record_fifo_alarm(p->handle);
break;
default:
f.frametype = -1;
break;
}
if (option_verbose > 3) ast_verbose("%s: LOCKING in handle_owned [%d]\n", p->dev,res);
res = ast_mutex_lock(&p->lock);
if (option_verbose > 3) ast_verbose("%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
if (p->bridge) { /* Check what happened, see if we need to report it. */
switch (f.frametype) {
case AST_FRAME_DTMF:
if ( !(p->bridge->c0 == p->owner &&
(p->bridge->flags & AST_BRIDGE_DTMF_CHANNEL_0) ) &&
!(p->bridge->c1 == p->owner &&
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
(p->bridge->flags & AST_BRIDGE_DTMF_CHANNEL_1) ))
/* Kill bridge, this is interesting. */
endbridge = 1;
break;
case AST_FRAME_CONTROL:
if (!(p->bridge->flags & AST_BRIDGE_IGNORE_SIGS))
#if 0
if (f.subclass == AST_CONTROL_BUSY ||
f.subclass == AST_CONTROL_CONGESTION ||
f.subclass == AST_CONTROL_HANGUP ||
f.subclass == AST_CONTROL_FLASH)
#endif
endbridge = 1;
break;
default:
break;
}
if (endbridge) {
if (p->bridge->fo)
*p->bridge->fo = ast_frisolate(&f);
if (p->bridge->rc)
*p->bridge->rc = p->owner;
ast_mutex_lock(&p->bridge->lock); {
p->bridge->endbridge = 1;
pthread_cond_signal(&p->bridge->cond);
} ast_mutex_unlock(&p->bridge->lock);
}
if (endbridge){
res = ast_mutex_unlock(&p->lock);
if (option_verbose > 3) ast_verbose("%s: unLOCKING in handle_owned [%d]\n", p->dev,res);
return 0;
}
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_owned: Prepared frame type[%d]subclass[%d], bridge=%p owner=[%s]\n",
p->dev, f.frametype, f.subclass, (void *)p->bridge, p->owner->name);
// Trylock used here to avoid deadlock that can occur if we
// happen to be in here handling an event when hangup is called
// Problem is that hangup holds p->owner->lock
if ((f.frametype >= 0)&& (f.frametype != AST_FRAME_NULL)&&(p->owner)) {
if (ast_mutex_trylock(&p->owner->lock)==0) {
Mark Spencer
committed
ast_queue_frame(p->owner, &f);
ast_mutex_unlock(&p->owner->lock);
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "%s: handled_owned: Queued Frame to [%s]\n", p->dev,p->owner->name);
res = ast_mutex_unlock(&p->lock);
if (option_verbose > 3) ast_verbose("%s: unLOCKING in handle_owned [%d]\n", p->dev,res);
}
static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
{
if (option_verbose > 3) {
char str[VPB_MAX_STR];
vpb_translate_event(e, str);
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: mode=%d, event[%d][%s]=[%d]\n",
p->dev, p->mode, e->type,str, e->data);
}
switch(e->type) {
case VPB_RING:
if (p->mode == MODE_FXO) /* FXO port ring, start * */ {
vpb_new(p, AST_STATE_RING, p->context);
if(!strcasecmp(p->callerid, "on")) {
if (option_verbose>3)
ast_verbose(VERBOSE_PREFIX_4 "Using VPB Caller ID\n");
get_callerid(p); // Australian Caller ID only between 1st and 2nd ring
}
get_callerid_ast(p); // Caller ID using the ast functions
}
break;
case VPB_RING_OFF:
break;
case VPB_STATION_OFFHOOK:
if (p->mode == MODE_IMMEDIATE)
vpb_new(p,AST_STATE_RING, p->context);
else {
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: playing dialtone\n",p->dev);
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
playtone(p->handle, &Dialtone);
p->wantdtmf = 1;
p->ext[0] = 0; /* Just to be sure & paranoid.*/
p->state=VPB_STATE_PLAYDIAL;
}
break;
case VPB_DIALEND:
if (p->mode == MODE_DIALTONE){
if (p->state == VPB_STATE_PLAYDIAL) {
playtone(p->handle, &Dialtone);
p->wantdtmf = 1;
p->ext[0] = 0; // Just to be sure & paranoid.
}
/* These are not needed as they have timers to restart them
else if (p->state == VPB_STATE_PLAYBUSY) {
playtone(p->handle, &Busytone);
p->wantdtmf = 1;
p->ext[0] = 0; // Just to be sure & paranoid.
}
else if (p->state == VPB_STATE_PLAYRING) {
playtone(p->handle, &Ringbacktone);
p->wantdtmf = 1;
p->ext[0] = 0; // Just to be sure & paranoid.
}
*/
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: Got a DIALEND when not really expected\n",p->dev);
}
break;
case VPB_STATION_ONHOOK: /* clear ext */
stoptone(p->handle);
p->wantdtmf = 1 ;
p->ext[0] = 0;
p->state=VPB_STATE_ONHOOK;
break;
case VPB_DTMF:
if (p->state == VPB_STATE_ONHOOK){
/* DTMF's being passed while on-hook maybe Caller ID */
break;
}
if (p->wantdtmf == 1) {
stoptone(p->handle);
p->wantdtmf = 0;
}
p->state=VPB_STATE_GETDTMF;
s[0] = e->data;
strncat(p->ext, s, sizeof(p->ext) - strlen(p->ext) - 1);
if (ast_exists_extension(NULL, p->context, p->ext, 1, p->callerid)){
if (option_verbose > 3) {
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: Matched on [%s] in [%s]\n", p->dev,p->ext , p->context);
}
vpb_new(p,AST_STATE_RING, p->context);
} else if (!ast_canmatch_extension(NULL, p->context, p->ext, 1, p->callerid)){
if (ast_exists_extension(NULL, "default", p->ext, 1, p->callerid)) {
vpb_new(p,AST_STATE_RING, "default");
} else if (!ast_canmatch_extension(NULL, "default", p->ext, 1, p->callerid)) {
if (option_verbose > 3) {
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: can't match anything in %s or default\n",
p->dev, p->context);
}
playtone(p->handle, &Busytone);
vpb_timer_stop(p->busy_timer);
vpb_timer_start(p->busy_timer);
}
break;
default:
/* Ignore.*/
break;
}
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: mode=%d, [%d=>%d]\n",