<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/19748">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">sig_analog: Add Call Waiting Deluxe support.<br><br>Adds support for Call Waiting Deluxe options to enhance<br>the current call waiting feature.<br><br>As part of this change, a mechanism is also added that<br>allows a channel driver to queue an audio file for Dial()<br>to play, which is necessary for the announcement function.<br><br>ASTERISK-30373 #close<br><br>Change-Id: Ifd222b5f757c8dd382158a89c6b6ad9a82b07421<br>---<br>M apps/app_dial.c<br>M channels/chan_dahdi.c<br>M channels/chan_dahdi.h<br>M channels/sig_analog.c<br>M channels/sig_analog.h<br>M configs/samples/chan_dahdi.conf.sample<br>A doc/CHANGES-staging/callwaitingdeluxe.txt<br>M include/asterisk/channel.h<br>M main/channel_internal_api.c<br>9 files changed, 309 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/48/19748/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_dial.c b/apps/app_dial.c</span><br><span>index c389225..c09c61d 100644</span><br><span>--- a/apps/app_dial.c</span><br><span>+++ b/apps/app_dial.c</span><br><span>@@ -1417,6 +1417,10 @@</span><br><span>                                  }</span><br><span>                            }</span><br><span>                            continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else if (!ast_strlen_zero(ast_channel_dial_announcement(c))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_verb(3, "Playing audio file %s on %s\n", ast_channel_dial_announcement(c), ast_channel_name(in));</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_streamfile(in, ast_channel_dial_announcement(c), ast_channel_language(in));</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_channel_dial_announcement_set(c, ""); /* Don't set to NULL, that will cause a crash */</span><br><span>                     }</span><br><span>                    f = ast_read(winner);</span><br><span>                        if (!f) {</span><br><span>diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c</span><br><span>index 5607eb0..ca75633 100644</span><br><span>--- a/channels/chan_dahdi.c</span><br><span>+++ b/channels/chan_dahdi.c</span><br><span>@@ -9071,6 +9071,26 @@</span><br><span>          return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (p->sig == SIG_FXOLS || p->sig == SIG_FXOKS || p->sig == SIG_FXOGS) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct analog_pvt *analog_p = p->sig_pvt;</span><br><span style="color: hsl(120, 100%, 40%);">+          if (analog_p->callwaitdeluxepending) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     unsigned int mssinceflash = ast_tvdiff_ms(ast_tvnow(), analog_p->flashtime);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (mssinceflash >= 1000) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                /* Timer expired: the user hasn't yet selected an option. Take the default action and get on with it. */</span><br><span style="color: hsl(120, 100%, 40%);">+                          /* Note: If in the future Advanced Call Waiting Deluxe (*76) is supported, then as part of the</span><br><span style="color: hsl(120, 100%, 40%);">+                                 * dialing code, we'll need to automatically invoke the preselected behavior about 2-3 seconds after</span><br><span style="color: hsl(120, 100%, 40%);">+                               * the call waiting begins (this allows for the SAS, CAS, and CWCID spill to be sent first).</span><br><span style="color: hsl(120, 100%, 40%);">+                           */</span><br><span style="color: hsl(120, 100%, 40%);">+                           analog_p->callwaitdeluxepending = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                               analog_callwaiting_deluxe(analog_p, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_mutex_unlock(&p->lock);</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* The user shouldn't hear anything after hook flashing, until a decision is made, by the user or when the timer expires. */</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_debug(5, "Dropping frame since Call Waiting Deluxe pending on %s\n", ast_channel_name(ast));</span><br><span style="color: hsl(120, 100%, 40%);">+                    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  if (p->dialing) {</span><br><span>                 ast_mutex_unlock(&p->lock);</span><br><span>           ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",</span><br><span>@@ -12805,6 +12825,7 @@</span><br><span> </span><br><span>                tmp->usedistinctiveringdetection = usedistinctiveringdetection;</span><br><span>           tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;</span><br><span style="color: hsl(120, 100%, 40%);">+              tmp->callwaitingdeluxe = conf->chan.callwaitingdeluxe; /* Not used in DAHDI pvt, only analog pvt */</span><br><span>            tmp->threewaycalling = conf->chan.threewaycalling;</span><br><span>             tmp->adsi = conf->chan.adsi;</span><br><span>           tmp->use_smdi = conf->chan.use_smdi;</span><br><span>@@ -13136,6 +13157,7 @@</span><br><span>                                         break;</span><br><span>                               }</span><br><span>                            analog_p->callwaitingcallerid = conf->chan.callwaitingcallerid;</span><br><span style="color: hsl(120, 100%, 40%);">+                         analog_p->callwaitingdeluxe = conf->chan.callwaitingdeluxe;</span><br><span>                            analog_p->ringt = conf->chan.ringt;</span><br><span>                            analog_p->ringt_base = ringt_base;</span><br><span>                                analog_p->onhooktime = time(NULL);</span><br><span>@@ -18260,6 +18282,8 @@</span><br><span>                      confp->chan.callwaiting = ast_true(v->value);</span><br><span>          } else if (!strcasecmp(v->name, "callwaitingcallerid")) {</span><br><span>                       confp->chan.callwaitingcallerid = ast_true(v->value);</span><br><span style="color: hsl(120, 100%, 40%);">+           } else if (!strcasecmp(v->name, "callwaitingdeluxe")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  confp->chan.callwaitingdeluxe = ast_true(v->value);</span><br><span>            } else if (!strcasecmp(v->name, "context")) {</span><br><span>                   ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));</span><br><span>                } else if (!strcasecmp(v->name, "language")) {</span><br><span>diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h</span><br><span>index de813f2..b7e222c 100644</span><br><span>--- a/channels/chan_dahdi.h</span><br><span>+++ b/channels/chan_dahdi.h</span><br><span>@@ -222,6 +222,10 @@</span><br><span>   */</span><br><span>  unsigned int callwaitingcallerid:1;</span><br><span>  /*!</span><br><span style="color: hsl(120, 100%, 40%);">+    * \brief TRUE if Call Waiting Deluxe options should be available</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int callwaitingdeluxe:1;</span><br><span style="color: hsl(120, 100%, 40%);">+     /*!</span><br><span>   * \brief TRUE if support for call forwarding enabled.</span><br><span>        * Dial *72 to enable call forwarding.</span><br><span>        * Dial *73 to disable call forwarding.</span><br><span>diff --git a/channels/sig_analog.c b/channels/sig_analog.c</span><br><span>index b694a96..4893ea5 100644</span><br><span>--- a/channels/sig_analog.c</span><br><span>+++ b/channels/sig_analog.c</span><br><span>@@ -1567,6 +1567,162 @@</span><br><span>   }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+enum callwaiting_deluxe_option {</span><br><span style="color: hsl(120, 100%, 40%);">+  CWD_CONFERENCE = '3',</span><br><span style="color: hsl(120, 100%, 40%);">+ CWD_HOLD = '6',</span><br><span style="color: hsl(120, 100%, 40%);">+       CWD_DROP = '7',</span><br><span style="color: hsl(120, 100%, 40%);">+       CWD_ANNOUNCEMENT = '8',</span><br><span style="color: hsl(120, 100%, 40%);">+       CWD_FORWARD = '9',</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *callwaiting_deluxe_optname(int option)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (option) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case CWD_CONFERENCE:</span><br><span style="color: hsl(120, 100%, 40%);">+          return "CONFERENCE";</span><br><span style="color: hsl(120, 100%, 40%);">+        case CWD_HOLD:</span><br><span style="color: hsl(120, 100%, 40%);">+                return "HOLD";</span><br><span style="color: hsl(120, 100%, 40%);">+      case CWD_DROP:</span><br><span style="color: hsl(120, 100%, 40%);">+                return "DROP";</span><br><span style="color: hsl(120, 100%, 40%);">+      case CWD_ANNOUNCEMENT:</span><br><span style="color: hsl(120, 100%, 40%);">+                return "ANNOUNCEMENT";</span><br><span style="color: hsl(120, 100%, 40%);">+      case CWD_FORWARD:</span><br><span style="color: hsl(120, 100%, 40%);">+             return "FORWARD";</span><br><span style="color: hsl(120, 100%, 40%);">+   default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return "DEFAULT";</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int analog_callwaiting_deluxe(struct analog_pvt *p, int option)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *announce_var;</span><br><span style="color: hsl(120, 100%, 40%);">+     char announcement[PATH_MAX];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_debug(1, "Handling Call Waiting on channel %d with option %c: treatment %s\n", p->channel, option, callwaiting_deluxe_optname(option));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!p->subs[ANALOG_SUB_CALLWAIT].owner) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* This can happen if the caller hook flashes and the call waiting hangs up before the CWD timer expires (1 second) */</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_debug(1, "Call waiting call disappeared before it could be handled?\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   analog_lock_sub_owner(p, ANALOG_SUB_CALLWAIT);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!p->subs[ANALOG_SUB_CALLWAIT].owner) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_WARNING, "Whoa, the call-waiting call disappeared.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Note that when p->callwaitdeluxepending, dahdi_write will drop incoming frames to the channel,</span><br><span style="color: hsl(120, 100%, 40%);">+   * since the user shouldn't hear anything after flashing until either a DTMF has been received</span><br><span style="color: hsl(120, 100%, 40%);">+     * or it's been a second and the decision is made automatically. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (option) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case CWD_CONFERENCE:</span><br><span style="color: hsl(120, 100%, 40%);">+          /* We should never have a call waiting if we have a 3-way anyways, but check just in case,</span><br><span style="color: hsl(120, 100%, 40%);">+             * there better be no existing SUB_THREEWAY since we're going to make one (and then swap the call wait to it) */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (p->subs[ANALOG_SUB_THREEWAY].owner) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_channel_unlock(p->subs[ANALOG_SUB_CALLWAIT].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_log(LOG_WARNING, "Already have a 3-way call on channel %d, can't conference!\n", p->channel);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* To conference the incoming call, swap it from SUB_CALLWAIT to SUB_THREEWAY,</span><br><span style="color: hsl(120, 100%, 40%);">+                 * and then the existing 3-way logic will ensure that flashing again will drop the call waiting */</span><br><span style="color: hsl(120, 100%, 40%);">+            analog_alloc_sub(p, ANALOG_SUB_THREEWAY);</span><br><span style="color: hsl(120, 100%, 40%);">+             analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_CALLWAIT);</span><br><span style="color: hsl(120, 100%, 40%);">+                analog_unalloc_sub(p, ANALOG_SUB_CALLWAIT);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_verb(3, "Building conference call with %s and %s\n", ast_channel_name(p->subs[ANALOG_SUB_THREEWAY].owner), ast_channel_name(p->subs[ANALOG_SUB_REAL].owner));</span><br><span style="color: hsl(120, 100%, 40%);">+             analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+             analog_set_inthreeway(p, ANALOG_SUB_REAL, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               if (ast_channel_state(p->subs[ANALOG_SUB_THREEWAY].owner) == AST_STATE_RINGING) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_setstate(p->subs[ANALOG_SUB_THREEWAY].owner, AST_STATE_UP);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_queue_control(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_ANSWER);</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* Stop the ringing on the call wait channel (yeah, apparently this is how it's done) */</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_queue_hold(p->subs[ANALOG_SUB_THREEWAY].owner, p->mohsuggest);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_queue_unhold(p->subs[ANALOG_SUB_THREEWAY].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             analog_stop_callwait(p);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner); /* Unlock what was originally SUB_CALLWAIT */</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CWD_ANNOUNCEMENT:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* We can't just call ast_streamfile here, this thread isn't responsible for media on the call waiting channel.</span><br><span style="color: hsl(120, 100%, 40%);">+                * What we need is something like ast_channel_call_forward_set, that sets a string field that</span><br><span style="color: hsl(120, 100%, 40%);">+          * app_dial will see and do something with. Et voila, ast_channel_dial_announcement_set.</span><br><span style="color: hsl(120, 100%, 40%);">+               * This allows us to tell app_dial to play an audio file, and it will actually handle that.</span><br><span style="color: hsl(120, 100%, 40%);">+            * It's a lot easier than other ways of trying to send early media to the channel</span><br><span style="color: hsl(120, 100%, 40%);">+          * (such as every call from the core to dahdi_read, sending the channel one frame of the audio file, etc.)</span><br><span style="color: hsl(120, 100%, 40%);">+             */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* There's not a particularly good stock audio prompt to use here. The Pat Fleet library has some better</span><br><span style="color: hsl(120, 100%, 40%);">+           * ones but we want one that is also in the default Allison Smith library. "One moment please" works okay.</span><br><span style="color: hsl(120, 100%, 40%);">+           * Check if a variable containing the prompt to use was specified on the call waiting channel, and</span><br><span style="color: hsl(120, 100%, 40%);">+             * fall back to a reasonable default if not. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* The SUB_CALLWAIT channel is already locked here, no need to lock and unlock to get the variable. */</span><br><span style="color: hsl(120, 100%, 40%);">+                announce_var = pbx_builtin_getvar_helper(p->subs[ANALOG_SUB_CALLWAIT].owner, "CALLWAITDELUXEANNOUNCEMENT");</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_copy_string(announcement, S_OR(announce_var, "one-moment-please"), sizeof(announcement));</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_debug(2, "Call Waiting Deluxe announcement for %s: %s\n", ast_channel_name(p->subs[ANALOG_SUB_CALLWAIT].owner), announcement);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_channel_dial_announcement_set(p->subs[ANALOG_SUB_CALLWAIT].owner, announcement);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_channel_unlock(p->subs[ANALOG_SUB_CALLWAIT].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+            /* Unlike all the other options, the call waiting is still active with this option,</span><br><span style="color: hsl(120, 100%, 40%);">+            * so we don't call analog_stop_callwait(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                * The call waiting will continue to be here, and at some later point the user can flash again and choose a finalizing option</span><br><span style="color: hsl(120, 100%, 40%);">+          * (or even queue the announcement again... and again... and again...)</span><br><span style="color: hsl(120, 100%, 40%);">+                 */</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CWD_FORWARD:</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Go away, call waiting, call again some other day... */</span><br><span style="color: hsl(120, 100%, 40%);">+             analog_stop_callwait(p);</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Can't use p->call_forward exten because that's for *72 forwarding, and sig_analog doesn't</span><br><span style="color: hsl(120, 100%, 40%);">+            * have a Busy/Don't Answer call forwarding exten internally, so let the dialplan deal with it.</span><br><span style="color: hsl(120, 100%, 40%);">+            * by sending the call to the 'f' extension.</span><br><span style="color: hsl(120, 100%, 40%);">+           */</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_channel_call_forward_set(p->subs[ANALOG_SUB_CALLWAIT].owner, "f");</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_channel_unlock(p->subs[ANALOG_SUB_CALLWAIT].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+            /* app_dial already has a verbose message for forwarding, so we don't really need one here also since that does the job */</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CWD_DROP:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Fall through: logic is identical to hold, except we drop the original call right after we swap. */</span><br><span style="color: hsl(120, 100%, 40%);">+ case CWD_HOLD:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Fall through: this option is simply the default */</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Swap to call-wait, same as with the non-deluxe call waiting handling. */</span><br><span style="color: hsl(120, 100%, 40%);">+           analog_swap_subs(p, ANALOG_SUB_REAL, ANALOG_SUB_CALLWAIT);</span><br><span style="color: hsl(120, 100%, 40%);">+            analog_play_tone(p, ANALOG_SUB_REAL, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+             analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_debug(1, "Making %s the new owner\n", ast_channel_name(p->owner));</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ast_channel_state(p->subs[ANALOG_SUB_REAL].owner) == AST_STATE_RINGING) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_setstate(p->subs[ANALOG_SUB_REAL].owner, AST_STATE_UP);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             analog_stop_callwait(p);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            if (option == CWD_DROP) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* Disconnect the previous call (the original call is now the SUB_CALLWAIT since we swapped above) */</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_queue_hangup(p->subs[ANALOG_SUB_CALLWAIT].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_verb(3, "Dropping original call and swapping to call waiting on %s\n", ast_channel_name(p->subs[ANALOG_SUB_REAL].owner));</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* Start music on hold if appropriate */</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_queue_hold(p->subs[ANALOG_SUB_CALLWAIT].owner, p->mohsuggest);</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_verb(3, "Holding original call and swapping to call waiting on %s\n", ast_channel_name(p->subs[ANALOG_SUB_REAL].owner));</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Stop ringing on the incoming call */</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_queue_hold(p->subs[ANALOG_SUB_REAL].owner, p->mohsuggest);</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Unlock the call-waiting call that we swapped to real-call. */</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_channel_unlock(p->subs[ANALOG_SUB_REAL].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     analog_update_conf(p);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)</span><br><span> {</span><br><span>  struct ast_frame *f = *dest;</span><br><span>@@ -1604,6 +1760,50 @@</span><br><span>                p->subs[idx].f.frametype = AST_FRAME_NULL;</span><br><span>                p->subs[idx].f.subclass.integer = 0;</span><br><span>              *dest = &p->subs[idx].f;</span><br><span style="color: hsl(120, 100%, 40%);">+       }  else if (p->callwaitdeluxepending) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (f->frametype == AST_FRAME_DTMF_END) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  unsigned int mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);</span><br><span style="color: hsl(120, 100%, 40%);">+                      p->callwaitdeluxepending = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* This is the case where a user explicitly took action (made a decision)</span><br><span style="color: hsl(120, 100%, 40%);">+                      * for Call Waiting Deluxe.</span><br><span style="color: hsl(120, 100%, 40%);">+                    * Because we already handled the hook flash, if the user doesn't do</span><br><span style="color: hsl(120, 100%, 40%);">+                       * anything within a second, then we still need to eventually take</span><br><span style="color: hsl(120, 100%, 40%);">+                     * the default action (swap) for the call waiting.</span><br><span style="color: hsl(120, 100%, 40%);">+                     *</span><br><span style="color: hsl(120, 100%, 40%);">+                     * dahdi_write will also drop audio if callwaitdeluxepending is set HIGH,</span><br><span style="color: hsl(120, 100%, 40%);">+                      * and also check if flashtime hits 1000, in which case it will set the flag LOW and then take the</span><br><span style="color: hsl(120, 100%, 40%);">+                     * default action, e.g. analog_callwaiting_deluxe(p, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                       */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* Slightly less than 1000, so there's no chance of a race condition</span><br><span style="color: hsl(120, 100%, 40%);">+                       * between do_monitor when it sees flashtime hitting 1000 and us. */</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (mssinceflash > 990) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          /* This was more than a second ago, clear the flag and process normally. */</span><br><span style="color: hsl(120, 100%, 40%);">+                           /* Because another thread has to monitor channels with pending CWDs,</span><br><span style="color: hsl(120, 100%, 40%);">+                           * in theory, we shouldn't need to check this here. */</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_debug(1, "It's been %u ms since the last flash, this is not a Call Waiting Deluxe DTMF\n", mssinceflash);</span><br><span style="color: hsl(120, 100%, 40%);">+                           analog_cb_handle_dtmf(p, ast, idx, dest);</span><br><span style="color: hsl(120, 100%, 40%);">+                             return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* Okay, actually do something now. */</span><br><span style="color: hsl(120, 100%, 40%);">+                        switch (f->subclass.integer) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     case CWD_CONFERENCE:</span><br><span style="color: hsl(120, 100%, 40%);">+                  case CWD_HOLD:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case CWD_DROP:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case CWD_ANNOUNCEMENT:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case CWD_FORWARD:</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_debug(1, "Got some DTMF, but it's for Call Waiting Deluxe: %c\n", f->subclass.integer);</span><br><span style="color: hsl(120, 100%, 40%);">+                          analog_callwaiting_deluxe(p, f->subclass.integer);</span><br><span style="color: hsl(120, 100%, 40%);">+                         break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        default:</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_log(LOG_WARNING, "Invalid Call Waiting Deluxe option (%c), using default\n", f->subclass.integer);</span><br><span style="color: hsl(120, 100%, 40%);">+                           analog_callwaiting_deluxe(p, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             p->subs[idx].f.frametype = AST_FRAME_NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         p->subs[idx].f.subclass.integer = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               *dest = &p->subs[idx].f;</span><br><span>      } else {</span><br><span>             analog_cb_handle_dtmf(p, ast, idx, dest);</span><br><span>    }</span><br><span>@@ -2892,6 +3092,7 @@</span><br><span>            analog_get_and_handle_alarms(p);</span><br><span>             cause_code->ast_cause = AST_CAUSE_NETWORK_OUT_OF_ORDER;</span><br><span>   case ANALOG_EVENT_ONHOOK:</span><br><span style="color: hsl(120, 100%, 40%);">+             p->callwaitdeluxepending = 0;</span><br><span>             ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);</span><br><span>              ast_channel_hangupcause_hash_set(ast, cause_code, data_size);</span><br><span>                switch (p->sig) {</span><br><span>@@ -3207,6 +3408,7 @@</span><br><span>                 }</span><br><span>            /* Remember last time we got a flash-hook */</span><br><span>                 gettimeofday(&p->flashtime, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+             p->callwaitdeluxepending = 0;</span><br><span>             switch (mysig) {</span><br><span>             case ANALOG_SIG_FXOLS:</span><br><span>               case ANALOG_SIG_FXOGS:</span><br><span>@@ -3235,6 +3437,20 @@</span><br><span>                                      goto winkflashdone;</span><br><span>                          }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                         /* If line has Call Waiting Deluxe, see what the user wants to do.</span><br><span style="color: hsl(120, 100%, 40%);">+                             * Only do this if this is an as yet unanswered call waiting, not an existing, answered SUB_CALLWAIT. */</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (ast_channel_state(p->subs[ANALOG_SUB_CALLWAIT].owner) == AST_STATE_RINGING) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                  if (p->callwaitingdeluxe) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                /* This thread cannot block, so just set the flag that we need</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 * to wait for a Call Waiting Deluxe option (or let it time out),</span><br><span style="color: hsl(120, 100%, 40%);">+                                              * and then we're done for now. */</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ast_channel_unlock(p->subs[ANALOG_SUB_CALLWAIT].owner);</span><br><span style="color: hsl(120, 100%, 40%);">+                                            p->callwaitdeluxepending = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                                              ast_debug(1, "Deferring call waiting manipulation, waiting for Call Waiting Deluxe option from user\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                                            goto winkflashdone;</span><br><span style="color: hsl(120, 100%, 40%);">+                                   }</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                          /* Swap to call-wait */</span><br><span>                              analog_swap_subs(p, ANALOG_SUB_REAL, ANALOG_SUB_CALLWAIT);</span><br><span>                           analog_play_tone(p, ANALOG_SUB_REAL, -1);</span><br><span>@@ -3768,6 +3984,7 @@</span><br><span>            case ANALOG_SIG_FXOKS:</span><br><span>                       res = analog_off_hook(i);</span><br><span>                    i->fxsoffhookstate = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    i->callwaitdeluxepending = 0;</span><br><span>                     if (res && (errno == EBUSY)) {</span><br><span>                               break;</span><br><span>                       }</span><br><span>diff --git a/channels/sig_analog.h b/channels/sig_analog.h</span><br><span>index 7e9acda..6dfd9df 100644</span><br><span>--- a/channels/sig_analog.h</span><br><span>+++ b/channels/sig_analog.h</span><br><span>@@ -320,6 +320,7 @@</span><br><span> </span><br><span>         /* XXX: All variables after this are internal */</span><br><span>     unsigned int callwaiting:1;             /*!< TRUE if call waiting is enabled. (Active option) */</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int callwaitingdeluxe:1;       /*!< TRUE if Call Waiting Deluxe options are available */</span><br><span>         unsigned int dialednone:1;</span><br><span>   unsigned int dialing:1;                 /*!< TRUE if in the process of dialing digits or sending something */</span><br><span>     unsigned int dnd:1;                             /*!< TRUE if Do-Not-Disturb is enabled. */</span><br><span>@@ -335,6 +336,11 @@</span><br><span>          */</span><br><span>  unsigned int callwaitcas:1;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       /*!</span><br><span style="color: hsl(120, 100%, 40%);">+    * \brief TRUE if a Call Waiting Deluxe action is currently pending.</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int callwaitdeluxepending:1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      char callwait_num[AST_MAX_EXTENSION];</span><br><span>        char callwait_name[AST_MAX_EXTENSION];</span><br><span>       char lastcid_num[AST_MAX_EXTENSION];</span><br><span>@@ -382,6 +388,8 @@</span><br><span> </span><br><span> int analog_config_complete(struct analog_pvt *p);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int analog_callwaiting_deluxe(struct analog_pvt *p, int option);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub index, struct ast_frame **dest);</span><br><span> </span><br><span> enum analog_cid_start analog_str_to_cidstart(const char *value);</span><br><span>diff --git a/configs/samples/chan_dahdi.conf.sample b/configs/samples/chan_dahdi.conf.sample</span><br><span>index 6b29549..4ddc901 100644</span><br><span>--- a/configs/samples/chan_dahdi.conf.sample</span><br><span>+++ b/configs/samples/chan_dahdi.conf.sample</span><br><span>@@ -676,6 +676,30 @@</span><br><span> ;</span><br><span> callwaiting=yes</span><br><span> ;</span><br><span style="color: hsl(120, 100%, 40%);">+; Whether or not to allow for Call Waiting Deluxe options to be used.</span><br><span style="color: hsl(120, 100%, 40%);">+; The Call Waiting Deluxe options are:</span><br><span style="color: hsl(120, 100%, 40%);">+;  3: Conference - conference the call waiting call with the existing call</span><br><span style="color: hsl(120, 100%, 40%);">+;  6: Hold (default) - hold the current call and switch to the new one</span><br><span style="color: hsl(120, 100%, 40%);">+;  7: Drop - drop current call and switch to new (same as hanging up and answering)</span><br><span style="color: hsl(120, 100%, 40%);">+;  8: Announcement - play announcement to call waiting caller telling them to hold</span><br><span style="color: hsl(120, 100%, 40%);">+;  9: Forward - forward the call waiting call to a preconfigured extension</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; Some CPE (Caller ID units, screenphones, etc.) have dedicated buttons for utilizing</span><br><span style="color: hsl(120, 100%, 40%);">+; the Call Waiting Deluxe features, but these can also be used from any phone manually</span><br><span style="color: hsl(120, 100%, 40%);">+; by simply hook flashing as usual and then quickly dialing the appropriate DTMF digit.</span><br><span style="color: hsl(120, 100%, 40%);">+; If not digit is received within 1 second, the default action is assumed,</span><br><span style="color: hsl(120, 100%, 40%);">+; as if Call Waiting Deluxe was not used.</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; The following extensions are also available in the dialplan to utilize this functionality:</span><br><span style="color: hsl(120, 100%, 40%);">+; - The CALLWAITDELUXEANNOUNCEMENT variable can be set on the incoming channel to control the</span><br><span style="color: hsl(120, 100%, 40%);">+;   announcement prompt played to the call waiting caller. Default is "one-moment-please".</span><br><span style="color: hsl(120, 100%, 40%);">+; - If the forward option is used, the call waiting channel will be forwarded to the 'f' extension</span><br><span style="color: hsl(120, 100%, 40%);">+;   in the channel's configured context. You can then use any dialplan mechanism to route the call.</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; Default is 'no'.</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+;callwaitingdeluxe=yes</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span> ; Configure the number of outstanding call waiting calls for internal ISDN</span><br><span> ; endpoints before bouncing the calls as busy.  This option is equivalent to</span><br><span> ; the callwaiting option for analog ports.</span><br><span>diff --git a/doc/CHANGES-staging/callwaitingdeluxe.txt b/doc/CHANGES-staging/callwaitingdeluxe.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..dd81a94</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/callwaitingdeluxe.txt</span><br><span>@@ -0,0 +1,5 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: sig_analog</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Call Waiting Deluxe options are now supported</span><br><span style="color: hsl(120, 100%, 40%);">+for FXS channels. Refer to the sample config</span><br><span style="color: hsl(120, 100%, 40%);">+for more information about these options.</span><br><span>diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h</span><br><span>index e5613df..c1c8e20 100644</span><br><span>--- a/include/asterisk/channel.h</span><br><span>+++ b/include/asterisk/channel.h</span><br><span>@@ -4140,6 +4140,7 @@</span><br><span> DECLARE_STRINGFIELD_SETTERS_FOR(parkinglot);</span><br><span> DECLARE_STRINGFIELD_SETTERS_FOR(hangupsource);</span><br><span> DECLARE_STRINGFIELD_SETTERS_FOR(dialcontext);</span><br><span style="color: hsl(120, 100%, 40%);">+DECLARE_STRINGFIELD_SETTERS_FOR(dial_announcement);</span><br><span> </span><br><span> const char *ast_channel_name(const struct ast_channel *chan);</span><br><span> const char *ast_channel_language(const struct ast_channel *chan);</span><br><span>@@ -4154,6 +4155,7 @@</span><br><span> const char *ast_channel_parkinglot(const struct ast_channel *chan);</span><br><span> const char *ast_channel_hangupsource(const struct ast_channel *chan);</span><br><span> const char *ast_channel_dialcontext(const struct ast_channel *chan);</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_channel_dial_announcement(const struct ast_channel *chan);</span><br><span> </span><br><span> const char *ast_channel_appl(const struct ast_channel *chan);</span><br><span> void ast_channel_appl_set(struct ast_channel *chan, const char *value);</span><br><span>diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c</span><br><span>index bc0fb4c..d52c84a 100644</span><br><span>--- a/main/channel_internal_api.c</span><br><span>+++ b/main/channel_internal_api.c</span><br><span>@@ -110,6 +110,7 @@</span><br><span>              AST_STRING_FIELD(parkinglot);   /*! Default parking lot, if empty, default parking lot  */</span><br><span>           AST_STRING_FIELD(hangupsource); /*! Who is responsible for hanging up this channel */</span><br><span>                AST_STRING_FIELD(dialcontext);  /*!< Dial: Extension context that we were called from */</span><br><span style="color: hsl(120, 100%, 40%);">+           AST_STRING_FIELD(dial_announcement); /*!< Audio file to play if asked to dial on this interface */</span><br><span>        );</span><br><span> </span><br><span>       struct ast_channel_id uniqueid;         /*!< Unique Channel Identifier - can be specified on creation */</span><br><span>@@ -286,6 +287,7 @@</span><br><span> DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot, 0);</span><br><span> DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(hangupsource, 0, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP);</span><br><span> DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+DEFINE_STRINGFIELD_SETTERS_FOR(dial_announcement, 0);</span><br><span> </span><br><span> #define DEFINE_STRINGFIELD_GETTER_FOR(field) const char *ast_channel_##field(const struct ast_channel *chan) \</span><br><span> { \</span><br><span>@@ -303,6 +305,7 @@</span><br><span> DEFINE_STRINGFIELD_GETTER_FOR(parkinglot);</span><br><span> DEFINE_STRINGFIELD_GETTER_FOR(hangupsource);</span><br><span> DEFINE_STRINGFIELD_GETTER_FOR(dialcontext);</span><br><span style="color: hsl(120, 100%, 40%);">+DEFINE_STRINGFIELD_GETTER_FOR(dial_announcement);</span><br><span> </span><br><span> const char *ast_channel_uniqueid(const struct ast_channel *chan)</span><br><span> {</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/19748">change 19748</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/19748"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ifd222b5f757c8dd382158a89c6b6ad9a82b07421 </div>
<div style="display:none"> Gerrit-Change-Number: 19748 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: N A <asterisk@phreaknet.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>