[PATCH 00/10] Update telephony-ofono driver

STALE5688d

12 messages, 2 authors, 2011-01-06 · open the first message on its own page

[PATCH 00/10] Update telephony-ofono driver

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:37

From: Luiz Augusto von Dentz <redacted>

This patches update the ofono backend so it can be used with recent
versions of ofono (> 0.28), it can be tested by compiling bluetoothd with
--with-telephony=ofono

Since the hfp doesn't really support multiple modems, at least not in the
same record/connection, the driver will pick the first modem that has
org.ofono.NetworkRegistration since that is what hfp expect as indicator.

Calls are only picked/indicated if they belong to the modem in use
otherwise they are ignored.

Note that there is still a plan to integrate hfp inside ofono and this
changes doesn't change anything, it basically add the possibility to use
ofono with BlueZ 4.x since 5.x probably will change this entirely.

Luiz Augusto von Dentz (10):
  telephony-ofono: notify alerting calls when headset connects
  telephony-ofono: fix not being able to answer alerting/waiting calls
  telephony-ofono: fix not setting originating when status property
    changes
  telephony-ofono: make use of GetModems method
  telephony-ofono: make use of GetCalls method
  telephony-ofono: fix not canceling pending calls on exit
  telephony-ofono: simplify watches handling logic
  telephony-ofono: handle ofono appearing/disappearing from bus
  telephony-ofono: add handling for Modem.Interfaces property
  telephony-ofono: fix not updating indicators when a call is removed

 audio/telephony-ofono.c |  916 +++++++++++++++++++++++++++++++----------------
 1 files changed, 604 insertions(+), 312 deletions(-)

[PATCH 01/10] telephony-ofono: notify alerting calls when headset connects

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:38

From: Luiz Augusto von Dentz <redacted>

---
 audio/telephony-ofono.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index 00c3f6e..babf38f 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -128,9 +128,32 @@ static struct voice_call *find_vc_with_status(int status)
 	return NULL;
 }
 
+static int number_type(const char *number)
+{
+	if (number == NULL)
+		return NUMBER_TYPE_TELEPHONY;
+
+	if (number[0] == '+' || strncmp(number, "00", 2) == 0)
+		return NUMBER_TYPE_INTERNATIONAL;
+
+	return NUMBER_TYPE_TELEPHONY;
+}
+
 void telephony_device_connected(void *telephony_device)
 {
+	struct voice_call *coming;
+
 	DBG("telephony-ofono: device %p connected", telephony_device);
+
+	coming = find_vc_with_status(CALL_STATUS_ALERTING);
+	if (coming) {
+		if (find_vc_with_status(CALL_STATUS_ACTIVE))
+			telephony_call_waiting_ind(coming->number,
+						number_type(coming->number));
+		else
+			telephony_incoming_call_ind(coming->number,
+						number_type(coming->number));
+	}
 }
 
 void telephony_device_disconnected(void *telephony_device)
-- 
1.7.1

[PATCH 02/10] telephony-ofono: fix not being able to answer alerting/waiting calls

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:39

From: Luiz Augusto von Dentz <redacted>

