X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=chan_lcr.c;h=52c2a3121a13762fb30ee200ff7d2463258e5bed;hp=ab9c76ad41fe8e156a16a13943f151a5237ec160;hb=b1ab2b9ac1cfc15d2a8f5850145dd69043cc3ef7;hpb=d2b113f2c4f11acfaee1b2e0fd2f03744a89f6d4 diff --git a/chan_lcr.c b/chan_lcr.c index ab9c76a..52c2a31 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -78,6 +78,27 @@ LCR and the chan_call instance is destroyed. If the ref is 0 and the state is CHAN_LCR_STATE_RELEASE, see the proceedure "Call is released by LCR". + +Locking issues: + +The deadlocking problem: + +- chan_lcr locks chan_lock and waits inside ast_queue_xxxx() for ast_channel +to be unlocked. +- ast_channel thread locks ast_channel and calls a tech function and waits +there for chan_lock to be unlocked. + +The solution: + +Never call ast_queue_xxxx() if ast_channel is not locked and don't wait until +ast_channel can be locked. All messages to asterisk are queued inside call +instance and will be handled using a try-lock to get ast_channel lock. +If it succeeds to lock ast_channel, the ast_queue_xxxx can safely called even +if the lock is incremented and decremented there. + +Exception: Calling ast_queue_frame inside ast->tech->read is safe, because +it is called from ast_channel process which has already locked ast_channel. + */ #include @@ -274,6 +295,7 @@ struct chan_call *alloc_call(void) free_call(*callp); return(NULL); } + fcntl((*callp)->pipe[0], F_SETFL, O_NONBLOCK); CDEBUG(*callp, NULL, "Call instance allocated.\n"); return(*callp); } @@ -342,6 +364,9 @@ void apply_opt(struct chan_call *call, char *data) char string[1024], *p = string, *opt, *key; int gain, i, newmode = 0; + if (!data[0]) + return; // no opts + strncpy(string, data, sizeof(string)-1); string[sizeof(string)-1] = '\0'; @@ -432,12 +457,12 @@ void apply_opt(struct chan_call *call, char *data) break; case 't': if (opt[1] != '\0') { - CERROR(call, call->ast, "Option 't' (transparent) expects no parameter.\n", opt); + CERROR(call, call->ast, "Option 't' (no_dsp) expects no parameter.\n", opt); break; } - CDEBUG(call, call->ast, "Option 't' (transparent).\n"); - if (!call->transparent) { - call->transparent = 1; + CDEBUG(call, call->ast, "Option 't' (no dsp).\n"); + if (!call->nodsp) { + call->nodsp = 1; newmode = 1; } break; @@ -451,6 +476,14 @@ void apply_opt(struct chan_call *call, char *data) if (call->bchannel) bchannel_pipeline(call->bchannel, call->pipeline); break; + case 'r': + if (opt[1] != '\0') { + CERROR(call, call->ast, "Option 'r' (re-buffer 160 bytes) expects no parameter.\n", opt); + break; + } + CDEBUG(call, call->ast, "Option 'r' (re-buffer 160 bytes)"); + call->rebuffer = 1; + break; #if 0 case 's': if (opt[1] != '\0') { @@ -491,7 +524,7 @@ todo /* re-open, if bchannel is created */ if (call->bchannel && call->bchannel->b_sock > -1) { bchannel_destroy(call->bchannel); - if (bchannel_create(call->bchannel, ((call->transparent)?1:0) + ((call->hdlc)?2:0))) + if (bchannel_create(call->bchannel, ((call->nodsp)?1:0) + ((call->hdlc)?2:0))) bchannel_activate(call->bchannel, 1); } } @@ -508,7 +541,7 @@ static void send_setup_to_lcr(struct chan_call *call) if (!call->ast || !call->ref) return; - CDEBUG(call, call->ast, "Sending setup to LCR. (interface=%s dialstring=%s)\n", call->interface, call->dialstring); + CDEBUG(call, call->ast, "Sending setup to LCR. (interface=%s dialstring=%s, cid=%s)\n", call->interface, call->dialstring, call->cid_num); /* send setup message to LCR */ memset(&newparam, 0, sizeof(union parameter)); @@ -520,13 +553,13 @@ static void send_setup_to_lcr(struct chan_call *call) newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN; strncpy(newparam.setup.callerinfo.display, call->display, sizeof(newparam.setup.callerinfo.display)-1); call->display[0] = '\0'; - if (ast->cid.cid_num) if (ast->cid.cid_num[0]) - strncpy(newparam.setup.callerinfo.id, ast->cid.cid_num, sizeof(newparam.setup.callerinfo.id)-1); - if (ast->cid.cid_name) if (ast->cid.cid_name[0]) - strncpy(newparam.setup.callerinfo.name, ast->cid.cid_name, sizeof(newparam.setup.callerinfo.name)-1); - if (ast->cid.cid_rdnis) if (ast->cid.cid_rdnis[0]) + if (call->cid_num[0]) + strncpy(newparam.setup.callerinfo.id, call->cid_num, sizeof(newparam.setup.callerinfo.id)-1); + if (call->cid_name[0]) + strncpy(newparam.setup.callerinfo.name, call->cid_name, sizeof(newparam.setup.callerinfo.name)-1); + if (call->cid_rdnis[0]) { - strncpy(newparam.setup.redirinfo.id, ast->cid.cid_rdnis, sizeof(newparam.setup.redirinfo.id)-1); + strncpy(newparam.setup.redirinfo.id, call->cid_rdnis, sizeof(newparam.setup.redirinfo.id)-1); newparam.setup.redirinfo.itype = INFO_ITYPE_CHAN; newparam.setup.redirinfo.ntype = INFO_NTYPE_UNKNOWN; } @@ -559,8 +592,13 @@ static void send_setup_to_lcr(struct chan_call *call) newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN; } newparam.setup.capainfo.bearer_capa = ast->transfercapability; - newparam.setup.capainfo.bearer_info1 = (options.law=='a')?3:2; newparam.setup.capainfo.bearer_mode = INFO_BMODE_CIRCUIT; + if (call->hdlc) + newparam.setup.capainfo.source_mode = B_MODE_HDLC; + else { + newparam.setup.capainfo.source_mode = B_MODE_TRANSPARENT; + newparam.setup.capainfo.bearer_info1 = (options.law=='a')?3:2; + } newparam.setup.capainfo.hlc = INFO_HLC_NONE; newparam.setup.capainfo.exthlc = INFO_HLC_NONE; send_message(MESSAGE_SETUP, call->ref, &newparam); @@ -708,7 +746,11 @@ static void lcr_start_pbx(struct chan_call *call, struct ast_channel *ast, int c goto release; } call->pbx_started = 1; - return; +// if (call->state == CHAN_LCR_STATE_IN_DIALING) + ast_setstate(ast, AST_STATE_RINGING); +// else +// ast_setstate(ast, AST_STATE_RINGING); +// return; } /* @@ -777,9 +819,7 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet } ast->transfercapability = param->setup.capainfo.bearer_capa; /* enable hdlc if transcap is data */ - if (ast->transfercapability == INFO_BC_DATAUNRESTRICTED - || ast->transfercapability == INFO_BC_DATARESTRICTED - || ast->transfercapability == INFO_BC_VIDEO) + if (param->setup.capainfo.source_mode == B_MODE_HDLC) call->hdlc = 1; strncpy(call->oad, numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international), sizeof(call->oad)-1); @@ -793,7 +833,8 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet /* change state */ call->state = CHAN_LCR_STATE_IN_SETUP; - lcr_start_pbx(call, ast, param->setup.dialinginfo.sending_complete); + if (!call->pbx_started) + lcr_start_pbx(call, ast, param->setup.dialinginfo.sending_complete); } /* @@ -821,9 +862,9 @@ static void lcr_in_proceeding(struct chan_call *call, int message_type, union pa /* change state */ call->state = CHAN_LCR_STATE_OUT_PROCEEDING; - /* send event to asterisk */ + /* queue event for asterisk */ if (call->ast && call->pbx_started) - ast_queue_control(call->ast, AST_CONTROL_PROCEEDING); + strncat(call->queue_string, "P", sizeof(call->queue_string)-1); } /* @@ -835,9 +876,9 @@ static void lcr_in_alerting(struct chan_call *call, int message_type, union para /* change state */ call->state = CHAN_LCR_STATE_OUT_ALERTING; - /* send event to asterisk */ + /* queue event to asterisk */ if (call->ast && call->pbx_started) - ast_queue_control(call->ast, AST_CONTROL_RINGING); + strncat(call->queue_string, "R", sizeof(call->queue_string)-1); } /* @@ -860,9 +901,9 @@ static void lcr_in_connect(struct chan_call *call, int message_type, union param } /* copy connectinfo */ memcpy(&call->connectinfo, ¶m->connectinfo, sizeof(struct connect_info)); - /* send event to asterisk */ + /* queue event to asterisk */ if (call->ast && call->pbx_started) - ast_queue_control(call->ast, AST_CONTROL_ANSWER); + strncat(call->queue_string, "A", sizeof(call->queue_string)-1); } /* @@ -894,12 +935,12 @@ static void lcr_in_disconnect(struct chan_call *call, int message_type, union pa call->ref = 0; /* change to release state */ call->state = CHAN_LCR_STATE_RELEASE; - /* release asterisk */ + /* queue release asterisk */ if (ast) { ast->hangupcause = call->cause; if (call->pbx_started) - ast_queue_hangup(ast); + strcpy(call->queue_string, "H"); // overwrite other indications else { ast_hangup(ast); // call will be destroyed here } @@ -925,12 +966,12 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param call->cause = param->disconnectinfo.cause; call->location = param->disconnectinfo.location; } - /* if we have an asterisk instance, send hangup, else we are done */ + /* if we have an asterisk instance, queue hangup, else we are done */ if (ast) { ast->hangupcause = call->cause; if (call->pbx_started) - ast_queue_hangup(ast); + strcpy(call->queue_string, "H"); else { ast_hangup(ast); // call will be destroyed here } @@ -947,8 +988,6 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param static void lcr_in_information(struct chan_call *call, int message_type, union parameter *param) { struct ast_channel *ast = call->ast; - struct ast_frame fr; - char *p; CDEBUG(call, call->ast, "Incoming information from LCR. (dialing=%s)\n", param->information.id); @@ -963,22 +1002,17 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p return; } - /* copy digits */ - p = param->information.id; - if (call->state == CHAN_LCR_STATE_IN_DIALING && *p) - { - CDEBUG(call, call->ast, "Asterisk is started, sending DTMF frame.\n"); - while (*p) - { - /* send digit to asterisk */ - memset(&fr, 0, sizeof(fr)); - fr.frametype = AST_FRAME_DTMF; - fr.subclass = *p; - fr.delivery = ast_tv(0, 0); - ast_queue_frame(call->ast, &fr); - p++; - } + /* change dailing state after setup */ + if (call->state == CHAN_LCR_STATE_IN_SETUP) { + CDEBUG(call, call->ast, "Changing from SETUP to DIALING state.\n"); + call->state = CHAN_LCR_STATE_IN_DIALING; +// ast_setstate(ast, AST_STATE_DIALING); } + + /* queue digits */ + if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0]) + strncat(call->queue_string, param->information.id, sizeof(call->queue_string)-1); + /* use bridge to forware message not supported by asterisk */ if (call->state == CHAN_LCR_STATE_CONNECT) { CDEBUG(call, call->ast, "Call is connected, briding.\n"); @@ -1028,21 +1062,17 @@ static void lcr_in_facility(struct chan_call *call, int message_type, union para void lcr_in_dtmf(struct chan_call *call, int val) { struct ast_channel *ast = call->ast; - struct ast_frame fr; + char digit[2]; if (!ast) return; if (!call->pbx_started) return; - CDEBUG(call, call->ast, "Forwarding DTMF digit '%c' to Asterisk.\n", val); - - /* send digit to asterisk */ - memset(&fr, 0, sizeof(fr)); - fr.frametype = AST_FRAME_DTMF; - fr.subclass = val; - fr.delivery = ast_tv(0, 0); - ast_queue_frame(call->ast, &fr); + CDEBUG(call, call->ast, "Recognised DTMF digit '%c'.\n", val); + digit[0] = val; + digit[1] = '\0'; + strncat(call->queue_string, digit, sizeof(call->queue_string)-1); } /* @@ -1062,7 +1092,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) switch(param->bchannel.type) { case BCHANNEL_ASSIGN: - CDEBUG(NULL, NULL, "Received BCHANNEL_ASSIGN message. (handle=%08lx)\n", param->bchannel.handle); + CDEBUG(NULL, NULL, "Received BCHANNEL_ASSIGN message. (handle=%08lx) for ref %d\n", param->bchannel.handle, ref); if ((bchannel = find_bchannel_handle(param->bchannel.handle))) { CERROR(NULL, NULL, "bchannel handle %x already assigned.\n", (int)param->bchannel.handle); @@ -1111,9 +1141,10 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) CDEBUG(call, call->ast, "Join bchannel, because call is already bridged.\n"); bchannel_join(bchannel, call->bridge_id); } + /* create only, if call exists, othewhise it bchannel is freed below... */ + if (bchannel_create(bchannel, ((call->nodsp)?1:0) + ((call->hdlc)?2:0))) + bchannel_activate(bchannel, 1); } - if (bchannel_create(bchannel, ((call->transparent)?1:0) + ((call->hdlc)?2:0))) - bchannel_activate(bchannel, 1); /* acknowledge */ newparam.bchannel.type = BCHANNEL_ASSIGN_ACK; newparam.bchannel.handle = param->bchannel.handle; @@ -1306,7 +1337,7 @@ again: goto again; } CDEBUG(call, call->ast, "Queue call release, because Asterisk channel is running.\n"); - ast_queue_hangup(call->ast); + strcpy(call->queue_string, "H"); call = call->next; } @@ -1397,7 +1428,6 @@ int handle_socket(void) int open_socket(void) { int ret; - char *socket_name = SOCKET_NAME; int conn; struct sockaddr_un sock_address; unsigned int on = 1; @@ -1413,7 +1443,7 @@ int open_socket(void) /* set socket address and name */ memset(&sock_address, 0, sizeof(sock_address)); sock_address.sun_family = PF_UNIX; - strcpy(sock_address.sun_path, socket_name); + sprintf(sock_address.sun_path, SOCKET_NAME, options.lock); /* connect socket */ if ((conn = connect(lcr_sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0) @@ -1460,10 +1490,77 @@ void close_socket(void) lcr_sock = -1; } + +/* sending queue to asterisk */ +static int queue_send(void) +{ + int work = 0; + struct chan_call *call; + struct ast_channel *ast; + struct ast_frame fr; + char *p; + + call = call_first; + while(call) { + p = call->queue_string; + ast = call->ast; + if (*p && ast) { + /* there is something to queue */ + if (!ast_channel_trylock(ast)) { /* succeed */ + while(*p) { + switch (*p) { + case 'P': + CDEBUG(call, ast, "Sending queued PROCEEDING to Asterisk.\n"); + ast_queue_control(ast, AST_CONTROL_PROCEEDING); + break; + case 'R': + CDEBUG(call, ast, "Sending queued RINGING to Asterisk.\n"); + ast_queue_control(ast, AST_CONTROL_RINGING); + break; + case 'A': + CDEBUG(call, ast, "Sending queued ANSWER to Asterisk.\n"); + ast_queue_control(ast, AST_CONTROL_ANSWER); + break; + case 'H': + CDEBUG(call, ast, "Sending queued HANGUP to Asterisk.\n"); + ast_queue_hangup(ast); + break; + case '1': case '2': case '3': case 'a': + case '4': case '5': case '6': case 'b': + case '7': case '8': case '9': case 'c': + case '*': case '0': case '#': case 'd': + CDEBUG(call, ast, "Sending queued digit '%c' to Asterisk.\n", *p); + /* send digit to asterisk */ + memset(&fr, 0, sizeof(fr)); + fr.frametype = AST_FRAME_DTMF_BEGIN; + fr.subclass = *p; + fr.delivery = ast_tv(0, 0); + ast_queue_frame(ast, &fr); + fr.frametype = AST_FRAME_DTMF_END; + ast_queue_frame(ast, &fr); + break; + default: + CDEBUG(call, ast, "Ignoring queued digit 0x%02d.\n", *p); + } + p++; + } + call->queue_string[0] = '\0'; + ast_channel_unlock(ast); + work = 1; + } + } + call = call->next; + } + + return work; +} + +/* signal handler */ void sighandler(int sigset) { } +/* chan_lcr thread */ static void *chan_thread(void *arg) { int work; @@ -1512,7 +1609,13 @@ static void *chan_thread(void *arg) ret = bchannel_handle(); if (ret) work = 1; - + + /* handle messages to asterisk */ + ret = queue_send(); + if (ret) + work = 1; + + /* delay if no work done */ if (!work) { ast_mutex_unlock(&chan_lock); usleep(30000); @@ -1548,6 +1651,7 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c if (lcr_sock < 0) { CERROR(NULL, NULL, "Rejecting call from Asterisk, because LCR not running.\n"); + ast_mutex_unlock(&chan_lock); return NULL; } @@ -1556,6 +1660,7 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c if (!call) { /* failed to create instance */ + ast_mutex_unlock(&chan_lock); return NULL; } @@ -1566,6 +1671,7 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c CERROR(NULL, NULL, "Failed to create Asterisk channel.\n"); free_call(call); /* failed to create instance */ + ast_mutex_unlock(&chan_lock); return NULL; } ast->tech = &lcr_tech; @@ -1651,11 +1757,26 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout) && ast->transfercapability != INFO_BC_VIDEO) ast->transfercapability = INFO_BC_DATAUNRESTRICTED; + call->cid_num[0] = 0; + call->cid_name[0] = 0; + call->cid_rdnis[0] = 0; + + if (ast->cid.cid_num) if (ast->cid.cid_num[0]) + strncpy(call->cid_num, ast->cid.cid_num, + sizeof(call->cid_num)-1); + + if (ast->cid.cid_name) if (ast->cid.cid_name[0]) + strncpy(call->cid_name, ast->cid.cid_name, + sizeof(call->cid_name)-1); + if (ast->cid.cid_rdnis) if (ast->cid.cid_rdnis[0]) + strncpy(call->cid_rdnis, ast->cid.cid_rdnis, + sizeof(call->cid_rdnis)-1); + ast_mutex_unlock(&chan_lock); return 0; } -static int lcr_digit(struct ast_channel *ast, char digit) +static int lcr_digit_begin(struct ast_channel *ast, char digit) { struct chan_call *call; union parameter newparam; @@ -1696,6 +1817,12 @@ static int lcr_digit(struct ast_channel *ast, char digit) return(0); } +static int lcr_digit_end(struct ast_channel *ast, char digit, unsigned int duration) +{ + printf("DIGIT END %c\n", digit); + return (0); +} + static int lcr_answer(struct ast_channel *ast) { union parameter newparam; @@ -1709,17 +1836,19 @@ static int lcr_answer(struct ast_channel *ast) return -1; } - CDEBUG(call, ast, "Received answer from Asterisk.\n"); + CDEBUG(call, ast, "Received answer from Asterisk (maybe during lcr_bridge).\n"); /* copy connectinfo, if bridged */ if (call->bridge_call) memcpy(&call->connectinfo, &call->bridge_call->connectinfo, sizeof(struct connect_info)); /* send connect message to lcr */ - memset(&newparam, 0, sizeof(union parameter)); - memcpy(&newparam.connectinfo, &call->connectinfo, sizeof(struct connect_info)); - send_message(MESSAGE_CONNECT, call->ref, &newparam); + if (call->state != CHAN_LCR_STATE_CONNECT) { + memset(&newparam, 0, sizeof(union parameter)); + memcpy(&newparam.connectinfo, &call->connectinfo, sizeof(struct connect_info)); + send_message(MESSAGE_CONNECT, call->ref, &newparam); + call->state = CHAN_LCR_STATE_CONNECT; + } /* change state */ - call->state = CHAN_LCR_STATE_CONNECT; /* request bchannel */ if (!call->bchannel) { CDEBUG(call, ast, "Requesting B-channel.\n"); @@ -1770,7 +1899,7 @@ static int lcr_hangup(struct ast_channel *ast) if (ast->hangupcause > 0) send_release_and_import(call, ast->hangupcause, LOCATION_PRIVATE_LOCAL); else - send_release_and_import(call, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL); + send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL); /* remove call */ free_call(call); if (!pthread_equal(tid, chan_tid)) @@ -1821,8 +1950,7 @@ static int lcr_write(struct ast_channel *ast, struct ast_frame *f) static struct ast_frame *lcr_read(struct ast_channel *ast) { struct chan_call *call; - int i, len; - unsigned char *p; + int len; ast_mutex_lock(&chan_lock); call = ast->tech_pvt; @@ -1831,20 +1959,23 @@ static struct ast_frame *lcr_read(struct ast_channel *ast) return NULL; } if (call->pipe[0] > -1) { - len = read(call->pipe[0], call->read_buff, sizeof(call->read_buff)); + if (call->rebuffer && !call->hdlc) { + len = read(call->pipe[0], call->read_buff, 160); + } else { + len = read(call->pipe[0], call->read_buff, sizeof(call->read_buff)); + } + if (len < 0 && errno == EAGAIN) { + ast_mutex_unlock(&chan_lock); + return &ast_null_frame; + } if (len <= 0) { close(call->pipe[0]); call->pipe[0] = -1; + ast_mutex_unlock(&chan_lock); return NULL; } } - p = call->read_buff; - for (i = 0; i < len; i++) { - *p = flip_bits[*p]; - p++; - } - call->read_fr.frametype = AST_FRAME_VOICE; call->read_fr.subclass = ast->nativeformats; call->read_fr.datalen = len; @@ -1964,21 +2095,25 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz /* * fixup asterisk */ -static int lcr_fixup(struct ast_channel *oldast, struct ast_channel *newast) +static int lcr_fixup(struct ast_channel *oldast, struct ast_channel *ast) { struct chan_call *call; + if (!ast) { + return -1; + } + ast_mutex_lock(&chan_lock); - call = oldast->tech_pvt; + call = ast->tech_pvt; if (!call) { - CERROR(NULL, oldast, "Received fixup from Asterisk, but no call instance exists.\n"); + CERROR(NULL, ast, "Received fixup from Asterisk, but no call instance exists.\n"); ast_mutex_unlock(&chan_lock); return -1; } - CDEBUG(call, oldast, "Received fixup from Asterisk.\n"); - call->ast = newast; - ast_mutex_lock(&chan_lock); + CDEBUG(call, ast, "Received fixup from Asterisk.\n"); + call->ast = ast; + ast_mutex_unlock(&chan_lock); return 0; } @@ -2025,26 +2160,54 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1, carr[0] = ast1; carr[1] = ast2; - + /* join via dsp (if the channels are currently open) */ ast_mutex_lock(&chan_lock); - bridge_id = new_bridge_id(); call1 = ast1->tech_pvt; call2 = ast2->tech_pvt; - if (call1 && call2) - { + if (!call1 || !call2) { + CDEBUG(NULL, NULL, "Bridge, but we don't have two call instances, exitting.\n"); + ast_mutex_unlock(&chan_lock); + return AST_BRIDGE_COMPLETE; + } + + /* join, if both call instances uses dsp */ + if (!call1->nodsp && !call2->nodsp) { + CDEBUG(NULL, NULL, "Both calls use DSP, briding via DSP.\n"); + + /* get bridge id and join */ + bridge_id = new_bridge_id(); + call1->bridge_id = bridge_id; if (call1->bchannel) bchannel_join(call1->bchannel, bridge_id); - call1->bridge_call = call2; - } - if (call2) - { + call2->bridge_id = bridge_id; if (call2->bchannel) bchannel_join(call2->bchannel, bridge_id); - call2->bridge_call = call1; + } else + if (call1->nodsp && call2->nodsp) + CDEBUG(NULL, NULL, "Both calls use no DSP, briding in channel driver.\n"); + else + CDEBUG(NULL, NULL, "One call uses no DSP, briding in channel driver.\n"); + call1->bridge_call = call2; + call2->bridge_call = call1; + + if (call1->state == CHAN_LCR_STATE_IN_SETUP + || call1->state == CHAN_LCR_STATE_IN_DIALING + || call1->state == CHAN_LCR_STATE_IN_PROCEEDING + || call1->state == CHAN_LCR_STATE_IN_ALERTING) { + CDEBUG(call1, ast1, "Bridge established before lcr_answer, so we call it ourself: Calling lcr_answer...\n"); + lcr_answer(ast1); + } + if (call2->state == CHAN_LCR_STATE_IN_SETUP + || call2->state == CHAN_LCR_STATE_IN_DIALING + || call2->state == CHAN_LCR_STATE_IN_PROCEEDING + || call2->state == CHAN_LCR_STATE_IN_ALERTING) { + CDEBUG(call2, ast2, "Bridge established before lcr_answer, so we call it ourself: Calling lcr_answer...\n"); + lcr_answer(ast2); } + ast_mutex_unlock(&chan_lock); while(1) { @@ -2091,24 +2254,24 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1, ast_mutex_lock(&chan_lock); call1 = ast1->tech_pvt; call2 = ast2->tech_pvt; - if (call1) + if (call1 && call1->bridge_id) { call1->bridge_id = 0; if (call1->bchannel) bchannel_join(call1->bchannel, 0); if (call1->bridge_call) call1->bridge_call->bridge_call = NULL; - call1->bridge_call = NULL; } - if (call2) + if (call2 && call1->bridge_id) { call2->bridge_id = 0; if (call2->bchannel) bchannel_join(call2->bchannel, 0); if (call2->bridge_call) call2->bridge_call->bridge_call = NULL; - call2->bridge_call = NULL; } + call1->bridge_call = NULL; + call2->bridge_call = NULL; ast_mutex_unlock(&chan_lock); return AST_BRIDGE_COMPLETE; @@ -2117,7 +2280,8 @@ static struct ast_channel_tech lcr_tech = { .type="LCR", .description="Channel driver for connecting to Linux-Call-Router", .requester=lcr_request, - .send_digit_begin=lcr_digit, + .send_digit_begin=lcr_digit_begin, + .send_digit_end=lcr_digit_end, .call=lcr_call, .bridge=lcr_bridge, .hangup=lcr_hangup, @@ -2291,7 +2455,7 @@ int load_module(void) " d - Send display text on called phone, text is the optarg.\n" " n - Don't detect dtmf tones on called channel.\n" " h - Force data call (HDLC).\n" - " t - Disable all audio features (required for fax application).\n" + " t - Disable mISDN_dsp features (required for fax application).\n" " c - Make crypted outgoing call, optarg is keyindex.\n" " e - Perform echo cancelation on this channel.\n" " Takes mISDN pipeline option as optarg.\n"