aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsaman <mahmoudi.saman1@gmail.com>2021-02-07 15:01:20 +0330
committerSaman Mahmoodi <mahmoudi.saman1@gmail.com>2021-03-13 15:00:29 +0330
commit8987ae42114a8b15522734e40d117fd061e7bf3b (patch)
tree78ceae43519a246d5f5f559572116fc9da833271
parent4739f747c8fbdeda94a400122651862cfdb522b7 (diff)
Add call waiting/hold featureslamprey_11.91.0lamprey/11.91.011.91.0
I have developed most features that needed for handling waiting call response and hold call response. Also I have changed hangup verb due to have multiple active call. The changes are including getting argument for hangup specific call. For correctly working this feature you should subscribe waitingCall event as in README.md. Signed-off-by: saman <mahmoudi.saman1@gmail.com> Change-Id: I84c601ddd6f27d8d8e7b6d8c338ea04a48240447
-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,
},