Merged revisions 303771 via svnmerge from
authorRichard Mudgett <rmudgett@digium.com>
Tue, 25 Jan 2011 17:58:00 +0000 (17:58 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 25 Jan 2011 17:58:00 +0000 (17:58 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.8

................
  r303771 | rmudgett | 2011-01-25 11:49:20 -0600 (Tue, 25 Jan 2011) | 54 lines

  Merged revisions 303769 via svnmerge from
  https://origsvn.digium.com/svn/asterisk/branches/1.6.2

  ................
    r303769 | rmudgett | 2011-01-25 11:42:42 -0600 (Tue, 25 Jan 2011) | 47 lines

    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: https://origsvn.digium.com/svn/asterisk/trunk@303772 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_dahdi.c
channels/sig_pri.c
channels/sig_pri.h
channels/sig_ss7.c
channels/sig_ss7.h

index dd3366e..328ec8b 100644 (file)
@@ -7705,7 +7705,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
 #if defined(HAVE_PRI)
                if (dahdi_sig_pri_lib_handles(p->sig)
-                       && !((struct sig_pri_chan *) p->sig_pvt)->proceeding
+                       && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
                        && p->pri
                        && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
                        /* absorb event */
@@ -7725,7 +7725,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
 #if defined(HAVE_PRI)
                if (dahdi_sig_pri_lib_handles(p->sig)
-                       && !((struct sig_pri_chan *) p->sig_pvt)->proceeding
+                       && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
                        && p->pri
                        && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
                        /* absorb event */
@@ -8976,7 +8976,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                                || f->frametype == AST_FRAME_DTMF_END) {
 #ifdef HAVE_PRI
                                if (dahdi_sig_pri_lib_handles(p->sig)
-                                       && !((struct sig_pri_chan *) p->sig_pvt)->proceeding
+                                       && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
                                        && p->pri
                                        && ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING))
                                                || (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
@@ -9209,7 +9209,17 @@ 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;
+                       /* 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;
+                       }
                        break;
                case AST_CONTROL_HOLD:
                        ast_moh_start(chan, data, p->mohinterpret);
index a858ef2..27e5dcf 100644 (file)
@@ -1242,12 +1242,9 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
                new_chan->waiting_for_aoce = old_chan->waiting_for_aoce;
                new_chan->holding_aoce = old_chan->holding_aoce;
 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
-               new_chan->alerting = old_chan->alerting;
                new_chan->alreadyhungup = old_chan->alreadyhungup;
                new_chan->isidlecall = old_chan->isidlecall;
-               new_chan->proceeding = old_chan->proceeding;
                new_chan->progress = old_chan->progress;
-               new_chan->setup_ack = old_chan->setup_ack;
                new_chan->outgoing = old_chan->outgoing;
                new_chan->digital = old_chan->digital;
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1259,12 +1256,9 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
                old_chan->waiting_for_aoce = 0;
                old_chan->holding_aoce = 0;
 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
-               old_chan->alerting = 0;
                old_chan->alreadyhungup = 0;
                old_chan->isidlecall = 0;
-               old_chan->proceeding = 0;
                old_chan->progress = 0;
-               old_chan->setup_ack = 0;
                old_chan->outgoing = 0;
                old_chan->digital = 0;
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1272,6 +1266,8 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
 
                /* More stuff to transfer to the new channel. */
+               new_chan->call_level = old_chan->call_level;
+               old_chan->call_level = SIG_PRI_CALL_LEVEL_IDLE;
 #if defined(HAVE_PRI_REVERSE_CHARGE)
                new_chan->reverse_charging_indication = old_chan->reverse_charging_indication;
 #endif /* defined(HAVE_PRI_REVERSE_CHARGE) */
@@ -1632,12 +1628,28 @@ static void *pri_ss_thread(void *data)
                /* Start the real PBX */
                ast_copy_string(chan->exten, exten, sizeof(chan->exten));
                sig_pri_dsp_reset_and_flush_digits(p);
-               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)) {
                        sig_pri_lock_private(p);
-                       if (p->pri->pri) {              
+                       if (p->pri->pri) {
                                if (!pri_grab(p, p->pri)) {
+                                       if (p->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING) {
+                                               p->call_level = SIG_PRI_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->pri->span);
@@ -1645,6 +1657,7 @@ static void *pri_ss_thread(void *data)
                        }
                        sig_pri_unlock_private(p);
                }
+#endif /* defined(ISSUE_16789) */
 
                sig_pri_set_echocanceller(p, 1);
                ast_setstate(chan, AST_STATE_RING);
@@ -5696,13 +5709,14 @@ static void *pri_dchannel(void *vpri)
                                                /* Setup law */
                                                if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
                                                        /* Just announce proceeding */
-                                                       pri->pvts[chanpos]->proceeding = 1;
+                                                       pri->pvts[chanpos]->call_level = SIG_PRI_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 = SIG_PRI_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 = SIG_PRI_CALL_LEVEL_OVERLAP;
+                                                       pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
                                                }
 
                                                /* Start PBX */
@@ -5786,6 +5800,21 @@ static void *pri_dchannel(void *vpri)
                                                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
                                                                        e->ring.subcmds, e->ring.call);
 
+                                                               if (!pri->pvts[chanpos]->digital
+                                                                       && !pri->pvts[chanpos]->no_b_channel) {
+                                                                       /*
+                                                                        * 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, pri_ss_thread, pri->pvts[chanpos])) {
                                                                ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
@@ -5944,7 +5973,9 @@ static void *pri_dchannel(void *vpri)
                                                sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCNR);
                                                sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
                                                pri_queue_control(pri, chanpos, AST_CONTROL_RINGING);
-                                               pri->pvts[chanpos]->alerting = 1;
+                                               if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_ALERTING) {
+                                                       pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_ALERTING;
+                                               }
 
                                                if (
 #ifdef PRI_PROGRESS_MASK
@@ -6031,11 +6062,11 @@ static void *pri_dchannel(void *vpri)
                                        sig_pri_lock_private(pri->pvts[chanpos]);
                                        sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
                                                e->proceeding.subcmds, e->proceeding.call);
-                                       if (!pri->pvts[chanpos]->proceeding) {
+                                       if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING) {
+                                               pri->pvts[chanpos]->call_level = SIG_PRI_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);
                                                pri_queue_control(pri, chanpos, AST_CONTROL_PROCEEDING);
-                                               pri->pvts[chanpos]->proceeding = 1;
                                        }
                                        if (!pri->pvts[chanpos]->progress
                                                && !pri->pvts[chanpos]->no_b_channel
@@ -6170,7 +6201,9 @@ static void *pri_dchannel(void *vpri)
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
                                        e->answer.subcmds, e->answer.call);
-                               pri->pvts[chanpos]->proceeding = 1;
+                               if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_CONNECT) {
+                                       pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
+                               }
                                sig_pri_open_media(pri->pvts[chanpos]);
                                pri_queue_control(pri, chanpos, AST_CONTROL_ANSWER);
                                /* Enable echo cancellation if it's not on already */
@@ -6593,16 +6626,36 @@ static void *pri_dchannel(void *vpri)
                                } else {
                                        chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
                                        if (chanpos > -1) {
+                                               unsigned int len;
+
                                                sig_pri_lock_private(pri->pvts[chanpos]);
                                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->setup_ack.channel,
                                                        e->setup_ack.subcmds, e->setup_ack.call);
-                                               pri->pvts[chanpos]->setup_ack = 1;
+                                               if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_OVERLAP) {
+                                                       pri->pvts[chanpos]->call_level = SIG_PRI_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
+                                                       && !pri->pvts[chanpos]->no_b_channel) {
+                                                       /*
+                                                        * Call has a channel.
+                                                        * Indicate for overlap dialing that dialtone may be present.
+                                                        */
+                                                       pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
+                                                       pri->pvts[chanpos]->progress = 1;/* Claim to have seen inband-information */
+                                                       sig_pri_set_dialing(pri->pvts[chanpos], 0);
+                                                       sig_pri_open_media(pri->pvts[chanpos]);
+                                               }
                                                sig_pri_unlock_private(pri->pvts[chanpos]);
                                        } else
                                                ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel);
