summaryrefslogtreecommitdiff
path: root/addons/chan_mobile.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2013-01-15 23:54:34 +0000
committerMatthew Jordan <mjordan@digium.com>2013-01-15 23:54:34 +0000
commita4d0878955241dc6f3feb65482f017a57959d67e (patch)
treea413eb48a6b30261061584cfb3b1c63decdfee3c /addons/chan_mobile.c
parent491e0064b8afb923508af4d713f05d31046bbf62 (diff)
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) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@379144 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'addons/chan_mobile.c')
-rw-r--r--addons/chan_mobile.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c
index 95c7f27d9..96c525856 100644
--- a/addons/chan_mobile.c
+++ b/addons/chan_mobile.c
@@ -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;