975b33952e
This patchset is based on the branch on the sysmocom.de git, https://git.sysmocom.de/ofono/log/?h=lynxis/voicecall The original branch was based on old ofono so this patches are manually merged to ofono 1.21 and tested on debian initially.
467 lines
14 KiB
Diff
467 lines
14 KiB
Diff
From 2ae2366c262a15e4f3269afd9c80ddf06c1b9b46 Mon Sep 17 00:00:00 2001
|
|
From: Alexander Couzens <lynxis@fe80.eu>
|
|
Date: Tue, 25 Jul 2017 12:42:29 +0200
|
|
Subject: [PATCH 06/17] add call-list helper to manage voice call lists
|
|
|
|
Many drivers asks the modem for a complete call list of current calls.
|
|
These list of calls can be feeded into call-list which parse the
|
|
list and notify ofono for new calls.
|
|
---
|
|
Makefile.am | 13 ++-
|
|
include/call-list.h | 38 ++++++++
|
|
src/call-list.c | 114 ++++++++++++++++++++++++
|
|
unit/test-call-list.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
4 files changed, 399 insertions(+), 3 deletions(-)
|
|
create mode 100644 include/call-list.h
|
|
create mode 100644 src/call-list.c
|
|
create mode 100644 unit/test-call-list.c
|
|
|
|
Index: ofono-1.21/Makefile.am
|
|
===================================================================
|
|
--- ofono-1.21.orig/Makefile.am
|
|
+++ ofono-1.21/Makefile.am
|
|
@@ -22,7 +22,7 @@ pkginclude_HEADERS = include/log.h inclu
|
|
include/private-network.h include/cdma-netreg.h \
|
|
include/cdma-provision.h include/handsfree.h \
|
|
include/handsfree-audio.h include/siri.h \
|
|
- include/netmon.h include/lte.h
|
|
+ include/netmon.h include/lte.h include/call-list.h
|
|
|
|
nodist_pkginclude_HEADERS = include/version.h
|
|
|
|
@@ -630,7 +630,7 @@ src_ofonod_SOURCES = $(builtin_sources)
|
|
src/cdma-provision.c src/handsfree.c \
|
|
src/handsfree-audio.c src/bluetooth.h \
|
|
src/hfp.h src/siri.c \
|
|
- src/netmon.c src/lte.c \
|
|
+ src/netmon.c src/lte.c src/call-list.c \
|
|
src/netmonagent.c src/netmonagent.h
|
|
|
|
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
|
@@ -807,7 +807,8 @@ unit_tests = unit/test-common unit/test-
|
|
unit/test-rilmodem-cs \
|
|
unit/test-rilmodem-sms \
|
|
unit/test-rilmodem-cb \
|
|
- unit/test-rilmodem-gprs
|
|
+ unit/test-rilmodem-gprs \
|
|
+ unit/test-call-list
|
|
|
|
noinst_PROGRAMS = $(unit_tests) \
|
|
unit/test-sms-root unit/test-mux unit/test-caif
|
|
@@ -849,6 +850,12 @@ unit_test_sms_root_SOURCES = unit/test-s
|
|
unit_test_sms_root_LDADD = @GLIB_LIBS@
|
|
unit_objects += $(unit_test_sms_root_OBJECTS)
|
|
|
|
+unit_test_call_list_SOURCES = \
|
|
+ src/common.c src/util.c src/log.c \
|
|
+ src/call-list.c unit/test-call-list.c
|
|
+unit_test_call_list_LDADD = @GLIB_LIBS@ -ldl
|
|
+unit_objects += $(unit_test_call_list_OBJECTS)
|
|
+
|
|
unit_test_mux_SOURCES = unit/test-mux.c $(gatchat_sources)
|
|
unit_test_mux_LDADD = @GLIB_LIBS@
|
|
unit_objects += $(unit_test_mux_OBJECTS)
|
|
Index: ofono-1.21/include/call-list.h
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ ofono-1.21/include/call-list.h
|
|
@@ -0,0 +1,38 @@
|
|
+/*
|
|
+ *
|
|
+ * oFono - Open Source Telephony
|
|
+ *
|
|
+ * Copyright (C) 2017 Alexander Couzens <lynxis@fe80.eu>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <glib.h>
|
|
+
|
|
+struct ofono_voicecall;
|
|
+struct ofono_phone_number;
|
|
+
|
|
+/*
|
|
+ * Can be called by the driver in the dialing callback,
|
|
+ * when the new call id already known
|
|
+ */
|
|
+void ofono_call_list_dial_callback(struct ofono_voicecall *vc,
|
|
+ GSList **call_list,
|
|
+ const struct ofono_phone_number *ph,
|
|
+ int call_id);
|
|
+
|
|
+/*
|
|
+ * Called with a list of known calls e.g. clcc.
|
|
+ * Call list will take ownership of all ofono call within the calls.
|
|
+ */
|
|
+void ofono_call_list_notify(struct ofono_voicecall *vc,
|
|
+ GSList **call_list,
|
|
+ GSList *calls);
|
|
Index: ofono-1.21/src/call-list.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ ofono-1.21/src/call-list.c
|
|
@@ -0,0 +1,114 @@
|
|
+/*
|
|
+ *
|
|
+ * oFono - Open Source Telephony
|
|
+ *
|
|
+ * Copyright (C) 2017 Alexander Couzens <lynxis@fe80.eu>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <glib.h>
|
|
+
|
|
+#include "common.h"
|
|
+
|
|
+#include <ofono/types.h>
|
|
+#include <ofono/log.h>
|
|
+#include <ofono/voicecall.h>
|
|
+#include <ofono/call-list.h>
|
|
+
|
|
+#include <string.h>
|
|
+
|
|
+void ofono_call_list_dial_callback(struct ofono_voicecall *vc,
|
|
+ GSList **call_list,
|
|
+ const struct ofono_phone_number *ph,
|
|
+ int call_id)
|
|
+{
|
|
+ GSList *list;
|
|
+ struct ofono_call *call;
|
|
+
|
|
+ /* list_notify could be triggered before this call back is handled */
|
|
+ list = g_slist_find_custom(*call_list,
|
|
+ GINT_TO_POINTER(call_id),
|
|
+ ofono_call_compare_by_id);
|
|
+
|
|
+ if (list && list->data) {
|
|
+ call = list->data;
|
|
+ DBG("Call id %d already known. In state %s(%d)",
|
|
+ call_id, ofono_call_status_to_string(call->status),
|
|
+ call->status);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ call = g_new0(struct ofono_call, 1);
|
|
+ call->id = call_id;
|
|
+
|
|
+ memcpy(&call->called_number, ph, sizeof(*ph));
|
|
+ call->direction = CALL_DIRECTION_MOBILE_ORIGINATED;
|
|
+ call->status = CALL_STATUS_DIALING;
|
|
+ call->type = 0; /* voice */
|
|
+
|
|
+ *call_list = g_slist_insert_sorted(*call_list,
|
|
+ call,
|
|
+ ofono_call_compare);
|
|
+ ofono_voicecall_notify(vc, call);
|
|
+}
|
|
+
|
|
+void ofono_call_list_notify(struct ofono_voicecall *vc,
|
|
+ GSList **call_list,
|
|
+ GSList *calls)
|
|
+{
|
|
+ GSList *old_calls = *call_list;
|
|
+ GSList *new_calls = calls;
|
|
+ struct ofono_call *new_call, *old_call;
|
|
+
|
|
+ while (old_calls || new_calls) {
|
|
+ old_call = old_calls ? old_calls->data : NULL;
|
|
+ new_call = new_calls ? new_calls->data : NULL;
|
|
+
|
|
+ /* we drop disconnected calls and treat them as not existent */
|
|
+ if (new_call && new_call->status == CALL_STATUS_DISCONNECTED) {
|
|
+ new_calls = new_calls->next;
|
|
+ calls = g_slist_remove(calls, new_call);
|
|
+ g_free(new_call);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (old_call &&
|
|
+ (new_call == NULL ||
|
|
+ (new_call->id > old_call->id))) {
|
|
+ ofono_voicecall_disconnected(
|
|
+ vc,
|
|
+ old_call->id,
|
|
+ OFONO_DISCONNECT_REASON_UNKNOWN,
|
|
+ NULL);
|
|
+ old_calls = old_calls->next;
|
|
+ } else if (new_call &&
|
|
+ (old_call == NULL ||
|
|
+ (new_call->id < old_call->id))) {
|
|
+
|
|
+ /* new call, signal it */
|
|
+ if (new_call->type == 0)
|
|
+ ofono_voicecall_notify(vc, new_call);
|
|
+
|
|
+ new_calls = new_calls->next;
|
|
+ } else {
|
|
+ if (memcmp(new_call, old_call, sizeof(*new_call))
|
|
+ && new_call->type == 0)
|
|
+ ofono_voicecall_notify(vc, new_call);
|
|
+
|
|
+ new_calls = new_calls->next;
|
|
+ old_calls = old_calls->next;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ g_slist_free_full(*call_list, g_free);
|
|
+ *call_list = calls;
|
|
+}
|
|
Index: ofono-1.21/unit/test-call-list.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ ofono-1.21/unit/test-call-list.c
|
|
@@ -0,0 +1,237 @@
|
|
+/*
|
|
+ *
|
|
+ * oFono - Open Source Telephony
|
|
+ *
|
|
+ * Copyright (C) 2017 Alexander Couzens <lynxis@fe80.eu>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ */
|
|
+
|
|
+
|
|
+#include <glib.h>
|
|
+#include <string.h>
|
|
+
|
|
+
|
|
+#include "../src/common.h"
|
|
+#include <ofono/types.h>
|
|
+#include <ofono/call-list.h>
|
|
+
|
|
+struct voicecall {
|
|
+};
|
|
+
|
|
+struct notified {
|
|
+ unsigned int id;
|
|
+ enum call_status status;
|
|
+};
|
|
+
|
|
+static struct notified notified_list[32];
|
|
+static int notified_idx;
|
|
+static int notified_check;
|
|
+
|
|
+void reset_notified(void)
|
|
+{
|
|
+ notified_idx = 0;
|
|
+ notified_check = 0;
|
|
+ memset(¬ified_list, 0, sizeof(notified_list));
|
|
+}
|
|
+
|
|
+void ofono_voicecall_notify(struct ofono_voicecall *vc,
|
|
+ struct ofono_call *call)
|
|
+{
|
|
+ notified_list[notified_idx].id = call->id;
|
|
+ notified_list[notified_idx].status = call->status;
|
|
+ notified_idx++;
|
|
+}
|
|
+
|
|
+void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id,
|
|
+ enum ofono_disconnect_reason reason,
|
|
+ const struct ofono_error *error)
|
|
+{
|
|
+ notified_list[notified_idx].id = id;
|
|
+ notified_list[notified_idx].status = CALL_STATUS_DISCONNECTED;
|
|
+ notified_idx++;
|
|
+}
|
|
+
|
|
+static GSList *create_call(
|
|
+ GSList *calls,
|
|
+ unsigned int id,
|
|
+ enum call_status status,
|
|
+ enum call_direction direction)
|
|
+{
|
|
+ struct ofono_call *call = g_new0(struct ofono_call, 1);
|
|
+
|
|
+ call->id = id;
|
|
+ call->status = status;
|
|
+ call->direction = direction;
|
|
+
|
|
+ calls = g_slist_insert_sorted(calls, call, ofono_call_compare);
|
|
+
|
|
+ return calls;
|
|
+}
|
|
+
|
|
+static void assert_notified(unsigned int call_id, int call_status)
|
|
+{
|
|
+ g_assert(notified_idx >= notified_check);
|
|
+ g_assert(notified_list[notified_check].id == call_id);
|
|
+ g_assert(notified_list[notified_check].status == call_status);
|
|
+
|
|
+ notified_check++;
|
|
+}
|
|
+
|
|
+static void test_notify_disconnected(void)
|
|
+{
|
|
+ struct ofono_voicecall *vc = NULL;
|
|
+ struct ofono_phone_number ph;
|
|
+ GSList *call_list;
|
|
+ GSList *calls;
|
|
+
|
|
+ strcpy(ph.number, "004888123456");
|
|
+ ph.type = 0;
|
|
+
|
|
+ /* reset test */
|
|
+ reset_notified();
|
|
+ call_list = NULL;
|
|
+
|
|
+ /* fill disconnected call*/
|
|
+ calls = create_call(NULL, 1, CALL_STATUS_DISCONNECTED,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ ofono_call_list_notify(vc, &call_list, calls);
|
|
+
|
|
+ /* incoming call */
|
|
+ calls = create_call(NULL, 1, CALL_STATUS_DISCONNECTED,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ calls = create_call(calls, 1, CALL_STATUS_ALERTING,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ ofono_call_list_notify(vc, &call_list, calls);
|
|
+
|
|
+ /* answer call */
|
|
+ calls = create_call(NULL, 1, CALL_STATUS_ACTIVE,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ calls = create_call(calls, 1, CALL_STATUS_DISCONNECTED,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ ofono_call_list_notify(vc, &call_list, calls);
|
|
+
|
|
+ /* another call waiting */
|
|
+ calls = create_call(NULL, 1, CALL_STATUS_DISCONNECTED,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ calls = create_call(calls, 1, CALL_STATUS_ACTIVE,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ calls = create_call(calls, 2, CALL_STATUS_DISCONNECTED,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ calls = create_call(calls, 2, CALL_STATUS_WAITING,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ calls = create_call(calls, 2, CALL_STATUS_DISCONNECTED,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ ofono_call_list_notify(vc, &call_list, calls);
|
|
+
|
|
+ /* end all calls */
|
|
+ ofono_call_list_notify(vc, &call_list, NULL);
|
|
+
|
|
+ /* verify call history */
|
|
+ assert_notified(1, CALL_STATUS_ALERTING);
|
|
+ assert_notified(1, CALL_STATUS_ACTIVE);
|
|
+ assert_notified(2, CALL_STATUS_WAITING);
|
|
+ assert_notified(1, CALL_STATUS_DISCONNECTED);
|
|
+ assert_notified(2, CALL_STATUS_DISCONNECTED);
|
|
+
|
|
+ g_assert(notified_check == notified_idx);
|
|
+ g_slist_free_full(call_list, g_free);
|
|
+}
|
|
+
|
|
+static void test_notify(void)
|
|
+{
|
|
+ struct ofono_voicecall *vc = NULL;
|
|
+ struct ofono_phone_number ph;
|
|
+ GSList *call_list;
|
|
+ GSList *calls;
|
|
+
|
|
+ strcpy(ph.number, "004888123456");
|
|
+ ph.type = 0;
|
|
+
|
|
+ /* reset test */
|
|
+ reset_notified();
|
|
+ call_list = NULL;
|
|
+
|
|
+ /* incoming call */
|
|
+ calls = create_call(NULL, 1, CALL_STATUS_ALERTING,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ ofono_call_list_notify(vc, &call_list, calls);
|
|
+
|
|
+ /* answer call */
|
|
+ calls = create_call(NULL, 1, CALL_STATUS_ACTIVE,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ ofono_call_list_notify(vc, &call_list, calls);
|
|
+
|
|
+ /* another call waiting */
|
|
+ calls = create_call(NULL, 1, CALL_STATUS_ACTIVE,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ calls = create_call(calls, 2, CALL_STATUS_WAITING,
|
|
+ CALL_DIRECTION_MOBILE_TERMINATED);
|
|
+ ofono_call_list_notify(vc, &call_list, calls);
|
|
+
|
|
+ /* end all calls */
|
|
+ ofono_call_list_notify(vc, &call_list, NULL);
|
|
+
|
|
+ /* verify call history */
|
|
+ assert_notified(1, CALL_STATUS_ALERTING);
|
|
+ assert_notified(1, CALL_STATUS_ACTIVE);
|
|
+ assert_notified(2, CALL_STATUS_WAITING);
|
|
+ assert_notified(1, CALL_STATUS_DISCONNECTED);
|
|
+ assert_notified(2, CALL_STATUS_DISCONNECTED);
|
|
+
|
|
+ g_assert(notified_check == notified_idx);
|
|
+ g_slist_free_full(call_list, g_free);
|
|
+}
|
|
+
|
|
+static void test_dial_callback(void)
|
|
+{
|
|
+ struct ofono_voicecall *vc = NULL;
|
|
+ struct ofono_phone_number ph;
|
|
+ struct ofono_call *call;
|
|
+ GSList *call_list, *calls;
|
|
+
|
|
+ /* reset test */
|
|
+ reset_notified();
|
|
+ call_list = NULL;
|
|
+
|
|
+ strcpy(ph.number, "0099301234567890");
|
|
+ ph.type = 0;
|
|
+
|
|
+ /* check if a call gets added to the call_list */
|
|
+ ofono_call_list_dial_callback(vc, &call_list, &ph, 33);
|
|
+
|
|
+ call = call_list->data;
|
|
+ g_assert(strcmp(call->called_number.number, ph.number) == 0);
|
|
+ g_slist_free_full(call_list, g_free);
|
|
+
|
|
+ /* check when notify is faster than dial_callback */
|
|
+ call_list = NULL;
|
|
+ calls = create_call(NULL, 1, CALL_STATUS_DIALING,
|
|
+ CALL_DIRECTION_MOBILE_ORIGINATED);
|
|
+ ofono_call_list_notify(vc, &call_list, calls);
|
|
+ ofono_call_list_dial_callback(vc, &call_list, &ph, 1);
|
|
+ call = call_list->data;
|
|
+ g_assert(call_list->next == NULL);
|
|
+ g_slist_free_full(call_list, g_free);
|
|
+
|
|
+ call_list = NULL;
|
|
+}
|
|
+
|
|
+int main(int argc, char **argv)
|
|
+{
|
|
+ g_test_init(&argc, &argv, NULL);
|
|
+
|
|
+ g_test_add_func("/test-call-list/test_notify", test_notify);
|
|
+ g_test_add_func("/test-call-list/test_notify_disconnected",
|
|
+ test_notify_disconnected);
|
|
+ g_test_add_func("/test-call-list/dial_callback", test_dial_callback);
|
|
+ return g_test_run();
|
|
+}
|