diff options
author | Mikel Astiz <mikel.astiz@bmw-carit.de> | 2013-01-21 16:30:24 +0100 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2013-01-21 09:41:54 -0600 |
commit | 843bd71169e721780b7305e5623196764171da9e (patch) | |
tree | d4ce3e66158ac7e1a5c48bcf25932c60128c4a8d /drivers/hfpmodem/voicecall.c | |
parent | cbb784e734e1d4e42e21eb887d6bb1eaeeefa71d (diff) | |
download | ofono-843bd71169e721780b7305e5623196764171da9e.tar.bz2 |
hfpmodem: Fix release-and-swap without +CIEV
Some phones do not send the corresponding call state update (+CIEV)
after a successful release-and-swap operation (AT+CHLD=1).
This has been observed with a Nokia 500, while testing ReleaseAndSwap()
while an active and a held call exist:
ofonod[20414]: > AT+CLCC\r
ofonod[20414]: < \r\n+CLCC: 1,0,1,0,0,"<number1>",145\r\n
ofonod[20414]: < \r\n+CLCC: 2,0,0,0,0,"<number2>",145\r\n
ofonod[20414]: < \r\nOK\r\n
ofonod[20414]: > AT+CHLD=1\r
ofonod[20414]: < \r\nOK\r\n
After this, no +CIEV is received, but the call has been hung up.
The proposed approach to solve this consists of using AT+CLCC, unless
a call release has been received within a specific time period.
The result fixes the problem as can be seen below:
ofonod[20847]: < \r\n+CLCC: 1,0,1,0,0,"<number1>",145\r\n
ofonod[20847]: < \r\n+CLCC: 2,0,0,0,0,"<number2>",145\r\n
ofonod[20847]: < \r\nOK\r\n
ofonod[20847]: > AT+CHLD=1\r
ofonod[20847]: < \r\nOK\r\n
ofonod[20847]: > AT+CLCC\r
ofonod[20847]: < \r\n+CLCC: 1,0,0,0,0,"<number1>",145\r\n
ofonod[20847]: < \r\nOK\r\n
ofonod[20847]: < \r\n+CIEV: 5,2\r\n
ofonod[20847]: < \r\n+CIEV: 5,0\r\n
Diffstat (limited to 'drivers/hfpmodem/voicecall.c')
-rw-r--r-- | drivers/hfpmodem/voicecall.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/drivers/hfpmodem/voicecall.c b/drivers/hfpmodem/voicecall.c index e0da3fc1..39d81f1f 100644 --- a/drivers/hfpmodem/voicecall.c +++ b/drivers/hfpmodem/voicecall.c @@ -43,6 +43,7 @@ #define POLL_CLCC_INTERVAL 2000 #define POLL_CLCC_DELAY 50 +#define EXPECT_RELEASE_DELAY 50 #define CLIP_TIMEOUT 500 static const char *none_prefix[] = { NULL }; @@ -57,6 +58,7 @@ struct voicecall_data { int cind_val[HFP_INDICATOR_LAST]; unsigned int local_release; unsigned int clcc_source; + unsigned int expect_release_source; unsigned int clip_source; }; @@ -194,6 +196,11 @@ static void release_with_status(struct ofono_voicecall *vc, int status) c = c->next; g_slist_free_1(t); } + + if (vd->expect_release_source) { + g_source_remove(vd->expect_release_source); + vd->expect_release_source = 0; + } } static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data) @@ -471,13 +478,47 @@ static void hfp_set_udub(struct ofono_voicecall *vc, CALLBACK_WITH_FAILURE(cb, data); } +static gboolean expect_release(gpointer user_data) +{ + struct ofono_voicecall *vc = user_data; + struct voicecall_data *vd = ofono_voicecall_get_data(vc); + + g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix, + clcc_poll_cb, vc, NULL); + + vd->expect_release_source = 0; + + return FALSE; +} + +static void release_all_active_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct change_state_req *req = user_data; + struct voicecall_data *vd = ofono_voicecall_get_data(req->vc); + + if (!ok) + goto out; + + if (vd->expect_release_source) + g_source_remove(vd->expect_release_source); + + vd->expect_release_source = g_timeout_add(EXPECT_RELEASE_DELAY, + expect_release, + req->vc); + +out: + generic_cb(ok, result, user_data); +} + static void hfp_release_all_active(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data) { struct voicecall_data *vd = ofono_voicecall_get_data(vc); if (vd->ag_mpty_features & AG_CHLD_1) { - hfp_template("AT+CHLD=1", vc, generic_cb, 0x1, cb, data); + hfp_template("AT+CHLD=1", vc, release_all_active_cb, 0x1, cb, + data); return; } @@ -1111,6 +1152,9 @@ static void hfp_voicecall_remove(struct ofono_voicecall *vc) if (vd->clip_source) g_source_remove(vd->clip_source); + if (vd->expect_release_source) + g_source_remove(vd->expect_release_source); + g_slist_foreach(vd->calls, (GFunc) g_free, NULL); g_slist_free(vd->calls); |