]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Add HANGUPCAUSE hash support for analog and PRI DAHDI subtechs
authorKinsey Moore <kmoore@digium.com>
Fri, 22 Jun 2012 15:10:38 +0000 (15:10 +0000)
committerKinsey Moore <kmoore@digium.com>
Fri, 22 Jun 2012 15:10:38 +0000 (15:10 +0000)
This is part of the DAHDI support for the Asterisk 11 "Who Hung Up?"
project and covers the implementation for the technologies implemented
in sig_analog.c and sig_pri.c. Tested on a local machine to verify
protocol and cause information is available.

Review: https://reviewboard.asterisk.org/r/1953/
(issue SWP-4222)

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

channels/sig_analog.c
channels/sig_pri.c

index 149a773e15bd62b085b3f26a0a63cf117507546d..03c799e0f1d8f1f961395b67d56c8c76ad525aac 100644 (file)
@@ -2663,6 +2663,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
        pthread_t threadid;
        struct ast_channel *chan;
        struct ast_frame *f;
+       struct ast_control_pvt_cause_code *cause_code;
+       int data_size = sizeof(*cause_code);
+       char *subclass = NULL;
 
        ast_debug(1, "%s %d\n", __FUNCTION__, p->channel);
 
@@ -2693,7 +2696,29 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 
        ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", analog_event2str(res), res, p->channel, idx);
 
+       /* add length of "ANALOG " */
+       data_size += 7;
+
        if (res & (ANALOG_EVENT_PULSEDIGIT | ANALOG_EVENT_DTMFUP)) {
+               /* add length of "ANALOG_EVENT_" */
+               data_size += 13;
+               if (res & ANALOG_EVENT_PULSEDIGIT) {
+                       /* add length of "PULSEDIGIT" */
+                       data_size += 10;
+               } else {
+                       /* add length of "DTMFUP" */
+                       data_size += 6;
+               }
+
+               /* add length of " (c)" */
+               data_size += 4;
+
+               cause_code = alloca(data_size);
+               ast_copy_string(cause_code->chan_name, ast_channel_name(ast), AST_CHANNEL_NAME);
+               snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "ANALOG ANALOG_EVENT_%s (%c)",
+                       (res & ANALOG_EVENT_DTMFUP) ? "DTMFUP" : "PULSEDIGIT", res & 0xff);
+               ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
+
                analog_set_pulsedial(p, (res & ANALOG_EVENT_PULSEDIGIT) ? 1 : 0);
                ast_debug(1, "Detected %sdigit '%c'\n", (res & ANALOG_EVENT_PULSEDIGIT) ? "pulse ": "", res & 0xff);
                analog_confmute(p, 0);
@@ -2704,6 +2729,14 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
        }
 
        if (res & ANALOG_EVENT_DTMFDOWN) {
+               /* add length of "ANALOG_EVENT_DTMFDOWN (c)" */
+               data_size += 25;
+
+               cause_code = alloca(data_size);
+               ast_copy_string(cause_code->chan_name, ast_channel_name(ast), AST_CHANNEL_NAME);
+               snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "ANALOG ANALOG_EVENT_DTMFDOWN (%c)", res & 0xff);
+               ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
+
                ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
                /* Mute conference */
                analog_confmute(p, 1);
@@ -2713,6 +2746,13 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                return f;
        }
 
+       subclass = analog_event2str(res);
+       data_size += strlen(subclass);
+       cause_code = alloca(data_size);
+       ast_copy_string(cause_code->chan_name, ast_channel_name(ast), AST_CHANNEL_NAME);
+       snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "ANALOG %s", subclass);
+       ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
+
        switch (res) {
        case ANALOG_EVENT_EC_DISABLED:
                ast_verb(3, "Channel %d echo canceler disabled due to CED detection\n", p->channel);
index 93b9b4b8b908433c41268b5fd1e5423f404d5f83..ead02f5872e50c862a64a6c0051853c84aae9dd0 100644 (file)
@@ -1259,6 +1259,37 @@ static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclas
        pri_queue_frame(pri, chanpos, &f);
 }
 
+/*!
+ * \internal
+ * \brief Queue a PVT_CAUSE_CODE frame onto the owner channel.
+ * \since 11
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ * \param cause String describing the cause to be placed into the frame.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void pri_queue_pvt_cause_data(struct sig_pri_span *pri, int chanpos, const char *cause)
+{
+       struct ast_channel *chan;
+       struct ast_control_pvt_cause_code *cause_code;
+
+       sig_pri_lock_owner(pri, chanpos);
+       chan = pri->pvts[chanpos]->owner;
+       if (chan) {
+               int datalen = sizeof(*cause_code) + strlen(cause);
+               cause_code = alloca(datalen);
+               ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
+               ast_copy_string(cause_code->code, cause, datalen + 1 - sizeof(*cause_code));
+               ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
+               ast_channel_unlock(chan);
+       }
+}
+
 /*!
  * \internal
  * \brief Find the channel associated with the libpri call.
@@ -5440,7 +5471,6 @@ static void *pri_dchannel(void *vpri)
        pri_event *e;
        struct pollfd fds[SIG_PRI_NUM_DCHANS];
        int res;
-       int chanpos = 0;
        int x;
        int law;
        struct ast_channel *c;
@@ -5648,6 +5678,9 @@ static void *pri_dchannel(void *vpri)
                        ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
 
                if (e) {
+                       int chanpos = -1;
+                       char cause_str[35];
+
                        if (pri->debug) {
                                ast_verbose("Span %d: Processing event %s(%d)\n",
                                        pri->span, pri_event2str(e->e), e->e);
@@ -6448,6 +6481,11 @@ static void *pri_dchannel(void *vpri)
                                        e->proceeding.call);
 
                                if (e->proceeding.cause > -1) {
+                                       if (pri->pvts[chanpos]->owner) {
+                                               snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_PROGRESS (%d)", e->proceeding.cause);
+                                               pri_queue_pvt_cause_data(pri, chanpos, cause_str);
+                                       }
+
                                        ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
 
                                        /* Work around broken, out of spec USER_BUSY cause in a progress message */
@@ -6459,6 +6497,8 @@ static void *pri_dchannel(void *vpri)
                                                        pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
                                                }
                                        }
+                               } else if (pri->pvts[chanpos]->owner) {
+                                       pri_queue_pvt_cause_data(pri, chanpos, "PRI PRI_EVENT_PROGRESS");
                                }
 
                                if (!pri->pvts[chanpos]->progress
@@ -6736,6 +6776,9 @@ static void *pri_dchannel(void *vpri)
                                        if (pri->pvts[chanpos]->owner) {
                                                int do_hangup = 0;
 
+                                               snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP (%d)", e->hangup.cause);
+                                               pri_queue_pvt_cause_data(pri, chanpos, cause_str);
+
                                                /* Queue a BUSY instead of a hangup if our cause is appropriate */
                                                ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
                                                switch (ast_channel_state(pri->pvts[chanpos]->owner)) {
@@ -6885,6 +6928,9 @@ static void *pri_dchannel(void *vpri)
                                if (pri->pvts[chanpos]->owner) {
                                        int do_hangup = 0;
 
+                                       snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP_REQ (%d)", e->hangup.cause);
+                                       pri_queue_pvt_cause_data(pri, chanpos, cause_str);
+
                                        ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
                                        switch (ast_channel_state(pri->pvts[chanpos]->owner)) {
                                        case AST_STATE_BUSY:
@@ -7218,6 +7264,27 @@ static void *pri_dchannel(void *vpri)
                                        pri->span, pri_event2str(e->e), e->e);
                                break;
                        }
+
+                       /* send tech-specific information for HANGUPCAUSE hash */
+                       if (chanpos > -1 && pri->pvts[chanpos]) {
+                               switch (e->e) {
+                               /* already handled above */
+                               case PRI_EVENT_PROGRESS:
+                               case PRI_EVENT_HANGUP:
+                               case PRI_EVENT_HANGUP_REQ:
+                                       break;
+                               default:
+                                       sig_pri_lock_private(pri->pvts[chanpos]);
+                                       if (pri->pvts[chanpos]->owner) {
+                                               char *event_str = pri_event2str(e->e);
+
+                                               snprintf(cause_str, sizeof(cause_str), "PRI %s", event_str);
+                                               pri_queue_pvt_cause_data(pri, chanpos, cause_str);
+                                       }
+                                       sig_pri_unlock_private(pri->pvts[chanpos]);
+                                       break;
+                               }
+                       }
                }
                ast_mutex_unlock(&pri->lock);
        }