---
 audio/telephony-ofono.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index babf38f..4f69673 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -263,9 +263,16 @@ void telephony_terminate_call_req(void *telephony_device)
 
 void telephony_answer_call_req(void *telephony_device)
 {
-	struct voice_call *vc = find_vc_with_status(CALL_STATUS_INCOMING);
+	struct voice_call *vc;
 	int ret;
 
+	vc = find_vc_with_status(CALL_STATUS_INCOMING);
+	if (!vc)
+		vc = find_vc_with_status(CALL_STATUS_ALERTING);
+
+	if (!vc)
+		vc = find_vc_with_status(CALL_STATUS_WAITING);
+
 	if (!vc) {
 		telephony_answer_call_rsp(telephony_device,
 					CME_ERROR_NOT_ALLOWED);
-- 
1.7.1

[PATCH 03/10] telephony-ofono: fix not setting originating when status property changes

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:40

From: Luiz Augusto von Dentz <redacted>

---
 audio/telephony-ofono.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index 4f69673..720b32d 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -834,6 +834,7 @@ static gboolean handle_vc_property_changed(DBusConnection *conn,
 					"callsetup", EV_CALLSETUP_ALERTING);
 			vc->status = CALL_STATUS_ALERTING;
 			DBG("vc status is CALL_STATUS_ALERTING");
+			vc->originating = TRUE;
 		} else if (g_str_equal(state, "incoming")) {
 			/* state change from waiting to incoming */
 			telephony_update_indicator(ofono_indicators,
@@ -842,6 +843,7 @@ static gboolean handle_vc_property_changed(DBusConnection *conn,
 						NUMBER_TYPE_TELEPHONY);
 			vc->status = CALL_STATUS_INCOMING;
 			DBG("vc status is CALL_STATUS_INCOMING");
+			vc->originating = FALSE;
 		}
 	}
 
-- 
1.7.1

[PATCH 04/10] telephony-ofono: make use of GetModems method

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:41

From: Luiz Augusto von Dentz <redacted>

Ofono API has changed, modem list is no longer a property
---
 audio/telephony-ofono.c |  271 +++++++++++++++++++++++++++++-----------------
 1 files changed, 171 insertions(+), 100 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index 720b32d..b96c504 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -67,6 +67,8 @@ static GSList *calls = NULL;
 static guint registration_watch = 0;
 static guint voice_watch = 0;
 static guint device_watch = 0;
+static guint modem_added_watch = 0;
+static guint modem_removed_watch = 0;
 
 /* HAL battery namespace key values */
 static int battchg_cur = -1;    /* "battery.charge_level.current" */
@@ -454,13 +456,13 @@ static gboolean iter_get_basic_args(DBusMessageIter *iter,
 	return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
 }
 
-static void handle_registration_property(const char *property, DBusMessageIter sub)
+static void handle_network_property(const char *property, DBusMessageIter *variant)
 {
 	const char *status, *operator;
 	unsigned int signals_bar;
 
 	if (g_str_equal(property, "Status")) {
-		dbus_message_iter_get_basic(&sub, &status);
+		dbus_message_iter_get_basic(variant, &status);
 		DBG("Status is %s", status);
 		if (g_str_equal(status, "registered")) {
 			net.status = NETWORK_REG_STATUS_HOME;
@@ -481,13 +483,13 @@ static void handle_registration_property(const char *property, DBusMessageIter s
 			telephony_update_indicator(ofono_indicators,
 						"service", EV_SERVICE_NONE);
 		}
-	} else if (g_str_equal(property, "Operator")) {
-		dbus_message_iter_get_basic(&sub, &operator);
+	} else if (g_str_equal(property, "Name")) {
+		dbus_message_iter_get_basic(variant, &operator);
 		DBG("Operator is %s", operator);
 		g_free(net.operator_name);
 		net.operator_name = g_strdup(operator);
 	} else if (g_str_equal(property, "SignalStrength")) {
-		dbus_message_iter_get_basic(&sub, &signals_bar);
+		dbus_message_iter_get_basic(variant, &signals_bar);
 		DBG("SignalStrength is %d", signals_bar);
 		net.signals_bar = signals_bar;
 		telephony_update_indicator(ofono_indicators, "signal",
@@ -495,16 +497,43 @@ static void handle_registration_property(const char *property, DBusMessageIter s
 	}
 }
 
-static void get_registration_reply(DBusPendingCall *call, void *user_data)
+static int parse_network_properties(DBusMessageIter *properties)
 {
-	DBusError err;
-	DBusMessage *reply;
-	DBusMessageIter iter, iter_entry;
 	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
 				AG_FEATURE_REJECT_A_CALL |
 				AG_FEATURE_ENHANCED_CALL_STATUS |
 				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
 
+	while (dbus_message_iter_get_arg_type(properties)
+						== DBUS_TYPE_DICT_ENTRY) {
+		const char *key;
+		DBusMessageIter value, entry;
+
+		dbus_message_iter_recurse(properties, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
+
+		handle_network_property(key, &value);
+
+		dbus_message_iter_next(properties);
+	}
+
+	telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
+								chld_str);
+
+	return 0;
+}
+
+static void get_properties_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusError err;
+	DBusMessage *reply;
+	DBusMessageIter iter, properties;
+	int ret = 0;
+
+	DBG("");
 	reply = dbus_pending_call_steal_reply(call);
 
 	dbus_error_init(&err);
@@ -517,67 +546,47 @@ static void get_registration_reply(DBusPendingCall *call, void *user_data)
 
 	dbus_message_iter_init(reply, &iter);
 
-	/* ARRAY -> ENTRY -> VARIANT */
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in GetProperties return");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &iter_entry);
-
-	if (dbus_message_iter_get_arg_type(&iter_entry)
-					!= DBUS_TYPE_DICT_ENTRY) {
-		error("Unexpected signature in GetProperties return");
+		error("Unexpected signature");
 		goto done;
 	}
 
-	while (dbus_message_iter_get_arg_type(&iter_entry)
-					!= DBUS_TYPE_INVALID) {
-		DBusMessageIter iter_property, sub;
-		char *property;
+	dbus_message_iter_recurse(&iter, &properties);
 
-		dbus_message_iter_recurse(&iter_entry, &iter_property);
-		if (dbus_message_iter_get_arg_type(&iter_property)
-					!= DBUS_TYPE_STRING) {
-			error("Unexpected signature in GetProperties return");
-			goto done;
-		}
-
-		dbus_message_iter_get_basic(&iter_property, &property);
-
-		dbus_message_iter_next(&iter_property);
-		dbus_message_iter_recurse(&iter_property, &sub);
-
-		handle_registration_property(property, sub);
-
-                dbus_message_iter_next(&iter_entry);
-        }
-
-	telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
-								chld_str);
+	ret = parse_network_properties(&properties);
+	if (ret < 0)
+		error("Unable to parse %s.GetProperty reply",
+						OFONO_NETWORKREG_INTERFACE);
 
 done:
 	dbus_message_unref(reply);
 }
 
-static int get_registration_and_signal_status()
+static void modem_added(const char *path)
 {
-	if (!modem_obj_path)
-		return -ENOENT;
+	int ret;
 
-	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-			OFONO_NETWORKREG_INTERFACE,
-			"GetProperties", get_registration_reply,
-			NULL, DBUS_TYPE_INVALID);
+	DBG("%s", path);
+
+	if (modem_obj_path != NULL)
+		return;
+
+	modem_obj_path = g_strdup(path);
+
+	ret = send_method_call(OFONO_BUS_NAME, path,
+				OFONO_NETWORKREG_INTERFACE, "GetProperties",
+				get_properties_reply, NULL, DBUS_TYPE_INVALID);
+	if (ret < 0)
+		error("Unable to send %s.GetProperties",
+						OFONO_NETWORKREG_INTERFACE);
 }
 
-static void list_modem_reply(DBusPendingCall *call, void *user_data)
+static void get_modems_reply(DBusPendingCall *call, void *user_data)
 {
 	DBusError err;
 	DBusMessage *reply;
-	DBusMessageIter iter, iter_entry, iter_property, iter_arrary, sub;
-	char *property, *modem_obj_path_local;
-	int ret;
+	DBusMessageIter iter, entry;
+	const char *path;
 
 	DBG("list_modem_reply is called\n");
 	reply = dbus_pending_call_steal_reply(call);
@@ -593,49 +602,29 @@ static void list_modem_reply(DBusPendingCall *call, void *user_data)
 	dbus_message_iter_init(reply, &iter);
 
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in ListModems return");
+		error("Unexpected signature");
 		goto done;
 	}
 
-	dbus_message_iter_recurse(&iter, &iter_entry);
+	dbus_message_iter_recurse(&iter, &entry);
 
-	if (dbus_message_iter_get_arg_type(&iter_entry)
-					!= DBUS_TYPE_DICT_ENTRY) {
-		error("Unexpected signature in ListModems return 2, %c",
-				dbus_message_iter_get_arg_type(&iter_entry));
+	if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_OBJECT_PATH) {
+		error("Unexpected signature");
 		goto done;
 	}
 
-	dbus_message_iter_recurse(&iter_entry, &iter_property);
-
-	dbus_message_iter_get_basic(&iter_property, &property);
-
-	dbus_message_iter_next(&iter_property);
-	dbus_message_iter_recurse(&iter_property, &iter_arrary);
-	dbus_message_iter_recurse(&iter_arrary, &sub);
-	while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+	dbus_message_iter_get_basic(&entry, &path);
 
-		dbus_message_iter_get_basic(&sub, &modem_obj_path_local);
-		modem_obj_path = g_strdup(modem_obj_path_local);
-		if (modem_obj_path != NULL) {
-			DBG("modem_obj_path is %p, %s\n", modem_obj_path,
-							modem_obj_path);
-			break;
-		}
-		dbus_message_iter_next(&sub);
-	}
+	modem_added(path);
 
-	ret = get_registration_and_signal_status();
-	if (ret < 0)
-		error("get_registration_and_signal_status() failed(%d)", ret);
 done:
 	dbus_message_unref(reply);
 }
 
-static gboolean handle_registration_property_changed(DBusConnection *conn,
+static gboolean handle_network_property_changed(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
-	DBusMessageIter iter, sub;
+	DBusMessageIter iter, variant;
 	const char *property;
 
 	dbus_message_iter_init(msg, &iter);
@@ -650,9 +639,9 @@ static gboolean handle_registration_property_changed(DBusConnection *conn,
 					" the property is %s", property);
 
 	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &sub);
+	dbus_message_iter_recurse(&iter, &variant);
 
-	handle_registration_property(property, sub);
+	handle_network_property(property, &variant);
 
 	return TRUE;
 }
@@ -910,6 +899,70 @@ static gboolean handle_vcmanager_property_changed(DBusConnection *conn,
 	return TRUE;
 }
 
+static gboolean handle_manager_modem_added(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessageIter iter, properties;
+	const char *path;
+
+	if (modem_obj_path != NULL)
+		return TRUE;
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter)
+						!= DBUS_TYPE_OBJECT_PATH) {
+		error("Unexpected signature in %s.%s signal",
+					dbus_message_get_interface(msg),
+					dbus_message_get_member(msg));
+		return TRUE;
+	}
+
+	dbus_message_iter_get_basic(&iter, &path);
+	dbus_message_iter_recurse(&iter, &properties);
+
+	modem_added(path);
+
+	return TRUE;
+}
+
+static void modem_removed(const char *path)
+{
+	if (g_strcmp0(modem_obj_path, path) != 0)
+		return;
+
+	DBG("%s", path);
+
+	g_slist_foreach(calls, (GFunc) vc_free, NULL);
+	g_slist_free(calls);
+	calls = NULL;
+
+	g_free(net.operator_name);
+	net.operator_name = NULL;
+
+	g_free(modem_obj_path);
+	modem_obj_path = NULL;
+}
+
+static gboolean handle_manager_modem_removed(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	const char *path;
+
+	if (!dbus_message_get_args(msg, NULL,
+				DBUS_TYPE_OBJECT_PATH, &path,
+				DBUS_TYPE_INVALID)) {
+		error("Unexpected signature in %s.%s signal",
+					dbus_message_get_interface(msg),
+					dbus_message_get_member(msg));
+		return TRUE;
+	}
+
+	modem_removed(path);
+
+	return TRUE;
+}
+
 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
 {
 	DBusMessage *reply;
@@ -1090,21 +1143,38 @@ int telephony_init(void)
 
 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
-	registration_watch = g_dbus_add_signal_watch(connection, OFONO_BUS_NAME,
-					NULL, OFONO_NETWORKREG_INTERFACE,
-					"PropertyChanged",
-					handle_registration_property_changed,
-					NULL, NULL);
 
-	voice_watch = g_dbus_add_signal_watch(connection, OFONO_BUS_NAME, NULL,
-					OFONO_VCMANAGER_INTERFACE,
-					"PropertyChanged",
-					handle_vcmanager_property_changed,
-					NULL, NULL);
+	registration_watch = g_dbus_add_signal_watch(connection,
+						OFONO_BUS_NAME, NULL,
+						OFONO_NETWORKREG_INTERFACE,
+						"PropertyChanged",
+						handle_network_property_changed,
+						NULL, NULL);
+
+	voice_watch = g_dbus_add_signal_watch(connection,
+						OFONO_BUS_NAME, NULL,
+						OFONO_VCMANAGER_INTERFACE,
+						"PropertyChanged",
+						handle_vcmanager_property_changed,
+						NULL, NULL);
+
+	modem_added_watch = g_dbus_add_signal_watch(connection,
+						OFONO_BUS_NAME, NULL,
+						OFONO_MANAGER_INTERFACE,
+						"ModemAdded",
+						handle_manager_modem_added,
+						NULL, NULL);
+
+	modem_removed_watch = g_dbus_add_signal_watch(connection,
+						OFONO_BUS_NAME, NULL,
+						OFONO_MANAGER_INTERFACE,
+						"ModemRemoved",
+						handle_manager_modem_removed,
+						NULL, NULL);
 
 	ret = send_method_call(OFONO_BUS_NAME, OFONO_PATH,
-				OFONO_MANAGER_INTERFACE, "GetProperties",
-				list_modem_reply, NULL, DBUS_TYPE_INVALID);
+				OFONO_MANAGER_INTERFACE, "GetModems",
+				get_modems_reply, NULL, DBUS_TYPE_INVALID);
 	if (ret < 0)
 		return ret;
 
@@ -1125,17 +1195,18 @@ int telephony_init(void)
 
 void telephony_exit(void)
 {
-	g_free(net.operator_name);
+	DBG("");
 
-	g_free(modem_obj_path);
 	g_free(last_dialed_number);
+	last_dialed_number = NULL;
 
-	g_slist_foreach(calls, (GFunc) vc_free, NULL);
-	g_slist_free(calls);
-	calls = NULL;
+	if (modem_obj_path)
+		modem_removed(modem_obj_path);
 
 	g_dbus_remove_watch(connection, registration_watch);
 	g_dbus_remove_watch(connection, voice_watch);
+	g_dbus_remove_watch(connection, modem_added_watch);
+	g_dbus_remove_watch(connection, modem_removed_watch);
 	g_dbus_remove_watch(connection, device_watch);
 
 	dbus_connection_unref(connection);
-- 
1.7.1

[PATCH 05/10] telephony-ofono: make use of GetCalls method

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:42

From: Luiz Augusto von Dentz <redacted>

---
 audio/telephony-ofono.c |  515 +++++++++++++++++++++++++----------------------
 1 files changed, 279 insertions(+), 236 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index b96c504..e1b6422 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -65,10 +65,11 @@ static GSList *calls = NULL;
 #define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
 
 static guint registration_watch = 0;
-static guint voice_watch = 0;
 static guint device_watch = 0;
 static guint modem_added_watch = 0;
 static guint modem_removed_watch = 0;
+static guint call_added_watch = 0;
+static guint call_removed_watch = 0;
 
 /* HAL battery namespace key values */
 static int battchg_cur = -1;    /* "battery.charge_level.current" */
@@ -456,6 +457,219 @@ static gboolean iter_get_basic_args(DBusMessageIter *iter,
 	return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
 }
 
+static void call_free(struct voice_call *vc)
+{
+	DBG("%s", vc->obj_path);
+
+	g_dbus_remove_watch(connection, vc->watch);
+	g_free(vc->obj_path);
+	g_free(vc->number);
+	g_free(vc);
+}
+
+static gboolean handle_vc_property_changed(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct voice_call *vc = data;
+	const char *obj_path = dbus_message_get_path(msg);
+	DBusMessageIter iter, sub;
+	const char *property, *state;
+
+	DBG("path %s", obj_path);
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+		error("Unexpected signature in vc PropertyChanged signal");
+		return TRUE;
+	}
+
+	dbus_message_iter_get_basic(&iter, &property);
+	DBG("property %s", property);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_recurse(&iter, &sub);
+	if (g_str_equal(property, "State")) {
+		dbus_message_iter_get_basic(&sub, &state);
+		DBG("State %s", state);
+		if (g_str_equal(state, "disconnected")) {
+			if (vc->status == CALL_STATUS_ACTIVE)
+				telephony_update_indicator(ofono_indicators,
+						"call", EV_CALL_INACTIVE);
+			else
+				telephony_update_indicator(ofono_indicators,
+					"callsetup", EV_CALLSETUP_INACTIVE);
+			if (vc->status == CALL_STATUS_INCOMING)
+				telephony_calling_stopped_ind();
+			calls = g_slist_remove(calls, vc);
+			call_free(vc);
+		} else if (g_str_equal(state, "active")) {
+			telephony_update_indicator(ofono_indicators,
+							"call", EV_CALL_ACTIVE);
+			telephony_update_indicator(ofono_indicators,
+							"callsetup",
+							EV_CALLSETUP_INACTIVE);
+			if (vc->status == CALL_STATUS_INCOMING)
+				telephony_calling_stopped_ind();
+			vc->status = CALL_STATUS_ACTIVE;
+		} else if (g_str_equal(state, "alerting")) {
+			telephony_update_indicator(ofono_indicators,
+					"callsetup", EV_CALLSETUP_ALERTING);
+			vc->status = CALL_STATUS_ALERTING;
+			vc->originating = TRUE;
+		} else if (g_str_equal(state, "incoming")) {
+			/* state change from waiting to incoming */
+			telephony_update_indicator(ofono_indicators,
+					"callsetup", EV_CALLSETUP_INCOMING);
+			telephony_incoming_call_ind(vc->number,
+						NUMBER_TYPE_TELEPHONY);
+			vc->status = CALL_STATUS_INCOMING;
+			vc->originating = FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static struct voice_call *call_new(const char *path, DBusMessageIter *properties)
+{
+	struct voice_call *vc;
+
+	DBG("%s", path);
+
+	vc = g_new0(struct voice_call, 1);
+	vc->obj_path = g_strdup(path);
+	vc->watch = g_dbus_add_signal_watch(connection, NULL, path,
+					OFONO_VC_INTERFACE, "PropertyChanged",
+					handle_vc_property_changed, vc, NULL);
+
+	while (dbus_message_iter_get_arg_type(properties)
+						== DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter entry, value;
+		const char *property, *cli, *state;
+
+		dbus_message_iter_recurse(properties, &entry);
+		dbus_message_iter_get_basic(&entry, &property);
+
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
+
+		if (g_str_equal(property, "LineIdentification")) {
+			dbus_message_iter_get_basic(&value, &cli);
+			DBG("cli %s", cli);
+			vc->number = g_strdup(cli);
+		} else if (g_str_equal(property, "State")) {
+			dbus_message_iter_get_basic(&value, &state);
+			DBG("state %s", state);
+			if (g_str_equal(state, "incoming"))
+				vc->status = CALL_STATUS_INCOMING;
+			else if (g_str_equal(state, "dialing"))
+				vc->status = CALL_STATUS_DIALING;
+			else if (g_str_equal(state, "alerting"))
+				vc->status = CALL_STATUS_ALERTING;
+			else if (g_str_equal(state, "waiting"))
+				vc->status = CALL_STATUS_WAITING;
+		}
+
+		dbus_message_iter_next(properties);
+	}
+
+	switch (vc->status) {
+	case CALL_STATUS_INCOMING:
+		DBG("CALL_STATUS_INCOMING");
+		vc->originating = FALSE;
+		telephony_update_indicator(ofono_indicators, "callsetup",
+					EV_CALLSETUP_INCOMING);
+		telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY);
+		break;
+	case CALL_STATUS_DIALING:
+		DBG("CALL_STATUS_DIALING");
+		vc->originating = TRUE;
+		g_free(last_dialed_number);
+		last_dialed_number = g_strdup(vc->number);
+		telephony_update_indicator(ofono_indicators, "callsetup",
+					EV_CALLSETUP_OUTGOING);
+		break;
+	case CALL_STATUS_ALERTING:
+		DBG("CALL_STATUS_ALERTING");
+		vc->originating = TRUE;
+		g_free(last_dialed_number);
+		last_dialed_number = g_strdup(vc->number);
+		telephony_update_indicator(ofono_indicators, "callsetup",
+					EV_CALLSETUP_ALERTING);
+		break;
+	case CALL_STATUS_WAITING:
+		DBG("CALL_STATUS_WAITING");
+		vc->originating = FALSE;
+		telephony_update_indicator(ofono_indicators, "callsetup",
+					EV_CALLSETUP_INCOMING);
+		telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY);
+		break;
+	}
+
+	return vc;
+}
+
+static void call_added(const char *path, DBusMessageIter *properties)
+{
+	struct voice_call *vc;
+
+	DBG("%s", path);
+
+	vc = find_vc(path);
+	if (vc)
+		return;
+
+	vc = call_new(path, properties);
+	calls = g_slist_prepend(calls, vc);
+}
+
+static void get_calls_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusError err;
+	DBusMessage *reply;
+	DBusMessageIter iter, entry;
+
+	DBG("");
+	reply = dbus_pending_call_steal_reply(call);
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("ofono replied with an error: %s, %s",
+				err.name, err.message);
+		dbus_error_free(&err);
+		goto done;
+	}
+
+	dbus_message_iter_init(reply, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+		error("Unexpected signature");
+		goto done;
+	}
+
+	dbus_message_iter_recurse(&iter, &entry);
+
+	while (dbus_message_iter_get_arg_type(&entry)
+						== DBUS_TYPE_STRUCT) {
+		const char *path;
+		DBusMessageIter value, properties;
+
+		dbus_message_iter_recurse(&entry, &value);
+		dbus_message_iter_get_basic(&value, &path);
+
+		dbus_message_iter_next(&value);
+		dbus_message_iter_recurse(&value, &properties);
+
+		call_added(path, &properties);
+
+		dbus_message_iter_next(&entry);
+	}
+
+done:
+	dbus_message_unref(reply);
+}
+
 static void handle_network_property(const char *property, DBusMessageIter *variant)
 {
 	const char *status, *operator;
@@ -554,9 +768,18 @@ static void get_properties_reply(DBusPendingCall *call, void *user_data)
 	dbus_message_iter_recurse(&iter, &properties);
 
 	ret = parse_network_properties(&properties);
-	if (ret < 0)
+	if (ret < 0) {
 		error("Unable to parse %s.GetProperty reply",
 						OFONO_NETWORKREG_INTERFACE);
+		goto done;
+	}
+
+	ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
+				OFONO_VCMANAGER_INTERFACE, "GetCalls",
+				get_calls_reply, NULL, DBUS_TYPE_INVALID);
+	if (ret < 0)
+		error("Unable to send %s.GetCalls",
+						OFONO_VCMANAGER_INTERFACE);
 
 done:
 	dbus_message_unref(reply);
