📄 chan_vpb.cc
字号:
/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 2003, Paul Bagyenda * Paul Bagyenda <bagyenda@dsmagic.com> * Copyright (C) 2004 - 2005, 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 * * 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 VoiceTronix Interface driver * * \ingroup channel_drivers *//*** MODULEINFO <depend>vpbapi</depend> ***/#include <vpbapi.h>extern "C" {#include "asterisk.h"ASTERISK_FILE_VERSION(__FILE__, "$Revision: 114180 $")#include <stdio.h>#include <string.h>#include "asterisk/lock.h"#include "asterisk/utils.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/callerid.h"#include "asterisk/dsp.h"#include "asterisk/features.h"#include "asterisk/musiconhold.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 <assert.h>#ifdef pthread_create#undef pthread_create#endif#define DEFAULT_GAIN 0#define DEFAULT_ECHO_CANCEL 1 #define VPB_SAMPLES 160 #define VPB_MAX_BUF VPB_SAMPLES*4 + AST_FRIENDLY_OFFSET#define VPB_NULL_EVENT 200#define VPB_WAIT_TIMEOUT 4000#define MAX_VPB_GAIN 12.0#define MIN_VPB_GAIN -12.0#define DTMF_CALLERID #define DTMF_CID_START 'D'#define DTMF_CID_STOP 'C'/**/#if defined(__cplusplus) || defined(c_plusplus) extern "C" {#endif/**/static const char desc[] = "VoiceTronix V6PCI/V12PCI/V4PCI API Support";static const char tdesc[] = "Standard VoiceTronix API Driver";static const char config[] = "vpb.conf";/* Backwards compatibility from trunk */#define ast_verb(level, ...) do { \ if (option_verbose >= level) { \ if (level >= 4) \ ast_verbose(VERBOSE_PREFIX_4 __VA_ARGS__); \ else if (level == 3) \ ast_verbose(VERBOSE_PREFIX_3 __VA_ARGS__); \ else if (level == 2) \ ast_verbose(VERBOSE_PREFIX_2 __VA_ARGS__); \ else if (level == 1) \ ast_verbose(VERBOSE_PREFIX_1 __VA_ARGS__); \ else \ ast_verbose(__VA_ARGS__); \ } \} while (0)#define ast_debug(level, ...) do { \ if (option_debug >= (level)) \ ast_log(LOG_DEBUG, __VA_ARGS__); \} while (0)/* Default context for dialtone mode */static char context[AST_MAX_EXTENSION] = "default";/* Default language */static char language[MAX_LANGUAGE] = "";static int gruntdetect_timeout = 3600000; /* Grunt detect timeout is 1hr. */static const int prefformat = AST_FORMAT_SLINEAR;/* Protect the interface list (of vpb_pvt's) */AST_MUTEX_DEFINE_STATIC(iflock);/* Protect the monitoring thread, so only one process can kill or start it, and not when it's doing something critical. */AST_MUTEX_DEFINE_STATIC(monlock);/* 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;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/* Pick a country or add your own! *//* These are the tones that are played to the user */#define TONES_AU/* #define TONES_USA */#ifdef TONES_AUstatic 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#ifdef TONES_USAstatic VPB_TONE Dialtone = {350, 440, 0, -16, -16, -100, 10000, 0};static VPB_TONE Busytone = {480, 620, 0, -10, -10, -100, 500, 500};static VPB_TONE Ringbacktone = {440, 480, 0, -20, -20, -100, 2000, 4000};#endif/* grunt tone defn's */#if 0static 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 } } };#endifstatic VPB_DETECT toned_ungrunt = { 2, VPB_GRUNT, 1, 2000, 1, 0, 0, -40, 0, 0, 30, 40, { { 0, 0, 0, 0 } } };/* Use loop polarity detection for CID */static int UsePolarityCID=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;/* Use Asterisk DTMF detection or VPB */static int use_ast_dtmfdet=0;static int relaxdtmf=0;/* Use Asterisk DTMF play back or VPB */static int use_ast_dtmf=0;/* Break for DTMF on native bridge ? */static int break_for_dtmf=1;/* Set EC suppression threshold */static short ec_supp_threshold=-1;/* Inter Digit Delay for collecting DTMF's */static int dtmf_idd = 3000;#define TIMER_PERIOD_RINGBACK 2000#define TIMER_PERIOD_BUSY 700#define TIMER_PERIOD_RING 4000static int timer_period_ring = TIMER_PERIOD_RING; #define VPB_EVENTS_ALL (VPB_MRING|VPB_MDIGIT|VPB_MDTMF|VPB_MTONEDETECT|VPB_MTIMEREXP \ |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_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \ |VPB_MRING_OFF|VPB_MSTATION_FLASH)#define VPB_EVENTS_NODTMF (VPB_MRING|VPB_MDIGIT|VPB_MTONEDETECT|VPB_MTIMEREXP \ |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_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, VPB_CALL_DISCONNECT, 0 }, { VPB_DIAL, VPB_CALL_DIALTONE, 0 }, { VPB_RINGBACK, VPB_CALL_RINGBACK, 0 }, { VPB_BUSY, 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#define VPB_GOT_RXHWG 1#define VPB_GOT_TXHWG 2#define VPB_GOT_RXSWG 4#define VPB_GOT_TXSWG 8typedef struct { int inuse; struct ast_channel *c0, *c1, **rc; struct ast_frame **fo; int flags; ast_mutex_t lock; ast_cond_t cond; int endbridge;} vpb_bridge_t;static vpb_bridge_t * bridges;static int max_bridges = MAX_BRIDGES_V4PCI;AST_MUTEX_DEFINE_STATIC(bridge_lock);typedef enum { vpb_model_unknown = 0, vpb_model_v4pci, vpb_model_v12pci} vpb_model_t;static struct vpb_pvt { 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 */ ast_group_t callgroup; /* Call group */ ast_group_t pickupgroup; /* Pickup group */ 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 */ int dialtone; /* NOT USED */ 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 callerid_type; /* Caller ID type: 0=>none 1=>vpb 2=>AstV23 3=>AstBell */ char cid_num[AST_MAX_EXTENSION]; char cid_name[AST_MAX_EXTENSION]; int dtmf_caller_pos; /* DTMF CallerID detection (Brazil)*/ int lastoutput; /* Holds the last Audio format output'ed */ int lastinput; /* Holds the last Audio format input'ed */ int last_ignore_dtmf; 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 */ void *ring_timer; /* Void pointer for ring vpb_timer */ int ring_timer_id; /* unique timer ID for ring timer */ void *dtmfidd_timer; /* Void pointer for DTMF IDD vpb_timer */ int dtmfidd_timer_id; /* unique timer ID for DTMF IDD timer */ struct ast_dsp *vad; /* AST Voice Activation Detection dsp */ struct timeval lastgrunt; /* time stamp 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 */ int play_buf_time; /* How long the last play_buf took */ struct timeval lastplay; /* Last play time */ ast_mutex_t play_dtmf_lock; char play_dtmf[16]; int faxhandled; /* has a fax tone been handled ? */ struct vpb_pvt *next; /* Next channel in list */} *iflist = NULL;static struct ast_channel *vpb_new(struct vpb_pvt *i, enum ast_channel_state state, const char *context);static void *do_chanreads(void *pvt);static struct ast_channel *vpb_request(const char *type, int format, void *data, int *cause);static int vpb_digit_begin(struct ast_channel *ast, char digit);static int vpb_digit_end(struct ast_channel *ast, char digit, unsigned int duration);static int vpb_call(struct ast_channel *ast, char *dest, int timeout);static int vpb_hangup(struct ast_channel *ast);static int vpb_answer(struct ast_channel *ast);static struct ast_frame *vpb_read(struct ast_channel *ast);static int vpb_write(struct ast_channel *ast, struct ast_frame *frame);static enum ast_bridge_result ast_vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);static struct ast_channel_tech vpb_tech = { type: "vpb", description: tdesc, capabilities: AST_FORMAT_SLINEAR, properties: 0, requester: vpb_request, devicestate: NULL, send_digit_begin: vpb_digit_begin, send_digit_end: vpb_digit_end, call: vpb_call, hangup: vpb_hangup, answer: vpb_answer, read: vpb_read, write: vpb_write, send_text: NULL, send_image: NULL, send_html: NULL, exception: NULL, bridge: ast_vpb_bridge, indicate: vpb_indicate, fixup: vpb_fixup, setoption: NULL, queryoption: NULL, transfer: NULL, write_video: NULL, bridged_channel: NULL};static struct ast_channel_tech vpb_tech_indicate = { type: "vpb", description: tdesc, capabilities: AST_FORMAT_SLINEAR, properties: 0, requester: vpb_request, devicestate: NULL, send_digit_begin: vpb_digit_begin, send_digit_end: vpb_digit_end, call: vpb_call, hangup: vpb_hangup, answer: vpb_answer, read: vpb_read, write: vpb_write, send_text: NULL, send_image: NULL, send_html: NULL, exception: NULL, bridge: ast_vpb_bridge, indicate: NULL, fixup: vpb_fixup, setoption: NULL, queryoption: NULL, transfer: NULL, write_video: NULL, bridged_channel: NULL};/* Can't get ast_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 enum ast_bridge_result ast_vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms){ struct vpb_pvt *p0 = (struct vpb_pvt *)c0->tech_pvt; struct vpb_pvt *p1 = (struct vpb_pvt *)c1->tech_pvt; int i; int res; struct ast_channel *cs[3]; struct ast_channel *who; struct ast_frame *f; cs[0] = c0; cs[1] = c1; #ifdef BAD_V4PCI_BRIDGE if (p0->vpb_model==vpb_model_v4pci)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -