diff options
author | rmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b> | 2011-01-25 17:42:42 +0000 |
---|---|---|
committer | rmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b> | 2011-01-25 17:42:42 +0000 |
commit | 0013388425c43990cc5c06b5d803ab6519f8aa97 (patch) | |
tree | 4109cb1d14a2e3dc1bf2f4ab20e111b2360d105e /channels | |
parent | 75ca086244174231a7f3e80c0e04e7397005ab04 (diff) |
Merged revisions 303765 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r303765 | rmudgett | 2011-01-25 11:36:50 -0600 (Tue, 25 Jan 2011) | 40 lines
Sending out unnecessary PROCEEDING messages breaks overlap dialing.
Issue #16789 was a good idea. Unfortunately, it breaks overlap dialing
through Asterisk. There is not enough information available at this point
to know if dialing is complete. The ast_exists_extension(),
ast_matchmore_extension(), and ast_canmatch_extension() calls are not
adequate to detect a dial through extension pattern of "_9!".
Workaround is to use the dialplan Proceeding() application early in
non-dial through extensions.
* Effectively revert issue #16789.
* Allow outgoing overlap dialing to hear dialtone and other early media.
A PROGRESS "inband-information is now available" message is now sent after
the SETUP_ACKNOWLEDGE message for non-digital calls. An
AST_CONTROL_PROGRESS is now generated for incoming SETUP_ACKNOWLEDGE
messages for non-digital calls.
* Handling of the AST_CONTROL_CONGESTION in chan_dahdi/sig_pri was
inconsistent with the cause codes.
* Added better protection from sending out of sequence messages by
combining several flags into a single enum value representing call
progress level.
* Added diagnostic messages for deferred overlap digits handling corner
cases.
(closes issue #17085)
Reported by: shawkris
(closes issue #18509)
Reported by: wimpy
Patches:
issue18509_early_media_v1.8_v3.patch uploaded by rmudgett (license 664)
Expanded upon issue18509_early_media_v1.8_v3.patch to include analog
and SS7 because of backporting requirements.
Tested by: wimpy, rmudgett
........
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.2@303769 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_dahdi.c | 451 |
1 files changed, 301 insertions, 150 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index da01d595a..4048afea0 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -505,6 +505,22 @@ static int r2links_count = 0; #define PRI_SPAN(p) (((p) >> 8) & 0xff) #define PRI_EXPLICIT(p) (((p) >> 16) & 0x01) +/*! Call establishment life cycle level for simple comparisons. */ +enum dahdi_call_level { + /*! Call does not exist. */ + DAHDI_CALL_LEVEL_IDLE, + /*! Call is present but has no response yet. (SETUP) */ + DAHDI_CALL_LEVEL_SETUP, + /*! Call is collecting digits for overlap dialing. (SETUP ACKNOWLEDGE) */ + DAHDI_CALL_LEVEL_OVERLAP, + /*! Call routing is happening. (PROCEEDING) */ + DAHDI_CALL_LEVEL_PROCEEDING, + /*! Called party is being alerted of the call. (ALERTING) */ + DAHDI_CALL_LEVEL_ALERTING, + /*! Call is connected/answered. (CONNECT) */ + DAHDI_CALL_LEVEL_CONNECT, +}; + struct dahdi_pri { pthread_t master; /*!< Thread of master */ ast_mutex_t lock; /*!< Mutex */ @@ -918,14 +934,17 @@ static struct dahdi_pvt { * \note Applies to SS7 channels. */ unsigned int remotelyblocked:1; + /*! + * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled + * \note Set from the "usesmdi" value read in from chan_dahdi.conf + */ + unsigned int use_smdi:1; #if defined(HAVE_PRI) || defined(HAVE_SS7) /*! * \brief XXX BOOLEAN Purpose??? * \note Applies to SS7 channels. */ unsigned int rlt:1; - /*! \brief TRUE if channel is alerting/ringing */ - unsigned int alerting:1; /*! \brief TRUE if the call has already gone/hungup */ unsigned int alreadyhungup:1; /*! @@ -933,29 +952,17 @@ static struct dahdi_pvt { * \note Applies to PRI channels. */ unsigned int isidlecall:1; - /*! - * \brief TRUE if call is in a proceeding state. - * The call has started working its way through the network. - */ - unsigned int proceeding:1; - /*! \brief TRUE if the call has seen progress through the network. */ + /*! \brief TRUE if the call has seen inband-information progress through the network. */ unsigned int progress:1; /*! * \brief TRUE if this channel is being reset/restarted * \note Applies to PRI channels. */ unsigned int resetting:1; - /*! - * \brief TRUE if this channel has received a SETUP_ACKNOWLEDGE - * \note Applies to PRI channels. - */ - unsigned int setup_ack:1; + + /*! Call establishment life cycle level for simple comparisons. */ + enum dahdi_call_level call_level; #endif - /*! - * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled - * \note Set from the "usesmdi" value read in from chan_dahdi.conf - */ - unsigned int use_smdi:1; struct mwisend_info mwisend_data; /*! \brief The serial port to listen for SMDI data on */ struct ast_smdi_interface *smdi_iface; @@ -2298,21 +2305,37 @@ static int dahdi_digit_begin(struct ast_channel *chan, char digit) #ifdef HAVE_PRI if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP)) - && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) { - if (pvt->setup_ack) { + && chan->_state == AST_STATE_DIALING) { + if (pvt->call_level < DAHDI_CALL_LEVEL_OVERLAP) { + unsigned int len; + + len = strlen(pvt->dialdest); + if (len < sizeof(pvt->dialdest) - 1) { + ast_debug(1, "Queueing digit '%c' since setup_ack not yet received\n", + digit); + pvt->dialdest[len++] = digit; + pvt->dialdest[len] = '\0'; + } else { + ast_log(LOG_WARNING, + "Span %d: Deferred digit buffer overflow for digit '%c'.\n", + pvt->span, digit); + } + goto out; + } + if (pvt->call_level < DAHDI_CALL_LEVEL_PROCEEDING) { if (!pri_grab(pvt, pvt->pri)) { pri_information(pvt->pri->pri, pvt->call, digit); pri_rel(pvt->pri); - } else + } else { ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span); - } else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) { - int res; - ast_debug(1, "Queueing digit '%c' since setup_ack not yet received\n", digit); - res = strlen(pvt->dialdest); - pvt->dialdest[res++] = digit; - pvt->dialdest[res] = '\0'; + } + goto out; + } + if (pvt->call_level < DAHDI_CALL_LEVEL_CONNECT) { + ast_log(LOG_WARNING, + "Span %d: Digit '%c' may be ignored by peer. (Call level:%d)\n", + pvt->span, digit, pvt->call_level); } - goto out; } #endif if ((dtmf = digit_to_dtmfindex(digit)) == -1) @@ -3582,6 +3605,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) ast_channel_unlock(ast); + p->call_level = DAHDI_CALL_LEVEL_SETUP; isup_iam(p->ss7->ss7, p->ss7call); ast_setstate(ast, AST_STATE_DIALING); ss7_rel(p->ss7); @@ -3897,11 +3921,14 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) if (pri_setup(p->pri->pri, p->call, sr)) { ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", c + p->stripmsd + dp_strip, dialplan2str(p->pri->dialplan)); + pri_destroycall(p->pri->pri, p->call); + p->call = NULL; pri_rel(p->pri); ast_mutex_unlock(&p->lock); pri_sr_free(sr); return -1; } + p->call_level = DAHDI_CALL_LEVEL_SETUP; pri_sr_free(sr); ast_setstate(ast, AST_STATE_DIALING); pri_rel(p->pri); @@ -4570,12 +4597,10 @@ static int dahdi_hangup(struct ast_channel *ast) p->pulsedial = 0; p->onhooktime = time(NULL); #if defined(HAVE_PRI) || defined(HAVE_SS7) - p->proceeding = 0; p->dialing = 0; p->progress = 0; - p->alerting = 0; - p->setup_ack = 0; p->rlt = 0; + p->call_level = DAHDI_CALL_LEVEL_IDLE; #endif if (p->dsp) { ast_dsp_free(p->dsp); @@ -4879,7 +4904,9 @@ static int dahdi_answer(struct ast_channel *ast) case SIG_PRI: /* Send a pri acknowledge */ if (!pri_grab(p, p->pri)) { - p->proceeding = 1; + if (p->call_level < DAHDI_CALL_LEVEL_CONNECT) { + p->call_level = DAHDI_CALL_LEVEL_CONNECT; + } p->dialing = 0; res = pri_answer(p->pri->pri, p->call, 0, !p->digital); pri_rel(p->pri); @@ -4892,7 +4919,9 @@ static int dahdi_answer(struct ast_channel *ast) #ifdef HAVE_SS7 case SIG_SS7: if (!ss7_grab(p, p->ss7)) { - p->proceeding = 1; + if (p->call_level < DAHDI_CALL_LEVEL_CONNECT) { + p->call_level = DAHDI_CALL_LEVEL_CONNECT; + } res = isup_anm(p->ss7->ss7, p->ss7call); ss7_rel(p->ss7); } else { @@ -5966,7 +5995,10 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast) p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0; ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff); #if defined(HAVE_PRI) - if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) { + if (((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) + && p->call_level < DAHDI_CALL_LEVEL_PROCEEDING + && p->pri + && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) { /* absorb event */ } else #endif /* defined(HAVE_PRI) */ @@ -5983,7 +6015,10 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast) if (res & DAHDI_EVENT_DTMFDOWN) { ast_debug(1, "DTMF Down '%c'\n", res & 0xff); #if defined(HAVE_PRI) - if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) { + if (((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) + && p->call_level < DAHDI_CALL_LEVEL_PROCEEDING + && p->pri + && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) { /* absorb event */ } else #endif /* defined(HAVE_PRI) */ @@ -7309,9 +7344,11 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) } else if (f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END) { #ifdef HAVE_PRI - if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && - ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) || - (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) { + if (((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) + && p->call_level < DAHDI_CALL_LEVEL_PROCEEDING + && p->pri + && ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) + || (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) { /* Don't accept in-band DTMF when in overlap dial mode */ ast_debug(1, "Absorbing inband %s DTMF digit: 0x%02X '%c' on %s\n", f->frametype == AST_FRAME_DTMF_BEGIN ? "begin" : "end", @@ -7422,22 +7459,6 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame) return -1; } -#if 0 -#ifdef HAVE_PRI - ast_mutex_lock(&p->lock); - if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) { - if (p->pri->pri) { - if (!pri_grab(p, p->pri)) { - pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital); - pri_rel(p->pri); - } else - ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); - } - p->proceeding=1; - } - ast_mutex_unlock(&p->lock); -#endif -#endif /* Write a frame of (presumably voice) data */ if (frame->frametype != AST_FRAME_VOICE) { if (frame->frametype != AST_FRAME_IMAGE) @@ -7513,57 +7534,60 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d switch (condition) { case AST_CONTROL_BUSY: #ifdef HAVE_PRI - if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) { - chan->hangupcause = AST_CAUSE_USER_BUSY; - chan->_softhangup |= AST_SOFTHANGUP_DEV; - res = 0; - } else if (!p->progress && - ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing) { - if (p->pri->pri) { - if (!pri_grab(p, p->pri)) { + if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) { + if (p->priindication_oob) { + chan->hangupcause = AST_CAUSE_USER_BUSY; + chan->_softhangup |= AST_SOFTHANGUP_DEV; + res = 0; + break; + } + res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY); + if (p->call_level < DAHDI_CALL_LEVEL_ALERTING && !p->outgoing) { + chan->hangupcause = AST_CAUSE_USER_BUSY; + p->progress = 1;/* No need to send plain PROGRESS after this. */ + if (p->pri && p->pri->pri) { + if (!pri_grab(p, p->pri)) { #ifdef HAVE_PRI_PROG_W_CAUSE - pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, PRI_CAUSE_USER_BUSY); /* cause = 17 */ + pri_progress_with_cause(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 1, chan->hangupcause); #else - pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1); + pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1); #endif - pri_rel(p->pri); + pri_rel(p->pri); + } else { + ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); + } } - else - ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); } - p->progress = 1; - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY); - } else + break; + } #endif - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY); + res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY); break; case AST_CONTROL_RINGING: #ifdef HAVE_PRI - if ((!p->alerting) && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) { - if (p->pri->pri) { + if (((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) + && p->call_level < DAHDI_CALL_LEVEL_ALERTING && !p->outgoing) { + p->call_level = DAHDI_CALL_LEVEL_ALERTING; + if (p->pri && p->pri->pri) { if (!pri_grab(p, p->pri)) { pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital); pri_rel(p->pri); - } - else + } else { ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); + } } - p->alerting = 1; } - #endif #ifdef HAVE_SS7 - if ((!p->alerting) && (p->sig == SIG_SS7) && p->ss7 && !p->outgoing && (chan->_state != AST_STATE_UP)) { - if (p->ss7->ss7) { + if (p->sig == SIG_SS7 + && p->call_level < DAHDI_CALL_LEVEL_ALERTING && !p->outgoing) { + p->call_level = DAHDI_CALL_LEVEL_ALERTING; + if (p->ss7 && p->ss7->ss7) { ss7_grab(p, p->ss7); - if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) p->rlt = 1; if (p->rlt != 1) /* No need to send CPG if call will be RELEASE */ isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING); - p->alerting = 1; ss7_rel(p->ss7); } } @@ -7582,34 +7606,35 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d case AST_CONTROL_PROCEEDING: ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name); #ifdef HAVE_PRI - if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing) { - if (p->pri->pri) { + if (((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) + && p->call_level < DAHDI_CALL_LEVEL_PROCEEDING && !p->outgoing) { + p->call_level = DAHDI_CALL_LEVEL_PROCEEDING; + if (p->pri && p->pri->pri) { if (!pri_grab(p, p->pri)) { pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital); pri_rel(p->pri); - } - else + } else { ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); + } } - p->proceeding = 1; p->dialing = 0; } #endif #ifdef HAVE_SS7 - /* This IF sends the FAR for an answered ALEG call */ - if (chan->_state == AST_STATE_UP && (p->rlt != 1) && (p->sig == SIG_SS7)){ - if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) - p->rlt = 1; - } - - if (!p->proceeding && p->sig == SIG_SS7 && p->ss7 && !p->outgoing) { - if (p->ss7->ss7) { - ss7_grab(p, p->ss7); - isup_acm(p->ss7->ss7, p->ss7call); - p->proceeding = 1; - ss7_rel(p->ss7); + if (p->sig == SIG_SS7) { + /* This IF sends the FAR for an answered ALEG call */ + if (chan->_state == AST_STATE_UP && (p->rlt != 1)){ + if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) + p->rlt = 1; + } + if (p->call_level < DAHDI_CALL_LEVEL_PROCEEDING && !p->outgoing) { + p->call_level = DAHDI_CALL_LEVEL_PROCEEDING; + if (p->ss7 && p->ss7->ss7) { + ss7_grab(p, p->ss7); + isup_acm(p->ss7->ss7, p->ss7call); + ss7_rel(p->ss7); + } } } #endif @@ -7620,9 +7645,11 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name); #ifdef HAVE_PRI p->digital = 0; /* Digital-only calls isn't allows any inband progress messages */ - if (!p->progress && !p->alerting && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing) { - if (p->pri->pri) { + if (((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) + && !p->progress && p->call_level < DAHDI_CALL_LEVEL_ALERTING + && !p->outgoing) { + p->progress = 1;/* No need to send plain PROGRESS again. */ + if (p->pri && p->pri->pri) { if (!pri_grab(p, p->pri)) { #ifdef HAVE_PRI_PROG_W_CAUSE pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, -1); /* no cause at all */ @@ -7630,23 +7657,23 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1); #endif pri_rel(p->pri); - } - else + } else { ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); + } } - p->progress = 1; } #endif #ifdef HAVE_SS7 - if (!p->progress && p->sig==SIG_SS7 && p->ss7 && !p->outgoing) { - if (p->ss7->ss7) { + if (p->sig == SIG_SS7 + && !p->progress && p->call_level < DAHDI_CALL_LEVEL_ALERTING + && !p->outgoing) { + p->progress = 1;/* No need to send inband-information progress again. */ + if (p->ss7 && p->ss7->ss7) { ss7_grab(p, p->ss7); isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO); - p->progress = 1; ss7_rel(p->ss7); /* enable echo canceler here on SS7 calls */ dahdi_enable_ec(p); - } } #endif @@ -7654,30 +7681,66 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d res = 0; break; case AST_CONTROL_CONGESTION: - chan->hangupcause = AST_CAUSE_CONGESTION; #ifdef HAVE_PRI - if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) { - chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION; - chan->_softhangup |= AST_SOFTHANGUP_DEV; - res = 0; - } else if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing) { - if (p->pri) { - if (!pri_grab(p, p->pri)) { + if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) { + if (p->priindication_oob) { + /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */ + switch (chan->hangupcause) { + case AST_CAUSE_USER_BUSY: + case AST_CAUSE_NORMAL_CLEARING: + case 0:/* Cause has not been set. */ + /* Supply a more appropriate cause. */ + chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION; + break; + default: + break; + } + chan->_softhangup |= AST_SOFTHANGUP_DEV; + res = 0; + break; + } + res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); + if (p->call_level < DAHDI_CALL_LEVEL_ALERTING && !p->outgoing) { + /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */ + switch (chan->hangupcause) { + case AST_CAUSE_USER_BUSY: + case AST_CAUSE_NORMAL_CLEARING: + case 0:/* Cause has not been set. */ + /* Supply a more appropriate cause. */ + chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION; + break; + default: + break; + } + p->progress = 1;/* No need to send plain PROGRESS after this. */ + if (p->pri && p->pri->pri) { + if (!pri_grab(p, p->pri)) { #ifdef HAVE_PRI_PROG_W_CAUSE - pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, PRI_CAUSE_SWITCH_CONGESTION); /* cause = 42 */ + pri_progress_with_cause(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 1, chan->hangupcause); #else - pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1); + pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1); #endif - pri_rel(p->pri); - } else - ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); + pri_rel(p->pri); + } else { + ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); + } + } } - p->progress = 1; - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); - } else + break; + } #endif - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); + /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */ + switch (chan->hangupcause) { + case AST_CAUSE_USER_BUSY: + case AST_CAUSE_NORMAL_CLEARING: + case 0:/* Cause has not been set. */ + /* Supply a more appropriate cause. */ + chan->hangupcause = AST_CAUSE_CONGESTION; + break; + default: + break; + } + res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); break; case AST_CONTROL_HOLD: #ifdef HAVE_PRI @@ -8085,12 +8148,28 @@ static void *ss_thread(void *data) if (p->dsp) { ast_dsp_digitreset(p->dsp); } - if (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) { +#if defined(ISSUE_16789) + /* + * Conditionaled out this code to effectively revert the Mantis + * issue 16789 change. It breaks overlap dialing through + * Asterisk. There is not enough information available at this + * point to know if dialing is complete. The + * ast_exists_extension(), ast_matchmore_extension(), and + * ast_canmatch_extension() calls are not adequate to detect a + * dial through extension pattern of "_9!". + * + * Workaround is to use the dialplan Proceeding() application + * early on non-dial through extensions. + */ + if ((p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) + && !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) { ast_mutex_lock(&p->lock); - if (p->pri->pri) { + if (p->pri->pri) { if (!pri_grab(p, p->pri)) { + if (p->call_level < DAHDI_CALL_LEVEL_PROCEEDING) { + p->call_level = DAHDI_CALL_LEVEL_PROCEEDING; + } pri_proceeding(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 0); - p->proceeding = 1; pri_rel(p->pri); } else { ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); @@ -8098,6 +8177,8 @@ static void *ss_thread(void *data) } ast_mutex_unlock(&p->lock); } +#endif /* defined(ISSUE_16789) */ + dahdi_enable_ec(p); ast_setstate(chan, AST_STATE_RING); res = ast_pbx_run(chan); @@ -11618,17 +11699,19 @@ static void ss7_start_call(struct dahdi_pvt *p, struct dahdi_ss7 *linkset) ast_log(LOG_WARNING, "Unable to set law on channel %d\n", p->channel); if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) { - p->proceeding = 1; + p->call_level = DAHDI_CALL_LEVEL_PROCEEDING; isup_acm(ss7, p->ss7call); + } else { + p->call_level = DAHDI_CALL_LEVEL_SETUP; } ast_mutex_unlock(&linkset->lock); c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, law, 0); - if (!c) { ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic); /* Holding this lock is assumed entering the function */ ast_mutex_lock(&linkset->lock); + p->call_level = DAHDI_CALL_LEVEL_IDLE; return; } else ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic); @@ -11883,7 +11966,9 @@ static void *ss7_linkset(void *data) ast_mutex_lock(&p->lock); switch (e->cpg.event) { case CPG_EVENT_ALERTING: - p->alerting = 1; + if (p->call_level < DAHDI_CALL_LEVEL_ALERTING) { + p->call_level = DAHDI_CALL_LEVEL_ALERTING; + } p->subs[SUB_REAL].needringing = 1; break; case CPG_EVENT_PROGRESS: @@ -12123,11 +12208,15 @@ static void *ss7_linkset(void *data) ast_mutex_lock(&p->lock); dahdi_queue_frame(p, &f, linkset); - p->proceeding = 1; + if (p->call_level < DAHDI_CALL_LEVEL_PROCEEDING) { + p->call_level = DAHDI_CALL_LEVEL_PROCEEDING; + } p->dialing = 0; /* Send alerting if subscriber is free */ if (e->acm.called_party_status_ind == 1) { - p->alerting = 1; + if (p->call_level < DAHDI_CALL_LEVEL_ALERTING) { + p->call_level = DAHDI_CALL_LEVEL_ALERTING; + } p->subs[SUB_REAL].needringing = 1; } ast_mutex_unlock(&p->lock); @@ -12231,6 +12320,9 @@ static void *ss7_linkset(void *data) } else { p = linkset->pvts[chanpos]; ast_mutex_lock(&p->lock); + if (p->call_level < DAHDI_CALL_LEVEL_CONNECT) { + p->call_level = DAHDI_CALL_LEVEL_CONNECT; + } p->subs[SUB_REAL].needanswer = 1; if (p->dsp && p->dsp_features) { ast_dsp_set_features(p->dsp, p->dsp_features); @@ -12490,6 +12582,22 @@ static int pri_fixup_principle(struct dahdi_pri *pri, int principle, q931_call * new->dsp_features = old->dsp_features; old->dsp = NULL; old->dsp_features = 0; + + /* Transfer flags from the old channel. */ + new->alreadyhungup = old->alreadyhungup; + new->isidlecall = old->isidlecall; + new->progress = old->progress; + new->outgoing = old->outgoing; + new->digital = old->digital; + old->alreadyhungup = 0; + old->isidlecall = 0; + old->progress = 0; + old->outgoing = 0; + old->digital = 0; + + /* More stuff to transfer to the new channel. */ + new->call_level = old->call_level; + old->call_level = DAHDI_CALL_LEVEL_IDLE; } return principle; } @@ -13266,13 +13374,14 @@ static void *pri_dchannel(void *vpri) ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel); if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) { /* Just announce proceeding */ - pri->pvts[chanpos]->proceeding = 1; + pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_PROCEEDING; pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0); + } else if (pri->switchtype == PRI_SWITCH_GR303_TMC) { + pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_CONNECT; + pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1); } else { - if (pri->switchtype != PRI_SWITCH_GR303_TMC) - pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1); - else - pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1); + pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_OVERLAP; + pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1); } /* Get the use_callingpres state */ pri->pvts[chanpos]->callingpres = e->ring.callingpres; @@ -13316,6 +13425,21 @@ static void *pri_dchannel(void *vpri) pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr); if (e->ring.redirectingreason >= 0) pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason)); + + if (!pri->pvts[chanpos]->digital) { + /* + * Call has a channel. + * Indicate that we are providing dialtone. + */ + pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */ +#ifdef HAVE_PRI_PROG_W_CAUSE + pri_progress_with_cause(pri->pri, e->ring.call, + PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */ +#else + pri_progress(pri->pri, e->ring.call, + PVT_TO_CHANNEL(pri->pvts[chanpos]), 1); +#endif + } } if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) { ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n", @@ -13419,7 +13543,9 @@ static void *pri_dchannel(void *vpri) if (ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) { dahdi_enable_ec(pri->pvts[chanpos]); pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1; - pri->pvts[chanpos]->alerting = 1; + if (pri->pvts[chanpos]->call_level < DAHDI_CALL_LEVEL_ALERTING) { + pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_ALERTING; + } } else ast_debug(1, "Deferring ringing notification because of extra digits to dial...\n"); @@ -13507,10 +13633,11 @@ static void *pri_dchannel(void *vpri) case PRI_EVENT_PROCEEDING: chanpos = pri_find_principle(pri, e->proceeding.channel); if (chanpos > -1) { - if (!pri->pvts[chanpos]->proceeding) { + ast_mutex_lock(&pri->pvts[chanpos]->lock); + if (pri->pvts[chanpos]->call_level < DAHDI_CALL_LEVEL_PROCEEDING) { struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, }; - ast_mutex_lock(&pri->pvts[chanpos]->lock); + pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_PROCEEDING; ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span); dahdi_queue_frame(pri->pvts[chanpos], &f, pri); @@ -13530,10 +13657,9 @@ static void *pri_dchannel(void *vpri) f.subclass = AST_CONTROL_PROGRESS; dahdi_queue_frame(pri->pvts[chanpos], &f, pri); } - pri->pvts[chanpos]->proceeding = 1; pri->pvts[chanpos]->dialing = 0; - ast_mutex_unlock(&pri->pvts[chanpos]->lock); } + ast_mutex_unlock(&pri->pvts[chanpos]->lock); } break; case PRI_EVENT_FACNAME: @@ -13602,7 +13728,9 @@ static void *pri_dchannel(void *vpri) ast_debug(1, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel); } else { pri->pvts[chanpos]->dialing = 0; - pri->pvts[chanpos]->proceeding = 1; + if (pri->pvts[chanpos]->call_level < DAHDI_CALL_LEVEL_CONNECT) { + pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_CONNECT; + } pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1; /* Enable echo cancellation if it's not on already */ dahdi_enable_ec(pri->pvts[chanpos]); @@ -13871,14 +13999,37 @@ static void *pri_dchannel(void *vpri) } else { chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call); if (chanpos > -1) { + unsigned int len; + ast_mutex_lock(&pri->pvts[chanpos]->lock); - pri->pvts[chanpos]->setup_ack = 1; + if (pri->pvts[chanpos]->call_level < DAHDI_CALL_LEVEL_OVERLAP) { + pri->pvts[chanpos]->call_level = DAHDI_CALL_LEVEL_OVERLAP; + } + /* Send any queued digits */ - for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) { + len = strlen(pri->pvts[chanpos]->dialdest); + for (x = 0; x < len; ++x) { ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]); pri_information(pri->pri, pri->pvts[chanpos]->call, pri->pvts[chanpos]->dialdest[x]); } + + if (!pri->pvts[chanpos]->progress + && (pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING) + && !pri->pvts[chanpos]->digital) { + /* + * Call has a channel. + * Indicate for overlap dialing that dialtone may be present. + */ + struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, }; + dahdi_queue_frame(pri->pvts[chanpos], &f, pri); + pri->pvts[chanpos]->progress = 1;/* Claim to have seen inband-information */ + pri->pvts[chanpos]->dialing = 0; + if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) { + ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features); + pri->pvts[chanpos]->dsp_features = 0; + } + } ast_mutex_unlock(&pri->pvts[chanpos]->lock); } else ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel); |