diff options
author | crichter <crichter@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-17 21:57:19 +0000 |
---|---|---|
committer | crichter <crichter@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-17 21:57:19 +0000 |
commit | a16d56835cd72deab9e7fef2386536eb4420f0be (patch) | |
tree | c1a9895e91b73c87eca474c56f008d8791ee2367 /channels/chan_misdn.c | |
parent | 73270eca9183395525ff214e19e8e1aa9149c359 (diff) |
This rather small ;-) commit merges the changes from my team branch 0.3.0 into t
he 1.2 branch.
These changes include the new mISDN mqueue interface which makes it possible to
compile chan_misdn against the current cvs version of mISDN/mISDNuser.
These changes also contain various additions and numerous bugfixes to chan_misdn
.
Each change is documented in the commit logs in the team/crichter/0.3.0 branch.
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.2@40306 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_misdn.c')
-rw-r--r-- | channels/chan_misdn.c | 3227 |
1 files changed, 2056 insertions, 1171 deletions
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index a170105ff..5b322f6bf 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -59,28 +59,63 @@ #include <asterisk/app.h> #include <asterisk/features.h> -#include "chan_misdn_config.h" -#include "isdn_lib.h" +#include <chan_misdn_config.h> +#include <isdn_lib.h> + +char global_tracefile[BUFFERSIZE+1]; + + +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 initialise 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 an +error (bufferoverun). */ +int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len); + +/* gets len bytes out of the jitterbuffer if available, else only the +available data is returned and the return value indicates the number +of data. */ +int misdn_jb_empty(struct misdn_jb *jb, char *data, int len); -ast_mutex_t release_lock_mutex; -#define release_lock ast_mutex_lock(&release_lock_mutex) -#define release_unlock ast_mutex_unlock(&release_lock_mutex) /* BEGIN: chan_misdn.h */ + + enum misdn_chan_state { MISDN_NOTHING, /*!< at beginning */ MISDN_WAITING4DIGS, /*!< when waiting for infos */ MISDN_EXTCANTMATCH, /*!< when asterisk couldnt match our ext */ 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 */ @@ -98,13 +133,24 @@ struct chan_list { ast_mutex_t lock; + char allowed_bearers[BUFFERSIZE+1]; + enum misdn_chan_state state; - int holded; + int need_queue_hangup; + int need_hangup; + int need_busy; + int orginator; 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; @@ -113,17 +159,34 @@ struct chan_list { 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 misdn_bchannel *holded_bc; unsigned int l3id; int addr; + + char context[BUFFERSIZE]; + + int zero_read_cnt; + int dropped_frame_cnt; + + int far_alerting; + int other_pid; + struct chan_list *other_ch; + + const struct tone_zone_sound *ts; struct chan_list *peer; struct chan_list *next; @@ -131,6 +194,11 @@ struct chan_list { 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; @@ -140,13 +208,19 @@ struct robin_list { }; static struct robin_list *robin = NULL; + + +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); - } + 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 ) @@ -155,7 +229,7 @@ static void free_robin_list ( void ) robin = NULL; } -struct robin_list* get_robin_position (char *group) +static struct robin_list* get_robin_position (char *group) { struct robin_list *iter = robin; for (; iter; iter = iter->next) { @@ -173,8 +247,11 @@ struct robin_list* get_robin_position (char *group) return robin; } -struct ast_channel *misdn_new(struct chan_list *cl, int state, char * name, char * context, char *exten, char *callerid, int format, int port, int c); -void send_digit_to_chan(struct chan_list *cl, char digit ); + +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 ); #define AST_CID_P(ast) ast->cid.cid_num @@ -184,48 +261,50 @@ void send_digit_to_chan(struct chan_list *cl, char digit ); #define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt #define MISDN_ASTERISK_PVT(ast) 1 -#define MISDN_ASTERISK_TYPE(ast) ast->tech->type - -/* END: chan_misdn.h */ #include <asterisk/strings.h> /* #define MISDN_DEBUG 1 */ -static char *desc = "Channel driver for mISDN Support (Bri/Pri)"; -static char *type = "mISDN"; +static char *desc = "Channel driver for mISDN Support (Bri/Pri)"; +static const char misdn_type[] = "mISDN"; -int tracing = 0 ; +static int tracing = 0 ; static int usecnt=0; -char **misdn_key_vector=NULL; -int misdn_key_vector_size=0; +static char **misdn_key_vector=NULL; +static int misdn_key_vector_size=0; /* Only alaw and mulaw is allowed for now */ static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */ static ast_mutex_t usecnt_lock; -int *misdn_debug; -int *misdn_debug_only; -int max_ports; +static int *misdn_debug; +static int *misdn_debug_only; +static int max_ports; struct chan_list dummy_cl; struct chan_list *cl_te=NULL; ast_mutex_t cl_te_lock; -enum event_response_e +static enum event_response_e cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data); -void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc); +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); -void cl_queue_chan(struct chan_list **list, struct chan_list *chan); -void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan); -struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc); -void chan_misdn_log(int level, int port, char *tmpl, ...); -void chan_misdn_trace_call(struct ast_channel *chan, int debug, char *tmpl, ...); + + +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); @@ -234,6 +313,10 @@ static void release_chan(struct misdn_bchannel *bc); 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); + +static int update_ec_config(struct misdn_bchannel *bc); + /*************** Helpers *****************/ static struct chan_list * get_chan_by_ast(struct ast_channel *ast) @@ -258,25 +341,21 @@ static struct chan_list * get_chan_by_ast_name(char *name) return NULL; } -static char* tone2str(struct misdn_bchannel *bc) -{ - static struct { - char name[16]; - enum tone_e tone; - } *tone, tone_buf[] = { - {"NOTONE",TONE_NONE}, - {"DIAL",TONE_DIAL}, - {"BUSY",TONE_BUSY}, - {"ALERT",TONE_ALERTING}, - {"",TONE_NONE} - }; - - - for (tone=&tone_buf[0]; tone->name[0]; tone++) { - if (tone->tone == bc->tone) return tone->name; - } - return NULL; -} + + +struct allowed_bearers { + int cap; + int val; + char *name; +}; + +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_restriced"}, + {INFO_CAPABILITY_VIDEO,16,"video"} +}; static char *bearer2str(int cap) { static char *bearers[]={ @@ -284,6 +363,7 @@ static char *bearer2str(int cap) { "Audio 3.1k", "Unres Digital", "Res Digital", + "Video", "Unknown Bearer" }; @@ -300,9 +380,30 @@ static char *bearer2str(int cap) { case INFO_CAPABILITY_DIGITAL_RESTRICTED: return bearers[3]; break; - default: + case INFO_CAPABILITY_VIDEO: return bearers[4]; break; + default: + return bearers[5]; + break; + } +} + + +static void print_facility( struct misdn_bchannel *bc) +{ + switch (bc->fac_type) { + case FACILITY_CALLDEFLECT: + chan_misdn_log(2,bc->port," --> calldeflect: %s\n", + bc->fac.calldeflect_nr); + break; + case FACILITY_CENTREX: + chan_misdn_log(2,bc->port," --> centrex: %s\n", + bc->fac.cnip); + break; + default: + chan_misdn_log(2,bc->port," --> unknown\n"); + } } @@ -322,7 +423,7 @@ static void print_bearer(struct misdn_bchannel *bc) } /*************** Helpers END *************/ -void send_digit_to_chan(struct chan_list *cl, char digit ) +static void send_digit_to_chan(struct chan_list *cl, char digit ) { static const char* dtmf_tones[] = { "!941+1336/100,!0/100", /* 0 */ @@ -416,10 +517,38 @@ static int misdn_set_debug(int fd, int argc, char *argv[]) return 0; } - static int misdn_set_crypt_debug(int fd, int argc, char *argv[]) { - if (argc != 5 )return RESULT_SHOWUSAGE; + if (argc != 5) return RESULT_SHOWUSAGE; + + return 0; +} + + +static int misdn_port_block(int fd, int argc, char *argv[]) +{ + int port; + + if (argc != 4) + return RESULT_SHOWUSAGE; + + port = atoi(argv[3]); + + misdn_lib_port_block(port); + + return 0; +} + +static int misdn_port_unblock(int fd, int argc, char *argv[]) +{ + int port; + + if (argc != 4) + return RESULT_SHOWUSAGE; + + port = atoi(argv[3]); + + misdn_lib_port_unblock(port); return 0; } @@ -453,6 +582,20 @@ static int misdn_port_up (int fd, int argc, char *argv[]) return 0; } +static int misdn_port_down (int fd, int argc, char *argv[]) +{ + int port; + + if (argc != 4) + return RESULT_SHOWUSAGE; + + port = atoi(argv[3]); + + misdn_lib_get_port_down(port); + + return 0; +} + static int misdn_show_config (int fd, int argc, char *argv[]) { @@ -470,12 +613,12 @@ static int misdn_show_config (int fd, int argc, char *argv[]) if (argc == 3 || onlyport == 0) { ast_cli(fd,"Misdn General-Config: \n"); - ast_cli(fd," -> VERSION: " CHAN_MISDN_VERSION "\n"); - + ast_cli(fd," -> Version: chan_misdn-" CHAN_MISDN_VERSION "\n"); for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) { misdn_cfg_get_config_string( 0, elem, buffer, BUFFERSIZE); ast_cli(fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : ""); } + ast_cli(fd, "\n"); } if (onlyport < 0) { @@ -505,23 +648,26 @@ static int misdn_show_config (int fd, int argc, char *argv[]) return 0; } - - struct state_struct { enum misdn_chan_state state; char txt[255] ; } ; -struct state_struct state_array[] = { +static struct state_struct state_array[] = { {MISDN_NOTHING,"NOTHING"}, /* at beginning */ {MISDN_WAITING4DIGS,"WAITING4DIGS"}, /* when waiting for infos */ {MISDN_EXTCANTMATCH,"EXTCANTMATCH"}, /* when asterisk couldnt match our ext */ {MISDN_DIALING,"DIALING"}, /* when pbx_start */ {MISDN_PROGRESS,"PROGRESS"}, /* when pbx_start */ + {MISDN_PROCEEDING,"PROCEEDING"}, /* when pbx_start */ {MISDN_CALLING,"CALLING"}, /* when misdn_call is called */ + {MISDN_CALLING_ACKNOWLEDGE,"CALLING_ACKNOWLEDGE"}, /* when misdn_call is called */ {MISDN_ALERTING,"ALERTING"}, /* when Alerting */ {MISDN_BUSY,"BUSY"}, /* when BUSY */ {MISDN_CONNECTED,"CONNECTED"}, /* when connected */ + {MISDN_PRECONNECTED,"PRECONNECTED"}, /* when connected */ + {MISDN_DISCONNECTED,"DISCONNECTED"}, /* when connected */ + {MISDN_RELEASED,"RELEASED"}, /* when connected */ {MISDN_BRIDGED,"BRIDGED"}, /* when bridged */ {MISDN_CLEANING,"CLEANING"}, /* when hangup from * but we were connected before */ {MISDN_HUNGUP_FROM_MISDN,"HUNGUP_FROM_MISDN"}, /* when DISCONNECT/RELEASE/REL_COMP cam from misdn */ @@ -531,45 +677,44 @@ struct state_struct state_array[] = { /* misdn_hangup */ }; - - - -char *misdn_get_ch_state(struct chan_list *p) +static char *misdn_get_ch_state(struct chan_list *p) { int i; + static char state[8]; + if( !p) return NULL; for (i=0; i< sizeof(state_array)/sizeof(struct state_struct); i++) { if ( state_array[i].state == p->state) return state_array[i].txt; } - - return NULL; + + sprintf(state,"%d",p->state) ; + + return state; } -static int misdn_reload (int fd, int argc, char *argv[]) + + +void reload_config(void) { int i, cfg_debug; - ast_cli(fd, "Reloading mISDN Config\n"); - chan_misdn_log(0, 0, "Dynamic Crypting Activation is not support during reload at the moment\n"); - free_robin_list(); - misdn_cfg_reload(); - - { - char tempbuf[BUFFERSIZE]; - misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, tempbuf, BUFFERSIZE); - if (strlen(tempbuf)) - tracing = 1; - } - + misdn_cfg_update_ptp(); + misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, global_tracefile, BUFFERSIZE); misdn_cfg_get( 0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(int)); + for (i = 0; i <= max_ports; i++) { misdn_debug[i] = cfg_debug; misdn_debug_only[i] = 0; } - +} + +static int misdn_reload (int fd, int argc, char *argv[]) +{ + ast_cli(fd, "Reloading mISDN Config\n"); + reload_config(); return 0; } @@ -577,12 +722,14 @@ static void print_bc_info (int fd, struct chan_list* help, struct misdn_bchannel { struct ast_channel *ast=help->ast; ast_cli(fd, - "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s ctx:%s state:%s\n", + "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n", + bc->pid, bc->port, bc->channel, bc->nt?"NT":"TE", help->orginator == ORG_AST?"*":"I", ast?ast->exten:NULL, ast?AST_CID_P(ast):NULL, + bc->rad, ast?ast->context:NULL, misdn_get_ch_state(help) ); @@ -593,9 +740,9 @@ static void print_bc_info (int fd, struct chan_list* help, struct misdn_bchannel " --> ch_addr: %x\n" " --> bc_addr: %x\n" " --> bc_l3id: %x\n" - " --> tone: %s\n" " --> display: %s\n" " --> activated: %d\n" + " --> state: %s\n" " --> capability: %s\n" " --> echo_cancel: %d\n" " --> notone : rx %d tx:%d\n" @@ -605,19 +752,19 @@ static void print_bc_info (int fd, struct chan_list* help, struct misdn_bchannel help->addr, bc->addr, bc?bc->l3_id:-1, - tone2str(bc), bc->display, bc->active, + bc_state2str(bc->bc_state), bearer2str(bc->capability), bc->ec_enable, + help->norxtone,help->notxtone, bc->holded, help->holded_bc?1:0 ); } - static int misdn_show_cls (int fd, int argc, char *argv[]) { struct chan_list *help=cl_te; @@ -642,8 +789,6 @@ static int misdn_show_cls (int fd, int argc, char *argv[]) return 0; } - - static int misdn_show_cl (int fd, int argc, char *argv[]) { struct chan_list *help=cl_te; @@ -680,13 +825,12 @@ static int misdn_set_tics (int fd, int argc, char *argv[]) return 0; } - - static int misdn_show_stacks (int fd, int argc, char *argv[]) { int port; - + ast_cli(fd, "BEGIN STACK_LIST:\n"); + for (port=misdn_cfg_get_next_port(0); port > 0; port=misdn_cfg_get_next_port(port)) { char buf[128]; @@ -746,8 +890,6 @@ static int misdn_send_cd (int fd, int argc, char *argv[]) return 0; } - - static int misdn_send_digit (int fd, int argc, char *argv[]) { char *channame; @@ -806,9 +948,11 @@ static int misdn_toggle_echocancel (int fd, int argc, char *argv[]) ast_cli(fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame); return 0; } else { - tmp->bc->ec_enable=tmp->bc->ec_enable?0:1; + + tmp->toggle_ec=tmp->toggle_ec?0:1; - if (tmp->bc->ec_enable) { + if (tmp->toggle_ec) { + update_ec_config(tmp->bc); manager_ec_enable(tmp->bc); } else { manager_ec_disable(tmp->bc); @@ -819,8 +963,6 @@ static int misdn_toggle_echocancel (int fd, int argc, char *argv[]) return 0; } - - static int misdn_send_display (int fd, int argc, char *argv[]) { char *channame; @@ -838,9 +980,7 @@ static int misdn_send_display (int fd, int argc, char *argv[]) tmp=get_chan_by_ast_name(channame); if (tmp && tmp->bc) { - int l = sizeof(tmp->bc->display); - strncpy(tmp->bc->display, msg, l); - tmp->bc->display[l-1] = 0; + ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display)); misdn_lib_send_event(tmp->bc, EVENT_INFORMATION); } else { ast_cli(fd,"No such channel %s\n",channame); @@ -851,9 +991,6 @@ static int misdn_send_display (int fd, int argc, char *argv[]) return RESULT_SUCCESS ; } - - - static char *complete_ch_helper(char *line, char *word, int pos, int state, int rpos) { struct ast_channel *c; @@ -909,7 +1046,6 @@ static struct ast_cli_entry cli_send_cd = complete_ch }; - static struct ast_cli_entry cli_send_digit = { {"misdn","send","digit", NULL}, misdn_send_digit, @@ -920,7 +1056,6 @@ static struct ast_cli_entry cli_send_digit = complete_ch }; - static struct ast_cli_entry cli_toggle_echocancel = { {"misdn","toggle","echocancel", NULL}, misdn_toggle_echocancel, @@ -929,8 +1064,6 @@ static struct ast_cli_entry cli_toggle_echocancel = complete_ch }; - - static struct ast_cli_entry cli_send_display = { {"misdn","send","display", NULL}, misdn_send_display, @@ -941,7 +1074,6 @@ static struct ast_cli_entry cli_send_display = complete_ch }; - static struct ast_cli_entry cli_show_config = { {"misdn","show","config", NULL}, misdn_show_config, @@ -949,7 +1081,6 @@ static struct ast_cli_entry cli_show_config = "Usage: misdn show config [port | 0]\n use 0 to only print the general config.\n" }; - static struct ast_cli_entry cli_reload = { {"misdn","reload", NULL}, misdn_reload, @@ -964,7 +1095,6 @@ static struct ast_cli_entry cli_set_tics = "\n" }; - static struct ast_cli_entry cli_show_cls = { {"misdn","show","channels", NULL}, misdn_show_cls, @@ -980,6 +1110,19 @@ static struct ast_cli_entry cli_show_cl = complete_ch }; +static struct ast_cli_entry cli_port_block= +{ {"misdn","port","block", NULL}, + misdn_port_block, + "Blocks the given port", + "Usage: misdn port block\n" +}; + +static struct ast_cli_entry cli_port_unblock= +{ {"misdn","port","unblock", NULL}, + misdn_port_unblock, + "Unblocks the given port", + "Usage: misdn port unblock\n" +}; static struct ast_cli_entry cli_restart_port = @@ -989,7 +1132,6 @@ static struct ast_cli_entry cli_restart_port = "Usage: misdn restart port\n" }; - static struct ast_cli_entry cli_port_up = { {"misdn","port","up", NULL}, misdn_port_up, @@ -997,6 +1139,14 @@ static struct ast_cli_entry cli_port_up = "Usage: misdn port up <port>\n" }; +static struct ast_cli_entry cli_port_down = +{ {"misdn","port","down", NULL}, + misdn_port_down, + "Tries to deacivate the L1 on the given port", + "Usage: misdn port down <port>\n" +}; + + static struct ast_cli_entry cli_show_stacks = { {"misdn","show","stacks", NULL}, @@ -1012,8 +1162,6 @@ static struct ast_cli_entry cli_show_port = "Usage: misdn show port <port>\n" }; - - static struct ast_cli_entry cli_set_debug = { {"misdn","set","debug", NULL}, misdn_set_debug, @@ -1031,6 +1179,372 @@ static struct ast_cli_entry cli_set_crypt_debug = /*** CLI END ***/ +static int update_config (struct chan_list *ch, int orig) +{ + if (!ch) { + ast_log(LOG_WARNING, "Cannot configure without chanlist\n"); + return -1; + } + + struct ast_channel *ast=ch->ast; + struct misdn_bchannel *bc=ch->bc; + if (! ast || ! bc ) { + ast_log(LOG_WARNING, "Cannot configure without ast || bc\n"); + return -1; + } + + int port=bc->port; + + chan_misdn_log(1,port,"update_config: Getting Config\n"); + + + int hdlc=0; + misdn_cfg_get( port, MISDN_CFG_HDLC, &hdlc, sizeof(int)); + + if (hdlc) { + switch (bc->capability) { + case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: + case INFO_CAPABILITY_DIGITAL_RESTRICTED: + chan_misdn_log(1,bc->port," --> CONF HDLC\n"); + bc->hdlc=1; + break; + } + + } + + + int pres, screen; + + misdn_cfg_get( port, MISDN_CFG_PRES, &pres, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_SCREEN, &screen, sizeof(int)); + chan_misdn_log(2,port," --> pres: %d screen: %d\n",pres, screen); + + if ( (pres + screen) < 0 ) { + + chan_misdn_log(2,port," --> pres: %x\n", ast->cid.cid_pres); + + switch (ast->cid.cid_pres & 0x60){ + + case AST_PRES_RESTRICTED: + bc->pres=1; + chan_misdn_log(2, port, " --> PRES: Restricted (0x1)\n"); + break; + + + case AST_PRES_UNAVAILABLE: + bc->pres=2; + chan_misdn_log(2, port, " --> PRES: Unavailable (0x2)\n"); + break; + + default: + bc->pres=0; + chan_misdn_log(2, port, " --> PRES: Allowed (0x0)\n"); + } + + switch (ast->cid.cid_pres & 0x3){ + + case AST_PRES_USER_NUMBER_UNSCREENED: + bc->screen=0; + chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); + break; + + case AST_PRES_USER_NUMBER_PASSED_SCREEN: + bc->screen=1; + chan_misdn_log(2, port, " --> SCREEN: Passed Screen (0x1)\n"); + break; + case AST_PRES_USER_NUMBER_FAILED_SCREEN: + bc->screen=2; + chan_misdn_log(2, port, " --> SCREEN: Failed Screen (0x2)\n"); + break; + + case AST_PRES_NETWORK_NUMBER: + bc->screen=3; + chan_misdn_log(2, port, " --> SCREEN: Network Nr. (0x3)\n"); + break; + + default: + bc->screen=0; + chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); + } + + + } else { + bc->screen=screen; + bc->pres=pres; + } + + return 0; + +} + + + + +void config_jitterbuffer(struct chan_list *ch) +{ + struct misdn_bchannel *bc=ch->bc; + int len=ch->jb_len, threshold=ch->jb_upper_threshold; + + chan_misdn_log(5,bc->port, "config_jb: Called\n"); + + if ( ! len ) { + chan_misdn_log(1,bc->port, "config_jb: Deactivating Jitterbuffer\n"); + bc->nojitter=1; + } else { + + if (len <=100 || len > 8000) { + chan_misdn_log(0,bc->port,"config_jb: Jitterbuffer out of Bounds, setting to 1000\n"); + len=1000; + } + + if ( threshold > len ) { + chan_misdn_log(0,bc->port,"config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n"); + } + + if ( ch->jb) { + cb_log(0,bc->port,"config_jb: We've got a Jitterbuffer Already on this port.\n"); + misdn_jb_destroy(ch->jb); + ch->jb=NULL; + } + + ch->jb=misdn_jb_init(len, threshold); + + if (!ch->jb ) + bc->nojitter=1; + } +} + + +void debug_numplan(int port, int numplan, char *type) +{ + switch (numplan) { + case NUMPLAN_INTERNATIONAL: + chan_misdn_log(2, port, " --> %s: International\n",type); + break; + case NUMPLAN_NATIONAL: + chan_misdn_log(2, port, " --> %s: National\n",type); + break; + case NUMPLAN_SUBSCRIBER: + chan_misdn_log(2, port, " --> %s: Subscriber\n",type); + break; + case NUMPLAN_UNKNOWN: + chan_misdn_log(2, port, " --> %s: Unknown\n",type); + break; + /* Maybe we should cut off the prefix if present ? */ + default: + chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n "); + break; + } +} + + + + +static int update_ec_config(struct misdn_bchannel *bc) +{ + int ec; + int port=bc->port; + + misdn_cfg_get( port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); + + if (ec == 1 ) { + bc->ec_enable=1; + } else if ( ec > 1 ) { + bc->ec_enable=1; + bc->ec_deftaps=ec; + } + + return 0; +} + + +static int read_config(struct chan_list *ch, int orig) { + + if (!ch) { + ast_log(LOG_WARNING, "Cannot configure without chanlist\n"); + return -1; + } + + struct ast_channel *ast=ch->ast; + struct misdn_bchannel *bc=ch->bc; + if (! ast || ! bc ) { + ast_log(LOG_WARNING, "Cannot configure without ast || bc\n"); + return -1; + } + + int port=bc->port; + + chan_misdn_log(5,port,"read_config: Getting Config\n"); + + char lang[BUFFERSIZE+1]; + + misdn_cfg_get( port, MISDN_CFG_LANGUAGE, lang, BUFFERSIZE); + ast_copy_string(ast->language, lang, sizeof(ast->language)); + + char musicclass[BUFFERSIZE+1]; + + misdn_cfg_get( port, MISDN_CFG_MUSICCLASS, musicclass, BUFFERSIZE); + ast_copy_string(ast->musicclass, musicclass, sizeof(ast->musicclass)); + + misdn_cfg_get( port, MISDN_CFG_TXGAIN, &bc->txgain, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_RXGAIN, &bc->rxgain, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_FAR_ALERTING, &ch->far_alerting, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, BUFFERSIZE); + + + int hdlc=0; + misdn_cfg_get( port, MISDN_CFG_HDLC, &hdlc, sizeof(int)); + + if (hdlc) { + switch (bc->capability) { + case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: + case INFO_CAPABILITY_DIGITAL_RESTRICTED: + chan_misdn_log(1,bc->port," --> CONF HDLC\n"); + bc->hdlc=1; + break; + } + + } + /*Initialize new Jitterbuffer*/ + { + misdn_cfg_get( port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, &ch->jb_upper_threshold, sizeof(int)); + + config_jitterbuffer(ch); + } + + misdn_cfg_get( bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context)); + + ast_copy_string (ast->context,ch->context,sizeof(ast->context)); + + update_ec_config(bc); + + { + int eb3; + + misdn_cfg_get( bc->port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int)); + bc->early_bconnect=eb3; + } + + port=bc->port; + + { + char buf[256]; + ast_group_t pg,cg; + + misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg)); + misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg)); + + chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n",ast_print_group(buf,sizeof(buf),cg),ast_print_group(buf,sizeof(buf),pg)); + ast->pickupgroup=pg; + ast->callgroup=cg; + } + + if ( orig == ORG_AST) { + misdn_cfg_get( port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(int)); + + { + char callerid[BUFFERSIZE+1]; + misdn_cfg_get( port, MISDN_CFG_CALLERID, callerid, BUFFERSIZE); + if ( ! ast_strlen_zero(callerid) ) { + chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid); + { + int l = sizeof(bc->oad); + strncpy(bc->oad,callerid, l); + bc->oad[l-1] = 0; + } + + } + + + misdn_cfg_get( port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int)); + debug_numplan(port, bc->dnumplan,"TON"); + debug_numplan(port, bc->onumplan,"LTON"); + debug_numplan(port, bc->cpnnumplan,"CTON"); + } + + + + } else { /** ORIGINATOR MISDN **/ + + misdn_cfg_get( port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int)); + debug_numplan(port, bc->cpnnumplan,"CTON"); + + char prefix[BUFFERSIZE+1]=""; + switch( bc->onumplan ) { + case NUMPLAN_INTERNATIONAL: + misdn_cfg_get( bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE); + break; + + case NUMPLAN_NATIONAL: + misdn_cfg_get( bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE); + break; + default: + break; + } + + { + int l = strlen(prefix) + strlen(bc->oad); + char tmp[l+1]; + strcpy(tmp,prefix); + strcat(tmp,bc->oad); + strcpy(bc->oad,tmp); + } + + if (!ast_strlen_zero(bc->dad)) { + ast_copy_string(bc->orig_dad,bc->dad, sizeof(bc->orig_dad)); + } + + if ( ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) { + ast_copy_string(bc->dad,bc->keypad, sizeof(bc->dad)); + } + + prefix[0] = 0; + + switch( bc->dnumplan ) { + case NUMPLAN_INTERNATIONAL: + misdn_cfg_get( bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE); + break; + case NUMPLAN_NATIONAL: + misdn_cfg_get( bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE); + break; + default: + break; + } + + { + int l = strlen(prefix) + strlen(bc->dad); + char tmp[l+1]; + strcpy(tmp,prefix); + strcat(tmp,bc->dad); + strcpy(bc->dad,tmp); + } + + if ( strcmp(bc->dad,ast->exten)) { + ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten)); + } + + ast_set_callerid(ast, bc->oad, NULL, bc->oad); + + if ( !ast_strlen_zero(bc->rad) ) + ast->cid.cid_rdnis=strdup(bc->rad); + + } /* ORIG MISDN END */ + + return 0; +} + + /*****************************/ /*** AST Indications Start ***/ /*****************************/ @@ -1041,9 +1555,8 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) int r; struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast); struct misdn_bchannel *newbc; - char *opts=NULL, *ext=NULL; + char *opts=NULL, *ext,*tokb; char dest_cp[256]; - char *tokb; { strncpy(dest_cp,dest,sizeof(dest_cp)-1); @@ -1056,12 +1569,10 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) if (ext) { opts=strtok_r(NULL,"/",&tokb); } else { - chan_misdn_log(-1,0,"misdn_call: No Extension given!\n"); + chan_misdn_log(0,0,"misdn_call: No Extension given!\n"); return -1; } } - - } if (!ast) { @@ -1076,7 +1587,6 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) return -1; } - if (!ch) { ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); ast->hangupcause=41; @@ -1092,183 +1602,15 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) ast_setstate(ast, AST_STATE_DOWN); return -1; } - + port=newbc->port; - - ast_copy_string(newbc->dad, ext, sizeof(newbc->dad)); - ast_copy_string(ast->exten, ext, sizeof(ast->exten)); + strncpy(newbc->dad,ext,sizeof( newbc->dad)); + strncpy(ast->exten,ext,sizeof(ast->exten)); - chan_misdn_log(1, 0, "* CALL: %s\n",dest); + chan_misdn_log(1, port, "* CALL: %s\n",dest); chan_misdn_log(1, port, " --> * dad:%s tech:%s ctx:%s\n",ast->exten,ast->name, ast->context); - { - char context[BUFFERSIZE]; - - misdn_cfg_get( port, MISDN_CFG_CONTEXT, context, sizeof(ast->context)); - { - int l = sizeof(ast->context); - strncpy(ast->context,context, l); - ast->context[l-1] = 0; - } - chan_misdn_log(2, port, " --> * Setting Context to %s\n",context); - misdn_cfg_get( port, MISDN_CFG_LANGUAGE, ast->language, BUFFERSIZE); - - misdn_cfg_get( port, MISDN_CFG_TXGAIN, &newbc->txgain, sizeof(int)); - misdn_cfg_get( port, MISDN_CFG_RXGAIN, &newbc->rxgain, sizeof(int)); - - misdn_cfg_get( port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(newbc->te_choose_channel), sizeof(int)); - - - { - char callerid[BUFFERSIZE]; - misdn_cfg_get( port, MISDN_CFG_CALLERID, callerid, BUFFERSIZE); - if ( ! ast_strlen_zero(callerid) ) { - chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid); - { - int l = sizeof(newbc->oad); - strncpy(newbc->oad,callerid, l); - newbc->oad[l-1] = 0; - } - } - - - misdn_cfg_get( port, MISDN_CFG_DIALPLAN, &newbc->dnumplan, sizeof(int)); - switch (newbc->dnumplan) { - case NUMPLAN_INTERNATIONAL: - chan_misdn_log(2, port, " --> TON: International\n"); - break; - case NUMPLAN_NATIONAL: - chan_misdn_log(2, port, " --> TON: National\n"); - break; - case NUMPLAN_SUBSCRIBER: - chan_misdn_log(2, port, " --> TON: Subscriber\n"); - break; - case NUMPLAN_UNKNOWN: - chan_misdn_log(2, port, " --> TON: Unknown\n"); - break; - /* Maybe we should cut off the prefix if present ? */ - default: - chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n "); - break; - } - - - misdn_cfg_get( port, MISDN_CFG_LOCALDIALPLAN, &newbc->onumplan, sizeof(int)); - switch (newbc->onumplan) { - case NUMPLAN_INTERNATIONAL: - chan_misdn_log(2, port, " --> TON: International\n"); - break; - case NUMPLAN_NATIONAL: - chan_misdn_log(2, port, " --> TON: National\n"); - break; - case NUMPLAN_SUBSCRIBER: - chan_misdn_log(2, port, " --> TON: Subscriber\n"); - break; - case NUMPLAN_UNKNOWN: - chan_misdn_log(2, port, " --> TON: Unknown\n"); - break; - /* Maybe we should cut off the prefix if present ? */ - default: - chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n "); - break; - } - } - - - - - { - int eb3; - - misdn_cfg_get( port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int)); - newbc->early_bconnect=eb3; - - } - - - - /* Will be overridden by asterisk in head! */ - { - int pres; - - misdn_cfg_get( port, MISDN_CFG_PRES, &pres, sizeof(int)); - newbc->pres=pres?0:1; - - } - - int def_callingpres; - misdn_cfg_get( port, MISDN_CFG_USE_CALLINGPRES, &def_callingpres, sizeof(int)); - if ( def_callingpres) { - - switch (ast->cid.cid_pres & 0x60){ - - case AST_PRES_RESTRICTED: - chan_misdn_log(2, port, " --> PRES: Restricted (0x1)\n"); - newbc->pres=1; - break; - - - case AST_PRES_UNAVAILABLE: - chan_misdn_log(2, port, " --> PRES: Unavailable (0x2)\n"); - newbc->pres=2; - break; - - default: - chan_misdn_log(2, port, " --> PRES: Allowed (0x0)\n"); - newbc->pres=0; - } - - switch (ast->cid.cid_pres & 0x3){ - - case AST_PRES_USER_NUMBER_UNSCREENED: - chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); - newbc->screen=0; - break; - - case AST_PRES_USER_NUMBER_PASSED_SCREEN: - chan_misdn_log(2, port, " --> SCREEN: Passed Screen (0x1)\n"); - newbc->screen=1; - break; - case AST_PRES_USER_NUMBER_FAILED_SCREEN: - chan_misdn_log(2, port, " --> SCREEN: Failed Screen (0x2)\n"); - newbc->screen=2; - break; - - case AST_PRES_NETWORK_NUMBER: - chan_misdn_log(2, port, " --> SCREEN: Network Nr. (0x3)\n"); - newbc->screen=3; - break; - - default: - chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); - newbc->screen=0; - } - } - - - { - int ec, ectr; - - misdn_cfg_get( port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); - - misdn_cfg_get( port, MISDN_CFG_ECHOTRAINING, &ectr, sizeof(int)); - if (ec == 1 ) { - newbc->ec_enable=1; - } else if ( ec > 1 ) { - newbc->ec_enable=1; - newbc->ec_deftaps=ec; - } - - - if (ectr>=0) { - newbc->ec_training=ectr; - } - - } - - } - chan_misdn_log(3, port, " --> * adding2newbc ext %s\n",ast->exten); if (ast->exten) { int l = sizeof(newbc->dad); @@ -1278,6 +1620,7 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) newbc->rad[0]=0; chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n",AST_CID_P(ast)); if (ast_strlen_zero(newbc->oad) && AST_CID_P(ast) ) { + if (AST_CID_P(ast)) { int l = sizeof(newbc->oad); strncpy(newbc->oad,AST_CID_P(ast), l); @@ -1288,14 +1631,7 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) { struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast); if (!ch) { ast_verbose("No chan_list in misdn_call"); return -1;} - ch->bc = newbc; - ch->orginator=ORG_AST; - ch->ast = ast; - MISDN_ASTERISK_TECH_PVT(ast) = ch ; - - - newbc->capability=ast->transfercapability; pbx_builtin_setvar_helper(ast,"TRANSFERCAPABILITY",ast_transfercapability2str(newbc->capability)); if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) { @@ -1303,17 +1639,19 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) } + /* update screening and presentation */ + update_config(ch,ORG_AST); + + /* fill in some ies from channel vary*/ + import_ch(ast, newbc, ch); + /* Finally The Options Override Everything */ if (opts) misdn_set_opt_exec(ast,opts); else - chan_misdn_log(1,0,"NO OPTS GIVEN\n"); - + chan_misdn_log(2,port,"NO OPTS GIVEN\n"); - cl_queue_chan(&cl_te, ch) ; ch->state=MISDN_CALLING; - - chan_misdn_trace_call(ast,1,"*->I: EVENT_CALL\n" ); r=misdn_lib_send_event( newbc, EVENT_SETUP ); @@ -1332,21 +1670,20 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) chan_misdn_log(1, port, " --> * SEND: State Dialing pid:%d\n",newbc?newbc->pid:1); ast_setstate(ast, AST_STATE_DIALING); - ast->hangupcause=16; + + if (newbc->nt) stop_bc_tones(ch); + return 0; } -int misdn_answer(struct ast_channel *ast) +static int misdn_answer(struct ast_channel *ast) { struct chan_list *p; - if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1; - p = MISDN_ASTERISK_TECH_PVT(ast) ; - - chan_misdn_trace_call(ast,1,"*->I: EVENT_ANSWER\n"); + if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast)) ) return -1; chan_misdn_log(1, p? (p->bc? p->bc->port : 0) : 0, "* ANSWER:\n"); @@ -1362,7 +1699,7 @@ int misdn_answer(struct ast_channel *ast) } { - char *tmp_key = pbx_builtin_getvar_helper(p->ast, "CRYPT_KEY"); + const char *tmp_key = pbx_builtin_getvar_helper(p->ast, "CRYPT_KEY"); if (tmp_key ) { chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n"); @@ -1378,27 +1715,35 @@ int misdn_answer(struct ast_channel *ast) } { - char *async=pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS"); - if (async) { + const char *nodsp=pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS"); + if (nodsp) { chan_misdn_log(1, p->bc->port, " --> Connection is transparent digital\n"); - p->bc->async=1; + p->bc->nodsp=1; + p->bc->hdlc=0; + p->bc->nojitter=1; } } p->state = MISDN_CONNECTED; + misdn_lib_echo(p->bc,0); + stop_indicate(p); + + if ( ast_strlen_zero(p->bc->cad) ) { + chan_misdn_log(2,p->bc->port," --> empty cad using dad\n"); + ast_copy_string(p->bc->cad,p->bc->dad,sizeof(p->bc->cad)); + } + misdn_lib_send_event( p->bc, EVENT_CONNECT); start_bc_tones(p); return 0; } -int misdn_digit(struct ast_channel *ast, char digit ) +static int misdn_digit(struct ast_channel *ast, char digit ) { struct chan_list *p; - if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1; - p = MISDN_ASTERISK_TECH_PVT(ast) ; - + if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) return -1; struct misdn_bchannel *bc=p->bc; chan_misdn_log(1, bc?bc->port:0, "* IND : Digit %c\n",digit); @@ -1452,14 +1797,13 @@ int misdn_digit(struct ast_channel *ast, char digit ) } -int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast) +static int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast) { struct chan_list *p; - if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1; - p = MISDN_ASTERISK_TECH_PVT(ast) ; + if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) )) return -1; - chan_misdn_log(1, p->bc?p->bc->port:0, "* IND: Got Fixup State:%s Holded:%d L3id:%x\n", misdn_get_ch_state(p), p->holded, p->l3id); + chan_misdn_log(1, p->bc?p->bc->port:0, "* IND: Got Fixup State:%s L3id:%x\n", misdn_get_ch_state(p), p->l3id); p->ast = ast ; p->state=MISDN_CONNECTED; @@ -1468,29 +1812,16 @@ int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast) } -int misdn_transfer (struct ast_channel *ast, char *dest) -{ - struct chan_list *p; - - if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1; - p = MISDN_ASTERISK_TECH_PVT(ast) ; - - chan_misdn_log(1, p->bc?p->bc->port:0, "* IND : Got Transfer %s\n",dest); - return 0; -} - - -int misdn_indication(struct ast_channel *ast, int cond) +static int misdn_indication(struct ast_channel *ast, int cond) { struct chan_list *p; - if (!ast || ! MISDN_ASTERISK_PVT(ast)) { + if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) { ast_log(LOG_WARNING, "Returnded -1 in misdn_indication\n"); return -1; } - p = MISDN_ASTERISK_TECH_PVT(ast) ; if (!p->bc ) { chan_misdn_log(1, 0, "* IND : Indication from %s\n",ast->exten); @@ -1498,56 +1829,85 @@ int misdn_indication(struct ast_channel *ast, int cond) return -1; } - chan_misdn_log(1, p->bc->port, "* IND : Indication from %s\n",ast->exten); + chan_misdn_log(1, p->bc->port, "* IND : Indication [%d] from %s\n",cond, ast->exten); switch (cond) { case AST_CONTROL_BUSY: chan_misdn_log(1, p->bc->port, "* IND :\tbusy\n"); chan_misdn_log(1, p->bc->port, " --> * SEND: State Busy pid:%d\n",p->bc?p->bc->pid:-1); ast_setstate(ast,AST_STATE_BUSY); - + p->bc->out_cause=17; if (p->state != MISDN_CONNECTED) { + start_bc_tones(p); misdn_lib_send_event( p->bc, EVENT_DISCONNECT); - manager_send_tone(p->bc, TONE_BUSY); } else { - chan_misdn_log(0, p->bc->port, " --> !! Got Busy in Connected State !?! port:%d ast:%s\n", - p->bc->port, ast->name); + chan_misdn_log(-1, p->bc->port, " --> !! Got Busy in Connected State !?! ast:%s\n", ast->name); } + return -1; break; case AST_CONTROL_RING: chan_misdn_log(1, p->bc->port, " --> * IND :\tring pid:%d\n",p->bc?p->bc->pid:-1); + return -1; break; + case AST_CONTROL_RINGING: - if ( p->state == MISDN_ALERTING) { - chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d but I ws Ringing before, so ignoreing it\n",p->bc?p->bc->pid:-1); - break; + switch (p->state) { + case MISDN_ALERTING: + chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoreing it\n",p->bc?p->bc->pid:-1); + break; + case MISDN_CONNECTED: + chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n",p->bc?p->bc->pid:-1); + return -1; + break; + default: + p->state=MISDN_ALERTING; + chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d\n",p->bc?p->bc->pid:-1); + misdn_lib_send_event( p->bc, EVENT_ALERTING); + + if (p->other_ch && p->other_ch->bc) { + if (misdn_inband_avail(p->other_ch->bc)) { + chan_misdn_log(1,p->bc->port, " --> other End is mISDN and has inband info available\n"); + break; + } + + if (!p->other_ch->bc->nt) { + chan_misdn_log(1,p->bc->port, " --> other End is mISDN TE so it has inband info for sure (?)\n"); + break; + } + } + + chan_misdn_log(1, p->bc->port, " --> * SEND: State Ring pid:%d\n",p->bc?p->bc->pid:-1); + ast_setstate(ast,AST_STATE_RINGING); + + if ( !p->bc->nt && (p->orginator==ORG_MISDN) && !p->incoming_early_audio ) + chan_misdn_log(1,p->bc->port, " --> incoming_early_audio off\n"); + else + return -1; } - p->state=MISDN_ALERTING; - - chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d\n",p->bc?p->bc->pid:-1); - - misdn_lib_send_event( p->bc, EVENT_ALERTING); - - manager_send_tone(p->bc, TONE_ALERTING); - chan_misdn_log(1, p->bc->port, " --> * SEND: State Ring pid:%d\n",p->bc?p->bc->pid:-1); - ast_setstate(ast,AST_STATE_RINGING); break; - case AST_CONTROL_ANSWER: chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n",p->bc?p->bc->pid:-1); + start_bc_tones(p); break; case AST_CONTROL_TAKEOFFHOOK: chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n",p->bc?p->bc->pid:-1); + return -1; break; case AST_CONTROL_OFFHOOK: chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n",p->bc?p->bc->pid:-1); + return -1; break; case AST_CONTROL_FLASH: chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n",p->bc?p->bc->pid:-1); break; case AST_CONTROL_PROGRESS: chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n",p->bc?p->bc->pid:-1); + misdn_lib_send_event( p->bc, EVENT_PROGRESS); + break; + case AST_CONTROL_PROCEEDING: + chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n",p->bc?p->bc->pid:-1); + misdn_lib_send_event( p->bc, EVENT_PROCEEDING); break; case AST_CONTROL_CONGESTION: chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n",p->bc?p->bc->pid:-1); @@ -1555,18 +1915,25 @@ int misdn_indication(struct ast_channel *ast, int cond) p->bc->out_cause=42; if (p->state != MISDN_CONNECTED) { start_bc_tones(p); - //misdn_lib_send_event( p->bc, EVENT_RELEASE_COMPLETE); misdn_lib_send_event( p->bc, EVENT_RELEASE); } else { misdn_lib_send_event( p->bc, EVENT_DISCONNECT); } + if (p->bc->nt) { - manager_send_tone(p->bc, TONE_BUSY); + hanguptone_indicate(p); } break; case -1 : - chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! pid:%d\n",p->bc?p->bc->pid:-1); + chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n",p->bc?p->bc->pid:-1); + + stop_indicate(p); + + if (p->state == MISDN_CONNECTED) + start_bc_tones(p); + break; + case AST_CONTROL_HOLD: chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n",p->bc?p->bc->pid:-1); break; @@ -1574,35 +1941,29 @@ int misdn_indication(struct ast_channel *ast, int cond) chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n",p->bc?p->bc->pid:-1); break; default: - ast_log(LOG_WARNING, " --> * Unknown Indication:%d pid:%d\n",cond,p->bc?p->bc->pid:-1); + ast_log(LOG_NOTICE, " --> * Unknown Indication:%d pid:%d\n",cond,p->bc?p->bc->pid:-1); } return 0; } -int misdn_hangup(struct ast_channel *ast) +static int misdn_hangup(struct ast_channel *ast) { struct chan_list *p; struct misdn_bchannel *bc=NULL; if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) ) ) return -1; - release_lock; - - chan_misdn_trace_call(ast,1,"*->I: EVENT_HANGUP cause=%d\n",ast->hangupcause); - ast_log(LOG_DEBUG, "misdn_hangup(%s)\n", ast->name); if (!p) { chan_misdn_log(3, 0, "misdn_hangup called, without chan_list obj.\n"); - release_unlock; return 0 ; } bc=p->bc; if (!bc) { - release_unlock; ast_log(LOG_WARNING,"Hangup with private but no bc ?\n"); return 0; } @@ -1611,31 +1972,32 @@ int misdn_hangup(struct ast_channel *ast) MISDN_ASTERISK_TECH_PVT(ast)=NULL; p->ast=NULL; + bc=p->bc; + if (ast->_state == AST_STATE_RESERVED) { /* between request and call */ MISDN_ASTERISK_TECH_PVT(ast)=NULL; - release_unlock; cl_dequeue_chan(&cl_te, p); free(p); - - misdn_lib_release(bc); + + if (bc) + misdn_lib_release(bc); return 0; } - stop_bc_tones(p); - - release_unlock; - - - - - + p->need_hangup=0; + p->need_queue_hangup=0; + + + if (!p->bc->nt) + stop_bc_tones(p); + { - char *varcause=NULL; - bc->cause=ast->hangupcause?ast->hangupcause:16; + const char *varcause=NULL; + bc->out_cause=ast->hangupcause?ast->hangupcause:16; if ( (varcause=pbx_builtin_getvar_helper(ast, "HANGUPCAUSE")) || (varcause=pbx_builtin_getvar_helper(ast, "PRI_CAUSE"))) { @@ -1647,6 +2009,7 @@ int misdn_hangup(struct ast_channel *ast) chan_misdn_log(2, bc->port, " --> l3id:%x\n",p->l3id); chan_misdn_log(1, bc->port, " --> cause:%d\n",bc->cause); chan_misdn_log(1, bc->port, " --> out_cause:%d\n",bc->out_cause); + chan_misdn_log(1, bc->port, " --> state:%s\n", misdn_get_ch_state(p)); switch (p->state) { case MISDN_CALLING: @@ -1656,81 +2019,112 @@ int misdn_hangup(struct ast_channel *ast) case MISDN_HOLDED: case MISDN_DIALING: start_bc_tones(p); - manager_send_tone(bc, TONE_BUSY); - p->state=MISDN_CLEANING; - - misdn_lib_send_event( bc, EVENT_RELEASE_COMPLETE); - + hanguptone_indicate(p); + + if (bc->need_disconnect) + misdn_lib_send_event( bc, EVENT_DISCONNECT); + break; + + case MISDN_CALLING_ACKNOWLEDGE: + start_bc_tones(p); + hanguptone_indicate(p); + + if (bc->need_disconnect) + misdn_lib_send_event( bc, EVENT_DISCONNECT); break; case MISDN_ALERTING: - chan_misdn_log(2, bc->port, " --> * State Alerting\n"); - + case MISDN_PROGRESS: + case MISDN_PROCEEDING: if (p->orginator != ORG_AST) - manager_send_tone(bc, TONE_BUSY); + hanguptone_indicate(p); - p->state=MISDN_CLEANING; - misdn_lib_send_event( bc, EVENT_DISCONNECT); + /*p->state=MISDN_CLEANING;*/ + if (bc->need_disconnect) + misdn_lib_send_event( bc, EVENT_DISCONNECT); break; case MISDN_CONNECTED: + case MISDN_PRECONNECTED: /* Alerting or Disconect */ - chan_misdn_log(2, bc->port, " --> * State Connected\n"); - start_bc_tones(p); - manager_send_tone(bc, TONE_BUSY); - misdn_lib_send_event( bc, EVENT_DISCONNECT); - + if (p->bc->nt) { + start_bc_tones(p); + hanguptone_indicate(p); + p->bc->progress_indicator=8; + } + if (bc->need_disconnect) + misdn_lib_send_event( bc, EVENT_DISCONNECT); + + /*p->state=MISDN_CLEANING;*/ + break; + case MISDN_DISCONNECTED: + misdn_lib_send_event( bc, EVENT_RELEASE); p->state=MISDN_CLEANING; /* MISDN_HUNGUP_FROM_AST; */ break; + case MISDN_RELEASED: case MISDN_CLEANING: + p->state=MISDN_CLEANING; + break; + + case MISDN_BUSY: break; case MISDN_HOLD_DISCONNECT: /* need to send release here */ - chan_misdn_log(2, bc->port, " --> state HOLD_DISC\n"); chan_misdn_log(1, bc->port, " --> cause %d\n",bc->cause); chan_misdn_log(1, bc->port, " --> out_cause %d\n",bc->out_cause); + bc->out_cause=-1; misdn_lib_send_event(bc,EVENT_RELEASE); + p->state=MISDN_CLEANING; break; default: - /* Alerting or Disconect */ - if (bc->nt) + if (bc->nt) { + bc->out_cause=-1; misdn_lib_send_event(bc, EVENT_RELEASE); - else - misdn_lib_send_event(bc, EVENT_DISCONNECT); - p->state=MISDN_CLEANING; /* MISDN_HUNGUP_FROM_AST; */ + p->state=MISDN_CLEANING; + } else { + if (bc->need_disconnect) + misdn_lib_send_event(bc, EVENT_DISCONNECT); + } } + + p->state=MISDN_CLEANING; } - chan_misdn_log(1, bc->port, "Channel: %s hanguped\n",ast->name); + + chan_misdn_log(1, bc->port, "Channel: %s hanguped new state:%s\n",ast->name,misdn_get_ch_state(p)); return 0; } -struct ast_frame *misdn_read(struct ast_channel *ast) +static struct ast_frame *misdn_read(struct ast_channel *ast) { struct chan_list *tmp; + int len; - char blah[255]; - int len =0 ; - - if (!ast) return NULL; - if (! (tmp=MISDN_ASTERISK_TECH_PVT(ast)) ) return NULL; - if (!tmp->bc) return NULL; - - - read(tmp->pipe[0],blah,sizeof(blah)); - - - len = misdn_ibuf_usedcount(tmp->bc->astbuf); + if (!ast) { + chan_misdn_log(1,0,"misdn_read called without ast\n"); + return NULL; + } + if (! (tmp=MISDN_ASTERISK_TECH_PVT(ast)) ) { + chan_misdn_log(1,0,"misdn_read called without ast->pvt\n"); + return NULL; + } + if (!tmp->bc) { + chan_misdn_log(1,0,"misdn_read called without bc\n"); + return NULL; + } - /*shrinken len if necessary, we transmit at maximum 4k*/ - len = len<=sizeof(tmp->ast_rd_buf)?len:sizeof(tmp->ast_rd_buf); - - misdn_ibuf_memcpy_r(tmp->ast_rd_buf, tmp->bc->astbuf,len); + len=read(tmp->pipe[0],tmp->ast_rd_buf,sizeof(tmp->ast_rd_buf)); + if (len<=0) { + /* we hangup here, since our pipe is closed */ + chan_misdn_log(2,tmp->bc->port,"misdn_read: Pipe closed, hanging up\n"); + return NULL; + } + tmp->frame.frametype = AST_FRAME_VOICE; tmp->frame.subclass = AST_FORMAT_ALAW; tmp->frame.datalen = len; @@ -1739,41 +2133,59 @@ struct ast_frame *misdn_read(struct ast_channel *ast) tmp->frame.offset= 0 ; tmp->frame.src = NULL; tmp->frame.data = tmp->ast_rd_buf ; - - chan_misdn_trace_call(tmp->ast,3,"*->I: EVENT_READ len=%d\n",len); + + if (tmp->faxdetect || tmp->ast_dsp ) { + return process_ast_dsp(tmp, &tmp->frame); + } + return &tmp->frame; } -int misdn_write(struct ast_channel *ast, struct ast_frame *frame) + +static int misdn_write(struct ast_channel *ast, struct ast_frame *frame) { - struct chan_list *p; + struct chan_list *ch; int i = 0; - if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast)) ) return -1; + if (!ast || ! (ch=MISDN_ASTERISK_TECH_PVT(ast)) ) return -1; - if (!p->bc ) { + if (!ch->bc ) { ast_log(LOG_WARNING, "private but no bc\n"); return -1; } - if (p->bc->tone != TONE_NONE) - manager_send_tone(p->bc,TONE_NONE); - - - if (p->holded ) { - chan_misdn_log(5, p->bc->port, "misdn_write: Returning because holded\n"); + if (ch->state == MISDN_HOLDED) { + chan_misdn_log(8, ch->bc->port, "misdn_write: Returning because holded\n"); return 0; } - if (p->notxtone) { - chan_misdn_log(5, p->bc->port, "misdn_write: Returning because notxone\n"); + if (ch->notxtone) { + chan_misdn_log(9, ch->bc->port, "misdn_write: Returning because notxone\n"); + return 0; + } + + + if ( !frame->subclass) { + chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n"); return 0; } if ( !(frame->subclass & prefformat)) { - chan_misdn_log(0, p->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass); + + chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass); + return 0; } + + if ( !frame->samples ) { + chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n"); + return 0; + } + + if ( ! ch->bc->addr ) { + chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples); + return 0; + } #if MISDN_DEBUG { @@ -1785,13 +2197,48 @@ int misdn_write(struct ast_channel *ast, struct ast_frame *frame) printf ("\n"); } #endif - chan_misdn_trace_call(ast,3,"*->I: EVENT_WRITE len=%d\n",frame->samples); - i= manager_tx2misdn_frm(p->bc, frame->data, frame->samples); + + + switch (ch->bc->bc_state) { + case BCHAN_ACTIVATED: + case BCHAN_BRIDGED: + break; + default: + if (!ch->dropped_frame_cnt) + chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) droping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d\n",frame->samples,ch->bc->addr, ast->exten, ast->cid.cid_num,misdn_get_ch_state( ch), ch->bc->bc_state); + + ch->dropped_frame_cnt++; + if (ch->dropped_frame_cnt > 100) { + ch->dropped_frame_cnt=0; + chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) droping: %d frames addr:%x dropped > 100 frames!\n",frame->samples,ch->bc->addr); + + } + + return 0; + } + + chan_misdn_log(9, ch->bc->port, "Sending :%d bytes 2 MISDN\n",frame->samples); + + if ( !ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability) ) { + /* Buffered Transmit (triggert by read from isdn side)*/ + if (misdn_jb_fill(ch->jb,frame->data,frame->samples) < 0) { + if (ch->bc->active) + cb_log(0,ch->bc->port,"Misdn Jitterbuffer Overflow.\n"); + } + + } else { + /*transmit without jitterbuffer*/ + i=misdn_lib_tx2misdn_frm(ch->bc, frame->data, frame->samples); + } + + return 0; } + + enum ast_bridge_result misdn_bridge (struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, @@ -1819,47 +2266,69 @@ enum ast_bridge_result misdn_bridge (struct ast_channel *c0, int bridging; misdn_cfg_get( 0, MISDN_GEN_BRIDGING, &bridging, sizeof(int)); if (bridging) { - int ecwb; - misdn_cfg_get( ch1->bc->port, MISDN_CFG_ECHOCANCELWHENBRIDGED, &ecwb, sizeof(int)); - if ( !ecwb ) { - chan_misdn_log(0, ch1->bc->port, "Disabling Echo Cancellor when Bridged\n"); + int ec; + misdn_cfg_get( ch1->bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); + if ( ec ) { + chan_misdn_log(2, ch1->bc->port, "Disabling Echo Cancellor when Bridged\n"); ch1->bc->ec_enable=0; manager_ec_disable(ch1->bc); } - misdn_cfg_get( ch2->bc->port, MISDN_CFG_ECHOCANCELWHENBRIDGED, &ecwb, sizeof(int)); - if ( !ecwb ) { - chan_misdn_log(0, ch2->bc->port, "Disabling Echo Cancellor when Bridged\n"); + misdn_cfg_get( ch2->bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); + if ( ec ) { + chan_misdn_log(2, ch2->bc->port, "Disabling Echo Cancellor when Bridged\n"); ch2->bc->ec_enable=0; - manager_ec_disable(ch2->bc); + manager_ec_disable(ch2->bc); } /* trying to make a mISDN_dsp conference */ - chan_misdn_log(0, ch1->bc->port, "I SEND: Making conference with Number:%d\n", (ch1->bc->pid<<1) +1); - + chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid +1); + misdn_lib_bridge(ch1->bc,ch2->bc); } - chan_misdn_log(1, ch1->bc->port, "* Makeing Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad); - + chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad); + + + if (! (flags&AST_BRIDGE_DTMF_CHANNEL_0) ) + ch1->ignore_dtmf=1; + + if (! (flags&AST_BRIDGE_DTMF_CHANNEL_1) ) + ch2->ignore_dtmf=1; + + while(1) { to=-1; who = ast_waitfor_n(carr, 2, &to); if (!who) { - ast_log(LOG_DEBUG,"misdn_bridge: empty read\n"); - continue; + ast_log(LOG_NOTICE,"misdn_bridge: empty read, breaking out\n"); + break; } f = ast_read(who); if (!f || f->frametype == AST_FRAME_CONTROL) { /* got hangup .. */ + + if (!f) + chan_misdn_log(1,ch1->bc->port,"Read Null Frame\n"); + else + chan_misdn_log(1,ch1->bc->port,"Read Frame Controll class:%d\n",f->subclass); + *fo=f; *rc=who; break; } - - + + if ( f->frametype == AST_FRAME_DTMF ) { + chan_misdn_log(1,0,"Read DTMF %d from %s\n",f->subclass, who->exten); + + *fo=f; + *rc=who; + break; + } + + if (who == c0) { ast_write(c1,f); } @@ -1868,20 +2337,67 @@ enum ast_bridge_result misdn_bridge (struct ast_channel *c0, } } - - if (bridging) { - misdn_lib_split_bridge(ch1->bc,ch2->bc); + + chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1); + + misdn_lib_split_bridge(ch1->bc,ch2->bc); + + + return AST_BRIDGE_COMPLETE; +} + +/** AST INDICATIONS END **/ + +static int dialtone_indicate(struct chan_list *cl) +{ + const struct tone_zone_sound *ts= NULL; + struct ast_channel *ast=cl->ast; + + + int nd=0; + misdn_cfg_get( cl->bc->port, MISDN_CFG_NODIALTONE, &nd, sizeof(nd)); + + if (nd) { + chan_misdn_log(1,cl->bc->port,"Not sending Dialtone, because config wants it\n"); + return 0; } - + + chan_misdn_log(3,cl->bc->port," --> Dial\n"); + ts=ast_get_indication_tone(ast->zone,"dial"); + cl->ts=ts; + + if (ts) { + cl->notxtone=0; + cl->norxtone=0; + ast_playtones_start(ast,0, ts->data, 0); + chan_misdn_log(4,cl->bc->port,"Starting Playtones\n"); + misdn_lib_tone_generator_start(cl->bc); + } + + return 0; +} + +static int hanguptone_indicate(struct chan_list *cl) +{ + misdn_lib_send_tone(cl->bc,TONE_HANGUP); + return 0; +} + +static int stop_indicate(struct chan_list *cl) +{ + struct ast_channel *ast=cl->ast; + chan_misdn_log(3,cl->bc->port," --> None\n"); + misdn_lib_tone_generator_stop(cl->bc); + ast_playtones_stop(ast); + /*ast_deactivate_generator(ast);*/ + return 0; } -/** AST INDICATIONS END **/ static int start_bc_tones(struct chan_list* cl) { - manager_bchannel_activate(cl->bc); - manager_send_tone(cl->bc ,TONE_NONE); + misdn_lib_tone_generator_stop(cl->bc); cl->notxtone=0; cl->norxtone=0; return 0; @@ -1889,9 +2405,8 @@ static int start_bc_tones(struct chan_list* cl) static int stop_bc_tones(struct chan_list *cl) { - if (cl->bc) { - manager_bchannel_deactivate(cl->bc); - } + if (!cl) return -1; + cl->notxtone=1; cl->norxtone=1; @@ -1899,16 +2414,21 @@ static int stop_bc_tones(struct chan_list *cl) } -struct chan_list *init_chan_list(void) +static struct chan_list *init_chan_list(int orig) { struct chan_list *cl=malloc(sizeof(struct chan_list)); if (!cl) { - chan_misdn_log(0, 0, "misdn_request: malloc failed!"); + chan_misdn_log(-1, 0, "misdn_request: malloc failed!"); return NULL; } memset(cl,0,sizeof(struct chan_list)); + + cl->orginator=orig; + cl->need_queue_hangup=1; + cl->need_hangup=1; + cl->need_busy=1; return cl; @@ -1918,30 +2438,22 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat { struct ast_channel *tmp = NULL; - char group[BUFFERSIZE]=""; + char group[BUFFERSIZE+1]=""; char buf[128]; char buf2[128], *ext=NULL, *port_str; char *tokb=NULL, *p=NULL; int channel=0, port=0; struct misdn_bchannel *newbc = NULL; - struct chan_list *cl=init_chan_list(); + struct chan_list *cl=init_chan_list(ORG_AST); + + sprintf(buf,"%s/%s",misdn_type,(char*)data); + ast_copy_string(buf2,data, 128); - sprintf(buf,"%s/%s",type,(char*)data); - strncpy(buf2,data, 128); - buf2[127] = 0; port_str=strtok_r(buf2,"/", &tokb); ext=strtok_r(NULL,"/", &tokb); - /* - if (!ext) { - ast_log(LOG_WARNING, " --> ! IND : CALL dad:%s WITH WRONG ARGS, check extension.conf\n",ext); - - return NULL; - } - */ - if (port_str) { if (port_str[0]=='g' && port_str[1]==':' ) { /* We make a group call lets checkout which ports are in my group */ @@ -1951,11 +2463,11 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat chan_misdn_log(2, 0, " --> Group Call group: %s\n",group); } else if ((p = strchr(port_str, ':'))) { - // we have a preselected channel + /* we have a preselected channel */ *p = 0; channel = atoi(++p); port = atoi(port_str); - chan_misdn_log(2, port, " --> Call on preselected Channel (%d) on Port %d\n", channel, port); + chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel); } else { port = atoi(port_str); @@ -1969,7 +2481,7 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat if (!ast_strlen_zero(group)) { - char cfg_group[BUFFERSIZE]; + char cfg_group[BUFFERSIZE+1]; struct robin_list *rr = NULL; if (misdn_cfg_is_group_method(group, METHOD_ROUND_ROBIN)) { @@ -1993,8 +2505,9 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat if (port >= port_start) next_chan = 1; - if (port < port_start && next_chan) { - if (++robin_channel >= MAX_BCHANS) { + if (port <= port_start && next_chan) { + int maxbchans=misdn_lib_get_maxchans(port); + if (++robin_channel >= maxbchans) { robin_channel = 1; } next_chan = 0; @@ -2003,17 +2516,25 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, BUFFERSIZE); if (!strcasecmp(cfg_group, group)) { - int l1, port_up; - - misdn_cfg_get( 0, MISDN_GEN_L1_INFO_OK, &l1, sizeof(l1)); - port_up = misdn_lib_port_up(port); + int port_up; + int check; + misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(int)); + port_up = misdn_lib_port_up(port, check); + + if (check && !port_up) + chan_misdn_log(1,port,"L1 is not Up on this Port\n"); - if ((l1 && port_up) || !l1) { + if (check && port_up<0) { + ast_log(LOG_WARNING,"This port (%d) is blocked\n", port); + } + + + if ( port_up>0 ) { newbc = misdn_lib_get_free_bc(port, robin_channel); if (newbc) { chan_misdn_log(4, port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel); if (port_up) - chan_misdn_log(4, port, "def_l1:%d, portup:%d\n", l1, port_up); + chan_misdn_log(4, port, "portup:%d\n", port_up); rr->port = newbc->port; rr->channel = newbc->channel; break; @@ -2024,7 +2545,7 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat } while (!newbc && robin_channel != rr->channel); if (!newbc) - chan_misdn_log(4, port, " Failed! No free channel in group %d!", group); + chan_misdn_log(-1, port, " Failed! No free channel in group %d!", group); } else { @@ -2032,16 +2553,17 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat port=misdn_cfg_get_next_port(port)) { misdn_cfg_get( port, MISDN_CFG_GROUPNAME, cfg_group, BUFFERSIZE); - + + chan_misdn_log(3,port, "Group [%s] Port [%d]\n", group, port); if (!strcasecmp(cfg_group, group)) { - int l1, port_up; + int port_up; + int check; + misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(int)); + port_up = misdn_lib_port_up(port, check); - misdn_cfg_get( 0, MISDN_GEN_L1_INFO_OK, &l1, sizeof(l1)); - port_up = misdn_lib_port_up(port); - - chan_misdn_log(4, port, "def_l1:%d, portup:%d\n", l1, port_up); + chan_misdn_log(4, port, "portup:%d\n", port_up); - if ((l1 && port_up) || !l1) { + if ( port_up>0 ) { newbc = misdn_lib_get_free_bc(port, 0); if (newbc) break; @@ -2057,20 +2579,45 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat } if (!newbc) { - chan_misdn_log(1, 0, " --> ! No free channel chan ext:%s even after Group Call\n",ext); - chan_misdn_log(1, 0, " --> SEND: State Down\n"); + chan_misdn_log(-1, 0, "Could not create channel on port:%d with extensions:%s\n",port,ext); return NULL; } - + + /* create ast_channel and link all the objects together */ cl->bc=newbc; - tmp = misdn_new(cl, AST_STATE_RESERVED, buf, "default", ext, ext, format, port, channel); + tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel); + cl->ast=tmp; + + /* register chan in local list */ + cl_queue_chan(&cl_te, cl) ; + + /* fill in the config into the objects */ + read_config(cl, ORG_AST); + + /* important */ + cl->need_hangup=0; return tmp; } -struct ast_channel_tech misdn_tech = { +int misdn_send_text (struct ast_channel *chan, const char *text) +{ + struct chan_list *tmp=chan->tech_pvt; + + if (tmp && tmp->bc) { + ast_copy_string(tmp->bc->display,text,sizeof(tmp->bc->display)); + misdn_lib_send_event(tmp->bc, EVENT_INFORMATION); + } else { + ast_log(LOG_WARNING, "No chan_list but send_text request?\n"); + return -1; + } + + return 0; +} + +static struct ast_channel_tech misdn_tech = { .type="mISDN", .description="Channel driver for mISDN Support (Bri/Pri)", .capabilities= AST_FORMAT_ALAW , @@ -2084,11 +2631,11 @@ struct ast_channel_tech misdn_tech = { .write=misdn_write, .indicate=misdn_indication, .fixup=misdn_fixup, + .send_text=misdn_send_text, .properties=0 - /* .transfer=misdn_transfer */ }; -struct ast_channel_tech misdn_tech_wo_bridge = { +static struct ast_channel_tech misdn_tech_wo_bridge = { .type="mISDN", .description="Channel driver for mISDN Support (Bri/Pri)", .capabilities=AST_FORMAT_ALAW , @@ -2101,69 +2648,64 @@ struct ast_channel_tech misdn_tech_wo_bridge = { .write=misdn_write, .indicate=misdn_indication, .fixup=misdn_fixup, + .send_text=misdn_send_text, .properties=0 - /* .transfer=misdn_transfer */ }; -unsigned long glob_channel=0; +static unsigned long glob_channel=0; -struct ast_channel *misdn_new(struct chan_list *chlist, int state, char * name, char * context, char *exten, char *callerid, int format, int port, int c) +static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char *exten, char *callerid, int format, int port, int c) { struct ast_channel *tmp; tmp = ast_channel_alloc(1); if (tmp) { - chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s ctx:%s\n",exten,callerid, context); + chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n",exten,callerid); if (c<=0) { c=glob_channel++; snprintf(tmp->name, sizeof(tmp->name), "%s/%d-u%d", - type, port, c); + misdn_type, port, c); } else { snprintf(tmp->name, sizeof(tmp->name), "%s/%d-%d", - type, port, c); + misdn_type, port, c); } - tmp->type = type; - + tmp->type = misdn_type; + tmp->nativeformats = prefformat; + tmp->readformat = format; + tmp->rawreadformat = format; tmp->writeformat = format; + tmp->rawwriteformat = format; tmp->tech_pvt = chlist; - + int bridging; misdn_cfg_get( 0, MISDN_GEN_BRIDGING, &bridging, sizeof(int)); if (bridging) tmp->tech = &misdn_tech; else tmp->tech = &misdn_tech_wo_bridge; - - + tmp->writeformat = format; tmp->readformat = format; tmp->priority=1; - - if (context) { - ast_copy_string(tmp->context, context, sizeof(tmp->context)); - } else { - chan_misdn_log(1,0,"misdn_new: no context given.\n"); - } - - if (exten) { + if (exten) ast_copy_string(tmp->exten, exten, sizeof(tmp->exten)); - } else { + else chan_misdn_log(1,0,"misdn_new: no exten given.\n"); - } if (callerid) { char *cid_name, *cid_num; ast_callerid_parse(callerid, &cid_name, &cid_num); + if (!ast_strlen_zero(cid_num)) { tmp->cid.cid_num = strdup(cid_num); tmp->cid.cid_ani = strdup(cid_num); @@ -2180,193 +2722,107 @@ struct ast_channel *misdn_new(struct chan_list *chlist, int state, char * name, } - if (chlist->bc) { - int port=chlist->bc->port; - misdn_cfg_get( port, MISDN_CFG_LANGUAGE, tmp->language, sizeof(tmp->language)); - - { - char buf[256]; - ast_group_t pg,cg; - - misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg)); - misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg)); - - chan_misdn_log(2, port, " --> * CallGrp:%s PickupGrp:%s\n",ast_print_group(buf,sizeof(buf),cg),ast_print_group(buf,sizeof(buf),pg)); - tmp->pickupgroup=pg; - tmp->callgroup=cg; - } - misdn_cfg_get(port, MISDN_CFG_TXGAIN, &chlist->bc->txgain, sizeof(int)); - misdn_cfg_get(port, MISDN_CFG_RXGAIN, &chlist->bc->rxgain, sizeof(int)); - chan_misdn_log(2, port, " --> rxgain:%d txgain:%d\n",chlist->bc->rxgain,chlist->bc->txgain); - - } else { - chan_misdn_log(3, 0, " --> Not Setting Pickupgroup, we have no bc yet\n"); - } - ast_setstate(tmp, state); if (state == AST_STATE_RING) tmp->rings = 1; else tmp->rings = 0; + + } else { - ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); - chan_misdn_log(0,0,"Unable to allocate channel structure\n"); + chan_misdn_log(-1,0,"Unable to allocate channel structure\n"); } return tmp; } - -int misdn_tx2ast_frm(struct chan_list * tmp, char * buf, int len ) +struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame) { - struct ast_frame frame; - - /* If in hold state we drop frame .. */ - if (tmp->holded ) return 0; - - switch(tmp->state) { - case MISDN_CLEANING: - case MISDN_EXTCANTMATCH: - case MISDN_WAITING4DIGS: - return 0; - default: - break; - } - - if (tmp->norxtone) { - chan_misdn_log(3, tmp->bc->port, "misdn_tx2ast_frm: Returning because norxtone\n"); - return 0; + struct ast_frame *f,*f2; + if (tmp->trans) + f2=ast_translate(tmp->trans, frame,0); + else { + chan_misdn_log(0, tmp->bc->port, "No T-Path found\n"); + return NULL; } - frame.frametype = AST_FRAME_VOICE; - frame.subclass = AST_FORMAT_ALAW; - frame.datalen = len; - frame.samples = len ; - frame.mallocd =0 ; - frame.offset= 0 ; - frame.src = NULL; - frame.data = buf ; - - if (tmp->faxdetect || tmp->ast_dsp ) { - struct ast_frame *f,*f2; - if (tmp->trans) - f2=ast_translate(tmp->trans, &frame,0); - else { - chan_misdn_log(0, tmp->bc->port, "No T-Path found\n"); - return 0; - } - - f = ast_dsp_process(tmp->ast, tmp->dsp, f2); - if (f && (f->frametype == AST_FRAME_DTMF)) { - ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c", f->subclass); - if (f->subclass == 'f' && tmp->faxdetect) { - /* Fax tone -- Handle and return NULL */ - struct ast_channel *ast = tmp->ast; - if (!tmp->faxhandled) { - tmp->faxhandled++; - if (strcmp(ast->exten, "fax")) { - if (ast_exists_extension(ast, ast_strlen_zero(ast->macrocontext)? ast->context : ast->macrocontext, "fax", 1, AST_CID_P(ast))) { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name); - /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ - pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten); - if (ast_async_goto(ast, ast->context, "fax", 1)) - ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, ast->context); - } else - ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n",ast->context, ast->exten); + f = ast_dsp_process(tmp->ast, tmp->dsp, f2); + if (f && (f->frametype == AST_FRAME_DTMF)) { + ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c", f->subclass); + if (f->subclass == 'f' && tmp->faxdetect) { + /* Fax tone -- Handle and return NULL */ + struct ast_channel *ast = tmp->ast; + if (!tmp->faxhandled) { + tmp->faxhandled++; + if (strcmp(ast->exten, "fax")) { + if (ast_exists_extension(ast, ast_strlen_zero(ast->macrocontext)? ast->context : ast->macrocontext, "fax", 1, AST_CID_P(ast))) { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name); + /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ + pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten); + if (ast_async_goto(ast, ast->context, "fax", 1)) + ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, ast->context); } else - ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); + ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n",ast->context, ast->exten); } else - ast_log(LOG_DEBUG, "Fax already handled\n"); - frame.frametype = AST_FRAME_NULL; - frame.subclass = 0; - f = &frame; - } else if ( tmp->ast_dsp) { - struct ast_frame fr; - memset(&fr, 0 , sizeof(fr)); - fr.frametype = AST_FRAME_DTMF; - fr.subclass = f->subclass ; - fr.src=NULL; - fr.data = NULL ; - fr.datalen = 0; - fr.samples = 0 ; - fr.mallocd =0 ; - fr.offset= 0 ; - - chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n",f->subclass); - ast_queue_frame(tmp->ast, &fr); - - frame.frametype = AST_FRAME_NULL; - frame.subclass = 0; - f = &frame; - } + ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); + } else + ast_log(LOG_DEBUG, "Fax already handled\n"); + + } else if ( tmp->ast_dsp) { + chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n",f->subclass); + return f; } } - - if (tmp && tmp->ast && MISDN_ASTERISK_PVT (tmp->ast) && MISDN_ASTERISK_TECH_PVT(tmp->ast) ) { -#if MISDN_DEBUG - int i, max=5>len?len:5; - - printf("write2* %p %d bytes: ",tmp, len); - - for (i=0; i< max ; i++) printf("%2.2x ",((char*) frame.data)[i]); - printf ("\n"); -#endif - chan_misdn_log(9, tmp->bc->port, "Queueing %d bytes 2 Asterisk\n",len); - ast_queue_frame(tmp->ast,&frame); - - } else { - ast_log (LOG_WARNING, "No ast || ast->pvt || ch\n"); - } - - return 0; + + frame->frametype = AST_FRAME_NULL; + frame->subclass = 0; + return frame; } -/** Channel Queue ***/ -struct chan_list *find_chan_by_l3id(struct chan_list *list, unsigned long l3id) +static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc) { struct chan_list *help=list; for (;help; help=help->next) { - if (help->l3id == l3id ) return help; + if (help->bc == bc) return help; } - chan_misdn_log(4, list? (list->bc? list->bc->port : 0) : 0, "$$$ find_chan: No channel found with l3id:%x\n",l3id); + chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n",bc->oad,bc->dad); return NULL; } -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) { struct chan_list *help=list; for (;help; help=help->next) { - if (help->bc == bc) return help; + if (help->bc->pid == pid) return help; } - chan_misdn_log(4, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n",bc->oad,bc->dad); + chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n",pid); return NULL; } - -struct chan_list *find_holded(struct chan_list *list, struct misdn_bchannel *bc) +static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchannel *bc) { struct chan_list *help=list; - chan_misdn_log(4, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n",bc->channel, bc->oad,bc->dad); + chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n",bc->channel, bc->oad,bc->dad); for (;help; help=help->next) { chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n",help->bc->holded, help->bc->channel); if (help->bc->port == bc->port && help->bc->holded ) return help; } - chan_misdn_log(4, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n",bc->oad,bc->dad); + chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n",bc->oad,bc->dad); return NULL; } -void cl_queue_chan(struct chan_list **list, struct chan_list *chan) +static void cl_queue_chan(struct chan_list **list, struct chan_list *chan) { chan_misdn_log(4, chan->bc? chan->bc->port : 0, "* Queuing chan %p\n",chan); @@ -2382,12 +2838,13 @@ void cl_queue_chan(struct chan_list **list, struct chan_list *chan) ast_mutex_unlock(&cl_te_lock); } -void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan) +static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan) { if (chan->dsp) ast_dsp_free(chan->dsp); if (chan->trans) ast_translator_free_path(chan->trans); + ast_mutex_lock(&cl_te_lock); @@ -2419,35 +2876,88 @@ void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan) /** Channel Queue End **/ +int pbx_start_chan(struct chan_list *ch) +{ + int ret=ast_pbx_start(ch->ast); + + if (ret>=0) + ch->need_hangup=0; + else + ch->need_hangup=1; + + return ret; +} + +static void hangup_chan(struct chan_list *ch) +{ + if (!ch) { + cb_log(1,0,"Cannot hangup chan, no ch\n"); + return; + } + + cb_log(1,ch->bc?ch->bc->port:0,"hangup_chan\n"); + + if (ch->need_hangup) + { + cb_log(1,ch->bc->port,"-> hangup\n"); + send_cause2ast(ch->ast,ch->bc,ch); + ch->need_hangup=0; + ch->need_queue_hangup=0; + if (ch->ast) + ast_hangup(ch->ast); + return; + } + + if (!ch->need_queue_hangup) { + cb_log(1,ch->bc->port,"No need to queue hangup\n"); + } + + ch->need_queue_hangup=0; + if (ch->ast) { + send_cause2ast(ch->ast,ch->bc,ch); + + if (ch->ast) + ast_queue_hangup(ch->ast); + cb_log(1,ch->bc->port,"-> queue_hangup\n"); + } else { + cb_log(1,ch->bc->port,"Cannot hangup chan, no ast\n"); + } +} /** Isdn asks us to release channel, pendant to misdn_hangup **/ static void release_chan(struct misdn_bchannel *bc) { struct ast_channel *ast=NULL; - { struct chan_list *ch=find_chan_by_bc(cl_te, bc); - if (!ch) ch=find_chan_by_l3id (cl_te, bc->l3_id); + if (!ch) { + chan_misdn_log(0, bc->port, "release_chan: Ch not found!\n"); + return; + } - release_lock; if (ch->ast) { ast=ch->ast; } - release_unlock; - chan_misdn_log(1, bc->port, "Trying to Release bc with l3id: %x\n",bc->l3_id); + chan_misdn_log(1, bc->port, "release_chan: bc with l3id: %x\n",bc->l3_id); + + /*releaseing jitterbuffer*/ + if (ch->jb ) { + misdn_jb_destroy(ch->jb); + ch->jb=NULL; + } else { + if (!bc->nojitter) + chan_misdn_log(5,bc->port,"Jitterbuffer already destroyed.\n"); + } + if (ch) { - if (ast) - chan_misdn_trace_call(ast,1,"I->*: EVENT_RELEASE\n"); close(ch->pipe[0]); close(ch->pipe[1]); + - if (ast && MISDN_ASTERISK_PVT(ast)) { + if (ast && MISDN_ASTERISK_TECH_PVT(ast)) { chan_misdn_log(1, bc->port, "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s\n",bc?bc->pid:-1, ast->context, ast->exten,AST_CID_P(ast),misdn_get_ch_state(ch)); chan_misdn_log(3, bc->port, " --> * State Down\n"); - /* copy cause */ - send_cause2ast(ast,bc); - MISDN_ASTERISK_TECH_PVT(ast)=NULL; @@ -2455,58 +2965,9 @@ static void release_chan(struct misdn_bchannel *bc) { chan_misdn_log(3, bc->port, " --> Setting AST State to down\n"); ast_setstate(ast, AST_STATE_DOWN); } - - switch(ch->state) { - case MISDN_EXTCANTMATCH: - case MISDN_WAITING4DIGS: - { - chan_misdn_log(3, bc->port, " --> * State Wait4dig | ExtCantMatch\n"); - ast_hangup(ast); - } - break; - - case MISDN_DIALING: - case MISDN_CALLING_ACKNOWLEDGE: - case MISDN_PROGRESS: - chan_misdn_log(2, bc->port, "* --> In State Dialin\n"); - chan_misdn_log(2, bc->port, "* --> Queue Hangup\n"); - - - ast_queue_hangup(ast); - break; - case MISDN_CALLING: - - chan_misdn_log(2, bc->port, "* --> In State Callin\n"); - - if (!bc->nt) { - chan_misdn_log(2, bc->port, "* --> Queue Hangup\n"); - ast_queue_hangup(ast); - } else { - chan_misdn_log(2, bc->port, "* --> Hangup\n"); - ast_queue_hangup(ast); - //ast_hangup(ast); - } - break; - - case MISDN_CLEANING: - /* this state comes out of ast so we mustnt call a ast function ! */ - chan_misdn_log(2, bc->port, "* --> In StateCleaning\n"); - break; - case MISDN_HOLD_DISCONNECT: - chan_misdn_log(2, bc->port, "* --> In HOLD_DISC\n"); - break; - default: - chan_misdn_log(2, bc->port, "* --> In State Default\n"); - chan_misdn_log(2, bc->port, "* --> Queue Hangup\n"); - - - if (ast && MISDN_ASTERISK_PVT(ast)) { - ast_queue_hangup(ast); - } else { - chan_misdn_log (0, bc->port, "!! Not really queued!\n"); - } - } } + + ch->state=MISDN_CLEANING; cl_dequeue_chan(&cl_te, ch); free(ch); @@ -2517,7 +2978,7 @@ static void release_chan(struct misdn_bchannel *bc) { } /*** release end **/ -void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan) +static void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan) { chan_misdn_log(4,0,"TRANSFERING %s to %s\n",holded_chan->ast->name, tmp_ch->ast->name); @@ -2526,14 +2987,12 @@ void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan) ast_moh_stop(AST_BRIDGED_P(holded_chan->ast)); holded_chan->state=MISDN_CONNECTED; - holded_chan->holded=0; misdn_lib_transfer(holded_chan->bc?holded_chan->bc:holded_chan->holded_bc); - ast_channel_masquerade(holded_chan->ast, AST_BRIDGED_P(tmp_ch->ast)); } -void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct ast_channel *ast) +static void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct ast_channel *ast) { char predial[256]=""; char *p = predial; @@ -2543,7 +3002,7 @@ void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct strncpy(predial, ast->exten, sizeof(predial) -1 ); ch->state=MISDN_DIALING; - + if (bc->nt) { int ret; ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); @@ -2556,15 +3015,20 @@ void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct } } - manager_send_tone(bc,TONE_DIAL); + if ( !bc->nt && (ch->orginator==ORG_MISDN) && !ch->incoming_early_audio ) + chan_misdn_log(1,bc->port, " --> incoming_early_audio off\n"); + else + dialtone_indicate(ch); chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, AST_CID_P(ast)); strncpy(ast->exten,"s", 2); - if (ast_pbx_start(ast)<0) { + if (pbx_start_chan(ch)<0) { ast=NULL; - manager_send_tone(bc,TONE_BUSY); + hangup_chan(ch); + hanguptone_indicate(ch); + if (bc->nt) misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); else @@ -2591,7 +3055,19 @@ void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct -void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc) { +static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch) { + if (!ast) { + chan_misdn_log(1,0,"send_cause2ast: No Ast\n"); + return; + } + if (!bc) { + chan_misdn_log(1,0,"send_cause2ast: No BC\n"); + return; + } + if (!ch) { + chan_misdn_log(1,0,"send_cause2ast: No Ch\n"); + return; + } ast->hangupcause=bc->cause; @@ -2603,55 +3079,122 @@ void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc) { case 4: case 22: case 27: + /* + * Not Queueing the Congestion anymore, since we want to hear + * the inband message + * chan_misdn_log(1, bc?bc->port:0, " --> * SEND: Queue Congestion pid:%d\n", bc?bc->pid:-1); + ch->state=MISDN_BUSY; ast_queue_control(ast, AST_CONTROL_CONGESTION); + */ break; case 21: case 17: /* user busy */ + + ch->state=MISDN_BUSY; + + if (!ch->need_busy) { + chan_misdn_log(1,bc?bc->port:0, "Queued busy already\n"); + break; + } + chan_misdn_log(1, bc?bc->port:0, " --> * SEND: Queue Busy pid:%d\n", bc?bc->pid:-1); ast_queue_control(ast, AST_CONTROL_BUSY); + ch->need_busy=0; + break; } } +void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch) +{ + char *tmp; + tmp=pbx_builtin_getvar_helper(chan,"MISDN_PID"); + if (tmp) { + ch->other_pid=atoi(tmp); + chan_misdn_log(1,bc->port,"IMPORT_PID: importing pid:%s\n",tmp); + + if (ch->other_pid >0) { + ch->other_ch=find_chan_by_pid(cl_te,ch->other_pid); + if (ch->other_ch) ch->other_ch->other_ch=ch; + } + } +} + +void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch) +{ + char tmp[32]; + + chan_misdn_log(1,bc->port,"EXPORT_PID: pid:%d\n",bc->pid); + sprintf(tmp,"%d",bc->pid); + pbx_builtin_setvar_helper(chan,"_MISDN_PID",tmp); +} + + + /************************************************************/ /* Receive Events from isdn_lib here */ /************************************************************/ -enum event_response_e +static enum event_response_e cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) { struct chan_list *ch=find_chan_by_bc(cl_te, bc); - if (!ch) - ch=find_chan_by_l3id(cl_te, bc->l3_id); + if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /* Debug Only Non-Bchan */ + int debuglevel=1; - if (event != EVENT_BCHAN_DATA) { /* Debug Only Non-Bchan */ - chan_misdn_log(1, bc->port, "I IND :%s oad:%s dad:%s port:%d\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->port); - misdn_lib_log_ies(bc); + if ( event==EVENT_CLEANUP && !user_data) + debuglevel=5; + + chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch?misdn_get_ch_state(ch):"none"); + if (debuglevel==1) { + misdn_lib_log_ies(bc); + chan_misdn_log(4,bc->port," --> bc_state:%s\n",bc_state2str(bc->bc_state)); + } } - if (event != EVENT_SETUP) { - if (!ch) { - if (event != EVENT_CLEANUP ) - ast_log(LOG_WARNING, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n",bc->l3_id, bc, manager_isdn_get_info( event), bc->port,bc->channel); - return -1; + if (!ch) { + switch(event) { + case EVENT_SETUP: + case EVENT_DISCONNECT: + case EVENT_PORT_ALARM: + case EVENT_RETRIEVE: + case EVENT_NEW_BC: + break; + case EVENT_RELEASE_COMPLETE: + chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n"); + break; + case EVENT_CLEANUP: + case EVENT_TONE_GENERATE: + case EVENT_BCHAN_DATA: + return -1; + + default: + chan_misdn_log(1,bc->port, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n",bc->l3_id, bc, manager_isdn_get_info( event), bc->port,bc->channel); + return -1; } } if (ch ) { switch (event) { + case EVENT_TONE_GENERATE: + break; + case EVENT_DISCONNECT: case EVENT_RELEASE: case EVENT_RELEASE_COMPLETE: case EVENT_CLEANUP: + case EVENT_TIMEOUT: + if (!ch->ast) + chan_misdn_log(3,bc->port,"ast_hangup already called, so we have no ast ptr anymore in event(%s)\n",manager_isdn_get_info(event)); break; default: if ( !ch->ast || !MISDN_ASTERISK_PVT(ch->ast) || !MISDN_ASTERISK_TECH_PVT(ch->ast)) { if (event!=EVENT_BCHAN_DATA) - ast_log(LOG_WARNING, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event)); + ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event)); return -1; } } @@ -2659,13 +3202,38 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) switch (event) { + case EVENT_PORT_ALARM: + { + int boa=0; + + misdn_cfg_get( bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(int)); + if (boa) { + cb_log(1,bc->port," --> blocking\n"); + misdn_lib_port_block(bc->port); + } + } + break; + + case EVENT_BCHAN_ACTIVATED: + break; + case EVENT_NEW_L3ID: ch->l3id=bc->l3_id; + ch->addr=bc->addr; break; case EVENT_NEW_BC: + if (!ch) { + ch=find_holded(cl_te,bc); + } + + if (!ch) { + ast_log(LOG_WARNING,"NEW_BC without chan_list?\n"); + break; + } + if (bc) - ch->bc=bc; + ch->bc=(struct misdn_bchannel*)user_data; break; case EVENT_DTMF_TONE: @@ -2682,9 +3250,12 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) fr.mallocd =0 ; fr.offset= 0 ; - chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf); - - ast_queue_frame(ch->ast, &fr); + if (!ch->ignore_dtmf) { + chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf); + ast_queue_frame(ch->ast, &fr); + } else { + chan_misdn_log(2, bc->port, " --> Ingoring DTMF:%c due to bridge flags\n", bc->dtmf); + } } break; case EVENT_STATUS: @@ -2694,8 +3265,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) { int stop_tone; misdn_cfg_get( 0, MISDN_GEN_STOP_TONE, &stop_tone, sizeof(int)); - if ( stop_tone && bc->tone != TONE_NONE) { - manager_send_tone(bc,TONE_NONE); + if ( stop_tone ) { + stop_indicate(ch); } if (ch->state == MISDN_WAITING4DIGS ) { @@ -2714,31 +3285,46 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) } /* chan_misdn_log(5, bc->port, "Can Match Extension: dad:%s oad:%s\n",bc->dad,bc->oad);*/ - char bc_context[BUFFERSIZE]; - misdn_cfg_get( bc->port, MISDN_CFG_CONTEXT, bc_context, BUFFERSIZE); - if(!ast_canmatch_extension(ch->ast, bc_context, bc->dad, 1, bc->oad)) { - chan_misdn_log(0, bc->port, "Extension can never match, so disconnecting\n"); - manager_send_tone(bc,TONE_BUSY); + /* Check for Pickup Request first */ + if (!strcmp(ch->ast->exten, ast_pickup_ext())) { + int ret;/** Sending SETUP_ACK**/ + ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); + if (ast_pickup_call(ch->ast)) { + hangup_chan(ch); + } else { + struct ast_channel *chan=ch->ast; + ch->state = MISDN_CALLING_ACKNOWLEDGE; + ast_setstate(chan, AST_STATE_DOWN); + hangup_chan(ch); + ch->ast=NULL; + break; + } + } + + if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { + + chan_misdn_log(-1, bc->port, "Extension can never match, so disconnecting\n"); + if (bc->nt) + hanguptone_indicate(ch); ch->state=MISDN_EXTCANTMATCH; bc->out_cause=1; - if (bc->nt) - misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); - else - misdn_lib_send_event(bc, EVENT_DISCONNECT ); + + misdn_lib_send_event(bc, EVENT_DISCONNECT ); + break; } - if (ast_exists_extension(ch->ast, bc_context, bc->dad, 1, bc->oad)) { + if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { ch->state=MISDN_DIALING; - manager_send_tone(bc,TONE_NONE); -/* chan_misdn_log(1, bc->port, " --> * Starting Ast ctx:%s\n", ch->ast->context);*/ - if (ast_pbx_start(ch->ast)<0) { - chan_misdn_log(0, bc->port, "ast_pbx_start returned < 0 in INFO\n"); - manager_send_tone(bc,TONE_BUSY); - if (bc->nt) - misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); - else - misdn_lib_send_event(bc, EVENT_DISCONNECT ); + stop_indicate(ch); +/* chan_misdn_log(1, bc->port, " --> * Starting Ast ctx:%s\n", ch->context);*/ + if (pbx_start_chan(ch)<0) { + hangup_chan(ch); + + chan_misdn_log(-1, bc->port, "ast_pbx_start returned < 0 in INFO\n"); + if (bc->nt) hanguptone_indicate(ch); + + misdn_lib_send_event(bc, EVENT_DISCONNECT ); } } @@ -2771,7 +3357,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ast_queue_frame(ch->ast, &fr); } - } } break; @@ -2784,6 +3369,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) } } + int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad); if (!bc->nt && ! msn_valid) { chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n"); @@ -2793,119 +3379,61 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) print_bearer(bc); { - struct chan_list *ch=init_chan_list(); + struct chan_list *ch=init_chan_list(ORG_MISDN); struct ast_channel *chan; - char name[128]; - if (!ch) { chan_misdn_log(0, bc->port, "cb_events: malloc for chan_list failed!\n"); return 0;} + + if (!ch) { chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n"); return 0;} ch->bc = bc; ch->l3id=bc->l3_id; ch->addr=bc->addr; ch->orginator = ORG_MISDN; + chan=misdn_new(ch, AST_STATE_RESERVED,bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel); + ch->ast = chan; + + read_config(ch, ORG_MISDN); - { - char prefix[BUFFERSIZE]=""; - switch( bc->onumplan ) { - case NUMPLAN_INTERNATIONAL: - misdn_cfg_get( bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE); - break; - - case NUMPLAN_NATIONAL: - misdn_cfg_get( bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE); - break; - - - case NUMPLAN_SUBSCRIBER: - /* dunno what to do here ? */ - break; + export_ch(chan, bc, ch); - case NUMPLAN_UNKNOWN: - break; - default: - break; - } + ch->ast->rings=1; + ast_setstate(ch->ast, AST_STATE_RINGING); - { - int l = strlen(prefix) + strlen(bc->oad); - char tmp[l+1]; - strcpy(tmp,prefix); - strcat(tmp,bc->oad); - strcpy(bc->oad,tmp); - } - - if (!ast_strlen_zero(bc->oad)) - sprintf(name,"mISDN/%d/%s",bc->port,bc->oad); - else - sprintf(name,"mISDN/%d",bc->port); + int pres,screen; + switch (bc->pres) { + case 1: + pres=AST_PRES_RESTRICTED; chan_misdn_log(2,bc->port," --> PRES: Restricted (1)\n"); + break; + case 2: + pres=AST_PRES_UNAVAILABLE; chan_misdn_log(2,bc->port," --> PRES: Restricted (2)\n"); + break; + default: + pres=AST_PRES_ALLOWED; chan_misdn_log(2,bc->port," --> PRES: Restricted (%d)\n", bc->pres); + } - if (!ast_strlen_zero(bc->dad)) { - strncpy(bc->orig_dad,bc->dad, sizeof(bc->orig_dad)); - bc->orig_dad[sizeof(bc->orig_dad)-1] = 0; - } - - if ( ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) { - strncpy(bc->dad,bc->keypad, sizeof(bc->dad)); - bc->dad[sizeof(bc->dad)-1] = 0; - } - prefix[0] = 0; - - switch( bc->dnumplan ) { - case NUMPLAN_INTERNATIONAL: - misdn_cfg_get( bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE); - break; - - case NUMPLAN_NATIONAL: - misdn_cfg_get( bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE); - break; - - - case NUMPLAN_SUBSCRIBER: - /* dunno what to do here ? */ - break; - - case NUMPLAN_UNKNOWN: - break; + switch (bc->screen) { + case 0: + screen=AST_PRES_USER_NUMBER_UNSCREENED; chan_misdn_log(2,bc->port," --> SCREEN: Unscreened (0)\n"); + break; + case 1: + screen=AST_PRES_USER_NUMBER_PASSED_SCREEN; chan_misdn_log(2,bc->port," --> SCREEN: Passed screen (1)\n"); + break; + case 2: + screen=AST_PRES_USER_NUMBER_FAILED_SCREEN; chan_misdn_log(2,bc->port," --> SCREEN: failed screen (2)\n"); + break; + case 3: + screen=AST_PRES_NETWORK_NUMBER; chan_misdn_log(2,bc->port," --> SCREEN: Network Number (3)\n"); + break; default: - break; - } - - { - int l = strlen(prefix) + strlen(bc->dad); - char tmp[l+1]; - strcpy(tmp,prefix); - strcat(tmp,bc->dad); - strcpy(bc->dad,tmp); - } - - char bc_context[BUFFERSIZE]; - misdn_cfg_get( bc->port, MISDN_CFG_CONTEXT, bc_context, BUFFERSIZE); - chan=misdn_new(ch, AST_STATE_RING,name ,bc_context, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel); - - if (!chan) { - misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); - return 0; - } - - ch->ast = chan; - pbx_builtin_setvar_helper(ch->ast,"REDIRECTING_NUMBER",bc->rad); - + screen=AST_PRES_USER_NUMBER_UNSCREENED; chan_misdn_log(2,bc->port," --> SCREEN: Unscreened (%d)\n",bc->screen); } - + chan->cid.cid_pres=pres+screen; - chan_misdn_trace_call(chan,1,"I->*: EVENT_SETUP\n"); - - if ( bc->pres ) { - chan->cid.cid_pres=AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; - } else { - chan->cid.cid_pres=AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; - } - pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability)); chan->transfercapability=bc->capability; - + switch (bc->capability) { case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: pbx_builtin_setvar_helper(chan,"CALLTYPE","DIGITAL"); @@ -2917,113 +3445,88 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) /** queue new chan **/ cl_queue_chan(&cl_te, ch) ; - - /* - added support for s extension hope it will help those poor cretains - which haven't overlap dial. - */ - { - - misdn_cfg_get( bc->port, MISDN_CFG_LANGUAGE, chan->language, sizeof(chan->language)); - - } - - { - int eb3; - - misdn_cfg_get( bc->port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int)); - bc->early_bconnect=eb3; - - } - { - int ec, ectr; - - misdn_cfg_get( bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); - - misdn_cfg_get( bc->port, MISDN_CFG_ECHOTRAINING, &ectr, sizeof(int)); - if (ec == 1 ) { - bc->ec_enable=1; - } else if ( ec > 1 ) { - bc->ec_enable=1; - bc->ec_deftaps=ec; - } - - if ( ectr>=0 ) { - bc->ec_training=ectr; + if (!strstr(ch->allowed_bearers,"all")) { + int i; + for (i=0; i< sizeof(allowed_bearers_array)/sizeof(struct allowed_bearers); i++) { + if (allowed_bearers_array[i].cap == bc->capability) { + if ( !strstr( ch->allowed_bearers, allowed_bearers_array[i].name)) { + chan_misdn_log(0,bc->port,"Bearer Not allowed\b"); + bc->out_cause=88; + + ch->state=MISDN_EXTCANTMATCH; + misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); + return RESPONSE_OK; + } + } + } } - - if (bc->urate>0) { - char buf[16]; - snprintf(buf,16,"%d",bc->urate); - pbx_builtin_setvar_helper(chan,"MISDN_URATE",buf); - } - - - - /** - from here on we start the PBX, so no configuration should - be considered anymore - **/ - - int ai; - misdn_cfg_get( bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai)); - if ( ai ) { - do_immediate_setup(bc, ch , chan); - break; - } - - - int immediate; - misdn_cfg_get( bc->port, MISDN_CFG_IMMEDIATE, &immediate, sizeof(int)); - - if (ast_strlen_zero(bc->orig_dad) && immediate ) { - do_immediate_setup(bc, ch , chan); - break; - } - /* Check for Pickup Request first */ if (!strcmp(chan->exten, ast_pickup_ext())) { int ret;/** Sending SETUP_ACK**/ ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); - if (ast_pickup_call(chan)) { - ast_hangup(chan); + hangup_chan(ch); } else { ch->state = MISDN_CALLING_ACKNOWLEDGE; - - ch->ast=NULL; - ast_setstate(chan, AST_STATE_DOWN); - ast_hangup(chan); - + hangup_chan(ch); + ch->ast=NULL; break; } } - /** Now after we've finished configuring our channel object - we'll jump into the dialplan **/ + /* + added support for s extension hope it will help those poor cretains + which haven't overlap dial. + */ + { + int ai; + misdn_cfg_get( bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai)); + if ( ai ) { + do_immediate_setup(bc, ch , chan); + break; + } + + + + } + + /* check if we should jump into s when we have no dad */ + { + int im; + misdn_cfg_get( bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im)); + if ( im && ast_strlen_zero(bc->dad) ) { + do_immediate_setup(bc, ch , chan); + break; + } + } + - char bc_context[BUFFERSIZE]; - misdn_cfg_get( bc->port, MISDN_CFG_CONTEXT, bc_context, BUFFERSIZE); - if(!ast_canmatch_extension(ch->ast, bc_context, bc->dad, 1, bc->oad)) { - chan_misdn_log(0, bc->port, "Extension can never match, so disconnecting\n"); - manager_send_tone(bc,TONE_BUSY); + chan_misdn_log(5,bc->port,"CONTEXT:%s\n",ch->context); + if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { + + chan_misdn_log(-1, bc->port, "Extension can never match, so disconnecting\n"); + + if (bc->nt) + hanguptone_indicate(ch); ch->state=MISDN_EXTCANTMATCH; bc->out_cause=1; + if (bc->nt) misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); else - misdn_lib_send_event(bc, EVENT_DISCONNECT ); + misdn_lib_send_event(bc, EVENT_RELEASE ); + break; } - if (ast_exists_extension(ch->ast, bc_context, bc->dad, 1, bc->oad)) { + if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { ch->state=MISDN_DIALING; - - if (bc->nt) { + + if (bc->nt || (bc->need_more_infos && misdn_lib_is_ptp(bc->port)) ) { int ret; ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); } else { @@ -3031,31 +3534,53 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ret= misdn_lib_send_event(bc, EVENT_PROCEEDING ); } - if (ast_pbx_start(chan)<0) { - chan_misdn_log(0, bc->port, "ast_pbx_start returned <0 in SETUP\n"); + if (pbx_start_chan(ch)<0) { + hangup_chan(ch); + + chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n"); chan=NULL; - manager_send_tone(bc,TONE_BUSY); - if (bc->nt) + + if (bc->nt) { + hanguptone_indicate(ch); misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); - else - misdn_lib_send_event(bc, EVENT_DISCONNECT ); + } else + misdn_lib_send_event(bc, EVENT_RELEASE); } } else { - int ret= misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); - if (ret == -ENOCHAN) { - ast_log(LOG_WARNING,"Channel was catched, before we could Acknowledge\n"); - misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); + + if (bc->sending_complete) { + ch->state=MISDN_EXTCANTMATCH; + bc->out_cause=1; + + if (bc->nt) { + chan_misdn_log(0,bc->port," --> sending_complete so we never match ..\n"); + misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE); + } else { + chan_misdn_log(0,bc->port," --> sending_complete so we never match ..\n"); + misdn_lib_send_event(bc, EVENT_RELEASE); + } + + } else { + + int ret= misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); + if (ret == -ENOCHAN) { + ast_log(LOG_WARNING,"Channel was catched, before we could Acknowledge\n"); + misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); + } + /* send tone to phone :) */ + + /** ADD IGNOREPAT **/ + + int stop_tone; + misdn_cfg_get( 0, MISDN_GEN_STOP_TONE, &stop_tone, sizeof(int)); + if ( (!ast_strlen_zero(bc->dad)) && stop_tone ) + stop_indicate(ch); + else { + dialtone_indicate(ch); + } + + ch->state=MISDN_WAITING4DIGS; } - /* send tone to phone :) */ - - int stop_tone; - misdn_cfg_get( 0, MISDN_GEN_STOP_TONE, &stop_tone, sizeof(int)); - if ( (!ast_strlen_zero(bc->dad)) && stop_tone ) - manager_send_tone(bc,TONE_NONE); - else - manager_send_tone(bc,TONE_DIAL); - - ch->state=MISDN_WAITING4DIGS; } } @@ -3094,6 +3619,10 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) misdn_inband_avail(bc) ) { start_bc_tones(ch); } + + ch->state = MISDN_PROCEEDING; + + ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING); } break; case EVENT_PROGRESS: @@ -3121,162 +3650,272 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) cb_log(1,bc->port,"Set State Ringing\n"); if ( misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) { - start_bc_tones(ch); - } + cb_log(1,bc->port,"Starting Tones, we have inband Data\n"); + start_bc_tones(ch); + } else { + cb_log(1,bc->port,"We have no inband Data, the other end must create ringing\n"); + if (ch->far_alerting) { + cb_log(1,bc->port,"The other end can not do ringing eh ?.. we must do all ourself.."); + start_bc_tones(ch); + /*tone_indicate(ch, TONE_FAR_ALERTING);*/ + } + } } break; case EVENT_CONNECT: + { + /*we answer when we've got our very new L3 ID from the NT stack */ misdn_lib_send_event(bc,EVENT_CONNECT_ACKNOWLEDGE); + + struct ast_channel *bridged=AST_BRIDGED_P(ch->ast); + + misdn_lib_echo(bc,0); + stop_indicate(ch); + + if (bridged && !strcasecmp(bridged->tech->type,"mISDN")) { + struct chan_list *bridged_ch=MISDN_ASTERISK_TECH_PVT(bridged); + + chan_misdn_log(1,bc->port," --> copying cpndialplan:%d and cad:%s to the A-Channel\n",bc->cpnnumplan,bc->cad); + if (bridged_ch) { + bridged_ch->bc->cpnnumplan=bc->cpnnumplan; + ast_copy_string(bridged_ch->bc->cad,bc->cad,sizeof(bc->cad)); + } + } + } + + + /* notice that we don't break here!*/ + case EVENT_CONNECT_ACKNOWLEDGE: { - bc->state=STATE_CONNECTED; - ch->l3id=bc->l3_id; ch->addr=bc->addr; start_bc_tones(ch); - chan_misdn_trace_call(ch->ast,1,"I->*: EVENT_CONNECT\n"); ch->state = MISDN_CONNECTED; ast_queue_control(ch->ast, AST_CONTROL_ANSWER); } break; case EVENT_DISCONNECT: - { - + /*we might not have an ch->ast ptr here anymore*/ + if (ch) { struct chan_list *holded_ch=find_holded(cl_te, bc); - - - send_cause2ast(ch->ast,bc); - - if (misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) { + + chan_misdn_log(3,bc->port," --> org:%d nt:%d, inbandavail:%d state:%d\n", ch->orginator, bc->nt, misdn_inband_avail(bc), ch->state); + if ( ch->orginator==ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) { /* If there's inband information available (e.g. a recorded message saying what was wrong with the dialled number, or perhaps even giving an alternative number, then play it instead of immediately releasing the call */ + chan_misdn_log(1,bc->port, " --> Inband Info Avail, not sending RELEASE\n"); + + ch->state=MISDN_DISCONNECTED; start_bc_tones(ch); break; } /*Check for holded channel, to implement transfer*/ - if (holded_ch ) { + if (holded_ch && ch->ast ) { + cb_log(1,bc->port," --> found holded ch\n"); if (ch->state == MISDN_CONNECTED ) { misdn_transfer_bc(ch, holded_ch) ; - misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); - break; } + hangup_chan(ch); + release_chan(bc); + break; } stop_bc_tones(ch); - bc->out_cause=16; - misdn_lib_send_event(bc,EVENT_RELEASE); - + hangup_chan(ch); } + bc->out_cause=-1; + if (bc->need_release) misdn_lib_send_event(bc,EVENT_RELEASE); break; case EVENT_RELEASE: { - - switch ( bc->cause) { - - case -1: - /* - OK, it really sucks, this is a RELEASE from NT-Stack So we take - it and return easylie, It seems that we've send a DISCONNECT - before, so we should RELEASE_COMPLETE after that Disconnect - (looks like ALERTING State at misdn_hangup !! - */ - return RESPONSE_OK; - break; - } - - bc->out_cause=16; - stop_bc_tones(ch); + hangup_chan(ch); release_chan(bc); + + if (bc->need_release_complete) + misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); } break; case EVENT_RELEASE_COMPLETE: { stop_bc_tones(ch); + hangup_chan(ch); + release_chan(bc); + if(ch) + ch->state=MISDN_CLEANING; + } + break; + case EVENT_CLEANUP: + { + stop_bc_tones(ch); + + switch(ch->state) { + case MISDN_CALLING: + bc->cause=27; /* Destination out of order */ + break; + default: + break; + } + + hangup_chan(ch); release_chan(bc); } break; + + case EVENT_TONE_GENERATE: + { + int tone_len=bc->tone_cnt; + struct ast_channel *ast=ch->ast; + void *tmp; + int res; + int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples); + + chan_misdn_log(9,bc->port,"TONE_GEN: len:%d\n"); + + if (!ast) break; + + if (!ast->generator) break; + + + tmp = ast->generatordata; + ast->generatordata = NULL; + generate = ast->generator->generate; + + if (tone_len <0 || tone_len > 512 ) { + ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n",tone_len); + tone_len=128; + } + + res = generate(ast, tmp, tone_len, tone_len); + ast->generatordata = tmp; + + if (res) { + ast_log(LOG_WARNING, "Auto-deactivating generator\n"); + ast_deactivate_generator(ast); + } else { + bc->tone_cnt=0; + } + } + break; + case EVENT_BCHAN_DATA: { - chan_misdn_trace_call(ch->ast,3,"I->*: EVENT_B_DATA len=%d\n",bc->bframe_len); - - if ( !misdn_cap_is_speech(ch->bc->capability) || bc->nojitter) { - misdn_tx2ast_frm(ch, bc->bframe, bc->bframe_len ); + if ( !misdn_cap_is_speech(ch->bc->capability) ) { + struct ast_frame frame; + /*In Data Modes we queue frames*/ + frame.frametype = AST_FRAME_VOICE; /*we have no data frames yet*/ + frame.subclass = AST_FORMAT_ALAW; + frame.datalen = bc->bframe_len; + frame.samples = bc->bframe_len ; + frame.mallocd =0 ; + frame.offset= 0 ; + frame.src = NULL; + frame.data = bc->bframe ; + + ast_queue_frame(ch->ast,&frame); } else { - int len=bc->bframe_len; - int free=misdn_ibuf_freecount(bc->astbuf); + fd_set wrfs; + struct timeval tv; + tv.tv_sec=0; + tv.tv_usec=0; + + FD_ZERO(&wrfs); + FD_SET(ch->pipe[1],&wrfs); - if (bc->bframe_len > free) { - ast_log(LOG_DEBUG, "sbuf overflow!\n"); - len=misdn_ibuf_freecount(bc->astbuf); + int t=select(FD_SETSIZE,NULL,&wrfs,NULL,&tv); - if (len == 0) { - ast_log(LOG_WARNING, "BCHAN_DATA: write buffer overflow port:%d channel:%d!\n",bc->port,bc->channel); - } + if (!t) { + chan_misdn_log(9, bc->port, "Select Timed out\n"); + break; } - misdn_ibuf_memcpy_w(bc->astbuf, bc->bframe, len); + if (t<0) { + chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n",strerror(errno)); + break; + } - { - char blah[1]="\0"; -#ifdef FLATTEN_JITTER - { - struct timeval tv; - gettimeofday(&tv,NULL); - - if (tv.tv_usec % 10000 > 0 ) { - write(ch->pipe[1], blah,sizeof(blah)); - bc->time_usec=tv.tv_usec; - } - } -#else - write(ch->pipe[1], blah,sizeof(blah)); -#endif - + if (FD_ISSET(ch->pipe[1],&wrfs)) { + chan_misdn_log(9, bc->port, "writing %d bytes 2 asterisk\n",bc->bframe_len); + int ret=write(ch->pipe[1], bc->bframe, bc->bframe_len); + if (ret<=0) { + chan_misdn_log(-1, bc->port, "Write returned <=0 (err=%s)\n",strerror(errno)); + } + } else { + chan_misdn_log(1, bc->port, "Wripe Pipe full!\n"); } } - } break; case EVENT_TIMEOUT: - break; /* Ignore now .. */ { - switch (ch->state) { + if (ch && bc) + chan_misdn_log(1,bc->port,"--> state: %s\n",misdn_get_ch_state(ch)); + + switch (ch->state) { case MISDN_CALLING: - chan_misdn_log(0, bc?bc->port:0, "GOT TIMOUT AT CALING pid:%d\n", bc?bc->pid:-1); - break; case MISDN_DIALING: case MISDN_PROGRESS: - break; + case MISDN_ALERTING: + case MISDN_PROCEEDING: + case MISDN_CALLING_ACKNOWLEDGE: + if (bc->nt) { + bc->progress_indicator=8; + hanguptone_indicate(ch); + } + + bc->out_cause=1; + misdn_lib_send_event(bc,EVENT_DISCONNECT); + break; + + case MISDN_WAITING4DIGS: + if (bc->nt) { + bc->progress_indicator=8; + bc->out_cause=1; + hanguptone_indicate(ch); + misdn_lib_send_event(bc,EVENT_DISCONNECT); + } else { + bc->out_cause=16; + misdn_lib_send_event(bc,EVENT_RELEASE); + } + + break; + + + case MISDN_CLEANING: + chan_misdn_log(1,bc->port," --> in state cleaning .. so ingoring, the stack should clean it for us\n"); + break; + default: misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); } } break; - case EVENT_CLEANUP: - { - stop_bc_tones(ch); - release_chan(bc); - } - break; + /***************************/ /** Suplementary Services **/ /***************************/ case EVENT_RETRIEVE: { + ch=find_holded(cl_te, bc); + if (!ch) { + ast_log(LOG_WARNING, "Found no Holded channel, cannot Retrieve\n"); + misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT); + break; + } struct ast_channel *hold_ast=AST_BRIDGED_P(ch->ast); ch->state = MISDN_CONNECTED; @@ -3297,34 +3936,77 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) misdn_cfg_get( bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(int)); if (!hold_allowed) { - chan_misdn_log(0, bc->port, "Hold not allowed on port:%d\n", bc->port); + + chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n"); misdn_lib_send_event(bc, EVENT_HOLD_REJECT); break; } +#if 0 { struct chan_list *holded_ch=find_holded(cl_te, bc); if (holded_ch) { misdn_lib_send_event(bc, EVENT_HOLD_REJECT); - chan_misdn_log(0, bc->port, "We can't use RETRIEVE at the moment due to mISDN bug!\n"); + + chan_misdn_log(-1, bc->port, "We can't use RETRIEVE at the moment due to mISDN bug!\n"); break; } } +#endif + struct ast_channel *bridged=AST_BRIDGED_P(ch->ast); - if (AST_BRIDGED_P(ch->ast)){ + if (bridged){ + struct chan_list *bridged_ch=MISDN_ASTERISK_TECH_PVT(bridged); ch->state = MISDN_HOLDED; ch->l3id = bc->l3_id; - ast_moh_start(AST_BRIDGED_P(ch->ast), NULL); + bc->holded_bc=bridged_ch->bc; misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE); + + ast_moh_start(bridged, NULL); } else { misdn_lib_send_event(bc, EVENT_HOLD_REJECT); chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n"); } } break; + + case EVENT_FACILITY: + print_facility(bc); + + switch (bc->fac_type) { + case FACILITY_CALLDEFLECT: + { + struct ast_channel *bridged=AST_BRIDGED_P(ch->ast); + struct chan_list *ch; + + if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) { + ch=MISDN_ASTERISK_TECH_PVT(bridged); + /*ch->state=MISDN_FACILITY_DEFLECTED;*/ + if (ch->bc) { + /* todo */ + } + + } + + } + + break; + default: + chan_misdn_log(1, bc->port," --> not yet handled\n"); + } + + break; + + case EVENT_RESTART: + + stop_bc_tones(ch); + release_chan(bc); + + break; + default: - ast_log(LOG_WARNING, "Got Unknown Event\n"); + ast_log(LOG_NOTICE, "Got Unknown Event\n"); break; } @@ -3341,13 +4023,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) *******************************************/ -int clearl3_true ( void ) { - int default_clearl3; - misdn_cfg_get( 0, MISDN_GEN_CLEAR_L3, &default_clearl3, sizeof(int)); - return default_clearl3; -} - -int g_config_initialized=0; +static int g_config_initialized=0; int load_module(void) { @@ -3359,7 +4035,7 @@ int load_module(void) if (max_ports<=0) { ast_log(LOG_ERROR, "Unable to initialize mISDN\n"); - return -1; + return 0; } @@ -3374,16 +4050,17 @@ int load_module(void) { - char tempbuf[BUFFERSIZE]; + char tempbuf[BUFFERSIZE+1]; misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, tempbuf, BUFFERSIZE); if (strlen(tempbuf)) tracing = 1; } ast_mutex_init(&cl_te_lock); - ast_mutex_init(&release_lock_mutex); + misdn_cfg_update_ptp(); misdn_cfg_get_ports_string(ports); + if (strlen(ports)) chan_misdn_log(0, 0, "Got: %s from get_ports\n",ports); @@ -3391,16 +4068,25 @@ int load_module(void) struct misdn_lib_iface iface = { .cb_event = cb_events, .cb_log = chan_misdn_log, - .cb_clearl3_true = clearl3_true + .cb_jb_empty = chan_misdn_jb_empty, }; if (misdn_lib_init(ports, &iface, NULL)) chan_misdn_log(0, 0, "No te ports initialized\n"); + + int ntflags=0; + char ntfile[BUFFERSIZE+1]; + + misdn_cfg_get( 0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(int)); + misdn_cfg_get( 0, MISDN_GEN_NTDEBUGFILE, &ntfile, BUFFERSIZE); + + misdn_lib_nt_debug_init(ntflags,ntfile); + } { if (ast_channel_register(&misdn_tech)) { - ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); + ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type); unload_module(); return -1; } @@ -3418,17 +4104,30 @@ int load_module(void) ast_cli_register(&cli_show_port); ast_cli_register(&cli_show_stacks); + ast_cli_register(&cli_port_block); + ast_cli_register(&cli_port_unblock); ast_cli_register(&cli_restart_port); ast_cli_register(&cli_port_up); + ast_cli_register(&cli_port_down); ast_cli_register(&cli_set_debug); ast_cli_register(&cli_set_crypt_debug); ast_cli_register(&cli_reload); - ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_flags", + ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt", "misdn_set_opt(:<opt><optarg>:<opt><optarg>..):\n" "Sets mISDN opts. and optargs\n" "\n" + "The available options are:\n" + " d - Send display text on called phone, text is the optparam\n" + " n - don't detect dtmf tones on called channel\n" + " h - make digital outgoing call\n" + " c - make crypted outgoing call, param is keyindex\n" + " e - perform echo cancelation on this channel,\n" + " takes taps as arguments (32,64,128,256)\n" + " s - send Non Inband DTMF as inband\n" + " vr - rxgain control\n" + " vt - txgain control\n" ); @@ -3439,9 +4138,11 @@ int load_module(void) "Supported Facilities are:\n" "\n" "type=calldeflect args=Nr where to deflect\n" - "\n" ); - + + + misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, global_tracefile, BUFFERSIZE); + chan_misdn_log(0, 0, "-- mISDN Channel Driver Registred -- (BE AWARE THIS DRIVER IS EXPERIMENTAL!)\n"); return 0; @@ -3469,8 +4170,11 @@ int unload_module(void) ast_cli_unregister(&cli_show_config); ast_cli_unregister(&cli_show_port); ast_cli_unregister(&cli_show_stacks); + ast_cli_unregister(&cli_port_block); + ast_cli_unregister(&cli_port_unblock); ast_cli_unregister(&cli_restart_port); ast_cli_unregister(&cli_port_up); + ast_cli_unregister(&cli_port_down); ast_cli_unregister(&cli_set_debug); ast_cli_unregister(&cli_set_crypt_debug); ast_cli_unregister(&cli_reload); @@ -3480,6 +4184,7 @@ int unload_module(void) ast_channel_unregister(&misdn_tech); + free_robin_list(); misdn_cfg_destroy(); misdn_lib_destroy(); @@ -3492,6 +4197,13 @@ int unload_module(void) return 0; } +int reload(void) +{ + reload_config(); + + return 0; +} + int usecount(void) { int res; @@ -3511,102 +4223,7 @@ char *key(void) return ASTERISK_GPL_KEY; } -void chan_misdn_log(int level, int port, char *tmpl, ...) -{ - if (! ((0 <= port) && (port <= max_ports))) { - ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port); - return; - } - - va_list ap; - char buf[1024]; - - va_start(ap, tmpl); - vsnprintf( buf, 1023, tmpl, ap ); - va_end(ap); - - if (misdn_debug_only[port] ? (level==1 && misdn_debug[port]) || (level==misdn_debug[port]) : level <= misdn_debug[port]) { - ast_console_puts(buf); - } - - if (level <= misdn_debug[0] && tracing) { - time_t tm = time(NULL); - char *tmp=ctime(&tm),*p; - char file[BUFFERSIZE]; - misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, file, BUFFERSIZE); - FILE *fp= fopen(file, "a+"); - - p=strchr(tmp,'\n'); - if (p) *p=':'; - - if (!fp) { - ast_console_puts("Error opening Tracefile: "); - ast_console_puts(strerror(errno)); - ast_console_puts("\n"); - return ; - } - - fputs(tmp,fp); - fputs(" ", fp); - fputs(buf, fp); - - fclose(fp); - } -} - - -void chan_misdn_trace_call(struct ast_channel *chan, int debug, char *tmpl, ...) -{ - va_list ap; - char buf[1024]; - char name[1024]; - - int trace; - misdn_cfg_get( 0, MISDN_GEN_TRACE_CALLS, &trace, sizeof(int)); - if (!trace) return ; - - if (misdn_debug[0] < debug) return ; - - char tracedir[BUFFERSIZE]; - misdn_cfg_get( 0, MISDN_GEN_TRACE_DIR, tracedir, BUFFERSIZE); - sprintf(name,"%s/%s.%s",tracedir, chan->uniqueid, chan->cid.cid_num ); - - va_start(ap, tmpl); - - vsprintf( buf, tmpl, ap ); - - va_end(ap); - - time_t tm = time(NULL); - char *tmp=ctime(&tm),*p; - FILE *fp= fopen(name, "a"); - int fd; - - if (!fp) { - ast_console_puts("Error opening Tracefile"); - ast_console_puts(strerror(errno)); - ast_console_puts("\n"); - return ; - } - - fd=fileno(fp) ; - - flock(fd, LOCK_EX); - - p=strchr(tmp,'\n'); - if (p) *p=':'; - - - - fputs(tmp,fp); - fputs(" ", fp); - fputs(buf, fp); - flock(fd, LOCK_UN); - - fclose(fp); - -} /*** SOME APPS ;)***/ @@ -3615,9 +4232,10 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data) { struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan); char *tok, *tokb; - - if (strcasecmp(MISDN_ASTERISK_TYPE(chan),"mISDN")) { + chan_misdn_log(0,0,"TYPE: %s\n",chan->tech->type); + + if (strcasecmp(chan->tech->type,"mISDN")) { ast_log(LOG_WARNING, "misdn_facility makes only sense with chan_misdn channels!\n"); return -1; } @@ -3659,8 +4277,9 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) int keyidx=0; int rxgain=0; int txgain=0; - - if (strcasecmp(MISDN_ASTERISK_TYPE(chan),"mISDN")) { + int change_jitter=0; + + if (strcasecmp(chan->tech->type,"mISDN")) { ast_log(LOG_WARNING, "misdn_set_opt makes only sense with chan_misdn channels!\n"); return -1; } @@ -3683,7 +4302,7 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) switch(tok[0]) { case 'd' : - strncpy(ch->bc->display,++tok,84); + ast_copy_string(ch->bc->display,++tok,84); chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n",ch->bc->display); break; @@ -3693,8 +4312,32 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) break; case 'j': - chan_misdn_log(1, ch->bc->port, "SETOPT: No jitter\n"); - ch->bc->nojitter=1; + chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n"); + tok++; + change_jitter=1; + + switch ( tok[0] ) { + case 'b' : + ch->jb_len=atoi(++tok); + chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n",ch->jb_len); + break; + case 't' : + ch->jb_upper_threshold=atoi(++tok); + chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d\n",ch->jb_upper_threshold); + break; + + case 'n': + ch->bc->nojitter=1; + chan_misdn_log(1, ch->bc->port, " --> nojitter\n"); + break; + + default: + ch->jb_len=4000; + ch->jb_upper_threshold=0; + chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n",ch->jb_len); + chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n",ch->jb_upper_threshold); + } + break; case 'v': @@ -3727,10 +4370,9 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) } { - int l = sizeof(ch->bc->crypt_key); - strncpy(ch->bc->crypt_key, misdn_key_vector[keyidx], l); - ch->bc->crypt_key[l-1] = 0; + ast_copy_string(ch->bc->crypt_key, misdn_key_vector[keyidx], sizeof(ch->bc->crypt_key)); } + chan_misdn_log(0, ch->bc->port, "SETOPT: crypt with key:%s\n",misdn_key_vector[keyidx]); break; @@ -3738,7 +4380,9 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n"); if (neglect) { + chan_misdn_log(1, ch->bc->port, " --> disabled\n"); ch->bc->ec_enable=0; + } else { ch->bc->ec_enable=1; ch->bc->orig=ch->orginator; @@ -3752,18 +4396,12 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) case 'h': chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n"); + if (strlen(tok) > 1 && tok[1]=='1') { - chan_misdn_log(1, ch->bc->port, "SETOPT: Digital TRANS_DIGITAL\n"); - ch->bc->async=1; - ch->bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; - /*ch->bc->state=STATE_CONNECTED; - misdn_lib_setup_bc(ch->bc);*/ - } else { - ch->bc->async=0; - ch->bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; - /*ch->bc->state=STATE_CONNECTED; - misdn_lib_setup_bc(ch->bc);*/ - } + chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n"); + ch->bc->hdlc=1; + } + ch->bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; break; case 's': @@ -3798,6 +4436,10 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) break; } } + + if (change_jitter) + config_jitterbuffer(ch); + if (ch->faxdetect || ch->ast_dsp) { @@ -3816,3 +4458,246 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) } +int chan_misdn_jb_empty ( struct misdn_bchannel *bc, char *buf, int len) +{ + struct chan_list *ch=find_chan_by_bc(cl_te, bc); + + if (ch && ch->jb) { + return misdn_jb_empty(ch->jb, buf, len); + } + + return -1; +} + + + +/*******************************************************/ +/***************** JITTERBUFFER ************************/ +/*******************************************************/ + + +/* allocates the jb-structure and initialise the elements*/ +struct misdn_jb *misdn_jb_init(int size, int upper_threshold) +{ + int i; + struct misdn_jb *jb = (struct misdn_jb*) malloc(sizeof(struct misdn_jb)); + jb->size = size; + jb->upper_threshold = upper_threshold; + jb->wp = 0; + jb->rp = 0; + jb->state_full = 0; + jb->state_empty = 0; + jb->bytes_wrote = 0; + jb->samples = (char *)malloc(size*sizeof(char)); + + if (!jb->samples) { + chan_misdn_log(-1,0,"No free Mem for jb->samples\n"); + return NULL; + } + + jb->ok = (char *)malloc(size*sizeof(char)); + + if (!jb->ok) { + chan_misdn_log(-1,0,"No free Mem for jb->ok\n"); + return NULL; + } + + for(i=0; i<size; i++) + jb->ok[i]=0; + + ast_mutex_init(&jb->mutexjb); + + return jb; +} + +/* frees the data and destroys the given jitterbuffer struct */ +void misdn_jb_destroy(struct misdn_jb *jb) +{ + ast_mutex_destroy(&jb->mutexjb); + + free(jb->samples); + free(jb); +} + +/* fills the jitterbuffer with len data returns < 0 if there was an + error (bufferoverflow). */ +int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len) +{ + int i, j, rp, wp; + + if (!jb || ! data) return 0; + + ast_mutex_lock (&jb->mutexjb); + + wp=jb->wp; + rp=jb->rp; + + for(i=0; i<len; i++) + { + jb->samples[wp]=data[i]; + jb->ok[wp]=1; + wp = (wp!=jb->size-1 ? wp+1 : 0); + + if(wp==jb->rp) + jb->state_full=1; + } + + if(wp>=rp) + jb->state_buffer=wp-rp; + else + jb->state_buffer= jb->size-rp+wp; + chan_misdn_log(9,0,"misdn_jb_fill: written:%d | Bufferstatus:%d p:%x\n",len,jb->state_buffer,jb); + + if(jb->state_full) + { + jb->wp=wp; + + rp=wp; + for(j=0; j<jb->upper_threshold; j++) + rp = (rp!=0 ? rp-1 : jb->size-1); + jb->rp=rp; + jb->state_full=0; + jb->state_empty=1; + + ast_mutex_unlock (&jb->mutexjb); + + return -1; + } + + if(!jb->state_empty) + { + jb->bytes_wrote+=len; + if(jb->bytes_wrote>=jb->upper_threshold) + { + jb->state_empty=1; + jb->bytes_wrote=0; + } + } + jb->wp=wp; + + ast_mutex_unlock (&jb->mutexjb); + + return 0; +} + +/* gets len bytes out of the jitterbuffer if available, else only the +available data is returned and the return value indicates the number +of data. */ +int misdn_jb_empty(struct misdn_jb *jb, char *data, int len) +{ + int i, wp, rp, read=0; + + ast_mutex_lock (&jb->mutexjb); + + rp=jb->rp; + wp=jb->wp; + + if(jb->state_empty) + { + for(i=0; i<len; i++) + { + if(wp==rp) + { + jb->rp=rp; + jb->state_empty=0; + + ast_mutex_unlock (&jb->mutexjb); + + return read; + } + else + { + if(jb->ok[rp]==1) + { + data[i]=jb->samples[rp]; + jb->ok[rp]=0; + rp=(rp!=jb->size-1 ? rp+1 : 0); + read+=1; + } + } + } + + if(wp >= rp) + jb->state_buffer=wp-rp; + else + jb->state_buffer= jb->size-rp+wp; + chan_misdn_log(9,0,"misdn_jb_empty: read:%d | Bufferstatus:%d p:%x\n",len,jb->state_buffer,jb); + + jb->rp=rp; + } + else + chan_misdn_log(9,0,"misdn_jb_empty: Wait...requested:%d p:%x\n",len,jb); + + ast_mutex_unlock (&jb->mutexjb); + + return read; +} + + + + +/*******************************************************/ +/*************** JITTERBUFFER END *********************/ +/*******************************************************/ + + + + +void chan_misdn_log(int level, int port, char *tmpl, ...) +{ + if (! ((0 <= port) && (port <= max_ports))) { + ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port); + port=0; + level=-1; + } + + va_list ap; + char buf[1024]; + char port_buf[8]; + sprintf(port_buf,"P[%2d] ",port); + + va_start(ap, tmpl); + vsnprintf( buf, 1023, tmpl, ap ); + va_end(ap); + + if (level == -1) + ast_log(LOG_WARNING, buf); + + else if (misdn_debug_only[port] ? + (level==1 && misdn_debug[port]) || (level==misdn_debug[port]) + : level <= misdn_debug[port]) { + + ast_console_puts(port_buf); + ast_console_puts(buf); + } + + if ((level <= misdn_debug[0]) && !ast_strlen_zero(global_tracefile) ) { + time_t tm = time(NULL); + char *tmp=ctime(&tm),*p; + + FILE *fp= fopen(global_tracefile, "a+"); + + p=strchr(tmp,'\n'); + if (p) *p=':'; + + if (!fp) { + ast_console_puts("Error opening Tracefile: [ "); + ast_console_puts(global_tracefile); + ast_console_puts(" ] "); + + ast_console_puts(strerror(errno)); + ast_console_puts("\n"); + return ; + } + + fputs(tmp,fp); + fputs(" ", fp); + fputs(port_buf,fp); + fputs(" ", fp); + fputs(buf, fp); + + fclose(fp); + } +} + + |