@@ -6738,10 +6791,8 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
                ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
        }
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
-       p->proceeding = 0;
+       p->call_level = SIG_PRI_CALL_LEVEL_IDLE;
        p->progress = 0;
-       p->alerting = 0;
-       p->setup_ack = 0;
        p->cid_num[0] = '\0';
        p->cid_subaddr[0] = '\0';
        p->cid_name[0] = '\0';
@@ -7302,6 +7353,8 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i
                                ast_log(LOG_WARNING, "Unable to setup CC recall call to device %s\n",
                                        device_name);
                                ao2_ref(monitor, -1);
+                               pri_destroycall(p->pri->pri, p->call);
+                               p->call = NULL;
                                pri_rel(p->pri);
                                pri_sr_free(sr);
                                return -1;
@@ -7318,10 +7371,13 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i
        if (core_id == -1 && 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);
                pri_sr_free(sr);
                return -1;
        }
+       p->call_level = SIG_PRI_CALL_LEVEL_SETUP;
        pri_sr_free(sr);
        ast_setstate(ast, AST_STATE_DIALING);
        sig_pri_set_dialing(p, 1);
@@ -7339,11 +7395,16 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                        chan->hangupcause = AST_CAUSE_USER_BUSY;
                        chan->_softhangup |= AST_SOFTHANGUP_DEV;
                        res = 0;
