Support FXS module Polarity Reversal on remote party Answer and Hangup
authorAlec L Davis <sivad.a@paradise.net.nz>
Thu, 22 Jul 2010 23:14:50 +0000 (23:14 +0000)
committerAlec L Davis <sivad.a@paradise.net.nz>
Thu, 22 Jul 2010 23:14:50 +0000 (23:14 +0000)
FXS lines normally connect to a telephone. However, when FXS lines are routed
to an external PBX or Key System to act as "external" or "CO" lines, it is
extremely difficult, if not impossible for the external PBX to know when
the call has been disconnected without receiving a polarity reversal on the line.

Now using answeronpolarityswitch and hanguponpolarityswitch keywords that
previously were used only for FXO ports, now applies like functionality for
an FXS port, but from the connected equipment's point of view.

(closes issue #17318)
Reported by: armeniki
Patches:
      fxs_linepolarity.diff5.txt uploaded by alecdavis (license 585)
Tested by: alecdavis

Review: https://reviewboard.asterisk.org/r/797/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@278809 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_dahdi.c
channels/sig_analog.c
channels/sig_analog.h
configs/chan_dahdi.conf.sample

index 85855e6..d2a5671 100644 (file)
@@ -2737,6 +2737,52 @@ static void my_set_needringing(void *pvt, int value)
        p->subs[SUB_REAL].needringing = value;
 }
 
+static void my_set_polarity(void *pvt, int value)
+{
+       struct dahdi_pvt *p = pvt;
+
+       if (p->channel == CHAN_PSEUDO) {
+               return;
+       }
+       p->polarity = value;
+       ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETPOLARITY, &value);
+}
+
+static void my_start_polarityswitch(void *pvt)
+{
+       struct dahdi_pvt *p = pvt;
+
+       if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
+               my_set_polarity(pvt, 0);
+       }
+}
+
+static void my_answer_polarityswitch(void *pvt)
+{
+       struct dahdi_pvt *p = pvt;
+
+       if (!p->answeronpolarityswitch) {
+               return;
+       }
+
+       my_set_polarity(pvt, 1);
+}
+
+static void my_hangup_polarityswitch(void *pvt)
+{
+       struct dahdi_pvt *p = pvt;
+
+       if (!p->hanguponpolarityswitch) {
+               return;
+       }
+
+       if (p->answeronpolarityswitch) {
+               my_set_polarity(pvt, 0);
+       } else {
+               my_set_polarity(pvt, 1);
+       }
+}
+
 static int my_start(void *pvt)
 {
        struct dahdi_pvt *p = pvt;
@@ -3454,6 +3500,10 @@ static struct analog_callback dahdi_analog_callbacks =
        .set_pulsedial = my_set_pulsedial,
        .get_orig_dialstring = my_get_orig_dialstring,
        .set_needringing = my_set_needringing,
+       .set_polarity = my_set_polarity,
+       .start_polarityswitch = my_start_polarityswitch,
+       .answer_polarityswitch = my_answer_polarityswitch,
+       .hangup_polarityswitch = my_hangup_polarityswitch,
 };
 
 /*! Round robin search locations. */
index 68677f5..3214681 100644 (file)
@@ -537,6 +537,35 @@ static void analog_set_needringing(struct analog_pvt *p, int value)
        }
 }
 
+#if 0
+static void analog_set_polarity(struct analog_pvt *p, int value)
+{
+       if (p->calls->set_polarity) {
+               return p->calls->set_polarity(p->chan_pvt, value);
+       }
+}
+#endif
+
+static void analog_start_polarityswitch(struct analog_pvt *p)
+{
+       if (p->calls->start_polarityswitch) {
+               return p->calls->start_polarityswitch(p->chan_pvt);
+       }
+}
+static void analog_answer_polarityswitch(struct analog_pvt *p)
+{
+       if (p->calls->answer_polarityswitch) {
+               return p->calls->answer_polarityswitch(p->chan_pvt);
+       }
+}
+
+static void analog_hangup_polarityswitch(struct analog_pvt *p)
+{
+       if (p->calls->hangup_polarityswitch) {
+               return p->calls->hangup_polarityswitch(p->chan_pvt);
+       }
+}
+
 static int analog_dsp_set_digitmode(struct analog_pvt *p, enum analog_dsp_digitmode mode)
 {
        if (p->calls->dsp_set_digitmode) {
@@ -1269,6 +1298,7 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
                case ANALOG_SIG_FXOKS:
                        /* If they're off hook, try playing congestion */
                        if (analog_is_off_hook(p)) {
+                               analog_hangup_polarityswitch(p);
                                analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
                        } else {
                                analog_play_tone(p, ANALOG_SUB_REAL, -1);
@@ -1360,9 +1390,21 @@ int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
                                p->owner = p->subs[ANALOG_SUB_REAL].owner;
                        }
                }
-               if ((p->sig == ANALOG_SIG_FXSLS) || (p->sig == ANALOG_SIG_FXSKS) || (p->sig == ANALOG_SIG_FXSGS)) {
+
+               switch (p->sig) {
+               case ANALOG_SIG_FXSLS:
+               case ANALOG_SIG_FXSKS:
+               case ANALOG_SIG_FXSGS:
                        analog_set_echocanceller(p, 1);
                        analog_train_echocanceller(p);
+                       break;
+               case ANALOG_SIG_FXOLS:
+               case ANALOG_SIG_FXOKS:
+               case ANALOG_SIG_FXOGS:
+                       analog_answer_polarityswitch(p);
+                       break;
+               default:
+                       break;
                }
                break;
        default:
@@ -2524,6 +2566,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                case ANALOG_SIG_FXOLS:
                case ANALOG_SIG_FXOGS:
                case ANALOG_SIG_FXOKS:
+                       analog_start_polarityswitch(p);
                        p->fxsoffhookstate = 0;
                        p->onhooktime = time(NULL);
                        p->msgstate = -1;
@@ -2705,6 +2748,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                                        ast_setstate(ast, AST_STATE_DIALING);
                                } else {
                                        ast_setstate(ast, AST_STATE_UP);
+                                       analog_answer_polarityswitch(p);
                                }
                                return &p->subs[index].f;
                        case AST_STATE_DOWN:
@@ -3443,6 +3487,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
                case ANALOG_SIG_FXOLS:
                case ANALOG_SIG_FXOGS:
                        i->fxsoffhookstate = 0;
+                       analog_start_polarityswitch(i);
                case ANALOG_SIG_FEATD:
                case ANALOG_SIG_FEATDMF:
                case ANALOG_SIG_FEATDMF_TA:
index e7f1ae2..ff62ed5 100644 (file)
@@ -147,6 +147,14 @@ struct analog_callback {
        /*! \brief Set channel off hook */
        int (* const off_hook)(void *pvt);
        void (* const set_needringing)(void *pvt, int value);
+       /*! \brief Set FXS line polarity to 0=IDLE NZ=REVERSED */
+       void (* const set_polarity)(void *pvt, int value);
+       /*! \brief Reset FXS line polarity to IDLE, based on answeronpolarityswitch and hanguponpolarityswitch */
+       void (* const start_polarityswitch)(void *pvt);
+       /*! \brief Switch FXS line polarity, based on answeronpolarityswitch=yes */
+       void (* const answer_polarityswitch)(void *pvt);
+       /*! \brief Switch FXS line polarity, based on answeronpolarityswitch and hanguponpolarityswitch */
+       void (* const hangup_polarityswitch)(void *pvt);
        /* We're assuming that we're going to only wink on ANALOG_SUB_REAL - even though in the code there's an argument to the index
         * function */
        int (* const wink)(void *pvt, enum analog_sub sub);
index 0bc4ac8..5679432 100644 (file)
@@ -820,14 +820,22 @@ pickupgroup=1
 ; useful to use the ztmonitor utility to record the audio that main/dsp.c
 ; is receiving after the caller hangs up.
 ;
-; Use a polarity reversal to mark when a outgoing call is answered by the
-; remote party.
+; For FXS (FXO signalled) ports
+;   switch the line polarity to signal the connected PBX that an outgoing
+;   call was answered by the remote party.
+; For FXO (FXS signalled) ports
+;   watch for a polarity reversal to mark when a outgoing call is
+;   answered by the remote party.
 ;
 ;answeronpolarityswitch=yes
 ;
-; In some countries, a polarity reversal is used to signal the disconnect of a
-; phone line.  If the hanguponpolarityswitch option is selected, the call will
-; be considered "hung up" on a polarity reversal.
+; For FXS (FXO signalled) ports
+;   switch the line polarity to signal the connected PBX that the current
+;   call was "hung up" by the remote party
+; For FXO (FXS signalled) ports
+;   In some countries, a polarity reversal is used to signal the disconnect of a
+;   phone line.  If the hanguponpolarityswitch option is selected, the call will
+;   be considered "hung up" on a polarity reversal.
 ;
 ;hanguponpolarityswitch=yes
 ;