aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md11
-rw-r--r--binding/gdbus/ofono_voicecallmanager.c88
-rw-r--r--binding/gdbus/ofono_voicecallmanager.h8
-rw-r--r--binding/telephony-binding.c188
4 files changed, 269 insertions, 26 deletions
diff --git a/README.md b/README.md
index 920be61..5fab4b8 100644
--- a/README.md
+++ b/README.md
@@ -11,10 +11,16 @@ Telephony service allows respective clients access to the Handsfree Profile via
| subscribe | subscribe to telephony events | *Request:* {"value": "callStateChanged"} |
| unsubscribe | unsubscribe to telephony events | *Request:* {"value": "callStateChanged"} |
| dial | dial respective number | *Request:* {"value": "15035551212"} |
-| last_dial | dial last dialed number | |
+| last_dial | dial last dialed number | |
+| hangup_all | hang up all active calls | |
| send_tones | send tone through the active call | *Request:* {"value": "1"} |
-| hangup | hangup an active call or reject incoming call | |
+| hangup | hangup an active call or reject incoming call. this verb does not hang up all calls if exist more than one active call | *Request:* {"id": "voicecall01"} |
| answer | answer incoming call | |
+| hold_and_answer | Puts the current call on hold and answers the currently waiting call | |
+| release_and_answer | Releases currently active call and activates any currently held calls | |
+| hangup_multiparty | Hangs up the multi-party call | |
+| create_multiparty | Joins active and held calls together into a multi-party call | |
+| swap_calls | Swaps Active and Held calls | |
| get_battery_level | getting battery level of connected phone device | |
| get_network_registration | getting network registration of connected phone device | *Response:* {"Status": "registered","Mode": "auto-only","Name": "Irancell","Strength": 20} |
@@ -25,6 +31,7 @@ Telephony service allows respective clients access to the Handsfree Profile via
| callStateChanged | Call status change event | see callStateChanged event |
| dialingCall | Outgoing call events | {"colp": "3305551212"} |
| incomingCall | Incoming call events | {"clip": "3305551212"} |
+| waitingCall | waiting call events | {"colp": "3305551212"} |
| terminatedCall | Terminated call event | *empty JSON response* |
| online | Connected status of Handsfree Profile | {"connected": true} |
| battery | Connected status of Handsfree Profile | {"battery level": 2} |
diff --git a/binding/gdbus/ofono_voicecallmanager.c b/binding/gdbus/ofono_voicecallmanager.c
index 2a361a1..78924dc 100644
--- a/binding/gdbus/ofono_voicecallmanager.c
+++ b/binding/gdbus/ofono_voicecallmanager.c
@@ -45,6 +45,8 @@ static void call_added(OrgOfonoVoiceCallManager *manager,
g_signal_emit_by_name(manager, "incoming-call", op, cl ? cl : "");
} else if (!strcmp(state, "dialing")) {
g_signal_emit_by_name(manager, "dialing-call", op, cl ? cl : "");
+ } else if (!strcmp(state, "waiting")) {
+ g_signal_emit_by_name(manager, "waiting-call", op, cl ? cl : "");
}
}
@@ -59,6 +61,7 @@ const OrgOfonoVoiceCallManager
*ofono_voicecallmanager_init(const gchar *op,
void (*incoming_call)(OrgOfonoVoiceCallManager *manager,gchar *,gchar *),
void (*dialing_call)(OrgOfonoVoiceCallManager *manager,gchar *,gchar *),
+ void (*waiting_call)(OrgOfonoVoiceCallManager *manager,gchar *,gchar *),
void (*terminated_call)(OrgOfonoVoiceCallManager *manager,gchar *))
{
OrgOfonoVoiceCallManager *manager = org_ofono_voice_call_manager_proxy_new_for_bus_sync(
@@ -89,6 +92,18 @@ const OrgOfonoVoiceCallManager
G_TYPE_STRING,
G_TYPE_STRING);
+ g_signal_new("waiting-call",
+ G_TYPE_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
g_signal_new("terminated-call",
G_TYPE_OBJECT,
G_SIGNAL_RUN_LAST,
@@ -108,6 +123,10 @@ const OrgOfonoVoiceCallManager
AFB_ERROR("Failed to connect to signal dialing-call\n");
}
+ if (g_signal_connect(G_OBJECT(manager), "waiting-call", G_CALLBACK(waiting_call), NULL) <= 0) {
+ AFB_ERROR("Failed to connect to signal waiting-call\n");
+ }
+
if (g_signal_connect(G_OBJECT(manager), "terminated-call", G_CALLBACK(terminated_call), NULL) <= 0) {
AFB_ERROR("Failed to connect to signal terminated-call\n");
}
@@ -188,3 +207,72 @@ void ofono_voicecallmanager_hangup_all(OrgOfonoVoiceCallManager *manager)
org_ofono_voice_call_manager_call_hangup_all_sync(manager, NULL, &error);
}
+
+gchar **ofono_voicecallmanager_create_multiparty(OrgOfonoVoiceCallManager *manager)
+{
+ gchar **out = NULL;
+ GError *error = NULL;
+ if (!manager) {
+ AFB_ERROR("Ofono VoiceCallmanager uninitialized\n");
+ return NULL;
+ }
+
+ org_ofono_voice_call_manager_call_create_multiparty_sync(manager, &out, NULL, &error);
+ if (error != NULL)
+ return NULL;
+ return out;
+}
+
+gboolean ofono_voicecallmanager_hangup_multiparty(OrgOfonoVoiceCallManager *manager)
+{
+ GError *error = NULL;
+ gboolean res;
+ if (!manager) {
+ AFB_ERROR("Ofono VoiceCallmanager uninitialized\n");
+ return FALSE;
+ }
+
+ res = org_ofono_voice_call_manager_call_hangup_multiparty_sync(manager, NULL, &error);
+
+ return (res && error == NULL);
+}
+
+gboolean ofono_voicecallmanager_hold_and_answer(OrgOfonoVoiceCallManager *manager)
+{
+ GError *error = NULL;
+ gboolean res;
+ if (!manager) {
+ AFB_ERROR("Ofono VoiceCallmanager uninitialized\n");
+ return FALSE;
+ }
+
+ res = org_ofono_voice_call_manager_call_hold_and_answer_sync(manager, NULL, &error);
+
+ return (res && error == NULL);
+}
+
+gboolean ofono_voicecallmanager_release_and_answer(OrgOfonoVoiceCallManager *manager)
+{
+ GError *error = NULL;
+ if (!manager) {
+ AFB_ERROR("Ofono VoiceCallmanager uninitialized\n");
+ return FALSE;
+ }
+ AFB_ERROR("release and answer");
+ org_ofono_voice_call_manager_call_release_and_answer_sync(manager, NULL, &error);
+
+ return (error == NULL);
+}
+
+gboolean ofono_voicecallmanager_swap_calls(OrgOfonoVoiceCallManager *manager)
+{
+ GError *error = NULL;
+ if (!manager) {
+ AFB_ERROR("Ofono VoiceCallmanager uninitialized\n");
+ return FALSE;
+ }
+
+ org_ofono_voice_call_manager_call_swap_calls_sync(manager, NULL, &error);
+
+ return (error == NULL);
+}
diff --git a/binding/gdbus/ofono_voicecallmanager.h b/binding/gdbus/ofono_voicecallmanager.h
index 65535cd..df058a2 100644
--- a/binding/gdbus/ofono_voicecallmanager.h
+++ b/binding/gdbus/ofono_voicecallmanager.h
@@ -22,9 +22,15 @@ OrgOfonoVoiceCallManager
*ofono_voicecallmanager_init(const gchar *,
void(*)(OrgOfonoVoiceCallManager *, gchar *, gchar *),
void(*)(OrgOfonoVoiceCallManager *, gchar *, gchar *),
+ void(*)(OrgOfonoVoiceCallManager *, gchar *, gchar *),
void(*)(OrgOfonoVoiceCallManager *, gchar *));
void ofono_voicecallmanager_free(OrgOfonoVoiceCallManager *);
gchar *ofono_voicecallmanager_dial(OrgOfonoVoiceCallManager *, gchar *, gchar *);
gboolean ofono_voicecallmanager_last_dial(OrgOfonoVoiceCallManager *manager);
gboolean ofono_voicecallmanager_send_tones(OrgOfonoVoiceCallManager *manager, const char *call_path);
-void ofono_hangup_all(OrgOfonoVoiceCallManager *);
+void ofono_voicecallmanager_hangup_all(OrgOfonoVoiceCallManager *);
+gboolean ofono_voicecallmanager_hangup_multiparty(OrgOfonoVoiceCallManager *);
+gboolean ofono_voicecallmanager_hold_and_answer(OrgOfonoVoiceCallManager *);
+gboolean ofono_voicecallmanager_release_and_answer(OrgOfonoVoiceCallManager *);
+gboolean ofono_voicecallmanager_swap_calls(OrgOfonoVoiceCallManager *);
+gchar **ofono_voicecallmanager_create_multiparty(OrgOfonoVoiceCallManager *);
diff --git a/binding/telephony-binding.c b/binding/telephony-binding.c
index 10c00fc..9e47c76 100644
--- a/binding/telephony-binding.c
+++ b/binding/telephony-binding.c
@@ -30,15 +30,25 @@
#define OFONO_MODEM_INTERFACE "org.ofono.Modem"
static OrgOfonoVoiceCallManager *vcm;
-static OrgOfonoVoiceCall *incoming_call, *voice_call;
+static OrgOfonoVoiceCall *incoming_call;
static afb_event_t call_state_changed_event;
static afb_event_t dialing_call_event;
static afb_event_t incoming_call_event;
+static afb_event_t waiting_call_event;
static afb_event_t terminated_call_event;
static afb_event_t online_event;
static afb_event_t battery_event;
static afb_event_t signal_event;
+static GList *voice_calls = NULL;
+
+static void remover(gpointer data, gchar *path) {
+ if (!g_strcmp0(path, g_dbus_proxy_get_object_path(G_DBUS_PROXY((OrgOfonoVoiceCall*)data)))) {
+ ofono_voicecall_free((OrgOfonoVoiceCall*)data);
+ voice_calls = g_list_remove(voice_calls, (gconstpointer)data);
+ }
+}
+
static void dial(afb_req_t request)
{
struct json_object *query, *val;
@@ -48,7 +58,7 @@ static void dial(afb_req_t request)
json_object_object_get_ex(query, "value", &val);
if (json_object_is_type(val, json_type_string)) {
number = json_object_get_string(val);
- if (voice_call) {
+ if (voice_calls) {
AFB_ERROR("dial: cannot dial with active call");
afb_req_fail(request, "active call", NULL);
} else {
@@ -68,7 +78,7 @@ static void dial(afb_req_t request)
static void last_dial(afb_req_t request)
{
- if (voice_call) {
+ if (voice_calls) {
AFB_ERROR("dial: cannot dial with active call");
afb_req_fail(request, "active call", NULL);
} else {
@@ -85,7 +95,7 @@ static void send_tones(afb_req_t request)
{
const char *value = afb_req_value(request, "value");
- if (!voice_call) {
+ if (!voice_calls) {
AFB_ERROR("send_tones: cannot send tone without active call");
afb_req_fail(request, "there is no active call", NULL);
} else {
@@ -98,19 +108,43 @@ static void send_tones(afb_req_t request)
}
}
-static void hangup(afb_req_t request)
+static void hangup_all (afb_req_t request)
{
- if (voice_call) {
- AFB_DEBUG("Hangup voice call\n");
- ofono_voicecall_hangup(voice_call);
- afb_req_success(request, NULL, NULL);
- } else if (incoming_call) {
- AFB_DEBUG("Reject incoming call\n");
- ofono_voicecall_hangup(incoming_call);
- afb_req_success(request, NULL, NULL);
+ if (!voice_calls) {
+ AFB_ERROR("hangup_all: cannot hang up without active call");
+ afb_req_fail(request, "there is no active call", NULL);
} else {
+ ofono_voicecallmanager_hangup_all(vcm);
+ afb_req_success(request, NULL, NULL);
+ }
+}
+
+static void hangup(afb_req_t request)
+{
+ const char* value = afb_req_value(request, "id");
+ const gchar *modem = ofono_manager_get_default_modem_path();
+ gchar *op = g_strconcat(modem, "/" , value, NULL);
+ if (g_list_length(voice_calls) > 0) {
+ GList *list;
+ for (list = voice_calls; list != NULL; list = list->next)
+ {
+ if (!g_strcmp0(op, g_dbus_proxy_get_object_path(G_DBUS_PROXY((OrgOfonoVoiceCall*)list->data)))) {
+ AFB_ERROR("object path = %s", g_dbus_proxy_get_object_path(G_DBUS_PROXY((OrgOfonoVoiceCall*)list->data)));
+ ofono_voicecall_hangup((OrgOfonoVoiceCall*)list->data);
+ afb_req_success(request, NULL, NULL);
+ g_free(op);
+ return;
+ }
+ }
+ AFB_ERROR("Hangup: Invalid ID");
+ afb_req_fail(request, "Invalid ID", NULL);
+ g_free(op);
+ return;
+ }
+ else {
AFB_ERROR("Hangup: no active call");
afb_req_fail(request, "failed hangup", NULL);
+ return;
}
}
@@ -118,13 +152,86 @@ static void answer(afb_req_t request)
{
if (incoming_call) {
AFB_DEBUG("Answer voice call\n");
- voice_call = incoming_call;
- ofono_voicecall_answer(voice_call);
+ voice_calls = g_list_append(voice_calls, (gpointer)incoming_call);
+ ofono_voicecall_answer(incoming_call);
+ ofono_voicecall_free(incoming_call);
+ incoming_call = NULL;
} else {
AFB_ERROR("Answer: no incoming call");
}
}
+static void hangup_multiparty(afb_req_t request)
+{
+ if (g_list_length(voice_calls) < 2) {
+ afb_req_fail(request, "failed hangup multiparty", NULL);
+ } else {
+ ofono_voicecallmanager_hangup_multiparty(vcm);
+ afb_req_success(request, NULL, NULL);
+ }
+}
+
+static void create_multiparty(afb_req_t request)
+{
+ gchar **reply = NULL;
+ if (g_list_length(voice_calls) > 1) {
+ reply = ofono_voicecallmanager_create_multiparty(vcm);
+ if (reply)
+ afb_req_success(request, NULL, NULL);
+ else
+ afb_req_fail(request, "failed create multiparty", NULL);
+ }
+ else {
+ AFB_ERROR("Create MultiParty: It should be greater than 1 active call");
+ afb_req_fail(request, "failed create multiparty", NULL);
+ }
+}
+
+static void hold_and_answer(afb_req_t request)
+{
+ if (g_list_length(voice_calls) > 1) {
+ if (ofono_voicecallmanager_hold_and_answer(vcm)) {
+ afb_req_success(request, NULL, NULL);
+ } else {
+ AFB_ERROR("hold_and_answer: failed");
+ afb_req_fail(request, "failed hold and answer", NULL);
+ }
+ } else {
+ AFB_ERROR("hold_and_answer: cannot hold and answer without waiting call");
+ afb_req_fail(request, "no waiting call", NULL);
+ }
+}
+
+static void release_and_answer(afb_req_t request)
+{
+ if (g_list_length(voice_calls) > 1) {
+ if (ofono_voicecallmanager_release_and_answer(vcm)) {
+ afb_req_success(request, NULL, NULL);
+ } else {
+ AFB_ERROR("release_and_answer: failed to release and answer\n");
+ afb_req_fail(request, "failed release and answer", NULL);
+ }
+ } else {
+ AFB_ERROR("release_and_answer: cannot release and answer without waiting call");
+ afb_req_fail(request, "does not exist waiting call", NULL);
+ }
+}
+
+static void swap_calls(afb_req_t request)
+{
+ if (g_list_length(voice_calls) > 1) {
+ if (ofono_voicecallmanager_swap_calls(vcm)) {
+ afb_req_success(request, NULL, NULL);
+ } else {
+ AFB_ERROR("dial: failed to swap calls\n");
+ afb_req_fail(request, "failed swap_calls", NULL);
+ }
+ } else {
+ AFB_ERROR("swap: there is no waiting call");
+ afb_req_fail(request, "swap calls", NULL);
+ }
+}
+
static void get_battery_level(afb_req_t request)
{
const gchar *device;
@@ -171,6 +278,8 @@ static void subscribe(afb_req_t request)
afb_req_subscribe(request, dialing_call_event);
} else if (!strcasecmp(value, "incomingCall")) {
afb_req_subscribe(request, incoming_call_event);
+ } else if (!strcasecmp(value, "waitingCall")) {
+ afb_req_subscribe(request, waiting_call_event);
} else if (!strcasecmp(value, "terminatedCall")) {
afb_req_subscribe(request, terminated_call_event);
} else if (!strcasecmp(value, "battery")) {
@@ -204,6 +313,8 @@ static void unsubscribe(afb_req_t request)
afb_req_unsubscribe(request, dialing_call_event);
} else if (!strcasecmp(value, "incomingCall")) {
afb_req_unsubscribe(request, incoming_call_event);
+ } else if (!strcasecmp(value, "waitingCall")) {
+ afb_req_unsubscribe(request, waiting_call_event);
} else if (!strcasecmp(value, "terminatedCall")) {
afb_req_unsubscribe(request, terminated_call_event);
} else {
@@ -231,6 +342,7 @@ static void incoming_call_cb(OrgOfonoVoiceCallManager *manager, gchar *op, gchar
json_object_object_add(call_info, "clip", json_object_new_string(clip));
afb_event_push(incoming_call_event, call_info);
incoming_call = ofono_voicecall_new(op, call_state_changed_cb);
+ voice_calls = g_list_append(voice_calls, (gpointer)incoming_call);
}
static void dialing_call_cb(OrgOfonoVoiceCallManager *manager, gchar *op, gchar *colp)
@@ -240,18 +352,22 @@ static void dialing_call_cb(OrgOfonoVoiceCallManager *manager, gchar *op, gchar
call_info = json_object_new_object();
json_object_object_add(call_info, "colp", json_object_new_string(colp));
afb_event_push(dialing_call_event, call_info);
- voice_call = ofono_voicecall_new(op, call_state_changed_cb);
+ voice_calls = g_list_append(voice_calls, (gpointer)ofono_voicecall_new(op, call_state_changed_cb));
+}
+
+static void waiting_call_cb(OrgOfonoVoiceCallManager *manager, gchar *op, gchar *colp)
+{
+ struct json_object *call_info;
+ call_info = json_object_new_object();
+ json_object_object_add(call_info, "colp", json_object_new_string(colp));
+ afb_event_push(waiting_call_event, call_info);
+ voice_calls = g_list_append(voice_calls, (gpointer)ofono_voicecall_new(op, call_state_changed_cb));
}
static void terminated_call_cb(OrgOfonoVoiceCallManager *manager, gchar *op)
{
- if (incoming_call) {
- ofono_voicecall_free(incoming_call);
- incoming_call = NULL;
- } else if (voice_call) {
- ofono_voicecall_free(voice_call);
- }
- voice_call = NULL;
+ if (g_list_length(voice_calls) > 0)
+ g_list_foreach(voice_calls, (GFunc)remover, op);
afb_event_push(terminated_call_event, NULL);
}
@@ -271,6 +387,7 @@ static int ofono_init_default_modem(void)
vcm = ofono_voicecallmanager_init(modem_path,
incoming_call_cb,
dialing_call_cb,
+ waiting_call_cb,
terminated_call_cb);
if (!vcm) {
AFB_ERROR("failed to initialize voice call manager\n");
@@ -455,6 +572,7 @@ static int ofono_init(afb_api_t api)
call_state_changed_event = afb_daemon_make_event("callStateChanged");
dialing_call_event = afb_daemon_make_event("dialingCall");
incoming_call_event = afb_daemon_make_event("incomingCall");
+ waiting_call_event = afb_daemon_make_event("waitingCall");
terminated_call_event = afb_daemon_make_event("terminatedCall");
online_event = afb_daemon_make_event("online");
battery_event = afb_daemon_make_event("battery");
@@ -492,10 +610,34 @@ static const afb_verb_t verbs[]= {
.callback = hangup,
},
{
+ .verb = "hangup_all",
+ .callback = hangup_all,
+ },
+ {
.verb = "answer",
.callback = answer,
},
{
+ .verb = "hangup_multiparty",
+ .callback = hangup_multiparty,
+ },
+ {
+ .verb = "create_multiparty",
+ .callback = create_multiparty,
+ },
+ {
+ .verb = "swap_calls",
+ .callback = swap_calls,
+ },
+ {
+ .verb = "hold_and_answer",
+ .callback = hold_and_answer,
+ },
+ {
+ .verb = "release_and_answer",
+ .callback = release_and_answer,
+ },
+ {
.verb = "get_battery_level",
.callback = get_battery_level,
},