diff --git a/CHANGES b/CHANGES index 734a2ca..708ea0a 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,9 @@ HEAD signaled as subscriber-number. Here the complete prefix including area code must be added. - better counting of active b-channels. - make capicommand(progress) "early-B3" usable for non NT-mode incoming channels too. +- support early Line-Interconnect (bridge) as soon as both b-channels are up. This bridges b-channels + from beginning of call-establishment, even before calls are connected and the bridge command is received. + Dial() option 'G' is used to activate this feature. chan_capi-1.1.1 diff --git a/README b/README index 844730c..17ee269 100644 --- a/README +++ b/README @@ -102,6 +102,12 @@ The Dial string This is needed to give additional commands like CCBS after Hangup. To really hangup the CAPI connection, use either capicommand(hangup) or wait for chan_capi/network timeout (about 20 seconds). + 'G' : early Line-Interconnect / bridge: Use Line-Interconnect as soon as + both b-channels are up. Both channels must be of type CAPI and + the incoming call may need 'capicommand(progress)' to enable early-B3 + on it as well as dial option 'b' for the outgoing channel. + Before Dial(), the capicommand(peerlink) must be used to signal the + dialed channel its peer. If the is used in dialstring, be sure the name (specified in capi.conf) does not start with 'contr' or 'g'. diff --git a/chan_capi.c b/chan_capi.c index 091f0cc..9e41838 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -893,6 +893,7 @@ static void interface_cleanup(struct capi_pvt *i) i->isdnstate = 0; i->cause = 0; + i->fsetting = 0; i->whentohangup = 0; i->whentoqueuehangup = 0; @@ -1061,7 +1062,7 @@ void capi_activehangup(struct capi_pvt *i, int state) return; } - if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) { + if ((i->fsetting & CAPI_FSETTING_STAYONLINE)) { /* user has requested to leave channel online for further actions like CCBS */ cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: disconnect deferred, stay-online mode PLCI=%#x\n", @@ -1217,9 +1218,14 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) use_defaultcid = 1; break; case 's': /* stay online */ - if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) + if ((i->fsetting & CAPI_FSETTING_STAYONLINE)) cc_log(LOG_WARNING, "'stay-online' already set in '%s'\n", idest); - i->isdnstate |= CAPI_ISDN_STATE_STAYONLINE; + i->fsetting |= CAPI_FSETTING_STAYONLINE; + break; + case 'G': /* early bridge */ + if ((i->fsetting & CAPI_FSETTING_EARLY_BRIDGE)) + cc_log(LOG_WARNING, "'early-bridge' already set in '%s'\n", idest); + i->fsetting |= CAPI_FSETTING_EARLY_BRIDGE; break; case 'q': /* disable QSIG */ cc_verbose(4, 0, VERBOSE_PREFIX_4 "%s: QSIG extensions for this call disabled\n", @@ -1557,15 +1563,6 @@ static int line_interconnect(struct capi_pvt *i0, struct capi_pvt *i1, int start (i1->isdnstate & CAPI_ISDN_STATE_DISCONNECT)) return -1; - if ((!(i0->isdnstate & CAPI_ISDN_STATE_B3_UP)) || - (!(i1->isdnstate & CAPI_ISDN_STATE_B3_UP))) { - cc_verbose(3, 1, VERBOSE_PREFIX_2 - "%s:%s line interconnect aborted, at least " - "one channel is not connected.\n", - i0->vname, i1->vname); - return -1; - } - if (start) { /* connect */ capi_sendf(i1, 0, CAPI_FACILITY_REQ, i0->PLCI, get_capi_MessageNumber(), @@ -1788,6 +1785,44 @@ static int pbx_capi_bridge_transfer( return ret; } +/* + * activate / deactivate b-channel bridge + */ +static int capi_bridge(int start, struct capi_pvt *i0, struct capi_pvt *i1, int flags) +{ + int ret = 0; + + if (start) { + if ((i0->isdnstate & CAPI_ISDN_STATE_LI) || + (i1->isdnstate & CAPI_ISDN_STATE_LI)) { + /* already in bridge */ + cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s/%s: already in bridge.\n", + i0->vname, i1->vname); + return 0; + } + if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) + capi_detect_dtmf(i0, 0); + + if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) + capi_detect_dtmf(i1, 0); + + capi_echo_canceller(i0, EC_FUNCTION_DISABLE); + capi_echo_canceller(i1, EC_FUNCTION_DISABLE); + cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s/%s: activating bridge.\n", + i0->vname, i1->vname); + ret = line_interconnect(i0, i1, 1); + } else { + cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s/%s: deactivating bridge.\n", + i0->vname, i1->vname); + line_interconnect(i0, i1, 0); + capi_detect_dtmf(i0, 1); + capi_detect_dtmf(i1, 1); + capi_echo_canceller(i0, EC_FUNCTION_ENABLE); + capi_echo_canceller(i1, EC_FUNCTION_ENABLE); + } + return ret; +} + /* * native bridging / line interconnect */ @@ -1833,18 +1868,8 @@ static CC_BRIDGE_RETURN pbx_capi_bridge( capi_wait_for_b3_up(i0); capi_wait_for_b3_up(i1); - if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) - capi_detect_dtmf(i0, 0); - - if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) - capi_detect_dtmf(i1, 0); - - capi_echo_canceller(i0, EC_FUNCTION_DISABLE); - capi_echo_canceller(i1, EC_FUNCTION_DISABLE); - - if (line_interconnect(i0, i1, 1)) { - ret = AST_BRIDGE_FAILED; - goto return_from_bridge; + if (capi_bridge(1, i0, i1, flags)) { + return AST_BRIDGE_FAILED; } for (;;) { @@ -1881,18 +1906,7 @@ static CC_BRIDGE_RETURN pbx_capi_bridge( priority = !priority; } - line_interconnect(i0, i1, 0); - -return_from_bridge: - - if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) - capi_detect_dtmf(i0, 1); - - if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) - capi_detect_dtmf(i1, 1); - - capi_echo_canceller(i0, EC_FUNCTION_ENABLE); - capi_echo_canceller(i1, EC_FUNCTION_ENABLE); + capi_bridge(0, i0, i1, 0); return ret; } @@ -2700,7 +2714,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig } capi_queue_cause_control(i, 0); } else { - if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) { + if ((i->fsetting & CAPI_FSETTING_STAYONLINE)) { cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online hangup frame queued.\n", i->vname); i->whentoqueuehangup = time(NULL) + 1; @@ -3449,6 +3463,20 @@ static void capidev_handle_connect_b3_active_indication(_cmsg *CMSG, unsigned in capi_detect_dtmf(i, 1); } + if (i->fsetting & CAPI_FSETTING_EARLY_BRIDGE) { + if ((i->peer != NULL) && (i->peer->tech == &capi_tech)) { + struct capi_pvt *i1; + i1 = CC_CHANNEL_PVT(i->peer); + if ((capi_controllers[i->controller]->lineinterconnect) && + (capi_controllers[i1->controller]->lineinterconnect) && + (i->bridge) && (i1->bridge)) { + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: activate early bridge to %s\n", + i->vname, i1->vname); + capi_bridge(1, i, i1, 0); + } + } + } + if (i->state == CAPI_STATE_CONNECTED) { capi_signal_answer(i); } @@ -3499,7 +3527,7 @@ static void capidev_handle_disconnect_b3_indication(_cmsg *CMSG, unsigned int PL } if ((i->state == CAPI_STATE_DISCONNECTING)) { - if (!(i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) { + if (!(i->fsetting & CAPI_FSETTING_STAYONLINE)) { /* active disconnect */ capi_send_disconnect(PLCI, NULL); } @@ -4567,7 +4595,7 @@ static void capi_disconnect(struct capi_pvt *i) { cc_mutex_lock(&i->lock); - i->isdnstate &= ~CAPI_ISDN_STATE_STAYONLINE; + i->fsetting &= ~CAPI_FSETTING_STAYONLINE; if ((i->isdnstate & CAPI_ISDN_STATE_B3_UP)) { cc_disconnect_b3(i, 0); } else { diff --git a/chan_capi.h b/chan_capi.h index a1267f9..a5e4352 100644 --- a/chan_capi.h +++ b/chan_capi.h @@ -246,8 +246,7 @@ struct cc_capi_gains { #define CAPI_ISDN_STATE_EC 0x00002000 #define CAPI_ISDN_STATE_DTMF 0x00004000 #define CAPI_ISDN_STATE_B3_SELECT 0x00008000 -#define CAPI_ISDN_STATE_STAYONLINE 0x00010000 -#define CAPI_ISDN_STATE_ISDNPROGRESS 0x00020000 +#define CAPI_ISDN_STATE_ISDNPROGRESS 0x00010000 #define CAPI_ISDN_STATE_3PTY 0x10000000 #define CAPI_ISDN_STATE_PBX_DONT 0x40000000 #define CAPI_ISDN_STATE_PBX 0x80000000 @@ -263,6 +262,10 @@ struct cc_capi_gains { #define CAPI_WAITEVENT_HOLD_IND 0x00040000 #define CAPI_WAITEVENT_ECT_IND 0x00050000 +/* Features and settings of current connection */ +#define CAPI_FSETTING_STAYONLINE 0x00000001 +#define CAPI_FSETTING_EARLY_BRIDGE 0x00000002 + /* Private qsig data for capi device */ struct cc_qsig_data { int calltransfer_active; @@ -400,6 +403,9 @@ struct capi_pvt { /* Common ISDN Profile (CIP) */ int cip; unsigned short transfercapability; + + /* Features and settings of current connection */ + unsigned int fsetting; /* if not null, receiving a fax */ FILE *fFax;