Merged revisions 379144,379147 via svnmerge from
authorAutomerge script <automerge@asterisk.org>
Wed, 16 Jan 2013 00:20:45 +0000 (00:20 +0000)
committerAutomerge script <automerge@asterisk.org>
Wed, 16 Jan 2013 00:20:45 +0000 (00:20 +0000)
file:///srv/subversion/repos/asterisk/trunk

................
  r379144 | mjordan | 2013-01-15 17:54:34 -0600 (Tue, 15 Jan 2013) | 17 lines

  Add busy detection to chan_mobile

  From the patch author:

  "First this patch adds general support for busy detection. It also adds support
   for the ECAM command at Sony Ericsson phones and also signals busy when only
   early media was received but the call got not answered."

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

  (closes issue ASTERISK-14527)
  Reported by: Artem Makhutov
  Tested by: Artem Makhutov
  patches:
    busy-full5.patch uploaded by artem (license 5757)
................
  r379147 | mjordan | 2013-01-15 18:16:22 -0600 (Tue, 15 Jan 2013) | 25 lines

  Set the INVALID_EXTEN channel variable when chan_misdn forces the 'i' extension

  The chan_misdn channel driver will send a channel with an invalid destination
  to the 'i' extension itself if said extension can be reached. It forgot,
  however, to set the INVALID_EXTEN channel variable when it bounces the channel
  to this extension. Dialplan writers everywhere moaned at yet another
  inconsistency.

  This is yet another example of why duplicating logic in multiple places results
  in bugs that stick around in Jira for just under three years.

  Yes: ASTERISK-15456 was created on January 18th, 2010. Patch committed on
  January 15th, 2013. Ouch.

  (closes issue ASTERISK-15456)
  Reported by: Thomas Omerzu
  patches:
    chan_misdn_invalid.patch2 uploaded by Thomas Omerzu (license 5927)
  ........

  Merged revisions 379145 from http://svn.asterisk.org/svn/asterisk/branches/1.8
  ........

  Merged revisions 379146 from http://svn.asterisk.org/svn/asterisk/branches/11
................

git-svn-id: https://origsvn.digium.com/svn/asterisk/team/mmichelson/threadpool@379156 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
addons/chan_mobile.c
channels/chan_misdn.c

diff --git a/CHANGES b/CHANGES
index 88de8ba..2600c05 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -11,6 +11,7 @@
 --- Functionality changes from Asterisk 11 to Asterisk 12 --------------------
 ------------------------------------------------------------------------------
 
+
 AMI (Asterisk Manager Interface)
 ------------------
  * The SIPshowpeer action will now include a 'SubscribeContext' field for a peer
@@ -31,6 +32,16 @@ AMI (Asterisk Manager Interface)
    'Manager Show Command' now displays the privileges needed for using a given
    manager command instead.
 
+Channel Drivers
+------------------
+
+chan_mobile
+------------------
+ * Added general support for busy detection.
+
+ * Added ECAM command support for Sony Ericsson phones.
+
+
 Features
 -------------------
  * The BRIDGE_FEATURES channel variable would previously only set features for
index 95c7f27..96c5258 100644 (file)
@@ -147,6 +147,7 @@ struct mbl_pvt {
        int ring_sched_id;
        struct ast_dsp *dsp;
        struct ast_sched_context *sched;
+       int hangupcause;
 
        /* flags */
        unsigned int outgoing:1;        /*!< outgoing call */
@@ -172,6 +173,9 @@ static int handle_response_ring(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmti(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cusd(struct mbl_pvt *pvt, char *buf);
+static int handle_response_busy(struct mbl_pvt *pvt);
+static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf);
+static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf);
 static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf);
 
 /* CLI stuff */
@@ -341,6 +345,7 @@ struct hfp_pvt {
        struct hfp_cind cind_map;       /*!< the cind name to index mapping for this AG */
        int rsock;                      /*!< our rfcomm socket */
        int rport;                      /*!< our rfcomm port */
+       int sent_alerting;              /*!< have we sent alerting? */
 };
 
 