-               } else if (!p->progress && p->pri && !p->outgoing) {
-                       if (p->pri->pri) {
+                       break;
+               }
+               res = sig_pri_play_tone(p, SIG_PRI_TONE_BUSY);
+               if (p->call_level < SIG_PRI_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);
 #endif
@@ -7352,13 +7413,12 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                                        ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
                                }
                        }
-                       p->progress = 1;
-                       res = sig_pri_play_tone(p, SIG_PRI_TONE_BUSY);
                }
                break;
        case AST_CONTROL_RINGING:
-               if ((!p->alerting) && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) {
-                       if (p->pri->pri) {
+               if (p->call_level < SIG_PRI_CALL_LEVEL_ALERTING && !p->outgoing) {
+                       p->call_level = SIG_PRI_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->no_b_channel || p->digital ? 0 : 1);
@@ -7367,7 +7427,6 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                                        ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
                                }
                        }
-                       p->alerting = 1;
                }
                res = sig_pri_play_tone(p, SIG_PRI_TONE_RINGTONE);
                if (chan->_state != AST_STATE_UP) {
@@ -7377,12 +7436,12 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                break;
        case AST_CONTROL_PROCEEDING:
                ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
-               if (!p->proceeding && p->pri && !p->outgoing) {
-                       if (p->pri->pri) {
+               if (p->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING && !p->outgoing) {
+                       p->call_level = SIG_PRI_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->no_b_channel || p->digital ? 0 : 1);
-                                       p->proceeding = 1;
                                        if (!p->no_b_channel && !p->digital) {
                                                sig_pri_set_dialing(p, 0);
                                        }
@@ -7398,8 +7457,10 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
        case AST_CONTROL_PROGRESS:
                ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
                sig_pri_set_digital(p, 0);      /* Digital-only calls isn't allowing any inband progress messages */
-               if (!p->progress && !p->alerting && p->pri && !p->outgoing && !p->no_b_channel) {
-                       if (p->pri->pri) {
+               if (!p->progress && p->call_level < SIG_PRI_CALL_LEVEL_ALERTING && !p->outgoing
+                       && !p->no_b_channel) {
+                       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 */
@@ -7411,22 +7472,45 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                                        ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
                                }
                        }
-                       p->progress = 1;
                }
                /* don't continue in ast_indicate */
                res = 0;
                break;
        case AST_CONTROL_CONGESTION:
-               chan->hangupcause = AST_CAUSE_CONGESTION;
                if (p->priindication_oob || p->no_b_channel) {
-                       chan->hangupcause = AST_CAUSE_SWITCH_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_SWITCH_CONGESTION;
+                               break;
+                       default:
+                               break;
+                       }
                        chan->_softhangup |= AST_SOFTHANGUP_DEV;
                        res = 0;
-               } else if (!p->progress && p->pri && !p->outgoing) {
-                       if (p->pri->pri) {
+                       break;
+               }
+               res = sig_pri_play_tone(p, SIG_PRI_TONE_CONGESTION);
+               if (p->call_level < SIG_PRI_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);
 #endif
@@ -7435,8 +7519,6 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                                        ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
                                }
                        }
-                       p->progress = 1;
-                       res = sig_pri_play_tone(p, SIG_PRI_TONE_CONGESTION);
                }
                break;
        case AST_CONTROL_HOLD:
@@ -7561,7 +7643,9 @@ int sig_pri_answer(struct sig_pri_chan *p, struct ast_channel *ast)
                        p->aoc_s_request_invoke_id_valid = 0;
                }
 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
-               p->proceeding = 1;
+               if (p->call_level < SIG_PRI_CALL_LEVEL_CONNECT) {
+                       p->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
+               }
                sig_pri_set_dialing(p, 0);
                sig_pri_open_media(p);
                res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
@@ -7690,22 +7774,37 @@ int sig_pri_available(struct sig_pri_chan **pvt, int is_specific_channel)
  * functions should handle it normally (generate inband DTMF) */
 int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char digit)
 {
-       if ((ast->_state == AST_STATE_DIALING) && !pvt->proceeding) {
-               if (pvt->setup_ack) {
+       if (ast->_state == AST_STATE_DIALING) {
+               if (pvt->call_level < SIG_PRI_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->pri->span, digit);
+                       }
+                       return 0;
+               }
+               if (pvt->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING) {
                        if (!pri_grab(pvt, pvt->pri)) {
                                pri_information(pvt->pri->pri, pvt->call, digit);
                                pri_rel(pvt->pri);
                        } else {
                                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->pri->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';
+                       return 0;
+               }
+               if (pvt->call_level < SIG_PRI_CALL_LEVEL_CONNECT) {
+                       ast_log(LOG_WARNING,
+                               "Span %d: Digit '%c' may be ignored by peer. (Call level:%d)\n",
+                               pvt->pri->span, digit, pvt->call_level);
                }
-               return 0;
        }
        return 1;
 }
index 2832bd5..1c37508 100644 (file)
@@ -144,6 +144,22 @@ enum sig_pri_moh_event {
        SIG_PRI_MOH_EVENT_NUM
 };
 
+/*! Call establishment life cycle level for simple comparisons. */
+enum sig_pri_call_level {
+       /*! Call does not exist. */
+       SIG_PRI_CALL_LEVEL_IDLE,
+       /*! Call is present but has no response yet. (SETUP) */
+       SIG_PRI_CALL_LEVEL_SETUP,
+       /*! Call is collecting digits for overlap dialing. (SETUP ACKNOWLEDGE) */
+       SIG_PRI_CALL_LEVEL_OVERLAP,
+       /*! Call routing is happening. (PROCEEDING) */
+       SIG_PRI_CALL_LEVEL_PROCEEDING,
+       /*! Called party is being alerted of the call. (ALERTING) */
+       SIG_PRI_CALL_LEVEL_ALERTING,
+       /*! Call is connected/answered. (CONNECT) */
+       SIG_PRI_CALL_LEVEL_CONNECT,
+};
+
 struct sig_pri_span;
 
 struct sig_pri_callback {
@@ -274,13 +290,10 @@ struct sig_pri_chan {
        unsigned int holding_aoce:1;     /*!< received AOC-E msg from asterisk. holding for disconnect/release */
 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
        unsigned int inalarm:1;
-       unsigned int alerting:1;                /*!< TRUE if channel is alerting/ringing */
        unsigned int alreadyhungup:1;   /*!< TRUE if the call has already gone/hungup */
        unsigned int isidlecall:1;              /*!< TRUE if this is an idle call */
-       unsigned int proceeding:1;              /*!< TRUE if call is in a proceeding state */
-       unsigned int progress:1;                /*!< TRUE if the call has seen progress through the network */
+       unsigned int progress:1;                /*!< TRUE if the call has seen inband-information progress through the network */
        unsigned int resetting:1;               /*!< TRUE if this channel is being reset/restarted */
-       unsigned int setup_ack:1;               /*!< TRUE if this channel has received a SETUP_ACKNOWLEDGE */
 
        unsigned int outgoing:1;
        unsigned int digital:1;
@@ -296,6 +309,8 @@ struct sig_pri_chan {
        struct sig_pri_span *pri;
        q931_call *call;                                /*!< opaque libpri call control structure */
 
+       /*! Call establishment life cycle level for simple comparisons. */
+       enum sig_pri_call_level call_level;
        int prioffset;                                  /*!< channel number in span */
        int logicalspan;                                /*!< logical span number within trunk group */
        int mastertrunkgroup;                   /*!< what trunk group is our master */
index 7e1f76a..68ebc5a 100644 (file)
@@ -431,8 +431,10 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
        char tmp[256];
 
        if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) {
-               p->proceeding = 1;
+               p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
                isup_acm(ss7, p->ss7call);
+       } else {
+               p->call_level = SIG_SS7_CALL_LEVEL_SETUP;
        }
 
        if (linkset->type == SS7_ITU) {
@@ -451,7 +453,7 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
                ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
                ast_mutex_lock(&linkset->lock);
                isup_rel(linkset->ss7, p->ss7call, -1);
-               p->proceeding = 0;
+               p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
                p->alreadyhungup = 1;
                return;
        }
@@ -682,7 +684,9 @@ void *ss7_linkset(void *data)
                                sig_ss7_lock_private(p);
                                switch (e->cpg.event) {
                                case CPG_EVENT_ALERTING:
-                                       p->alerting = 1;
+                                       if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
+                                               p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
+                                       }
                                        sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
                                        break;
                                case CPG_EVENT_PROGRESS:
@@ -925,11 +929,15 @@ void *ss7_linkset(void *data)
 
                                        sig_ss7_lock_private(p);
                                        sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROCEEDING);
-                                       p->proceeding = 1;
+                                       if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
+                                               p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
+                                       }
                                        sig_ss7_set_dialing(p, 0);
                                        /* Send alerting if subscriber is free */
                                        if (e->acm.called_party_status_ind == 1) {
-                                               p->alerting = 1;
+                                               if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
+                                                       p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
+                                               }
                                                sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
                                        }
                                        sig_ss7_unlock_private(p);
@@ -1033,6 +1041,9 @@ void *ss7_linkset(void *data)
                                } else {
                                        p = linkset->pvts[chanpos];
                                        sig_ss7_lock_private(p);
+                                       if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
+                                               p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
+                                       }
                                        sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_ANSWER);
 #if 0  /* This code no longer seems to be necessary so I did not convert it. */
                                        if (p->dsp && p->dsp_features) {
@@ -1361,6 +1372,7 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, char *rdest)
        if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
                (isup_far(p->ss7->ss7, p->ss7call));
 
+       p->call_level = SIG_SS7_CALL_LEVEL_SETUP;
        isup_iam(p->ss7->ss7, p->ss7call);
        sig_ss7_set_dialing(p, 1);
        ast_setstate(ast, AST_STATE_DIALING);
@@ -1389,10 +1401,9 @@ int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
 
        p->owner = NULL;
        sig_ss7_set_dialing(p, 0);
+       p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
        p->outgoing = 0;
-       p->proceeding = 0;
        p->progress = 0;
-       p->alerting = 0;
        p->rlt = 0;
        p->exten[0] = '\0';
        /* Perform low level hangup if no owner left */
@@ -1435,7 +1446,9 @@ int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast)
        int res;
 
        if (!ss7_grab(p, p->ss7)) {
-               p->proceeding = 1;
+               if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
+                       p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
+               }
                res = isup_anm(p->ss7->ss7, p->ss7call);
                ss7_rel(p->ss7);
        } else {
@@ -1484,15 +1497,14 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
                res = sig_ss7_play_tone(p, SIG_SS7_TONE_BUSY);
                break;
        case AST_CONTROL_RINGING:
-               if ((!p->alerting) && p->ss7 && !p->outgoing && (chan->_state != AST_STATE_UP)) {
-                       if (p->ss7->ss7) {
+               if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
+                       p->call_level = SIG_SS7_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);
                        }
                }