@@ -646,255 +869,68 @@ static gboolean handle_network_property_changed(DBusConnection *conn,
 	return TRUE;
 }
 
-static void vc_getproperties_reply(DBusPendingCall *call, void *user_data)
+static gboolean handle_vcmanager_call_added(DBusConnection *conn,
+						DBusMessage *msg, void *data)
 {
-	DBusMessage *reply;
-	DBusError err;
-	DBusMessageIter iter, iter_entry;
-	const char *path = user_data;
-	struct voice_call *vc;
-
-	DBG("in vc_getproperties_reply");
-
-	reply = dbus_pending_call_steal_reply(call);
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("ofono replied with an error: %s, %s",
-				err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	vc = find_vc(path);
-	if (!vc) {
-		error("in vc_getproperties_reply, vc is NULL");
-		goto done;
-	}
-
-	dbus_message_iter_init(reply, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in vc_getproperties_reply()");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &iter_entry);
-
-	if (dbus_message_iter_get_arg_type(&iter_entry)
-			!= DBUS_TYPE_DICT_ENTRY) {
-		error("Unexpected signature in vc_getproperties_reply()");
-		goto done;
-	}
-
-	while (dbus_message_iter_get_arg_type(&iter_entry)
-			!= DBUS_TYPE_INVALID) {
-		DBusMessageIter iter_property, sub;
-		char *property, *cli, *state;
-
-		dbus_message_iter_recurse(&iter_entry, &iter_property);
-		if (dbus_message_iter_get_arg_type(&iter_property)
-				!= DBUS_TYPE_STRING) {
-			error("Unexpected signature in"
-					" vc_getproperties_reply()");
-			goto done;
-		}
+	DBusMessageIter iter, properties;
+	const char *path = dbus_message_get_path(msg);
 
-		dbus_message_iter_get_basic(&iter_property, &property);
+	/* Ignore call if modem path doesn't math */
+	if (g_strcmp0(modem_obj_path, path) != 0)
+		return TRUE;
 
-		dbus_message_iter_next(&iter_property);
-		dbus_message_iter_recurse(&iter_property, &sub);
-		if (g_str_equal(property, "LineIdentification")) {
-			dbus_message_iter_get_basic(&sub, &cli);
-			DBG("in vc_getproperties_reply(), cli is %s", cli);
-			vc->number = g_strdup(cli);
-		} else if (g_str_equal(property, "State")) {
-			dbus_message_iter_get_basic(&sub, &state);
-			DBG("in vc_getproperties_reply(),"
-					" state is %s", state);
-			if (g_str_equal(state, "incoming"))
-				vc->status = CALL_STATUS_INCOMING;
-			else if (g_str_equal(state, "dialing"))
-				vc->status = CALL_STATUS_DIALING;
-			else if (g_str_equal(state, "alerting"))
-				vc->status = CALL_STATUS_ALERTING;
-			else if (g_str_equal(state, "waiting"))
-				vc->status = CALL_STATUS_WAITING;
-		}
+	dbus_message_iter_init(msg, &iter);
 
-		dbus_message_iter_next(&iter_entry);
+	if (dbus_message_iter_get_arg_type(&iter)
+						!= DBUS_TYPE_OBJECT_PATH) {
+		error("Unexpected signature in %s.%s signal",
+					dbus_message_get_interface(msg),
+					dbus_message_get_member(msg));
+		return TRUE;
 	}
 
-	switch (vc->status) {
-	case CALL_STATUS_INCOMING:
-		printf("in CALL_STATUS_INCOMING: case\n");
-		vc->originating = FALSE;
-		telephony_update_indicator(ofono_indicators, "callsetup",
-					EV_CALLSETUP_INCOMING);
-		telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY);
-		break;
-	case CALL_STATUS_DIALING:
-		printf("in CALL_STATUS_DIALING: case\n");
-		vc->originating = TRUE;
-		g_free(last_dialed_number);
-		last_dialed_number = g_strdup(vc->number);
-		telephony_update_indicator(ofono_indicators, "callsetup",
-					EV_CALLSETUP_OUTGOING);
-		break;
-	case CALL_STATUS_ALERTING:
-		printf("in CALL_STATUS_ALERTING: case\n");
-		vc->originating = TRUE;
-		g_free(last_dialed_number);
-		last_dialed_number = g_strdup(vc->number);
-		telephony_update_indicator(ofono_indicators, "callsetup",
-					EV_CALLSETUP_ALERTING);
-		break;
-	case CALL_STATUS_WAITING:
-		DBG("in CALL_STATUS_WAITING: case");
-		vc->originating = FALSE;
-		telephony_update_indicator(ofono_indicators, "callsetup",
-					EV_CALLSETUP_INCOMING);
-		telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY);
-		break;
-	}
-done:
-	dbus_message_unref(reply);
-}
+	dbus_message_iter_get_basic(&iter, &path);
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_recurse(&iter, &properties);
 
-static void vc_free(struct voice_call *vc)
-{
-	if (!vc)
-		return;
+	call_added(path, &properties);
 
-	g_dbus_remove_watch(connection, vc->watch);
-	g_free(vc->obj_path);
-	g_free(vc->number);
-	g_free(vc);
+	return TRUE;
 }
 
-static gboolean handle_vc_property_changed(DBusConnection *conn,
-					DBusMessage *msg, void *data)
+static void call_removed(const char *path)
 {
-	struct voice_call *vc = data;
-	const char *obj_path = dbus_message_get_path(msg);
-	DBusMessageIter iter, sub;
-	const char *property, *state;
-
-	DBG("in handle_vc_property_changed, obj_path is %s", obj_path);
-
-	dbus_message_iter_init(msg, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
-		error("Unexpected signature in vc PropertyChanged signal");
-		return TRUE;
-	}
+	struct voice_call *vc;
 
-	dbus_message_iter_get_basic(&iter, &property);
-	DBG("in handle_vc_property_changed(), the property is %s", property);
+	DBG("%s", path);
 
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &sub);
-	if (g_str_equal(property, "State")) {
-		dbus_message_iter_get_basic(&sub, &state);
-		DBG("in handle_vc_property_changed(), State is %s", state);
-		if (g_str_equal(state, "disconnected")) {
-			printf("in disconnected case\n");
-			if (vc->status == CALL_STATUS_ACTIVE)
-				telephony_update_indicator(ofono_indicators,
-						"call", EV_CALL_INACTIVE);
-			else
-				telephony_update_indicator(ofono_indicators,
-					"callsetup", EV_CALLSETUP_INACTIVE);
-			if (vc->status == CALL_STATUS_INCOMING)
-				telephony_calling_stopped_ind();
-			calls = g_slist_remove(calls, vc);
-			vc_free(vc);
-		} else if (g_str_equal(state, "active")) {
-			telephony_update_indicator(ofono_indicators,
-							"call", EV_CALL_ACTIVE);
-			telephony_update_indicator(ofono_indicators,
-							"callsetup",
-							EV_CALLSETUP_INACTIVE);
-			if (vc->status == CALL_STATUS_INCOMING)
-				telephony_calling_stopped_ind();
-			vc->status = CALL_STATUS_ACTIVE;
-			DBG("vc status is CALL_STATUS_ACTIVE");
-		} else if (g_str_equal(state, "alerting")) {
-			telephony_update_indicator(ofono_indicators,
-					"callsetup", EV_CALLSETUP_ALERTING);
-			vc->status = CALL_STATUS_ALERTING;
-			DBG("vc status is CALL_STATUS_ALERTING");
-			vc->originating = TRUE;
-		} else if (g_str_equal(state, "incoming")) {
-			/* state change from waiting to incoming */
-			telephony_update_indicator(ofono_indicators,
-					"callsetup", EV_CALLSETUP_INCOMING);
-			telephony_incoming_call_ind(vc->number,
-						NUMBER_TYPE_TELEPHONY);
-			vc->status = CALL_STATUS_INCOMING;
-			DBG("vc status is CALL_STATUS_INCOMING");
-			vc->originating = FALSE;
-		}
-	}
+	vc = find_vc(path);
+	if (vc == NULL)
+		return;
 
-	return TRUE;
+	calls = g_slist_remove(calls, vc);
+	call_free(vc);
 }
 