@@ -435,6 +440,10 @@ typedef enum {
        AT_CMER,
        AT_CIND_TEST,
        AT_CUSD,
+       AT_BUSY,
+       AT_NO_DIALTONE,
+       AT_NO_CARRIER,
+       AT_ECAM,
 } at_message_t;
 
 static int at_match_prefix(char *buf, char *prefix);
@@ -981,6 +990,7 @@ static int mbl_call(struct ast_channel *ast, const char *dest, int timeout)
                        ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
                        return -1;
                }
+               pvt->hangupcause = 0;
                pvt->needchup = 1;
                msg_queue_push(pvt, AT_OK, AT_D);
        } else {
@@ -1314,6 +1324,9 @@ static int mbl_queue_hangup(struct mbl_pvt *pvt)
                        if (ast_channel_trylock(pvt->owner)) {
                                DEADLOCK_AVOIDANCE(&pvt->lock);
                        } else {
+                               if (pvt->hangupcause != 0) {
+                                       ast_channel_hangupcause_set(pvt->owner, pvt->hangupcause);
+                               }
                                ast_queue_hangup(pvt->owner);
                                ast_channel_unlock(pvt->owner);
                                break;
@@ -2030,6 +2043,14 @@ static at_message_t at_read_full(int rsock, char *buf, size_t count)
                return AT_VGS;
        } else if (at_match_prefix(buf, "+CUSD:")) {
                return AT_CUSD;
+       } else if (at_match_prefix(buf, "BUSY")) {
+               return AT_BUSY;
+       } else if (at_match_prefix(buf, "NO DIALTONE")) {
+               return AT_NO_DIALTONE;
+       } else if (at_match_prefix(buf, "NO CARRIER")) {
+               return AT_NO_CARRIER;
+       } else if (at_match_prefix(buf, "*ECAV:")) {
+               return AT_ECAM;
        } else {
                return AT_UNKNOWN;
        }
@@ -2074,6 +2095,12 @@ static inline const char *at_msg2str(at_message_t msg)
                return "SMS PROMPT";
        case AT_CMS_ERROR:
                return "+CMS ERROR";
+       case AT_BUSY:
+               return "BUSY";
+       case AT_NO_DIALTONE:
+               return "NO DIALTONE";
+       case AT_NO_CARRIER:
+               return "NO CARRIER";
        /* at commands */
        case AT_A:
                return "ATA";
@@ -2101,6 +2128,8 @@ static inline const char *at_msg2str(at_message_t msg)
                return "AT+CIND=?";
        case AT_CUSD:
                return "AT+CUSD";
+       case AT_ECAM:
+               return "AT*ECAM";
        }
 }
 
@@ -2109,6 +2138,40 @@ static inline const char *at_msg2str(at_message_t msg)
  * bluetooth handsfree profile helpers
  */
 
+ /*!
+ * \brief Parse a ECAV event.
+ * \param hfp an hfp_pvt struct
+ * \param buf the buffer to parse (null terminated)
+ * \return -1 on error (parse error) or a ECAM value on success
+ *
+ * Example string: *ECAV: <ccid>,<ccstatus>,<calltype>[,<processid>]
+ * [,exitcause][,<number>,<type>]
+ *
+ * Example indicating busy: *ECAV: 1,7,1
+ */
+static int hfp_parse_ecav(struct hfp_pvt *hfp, char *buf)
+{
+       int ccid = 0;
+       int ccstatus = 0;
+       int calltype = 0;
+
+       if (!sscanf(buf, "*ECAV: %2d,%2d,%2d", &ccid, &ccstatus, &calltype)) {
+               ast_debug(1, "[%s] error parsing ECAV event '%s'\n", hfp->owner->id, buf);
+               return -1;
+       }
+
+       return ccstatus;
+}
+
+/*!
+ * \brief Enable Sony Erricson extensions / indications.
+ * \param hfp an hfp_pvt struct
+ */
+static int hfp_send_ecam(struct hfp_pvt *hfp)
+{
+       return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
+}
+
 /*!
  * \brief Parse a CIEV event.
  * \param hfp an hfp_pvt struct
@@ -3214,6 +3277,14 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
                        break;
                case AT_CLIP:
                        ast_debug(1, "[%s] caling line indication enabled\n", pvt->id);
+                       if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) {
+                               ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id);
+                               goto e_return;
+                       }
+
+                       break;
+               case AT_ECAM:
+                       ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\n", pvt->id);
                        if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
                                ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
                                goto e_return;
@@ -3345,6 +3416,21 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf)
                        ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
                        ast_debug(1, "[%s] no SMS support\n", pvt->id);
                        break;
+               case AT_ECAM:
+                       ast_debug(1, "[%s] Mobile does not support Sony Ericsson extensions\n", pvt->id);
+
+                       /* this is not a fatal error, let's continue with the initialization */
+
+                       if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
+                               ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
+                               goto e_return;
+                       }
+
+                       pvt->timeout = -1;
+                       pvt->hfp->initialized = 1;
+                       ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
+
+                       break;
                /* end initialization stuff */
 
                case AT_A:
@@ -3440,6 +3526,9 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                case HFP_CIND_CALLSETUP_NONE:
                        if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
                                if (pvt->owner) {
+                                       if (pvt->hfp->sent_alerting == 1) {
+                                               handle_response_busy(pvt);
+                                       }
                                        if (mbl_queue_hangup(pvt)) {
                                                ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
                                                return -1;
@@ -3458,6 +3547,7 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                        break;
                case HFP_CIND_CALLSETUP_OUTGOING:
                        if (pvt->outgoing) {
+                               pvt->hfp->sent_alerting = 0;
                                ast_debug(1, "[%s] outgoing call\n", pvt->id);
                        } else {
                                ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
@@ -3468,6 +3558,7 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                        if (pvt->outgoing) {
                                ast_debug(1, "[%s] remote alerting\n", pvt->id);
                                mbl_queue_control(pvt, AST_CONTROL_RINGING);
+                               pvt->hfp->sent_alerting = 1;
                        }
                        break;
                }
@@ -3662,6 +3753,50 @@ static int handle_response_cusd(struct mbl_pvt *pvt, char *buf)
        return 0;
 }
 
+/*!
+ * \brief Handle BUSY messages.
+ * \param pvt a mbl_pvt structure
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_busy(struct mbl_pvt *pvt)
+{
+       pvt->hangupcause = AST_CAUSE_USER_BUSY;
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_BUSY);
+       return 0;
+}
+
+/*!
+ * \brief Handle NO DIALTONE messages.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf)
+{
+       ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
+       return 0;
+}
+
+/*!
+ * \brief Handle NO CARRIER messages.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf)
+{
+       ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
+       return 0;
+}
+
 
 static void *do_monitor_phone(void *data)
 {
@@ -3820,6 +3955,40 @@ static void *do_monitor_phone(void *data)
                        }
                        ast_mutex_unlock(&pvt->lock);
                        break;
+               case AT_BUSY:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_busy(pvt)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_NO_DIALTONE:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_no_dialtone(pvt, buf)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_NO_CARRIER:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_no_carrier(pvt, buf)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_ECAM:
+                       ast_mutex_lock(&pvt->lock);
+                       if (hfp_parse_ecav(hfp, buf) == 7) {
+                               if (handle_response_busy(pvt)) {
+                                       ast_mutex_unlock(&pvt->lock);
+                                       goto e_cleanup;
+                               }
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
                case AT_UNKNOWN:
                        ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf);
                        break;
index af632f0..4047d1c 100644 (file)
@@ -10096,8 +10096,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                        ast_log(LOG_WARNING,
                                                "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
                                                bc->dialed.number, ch->context, bc->port);
+                                       pbx_builtin_setvar_helper(ch->ast, "INVALID_EXTEN", bc->dad);
                                        ast_channel_exten_set(ch->ast, "i");
-
                                        ch->state = MISDN_DIALING;
                                        start_pbx(ch, bc, ch->ast);
                                        break;
@@ -10354,6 +10354,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                ast_log(LOG_WARNING,
                                        "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
                                        bc->dialed.number, ch->context, bc->port);
+                               pbx_builtin_setvar_helper(ch->ast, "INVALID_EXTEN", bc->dad);
                                ast_channel_exten_set(ch->ast, "i");
                                misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
                                ch->state = MISDN_DIALING;