CAPI specs (5th edition diagrams in section A.5) say that early B3 should

trigger on progress indication ("Progress tones available") and this is
how chan_capi actually worked before revision 101 (2005-09-04).

Q.931 (05.98) sections 5.1.2 and 5.4 also specify similar handling on lower
level (they also add "Call is not end-to-end ISDN; further call progress
information may be available in-band" as possible triggering indication).

This patch adds 't' option to dial string that allows switching chan_capi
to such mode of operation.
Without this option set chan_capi works as it did previously.

While we are at it also let's clean up handling of 'DISCONNECT' message
received via INFO_IND - 'case 2' had unnecessary dependency on 'doB3' variable
(only one value is possible by this point in code with i->outgoing being set),
'case 4' had unreachable branch and unnecessary predicates (which were always
true).
These changes should not cause any differences in operation.

Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
This commit is contained in:
MelwareDE 2016-07-11 14:32:43 +00:00
parent 955b02d460
commit ea23483041
4 changed files with 63 additions and 32 deletions

View File

@ -6,6 +6,8 @@ HEAD
- refuse to reload on active channels - refuse to reload on active channels
- ast_devstate_changed() changes with new cache argument - ast_devstate_changed() changes with new cache argument
- check for bchannel information element on incoming call - check for bchannel information element on incoming call
- added 't' option to select in-band tones available indication as Q.931
(thanks to Maciej S. Szmigiero <mail@maciej.szmigiero.name>)
chan_capi-1.1.6 chan_capi-1.1.6

6
README
View File

@ -93,6 +93,9 @@ The Dial string
The string consists of a list of characters with the following meaning: The string consists of a list of characters with the following meaning:
'b' : early B3 always. 'b' : early B3 always.
'B' : early B3 on successful calls only. 'B' : early B3 on successful calls only.
't' : enable B3 only on in-band tones available indication as Q.931 (05/98)
recommends (without this option it will be enabled on "PROGRESS" or
"ALERTING" messages, any "Progress" indication or channel identification).
'd' : use the default caller ID that is set by defaultcid= in capi.conf 'd' : use the default caller ID that is set by defaultcid= in capi.conf
'o' : use overlap sending of number. 'o' : use overlap sending of number.
(Useful if additional digits should be send afterwards or together (Useful if additional digits should be send afterwards or together
@ -371,7 +374,8 @@ you:
indications) indications)
For normal PBX usage, you would use the "b" option, always Early B3. For normal PBX usage, you would use the "b" option, always Early B3.
You can also add "t" option so B3 will be enabled only on in-band tones available
indication as Q.931 (05/98) recommends.
Overlap sending (a.k.a. real dialtone) Overlap sending (a.k.a. real dialtone)
====================================== ======================================

View File

@ -1295,17 +1295,6 @@ void cc_start_b3(struct capi_pvt *i)
} }
} }
/*
* start early B3
*/
static void start_early_b3(struct capi_pvt *i)
{
if (i->doB3 != CAPI_B3_DONT) {
/* we do early B3 Connect */
cc_start_b3(i);
}
}
/* /*
* signal 'progress' to PBX * signal 'progress' to PBX
*/ */
@ -1313,7 +1302,11 @@ static void send_progress(struct capi_pvt *i)
{ {
struct ast_frame fr = { AST_FRAME_CONTROL, }; struct ast_frame fr = { AST_FRAME_CONTROL, };
start_early_b3(i); if (i->doB3 != CAPI_B3_DONT &&
!(i->fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL)) {
/* we do early B3 Connect */
cc_start_b3(i);
}
if (!(i->isdnstate & CAPI_ISDN_STATE_PROGRESS)) { if (!(i->isdnstate & CAPI_ISDN_STATE_PROGRESS)) {
i->isdnstate |= CAPI_ISDN_STATE_PROGRESS; i->isdnstate |= CAPI_ISDN_STATE_PROGRESS;
@ -1608,6 +1601,13 @@ static int pbx_capi_call(struct ast_channel *c, void *idest, int timeout)
cc_log(LOG_WARNING, "B3 already set in '%s'\n", idest); cc_log(LOG_WARNING, "B3 already set in '%s'\n", idest);
i->doB3 = CAPI_B3_ON_SUCCESS; i->doB3 = CAPI_B3_ON_SUCCESS;
break; break;
case 't': /* enable B3 only on in-band tones available indication */
if ((i->fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL))
cc_log(LOG_WARNING,
"B3 on in-band tones avail only already set in '%s'\n",
idest);
i->fsetting |= CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL;
break;
case 'o': /* overlap sending of digits */ case 'o': /* overlap sending of digits */
if (i->doOverlap) if (i->doOverlap)
cc_log(LOG_WARNING, "Overlap already set in '%s'\n", idest); cc_log(LOG_WARNING, "Overlap already set in '%s'\n", idest);
@ -1649,6 +1649,18 @@ static int pbx_capi_call(struct ast_channel *c, void *idest, int timeout)
return -1; return -1;
} }
if (((!dest) || (!dest[0])) &&
i->fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL)
cc_log(LOG_WARNING,
"dialtone request with B3 on in-band tones avail setting might not work on all exchanges in '%s'\n",
idest);
if (i->doB3 == CAPI_B3_DONT &&
i->fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL)
cc_log(LOG_WARNING,
"B3 on in-band tones avail setting ignored when early B3 is disabled in '%s'\n",
idest);
i->peer = cc_get_peer_link_id(pbx_builtin_getvar_helper(c, "CAPIPEERLINKID")); i->peer = cc_get_peer_link_id(pbx_builtin_getvar_helper(c, "CAPIPEERLINKID"));
i->outgoing = 1; i->outgoing = 1;
@ -3901,16 +3913,26 @@ static int search_did(struct ast_channel *c)
*/ */
static void handle_progress_indicator(_cmsg *CMSG, unsigned int PLCI, struct capi_pvt *i) static void handle_progress_indicator(_cmsg *CMSG, unsigned int PLCI, struct capi_pvt *i)
{ {
int inband_info = 0;
if (INFO_IND_INFOELEMENT(CMSG)[0] < 2) { if (INFO_IND_INFOELEMENT(CMSG)[0] < 2) {
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: Progress description missing\n", cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: Progress description missing\n",
i->vname); i->vname);
return; return;
} }
if ((INFO_IND_INFOELEMENT(CMSG)[2] & 0x60) != 0x00) {
cc_verbose(3, 1,
VERBOSE_PREFIX_4 "%s: Progress description has unsupported coding\n",
i->vname);
return;
}
switch(INFO_IND_INFOELEMENT(CMSG)[2] & 0x7f) { switch(INFO_IND_INFOELEMENT(CMSG)[2] & 0x7f) {
case 0x01: case 0x01:
cc_verbose(4, 1, VERBOSE_PREFIX_4 "%s: Not end-to-end ISDN\n", cc_verbose(4, 1, VERBOSE_PREFIX_4 "%s: Not end-to-end ISDN\n",
i->vname); i->vname);
inband_info = 1;
break; break;
case 0x02: case 0x02:
cc_verbose(4, 1, VERBOSE_PREFIX_4 "%s: Destination is non ISDN\n", cc_verbose(4, 1, VERBOSE_PREFIX_4 "%s: Destination is non ISDN\n",
@ -3932,12 +3954,19 @@ static void handle_progress_indicator(_cmsg *CMSG, unsigned int PLCI, struct cap
case 0x08: case 0x08:
cc_verbose(4, 1, VERBOSE_PREFIX_4 "%s: In-band information available\n", cc_verbose(4, 1, VERBOSE_PREFIX_4 "%s: In-band information available\n",
i->vname); i->vname);
inband_info = 1;
break; break;
default: default:
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: Unknown progress description %02x\n", cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: Unknown progress description %02x\n",
i->vname, INFO_IND_INFOELEMENT(CMSG)[2]); i->vname, INFO_IND_INFOELEMENT(CMSG)[2]);
} }
if (inband_info && i->doB3 != CAPI_B3_DONT &&
i->fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL)
cc_start_b3(i);
send_progress(i); send_progress(i);
return; return;
} }
@ -4139,12 +4168,17 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
} }
return; return;
} }
/* at this point the call is either incoming or we are always doing B3 */
/* case 2: we are doing B3, and receive the 0x8045 after a successful call */ /* case 2: we are doing B3, and receive the 0x8045 after a successful call */
if ((i->doB3 != CAPI_B3_DONT) && if ((i->state == CAPI_STATE_CONNECTED) && (i->outgoing == 1)) {
(i->state == CAPI_STATE_CONNECTED) && (i->outgoing == 1)) {
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 2\n", cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 2\n",
i->vname); i->vname);
/*
* FIXME: is this right? if this is just a normal hangup of
* a successful call shouldn't it be the same as case 1?
*/
capi_queue_cause_control(i, 1); capi_queue_cause_control(i, 1);
return; return;
} }
@ -4165,22 +4199,11 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
capi_queue_cause_control(i, 0); capi_queue_cause_control(i, 0);
return; return;
} }
/* case 4 (a.k.a. the italian case): B3 always. call is unsuccessful */ /* case 4 (a.k.a. the italian case): always doing B3 and call is unsuccessful */
if ((i->doB3 == CAPI_B3_ALWAYS) && (i->outgoing == 1)) { cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 4\n",
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 4\n",
i->vname);
if ((i->state == CAPI_STATE_CONNECTED) &&
(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) {
capi_queue_cause_control(i, 1);
return;
}
/* wait for the 0x001e (PROGRESS), play audio and wait for a timeout from the network */
return;
}
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: Other case DISCONNECT INFO_IND\n",
i->vname); i->vname);
return; /* play audio and wait for a timeout from the network */
} }
/* /*
@ -4285,7 +4308,8 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig
case 0x0018: /* Channel Identification */ case 0x0018: /* Channel Identification */
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CHANNEL IDENTIFICATION %02x\n", cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CHANNEL IDENTIFICATION %02x\n",
i->vname, INFO_IND_INFOELEMENT(CMSG)[1]); i->vname, INFO_IND_INFOELEMENT(CMSG)[1]);
if (i->doB3 == CAPI_B3_ON_SUCCESS) { if (i->doB3 != CAPI_B3_DONT &&
!(i->fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL)) {
/* try early B3 Connect */ /* try early B3 Connect */
cc_start_b3(i); cc_start_b3(i);
} }

View File

@ -348,6 +348,7 @@ struct cc_capi_gains {
/* Features and settings of current connection */ /* Features and settings of current connection */
#define CAPI_FSETTING_STAYONLINE 0x00000001 #define CAPI_FSETTING_STAYONLINE 0x00000001
#define CAPI_FSETTING_EARLY_BRIDGE 0x00000002 #define CAPI_FSETTING_EARLY_BRIDGE 0x00000002
#define CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL 0x00000004
/* Private qsig data for capi device */ /* Private qsig data for capi device */
struct cc_qsig_data { struct cc_qsig_data {