-static gboolean handle_vcmanager_property_changed(DBusConnection *conn,
+static gboolean handle_vcmanager_call_removed(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
-	DBusMessageIter iter, sub, array;
-	const char *property, *vc_obj_path = NULL;
-	struct voice_call *vc, *vc_new = NULL;
-
-	DBG("in handle_vcmanager_property_changed");
+	const char *path = dbus_message_get_path(msg);
 
-	dbus_message_iter_init(msg, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
-		error("Unexpected signature in vcmanager"
-					" PropertyChanged signal");
+	/* Ignore call if modem path doesn't math */
+	if (g_strcmp0(modem_obj_path, path) != 0)
 		return TRUE;
-	}
 
-	dbus_message_iter_get_basic(&iter, &property);
-	DBG("in handle_vcmanager_property_changed(),"
-				" the property is %s", property);
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &sub);
-	if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in vcmanager"
-					" PropertyChanged signal");
+	if (!dbus_message_get_args(msg, NULL,
+				DBUS_TYPE_OBJECT_PATH, &path,
+				DBUS_TYPE_INVALID)) {
+		error("Unexpected signature in %s.%s signal",
+					dbus_message_get_interface(msg),
+					dbus_message_get_member(msg));
 		return TRUE;
 	}
-	dbus_message_iter_recurse(&sub, &array);
-	while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-		dbus_message_iter_get_basic(&array, &vc_obj_path);
-		vc = find_vc(vc_obj_path);
-		if (vc) {
-			DBG("in handle_vcmanager_property_changed,"
-					" found an existing vc");
-		} else {
-			vc_new = g_new0(struct voice_call, 1);
-			vc_new->obj_path = g_strdup(vc_obj_path);
-			calls = g_slist_append(calls, vc_new);
-			vc_new->watch = g_dbus_add_signal_watch(connection,
-					NULL, vc_obj_path,
-					OFONO_VC_INTERFACE,
-					"PropertyChanged",
-					handle_vc_property_changed,
-					vc_new, NULL);
-		}
-		dbus_message_iter_next(&array);
-	}
 
-	if (!vc_new)
-		return TRUE;
-
-	send_method_call(OFONO_BUS_NAME, vc_new->obj_path,
-				OFONO_VC_INTERFACE,
-				"GetProperties", vc_getproperties_reply,
-				vc_new->obj_path, DBUS_TYPE_INVALID);
+	call_removed(path);
 
 	return TRUE;
 }
@@ -933,7 +969,7 @@ static void modem_removed(const char *path)
 
 	DBG("%s", path);
 
-	g_slist_foreach(calls, (GFunc) vc_free, NULL);
+	g_slist_foreach(calls, (GFunc) call_free, NULL);
 	g_slist_free(calls);
 	calls = NULL;
 
@@ -1151,13 +1187,6 @@ int telephony_init(void)
 						handle_network_property_changed,
 						NULL, NULL);
 
