voicecall: add __ofono_voicecall_dial internal api

The callback is only invoked when the call is CONNECTED (becomes
active).  Cancel ensures that the callback will not be called and
does nothing more in this version, it's an open question if we
want to release the call.
This commit is contained in:
Andrzej Zaborowski 2010-08-26 13:36:47 +02:00 committed by Denis Kenzior
parent 4b6be6ab46
commit 4a9a985c9d
2 changed files with 296 additions and 51 deletions

View File

@ -169,11 +169,28 @@ void __ofono_atom_free(struct ofono_atom *atom);
#include <ofono/cbs.h>
#include <ofono/devinfo.h>
#include <ofono/phonebook.h>
#include <ofono/voicecall.h>
#include <ofono/gprs.h>
#include <ofono/gprs-context.h>
#include <ofono/radio-settings.h>
#include <ofono/voicecall.h>
enum ofono_voicecall_interaction {
OFONO_VOICECALL_INTERACTION_NONE = 0,
OFONO_VOICECALL_INTERACTION_PUT_ON_HOLD = 1,
OFONO_VOICECALL_INTERACTION_DISCONNECT = 2,
};
typedef void (*ofono_voicecall_dial_cb_t)(struct ofono_call *call, void *data);
ofono_bool_t __ofono_voicecall_busy(struct ofono_voicecall *vc);
int __ofono_voicecall_dial(struct ofono_voicecall *vc,
const char *addr, int addr_type,
const char *message, unsigned char icon_id,
enum ofono_voicecall_interaction interaction,
ofono_voicecall_dial_cb_t cb, void *user_data);
void __ofono_voicecall_dial_cancel(struct ofono_voicecall *vc);
#include <ofono/sms.h>
struct sms;

View File

