Fix: Fill in the phone number info for outgoing call

There're two cases of outgoing call: dial from HF or dial from
phone. We could receive callsetup=2 indicator in both case. So
adding AT+CLCC query to sync the outgoing call.

In the first case, we only need to sync the phone number.  In
the second case, the phone is dialing from phone and we know
nothing. Create a new call and notify the core.

If phone does not support AT+CLCC and there's no call dialing
from HF, we fake a new call for it.
This commit is contained in:
Zhenhua Zhang 2009-11-13 19:28:32 +08:00 committed by Denis Kenzior
parent 6c428c9823
commit e620a058fb
1 changed files with 123 additions and 30 deletions

View File

@ -49,6 +49,7 @@
static const char *none_prefix[] = { NULL };
static const char *chld_prefix[] = { "+CHLD:", NULL };
static const char *clcc_prefix[] = { "+CLCC:", NULL };
struct voicecall_data {
GAtChat *chat;
@ -108,6 +109,20 @@ static struct ofono_call *create_call(struct voicecall_data *d, int type,
return call;
}
static struct ofono_call *new_call_notify(struct ofono_voicecall *vc, int type,
int direction, int status,
const char *num, int num_type, int clip)
{
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
struct ofono_call *c;
c = create_call(vd, type, direction, status, num, num_type, clip);
ofono_voicecall_notify(vc, c);
return c;
}
static void generic_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct change_state_req *req = user_data;
@ -351,23 +366,78 @@ static void ciev_call_notify(struct ofono_voicecall *vc,
{
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
if (g_slist_length(vd->calls) == 1) {
switch (value) {
case 0:
release_call(vc, call);
break;
case 1:
call->status = CALL_STATUS_ACTIVE;
ofono_voicecall_notify(vc, call);
break;
default:
break;
}
switch (value) {
case 0:
release_call(vc, call);
break;
case 1:
call->status = CALL_STATUS_ACTIVE;
ofono_voicecall_notify(vc, call);
break;
default:
break;
}
vd->cind_val[HFP_INDICATOR_CALL] = value;
}
static void sync_dialing_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_voicecall *vc = user_data;
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
struct ofono_error error;
GSList *calls = NULL;
GSList *l = NULL;
struct ofono_call *nc = NULL;
struct ofono_call *oc = vd->call;
unsigned int call_held = vd->cind_val[HFP_INDICATOR_CALLHELD];
dump_response("sync_dialing_cb", ok, result);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok)
return;
calls = at_util_parse_clcc(result);
if (calls == NULL)
return;
if (oc && call_held == 0) {
l = g_slist_find_custom(calls, oc, at_util_call_compare);
if (l) {
nc = l->data;
if (memcmp(nc, oc, sizeof(struct ofono_call))) {
ofono_voicecall_notify(vc, nc);
memcpy(oc, nc, sizeof(struct ofono_call));
}
}
} else {
while (calls) {
nc = calls->data;
if (vd->calls)
l = g_slist_find_custom(vd->calls, nc,
at_util_call_compare);
if (!l)
new_call_notify(vc, nc->type, nc->direction,
nc->status,
nc->phone_number.number,
nc->phone_number.type,
nc->clip_validity);
calls = calls->next;
}
}
g_slist_foreach(calls, (GFunc) g_free, NULL);
g_slist_free(calls);
}
static void ciev_callsetup_notify(struct ofono_voicecall *vc,
struct ofono_call *call,
unsigned int value)
@ -376,29 +446,50 @@ static void ciev_callsetup_notify(struct ofono_voicecall *vc,
unsigned int ciev_callsetup = vd->cind_val[HFP_INDICATOR_CALLSETUP];
unsigned int ciev_call = vd->cind_val[HFP_INDICATOR_CALL];
if (g_slist_length(vd->calls) == 1) {
switch (value) {
case 0:
/* call=0 and callsetup=1: reject an incoming call
* call=0 and callsetup=2,3: interrupt an outgoing call
*/
if (ciev_call == 0 && ciev_callsetup > 0)
release_call(vc, call);
break;
case 1:
case 2:
break;
case 3:
call->status = CALL_STATUS_ALERTING;
ofono_voicecall_notify(vc, call);
default:
break;
}
switch (value) {
case 0:
/* call=0 and callsetup=1: reject an incoming call
* call=0 and callsetup=2,3: interrupt an outgoing call
*/
if ((ciev_call == 0) && (ciev_callsetup > 0))
release_call(vc, call);
break;
case 1:
break;
case 2:
/* two cases of outgoing call: dial from HF or AG.
* from HF: query and sync the phone number.
* from AG: query and create call.
* if phone does not support CLLC, we guess the call.
*/
if (vd->ag_features & AG_FEATURE_ENHANCED_CALL_STATUS)
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
sync_dialing_cb,
vc, NULL);
else if (!vd->call)
vd->call = new_call_notify(vc, 0, 0,
CALL_STATUS_DIALING,
NULL, 128, 2);
break;
case 3:
call->status = CALL_STATUS_ALERTING;
ofono_voicecall_notify(vc, call);
default:
break;
}
vd->cind_val[HFP_INDICATOR_CALLSETUP] = value;
}
static void ciev_callheld_notify(struct ofono_voicecall *vc,
struct ofono_call *call,
unsigned int value)
{
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
vd->cind_val[HFP_INDICATOR_CALLHELD] = value;
}
static void ciev_notify(GAtResult *result, gpointer user_data)
{
struct ofono_voicecall *vc = user_data;
@ -423,6 +514,8 @@ static void ciev_notify(GAtResult *result, gpointer user_data)
ciev_call_notify(vc, call, value);
else if (index == vd->cind_pos[HFP_INDICATOR_CALLSETUP])
ciev_callsetup_notify(vc, call, value);
else if (index == vd->cind_pos[HFP_INDICATOR_CALLHELD])
ciev_callheld_notify(vc, call, value);
}
static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)