📄 chan_misdn.c
字号:
/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 2004 - 2006, Christian Richter * * Christian Richter <crich@beronet.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 the chan_misdn channel driver for Asterisk * \author Christian Richter <crich@beronet.com> * * \ingroup channel_drivers *//*** MODULEINFO <depend>isdnnet</depend> <depend>misdn</depend> <depend>suppserv</depend> ***/#include "asterisk.h"ASTERISK_FILE_VERSION(__FILE__, "$Revision: 136241 $")#include <stdio.h>#include <pthread.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 <signal.h>#include <sys/file.h>#include <semaphore.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/io.h"#include "asterisk/frame.h"#include "asterisk/translate.h"#include "asterisk/cli.h"#include "asterisk/musiconhold.h"#include "asterisk/dsp.h"#include "asterisk/translate.h"#include "asterisk/config.h"#include "asterisk/file.h"#include "asterisk/callerid.h"#include "asterisk/indications.h"#include "asterisk/app.h"#include "asterisk/features.h"#include "asterisk/term.h"#include "asterisk/sched.h"#include "asterisk/stringfields.h"#include "chan_misdn_config.h"#include "isdn_lib.h"char global_tracefile[BUFFERSIZE+1];static int g_config_initialized=0;struct misdn_jb{ int size; int upper_threshold; char *samples, *ok; int wp,rp; int state_empty; int state_full; int state_buffer; int bytes_wrote; ast_mutex_t mutexjb;};/* allocates the jb-structure and initialize the elements*/struct misdn_jb *misdn_jb_init(int size, int upper_threshold);/* frees the data and destroys the given jitterbuffer struct */void misdn_jb_destroy(struct misdn_jb *jb);/* fills the jitterbuffer with len data returns < 0 if there was anerror (buffer overrun). */int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);/* gets len bytes out of the jitterbuffer if available, else only theavailable data is returned and the return value indicates the numberof data. */int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);/* BEGIN: chan_misdn.h */ast_mutex_t release_lock;enum misdn_chan_state { MISDN_NOTHING=0, /*!< at beginning */ MISDN_WAITING4DIGS, /*!< when waiting for infos */ MISDN_EXTCANTMATCH, /*!< when asterisk couldn't match our ext */ MISDN_INCOMING_SETUP, /*!< for incoming setups*/ MISDN_DIALING, /*!< when pbx_start */ MISDN_PROGRESS, /*!< we got a progress */ MISDN_PROCEEDING, /*!< we got a progress */ MISDN_CALLING, /*!< when misdn_call is called */ MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */ MISDN_ALERTING, /*!< when Alerting */ MISDN_BUSY, /*!< when BUSY */ MISDN_CONNECTED, /*!< when connected */ MISDN_PRECONNECTED, /*!< when connected */ MISDN_DISCONNECTED, /*!< when connected */ MISDN_RELEASED, /*!< when connected */ MISDN_BRIDGED, /*!< when bridged */ MISDN_CLEANING, /*!< when hangup from * but we were connected before */ MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP cam from misdn */ MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of */ /* misdn_hangup */ MISDN_HOLDED, /*!< if this chan is holded */ MISDN_HOLD_DISCONNECT, /*!< if this chan is holded */ };#define ORG_AST 1#define ORG_MISDN 2struct hold_info { int port; int channel;};struct chan_list { char allowed_bearers[BUFFERSIZE+1]; enum misdn_chan_state state; int need_queue_hangup; int need_hangup; int need_busy; int noautorespond_on_setup; int originator; int norxtone; int notxtone; int toggle_ec; int incoming_early_audio; int ignore_dtmf; int pipe[2]; char ast_rd_buf[4096]; struct ast_frame frame; int faxdetect; /* 0:no 1:yes 2:yes+nojump */ int faxdetect_timeout; struct timeval faxdetect_tv; int faxhandled; int ast_dsp; int jb_len; int jb_upper_threshold; struct misdn_jb *jb; struct ast_dsp *dsp; struct ast_trans_pvt *trans; struct ast_channel * ast; int dummy; struct misdn_bchannel *bc; struct hold_info hold_info; unsigned int l3id; int addr; char context[BUFFERSIZE]; int zero_read_cnt; int dropped_frame_cnt; int far_alerting; int nttimeout; int other_pid; struct chan_list *other_ch; const struct ind_tone_zone_sound *ts; int overlap_dial; int overlap_dial_task; ast_mutex_t overlap_tv_lock; struct timeval overlap_tv; struct chan_list *peer; struct chan_list *next; struct chan_list *prev; struct chan_list *first;};void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);struct robin_list { char *group; int port; int channel; struct robin_list *next; struct robin_list *prev;};static struct robin_list *robin = NULL;static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);static inline void free_robin_list_r (struct robin_list *r){ if (r) { if (r->next) free_robin_list_r(r->next); if (r->group) free(r->group); free(r); }}static void free_robin_list ( void ){ free_robin_list_r(robin); robin = NULL;}static struct robin_list* get_robin_position (char *group) { struct robin_list *new; struct robin_list *iter = robin; for (; iter; iter = iter->next) { if (!strcasecmp(iter->group, group)) return iter; } new = (struct robin_list *)calloc(1, sizeof(struct robin_list)); new->group = strndup(group, strlen(group)); new->port = 0; new->channel = 0; if (robin) { new->next = robin; robin->prev = new; } robin = new; return robin;}/* the main schedule context for stuff like l1 watcher, overlap dial, ... */static struct sched_context *misdn_tasks = NULL;static pthread_t misdn_tasks_thread;static int *misdn_ports;static void chan_misdn_log(int level, int port, char *tmpl, ...);static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c);static void send_digit_to_chan(struct chan_list *cl, char digit );static void hangup_chan(struct chan_list *ch);static int pbx_start_chan(struct chan_list *ch);#define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt#define MISDN_ASTERISK_PVT(ast) 1#include <asterisk/strings.h>/* #define MISDN_DEBUG 1 */static const char misdn_type[] = "mISDN";static int tracing = 0 ;/* Only alaw and mulaw is allowed for now */static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */static int *misdn_debug;static int *misdn_debug_only;static int max_ports;static int *misdn_in_calls;static int *misdn_out_calls;struct chan_list dummy_cl;struct chan_list *cl_te=NULL;ast_mutex_t cl_te_lock;static enum event_response_ecb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch);static void cl_queue_chan(struct chan_list **list, struct chan_list *chan);static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan);static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc);static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid);static int dialtone_indicate(struct chan_list *cl);static int hanguptone_indicate(struct chan_list *cl);static int stop_indicate(struct chan_list *cl);static int start_bc_tones(struct chan_list *cl);static int stop_bc_tones(struct chan_list *cl);static void release_chan(struct misdn_bchannel *bc);static int misdn_check_l2l1(struct ast_channel *chan, void *data);static int misdn_set_opt_exec(struct ast_channel *chan, void *data);static int misdn_facility_exec(struct ast_channel *chan, void *data);int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);void debug_numplan(int port, int numplan, char *type);int add_out_calls(int port);int add_in_calls(int port);#ifdef MISDN_1_2static int update_pipeline_config(struct misdn_bchannel *bc);#elsestatic int update_ec_config(struct misdn_bchannel *bc);#endif/*************** Helpers *****************/static struct chan_list * get_chan_by_ast(struct ast_channel *ast){ struct chan_list *tmp; for (tmp=cl_te; tmp; tmp = tmp->next) { if ( tmp->ast == ast ) return tmp; } return NULL;}static struct chan_list * get_chan_by_ast_name(char *name){ struct chan_list *tmp; for (tmp=cl_te; tmp; tmp = tmp->next) { if ( tmp->ast && strcmp(tmp->ast->name,name) == 0) return tmp; } return NULL;}struct allowed_bearers { int cap; int val; char *name; int deprecated;};static struct allowed_bearers allowed_bearers_array[]= { {INFO_CAPABILITY_SPEECH,1,"speech"}, {INFO_CAPABILITY_AUDIO_3_1K,2,"3_1khz"}, {INFO_CAPABILITY_DIGITAL_UNRESTRICTED,4,"digital_unrestricted"}, {INFO_CAPABILITY_DIGITAL_RESTRICTED,8,"digital_restricted"}, {INFO_CAPABILITY_DIGITAL_RESTRICTED,8,"digital_restriced", 1}, /* Allow misspelling for backwards compatibility */ {INFO_CAPABILITY_VIDEO,16,"video"}};static char *bearer2str(int cap) { static char *bearers[]={ "Speech", "Audio 3.1k", "Unres Digital", "Res Digital", "Video", "Unknown Bearer" }; switch (cap) { case INFO_CAPABILITY_SPEECH: return bearers[0]; break; case INFO_CAPABILITY_AUDIO_3_1K: return bearers[1]; break; case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: return bearers[2]; break; case INFO_CAPABILITY_DIGITAL_RESTRICTED: return bearers[3]; break; case INFO_CAPABILITY_VIDEO: return bearers[4]; break; default: return bearers[5]; break; }}static void print_facility(struct FacParm *fac, struct misdn_bchannel *bc){ switch (fac->Function) { case Fac_CD: chan_misdn_log(1,bc->port," --> calldeflect to: %s, screened: %s\n", fac->u.CDeflection.DeflectedToNumber, fac->u.CDeflection.PresentationAllowed ? "yes" : "no"); break; case Fac_AOCDCurrency: if (fac->u.AOCDcur.chargeNotAvailable) chan_misdn_log(1,bc->port," --> AOCD currency: charge not available\n"); else if (fac->u.AOCDcur.freeOfCharge) chan_misdn_log(1,bc->port," --> AOCD currency: free of charge\n"); else if (fac->u.AOCDchu.billingId >= 0) chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%d billingId:%d\n", fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier, (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId); else chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%d\n", fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier, (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total"); break; case Fac_AOCDChargingUnit: if (fac->u.AOCDchu.chargeNotAvailable) chan_misdn_log(1,bc->port," --> AOCD charging unit: charge not available\n"); else if (fac->u.AOCDchu.freeOfCharge) chan_misdn_log(1,bc->port," --> AOCD charging unit: free of charge\n"); else if (fac->u.AOCDchu.billingId >= 0) chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n", fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId); else chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n", fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total"); break; default: chan_misdn_log(1,bc->port," --> unknown\n"); }}static void print_bearer(struct misdn_bchannel *bc) { chan_misdn_log(2, bc->port, " --> Bearer: %s\n",bearer2str(bc->capability)); switch(bc->law) { case INFO_CODEC_ALAW: chan_misdn_log(2, bc->port, " --> Codec: Alaw\n"); break; case INFO_CODEC_ULAW: chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n"); break; }}static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc){ char buf[128]; if (!ast) return; if (originator == ORG_AST) { ast = ast_bridged_channel(ast); if (!ast) return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -