diff options
-rw-r--r-- | README.md | 11 | ||||
-rw-r--r-- | binding/gdbus/ofono_voicecallmanager.c | 88 | ||||
-rw-r--r-- | binding/gdbus/ofono_voicecallmanager.h | 8 | ||||
-rw-r--r-- | binding/telephony-binding.c | 188 |
4 files changed, 269 insertions, 26 deletions
@@ -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, }, |