-	voice_watch = g_dbus_add_signal_watch(connection,
-						OFONO_BUS_NAME, NULL,
-						OFONO_VCMANAGER_INTERFACE,
-						"PropertyChanged",
-						handle_vcmanager_property_changed,
-						NULL, NULL);
-
 	modem_added_watch = g_dbus_add_signal_watch(connection,
 						OFONO_BUS_NAME, NULL,
 						OFONO_MANAGER_INTERFACE,
@@ -1171,6 +1200,19 @@ int telephony_init(void)
 						"ModemRemoved",
 						handle_manager_modem_removed,
 						NULL, NULL);
+	call_added_watch = g_dbus_add_signal_watch(connection,
+						OFONO_BUS_NAME, NULL,
+						OFONO_VCMANAGER_INTERFACE,
+						"CallAdded",
+						handle_vcmanager_call_added,
+						NULL, NULL);
+
+	call_removed_watch = g_dbus_add_signal_watch(connection,
+						OFONO_BUS_NAME, NULL,
+						OFONO_VCMANAGER_INTERFACE,
+						"CallRemoved",
+						handle_vcmanager_call_removed,
+						NULL, NULL);
 
 	ret = send_method_call(OFONO_BUS_NAME, OFONO_PATH,
 				OFONO_MANAGER_INTERFACE, "GetModems",
@@ -1204,9 +1246,10 @@ void telephony_exit(void)
 		modem_removed(modem_obj_path);
 
 	g_dbus_remove_watch(connection, registration_watch);
-	g_dbus_remove_watch(connection, voice_watch);
 	g_dbus_remove_watch(connection, modem_added_watch);
 	g_dbus_remove_watch(connection, modem_removed_watch);
+	g_dbus_remove_watch(connection, call_added_watch);
+	g_dbus_remove_watch(connection, call_removed_watch);
 	g_dbus_remove_watch(connection, device_watch);
 
 	dbus_connection_unref(connection);
-- 
1.7.1

[PATCH 06/10] telephony-ofono: fix not canceling pending calls on exit

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:43

From: Luiz Augusto von Dentz <redacted>

---
 audio/telephony-ofono.c |   19 ++++++++++++++++++-
 1 files changed, 18 insertions(+), 1 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index e1b6422..c554305 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -56,6 +56,7 @@ static DBusConnection *connection = NULL;
 static char *modem_obj_path = NULL;
 static char *last_dialed_number = NULL;
 static GSList *calls = NULL;
+static GSList *pending = NULL;
 
 #define OFONO_BUS_NAME "org.ofono"
 #define OFONO_PATH "/"
@@ -226,7 +227,7 @@ static int send_method_call(const char *dest, const char *path,
 	}
 
 	dbus_pending_call_set_notify(call, cb, user_data, NULL);
-	dbus_pending_call_unref(call);
+	pending = g_slist_prepend(pending, call);
 	dbus_message_unref(msg);
 
 	return 0;
@@ -610,6 +611,12 @@ static struct voice_call *call_new(const char *path, DBusMessageIter *properties
 	return vc;
 }
 
+static void remove_pending(DBusPendingCall *call)
+{
+	pending = g_slist_remove(pending, call);
+	dbus_pending_call_unref(call);
+}
+
 static void call_added(const char *path, DBusMessageIter *properties)
 {
 	struct voice_call *vc;
@@ -668,6 +675,7 @@ static void get_calls_reply(DBusPendingCall *call, void *user_data)
 
 done:
 	dbus_message_unref(reply);
+	remove_pending(call);
 }
 
 static void handle_network_property(const char *property, DBusMessageIter *variant)
@@ -783,6 +791,7 @@ static void get_properties_reply(DBusPendingCall *call, void *user_data)
 
 done:
 	dbus_message_unref(reply);
+	remove_pending(call);
 }
 
 static void modem_added(const char *path)
@@ -842,6 +851,7 @@ static void get_modems_reply(DBusPendingCall *call, void *user_data)
 
 done:
 	dbus_message_unref(reply);
+	remove_pending(call);
 }
 
 static gboolean handle_network_property_changed(DBusConnection *conn,
@@ -1052,6 +1062,7 @@ static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
 	}
 done:
 	dbus_message_unref(reply);
+	remove_pending(call);
 }
 
 static void hal_get_integer(const char *path, const char *key, void *user_data)
@@ -1170,6 +1181,7 @@ static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
 	hal_get_integer(path, "battery.charge_level.design", &battchg_design);
 done:
 	dbus_message_unref(reply);
+	remove_pending(call);
 }
 
 int telephony_init(void)
@@ -1252,6 +1264,11 @@ void telephony_exit(void)
 	g_dbus_remove_watch(connection, call_removed_watch);
 	g_dbus_remove_watch(connection, device_watch);
 
+	g_slist_foreach(pending, (GFunc) dbus_pending_call_cancel, NULL);
+	g_slist_foreach(pending, (GFunc) dbus_pending_call_unref, NULL);
+	g_slist_free(pending);
+	pending = NULL;
+
 	dbus_connection_unref(connection);
 	connection = NULL;
 
-- 
1.7.1

[PATCH 07/10] telephony-ofono: simplify watches handling logic

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:44

From: Luiz Augusto von Dentz <redacted>

---
 audio/telephony-ofono.c |   85 ++++++++++++++++++----------------------------
 1 files changed, 33 insertions(+), 52 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index c554305..00b24f9 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -56,6 +56,7 @@ static DBusConnection *connection = NULL;
 static char *modem_obj_path = NULL;
 static char *last_dialed_number = NULL;
 static GSList *calls = NULL;
+static GSList *watches = NULL;
 static GSList *pending = NULL;
 
 #define OFONO_BUS_NAME "org.ofono"
@@ -65,13 +66,6 @@ static GSList *pending = NULL;
 #define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
 #define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
 
-static guint registration_watch = 0;
-static guint device_watch = 0;
-static guint modem_added_watch = 0;
-static guint modem_removed_watch = 0;
-static guint call_added_watch = 0;
-static guint call_removed_watch = 0;
-
 /* HAL battery namespace key values */
 static int battchg_cur = -1;    /* "battery.charge_level.current" */
 static int battchg_last = -1;   /* "battery.charge_level.last_full" */
@@ -1130,6 +1124,18 @@ static gboolean handle_hal_property_modified(DBusConnection *conn,
 	return TRUE;
 }
 
+static void add_watch(const char *sender, const char *path,
+				const char *interface, const char *member,
+				GDBusSignalFunction function)
+{
+	guint watch;
+
+	watch = g_dbus_add_signal_watch(connection, sender, path, interface,
+					member, function, NULL, NULL);
+
+	watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
+}
+
 static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
 {
 	DBusMessage *reply;
@@ -1170,11 +1176,8 @@ static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
 
 	DBG("telephony-ofono: found battery device at %s", path);
 
-	device_watch = g_dbus_add_signal_watch(connection, NULL, path,
-					"org.freedesktop.Hal.Device",
-					"PropertyModified",
-					handle_hal_property_modified,
-					NULL, NULL);
+	add_watch(NULL, path, "org.freedesktop.Hal.Device",
+			"PropertyModified", handle_hal_property_modified);
 
 	hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
 	hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
@@ -1191,40 +1194,16 @@ int telephony_init(void)
 
 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
-
-	registration_watch = g_dbus_add_signal_watch(connection,
-						OFONO_BUS_NAME, NULL,
-						OFONO_NETWORKREG_INTERFACE,
-						"PropertyChanged",
-						handle_network_property_changed,
-						NULL, NULL);
-
-	modem_added_watch = g_dbus_add_signal_watch(connection,
-						OFONO_BUS_NAME, NULL,
-						OFONO_MANAGER_INTERFACE,
-						"ModemAdded",
-						handle_manager_modem_added,
-						NULL, NULL);
-
-	modem_removed_watch = g_dbus_add_signal_watch(connection,
-						OFONO_BUS_NAME, NULL,
-						OFONO_MANAGER_INTERFACE,
-						"ModemRemoved",
-						handle_manager_modem_removed,
-						NULL, NULL);
-	call_added_watch = g_dbus_add_signal_watch(connection,
-						OFONO_BUS_NAME, NULL,
-						OFONO_VCMANAGER_INTERFACE,
-						"CallAdded",
-						handle_vcmanager_call_added,
-						NULL, NULL);
-
-	call_removed_watch = g_dbus_add_signal_watch(connection,
-						OFONO_BUS_NAME, NULL,
-						OFONO_VCMANAGER_INTERFACE,
-						"CallRemoved",
-						handle_vcmanager_call_removed,
-						NULL, NULL);
+	add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE,
+			"PropertyChanged", handle_network_property_changed);
+	add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
+			"ModemAdded", handle_manager_modem_added);
+	add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
+			"ModemRemoved", handle_manager_modem_removed);
+	add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
+			"CallAdded", handle_vcmanager_call_added);
+	add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
+			"CallRemoved", handle_vcmanager_call_removed);
 
 	ret = send_method_call(OFONO_BUS_NAME, OFONO_PATH,
 				OFONO_MANAGER_INTERFACE, "GetModems",
@@ -1247,6 +1226,11 @@ int telephony_init(void)
 	return ret;
 }
 