@ -27,6 +27,7 @@
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include <glib.h>
#include <gdbus.h>
@ -57,6 +58,7 @@ struct ofono_voicecall {
const struct ofono_voicecall_driver *driver;
void *driver_data;
struct ofono_atom *atom;
struct dial_request *dial_req;
};
struct voicecall {
@ -64,6 +66,20 @@ struct voicecall {
struct ofono_voicecall *vc;
time_t start_time;
time_t detect_time;
const char *message;
uint8_t icon_id;
gboolean untracked;
};
struct dial_request {
struct ofono_voicecall *vc;
const char *message;
uint8_t icon_id;
enum ofono_voicecall_interaction interaction;
ofono_voicecall_dial_cb_t cb;
void *user_data;
struct voicecall *call;
struct ofono_phone_number ph;
};
static const char *default_en_list[] = { "911", "112", NULL };
@ -235,6 +251,14 @@ static void append_voicecall_properties(struct voicecall *v,
mpty = FALSE;
ofono_dbus_dict_append(dict, "Multiparty", DBUS_TYPE_BOOLEAN, &mpty);
if (v->message)
ofono_dbus_dict_append(dict, "Information", DBUS_TYPE_STRING,
&v->message);
if (v->icon_id)
ofono_dbus_dict_append(dict, "Icon", DBUS_TYPE_BYTE,
&v->icon_id);
}
static DBusMessage *voicecall_get_properties(DBusConnection *conn,
@ -529,6 +553,32 @@ static void voicecall_set_call_status(struct voicecall *call,
OFONO_VOICECALL_INTERFACE,
"StartTime", DBUS_TYPE_STRING,
&timestr);
if (call->vc->dial_req && call == call->vc->dial_req->call) {
struct dial_request *req = call->vc->dial_req;
if (req->cb)
req->cb(call->call, req->user_data);
/*
* TODO: parse the called number for DTMF tones to be
* sent after call becomes active, and send them.
*/
call->vc->dial_req = NULL;
g_free(req);
}
}
if (status == CALL_STATUS_DISCONNECTED && call->vc->dial_req &&
call == call->vc->dial_req->call) {
struct dial_request *req = call->vc->dial_req;
if (req->cb)
req->cb(NULL, req->user_data);
call->vc->dial_req = NULL;
g_free(req);
}
}
@ -906,10 +956,9 @@ static ofono_bool_t clir_string_to_clir(const char *clirstr,
}
static struct ofono_call *synthesize_outgoing_call(struct ofono_voicecall *vc,
DBusMessage *msg)
const char *number)
{
struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
const char *number;
struct ofono_call *call;
call = g_try_new0(struct ofono_call, 1);
@ -927,10 +976,7 @@ static struct ofono_call *synthesize_outgoing_call(struct ofono_voicecall *vc,
__ofono_modem_callid_hold(modem, call->id);
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
DBUS_TYPE_INVALID) == FALSE)
number = "";
else
if (number)
string_to_phone_number(number, &call->phone_number);
call->direction = CALL_DIRECTION_MOBILE_ORIGINATED;
@ -940,70 +986,80 @@ static struct ofono_call *synthesize_outgoing_call(struct ofono_voicecall *vc,
return call;
}
static void dial_callback(const struct ofono_error *error, void *data)
static struct voicecall *dial_handle_result(struct ofono_voicecall *vc,
const struct ofono_error *error,
const char *number,
gboolean *need_to_emit)
{
struct ofono_voicecall *vc = data;
DBusMessage *reply;
GSList *l;
struct voicecall *v;
struct ofono_call *call;
const char *path;
gboolean need_to_emit = FALSE;
*need_to_emit = FALSE;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Dial callback returned error: %s",
telephony_error_to_str(error));
reply = __ofono_error_failed(vc->pending);
__ofono_dbus_pending_reply(&vc->pending, reply);
return;
return NULL;
}
/* Two things can happen, the call notification arrived before dial
* callback or dial callback was first. Handle here */
for (l = vc->call_list; l; l = l->next) {
struct voicecall *v = l->data;
v = l->data;
if (v->call->status == CALL_STATUS_DIALING ||
v->call->status == CALL_STATUS_ALERTING ||
v->call->status == CALL_STATUS_ACTIVE)
break;
return v;
}
if (!l) {
call = synthesize_outgoing_call(vc, vc->pending);
call = synthesize_outgoing_call(vc, number);
if (!call)
return NULL;
if (!call) {
__ofono_dbus_pending_reply(&vc->pending,
__ofono_error_failed(vc->pending));
return;
}
v = voicecall_create(vc, call);
if (!v)
return NULL;
v = voicecall_create(vc, call);
v->detect_time = time(NULL);
if (!v) {
__ofono_dbus_pending_reply(&vc->pending,
__ofono_error_failed(vc->pending));
return;
}
DBG("Registering new call: %d", call->id);
voicecall_dbus_register(v);
v->detect_time = time(NULL);
vc->call_list = g_slist_insert_sorted(vc->call_list, v,
call_compare);
DBG("Registering new call: %d", call->id);
voicecall_dbus_register(v);
*need_to_emit = TRUE;
vc->call_list = g_slist_insert_sorted(vc->call_list, v,
call_compare);
return v;
}
need_to_emit = TRUE;
} else {
v = l->data;
call = v->call;
}
static void manager_dial_callback(const struct ofono_error *error, void *data)
{
struct ofono_voicecall *vc = data;
DBusMessage *reply;
const char *number;
gboolean need_to_emit;
struct voicecall *v;
if (dbus_message_get_args(vc->pending, NULL, DBUS_TYPE_STRING, &number,
DBUS_TYPE_INVALID) == FALSE)
number = NULL;
v = dial_handle_result(vc, error, number, &need_to_emit);
if (v) {
const char *path = voicecall_build_path(vc, v->call);
reply = dbus_message_new_method_return(vc->pending);
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
} else
reply = __ofono_error_failed(vc->pending);
reply = dbus_message_new_method_return(vc->pending);
path = voicecall_build_path(vc, call);
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
__ofono_dbus_pending_reply(&vc->pending, reply);
if (need_to_emit)
@ -1054,7 +1110,7 @@ static DBusMessage *manager_dial(DBusConnection *conn,
string_to_phone_number(number, &ph);
vc->driver->dial(vc, &ph, clir, OFONO_CUG_OPTION_DEFAULT,
dial_callback, vc);
manager_dial_callback, vc);
return NULL;
}
@ -1644,12 +1700,14 @@ void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id,
voicecall_set_call_status(call, CALL_STATUS_DISCONNECTED);
if (prev_status == CALL_STATUS_INCOMING ||
prev_status == CALL_STATUS_WAITING)
__ofono_history_call_missed(modem, call->call, ts);
else
__ofono_history_call_ended(modem, call->call,
call->detect_time, ts);
if (!call->untracked) {
if (prev_status == CALL_STATUS_INCOMING ||
prev_status == CALL_STATUS_WAITING)
__ofono_history_call_missed(modem, call->call, ts);
else
__ofono_history_call_ended(modem, call->call,
call->detect_time, ts);
}
voicecalls_emit_call_removed(vc, call);
@ -2095,3 +2153,173 @@ int ofono_voicecall_get_next_callid(struct ofono_voicecall *vc)
return __ofono_modem_callid_next(modem);
}
ofono_bool_t __ofono_voicecall_busy(struct ofono_voicecall *vc)
{
return vc->dial_req || vc->pending || voicecalls_have_active(vc) ||
g_slist_length(vc->call_list) >= MAX_VOICE_CALLS ||
voicecalls_have_incoming(vc) ||
voicecalls_num_connecting(vc) > 0;
}
static void dial_request_cb(const struct ofono_error *error, void *data)
{
struct ofono_voicecall *vc = data;
gboolean need_to_emit;
struct voicecall *v;
v = dial_handle_result(vc, error,
phone_number_to_string(&vc->dial_req->ph),
&need_to_emit);
if (v) {
v->message = vc->dial_req->message;
v->icon_id = vc->dial_req->icon_id;
/*
* TS 102 223 Section 6.4.13: The terminal shall not store
* in the UICC the call set-up details (called party number
* and associated parameters)
*/
v->untracked = TRUE;
}
if (need_to_emit)
voicecalls_emit_call_added(vc, v);
if (vc->dial_req->cb) {
if (v && v->call->status != CALL_STATUS_ACTIVE) {
vc->dial_req->call = v;
/* Wait for the call connected message */
return;
}
vc->dial_req->cb(v ? v->call : NULL, vc->dial_req->user_data);
}
g_free(vc->dial_req);
vc->dial_req = NULL;
}
static int dial_request(struct ofono_voicecall *vc)
{
if (g_slist_length(vc->call_list) >= MAX_VOICE_CALLS ||
voicecalls_have_incoming(vc) ||
voicecalls_num_connecting(vc) > 0 ||
vc->pending) {
g_free(vc->dial_req);
vc->dial_req = NULL;
return -EBUSY;
}
vc->driver->dial(vc, &vc->dial_req->ph, OFONO_CLIR_OPTION_DEFAULT,
OFONO_CUG_OPTION_DEFAULT, dial_request_cb, vc);
return 0;
}
static void hold_or_disconnect_cb(const struct ofono_error *error, void *data)
{
struct ofono_voicecall *vc = data;
ofono_voicecall_dial_cb_t cb = vc->dial_req->cb;
void *user_data = vc->dial_req->user_data;
int err;
if (!cb) {
g_free(vc->dial_req);
vc->dial_req = NULL;
return;
}
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
cb(FALSE, user_data);
g_free(vc->dial_req);
vc->dial_req = NULL;
return;
}
err = dial_request(vc);
if (err < 0)
cb(FALSE, user_data);
}
int __ofono_voicecall_dial(struct ofono_voicecall *vc,
const char *addr, int addr_type,
const char *message, unsigned char icon_id,
enum ofono_voicecall_interaction interaction,
ofono_voicecall_dial_cb_t cb, void *user_data)
{
struct dial_request *req;
if (!valid_phone_number_format(addr))
return -EINVAL;
if (!vc->driver->dial)
return -ENOSYS;
if (vc->dial_req || vc->pending)
return -EBUSY;
/*
* TODO: if addr starts with "112", possibly translate into the
* technology-specific emergency number.
*/
req = g_try_new0(struct dial_request, 1);
req->message = message;
req->icon_id = icon_id;
req->interaction = interaction;
req->cb = cb;
req->user_data = user_data;
/* TODO: parse the tones to dial after call connected */
req->ph.type = addr_type;
strncpy(req->ph.number, addr, 20);
if (!voicecalls_have_active(vc)) {
vc->dial_req = req;
return dial_request(vc);
}
switch (interaction) {
case OFONO_VOICECALL_INTERACTION_NONE:
return -EBUSY;
case OFONO_VOICECALL_INTERACTION_PUT_ON_HOLD:
/* Note: dialling automatically puts active calls on hold */
vc->dial_req = req;
return dial_request(vc);
case OFONO_VOICECALL_INTERACTION_DISCONNECT:
if (!vc->driver->release_all_active) {
g_free(req);
return -ENOSYS;
}
vc->driver->release_all_active(vc, hold_or_disconnect_cb, vc);
break;
}
vc->dial_req = req;
return 0;
}
void __ofono_voicecall_dial_cancel(struct ofono_voicecall *vc)
{
if (!vc->dial_req || !vc->dial_req->cb)
return;
vc->dial_req->cb = NULL;
/* XXX: If vc->dial_req->call is set, try to release it? */
}