@@ -1511,11 +1523,11 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
                                p->rlt = 1;
                }
 
-               if (!p->proceeding && p->ss7 && !p->outgoing) {
-                       if (p->ss7->ss7) {
+               if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING && !p->outgoing) {
+                       p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
+                       if (p->ss7 && p->ss7->ss7) {
                                ss7_grab(p, p->ss7);
                                isup_acm(p->ss7->ss7, p->ss7call);
-                               p->proceeding = 1;
                                ss7_rel(p->ss7);
                        }
                }
@@ -1524,11 +1536,11 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
                break;
        case AST_CONTROL_PROGRESS:
                ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
-               if (!p->progress && p->ss7 && !p->outgoing) {
-                       if (p->ss7->ss7) {
+               if (!p->progress && p->call_level < SIG_SS7_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 */
                                sig_ss7_set_echocanceller(p, 1);
index a4cee52..15b4a2a 100644 (file)
@@ -84,6 +84,20 @@ enum sig_ss7_law {
        SIG_SS7_ALAW
 };
 
+/*! Call establishment life cycle level for simple comparisons. */
+enum sig_ss7_call_level {
+       /*! Call does not exist. */
+       SIG_SS7_CALL_LEVEL_IDLE,
+       /*! Call is present but has no response yet. (SETUP) */
+       SIG_SS7_CALL_LEVEL_SETUP,
+       /*! Call routing is happening. (PROCEEDING) */
+       SIG_SS7_CALL_LEVEL_PROCEEDING,
+       /*! Called party is being alerted of the call. (ALERTING) */
+       SIG_SS7_CALL_LEVEL_ALERTING,
+       /*! Call is connected/answered. (CONNECT) */
+       SIG_SS7_CALL_LEVEL_CONNECT,
+};
+
 struct sig_ss7_linkset;
 
 struct sig_ss7_callback {
@@ -120,6 +134,9 @@ struct sig_ss7_chan {
        /*! \brief Opaque libss7 call control structure */
        struct isup_call *ss7call;
 
+       /*! Call establishment life cycle level for simple comparisons. */
+       enum sig_ss7_call_level call_level;
+
        int channel;                                    /*!< Channel Number */
        int cic;                                                /*!< CIC associated with channel */
        unsigned int dpc;                               /*!< CIC's DPC */
@@ -192,15 +209,8 @@ struct sig_ss7_chan {
        unsigned int inalarm:1;
        /*! TRUE if this channel is being used for an outgoing call. */
        unsigned int outgoing: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 channel is alerting/ringing */
-       unsigned int alerting:1;
        /*! \brief TRUE if the call has already gone/hungup */
        unsigned int alreadyhungup:1;
        /*! \brief XXX BOOLEAN Purpose??? */