+static void remove_watch(gpointer data)
+{
+	g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
+}
+
 void telephony_exit(void)
 {
 	DBG("");
@@ -1257,12 +1241,9 @@ void telephony_exit(void)
 	if (modem_obj_path)
 		modem_removed(modem_obj_path);
 
-	g_dbus_remove_watch(connection, registration_watch);
-	g_dbus_remove_watch(connection, modem_added_watch);
-	g_dbus_remove_watch(connection, modem_removed_watch);
-	g_dbus_remove_watch(connection, call_added_watch);
-	g_dbus_remove_watch(connection, call_removed_watch);
-	g_dbus_remove_watch(connection, device_watch);
+	g_slist_foreach(watches, (GFunc) remove_watch, NULL);
+	g_slist_free(watches);
+	watches = NULL;
 
 	g_slist_foreach(pending, (GFunc) dbus_pending_call_cancel, NULL);
 	g_slist_foreach(pending, (GFunc) dbus_pending_call_unref, NULL);
-- 
1.7.1

[PATCH 08/10] telephony-ofono: handle ofono appearing/disappearing from bus

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:45

From: Luiz Augusto von Dentz <redacted>

---
 audio/telephony-ofono.c |   31 ++++++++++++++++++++++++++-----
 1 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index 00b24f9..b6bea91 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -1187,10 +1187,28 @@ done:
 	remove_pending(call);
 }
 
+static void handle_service_connect(DBusConnection *conn, void *user_data)
+{
+	DBG("telephony-ofono: %s found", OFONO_BUS_NAME);
+
+	send_method_call(OFONO_BUS_NAME, OFONO_PATH,
+				OFONO_MANAGER_INTERFACE, "GetModems",
+				get_modems_reply, NULL, DBUS_TYPE_INVALID);
+}
+
+static void handle_service_disconnect(DBusConnection *conn, void *user_data)
+{
+	DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME);
+
+	if (modem_obj_path)
+		modem_removed(modem_obj_path);
+}
+
 int telephony_init(void)
 {
 	const char *battery_cap = "battery";
 	int ret;
+	guint watch;
 
 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
@@ -1205,11 +1223,14 @@ int telephony_init(void)
 	add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
 			"CallRemoved", handle_vcmanager_call_removed);
 
-	ret = send_method_call(OFONO_BUS_NAME, OFONO_PATH,
-				OFONO_MANAGER_INTERFACE, "GetModems",
-				get_modems_reply, NULL, DBUS_TYPE_INVALID);
-	if (ret < 0)
-		return ret;
+	watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME,
+						handle_service_connect,
+						handle_service_disconnect,
+						NULL, NULL);
+	if (watch == 0)
+		return -ENOMEM;
+
+	watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
 
 	ret = send_method_call("org.freedesktop.Hal",
 				"/org/freedesktop/Hal/Manager",
-- 
1.7.1

[PATCH 09/10] telephony-ofono: add handling for Modem.Interfaces property

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:46

From: Luiz Augusto von Dentz <redacted>

This should make sure a modem is only used if a network is available
---
 audio/telephony-ofono.c |  185 +++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 155 insertions(+), 30 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index b6bea91..6492081 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -61,6 +61,7 @@ static GSList *pending = NULL;
 
 #define OFONO_BUS_NAME "org.ofono"
 #define OFONO_PATH "/"
+#define OFONO_MODEM_INTERFACE "org.ofono.Modem"
 #define OFONO_MANAGER_INTERFACE "org.ofono.Manager"
 #define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration"
 #define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
@@ -788,15 +789,12 @@ done:
 	remove_pending(call);
 }
 
-static void modem_added(const char *path)
+static void network_found(const char *path)
 {
 	int ret;
 
 	DBG("%s", path);
 
-	if (modem_obj_path != NULL)
-		return;
-
 	modem_obj_path = g_strdup(path);
 
 	ret = send_method_call(OFONO_BUS_NAME, path,
@@ -807,12 +805,90 @@ static void modem_added(const char *path)
 						OFONO_NETWORKREG_INTERFACE);
 }
 
+static void modem_removed(const char *path)
+{
+	if (g_strcmp0(modem_obj_path, path) != 0)
+		return;
+
+	DBG("%s", path);
+
+	g_slist_foreach(calls, (GFunc) call_free, NULL);
+	g_slist_free(calls);
+	calls = NULL;
+
+	g_free(net.operator_name);
+	net.operator_name = NULL;
+
+	g_free(modem_obj_path);
+	modem_obj_path = NULL;
+}
+
+static void parse_modem_interfaces(const char *path, DBusMessageIter *ifaces)
+{
+	DBG("%s", path);
+
+	while (dbus_message_iter_get_arg_type(ifaces) == DBUS_TYPE_STRING) {
+		const char *iface;
+
+		dbus_message_iter_get_basic(ifaces, &iface);
+
+		if (g_str_equal(iface, OFONO_NETWORKREG_INTERFACE)) {
+			network_found(path);
+			return;
+		}
+
+		dbus_message_iter_next(ifaces);
+	}
+
+	modem_removed(path);
+}
+
+static void modem_added(const char *path, DBusMessageIter *properties)
+{
+	if (modem_obj_path != NULL) {
+		DBG("Ignoring, modem already exist");
+		return;
+	}
+
+	DBG("%s", path);
+
+	while (dbus_message_iter_get_arg_type(properties)
+						== DBUS_TYPE_DICT_ENTRY) {
+		const char *key;
+		DBusMessageIter interfaces, value, entry;
+
+		dbus_message_iter_recurse(properties, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
+
+		if (strcasecmp(key, "Interfaces") != 0)
+			goto next;
+
+		if (dbus_message_iter_get_arg_type(&value)
+							!= DBUS_TYPE_ARRAY) {
+			error("Invalid Signature");
+			return;
+		}
+
+		dbus_message_iter_recurse(&value, &interfaces);
+
+		parse_modem_interfaces(path, &interfaces);
+
+		if (modem_obj_path != NULL)
+			return;
+
+	next:
+		dbus_message_iter_next(properties);
+	}
+}
+
 static void get_modems_reply(DBusPendingCall *call, void *user_data)
 {
 	DBusError err;
 	DBusMessage *reply;
 	DBusMessageIter iter, entry;
-	const char *path;
 
 	DBG("list_modem_reply is called\n");
 	reply = dbus_pending_call_steal_reply(call);
@@ -825,6 +901,10 @@ static void get_modems_reply(DBusPendingCall *call, void *user_data)
 		goto done;
 	}
 
+	/* Skip modem selection if a modem already exist */
+	if (modem_obj_path != NULL)
+		goto done;
+
 	dbus_message_iter_init(reply, &iter);
 
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
@@ -834,14 +914,23 @@ static void get_modems_reply(DBusPendingCall *call, void *user_data)
 
 	dbus_message_iter_recurse(&iter, &entry);
 
-	if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_OBJECT_PATH) {
-		error("Unexpected signature");
-		goto done;
-	}
+	while (dbus_message_iter_get_arg_type(&entry)
+						== DBUS_TYPE_STRUCT) {
+		const char *path;
+		DBusMessageIter item, properties;
+
+		dbus_message_iter_recurse(&entry, &item);
+		dbus_message_iter_get_basic(&item, &path);
+
+		dbus_message_iter_next(&item);
+		dbus_message_iter_recurse(&item, &properties);
 
-	dbus_message_iter_get_basic(&entry, &path);
+		modem_added(path, &properties);
+		if (modem_obj_path != NULL)
+			break;
 
-	modem_added(path);
+		dbus_message_iter_next(&entry);
+	}
 
 done:
 	dbus_message_unref(reply);
@@ -873,6 +962,57 @@ static gboolean handle_network_property_changed(DBusConnection *conn,
 	return TRUE;
 }
 
+static void handle_modem_property(const char *path, const char *property,
+						DBusMessageIter *variant)
+{
+	DBG("%s", property);
+
+	if (g_str_equal(property, "Interfaces")) {
+		DBusMessageIter interfaces;
+
+		if (dbus_message_iter_get_arg_type(variant)
+							!= DBUS_TYPE_ARRAY) {
+			error("Invalid signature");
+			return;
+		}
+
+		dbus_message_iter_recurse(variant, &interfaces);
+		parse_modem_interfaces(path, &interfaces);
+	}
+}
+
+static gboolean handle_modem_property_changed(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessageIter iter, variant;
+	const char *property, *path;
+
+	path = dbus_message_get_path(msg);
+
+	/* Ignore if modem already exist and paths doesn't match */
+	if (modem_obj_path != NULL &&
+				g_str_equal(path, modem_obj_path) == FALSE)
+		return TRUE;
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+		error("Unexpected signature in %s.%s PropertyChanged signal",
+					dbus_message_get_interface(msg),
+					dbus_message_get_member(msg));
+		return TRUE;
+	}
+
+	dbus_message_iter_get_basic(&iter, &property);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_recurse(&iter, &variant);
+
+	handle_modem_property(path, property, &variant);
+
+	return TRUE;
+}
+
 static gboolean handle_vcmanager_call_added(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
@@ -959,31 +1099,14 @@ static gboolean handle_manager_modem_added(DBusConnection *conn,
 	}
 
 	dbus_message_iter_get_basic(&iter, &path);
+	dbus_message_iter_next(&iter);
 	dbus_message_iter_recurse(&iter, &properties);
 
-	modem_added(path);
+	modem_added(path, &properties);
 
 	return TRUE;
 }
 
-static void modem_removed(const char *path)
-{
-	if (g_strcmp0(modem_obj_path, path) != 0)
-		return;
-
-	DBG("%s", path);
-
-	g_slist_foreach(calls, (GFunc) call_free, NULL);
-	g_slist_free(calls);
-	calls = NULL;
-
-	g_free(net.operator_name);
-	net.operator_name = NULL;
-
-	g_free(modem_obj_path);
-	modem_obj_path = NULL;
-}
-
 static gboolean handle_manager_modem_removed(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
@@ -1212,6 +1335,8 @@ int telephony_init(void)
 
 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
+	add_watch(OFONO_BUS_NAME, NULL, OFONO_MODEM_INTERFACE,
+			"PropertyChanged", handle_modem_property_changed);
 	add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE,
 			"PropertyChanged", handle_network_property_changed);
 	add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
-- 
1.7.1

[PATCH 10/10] telephony-ofono: fix not updating indicators when a call is removed

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-01-05 15:59:47

From: Luiz Augusto von Dentz <redacted>

In some extreme cases such as modem removal ofono may not have a chance
to set the call to disconnected state so indicators would not be update
properly.
---
 audio/telephony-ofono.c |   18 ++++++++++--------
 1 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index 6492081..ae8f56a 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -457,6 +457,16 @@ static void call_free(struct voice_call *vc)
 {
 	DBG("%s", vc->obj_path);
 
+	if (vc->status == CALL_STATUS_ACTIVE)
+		telephony_update_indicator(ofono_indicators, "call",
+							EV_CALL_INACTIVE);
+	else
+		telephony_update_indicator(ofono_indicators, "callsetup",
+							EV_CALLSETUP_INACTIVE);
+
+	if (vc->status == CALL_STATUS_INCOMING)
+		telephony_calling_stopped_ind();
+
 	g_dbus_remove_watch(connection, vc->watch);
 	g_free(vc->obj_path);
 	g_free(vc->number);
@@ -489,14 +499,6 @@ static gboolean handle_vc_property_changed(DBusConnection *conn,
 		dbus_message_iter_get_basic(&sub, &state);
 		DBG("State %s", state);
 		if (g_str_equal(state, "disconnected")) {
-			if (vc->status == CALL_STATUS_ACTIVE)
-				telephony_update_indicator(ofono_indicators,
-						"call", EV_CALL_INACTIVE);
-			else
-				telephony_update_indicator(ofono_indicators,
-					"callsetup", EV_CALLSETUP_INACTIVE);
-			if (vc->status == CALL_STATUS_INCOMING)
-				telephony_calling_stopped_ind();
 			calls = g_slist_remove(calls, vc);
 			call_free(vc);
 		} else if (g_str_equal(state, "active")) {
-- 
1.7.1

Re: [PATCH 00/10] Update telephony-ofono driver

From: Johan Hedberg <hidden>
Date: 2011-01-06 22:39:20

Hi Luiz,

On Wed, Jan 05, 2011, Luiz Augusto von Dentz wrote:
This patches update the ofono backend so it can be used with recent
versions of ofono (> 0.28), it can be tested by compiling bluetoothd with
--with-telephony=ofono

Since the hfp doesn't really support multiple modems, at least not in the
same record/connection, the driver will pick the first modem that has
org.ofono.NetworkRegistration since that is what hfp expect as indicator.

Calls are only picked/indicated if they belong to the modem in use
otherwise they are ignored.

Note that there is still a plan to integrate hfp inside ofono and this
changes doesn't change anything, it basically add the possibility to use
ofono with BlueZ 4.x since 5.x probably will change this entirely.

Luiz Augusto von Dentz (10):
  telephony-ofono: notify alerting calls when headset connects
  telephony-ofono: fix not being able to answer alerting/waiting calls
  telephony-ofono: fix not setting originating when status property
    changes
  telephony-ofono: make use of GetModems method
  telephony-ofono: make use of GetCalls method
  telephony-ofono: fix not canceling pending calls on exit
  telephony-ofono: simplify watches handling logic
  telephony-ofono: handle ofono appearing/disappearing from bus
  telephony-ofono: add handling for Modem.Interfaces property
  telephony-ofono: fix not updating indicators when a call is removed

 audio/telephony-ofono.c |  916 +++++++++++++++++++++++++++++++----------------
 1 files changed, 604 insertions(+), 312 deletions(-)
All 10 patches have been pushed upstream. Thanks.

Johan
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help