All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v17 00/15] Add org.bluez.Telephony interface
@ 2012-08-03 12:07 Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 01/15] doc: Add telephony interface documents Frédéric Danis
                   ` (14 more replies)
  0 siblings, 15 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Hello,

This set of patches replaces telephony drivers for HeadSet, HandsFree,
DUN and SAP Profiles by a new DBus interface (org.bluez.Telephony).

This will simplify BlueZ code by focusing on the Bluetooth
communication part and by letting the external application (i.e. oFono)
take charge of the Telephony tasks (AT parsing and modem specific code,
which can be removed from BlueZ code). So, it becomes simpler, easier
to maintain and debug.

External applications, which should implement AT parsing and telephony
part of HeadSet or HandsFree Profiles, will have to register a telephony
agent using this new interface.

Any comments appreciated.

Regards

PS: Since latest Patch set:
- split patch 1 between telephony interface documentations and update of
  assigned numbers document

Frédéric Danis (15):
  doc: Add telephony interface documents
  doc: Add HSP HS channel to assigned numbers
  audio: Move telephony drivers to D-Bus interface
  audio: Simplify org.bluez.Headset
  audio: Remove dummy telephony driver
  audio: Remove maemo5 telephony driver
  audio: Remove maemo6 telephony driver
  audio: Remove oFono telephony driver
  audio: Move HFP/HSP AG servers to telephony.c
  audio: Send transport path to telephony agent
  audio: Move HFP HF server to telephony.c
  audio: Add DUN GW to org.bluez.Telephony
  audio: Add SAP GW to org.bluez.Telephony
  adapter: Add API to get fast connectable mode
  audio: Add fast connectable to telephony interface

 Makefile.am                    |   19 +-
 audio/audio.conf               |    7 -
 audio/device.h                 |    1 +
 audio/gateway.c                |  436 +++-----
 audio/gateway.h                |    8 +
 audio/headset.c                | 1844 ++++-----------------------------
 audio/headset.h                |   16 +-
 audio/manager.c                |  628 +-----------
 audio/manager.h                |    4 -
 audio/media.c                  |   34 +
 audio/telephony-dummy.c        |  447 --------
 audio/telephony-maemo5.c       | 2105 --------------------------------------
 audio/telephony-maemo6.c       | 2200 ----------------------------------------
 audio/telephony-ofono.c        | 1637 ------------------------------
 audio/telephony.c              | 1634 +++++++++++++++++++++++++++++
 audio/telephony.h              |  205 +---
 audio/transport.c              |  117 ++-
 doc/assigned-numbers.txt       |    2 +
 doc/audio-api.txt              |  232 ++---
 doc/audio-telephony-design.txt |  106 ++
 doc/hfp-api.txt                |   46 -
 doc/media-api.txt              |   19 +-
 src/adapter.c                  |   15 +-
 src/adapter.h                  |    1 +
 24 files changed, 2349 insertions(+), 9414 deletions(-)
 delete mode 100644 audio/telephony-dummy.c
 delete mode 100644 audio/telephony-maemo5.c
 delete mode 100644 audio/telephony-maemo6.c
 delete mode 100644 audio/telephony-ofono.c
 create mode 100644 audio/telephony.c
 create mode 100644 doc/audio-telephony-design.txt

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v17 01/15] doc: Add telephony interface documents
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-05  4:37   ` Marcel Holtmann
  2012-08-03 12:07 ` [PATCH v17 02/15] doc: Add HSP HS channel to assigned numbers Frédéric Danis
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

---
 Makefile.am                    |    2 +-
 doc/audio-api.txt              |   87 +++++++++++++++++++++++++++++++++
 doc/audio-telephony-design.txt |  106 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 194 insertions(+), 1 deletion(-)
 create mode 100644 doc/audio-telephony-design.txt

diff --git a/Makefile.am b/Makefile.am
index 45a811c..1aa302c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -381,7 +381,7 @@ EXTRA_DIST += doc/manager-api.txt \
 		doc/network-api.txt doc/input-api.txt doc/audio-api.txt \
 		doc/control-api.txt doc/hfp-api.txt doc/health-api.txt \
 		doc/sap-api.txt doc/media-api.txt doc/assigned-numbers.txt \
-		doc/supported-features.txt
+		doc/supported-features.txt doc/audio-telephony-design.txt
 
 AM_YFLAGS = -d
 
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index ca430fc..c620a7d 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -423,3 +423,90 @@ properties	boolean Connected [readonly]
 		uint16 MicrophoneGain  [readonly]
 
 			The speaker gain when available.
+
+
+Telephony hierarchy
+===================
+
+Service		org.bluez
+Interface	org.bluez.Telephony
+Object path	[variable prefix]/{hci0,hci1,...}
+
+Methods		void RegisterAgent(object path, dict properties)
+
+			Register a TelephonyAgent to sender, the sender can
+			register as many agents as it likes.
+			Object path should be unique for an agent and a UUID.
+
+			Note: If the sender disconnects its agents are
+			automatically unregistered.
+
+			possible properties:
+
+				string UUID:
+
+					UUID of the profile which the agent is
+					for.
+
+				uint16 Version:
+
+					Version of the profile which the agent
+					implements.
+
+				uint16 Features:
+
+					Agent supported features as defined in
+					profile spec e.g. HFP.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void UnregisterAgent(object path)
+
+			Unregister sender agent.
+
+TelephonyAgent hierarchy
+========================
+
+Service		unique name
+Interface	org.bluez.TelephonyAgent
+Object path	freely definable
+
+Methods		void NewConnection(filedescriptor fd, dict properties)
+
+			This method gets called whenever a new connection
+			has been established. This method assumes that D-Bus
+			daemon with file descriptor passing capability is
+			being used.
+
+			The agent should only return successfully once the
+			establishment of the service level connection (SLC)
+			has been completed.  In the case of Handsfree this
+			means that BRSF exchange has been performed and
+			necessary initialization has been done.
+
+			possible properties:
+
+				object Device:
+
+					BlueZ remote device object.
+
+				uint16 Version:
+
+					Remote profile version.
+
+				uint16 Features:
+
+					Remote profile features.
+
+				object Transport:
+
+					Optional. MediaTransport object path.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.Failed
+
+		void Release()
+
+			This method gets called whenever the service daemon
+			unregisters the agent or whenever the Adapter where
+			the TelephonyAgent registers itself is removed.
diff --git a/doc/audio-telephony-design.txt b/doc/audio-telephony-design.txt
new file mode 100644
index 0000000..a5936f6
--- /dev/null
+++ b/doc/audio-telephony-design.txt
@@ -0,0 +1,106 @@
+The org.bluez.Telephony interface will simplify BlueZ code by focusing on
+the Bluetooth communication part and by letting the external application (i.e.
+oFono) take charge of the Telephony tasks (AT parsing and modem specific code).
+So, it becomes simpler, easier to maintain and debug.
+
+External applications, which should implement AT parsing and telephony
+part of HeadSet or HandsFree Profiles, will have to register an
+org.bluez.TelephonyAgent using this new interface. This will setup a SDP record
+for the profile and a RFCOMM server listening for incoming connection.
+
+When a new device is connected, NewConnection method of TelephonyAgent is
+called. The telephony agent should reply to it after proper communication
+establishment (directly for HSP or after SLC setup completes for HFP).
+
+Interaction with the audio component (i.e. PulseAudio) will be done through the
+MediaTransport object (passed to telephony agent during NewConnection call).
+
+Here is some flowcharts of interactions between BlueZ, telephony agent (oFono)
+and audio component (PulseAudio):
+
+        .....>  Bluetooth communication between headset and phone
+        ----->  Dbus messages and signals
+
+SCO connection - AG initiated
+
+	PulseAudio              BlueZ             HF
+	|                         |               |
+	|    transport acquire    |               |
+	|------------------------>|               |
+	|                         |  connect SCO  |
+	|                         |<.............>|
+	|      return SCO fd      |               |
+	|<------------------------|               |
+	|                         |               |
+
+SCO connection - HF initiated
+
+	PulseAudio              BlueZ             HF
+	|                         |               |
+	|                         |  connect SCO  |
+	|                         |<.............>|
+	|  state changed signal   |               |
+	|<------------------------|               |
+	|                         |               |
+	|    transport acquire    |               |
+	|------------------------>|               |
+	|                         |               |
+	|      return SCO fd      |               |
+	|<------------------------|               |
+	|                         |               |
+
+AT+NREC
+
+	HF              oFono           BlueZ           PulseAudio
+	|     AT+NREC     |               |                  |
+	|................>|               |                  |
+	|                 |  SetProperty  |                  |
+	|                 |-------------->|                  |
+	|                 |               | property changed |
+	|                 |               |      signal      |
+	|                 |               |----------------->|
+
+
++BSIR
+
+	HF          oFono         BlueZ        PulseAudio        app
+	|             |             |               |             |
+	|             |             |               |<------------|
+	|             |             |  SetProperty  |             |
+	|             |             |<--------------|             |
+	|             |             |               |             |
+	|             |   property changed signal   |             |
+	|             |<------------*-------------->|             |
+	|   +BSIR:x   |             |               |             |
+	|<............|             |               |             |
+	|             |             |               |             |
+
+
+AT+VGS,AT+VGM
+
+	HF          oFono         BlueZ        PulseAudio        app
+	|             |             |               |             |
+	|  AT+VGS=xx  |             |               |             |
+	|............>|             |               |             |
+	|             | SetProperty |               |             |
+	|             |------------>|               |             |
+	|             |             |               |             |
+	|             |   property changed signal   |             |
+	|             |<------------*-------------->|             |
+	|             |             |               |------------>|
+	|             |             |               |             |
+
+
++VGS,+VGM
+
+	HF          oFono         BlueZ        PulseAudio        app
+	|             |             |               |             |
+	|             |             |               |<------------|
+	|             |             |  SetProperty  |             |
+	|             |             |<--------------|             |
+	|             |             |               |             |
+	|             |   property changed signal   |             |
+	|             |<------------*-------------->|             |
+	|   +VGS:xx   |             |               |             |
+	|<............|             |               |------------>|
+	|             |             |               |             |
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 02/15] doc: Add HSP HS channel to assigned numbers
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 01/15] doc: Add telephony interface documents Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 03/15] audio: Move telephony drivers to D-Bus interface Frédéric Danis
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

---
 doc/assigned-numbers.txt |    1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/assigned-numbers.txt b/doc/assigned-numbers.txt
index cda934c..120d7ea 100644
--- a/doc/assigned-numbers.txt
+++ b/doc/assigned-numbers.txt
@@ -8,6 +8,7 @@ avoid conflicts.
 Profile		Channel
 -----------------------
 DUN		1
+HSP HS		6
 HFP HF		7
 OPP		9
 FTP		10
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 03/15] audio: Move telephony drivers to D-Bus interface
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 01/15] doc: Add telephony interface documents Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 02/15] doc: Add HSP HS channel to assigned numbers Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 04/15] audio: Simplify org.bluez.Headset Frédéric Danis
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Add a D-Bus interface called org.bluez.Telephony to replace current
telephony drivers for HeadSet/HandsFree Profiles.

This will simplify BlueZ code by focusing on the Bluetooth
communication part and by letting the external application (i.e. oFono)
take charge of the Telephony tasks (AT parsing and modem specific code,
which can be removed from BlueZ code). So, it becomes simpler, easier
to maintain and debug.

Telephony application will have to register an agent using this new
interface.

Remove functions related to AT parsing from audio/headset.c.

Remove current telephony drivers (dummy, maemo 5, maemo 6 and oFono)
from the build as they have been replaced and are no longer needed.
---
 Makefile.am       |   13 +-
 audio/headset.c   |  694 +++++------------------------------------------------
 audio/headset.h   |    3 +
 audio/manager.c   |   13 +-
 audio/telephony.c |  633 ++++++++++++++++++++++++++++++++++++++++++++++++
 audio/telephony.h |   35 +--
 6 files changed, 719 insertions(+), 672 deletions(-)
 create mode 100644 audio/telephony.c

diff --git a/Makefile.am b/Makefile.am
index 1aa302c..2a8b903 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -148,14 +148,8 @@ builtin_sources += audio/main.c \
 			audio/avdtp.h audio/avdtp.c \
 			audio/media.h audio/media.c \
 			audio/transport.h audio/transport.c \
-			audio/telephony.h audio/a2dp-codecs.h
-builtin_nodist += audio/telephony.c
-
-noinst_LIBRARIES += audio/libtelephony.a
-
-audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
-				audio/telephony-maemo5.c audio/telephony-ofono.c \
-				audio/telephony-maemo6.c
+			audio/telephony.h audio/telephony.c \
+			audio/a2dp-codecs.h
 endif
 
 if SAPPLUGIN
@@ -428,9 +422,6 @@ MAINTAINERCLEANFILES = Makefile.in \
 src/builtin.h: src/genbuiltin $(builtin_sources)
 	$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
 
-audio/telephony.c: audio/@TELEPHONY_DRIVER@
-	$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
-
 profiles/sap/sap.c: profiles/sap/@SAP_DRIVER@
 	$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
 
diff --git a/audio/headset.c b/audio/headset.c
index 1014c59..668e9f1 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -42,11 +42,16 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
+#include "btio.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+
 #include "log.h"
 #include "device.h"
 #include "manager.h"
@@ -54,10 +59,7 @@
 #include "telephony.h"
 #include "headset.h"
 #include "sdp-client.h"
-#include "btio.h"
 #include "dbus-common.h"
-#include "../src/adapter.h"
-#include "../src/device.h"
 
 #define DC_TIMEOUT 3
 
@@ -69,8 +71,6 @@
 #define HEADSET_GAIN_MICROPHONE 'M'
 
 static struct {
-	gboolean telephony_ready;	/* Telephony plugin initialized */
-	uint32_t features;		/* HFP AG features */
 	const struct indicator *indicators;	/* Available HFP indicators */
 	int er_mode;			/* Event reporting mode */
 	int er_ind;			/* Event reporting for indicators */
@@ -80,8 +80,6 @@ static struct {
 	guint ring_timer;		/* For incoming call indication */
 	const char *chld;		/* Response to AT+CHLD=? */
 } ag = {
-	.telephony_ready = FALSE,
-	.features = 0,
 	.er_mode = 3,
 	.er_ind = 0,
 	.rh = BTRH_NOT_SUPPORTED,
@@ -132,9 +130,7 @@ struct pending_connect {
 };
 
 struct headset_slc {
-	char buf[BUF_SIZE];
-	int data_start;
-	int data_length;
+	struct telephony_device *tel_dev;
 
 	gboolean cli_active;
 	gboolean cme_enabled;
@@ -158,6 +154,7 @@ struct headset {
 
 	GIOChannel *rfcomm;
 	GIOChannel *tmp_rfcomm;
+	const char *connecting_uuid;
 	GIOChannel *sco;
 	guint sco_id;
 
@@ -235,40 +232,6 @@ static void print_ag_features(uint32_t features)
 	g_free(str);
 }
 
-static void print_hf_features(uint32_t features)
-{
-	GString *gstr;
-	char *str;
-
-	if (features == 0) {
-		DBG("HFP HF features: (none)");
-		return;
-	}
-
-	gstr = g_string_new("HFP HF features: ");
-
-	if (features & HF_FEATURE_EC_ANDOR_NR)
-		g_string_append(gstr, "\"EC and/or NR function\" ");
-	if (features & HF_FEATURE_CALL_WAITING_AND_3WAY)
-		g_string_append(gstr, "\"Call waiting and 3-way calling\" ");
-	if (features & HF_FEATURE_CLI_PRESENTATION)
-		g_string_append(gstr, "\"CLI presentation capability\" ");
-	if (features & HF_FEATURE_VOICE_RECOGNITION)
-		g_string_append(gstr, "\"Voice recognition activation\" ");
-	if (features & HF_FEATURE_REMOTE_VOLUME_CONTROL)
-		g_string_append(gstr, "\"Remote volume control\" ");
-	if (features & HF_FEATURE_ENHANCED_CALL_STATUS)
-		g_string_append(gstr, "\"Enhanced call status\" ");
-	if (features & HF_FEATURE_ENHANCED_CALL_CONTROL)
-		g_string_append(gstr, "\"Enhanced call control\" ");
-
-	str = g_string_free(gstr, FALSE);
-
-	DBG("%s", str);
-
-	g_free(str);
-}
-
 static const char *state2str(headset_state_t state)
 {
 	switch (state) {
@@ -332,97 +295,6 @@ static int __attribute__((format(printf, 2, 3)))
 	return ret;
 }
 
-static int supported_features(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-	int err;
-
-	if (strlen(buf) < 9)
-		return -EINVAL;
-
-	slc->hf_features = strtoul(&buf[8], NULL, 10);
-
-	print_hf_features(slc->hf_features);
-
-	err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
-	if (err < 0)
-		return err;
-
-	return headset_send(hs, "\r\nOK\r\n");
-}
-
-static char *indicator_ranges(const struct indicator *indicators)
-{
-	int i;
-	GString *gstr;
-
-	gstr = g_string_new("\r\n+CIND: ");
-
-	for (i = 0; indicators[i].desc != NULL; i++) {
-		if (i == 0)
-			g_string_append_printf(gstr, "(\"%s\",(%s))",
-						indicators[i].desc,
-						indicators[i].range);
-		else
-			g_string_append_printf(gstr, ",(\"%s\",(%s))",
-						indicators[i].desc,
-						indicators[i].range);
-	}
-
-	g_string_append(gstr, "\r\n");
-
-	return g_string_free(gstr, FALSE);
-}
-
-static char *indicator_values(const struct indicator *indicators)
-{
-	int i;
-	GString *gstr;
-
-	gstr = g_string_new("\r\n+CIND: ");
-
-	for (i = 0; indicators[i].desc != NULL; i++) {
-		if (i == 0)
-			g_string_append_printf(gstr, "%d", indicators[i].val);
-		else
-			g_string_append_printf(gstr, ",%d", indicators[i].val);
-	}
-
-	g_string_append(gstr, "\r\n");
-
-	return g_string_free(gstr, FALSE);
-}
-
-static int report_indicators(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-	int err;
-	char *str;
-
-	if (strlen(buf) < 8)
-		return -EINVAL;
-
-	if (ag.indicators == NULL) {
-		error("HFP AG indicators not initialized");
-		return headset_send(hs, "\r\nERROR\r\n");
-	}
-
-	if (buf[7] == '=')
-		str = indicator_ranges(ag.indicators);
-	else
-		str = indicator_values(ag.indicators);
-
-	err = headset_send(hs, "%s", str);
-
-	g_free(str);
-
-	if (err < 0)
-		return err;
-
-	return headset_send(hs, "\r\nOK\r\n");
-}
-
 static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
 {
 	struct headset *hs = dev->headset;
@@ -655,12 +527,12 @@ static int hfp_cmp(struct headset *hs)
 		return -1;
 }
 
-static void hfp_slc_complete(struct audio_device *dev)
+void headset_profile_connection_complete(struct audio_device *dev)
 {
 	struct headset *hs = dev->headset;
 	struct pending_connect *p = hs->pending;
 
-	DBG("HFP Service Level Connection established");
+	DBG("Profile connection established");
 
 	headset_set_state(dev, HEADSET_STATE_CONNECTED);
 
@@ -707,6 +579,7 @@ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
 	struct audio_device *device = telephony_device;
 	struct headset *hs = device->headset;
 	struct headset_slc *slc = hs->slc;
+	uint32_t ag_features;
 	int ret;
 
 	if (err != CME_ERROR_NONE)
@@ -719,74 +592,12 @@ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
 	if (hs->state != HEADSET_STATE_CONNECTING)
 		return 0;
 
+	ag_features = telephony_get_ag_features();
 	if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
-			ag.features & AG_FEATURE_THREE_WAY_CALLING)
+			ag_features & AG_FEATURE_THREE_WAY_CALLING)
 		return 0;
 
-	hfp_slc_complete(device);
-
-	return 0;
-}
-
-static int event_reporting(struct audio_device *dev, const char *buf)
-{
-	char **tokens; /* <mode>, <keyp>, <disp>, <ind>, <bfr> */
-
-	if (strlen(buf) < 13)
-		return -EINVAL;
-
-	tokens = g_strsplit(&buf[8], ",", 5);
-	if (g_strv_length(tokens) < 4) {
-		g_strfreev(tokens);
-		return -EINVAL;
-	}
-
-	ag.er_mode = atoi(tokens[0]);
-	ag.er_ind = atoi(tokens[3]);
-
-	g_strfreev(tokens);
-	tokens = NULL;
-
-	DBG("Event reporting (CMER): mode=%d, ind=%d",
-			ag.er_mode, ag.er_ind);
-
-	switch (ag.er_ind) {
-	case 0:
-	case 1:
-		telephony_event_reporting_req(dev, ag.er_ind);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int call_hold(struct audio_device *dev, const char *buf)
-{
-	struct headset *hs = dev->headset;
-	int err;
-
-	if (strlen(buf) < 9)
-		return -EINVAL;
-
-	if (buf[8] != '?') {
-		telephony_call_hold_req(dev, &buf[8]);
-		return 0;
-	}
-
-	err = headset_send(hs, "\r\n+CHLD: (%s)\r\n", ag.chld);
-	if (err < 0)
-		return err;
-
-	err = headset_send(hs, "\r\nOK\r\n");
-	if (err < 0)
-		return err;
-
-	if (hs->state != HEADSET_STATE_CONNECTING)
-		return 0;
-
-	hfp_slc_complete(dev);
+	headset_profile_connection_complete(device);
 
 	return 0;
 }
@@ -796,47 +607,11 @@ int telephony_key_press_rsp(void *telephony_device, cme_error_t err)
 	return telephony_generic_rsp(telephony_device, err);
 }
 
-static int key_press(struct audio_device *device, const char *buf)
-{
-	if (strlen(buf) < 9)
-		return -EINVAL;
-
-	g_dbus_emit_signal(device->conn, device->path,
-			AUDIO_HEADSET_INTERFACE, "AnswerRequested",
-			DBUS_TYPE_INVALID);
-
-	if (ag.ring_timer) {
-		g_source_remove(ag.ring_timer);
-		ag.ring_timer = 0;
-	}
-
-	telephony_key_press_req(device, &buf[8]);
-
-	return 0;
-}
-
 int telephony_answer_call_rsp(void *telephony_device, cme_error_t err)
 {
 	return telephony_generic_rsp(telephony_device, err);
 }
 
-static int answer_call(struct audio_device *device, const char *buf)
-{
-	if (ag.ring_timer) {
-		g_source_remove(ag.ring_timer);
-		ag.ring_timer = 0;
-	}
-
-	if (ag.number) {
-		g_free(ag.number);
-		ag.number = NULL;
-	}
-
-	telephony_answer_call_req(device);
-
-	return 0;
-}
-
 int telephony_terminate_call_rsp(void *telephony_device,
 					cme_error_t err)
 {
@@ -853,99 +628,21 @@ int telephony_terminate_call_rsp(void *telephony_device,
 	return headset_send(hs, "\r\nOK\r\n");
 }
 
-static int terminate_call(struct audio_device *device, const char *buf)
-{
-	if (ag.number) {
-		g_free(ag.number);
-		ag.number = NULL;
-	}
-
-	if (ag.ring_timer) {
-		g_source_remove(ag.ring_timer);
-		ag.ring_timer = 0;
-	}
-
-	telephony_terminate_call_req(device);
-
-	return 0;
-}
-
-static int cli_notification(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-
-	if (strlen(buf) < 9)
-		return -EINVAL;
-
-	slc->cli_active = buf[8] == '1' ? TRUE : FALSE;
-
-	return headset_send(hs, "\r\nOK\r\n");
-}
-
 int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err)
 {
 	return telephony_generic_rsp(telephony_device, err);
 }
 
-static int response_and_hold(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-
-	if (strlen(buf) < 8)
-		return -EINVAL;
-
-	if (ag.rh == BTRH_NOT_SUPPORTED)
-		return telephony_generic_rsp(device, CME_ERROR_NOT_SUPPORTED);
-
-	if (buf[7] == '=') {
-		telephony_response_and_hold_req(device, atoi(&buf[8]) < 0);
-		return 0;
-	}
-
-	if (ag.rh >= 0)
-		headset_send(hs, "\r\n+BTRH: %d\r\n", ag.rh);
-
-	return headset_send(hs, "\r\nOK\r\n");
-}
-
 int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err)
 {
 	return telephony_generic_rsp(telephony_device, err);
 }
 
-static int last_dialed_number(struct audio_device *device, const char *buf)
-{
-	telephony_last_dialed_number_req(device);
-
-	return 0;
-}
-
 int telephony_dial_number_rsp(void *telephony_device, cme_error_t err)
 {
 	return telephony_generic_rsp(telephony_device, err);
 }
 
-static int dial_number(struct audio_device *device, const char *buf)
-{
-	char number[BUF_SIZE];
-	size_t buf_len;
-
-	buf_len = strlen(buf);
-
-	if (buf[buf_len - 1] != ';') {
-		DBG("Rejecting non-voice call dial request");
-		return -EINVAL;
-	}
-
-	memset(number, 0, sizeof(number));
-	strncpy(number, &buf[3], buf_len - 4);
-
-	telephony_dial_number_req(device, number);
-
-	return 0;
-}
-
 static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
 {
 	struct headset *hs = device->headset;
@@ -993,111 +690,21 @@ static int headset_set_gain(struct audio_device *device, uint16_t gain, char typ
 	return 0;
 }
 
-static int signal_gain_setting(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-	dbus_uint16_t gain;
-	int err;
-
-	if (strlen(buf) < 8) {
-		error("Too short string for Gain setting");
-		return -EINVAL;
-	}
-
-	gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
-
-	err = headset_set_gain(device, gain, buf[5]);
-	if (err < 0 && err != -EALREADY)
-		return err;
-
-	return headset_send(hs, "\r\nOK\r\n");
-}
-
 int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err)
 {
 	return telephony_generic_rsp(telephony_device, err);
 }
 
-static int dtmf_tone(struct audio_device *device, const char *buf)
-{
-	char tone;
-
-	if (strlen(buf) < 8) {
-		error("Too short string for DTMF tone");
-		return -EINVAL;
-	}
-
-	tone = buf[7];
-	if (tone >= '#' && tone <= 'D')
-		telephony_transmit_dtmf_req(device, tone);
-	else
-		return -EINVAL;
-
-	return 0;
-}
-
 int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err)
 {
 	return telephony_generic_rsp(telephony_device, err);
 }
 
-static int subscriber_number(struct audio_device *device, const char *buf)
-{
-	telephony_subscriber_number_req(device);
-
-	return 0;
-}
-
 int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err)
 {
 	return telephony_generic_rsp(telephony_device, err);
 }
 
-static int list_current_calls(struct audio_device *device, const char *buf)
-{
-	telephony_list_current_calls_req(device);
-
-	return 0;
-}
-
-static int extended_errors(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-
-	if (strlen(buf) < 9)
-		return -EINVAL;
-
-	if (buf[8] == '1') {
-		slc->cme_enabled = TRUE;
-		DBG("CME errors enabled for headset %p", hs);
-	} else {
-		slc->cme_enabled = FALSE;
-		DBG("CME errors disabled for headset %p", hs);
-	}
-
-	return headset_send(hs, "\r\nOK\r\n");
-}
-
-static int call_waiting_notify(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-
-	if (strlen(buf) < 9)
-		return -EINVAL;
-
-	if (buf[8] == '1') {
-		slc->cwa_enabled = TRUE;
-		DBG("Call waiting notification enabled for headset %p", hs);
-	} else {
-		slc->cwa_enabled = FALSE;
-		DBG("Call waiting notification disabled for headset %p", hs);
-	}
-
-	return headset_send(hs, "\r\nOK\r\n");
-}
-
 int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err)
 {
 	return telephony_generic_rsp(telephony_device, err);
@@ -1145,108 +752,6 @@ int telephony_operator_selection_ind(int mode, const char *oper)
 	return 0;
 }
 
-static int operator_selection(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-
-	if (strlen(buf) < 8)
-		return -EINVAL;
-
-	switch (buf[7]) {
-	case '?':
-		telephony_operator_selection_req(device);
-		break;
-	case '=':
-		return headset_send(hs, "\r\nOK\r\n");
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int nr_and_ec(struct audio_device *device, const char *buf)
-{
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-
-	if (strlen(buf) < 9)
-		return -EINVAL;
-
-	if (buf[8] == '0')
-		slc->nrec_req = FALSE;
-	else
-		slc->nrec_req = TRUE;
-
-	telephony_nr_and_ec_req(device, slc->nrec_req);
-
-	return 0;
-}
-
-static int voice_dial(struct audio_device *device, const char *buf)
-{
-	gboolean enable;
-
-	if (strlen(buf) < 9)
-		return -EINVAL;
-
-	if (buf[8] == '0')
-		enable = FALSE;
-	else
-		enable = TRUE;
-
-	telephony_voice_dial_req(device, enable);
-
-	return 0;
-}
-
-static int apple_command(struct audio_device *device, const char *buf)
-{
-	DBG("Got Apple command: %s", buf);
-
-	return telephony_generic_rsp(device, CME_ERROR_NONE);
-}
-
-static struct event event_callbacks[] = {
-	{ "ATA", answer_call },
-	{ "ATD", dial_number },
-	{ "AT+VG", signal_gain_setting },
-	{ "AT+BRSF", supported_features },
-	{ "AT+CIND", report_indicators },
-	{ "AT+CMER", event_reporting },
-	{ "AT+CHLD", call_hold },
-	{ "AT+CHUP", terminate_call },
-	{ "AT+CKPD", key_press },
-	{ "AT+CLIP", cli_notification },
-	{ "AT+BTRH", response_and_hold },
-	{ "AT+BLDN", last_dialed_number },
-	{ "AT+VTS", dtmf_tone },
-	{ "AT+CNUM", subscriber_number },
-	{ "AT+CLCC", list_current_calls },
-	{ "AT+CMEE", extended_errors },
-	{ "AT+CCWA", call_waiting_notify },
-	{ "AT+COPS", operator_selection },
-	{ "AT+NREC", nr_and_ec },
-	{ "AT+BVRA", voice_dial },
-	{ "AT+XAPL", apple_command },
-	{ "AT+IPHONEACCEV", apple_command },
-	{ 0 }
-};
-
-static int handle_event(struct audio_device *device, const char *buf)
-{
-	struct event *ev;
-
-	DBG("Received %s", buf);
-
-	for (ev = event_callbacks; ev->cmd; ev++) {
-		if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
-			return ev->callback(device, buf);
-	}
-
-	return -EINVAL;
-}
-
 static void close_sco(struct audio_device *device)
 {
 	struct headset *hs = device->headset;
@@ -1265,95 +770,6 @@ static void close_sco(struct audio_device *device)
 	}
 }
 
-static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
-				struct audio_device *device)
-{
-	struct headset *hs;
-	struct headset_slc *slc;
-	unsigned char buf[BUF_SIZE];
-	ssize_t bytes_read;
-	size_t free_space;
-	int fd;
-
-	if (cond & G_IO_NVAL)
-		return FALSE;
-
-	hs = device->headset;
-	slc = hs->slc;
-
-	if (cond & (G_IO_ERR | G_IO_HUP)) {
-		DBG("ERR or HUP on RFCOMM socket");
-		goto failed;
-	}
-
-	fd = g_io_channel_unix_get_fd(chan);
-
-	bytes_read = read(fd, buf, sizeof(buf) - 1);
-	if (bytes_read < 0)
-		return TRUE;
-
-	free_space = sizeof(slc->buf) - slc->data_start -
-			slc->data_length - 1;
-
-	if (free_space < (size_t) bytes_read) {
-		/* Very likely that the HS is sending us garbage so
-		 * just ignore the data and disconnect */
-		error("Too much data to fit incoming buffer");
-		goto failed;
-	}
-
-	memcpy(&slc->buf[slc->data_start], buf, bytes_read);
-	slc->data_length += bytes_read;
-
-	/* Make sure the data is null terminated so we can use string
-	 * functions */
-	slc->buf[slc->data_start + slc->data_length] = '\0';
-
-	while (slc->data_length > 0) {
-		char *cr;
-		int err;
-		off_t cmd_len;
-
-		cr = strchr(&slc->buf[slc->data_start], '\r');
-		if (!cr)
-			break;
-
-		cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start];
-		*cr = '\0';
-
-		if (cmd_len > 1)
-			err = handle_event(device, &slc->buf[slc->data_start]);
-		else
-			/* Silently skip empty commands */
-			err = 0;
-
-		if (err == -EINVAL) {
-			error("Badly formated or unrecognized command: %s",
-					&slc->buf[slc->data_start]);
-			err = telephony_generic_rsp(device,
-						CME_ERROR_NOT_SUPPORTED);
-			if (err < 0)
-				goto failed;
-		} else if (err < 0)
-			error("Error handling command %s: %s (%d)",
-						&slc->buf[slc->data_start],
-						strerror(-err), -err);
-
-		slc->data_start += cmd_len;
-		slc->data_length -= cmd_len;
-
-		if (!slc->data_length)
-			slc->data_start = 0;
-	}
-
-	return TRUE;
-
-failed:
-	headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-
-	return FALSE;
-}
-
 static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
 			struct audio_device *device)
 {
@@ -1372,21 +788,33 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 {
 	struct audio_device *dev = user_data;
 	struct headset *hs = dev->headset;
+	struct btd_device *btd_dev = dev->btd_dev;
+	struct btd_adapter *adapter;
 	struct pending_connect *p = hs->pending;
 	char hs_address[18];
+	struct telephony_device *tel_dev;
 
 	if (err) {
 		error("%s", err->message);
 		goto failed;
 	}
 
+	adapter = device_get_adapter(btd_dev);
+
 	/* For HFP telephony isn't ready just disconnect */
-	if (hs->hfp_active && !ag.telephony_ready) {
+	if (hs->hfp_active && !telephony_is_ready(adapter)) {
 		error("Unable to accept HFP connection since the telephony "
 				"subsystem isn't initialized");
 		goto failed;
 	}
 
+	tel_dev = telephony_device_connecting(chan, btd_dev, dev,
+							hs->connecting_uuid);
+	if (tel_dev == NULL)
+		goto failed;
+
+	hs->connecting_uuid = NULL;
+
 	hs->rfcomm = hs->tmp_rfcomm;
 	hs->tmp_rfcomm = NULL;
 
@@ -1397,42 +825,21 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	else
 		hs->auto_dc = FALSE;
 
-	g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
-			(GIOFunc) rfcomm_io_cb, dev);
-
 	DBG("%s: Connected to %s", dev->path, hs_address);
 
 	hs->slc = g_new0(struct headset_slc, 1);
+	hs->slc->tel_dev = tel_dev;
 	hs->slc->sp_gain = 15;
 	hs->slc->mic_gain = 15;
 	hs->slc->nrec = TRUE;
 
-	/* In HFP mode wait for Service Level Connection */
-	if (hs->hfp_active)
-		return;
-
-	headset_set_state(dev, HEADSET_STATE_CONNECTED);
-
-	if (p && p->target_state == HEADSET_STATE_PLAYING) {
-		p->err = sco_connect(dev, NULL, NULL, NULL);
-		if (p->err < 0)
-			goto failed;
-		return;
-	}
-
-	if (p && p->msg) {
-		DBusMessage *reply = dbus_message_new_method_return(p->msg);
-		g_dbus_send_message(dev->conn, reply);
-	}
-
-	pending_connect_finalize(dev);
-
 	return;
 
 failed:
 	if (p && p->msg)
 		error_connect_failed(dev->conn, p->msg, p->err);
 	pending_connect_finalize(dev);
+
 	if (hs->rfcomm)
 		headset_set_state(dev, HEADSET_STATE_CONNECTED);
 	else
@@ -1574,12 +981,19 @@ static int get_records(struct audio_device *device, headset_stream_cb_t cb,
 		svclass = hs->search_hfp ? HANDSFREE_SVCLASS_ID :
 							HEADSET_SVCLASS_ID;
 
+	if (svclass == HANDSFREE_SVCLASS_ID)
+		hs->connecting_uuid = HFP_AG_UUID;
+	else
+		hs->connecting_uuid = HSP_AG_UUID;
+
 	sdp_uuid16_create(&uuid, svclass);
 
 	err = bt_search_service(&device->src, &device->dst, &uuid,
 						get_record_cb, device, NULL);
-	if (err < 0)
+	if (err < 0) {
+		hs->connecting_uuid = NULL;
 		return err;
+	}
 
 	if (hs->pending) {
 		hs->pending->svclass = svclass;
@@ -1716,6 +1130,7 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
 {
 	struct audio_device *device = data;
 	struct headset *hs = device->headset;
+	struct btd_adapter *adapter;
 	int err;
 
 	if (hs->state == HEADSET_STATE_CONNECTING)
@@ -1723,7 +1138,9 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
 	else if (hs->state > HEADSET_STATE_CONNECTING)
 		return btd_error_already_connected(msg);
 
-	if (hs->hfp_handle && !ag.telephony_ready)
+	adapter = device_get_adapter(device->btd_dev);
+
+	if (hs->hfp_handle && !telephony_is_ready(adapter))
 		return btd_error_not_ready(msg);
 
 	device->auto_connect = FALSE;
@@ -2010,9 +1427,6 @@ static int headset_close_rfcomm(struct audio_device *dev)
 		hs->rfcomm = NULL;
 	}
 
-	g_free(hs->slc);
-	hs->slc = NULL;
-
 	return 0;
 }
 
@@ -2108,7 +1522,7 @@ uint32_t headset_config_init(GKeyFile *config)
 
 	/* Use the default values if there is no config file */
 	if (config == NULL)
-		return ag.features;
+		return telephony_get_ag_features();
 
 	str = g_key_file_get_string(config, "General", "SCORouting",
 					&err);
@@ -2138,7 +1552,7 @@ uint32_t headset_config_init(GKeyFile *config)
 		g_free(str);
 	}
 
-	return ag.features;
+	return telephony_get_ag_features();
 }
 
 static gboolean hs_dc_timeout(struct audio_device *dev)
@@ -2330,6 +1744,13 @@ GIOChannel *headset_get_rfcomm(struct audio_device *dev)
 	return hs->tmp_rfcomm;
 }
 
+void headset_set_connecting_uuid(struct audio_device *dev, const char *uuid)
+{
+	struct headset *hs = dev->headset;
+
+	hs->connecting_uuid = uuid;
+}
+
 int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
 {
 	struct headset *hs = dev->headset;
@@ -2381,6 +1802,14 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 	case HEADSET_STATE_DISCONNECTED:
 		value = FALSE;
 		close_sco(dev);
+
+		if (dev->headset->slc) {
+			telephony_device_disconnect(slc->tel_dev);
+			slc->tel_dev = NULL;
+		}
+
+		dev->headset->connecting_uuid = NULL;
+
 		headset_close_rfcomm(dev);
 		emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "State",
@@ -2393,7 +1822,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 			emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "Connected",
 					DBUS_TYPE_BOOLEAN, &value);
-			telephony_device_disconnected(dev);
 		}
 		active_devices = g_slist_remove(active_devices, dev);
 		break;
@@ -2409,7 +1837,8 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 					AUDIO_HEADSET_INTERFACE, "State",
 					DBUS_TYPE_STRING, &state_str);
 		if (hs->state < state) {
-			if (ag.features & AG_FEATURE_INBAND_RINGTONE)
+			if (telephony_get_ag_features() &
+					AG_FEATURE_INBAND_RINGTONE)
 				slc->inband_ring = TRUE;
 			else
 				slc->inband_ring = FALSE;
@@ -2423,7 +1852,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 						"Connected",
 						DBUS_TYPE_BOOLEAN, &value);
 			active_devices = g_slist_append(active_devices, dev);
-			telephony_device_connected(dev);
 		} else if (hs->state == HEADSET_STATE_PLAYING) {
 			value = FALSE;
 			g_dbus_emit_signal(dev->conn, dev->path,
@@ -2743,15 +2171,13 @@ int telephony_ready_ind(uint32_t features,
 			const struct indicator *indicators, int rh,
 			const char *chld)
 {
-	ag.telephony_ready = TRUE;
-	ag.features = features;
 	ag.indicators = indicators;
 	ag.rh = rh;
 	ag.chld = chld;
 
 	DBG("Telephony plugin initialized");
 
-	print_ag_features(ag.features);
+	print_ag_features(telephony_get_ag_features());
 
 	return 0;
 }
diff --git a/audio/headset.h b/audio/headset.h
index 465c2d6..d877eef 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -110,3 +110,6 @@ gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock);
 gboolean headset_suspend(struct audio_device *dev, void *data);
 gboolean headset_play(struct audio_device *dev, void *data);
 void headset_shutdown(struct audio_device *dev);
+
+void headset_profile_connection_complete(struct audio_device *dev);
+void headset_set_connecting_uuid(struct audio_device *dev, const char *uuid);
diff --git a/audio/manager.c b/audio/manager.c
index 999124d..67193da 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -873,11 +873,12 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
 	adp->powered = powered;
 
 	if (powered) {
-		/* telephony driver already initialized*/
-		if (telephony == TRUE)
-			return;
-		telephony_init();
-		telephony = TRUE;
+		if (telephony == FALSE) {
+			telephony_init();
+			telephony = TRUE;
+		}
+
+		telephony_adapter_init(adapter);
 		return;
 	}
 
@@ -885,6 +886,8 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
 	if (telephony == FALSE)
 		return;
 
+	telephony_adapter_exit(adapter);
+
 	for (l = adapters; l; l = l->next) {
 		adp = l->data;
 
diff --git a/audio/telephony.c b/audio/telephony.c
new file mode 100644
index 0000000..49ccafd
--- /dev/null
+++ b/audio/telephony.c
@@ -0,0 +1,633 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  Frederic Danis <frederic.danis@intel.com>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
+
+#include "btio.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+
+#include "log.h"
+#include "device.h"
+#include "error.h"
+#include "glib-helper.h"
+#include "sdp-client.h"
+#include "headset.h"
+#include "telephony.h"
+#include "dbus-common.h"
+
+#define AUDIO_TELEPHONY_INTERFACE "org.bluez.Telephony"
+#define AUDIO_TELEPHONY_AGENT_INTERFACE "org.bluez.TelephonyAgent"
+
+#define DEFAULT_HS_HS_CHANNEL 6
+#define DEFAULT_HF_HS_CHANNEL 7
+
+/*
+ * Profile configuration
+ *
+ * It describes for each supported profile:
+ *  - UUID, RFCOMM channel and security level
+ *  - remote UUID, service class and profile descriptor if they exist
+ *  - profile connection complete callback called when agent replied to
+ *    NewConnection method call
+ */
+struct profile_config {
+	const char		*uuid;		/* agent property UUID */
+	uint8_t			channel;
+	const char		*r_uuid;
+	uint16_t		r_class;
+	uint16_t		r_profile;
+	DBusPendingCallNotifyFunction connection_reply;
+};
+
+/*
+ * Telephony agent
+ *
+ * It represents the telephony agent with provided version and features.
+ *
+ * This is done by adapter.
+ */
+struct telephony_agent {
+	struct btd_adapter	*btd_adapter;
+	struct profile_config	*config;	/* default configuration */
+	char			*name;		/* agent DBus bus id */
+	char			*path;		/* agent object path */
+	uint16_t		version;	/* agent profile version */
+	uint16_t		features;	/* agent supported features */
+	guint			watch;		/* agent disconnect watcher */
+};
+
+/*
+ * Telephony device
+ *
+ * It represents the connection between telephony agent (name, path and config)
+ * and remote device (with its profile version and supported features if they
+ * can be retrieved).
+ *
+ * This is used after authentication completion and remote SDP record retrieval
+ * (if supported by profile, i.e. HFP/HSP) until disconnection.
+ */
+struct telephony_device {
+	struct btd_device	*btd_dev;
+	struct profile_config	*config;	/* default configuration */
+	char			*name;		/* agent DBus bus id */
+	char			*path;		/* agent object path */
+	struct audio_device	*au_dev;	/* Audio device for HSP/HFP */
+	uint16_t		version;	/* remote profile version */
+	uint16_t		features;	/* remote supported features */
+	GIOChannel		*rfcomm;	/* connected RFCOMM channel */
+	gboolean		pending_sdp;	/* SDP request is pending */
+	DBusPendingCall		*call;		/* D-Bus pending call */
+};
+
+static DBusConnection *connection = NULL;
+
+static GSList *agents = NULL;	/* server list */
+
+static struct telephony_agent *find_agent(struct btd_adapter *adapter,
+					const char *sender, const char *path,
+					const char *uuid)
+{
+	GSList *l;
+
+	for (l = agents; l; l = l->next) {
+		struct telephony_agent *agent = l->data;
+
+		if (agent->btd_adapter != adapter)
+			continue;
+
+		if (sender && g_strcmp0(agent->name, sender) != 0)
+			continue;
+
+		if (path && g_strcmp0(agent->path, path) != 0)
+			continue;
+
+		if (uuid && g_strcmp0(agent->config->uuid, uuid) != 0)
+			continue;
+
+		return agent;
+	}
+
+	return NULL;
+}
+
+static void free_agent(struct telephony_agent *agent)
+{
+	DBusMessage *msg;
+
+	if (agent->watch) {
+		msg = dbus_message_new_method_call(agent->name, agent->path,
+				AUDIO_TELEPHONY_AGENT_INTERFACE, "Release");
+		dbus_message_set_no_reply(msg, TRUE);
+		g_dbus_send_message(connection, msg);
+
+		g_dbus_remove_watch(connection, agent->watch);
+		agent->watch = 0;
+	}
+
+	btd_adapter_unref(agent->btd_adapter);
+	g_free(agent->name);
+	g_free(agent->path);
+	g_free(agent);
+}
+
+gboolean telephony_is_uuid_supported(struct btd_adapter *adapter,
+						const char *uuid)
+{
+	return find_agent(adapter, NULL, NULL, uuid) != NULL;
+}
+
+static gboolean parse_properties(DBusMessageIter *props, const char **uuid,
+				uint16_t *version, uint16_t *features)
+{
+	gboolean has_uuid = FALSE;
+
+	while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
+		const char *key;
+		DBusMessageIter value, entry;
+		int var;
+
+		dbus_message_iter_recurse(props, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
+
+		var = dbus_message_iter_get_arg_type(&value);
+		if (strcasecmp(key, "UUID") == 0) {
+			if (var != DBUS_TYPE_STRING)
+				return FALSE;
+			dbus_message_iter_get_basic(&value, uuid);
+			has_uuid = TRUE;
+		} else if (strcasecmp(key, "Version") == 0) {
+			if (var != DBUS_TYPE_UINT16)
+				return FALSE;
+			dbus_message_iter_get_basic(&value, version);
+		} else if (strcasecmp(key, "Features") == 0) {
+			if (var != DBUS_TYPE_UINT16)
+				return FALSE;
+			dbus_message_iter_get_basic(&value, features);
+		}
+
+		dbus_message_iter_next(props);
+	}
+
+	return has_uuid;
+}
+
+static int dev_close(struct telephony_device *tel_dev)
+{
+	int sock;
+
+	if (tel_dev->rfcomm) {
+		sock = g_io_channel_unix_get_fd(tel_dev->rfcomm);
+		shutdown(sock, SHUT_RDWR);
+
+		g_io_channel_shutdown(tel_dev->rfcomm, TRUE, NULL);
+		g_io_channel_unref(tel_dev->rfcomm);
+
+		tel_dev->rfcomm = NULL;
+	}
+
+	return 0;
+}
+
+static gboolean agent_sendfd(struct telephony_device *tel_dev, int fd,
+				DBusPendingCallNotifyFunction notify)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict;
+	const char *path;
+
+	msg = dbus_message_new_method_call(tel_dev->name, tel_dev->path,
+			AUDIO_TELEPHONY_AGENT_INTERFACE, "NewConnection");
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	path = device_get_path(tel_dev->btd_dev);
+	dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH, &path);
+	dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16,
+							&tel_dev->version);
+
+	if (tel_dev->features != 0xFFFF)
+		dict_append_entry(&dict, "Features", DBUS_TYPE_UINT16,
+							&tel_dev->features);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	if (!dbus_connection_send_with_reply(connection, msg,
+							&tel_dev->call, -1)) {
+		dbus_message_unref(msg);
+		return FALSE;
+	}
+
+	dbus_pending_call_set_notify(tel_dev->call, notify, tel_dev, NULL);
+	dbus_message_unref(msg);
+
+	return TRUE;
+}
+
+static gboolean hs_dev_disconnect_cb(GIOChannel *chan, GIOCondition cond,
+					gpointer data)
+{
+	struct telephony_device *tel_dev = data;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	headset_set_state(tel_dev->au_dev, HEADSET_STATE_DISCONNECTED);
+
+	return FALSE;
+}
+
+static void hs_newconnection_reply(DBusPendingCall *call, void *user_data)
+{
+	struct telephony_device *tel_dev = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		DBG("Agent reply: %s", derr.message);
+		dbus_error_free(&derr);
+		headset_set_state(tel_dev->au_dev, HEADSET_STATE_DISCONNECTED);
+		goto done;
+	}
+
+	DBG("Agent reply: file descriptor passed successfully");
+	g_io_add_watch(tel_dev->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			hs_dev_disconnect_cb, tel_dev);
+	headset_profile_connection_complete(tel_dev->au_dev);
+
+done:
+	dbus_pending_call_unref(tel_dev->call);
+	tel_dev->call = NULL;
+	dbus_message_unref(reply);
+}
+
+static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+	struct telephony_device *tel_dev = user_data;
+	sdp_data_t *sdpdata;
+	uuid_t uuid;
+	sdp_list_t *profiles;
+	sdp_profile_desc_t *desc;
+	int sk;
+
+	tel_dev->pending_sdp = FALSE;
+
+	if (err < 0) {
+		error("Unable to get service record: %s (%d)", strerror(-err),
+					-err);
+		goto failed;
+	}
+
+	if (!recs || !recs->data) {
+		error("No records found");
+		goto failed;
+	}
+
+	if (!tel_dev->rfcomm) {
+		DBG("RFCOMM disconnected from server before sdp reply");
+		goto failed;
+	}
+
+	sdpdata = sdp_data_get(recs->data, SDP_ATTR_SUPPORTED_FEATURES);
+	if (sdpdata && sdpdata->dtd == SDP_UINT16)
+		tel_dev->features = sdpdata->val.uint16;
+
+	sdp_uuid16_create(&uuid, tel_dev->config->r_profile);
+
+	if (sdp_get_profile_descs(recs->data, &profiles) < 0)
+		goto failed;
+
+	desc = profiles->data;
+
+	if (sdp_uuid_cmp(&desc->uuid, &uuid) == 0)
+		tel_dev->version = desc->version;
+
+	sdp_list_free(profiles, free);
+
+	sk = g_io_channel_unix_get_fd(tel_dev->rfcomm);
+
+	if (agent_sendfd(tel_dev, sk, tel_dev->config->connection_reply) ==
+									FALSE) {
+		error("Failed to send RFCOMM socket to agent %s, path %s",
+						tel_dev->name, tel_dev->path);
+		goto failed;
+	}
+
+	return;
+
+failed:
+	headset_set_state(tel_dev->au_dev, HEADSET_STATE_DISCONNECTED);
+}
+
+struct telephony_device *telephony_device_connecting(GIOChannel *io,
+					struct btd_device *btd_dev,
+					struct audio_device *au_dev,
+					const char *uuid)
+{
+	struct btd_adapter *adapter;
+	struct telephony_agent *agent;
+	struct telephony_device *tel_dev;
+	uuid_t r_uuid;
+	int err;
+
+	adapter = device_get_adapter(btd_dev);
+	agent = find_agent(adapter, NULL, NULL, uuid);
+	if (agent == NULL)
+		return NULL;
+
+	tel_dev = g_new0(struct telephony_device, 1);
+	tel_dev->btd_dev = btd_device_ref(btd_dev);
+	tel_dev->name = g_strdup(agent->name);
+	tel_dev->path = g_strdup(agent->path);
+	tel_dev->config = agent->config;
+	tel_dev->au_dev = au_dev;
+	tel_dev->rfcomm = g_io_channel_ref(io);
+	tel_dev->features = 0xFFFF;
+
+	sdp_uuid16_create(&r_uuid, tel_dev->config->r_class);
+
+	err = bt_search_service(&au_dev->src, &au_dev->dst, &r_uuid,
+				get_record_cb, tel_dev, NULL);
+	if (err < 0) {
+		telephony_device_disconnect(tel_dev);
+		return NULL;
+	}
+
+	tel_dev->pending_sdp = TRUE;
+
+	return tel_dev;
+}
+
+void telephony_device_disconnect(struct telephony_device *device)
+{
+	dev_close(device);
+
+	if (device->pending_sdp) {
+		struct btd_adapter *adapter;
+		bdaddr_t src, dst;
+
+		adapter = device_get_adapter(device->btd_dev);
+		adapter_get_address(adapter, &src);
+		device_get_address(device->btd_dev, &dst, NULL);
+		bt_cancel_discovery(&src, &dst);
+	}
+
+	if (device->call) {
+		dbus_pending_call_cancel(device->call);
+		dbus_pending_call_unref(device->call);
+	}
+
+	btd_device_unref(device->btd_dev);
+	g_free(device->name);
+	g_free(device->path);
+	g_free(device);
+}
+
+gboolean telephony_is_ready(struct btd_adapter *adapter)
+{
+	return find_agent(adapter, NULL, NULL, HFP_AG_UUID) ? TRUE : FALSE;
+}
+
+uint32_t telephony_get_ag_features(void)
+{
+	return 0;
+}
+
+static struct profile_config default_configs[] = {
+	{ HSP_AG_UUID,
+		DEFAULT_HS_AG_CHANNEL,
+		HSP_HS_UUID,
+		HEADSET_SVCLASS_ID,
+		HEADSET_PROFILE_ID,
+		hs_newconnection_reply },
+	{ HFP_AG_UUID,
+		DEFAULT_HF_AG_CHANNEL,
+		HFP_HS_UUID,
+		HANDSFREE_SVCLASS_ID,
+		HANDSFREE_PROFILE_ID,
+		hs_newconnection_reply },
+};
+
+static void agent_disconnect_cb(DBusConnection *conn, void *user_data)
+{
+	struct telephony_agent *agent = user_data;
+
+	DBG("Agent exited without calling Unregister");
+
+	agent->watch = 0;
+	agents = g_slist_remove(agents, agent);
+	free_agent(agent);
+}
+
+static struct telephony_agent *agent_new(struct btd_adapter *adapter,
+					const char *sender, const char *path,
+					const char *uuid, uint16_t version,
+					uint16_t features)
+{
+	unsigned int i;
+
+	for (i = 0; i < G_N_ELEMENTS(default_configs) ; i++) {
+		if (strcasecmp(uuid, default_configs[i].uuid) == 0) {
+			struct telephony_agent *agent;
+
+			agent = g_new0(struct telephony_agent, 1);
+			agent->btd_adapter = btd_adapter_ref(adapter);
+			agent->config = &default_configs[i];
+			agent->name = g_strdup(sender);
+			agent->path = g_strdup(path);
+			agent->version = version;
+			agent->features = features;
+
+			return agent;
+		}
+	}
+
+	return NULL;
+}
+
+static DBusMessage *register_agent(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct btd_adapter *adapter = data;
+	DBusMessageIter args, props;
+	const char *sender, *path, *uuid;
+	uint16_t version = 0;
+	uint16_t features = 0xFFFF;
+	struct telephony_agent *agent;
+
+	sender = dbus_message_get_sender(msg);
+
+	dbus_message_iter_init(msg, &args);
+
+	dbus_message_iter_get_basic(&args, &path);
+	dbus_message_iter_next(&args);
+
+	if (find_agent(adapter, sender, path, NULL) != NULL)
+		return btd_error_already_exists(msg);
+
+	dbus_message_iter_recurse(&args, &props);
+	if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
+		return btd_error_invalid_args(msg);
+
+	if (!parse_properties(&props, &uuid, &version, &features))
+		return btd_error_invalid_args(msg);
+
+	if (find_agent(adapter, NULL, NULL, uuid) != NULL)
+		return btd_error_already_exists(msg);
+
+	/* initialize agent properties */
+	agent = agent_new(adapter, sender, path, uuid, version, features);
+	if (agent == NULL)
+		return btd_error_invalid_args(msg);
+
+	agent->watch = g_dbus_add_disconnect_watch(conn, sender,
+							agent_disconnect_cb,
+							agent, NULL);
+
+	DBG("Register agent : %s%s for %s version 0x%04X with features 0x%02X",
+					sender, path, uuid, version, features);
+
+	agents = g_slist_append(agents, agent);
+
+	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *unregister_agent(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	struct btd_adapter *adapter = data;
+	const char *sender, *path;
+	struct telephony_agent *agent;
+
+	if (!dbus_message_get_args(msg, NULL,
+				DBUS_TYPE_OBJECT_PATH, &path,
+				DBUS_TYPE_INVALID))
+		return NULL;
+
+	sender = dbus_message_get_sender(msg);
+
+	agent = find_agent(adapter, sender, path, NULL);
+	if (agent == NULL)
+		return btd_error_does_not_exist(msg);
+
+	agents = g_slist_remove(agents, agent);
+
+	DBG("Unregister agent : %s%s", sender, path);
+
+	free_agent(agent);
+
+	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable telsrv_methods[] = {
+	{ GDBUS_METHOD("RegisterAgent",
+			GDBUS_ARGS({ "agent", "o" }, { "properties", "a{sv}" }),
+			NULL, register_agent) },
+	{ GDBUS_METHOD("UnregisterAgent",
+			GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
+	{ }
+};
+
+static void path_unregister(void *data)
+{
+	DBG("Unregistered interface %s", AUDIO_TELEPHONY_INTERFACE);
+}
+
+int telephony_adapter_init(struct btd_adapter *adapter)
+{
+	const char *path;
+
+	DBG("adapter: %p", adapter);
+
+	path = adapter_get_path(adapter);
+
+	if (!g_dbus_register_interface(connection, path,
+					AUDIO_TELEPHONY_INTERFACE,
+					telsrv_methods, NULL,
+					NULL, adapter, path_unregister)) {
+		error("D-Bus failed to register %s interface",
+				AUDIO_TELEPHONY_INTERFACE);
+		return -1;
+	}
+
+	DBG("Registered interface %s", AUDIO_TELEPHONY_INTERFACE);
+
+	return 0;
+}
+
+void telephony_adapter_exit(struct btd_adapter *adapter)
+{
+	struct telephony_agent *agent;
+
+	DBG("adapter: %p", adapter);
+
+	g_dbus_unregister_interface(connection, adapter_get_path(adapter),
+			AUDIO_TELEPHONY_INTERFACE);
+
+	while ((agent = find_agent(adapter, NULL, NULL, NULL)) != NULL) {
+		agents = g_slist_remove(agents, agent);
+		free_agent(agent);
+	}
+}
+
+int telephony_init(void)
+{
+	DBG("");
+
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+	return 0;
+}
+
+void telephony_exit(void)
+{
+	DBG("");
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+}
diff --git a/audio/telephony.h b/audio/telephony.h
index 73b390c..f835202 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -141,29 +141,18 @@ struct indicator {
 	gboolean ignore_redundant;
 };
 
-/* Notify telephony-*.c of connected/disconnected devices. Implemented by
- * telephony-*.c
- */
-void telephony_device_connected(void *telephony_device);
-void telephony_device_disconnected(void *telephony_device);
+struct telephony_device;
 
-/* HF requests (sent by the handsfree device). These are implemented by
- * telephony-*.c
- */
-void telephony_event_reporting_req(void *telephony_device, int ind);
-void telephony_response_and_hold_req(void *telephony_device, int rh);
-void telephony_last_dialed_number_req(void *telephony_device);
-void telephony_terminate_call_req(void *telephony_device);
-void telephony_answer_call_req(void *telephony_device);
-void telephony_dial_number_req(void *telephony_device, const char *number);
-void telephony_transmit_dtmf_req(void *telephony_device, char tone);
-void telephony_subscriber_number_req(void *telephony_device);
-void telephony_list_current_calls_req(void *telephony_device);
-void telephony_operator_selection_req(void *telephony_device);
-void telephony_call_hold_req(void *telephony_device, const char *cmd);
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable);
-void telephony_voice_dial_req(void *telephony_device, gboolean enable);
-void telephony_key_press_req(void *telephony_device, const char *keys);
+struct telephony_device *telephony_device_connecting(GIOChannel *io,
+					struct btd_device *btd_dev,
+					struct audio_device *au_dev,
+					const char *uuid);
+void telephony_device_disconnect(struct telephony_device *device);
+
+gboolean telephony_is_ready(struct btd_adapter *adapter);
+uint32_t telephony_get_ag_features(void);
+gboolean telephony_is_uuid_supported(struct btd_adapter *adapter,
+						const char *uuid);
 
 /* AG responses to HF requests. These are implemented by headset.c */
 int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err);
@@ -240,5 +229,7 @@ static inline int telephony_get_indicator(const struct indicator *indicators,
 	return -ENOENT;
 }
 
+int telephony_adapter_init(struct btd_adapter *adapter);
+void telephony_adapter_exit(struct btd_adapter *adapter);
 int telephony_init(void);
 void telephony_exit(void);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 04/15] audio: Simplify org.bluez.Headset
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (2 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 03/15] audio: Move telephony drivers to D-Bus interface Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 05/15] audio: Remove dummy telephony driver Frédéric Danis
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Simplify org.bluez.Headset interface by removing methods, signal and
properties which should be managed by external telephony program.
In audio/headset.[ch], remove functions no more used by telephony
drivers.

Move SpeakerGain and MicrophoneGain properties to Media Transport.
---
 Makefile.am       |    4 +-
 audio/audio.conf  |    7 -
 audio/headset.c   |  939 +----------------------------------------------------
 audio/headset.h   |    5 -
 audio/manager.c   |   19 --
 audio/manager.h   |    4 -
 audio/telephony.h |  171 ----------
 audio/transport.c |   90 +++--
 doc/audio-api.txt |  167 ++--------
 doc/media-api.txt |   19 +-
 10 files changed, 106 insertions(+), 1319 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 2a8b903..b18450c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -315,9 +315,7 @@ endif
 EXTRA_DIST += src/genbuiltin src/bluetooth.conf src/org.bluez.service \
 			src/main.conf profiles/network/network.conf \
 			profiles/input/input.conf profiles/proximity/proximity.conf \
-			audio/audio.conf audio/telephony-dummy.c \
-			audio/telephony-maemo5.c audio/telephony-ofono.c \
-			audio/telephony-maemo6.c profiles/sap/sap-dummy.c \
+			audio/audio.conf profiles/sap/sap-dummy.c \
 			profiles/sap/sap-u8500.c
 
 if AUDIOPLUGIN
diff --git a/audio/audio.conf b/audio/audio.conf
index 662647c..9e9e664 100644
--- a/audio/audio.conf
+++ b/audio/audio.conf
@@ -31,10 +31,3 @@ HFP=true
 
 # Maximum number of connected HSP/HFP devices per adapter. Defaults to 1
 MaxConnected=1
-
-# Set to true to enable use of fast connectable mode (faster page scanning)
-# for HFP when incoming call starts. Default settings are restored after
-# call is answered or rejected. Page scan interval is much shorter and page
-# scan type changed to interlaced. Such allows faster connection initiated
-# by a headset.
-FastConnectable=false
diff --git a/audio/headset.c b/audio/headset.c
index 668e9f1..0070953 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -63,35 +63,7 @@
 
 #define DC_TIMEOUT 3
 
-#define RING_INTERVAL 3
-
-#define BUF_SIZE 1024
-
-#define HEADSET_GAIN_SPEAKER 'S'
-#define HEADSET_GAIN_MICROPHONE 'M'
-
-static struct {
-	const struct indicator *indicators;	/* Available HFP indicators */
-	int er_mode;			/* Event reporting mode */
-	int er_ind;			/* Event reporting for indicators */
-	int rh;				/* Response and Hold state */
-	char *number;			/* Incoming phone number */
-	int number_type;		/* Incoming number type */
-	guint ring_timer;		/* For incoming call indication */
-	const char *chld;		/* Response to AT+CHLD=? */
-} ag = {
-	.er_mode = 3,
-	.er_ind = 0,
-	.rh = BTRH_NOT_SUPPORTED,
-	.number = NULL,
-	.number_type = 0,
-	.ring_timer = 0,
-};
-
 static gboolean sco_hci = TRUE;
-static gboolean fast_connectable = FALSE;
-
-static GSList *active_devices = NULL;
 
 static char *str_state[] = {
 	"HEADSET_STATE_DISCONNECTED",
@@ -129,30 +101,12 @@ struct pending_connect {
 	uint16_t svclass;
 };
 
-struct headset_slc {
-	struct telephony_device *tel_dev;
-
-	gboolean cli_active;
-	gboolean cme_enabled;
-	gboolean cwa_enabled;
-	gboolean pending_ring;
-	gboolean inband_ring;
-	gboolean nrec;
-	gboolean nrec_req;
-
-	int sp_gain;
-	int mic_gain;
-
-	unsigned int hf_features;
-};
-
 struct headset {
 	uint32_t hsp_handle;
 	uint32_t hfp_handle;
 
 	int rfcomm_ch;
 
-	GIOChannel *rfcomm;
 	GIOChannel *tmp_rfcomm;
 	const char *connecting_uuid;
 	GIOChannel *sco;
@@ -170,15 +124,10 @@ struct headset {
 	struct pending_connect *pending;
 
 	headset_lock_t lock;
-	struct headset_slc *slc;
+	struct telephony_device *tel_dev;
 	GSList *nrec_cbs;
 };
 
-struct event {
-	const char *cmd;
-	int (*callback) (struct audio_device *device, const char *buf);
-};
-
 static GSList *headset_callbacks = NULL;
 
 static void error_connect_failed(DBusConnection *conn, DBusMessage *msg,
@@ -194,44 +143,6 @@ static int rfcomm_connect(struct audio_device *device, headset_stream_cb_t cb,
 static int get_records(struct audio_device *device, headset_stream_cb_t cb,
 			void *user_data, unsigned int *cb_id);
 
-static void print_ag_features(uint32_t features)
-{
-	GString *gstr;
-	char *str;
-
-	if (features == 0) {
-		DBG("HFP AG features: (none)");
-		return;
-	}
-
-	gstr = g_string_new("HFP AG features: ");
-
-	if (features & AG_FEATURE_THREE_WAY_CALLING)
-		g_string_append(gstr, "\"Three-way calling\" ");
-	if (features & AG_FEATURE_EC_ANDOR_NR)
-		g_string_append(gstr, "\"EC and/or NR function\" ");
-	if (features & AG_FEATURE_VOICE_RECOGNITION)
-		g_string_append(gstr, "\"Voice recognition function\" ");
-	if (features & AG_FEATURE_INBAND_RINGTONE)
-		g_string_append(gstr, "\"In-band ring tone capability\" ");
-	if (features & AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG)
-		g_string_append(gstr, "\"Attach a number to a voice tag\" ");
-	if (features & AG_FEATURE_REJECT_A_CALL)
-		g_string_append(gstr, "\"Ability to reject a call\" ");
-	if (features & AG_FEATURE_ENHANCED_CALL_STATUS)
-		g_string_append(gstr, "\"Enhanced call status\" ");
-	if (features & AG_FEATURE_ENHANCED_CALL_CONTROL)
-		g_string_append(gstr, "\"Enhanced call control\" ");
-	if (features & AG_FEATURE_EXTENDED_ERROR_RESULT_CODES)
-		g_string_append(gstr, "\"Extended Error Result Codes\" ");
-
-	str = g_string_free(gstr, FALSE);
-
-	DBG("%s", str);
-
-	g_free(str);
-}
-
 static const char *state2str(headset_state_t state)
 {
 	switch (state) {
@@ -249,52 +160,6 @@ static const char *state2str(headset_state_t state)
 	return NULL;
 }
 
-static int headset_send_valist(struct headset *hs, char *format, va_list ap)
-{
-	char rsp[BUF_SIZE];
-	ssize_t total_written, count;
-	int fd;
-
-	count = vsnprintf(rsp, sizeof(rsp), format, ap);
-
-	if (count < 0)
-		return -EINVAL;
-
-	if (!hs->rfcomm) {
-		error("headset_send: the headset is not connected");
-		return -EIO;
-	}
-
-	total_written = 0;
-	fd = g_io_channel_unix_get_fd(hs->rfcomm);
-
-	while (total_written < count) {
-		ssize_t written;
-
-		written = write(fd, rsp + total_written,
-				count - total_written);
-		if (written < 0)
-			return -errno;
-
-		total_written += written;
-	}
-
-	return 0;
-}
-
-static int __attribute__((format(printf, 2, 3)))
-			headset_send(struct headset *hs, char *format, ...)
-{
-	va_list ap;
-	int ret;
-
-	va_start(ap, format);
-	ret = headset_send_valist(hs, format, ap);
-	va_end(ap);
-
-	return ret;
-}
-
 static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
 {
 	struct headset *hs = dev->headset;
@@ -375,64 +240,11 @@ static unsigned int connect_cb_new(struct headset *hs,
 	return cb->id;
 }
 
-static void __attribute__((format(printf, 3, 4)))
-		send_foreach_headset(GSList *devices,
-					int (*cmp) (struct headset *hs),
-					char *format, ...)
-{
-	GSList *l;
-	va_list ap;
-
-	for (l = devices; l != NULL; l = l->next) {
-		struct audio_device *device = l->data;
-		struct headset *hs = device->headset;
-		int ret;
-
-		assert(hs != NULL);
-
-		if (cmp && cmp(hs) != 0)
-			continue;
-
-		va_start(ap, format);
-		ret = headset_send_valist(hs, format, ap);
-		if (ret < 0)
-			error("Failed to send to headset: %s (%d)",
-					strerror(-ret), -ret);
-		va_end(ap);
-	}
-}
-
-static int cli_cmp(struct headset *hs)
-{
-	struct headset_slc *slc = hs->slc;
-
-	if (!hs->hfp_active)
-		return -1;
-
-	if (slc->cli_active)
-		return 0;
-	else
-		return -1;
-}
-
-static gboolean ring_timer_cb(gpointer data)
-{
-	send_foreach_headset(active_devices, NULL, "\r\nRING\r\n");
-
-	if (ag.number)
-		send_foreach_headset(active_devices, cli_cmp,
-					"\r\n+CLIP: \"%s\",%d\r\n",
-					ag.number, ag.number_type);
-
-	return TRUE;
-}
-
 static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 {
 	int sk;
 	struct audio_device *dev = user_data;
 	struct headset *hs = dev->headset;
-	struct headset_slc *slc = hs->slc;
 	struct pending_connect *p = hs->pending;
 
 	if (err) {
@@ -445,7 +257,7 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 			pending_connect_finalize(dev);
 		}
 
-		if (hs->rfcomm)
+		if (hs->tel_dev)
 			headset_set_state(dev, HEADSET_STATE_CONNECTED);
 		else
 			headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
@@ -473,14 +285,6 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	fcntl(sk, F_SETFL, 0);
 
 	headset_set_state(dev, HEADSET_STATE_PLAYING);
-
-	if (slc->pending_ring) {
-		ring_timer_cb(NULL);
-		ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
-						ring_timer_cb,
-						NULL);
-		slc->pending_ring = FALSE;
-	}
 }
 
 static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb,
@@ -519,14 +323,6 @@ static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb,
 	return 0;
 }
 
-static int hfp_cmp(struct headset *hs)
-{
-	if (hs->hfp_active)
-		return 0;
-	else
-		return -1;
-}
-
 void headset_profile_connection_complete(struct audio_device *dev)
 {
 	struct headset *hs = dev->headset;
@@ -556,202 +352,6 @@ void headset_profile_connection_complete(struct audio_device *dev)
 	}
 }
 
-static int telephony_generic_rsp(struct audio_device *device, cme_error_t err)
-{
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-
-	if ((err != CME_ERROR_NONE) && slc->cme_enabled)
-		return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
-
-	switch (err) {
-	case CME_ERROR_NONE:
-		return headset_send(hs, "\r\nOK\r\n");
-	case CME_ERROR_NO_NETWORK_SERVICE:
-		return headset_send(hs, "\r\nNO CARRIER\r\n");
-	default:
-		return headset_send(hs, "\r\nERROR\r\n");
-	}
-}
-
-int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
-{
-	struct audio_device *device = telephony_device;
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-	uint32_t ag_features;
-	int ret;
-
-	if (err != CME_ERROR_NONE)
-		return telephony_generic_rsp(telephony_device, err);
-
-	ret = headset_send(hs, "\r\nOK\r\n");
-	if (ret < 0)
-		return ret;
-
-	if (hs->state != HEADSET_STATE_CONNECTING)
-		return 0;
-
-	ag_features = telephony_get_ag_features();
-	if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
-			ag_features & AG_FEATURE_THREE_WAY_CALLING)
-		return 0;
-
-	headset_profile_connection_complete(device);
-
-	return 0;
-}
-
-int telephony_key_press_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_answer_call_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_terminate_call_rsp(void *telephony_device,
-					cme_error_t err)
-{
-	struct audio_device *device = telephony_device;
-	struct headset *hs = device->headset;
-
-	if (err != CME_ERROR_NONE)
-		return telephony_generic_rsp(telephony_device, err);
-
-	g_dbus_emit_signal(device->conn, device->path,
-			AUDIO_HEADSET_INTERFACE, "CallTerminated",
-			DBUS_TYPE_INVALID);
-
-	return headset_send(hs, "\r\nOK\r\n");
-}
-
-int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_dial_number_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
-{
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-	const char *name, *property;
-
-	if (gain > 15) {
-		error("Invalid gain value: %u", gain);
-		return -EINVAL;
-	}
-
-	switch (type) {
-	case HEADSET_GAIN_SPEAKER:
-		if (slc->sp_gain == gain) {
-			DBG("Ignoring no-change in speaker gain");
-			return -EALREADY;
-		}
-		name = "SpeakerGainChanged";
-		property = "SpeakerGain";
-		slc->sp_gain = gain;
-		break;
-	case HEADSET_GAIN_MICROPHONE:
-		if (slc->mic_gain == gain) {
-			DBG("Ignoring no-change in microphone gain");
-			return -EALREADY;
-		}
-		name = "MicrophoneGainChanged";
-		property = "MicrophoneGain";
-		slc->mic_gain = gain;
-		break;
-	default:
-		error("Unknown gain setting");
-		return -EINVAL;
-	}
-
-	g_dbus_emit_signal(device->conn, device->path,
-				AUDIO_HEADSET_INTERFACE, name,
-				DBUS_TYPE_UINT16, &gain,
-				DBUS_TYPE_INVALID);
-
-	emit_property_changed(device->conn, device->path,
-				AUDIO_HEADSET_INTERFACE, property,
-				DBUS_TYPE_UINT16, &gain);
-
-	return 0;
-}
-
-int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_call_hold_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err)
-{
-	struct audio_device *device = telephony_device;
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-
-	if (err == CME_ERROR_NONE) {
-		GSList *l;
-
-		for (l = hs->nrec_cbs; l; l = l->next) {
-			struct headset_nrec_callback *nrec_cb = l->data;
-
-			nrec_cb->cb(device, slc->nrec_req, nrec_cb->user_data);
-		}
-
-		slc->nrec = hs->slc->nrec_req;
-	}
-
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err)
-{
-	return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_operator_selection_ind(int mode, const char *oper)
-{
-	if (!active_devices)
-		return -ENODEV;
-
-	send_foreach_headset(active_devices, hfp_cmp,
-				"\r\n+COPS: %d,0,\"%s\"\r\n",
-				mode, oper);
-	return 0;
-}
-
 static void close_sco(struct audio_device *device)
 {
 	struct headset *hs = device->headset;
@@ -792,7 +392,6 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	struct btd_adapter *adapter;
 	struct pending_connect *p = hs->pending;
 	char hs_address[18];
-	struct telephony_device *tel_dev;
 
 	if (err) {
 		error("%s", err->message);
@@ -808,14 +407,14 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 		goto failed;
 	}
 
-	tel_dev = telephony_device_connecting(chan, btd_dev, dev,
+	hs->tel_dev = telephony_device_connecting(chan, btd_dev, dev,
 							hs->connecting_uuid);
-	if (tel_dev == NULL)
+	if (hs->tel_dev == NULL)
 		goto failed;
 
 	hs->connecting_uuid = NULL;
 
-	hs->rfcomm = hs->tmp_rfcomm;
+	g_io_channel_unref(hs->tmp_rfcomm);
 	hs->tmp_rfcomm = NULL;
 
 	ba2str(&dev->dst, hs_address);
@@ -827,12 +426,6 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 
 	DBG("%s: Connected to %s", dev->path, hs_address);
 
-	hs->slc = g_new0(struct headset_slc, 1);
-	hs->slc->tel_dev = tel_dev;
-	hs->slc->sp_gain = 15;
-	hs->slc->mic_gain = 15;
-	hs->slc->nrec = TRUE;
-
 	return;
 
 failed:
@@ -840,10 +433,7 @@ failed:
 		error_connect_failed(dev->conn, p->msg, p->err);
 	pending_connect_finalize(dev);
 
-	if (hs->rfcomm)
-		headset_set_state(dev, HEADSET_STATE_CONNECTED);
-	else
-		headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+	headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
 }
 
 static int headset_set_channel(struct headset *headset,
@@ -1105,26 +695,6 @@ static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,
 
 }
 
-static DBusMessage *hs_is_connected(DBusConnection *conn,
-						DBusMessage *msg,
-						void *data)
-{
-	struct audio_device *device = data;
-	DBusMessage *reply;
-	dbus_bool_t connected;
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	connected = (device->headset->state >= HEADSET_STATE_CONNECTED);
-
-	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
-					DBUS_TYPE_INVALID);
-
-	return reply;
-}
-
 static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
@@ -1156,95 +726,6 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
-static DBusMessage *hs_ring(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	struct audio_device *device = data;
-	struct headset *hs = device->headset;
-	DBusMessage *reply = NULL;
-	int err;
-
-	if (hs->state < HEADSET_STATE_CONNECTED)
-		return btd_error_not_connected(msg);
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	if (ag.ring_timer) {
-		DBG("IndicateCall received when already indicating");
-		return reply;
-	}
-
-	err = headset_send(hs, "\r\nRING\r\n");
-	if (err < 0) {
-		dbus_message_unref(reply);
-		return btd_error_failed(msg, strerror(-err));
-	}
-
-	ring_timer_cb(NULL);
-	ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,
-						NULL);
-
-	return reply;
-}
-
-static DBusMessage *hs_cancel_call(DBusConnection *conn,
-					DBusMessage *msg,
-					void *data)
-{
-	struct audio_device *device = data;
-	struct headset *hs = device->headset;
-	DBusMessage *reply = NULL;
-
-	if (hs->state < HEADSET_STATE_CONNECTED)
-		return btd_error_not_connected(msg);
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	if (ag.ring_timer) {
-		g_source_remove(ag.ring_timer);
-		ag.ring_timer = 0;
-	} else
-		DBG("Got CancelCall method call but no call is active");
-
-	return reply;
-}
-
-static DBusMessage *hs_set_gain(DBusConnection *conn,
-				DBusMessage *msg,
-				void *data, uint16_t gain,
-				char type)
-{
-	struct audio_device *device = data;
-	struct headset *hs = device->headset;
-	DBusMessage *reply;
-	int err;
-
-	if (hs->state < HEADSET_STATE_CONNECTED)
-		return btd_error_not_connected(msg);
-
-	err = headset_set_gain(device, gain, type);
-	if (err < 0)
-		return btd_error_invalid_args(msg);
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	if (hs->state == HEADSET_STATE_PLAYING) {
-		err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain);
-		if (err < 0) {
-			dbus_message_unref(reply);
-			return btd_error_failed(msg, strerror(-err));
-		}
-	}
-
-	return reply;
-}
-
 static DBusMessage *hs_get_properties(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
@@ -1280,94 +761,22 @@ static DBusMessage *hs_get_properties(DBusConnection *conn,
 	value = (device->headset->state >= HEADSET_STATE_CONNECTED);
 	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
 
-	if (!value)
-		goto done;
-
-	/* SpeakerGain */
-	dict_append_entry(&dict, "SpeakerGain",
-				DBUS_TYPE_UINT16,
-				&device->headset->slc->sp_gain);
-
-	/* MicrophoneGain */
-	dict_append_entry(&dict, "MicrophoneGain",
-				DBUS_TYPE_UINT16,
-				&device->headset->slc->mic_gain);
-
-done:
 	dbus_message_iter_close_container(&iter, &dict);
 
 	return reply;
 }
 
-static DBusMessage *hs_set_property(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	const char *property;
-	DBusMessageIter iter;
-	DBusMessageIter sub;
-	uint16_t gain;
-
-	if (!dbus_message_iter_init(msg, &iter))
-		return btd_error_invalid_args(msg);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		return btd_error_invalid_args(msg);
-
-	dbus_message_iter_get_basic(&iter, &property);
-	dbus_message_iter_next(&iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-		return btd_error_invalid_args(msg);
-	dbus_message_iter_recurse(&iter, &sub);
-
-	if (g_str_equal("SpeakerGain", property)) {
-		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
-			return btd_error_invalid_args(msg);
-
-		dbus_message_iter_get_basic(&sub, &gain);
-		return hs_set_gain(conn, msg, data, gain,
-					HEADSET_GAIN_SPEAKER);
-	} else if (g_str_equal("MicrophoneGain", property)) {
-		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
-			return btd_error_invalid_args(msg);
-
-		dbus_message_iter_get_basic(&sub, &gain);
-		return hs_set_gain(conn, msg, data, gain,
-					HEADSET_GAIN_MICROPHONE);
-	}
-
-	return btd_error_invalid_args(msg);
-}
-
 static const GDBusMethodTable headset_methods[] = {
 	{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, hs_connect) },
 	{ GDBUS_METHOD("Disconnect", NULL, NULL, hs_disconnect) },
-	{ GDBUS_METHOD("IsConnected",
-			NULL, GDBUS_ARGS({ "connected", "b" }),
-			hs_is_connected) },
-	{ GDBUS_METHOD("IndicateCall", NULL, NULL, hs_ring) },
-	{ GDBUS_METHOD("CancelCall", NULL, NULL, hs_cancel_call) },
 	{ GDBUS_METHOD("Stop", NULL, NULL, hs_stop) },
 	{ GDBUS_METHOD("GetProperties",
 			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
 			hs_get_properties) },
-	{ GDBUS_METHOD("SetProperty",
-			GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
-			hs_set_property) },
 	{ }
 };
 
 static const GDBusSignalTable headset_signals[] = {
-	{ GDBUS_DEPRECATED_SIGNAL("Connected", NULL) },
-	{ GDBUS_DEPRECATED_SIGNAL("Disconnected", NULL) },
-	{ GDBUS_SIGNAL("AnswerRequested", NULL) },
-	{ GDBUS_DEPRECATED_SIGNAL("Stopped", NULL) },
-	{ GDBUS_DEPRECATED_SIGNAL("Playing", NULL) },
-	{ GDBUS_DEPRECATED_SIGNAL("SpeakerGainChanged",
-						GDBUS_ARGS({ "gain", "q" })) },
-	{ GDBUS_DEPRECATED_SIGNAL("MicrophoneGainChanged",
-						GDBUS_ARGS({ "gain", "q" })) },
-	{ GDBUS_SIGNAL("CallTerminated", NULL) },
 	{ GDBUS_SIGNAL("PropertyChanged",
 			GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
 	{ }
@@ -1418,13 +827,11 @@ void headset_update(struct audio_device *dev, uint16_t svc,
 static int headset_close_rfcomm(struct audio_device *dev)
 {
 	struct headset *hs = dev->headset;
-	GIOChannel *rfcomm = hs->tmp_rfcomm ? hs->tmp_rfcomm : hs->rfcomm;
 
-	if (rfcomm) {
-		g_io_channel_shutdown(rfcomm, TRUE, NULL);
-		g_io_channel_unref(rfcomm);
+	if (hs->tmp_rfcomm) {
+		g_io_channel_shutdown(hs->tmp_rfcomm, TRUE, NULL);
+		g_io_channel_unref(hs->tmp_rfcomm);
 		hs->tmp_rfcomm = NULL;
-		hs->rfcomm = NULL;
 	}
 
 	return 0;
@@ -1539,19 +946,6 @@ uint32_t headset_config_init(GKeyFile *config)
 		g_free(str);
 	}
 
-	/* Init fast connectable option */
-	str = g_key_file_get_string(config, "Headset", "FastConnectable",
-					&err);
-	if (err) {
-		DBG("audio.conf: %s", err->message);
-		g_clear_error(&err);
-	} else {
-		fast_connectable = strcmp(str, "true") == 0;
-		if (fast_connectable)
-			manager_set_fast_connectable(FALSE);
-		g_free(str);
-	}
-
 	return telephony_get_ag_features();
 }
 
@@ -1590,7 +984,7 @@ gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id)
 		return TRUE;
 
 	if (hs->auto_dc) {
-		if (hs->rfcomm)
+		if (hs->tel_dev)
 			hs->dc_timer = g_timeout_add_seconds(DC_TIMEOUT,
 						(GSourceFunc) hs_dc_timeout,
 						dev);
@@ -1629,7 +1023,7 @@ unsigned int headset_request_stream(struct audio_device *dev,
 			hs->state == HEADSET_STATE_PLAY_IN_PROGRESS)
 		return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);
 
-	if (hs->rfcomm == NULL) {
+	if (hs->tel_dev == NULL) {
 		if (rfcomm_connect(dev, cb, user_data, &id) < 0)
 			return 0;
 		hs->auto_dc = TRUE;
@@ -1658,7 +1052,7 @@ unsigned int headset_config_stream(struct audio_device *dev,
 		return connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb,
 					user_data);
 
-	if (hs->rfcomm)
+	if (hs->tel_dev)
 		goto done;
 
 	if (rfcomm_connect(dev, cb, user_data, &id) < 0)
@@ -1766,29 +1160,18 @@ int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
 int headset_connect_sco(struct audio_device *dev, GIOChannel *io)
 {
 	struct headset *hs = dev->headset;
-	struct headset_slc *slc = hs->slc;
 
 	if (hs->sco)
 		return -EISCONN;
 
 	hs->sco = g_io_channel_ref(io);
 
-	if (slc->pending_ring) {
-		ring_timer_cb(NULL);
-		ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
-						ring_timer_cb,
-						NULL);
-		slc->pending_ring = FALSE;
-	}
-
 	return 0;
 }
 
 void headset_set_state(struct audio_device *dev, headset_state_t state)
 {
 	struct headset *hs = dev->headset;
-	struct headset_slc *slc = hs->slc;
-	gboolean value;
 	const char *state_str;
 	headset_state_t old_state = hs->state;
 	GSList *l;
@@ -1800,12 +1183,11 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 
 	switch (state) {
 	case HEADSET_STATE_DISCONNECTED:
-		value = FALSE;
 		close_sco(dev);
 
-		if (dev->headset->slc) {
-			telephony_device_disconnect(slc->tel_dev);
-			slc->tel_dev = NULL;
+		if (dev->headset->tel_dev) {
+			telephony_device_disconnect(dev->headset->tel_dev);
+			dev->headset->tel_dev = NULL;
 		}
 
 		dev->headset->connecting_uuid = NULL;
@@ -1814,16 +1196,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 		emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "State",
 					DBUS_TYPE_STRING, &state_str);
-		g_dbus_emit_signal(dev->conn, dev->path,
-					AUDIO_HEADSET_INTERFACE,
-					"Disconnected",
-					DBUS_TYPE_INVALID);
-		if (hs->state > HEADSET_STATE_CONNECTING) {
-			emit_property_changed(dev->conn, dev->path,
-					AUDIO_HEADSET_INTERFACE, "Connected",
-					DBUS_TYPE_BOOLEAN, &value);
-		}
-		active_devices = g_slist_remove(active_devices, dev);
 		break;
 	case HEADSET_STATE_CONNECTING:
 		emit_property_changed(dev->conn, dev->path,
@@ -1836,38 +1208,10 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 			emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "State",
 					DBUS_TYPE_STRING, &state_str);
-		if (hs->state < state) {
-			if (telephony_get_ag_features() &
-					AG_FEATURE_INBAND_RINGTONE)
-				slc->inband_ring = TRUE;
-			else
-				slc->inband_ring = FALSE;
-			g_dbus_emit_signal(dev->conn, dev->path,
-						AUDIO_HEADSET_INTERFACE,
-						"Connected",
-						DBUS_TYPE_INVALID);
-			value = TRUE;
-			emit_property_changed(dev->conn, dev->path,
-						AUDIO_HEADSET_INTERFACE,
-						"Connected",
-						DBUS_TYPE_BOOLEAN, &value);
-			active_devices = g_slist_append(active_devices, dev);
-		} else if (hs->state == HEADSET_STATE_PLAYING) {
-			value = FALSE;
-			g_dbus_emit_signal(dev->conn, dev->path,
-						AUDIO_HEADSET_INTERFACE,
-						"Stopped",
-						DBUS_TYPE_INVALID);
-			emit_property_changed(dev->conn, dev->path,
-						AUDIO_HEADSET_INTERFACE,
-						"Playing",
-						DBUS_TYPE_BOOLEAN, &value);
-		}
 		break;
 	case HEADSET_STATE_PLAY_IN_PROGRESS:
 		break;
 	case HEADSET_STATE_PLAYING:
-		value = TRUE;
 		emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "State",
 					DBUS_TYPE_STRING, &state_str);
@@ -1877,18 +1221,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 		hs->sco_id = g_io_add_watch(hs->sco,
 					G_IO_ERR | G_IO_NVAL,
 					(GIOFunc) sco_cb, dev);
-
-		g_dbus_emit_signal(dev->conn, dev->path,
-					AUDIO_HEADSET_INTERFACE, "Playing",
-					DBUS_TYPE_INVALID);
-		emit_property_changed(dev->conn, dev->path,
-					AUDIO_HEADSET_INTERFACE, "Playing",
-					DBUS_TYPE_BOOLEAN, &value);
-
-		if (slc->sp_gain >= 0)
-			headset_send(hs, "\r\n+VGS=%u\r\n", slc->sp_gain);
-		if (slc->mic_gain >= 0)
-			headset_send(hs, "\r\n+VGM=%u\r\n", slc->mic_gain);
 		break;
 	}
 
@@ -1993,60 +1325,6 @@ int headset_get_sco_fd(struct audio_device *dev)
 	return g_io_channel_unix_get_fd(hs->sco);
 }
 
-gboolean headset_get_nrec(struct audio_device *dev)
-{
-	struct headset *hs = dev->headset;
-
-	if (!hs->slc)
-		return TRUE;
-
-	return hs->slc->nrec;
-}
-
-unsigned int headset_add_nrec_cb(struct audio_device *dev,
-					headset_nrec_cb cb, void *user_data)
-{
-	struct headset *hs = dev->headset;
-	struct headset_nrec_callback *nrec_cb;
-	static unsigned int id = 0;
-
-	nrec_cb = g_new(struct headset_nrec_callback, 1);
-	nrec_cb->cb = cb;
-	nrec_cb->user_data = user_data;
-	nrec_cb->id = ++id;
-
-	hs->nrec_cbs = g_slist_prepend(hs->nrec_cbs, nrec_cb);
-
-	return nrec_cb->id;
-}
-
-gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id)
-{
-	struct headset *hs = dev->headset;
-	GSList *l;
-
-	for (l = hs->nrec_cbs; l != NULL; l = l->next) {
-		struct headset_nrec_callback *cb = l->data;
-		if (cb && cb->id == id) {
-			hs->nrec_cbs = g_slist_remove(hs->nrec_cbs, cb);
-			g_free(cb);
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
-gboolean headset_get_inband(struct audio_device *dev)
-{
-	struct headset *hs = dev->headset;
-
-	if (!hs->slc)
-		return TRUE;
-
-	return hs->slc->inband_ring;
-}
-
 gboolean headset_get_sco_hci(struct audio_device *dev)
 {
 	return sco_hci;
@@ -2063,193 +1341,6 @@ void headset_shutdown(struct audio_device *dev)
 	headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
 }
 
-int telephony_event_ind(int index)
-{
-	if (!active_devices)
-		return -ENODEV;
-
-	if (!ag.er_ind) {
-		DBG("telephony_report_event called but events are disabled");
-		return -EINVAL;
-	}
-
-	send_foreach_headset(active_devices, hfp_cmp,
-				"\r\n+CIEV: %d,%d\r\n", index + 1,
-				ag.indicators[index].val);
-
-	return 0;
-}
-
-int telephony_response_and_hold_ind(int rh)
-{
-	if (!active_devices)
-		return -ENODEV;
-
-	ag.rh = rh;
-
-	/* If we aren't in any response and hold state don't send anything */
-	if (ag.rh < 0)
-		return 0;
-
-	send_foreach_headset(active_devices, hfp_cmp, "\r\n+BTRH: %d\r\n",
-				ag.rh);
-
-	return 0;
-}
-
-int telephony_incoming_call_ind(const char *number, int type)
-{
-	struct audio_device *dev;
-	struct headset *hs;
-	struct headset_slc *slc;
-
-	if (fast_connectable)
-		manager_set_fast_connectable(TRUE);
-
-	if (!active_devices)
-		return -ENODEV;
-
-	/* Get the latest connected device */
-	dev = active_devices->data;
-	hs = dev->headset;
-	slc = hs->slc;
-
-	if (ag.ring_timer) {
-		DBG("telephony_incoming_call_ind: already calling");
-		return -EBUSY;
-	}
-
-	/* With HSP 1.2 the RING messages should *not* be sent if inband
-	 * ringtone is being used */
-	if (!hs->hfp_active && slc->inband_ring)
-		return 0;
-
-	g_free(ag.number);
-	ag.number = g_strdup(number);
-	ag.number_type = type;
-
-	if (slc->inband_ring && hs->hfp_active &&
-					hs->state != HEADSET_STATE_PLAYING) {
-		slc->pending_ring = TRUE;
-		return 0;
-	}
-
-	ring_timer_cb(NULL);
-	ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,
-						NULL);
-
-	return 0;
-}
-
-int telephony_calling_stopped_ind(void)
-{
-	struct audio_device *dev;
-
-	if (fast_connectable)
-		manager_set_fast_connectable(FALSE);
-
-	if (ag.ring_timer) {
-		g_source_remove(ag.ring_timer);
-		ag.ring_timer = 0;
-	}
-
-	if (!active_devices)
-		return 0;
-
-	/* In case SCO isn't fully up yet */
-	dev = active_devices->data;
-
-	if (!dev->headset->slc->pending_ring && !ag.ring_timer)
-		return -EINVAL;
-
-	dev->headset->slc->pending_ring = FALSE;
-
-	return 0;
-}
-
-int telephony_ready_ind(uint32_t features,
-			const struct indicator *indicators, int rh,
-			const char *chld)
-{
-	ag.indicators = indicators;
-	ag.rh = rh;
-	ag.chld = chld;
-
-	DBG("Telephony plugin initialized");
-
-	print_ag_features(telephony_get_ag_features());
-
-	return 0;
-}
-
-int telephony_deinit(void)
-{
-	g_free(ag.number);
-
-	memset(&ag, 0, sizeof(ag));
-
-	ag.er_mode = 3;
-	ag.rh = BTRH_NOT_SUPPORTED;
-
-	DBG("Telephony deinitialized");
-
-	return 0;
-}
-
-int telephony_list_current_call_ind(int idx, int dir, int status, int mode,
-					int mprty, const char *number,
-					int type)
-{
-	if (!active_devices)
-		return -ENODEV;
-
-	if (number && strlen(number) > 0)
-		send_foreach_headset(active_devices, hfp_cmp,
-				"\r\n+CLCC: %d,%d,%d,%d,%d,\"%s\",%d\r\n",
-				idx, dir, status, mode, mprty, number, type);
-	else
-		send_foreach_headset(active_devices, hfp_cmp,
-					"\r\n+CLCC: %d,%d,%d,%d,%d\r\n",
-					idx, dir, status, mode, mprty);
-
-	return 0;
-}
-
-int telephony_subscriber_number_ind(const char *number, int type, int service)
-{
-	if (!active_devices)
-		return -ENODEV;
-
-	send_foreach_headset(active_devices, hfp_cmp,
-				"\r\n+CNUM: ,%s,%d,,%d\r\n",
-				number, type, service);
-
-	return 0;
-}
-
-static int cwa_cmp(struct headset *hs)
-{
-	if (!hs->hfp_active)
-		return -1;
-
-	if (hs->slc->cwa_enabled)
-		return 0;
-	else
-		return -1;
-}
-
-int telephony_call_waiting_ind(const char *number, int type)
-{
-	if (!active_devices)
-		return -ENODEV;
-
-	send_foreach_headset(active_devices, cwa_cmp,
-				"\r\n+CCWA: \"%s\",%d\r\n",
-				number, type);
-
-	return 0;
-}
-
 unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data)
 {
 	struct headset_state_callback *state_cb;
diff --git a/audio/headset.h b/audio/headset.h
index d877eef..61e63c8 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -95,11 +95,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state);
 int headset_get_channel(struct audio_device *dev);
 
 int headset_get_sco_fd(struct audio_device *dev);
-gboolean headset_get_nrec(struct audio_device *dev);
-unsigned int headset_add_nrec_cb(struct audio_device *dev,
-					headset_nrec_cb cb, void *user_data);
-gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id);
-gboolean headset_get_inband(struct audio_device *dev);
 gboolean headset_get_sco_hci(struct audio_device *dev);
 
 gboolean headset_is_active(struct audio_device *dev);
diff --git a/audio/manager.c b/audio/manager.c
index 67193da..2b125a0 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -1425,22 +1425,3 @@ gboolean manager_allow_headset_connection(struct audio_device *device)
 
 	return TRUE;
 }
-
-void manager_set_fast_connectable(gboolean enable)
-{
-	GSList *l;
-
-	if (enable && !manager_allow_headset_connection(NULL)) {
-		DBG("Refusing enabling fast connectable");
-		return;
-	}
-
-	for (l = adapters; l != NULL; l = l->next) {
-		struct audio_adapter *adapter = l->data;
-
-		if (btd_adapter_set_fast_connectable(adapter->btd_adapter,
-								enable))
-			error("Changing fast connectable for hci%d failed",
-				adapter_get_dev_id(adapter->btd_adapter));
-	}
-}
diff --git a/audio/manager.h b/audio/manager.h
index f1d3021..85e5065 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -57,7 +57,3 @@ struct audio_device *manager_get_device(const bdaddr_t *src,
 					gboolean create);
 
 gboolean manager_allow_headset_connection(struct audio_device *device);
-
-/* TRUE to enable fast connectable and FALSE to disable fast connectable for all
- * audio adapters. */
-void manager_set_fast_connectable(gboolean enable);
diff --git a/audio/telephony.h b/audio/telephony.h
index f835202..1a4ab06 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -26,13 +26,6 @@
 #include <errno.h>
 #include <glib.h>
 
-/* Response and hold values */
-#define BTRH_NOT_SUPPORTED	-2
-#define BTRH_NONE		-1
-#define BTRH_HOLD		0
-#define BTRH_ACCEPT		1
-#define BTRH_REJECT		2
-
 /* HFP feature bits */
 #define AG_FEATURE_THREE_WAY_CALLING		0x0001
 #define AG_FEATURE_EC_ANDOR_NR			0x0002
@@ -52,95 +45,6 @@
 #define HF_FEATURE_ENHANCED_CALL_STATUS		0x0020
 #define HF_FEATURE_ENHANCED_CALL_CONTROL	0x0040
 
-/* Indicator event values */
-#define EV_SERVICE_NONE			0
-#define EV_SERVICE_PRESENT		1
-
-#define EV_CALL_INACTIVE		0
-#define EV_CALL_ACTIVE			1
-
-#define EV_CALLSETUP_INACTIVE		0
-#define EV_CALLSETUP_INCOMING		1
-#define EV_CALLSETUP_OUTGOING		2
-#define EV_CALLSETUP_ALERTING		3
-
-#define EV_CALLHELD_NONE		0
-#define EV_CALLHELD_MULTIPLE		1
-#define EV_CALLHELD_ON_HOLD		2
-
-#define EV_ROAM_INACTIVE		0
-#define EV_ROAM_ACTIVE			1
-
-/* Call parameters */
-#define CALL_DIR_OUTGOING		0
-#define CALL_DIR_INCOMING		1
-
-#define CALL_STATUS_ACTIVE		0
-#define CALL_STATUS_HELD		1
-#define CALL_STATUS_DIALING		2
-#define CALL_STATUS_ALERTING		3
-#define CALL_STATUS_INCOMING		4
-#define CALL_STATUS_WAITING		5
-
-#define CALL_MODE_VOICE			0
-#define CALL_MODE_DATA			1
-#define CALL_MODE_FAX			2
-
-#define CALL_MULTIPARTY_NO		0
-#define CALL_MULTIPARTY_YES		1
-
-/* Subscriber number parameters */
-#define SUBSCRIBER_SERVICE_VOICE	4
-#define SUBSCRIBER_SERVICE_FAX		5
-
-/* Operator selection mode values */
-#define OPERATOR_MODE_AUTO		0
-#define OPERATOR_MODE_MANUAL		1
-#define OPERATOR_MODE_DEREGISTER	2
-#define OPERATOR_MODE_MANUAL_AUTO	4
-
-/* Some common number types */
-#define NUMBER_TYPE_UNKNOWN		128
-#define NUMBER_TYPE_TELEPHONY		129
-#define NUMBER_TYPE_INTERNATIONAL	145
-#define NUMBER_TYPE_NATIONAL		161
-#define NUMBER_TYPE_VOIP		255
-
-/* Extended Audio Gateway Error Result Codes */
-typedef enum {
-	CME_ERROR_NONE			= -1,
-	CME_ERROR_AG_FAILURE		= 0,
-	CME_ERROR_NO_PHONE_CONNECTION	= 1,
-	CME_ERROR_NOT_ALLOWED		= 3,
-	CME_ERROR_NOT_SUPPORTED		= 4,
-	CME_ERROR_PH_SIM_PIN_REQUIRED	= 5,
-	CME_ERROR_SIM_NOT_INSERTED	= 10,
-	CME_ERROR_SIM_PIN_REQUIRED	= 11,
-	CME_ERROR_SIM_PUK_REQUIRED	= 12,
-	CME_ERROR_SIM_FAILURE		= 13,
-	CME_ERROR_SIM_BUSY		= 14,
-	CME_ERROR_INCORRECT_PASSWORD	= 16,
-	CME_ERROR_SIM_PIN2_REQUIRED	= 17,
-	CME_ERROR_SIM_PUK2_REQUIRED	= 18,
-	CME_ERROR_MEMORY_FULL		= 20,
-	CME_ERROR_INVALID_INDEX		= 21,
-	CME_ERROR_MEMORY_FAILURE	= 23,
-	CME_ERROR_TEXT_STRING_TOO_LONG	= 24,
-	CME_ERROR_INVALID_TEXT_STRING	= 25,
-	CME_ERROR_DIAL_STRING_TOO_LONG	= 26,
-	CME_ERROR_INVALID_DIAL_STRING	= 27,
-	CME_ERROR_NO_NETWORK_SERVICE	= 30,
-	CME_ERROR_NETWORK_TIMEOUT	= 31,
-	CME_ERROR_NETWORK_NOT_ALLOWED	= 32,
-} cme_error_t;
-
-struct indicator {
-	const char *desc;
-	const char *range;
-	int val;
-	gboolean ignore_redundant;
-};
-
 struct telephony_device;
 
 struct telephony_device *telephony_device_connecting(GIOChannel *io,
@@ -154,81 +58,6 @@ uint32_t telephony_get_ag_features(void);
 gboolean telephony_is_uuid_supported(struct btd_adapter *adapter,
 						const char *uuid);
 
-/* AG responses to HF requests. These are implemented by headset.c */
-int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err);
-int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err);
-int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_terminate_call_rsp(void *telephony_device, cme_error_t err);
-int telephony_answer_call_rsp(void *telephony_device, cme_error_t err);
-int telephony_dial_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err);
-int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err);
-int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err);
-int telephony_call_hold_rsp(void *telephony_device, cme_error_t err);
-int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err);
-int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err);
-int telephony_key_press_rsp(void *telephony_device, cme_error_t err);
-
-/* Event indications by AG. These are implemented by headset.c */
-int telephony_event_ind(int index);
-int telephony_response_and_hold_ind(int rh);
-int telephony_incoming_call_ind(const char *number, int type);
-int telephony_calling_stopped_ind(void);
-int telephony_ready_ind(uint32_t features, const struct indicator *indicators,
-			int rh, const char *chld);
-int telephony_deinit(void);
-int telephony_list_current_call_ind(int idx, int dir, int status, int mode,
-					int mprty, const char *number,
-					int type);
-int telephony_subscriber_number_ind(const char *number, int type,
-					int service);
-int telephony_call_waiting_ind(const char *number, int type);
-int telephony_operator_selection_ind(int mode, const char *oper);
-
-/* Helper function for quick indicator updates */
-static inline int telephony_update_indicator(struct indicator *indicators,
-						const char *desc,
-						int new_val)
-{
-	int i;
-	struct indicator *ind = NULL;
-
-	for (i = 0; indicators[i].desc != NULL; i++) {
-		if (g_str_equal(indicators[i].desc, desc)) {
-			ind = &indicators[i];
-			break;
-		}
-	}
-
-	if (!ind)
-		return -ENOENT;
-
-	DBG("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val);
-
-	if (ind->ignore_redundant && ind->val == new_val) {
-		DBG("Ignoring no-change indication");
-		return 0;
-	}
-
-	ind->val = new_val;
-
-	return telephony_event_ind(i);
-}
-
-static inline int telephony_get_indicator(const struct indicator *indicators,
-						const char *desc)
-{
-	int i;
-
-	for (i = 0; indicators[i].desc != NULL; i++) {
-		if (g_str_equal(indicators[i].desc, desc))
-			return indicators[i].val;
-	}
-
-	return -ENOENT;
-}
-
 int telephony_adapter_init(struct btd_adapter *adapter);
 void telephony_adapter_exit(struct btd_adapter *adapter);
 int telephony_init(void);
diff --git a/audio/transport.c b/audio/transport.c
index 832ad2a..6d4ad55 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -70,7 +70,10 @@ struct a2dp_transport {
 
 struct headset_transport {
 	struct audio_device	*device;
-	unsigned int		nrec_id;
+	gboolean		nrec;
+	gboolean		inband;
+	uint16_t		output_gain;
+	uint16_t		input_gain;
 };
 
 struct media_transport {
@@ -788,26 +791,62 @@ static int set_property_headset(struct media_transport *transport,
 						const char *property,
 						DBusMessageIter *value)
 {
-	if (g_strcmp0(property, "NREC") == 0) {
-		gboolean nrec;
+	struct headset_transport *headset = transport->data;
 
+	if (g_strcmp0(property, "NREC") == 0) {
 		if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
 			return -EINVAL;
-		dbus_message_iter_get_basic(value, &nrec);
+		dbus_message_iter_get_basic(value, &headset->nrec);
 
-		/* FIXME: set new nrec */
+		emit_property_changed(transport->conn, transport->path,
+					MEDIA_TRANSPORT_INTERFACE, "NREC",
+					DBUS_TYPE_BOOLEAN, &headset->nrec);
 		return 0;
 	} else if (g_strcmp0(property, "InbandRingtone") == 0) {
-		gboolean inband;
-
 		if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
 			return -EINVAL;
-		dbus_message_iter_get_basic(value, &inband);
+		dbus_message_iter_get_basic(value, &headset->inband);
+
+		emit_property_changed(transport->conn, transport->path,
+					MEDIA_TRANSPORT_INTERFACE,
+					"InbandRingtone",
+					DBUS_TYPE_BOOLEAN, &headset->inband);
+		return 0;
+	} else if (g_strcmp0(property, "OutputGain") == 0) {
+		uint16_t gain;
+
+		if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+			return -EINVAL;
+		dbus_message_iter_get_basic(value, &gain);
+
+		if (gain > 15)
+			goto failed;
+
+		headset->output_gain = gain;
+		emit_property_changed(transport->conn, transport->path,
+					MEDIA_TRANSPORT_INTERFACE,
+					"OutputGain", DBUS_TYPE_UINT16,
+					&headset->output_gain);
+		return 0;
+	} else if (g_strcmp0(property, "InputGain") == 0) {
+		uint16_t gain;
+
+		if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+			return -EINVAL;
+		dbus_message_iter_get_basic(value, &gain);
+
+		if (gain > 15)
+			goto failed;
 
-		/* FIXME: set new inband */
+		headset->input_gain = gain;
+		emit_property_changed(transport->conn, transport->path,
+					MEDIA_TRANSPORT_INTERFACE,
+					"InputGain", DBUS_TYPE_UINT16,
+					&headset->input_gain);
 		return 0;
 	}
 
+failed:
 	return -EINVAL;
 }
 
@@ -879,14 +918,16 @@ static void get_properties_a2dp(struct media_transport *transport,
 static void get_properties_headset(struct media_transport *transport,
 						DBusMessageIter *dict)
 {
-	gboolean nrec, inband;
+	struct headset_transport *headset = transport->data;
 	const char *routing;
 
-	nrec = headset_get_nrec(transport->device);
-	dict_append_entry(dict, "NREC", DBUS_TYPE_BOOLEAN, &nrec);
-
-	inband = headset_get_inband(transport->device);
-	dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN, &inband);
+	dict_append_entry(dict, "NREC", DBUS_TYPE_BOOLEAN, &headset->nrec);
+	dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN,
+						&headset->inband);
+	dict_append_entry(dict, "OutputGain", DBUS_TYPE_UINT16,
+						&headset->output_gain);
+	dict_append_entry(dict, "InputGain", DBUS_TYPE_UINT16,
+						&headset->input_gain);
 
 	routing = headset_get_sco_hci(transport->device) ? "HCI" : "PCM";
 	dict_append_entry(dict, "Routing", DBUS_TYPE_STRING, &routing);
@@ -985,9 +1026,6 @@ static void destroy_headset(void *data)
 {
 	struct headset_transport *headset = data;
 
-	if (headset->nrec_id > 0)
-		headset_remove_nrec_cb(headset->device, headset->nrec_id);
-
 	g_free(headset);
 }
 
@@ -1015,18 +1053,6 @@ static void media_transport_free(void *data)
 	g_free(transport);
 }
 
-static void headset_nrec_changed(struct audio_device *dev, gboolean nrec,
-							void *user_data)
-{
-	struct media_transport *transport = user_data;
-
-	DBG("");
-
-	emit_property_changed(transport->conn, transport->path,
-				MEDIA_TRANSPORT_INTERFACE, "NREC",
-				DBUS_TYPE_BOOLEAN, &nrec);
-}
-
 struct media_transport *media_transport_create(DBusConnection *conn,
 						struct media_endpoint *endpoint,
 						struct audio_device *device,
@@ -1068,9 +1094,7 @@ struct media_transport *media_transport_create(DBusConnection *conn,
 
 		headset = g_new0(struct headset_transport, 1);
 		headset->device = device;
-		headset->nrec_id = headset_add_nrec_cb(device,
-							headset_nrec_changed,
-							transport);
+		headset->nrec = TRUE;
 
 		transport->resume = resume_headset;
 		transport->suspend = suspend_headset;
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index c620a7d..e8bb210 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -66,20 +66,6 @@ Methods		void Connect()
 			Disconnect from the HSP/HFP service on the remote
 			device.
 
-		void IndicateCall()
-
-			Indicate an incoming call on the headset
-			connected to the stream. Will continue to
-			ring the headset about every 3 seconds.
-
-		void CancelCall()
-
-			Cancel the incoming call indication.
-
-		void Play() {deprecated}
-
-			Open the audio connection to the headset.
-
 		void Stop()
 
 			Close the audio connection.
@@ -91,44 +77,7 @@ Methods		void Connect()
 
 			Possible Errors: org.bluez.Error.InvalidArguments
 
-		void SetProperty(string name, variant value)
-
-			Changes the value of the specified property. Only
-			properties that are listed as read-write are changeable.
-			On success this will emit a PropertyChanged signal.
-
-			Possible Errors: org.bluez.Error.DoesNotExist
-					 org.bluez.Error.InvalidArguments
-
-Signals		void AnswerRequested()
-
-			Sent when the answer button is pressed on the headset
-
-		void Connected() {deprecated}
-
-			Sent when the device has been connected to.
-
-		void Disconnected() {deprecated}
-
-			Sent when the device has been disconnected from.
-
-		void Stopped() {deprecated}
-
-			Sent when the audio connection is closed
-
-		void Playing() {deprecated}
-
-			Sent when the audio connection is opened
-
-		void SpeakerGainChanged(uint16 gain) {deprecated}
-
-			The speaker gain changed.
-
-		void MicrophoneGainChanged(uint16 gain) {deprecated}
-
-			The microphone gain changed.
-
-		PropertyChanged(string name, variant value)
+Signals		PropertyChanged(string name, variant value)
 
 			This signal indicates a changed value of the given
 			property.
@@ -158,24 +107,6 @@ properties	string State [readonly]
 			"playing" -> "disconnected"
 				Disconnected from the remote device
 
-		boolean Connected [readonly]
-
-			Indicates if there is a active connection to the
-			HSP/HFP connection on the remote device.
-
-		boolean Playing  [readonly]
-
-			Indicates if an audio connection to the headset
-			is active.
-
-		uint16 SpeakerGain  [readwrite]
-
-			The speaker gain when available.
-
-		uint16 MicrophoneGain  [readwrite]
-
-			The speaker gain when available.
-
 
 AudioSink hierarchy
 ===================
@@ -329,100 +260,40 @@ Methods		void Connect()
 
 			Disconnect from the AG service on the remote device
 
-		void AnswerCall()
-
-			It has to called only after Ring signal received.
-
-		void TerminateCall()
-
-			Terminate call which is running or reject an incoming
-			call. This has nothing with any 3-way situation incl.
-			RaH. Just plain old PDH.
-
-		void Call(string number)
-
-			Dial a number 'number'. No number processing is done
-			thus if AG would reject to dial it don't blame me :)
-
-		string GetOperatorName()
-
-			Find out the name of the currently selected network
-			operator by AG.
-
-		void SendDTMF(string digits)
-
-			Will send each digit in the 'digits' sequentially. Would
-			send nothing if there is non-dtmf digit.
-
-		string GetSubscriberNumber()
-
-			Get the voicecall subscriber number of AG
-
 		dict GetProperties()
 
 			Returns all properties for the interface. See the
 			properties section for available properties.
 
-Signals		void Ring(string number)
-
-			Someone's calling from 'number'.
-			Caller number is provided as received from AG.
-
-		void CallTerminated()
-
-			Call failed to set up. It means that we tried to call
-			someone or someone tried to call us but call was not
-			accepted.
-
-		void CallStarted()
-
-			Call set up successfully.
-
-		void CallEnded()
-
-			Call was started and now ended. In contrast with
-			CallTerminated where call didn't started
-
-		PropertyChanged(string name, variant value)
+Signals		PropertyChanged(string name, variant value)
 
 			This signal indicates a changed value of the given
 			property.
 
-properties	boolean Connected [readonly]
-
-			Indicates if there is an active connection to the
-			AG service on the remote device.
-
-		uint16 RegistrationStatus [readonly]
-
-			Service availability indicator of AG, where:
-			0 implies no service. No Home/Roam network available.
-			1 implies presence of service. Home/Roam network
-			available.
-
-		uint16 SignalStrength [readonly]
-
-			Signal strength indicator of AG, the value ranges from
-			0 to 5.
-
-		uint16 RoamingStatus [readonly]
+properties	string State [readonly]
 
-			Roaming status indicator of AG, where:
-			0 means roaming is not active
-			1 means a roaming is active
+			Possible values: "disconnected", "connecting",
+			"connected", "playing"
 
-		uint16 BatteryCharge [readonly]
+			"disconnected" -> "connecting"
+				Either an incoming or outgoing connection
+				attempt ongoing.
 
-			Battery Charge indicator of AG, the value ranges from
-			0 to 5.
+			"connecting" -> "disconnected"
+				Connection attempt failed
 
-		uint16 SpeakerGain  [readonly]
+			"connecting" -> "connected"
+				Successfully connected
 
-			The speaker gain when available.
+			"connected" -> "playing"
+				SCO audio connection successfully opened
 
-		uint16 MicrophoneGain  [readonly]
+			"playing" -> "connected"
+				SCO audio connection closed
 
-			The speaker gain when available.
+			"connected" -> "disconnected"
+			"playing" -> "disconnected"
+				Disconnected from the remote device
 
 
 Telephony hierarchy
diff --git a/doc/media-api.txt b/doc/media-api.txt
index e5eeaa0..4a3afd2 100644
--- a/doc/media-api.txt
+++ b/doc/media-api.txt
@@ -326,15 +326,12 @@ Properties	object Device [readonly]
 		boolean NREC [readwrite]
 
 			Optional. Indicates if echo cancelling and noise
-			reduction functions are active in the transport, this
-			property is only writeable when the transport was
-			acquired by the sender.
+			reduction functions are active in the transport.
 
 		boolean InbandRingtone [readwrite]
 
 			Optional. Indicates if the transport support sending
-			ringtones, this property is only writeable when the
-			transport was acquired by the sender.
+			ringtones.
 
 		string Routing [readonly]
 
@@ -349,3 +346,15 @@ Properties	object Device [readonly]
 			acquired by the sender.
 
 			Possible Values: 0-127
+
+		uint16 OutputGain  [readwrite]
+
+			Optional. The speaker gain when available.
+
+			Possible values: 0-15
+
+		uint16 InputGain  [readwrite]
+
+			Optional. The microphone gain when available.
+
+			Possible values: 0-15
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 05/15] audio: Remove dummy telephony driver
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (3 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 04/15] audio: Simplify org.bluez.Headset Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 06/15] audio: Remove maemo5 " Frédéric Danis
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Remove dummy telephony driver which has been deprecated by
org.bluez.Telephony interface.
---
 audio/telephony-dummy.c |  447 -----------------------------------------------
 1 file changed, 447 deletions(-)
 delete mode 100644 audio/telephony-dummy.c

diff --git a/audio/telephony-dummy.c b/audio/telephony-dummy.c
deleted file mode 100644
index 2f89139..0000000
--- a/audio/telephony-dummy.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-#define TELEPHONY_DUMMY_IFACE "org.bluez.TelephonyTest"
-#define TELEPHONY_DUMMY_PATH "/org/bluez/test"
-
-static DBusConnection *connection = NULL;
-
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-static char *subscriber_number = NULL;
-static char *active_call_number = NULL;
-static int active_call_status = 0;
-static int active_call_dir = 0;
-
-static gboolean events_enabled = FALSE;
-
-static struct indicator dummy_indicators[] =
-{
-	{ "battchg",	"0-5",	5,	TRUE },
-	{ "signal",	"0-5",	5,	TRUE },
-	{ "service",	"0,1",	1,	TRUE },
-	{ "call",	"0,1",	0,	TRUE },
-	{ "callsetup",	"0-3",	0,	TRUE },
-	{ "callheld",	"0-2",	0,	FALSE },
-	{ "roam",	"0,1",	0,	TRUE },
-	{ NULL }
-};
-
-void telephony_device_connected(void *telephony_device)
-{
-	DBG("telephony-dummy: device %p connected", telephony_device);
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
-	DBG("telephony-dummy: device %p disconnected", telephony_device);
-	events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
-	events_enabled = ind == 1 ? TRUE : FALSE;
-
-	telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
-	telephony_response_and_hold_rsp(telephony_device,
-						CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
-	telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NONE);
-
-	/* Notify outgoing call set-up successfully initiated */
-	telephony_update_indicator(dummy_indicators, "callsetup",
-					EV_CALLSETUP_OUTGOING);
-	telephony_update_indicator(dummy_indicators, "callsetup",
-					EV_CALLSETUP_ALERTING);
-
-	active_call_status = CALL_STATUS_ALERTING;
-	active_call_dir = CALL_DIR_OUTGOING;
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
-	g_free(active_call_number);
-	active_call_number = NULL;
-
-	telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-
-	if (telephony_get_indicator(dummy_indicators, "callsetup") > 0)
-		telephony_update_indicator(dummy_indicators, "callsetup",
-						EV_CALLSETUP_INACTIVE);
-	else
-		telephony_update_indicator(dummy_indicators, "call",
-						EV_CALL_INACTIVE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
-	telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-
-	telephony_update_indicator(dummy_indicators, "call", EV_CALL_ACTIVE);
-	telephony_update_indicator(dummy_indicators, "callsetup",
-					EV_CALLSETUP_INACTIVE);
-
-	active_call_status = CALL_STATUS_ACTIVE;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
-	g_free(active_call_number);
-	active_call_number = g_strdup(number);
-
-	DBG("telephony-dummy: dial request to %s", active_call_number);
-
-	telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-
-	/* Notify outgoing call set-up successfully initiated */
-	telephony_update_indicator(dummy_indicators, "callsetup",
-					EV_CALLSETUP_OUTGOING);
-	telephony_update_indicator(dummy_indicators, "callsetup",
-					EV_CALLSETUP_ALERTING);
-
-	active_call_status = CALL_STATUS_ALERTING;
-	active_call_dir = CALL_DIR_OUTGOING;
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
-	DBG("telephony-dummy: transmit dtmf: %c", tone);
-	telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
-	DBG("telephony-dummy: subscriber number request");
-	if (subscriber_number)
-		telephony_subscriber_number_ind(subscriber_number,
-						NUMBER_TYPE_TELEPHONY,
-						SUBSCRIBER_SERVICE_VOICE);
-	telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
-	DBG("telephony-dummy: list current calls request");
-	if (active_call_number)
-		telephony_list_current_call_ind(1, active_call_dir,
-						active_call_status,
-						CALL_MODE_VOICE,
-						CALL_MULTIPARTY_NO,
-						active_call_number,
-						NUMBER_TYPE_TELEPHONY);
-	telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
-	telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "DummyOperator");
-	telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
-	DBG("telephony-dymmy: got call hold request %s", cmd);
-	telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
-	DBG("telephony-dummy: got %s NR and EC request",
-			enable ? "enable" : "disable");
-
-	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
-	DBG("telephony-dummy: got %s voice dial request",
-			enable ? "enable" : "disable");
-
-	g_dbus_emit_signal(connection, TELEPHONY_DUMMY_PATH,
-			TELEPHONY_DUMMY_IFACE, "VoiceDial",
-			DBUS_TYPE_INVALID);
-
-	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
-	DBG("telephony-dummy: got key press request for %s", keys);
-	telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-/* D-Bus method handlers */
-static DBusMessage *outgoing_call(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	const char *number;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
-						DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	DBG("telephony-dummy: outgoing call to %s", number);
-
-	g_free(active_call_number);
-	active_call_number = g_strdup(number);
-
-	telephony_update_indicator(dummy_indicators, "callsetup",
-					EV_CALLSETUP_OUTGOING);
-	telephony_update_indicator(dummy_indicators, "callsetup",
-					EV_CALLSETUP_ALERTING);
-
-	active_call_status = CALL_STATUS_ALERTING;
-	active_call_dir = CALL_DIR_OUTGOING;
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *incoming_call(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	const char *number;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
-						DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	DBG("telephony-dummy: incoming call to %s", number);
-
-	g_free(active_call_number);
-	active_call_number = g_strdup(number);
-
-	telephony_update_indicator(dummy_indicators, "callsetup",
-					EV_CALLSETUP_INCOMING);
-
-	active_call_status = CALL_STATUS_INCOMING;
-	active_call_dir = CALL_DIR_INCOMING;
-
-	telephony_incoming_call_ind(number, NUMBER_TYPE_TELEPHONY);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	DBG("telephony-dummy: cancel call");
-
-	g_free(active_call_number);
-	active_call_number = NULL;
-
-	if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) {
-		telephony_update_indicator(dummy_indicators, "callsetup",
-						EV_CALLSETUP_INACTIVE);
-		telephony_calling_stopped_ind();
-	}
-
-	if (telephony_get_indicator(dummy_indicators, "call") > 0)
-		telephony_update_indicator(dummy_indicators, "call",
-						EV_CALL_INACTIVE);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *signal_strength(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	dbus_uint32_t strength;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &strength,
-						DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	if (strength > 5)
-		return btd_error_invalid_args(msg);
-
-	telephony_update_indicator(dummy_indicators, "signal", strength);
-
-	DBG("telephony-dummy: signal strength set to %u", strength);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *battery_level(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	dbus_uint32_t level;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &level,
-						DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	if (level > 5)
-		return btd_error_invalid_args(msg);
-
-	telephony_update_indicator(dummy_indicators, "battchg", level);
-
-	DBG("telephony-dummy: battery level set to %u", level);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *roaming_status(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	dbus_bool_t roaming;
-	int val;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &roaming,
-						DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	val = roaming ? EV_ROAM_ACTIVE : EV_ROAM_INACTIVE;
-
-	telephony_update_indicator(dummy_indicators, "roam", val);
-
-	DBG("telephony-dummy: roaming status set to %d", val);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *registration_status(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	dbus_bool_t registration;
-	int val;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &registration,
-						DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	val = registration ? EV_SERVICE_PRESENT : EV_SERVICE_NONE;
-
-	telephony_update_indicator(dummy_indicators, "service", val);
-
-	DBG("telephony-dummy: registration status set to %d", val);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_subscriber_number(DBusConnection *conn,
-						DBusMessage *msg,
-						void *data)
-{
-	const char *number;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
-						DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	g_free(subscriber_number);
-	subscriber_number = g_strdup(number);
-
-	DBG("telephony-dummy: subscriber number set to %s", number);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static const GDBusMethodTable dummy_methods[] = {
-	{ GDBUS_METHOD("OutgoingCall",
-			GDBUS_ARGS({ "number", "s" }), NULL,
-			outgoing_call) },
-	{ GDBUS_METHOD("IncomingCall",
-			GDBUS_ARGS({ "number", "s" }), NULL,
-			incoming_call) },
-	{ GDBUS_METHOD("CancelCall", NULL, NULL, cancel_call) },
-	{ GDBUS_METHOD("SignalStrength",
-			GDBUS_ARGS({ "strength", "u" }), NULL,
-			signal_strength) },
-	{ GDBUS_METHOD("BatteryLevel",
-			GDBUS_ARGS({ "level", "u" }), NULL,
-			battery_level) },
-	{ GDBUS_METHOD("RoamingStatus",
-			GDBUS_ARGS({ "roaming", "b" }), NULL,
-			roaming_status) },
-	{ GDBUS_METHOD("RegistrationStatus",
-			GDBUS_ARGS({ "registration", "b" }), NULL,
-			registration_status) },
-	{ GDBUS_METHOD("SetSubscriberNumber",
-			GDBUS_ARGS({ "number", "s" }), NULL,
-			set_subscriber_number) },
-	{ }
-};
-
-static const GDBusSignalTable dummy_signals[] = {
-	{ GDBUS_SIGNAL("VoiceDial", NULL) },
-	{ }
-};
-
-int telephony_init(void)
-{
-	uint32_t features = AG_FEATURE_REJECT_A_CALL |
-				AG_FEATURE_ENHANCED_CALL_STATUS |
-				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
-
-	DBG("");
-
-	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
-	if (g_dbus_register_interface(connection, TELEPHONY_DUMMY_PATH,
-					TELEPHONY_DUMMY_IFACE,
-					dummy_methods, dummy_signals,
-					NULL, NULL, NULL) == FALSE) {
-		error("telephony-dummy interface %s init failed on path %s",
-			TELEPHONY_DUMMY_IFACE, TELEPHONY_DUMMY_PATH);
-		return -1;
-	}
-
-	telephony_ready_ind(features, dummy_indicators, BTRH_NOT_SUPPORTED,
-								chld_str);
-
-	return 0;
-}
-
-void telephony_exit(void)
-{
-	DBG("");
-
-	g_dbus_unregister_interface(connection, TELEPHONY_DUMMY_PATH,
-						TELEPHONY_DUMMY_IFACE);
-	dbus_connection_unref(connection);
-	connection = NULL;
-
-	telephony_deinit();
-}
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 06/15] audio: Remove maemo5 telephony driver
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (4 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 05/15] audio: Remove dummy telephony driver Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 07/15] audio: Remove maemo6 " Frédéric Danis
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Remove Maemo 5 telephony driver which has been deprecated by
org.bluez.Telephony interface.
---
 audio/telephony-maemo5.c | 2105 ----------------------------------------------
 1 file changed, 2105 deletions(-)
 delete mode 100644 audio/telephony-maemo5.c

diff --git a/audio/telephony-maemo5.c b/audio/telephony-maemo5.c
deleted file mode 100644
index 8a00296..0000000
--- a/audio/telephony-maemo5.c
+++ /dev/null
@@ -1,2105 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-/* SSC D-Bus definitions */
-#define SSC_DBUS_NAME  "com.nokia.phone.SSC"
-#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
-#define SSC_DBUS_PATH  "/com/nokia/phone/SSC"
-
-/* libcsnet D-Bus definitions */
-#define NETWORK_BUS_NAME		"com.nokia.phone.net"
-#define NETWORK_INTERFACE		"Phone.Net"
-#define NETWORK_PATH			"/com/nokia/phone/net"
-
-/* Mask bits for supported services */
-#define NETWORK_MASK_GPRS_SUPPORT	0x01
-#define NETWORK_MASK_CS_SERVICES	0x02
-#define NETWORK_MASK_EGPRS_SUPPORT	0x04
-#define NETWORK_MASK_HSDPA_AVAIL	0x08
-#define NETWORK_MASK_HSUPA_AVAIL	0x10
-
-/* network get cell info: cell type */
-#define NETWORK_UNKNOWN_CELL		0
-#define NETWORK_GSM_CELL		1
-#define NETWORK_WCDMA_CELL		2
-
-enum net_registration_status {
-	NETWORK_REG_STATUS_HOME = 0x00,
-	NETWORK_REG_STATUS_ROAM,
-	NETWORK_REG_STATUS_ROAM_BLINK,
-	NETWORK_REG_STATUS_NOSERV,
-	NETWORK_REG_STATUS_NOSERV_SEARCHING,
-	NETWORK_REG_STATUS_NOSERV_NOTSEARCHING,
-	NETWORK_REG_STATUS_NOSERV_NOSIM,
-	NETWORK_REG_STATUS_POWER_OFF = 0x08,
-	NETWORK_REG_STATUS_NSPS,
-	NETWORK_REG_STATUS_NSPS_NO_COVERAGE,
-	NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW
-};
-
-enum network_types {
-	NETWORK_GSM_HOME_PLMN = 0,
-	NETWORK_GSM_PREFERRED_PLMN,
-	NETWORK_GSM_FORBIDDEN_PLMN,
-	NETWORK_GSM_OTHER_PLMN,
-	NETWORK_GSM_NO_PLMN_AVAIL
-};
-
-enum network_alpha_tag_name_type {
-	NETWORK_HARDCODED_LATIN_OPER_NAME = 0,
-	NETWORK_HARDCODED_USC2_OPER_NAME,
-	NETWORK_NITZ_SHORT_OPER_NAME,
-	NETWORK_NITZ_FULL_OPER_NAME,
-};
-
-#define TELEPHONY_MAEMO_PATH		"/com/nokia/MaemoTelephony"
-#define TELEPHONY_MAEMO_INTERFACE	"com.nokia.MaemoTelephony"
-
-#define CALLERID_BASE		"/var/lib/bluetooth/maemo-callerid-"
-#define ALLOWED_FLAG_FILE	"/var/lib/bluetooth/maemo-callerid-allowed"
-#define RESTRICTED_FLAG_FILE	"/var/lib/bluetooth/maemo-callerid-restricted"
-#define NONE_FLAG_FILE		"/var/lib/bluetooth/maemo-callerid-none"
-
-static uint32_t callerid = 0;
-
-/* CSD CALL plugin D-Bus definitions */
-#define CSD_CALL_BUS_NAME	"com.nokia.csd.Call"
-#define CSD_CALL_INTERFACE	"com.nokia.csd.Call"
-#define CSD_CALL_INSTANCE	"com.nokia.csd.Call.Instance"
-#define CSD_CALL_CONFERENCE	"com.nokia.csd.Call.Conference"
-#define CSD_CALL_PATH		"/com/nokia/csd/call"
-#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
-
-/* Call status values as exported by the CSD CALL plugin */
-#define CSD_CALL_STATUS_IDLE			0
-#define CSD_CALL_STATUS_CREATE			1
-#define CSD_CALL_STATUS_COMING			2
-#define CSD_CALL_STATUS_PROCEEDING		3
-#define CSD_CALL_STATUS_MO_ALERTING		4
-#define CSD_CALL_STATUS_MT_ALERTING		5
-#define CSD_CALL_STATUS_WAITING			6
-#define CSD_CALL_STATUS_ANSWERED		7
-#define CSD_CALL_STATUS_ACTIVE			8
-#define CSD_CALL_STATUS_MO_RELEASE		9
-#define CSD_CALL_STATUS_MT_RELEASE		10
-#define CSD_CALL_STATUS_HOLD_INITIATED		11
-#define CSD_CALL_STATUS_HOLD			12
-#define CSD_CALL_STATUS_RETRIEVE_INITIATED	13
-#define CSD_CALL_STATUS_RECONNECT_PENDING	14
-#define CSD_CALL_STATUS_TERMINATED		15
-#define CSD_CALL_STATUS_SWAP_INITIATED		16
-
-#define CALL_FLAG_NONE				0
-#define CALL_FLAG_PRESENTATION_ALLOWED		0x01
-#define CALL_FLAG_PRESENTATION_RESTRICTED	0x02
-
-/* SIM Phonebook D-Bus definitions */
-#define SIM_PHONEBOOK_BUS_NAME			"com.nokia.phone.SIM"
-#define SIM_PHONEBOOK_INTERFACE			"Phone.Sim.Phonebook"
-#define SIM_PHONEBOOK_PATH			"/com/nokia/phone/SIM/phonebook"
-
-#define PHONEBOOK_INDEX_FIRST_ENTRY		0xFFFF
-#define PHONEBOOK_INDEX_NEXT_FREE_LOCATION	0xFFFE
-
-enum sim_phonebook_type {
-	SIM_PHONEBOOK_TYPE_ADN = 0x0,
-	SIM_PHONEBOOK_TYPE_SDN,
-	SIM_PHONEBOOK_TYPE_FDN,
-	SIM_PHONEBOOK_TYPE_VMBX,
-	SIM_PHONEBOOK_TYPE_MBDN,
-	SIM_PHONEBOOK_TYPE_EN,
-	SIM_PHONEBOOK_TYPE_MSISDN
-};
-
-enum sim_phonebook_location_type {
-	SIM_PHONEBOOK_LOCATION_EXACT = 0x0,
-	SIM_PHONEBOOK_LOCATION_NEXT
-};
-
-struct csd_call {
-	char *object_path;
-	int status;
-	gboolean originating;
-	gboolean emergency;
-	gboolean on_hold;
-	gboolean conference;
-	char *number;
-	gboolean setup;
-};
-
-static struct {
-	uint8_t status;
-	uint16_t lac;
-	uint32_t cell_id;
-	uint32_t operator_code;
-	uint32_t country_code;
-	uint8_t network_type;
-	uint8_t supported_services;
-	uint16_t signals_bar;
-	char *operator_name;
-} net = {
-	.status = NETWORK_REG_STATUS_NOSERV,
-	.lac = 0,
-	.cell_id = 0,
-	.operator_code = 0,
-	.country_code = 0,
-	.network_type = NETWORK_GSM_NO_PLMN_AVAIL,
-	.supported_services = 0,
-	.signals_bar = 0,
-	.operator_name = NULL,
-};
-
-static DBusConnection *connection = NULL;
-
-static GSList *calls = NULL;
-
-/* Reference count for determining the call indicator status */
-static GSList *active_calls = NULL;
-
-static char *msisdn = NULL;	/* Subscriber number */
-static char *vmbx = NULL;	/* Voice mailbox number */
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1;	/* "battery.charge_level.current" */
-static int battchg_last = -1;	/* "battery.charge_level.last_full" */
-static int battchg_design = -1;	/* "battery.charge_level.design" */
-
-static gboolean get_calls_active = FALSE;
-
-static gboolean events_enabled = FALSE;
-
-/* Supported set of call hold operations */
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-
-static char *last_dialed_number = NULL;
-
-/* Timer for tracking call creation requests */
-static guint create_request_timer = 0;
-
-static struct indicator maemo_indicators[] =
-{
-	{ "battchg",	"0-5",	5,	TRUE },
-	{ "signal",	"0-5",	0,	TRUE },
-	{ "service",	"0,1",	0,	TRUE },
-	{ "call",	"0,1",	0,	TRUE },
-	{ "callsetup",	"0-3",	0,	TRUE },
-	{ "callheld",	"0-2",	0,	FALSE },
-	{ "roam",	"0,1",	0,	TRUE },
-	{ NULL }
-};
-
-static char *call_status_str[] = {
-	"IDLE",
-	"CREATE",
-	"COMING",
-	"PROCEEDING",
-	"MO_ALERTING",
-	"MT_ALERTING",
-	"WAITING",
-	"ANSWERED",
-	"ACTIVE",
-	"MO_RELEASE",
-	"MT_RELEASE",
-	"HOLD_INITIATED",
-	"HOLD",
-	"RETRIEVE_INITIATED",
-	"RECONNECT_PENDING",
-	"TERMINATED",
-	"SWAP_INITIATED",
-	"???"
-};
-
-static struct csd_call *find_call(const char *path)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (g_str_equal(call->object_path, path))
-			return call;
-	}
-
-	return NULL;
-}
-
-static struct csd_call *find_non_held_call(void)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (call->status == CSD_CALL_STATUS_IDLE)
-			continue;
-
-		if (call->status != CSD_CALL_STATUS_HOLD)
-			return call;
-	}
-
-	return NULL;
-}
-
-static struct csd_call *find_non_idle_call(void)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (call->status != CSD_CALL_STATUS_IDLE)
-			return call;
-	}
-
-	return NULL;
-}
-
-static struct csd_call *find_call_with_status(int status)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (call->status == status)
-			return call;
-	}
-
-	return NULL;
-}
-
-static int release_conference(void)
-{
-	DBusMessage *msg;
-
-	DBG("telephony-maemo: releasing conference call");
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-						CSD_CALL_CONFERENCE_PATH,
-						CSD_CALL_INSTANCE,
-						"Release");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int release_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-						call->object_path,
-						CSD_CALL_INSTANCE,
-						"Release");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int answer_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-						call->object_path,
-						CSD_CALL_INSTANCE,
-						"Answer");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int split_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-						call->object_path,
-						CSD_CALL_INSTANCE,
-						"Split");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int unhold_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Unhold");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int hold_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Hold");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int swap_calls(void)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Swap");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int create_conference(void)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Conference");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int call_transfer(void)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Transfer");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-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 csd_call *coming;
-
-	DBG("telephony-maemo: device %p connected", telephony_device);
-
-	coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-	if (coming) {
-		if (find_call_with_status(CSD_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)
-{
-	DBG("telephony-maemo: device %p disconnected", telephony_device);
-	events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
-	events_enabled = ind == 1 ? TRUE : FALSE;
-
-	telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
-	telephony_response_and_hold_rsp(telephony_device,
-						CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
-	DBG("telephony-maemo: last dialed number request");
-
-	if (last_dialed_number)
-		telephony_dial_number_req(telephony_device,
-						last_dialed_number);
-	else
-		telephony_last_dialed_number_rsp(telephony_device,
-						CME_ERROR_NOT_ALLOWED);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
-	struct csd_call *call;
-	int err;
-
-	call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-	if (!call)
-		call = find_non_idle_call();
-
-	if (!call) {
-		error("No active call");
-		telephony_terminate_call_rsp(telephony_device,
-						CME_ERROR_NOT_ALLOWED);
-		return;
-	}
-
-	if (call->conference)
-		err = release_conference();
-	else
-		err = release_call(call);
-
-	if (err < 0)
-		telephony_terminate_call_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-	else
-		telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
-	struct csd_call *call;
-
-	call = find_call_with_status(CSD_CALL_STATUS_COMING);
-	if (!call)
-		call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-
-	if (!call)
-		call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
-	if (!call)
-		call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
-	if (!call) {
-		telephony_answer_call_rsp(telephony_device,
-						CME_ERROR_NOT_ALLOWED);
-		return;
-	}
-
-	if (answer_call(call) < 0)
-		telephony_answer_call_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-	else
-		telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int send_method_call(const char *dest, const char *path,
-				const char *interface, const char *method,
-				DBusPendingCallNotifyFunction cb,
-				void *user_data, int type, ...)
-{
-	DBusMessage *msg;
-	DBusPendingCall *call;
-	va_list args;
-
-	msg = dbus_message_new_method_call(dest, path, interface, method);
-	if (!msg) {
-		error("Unable to allocate new D-Bus %s message", method);
-		return -ENOMEM;
-	}
-
-	va_start(args, type);
-
-	if (!dbus_message_append_args_valist(msg, type, args)) {
-		dbus_message_unref(msg);
-		va_end(args);
-		return -EIO;
-	}
-
-	va_end(args);
-
-	if (!cb) {
-		g_dbus_send_message(connection, msg);
-		return 0;
-	}
-
-	if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
-		error("Sending %s failed", method);
-		dbus_message_unref(msg);
-		return -EIO;
-	}
-
-	dbus_pending_call_set_notify(call, cb, user_data, NULL);
-	dbus_pending_call_unref(call);
-	dbus_message_unref(msg);
-
-	return 0;
-}
-
-static const char *memory_dial_lookup(int location)
-{
-	if (location == 1)
-		return vmbx;
-	else
-		return NULL;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
-	uint32_t flags = callerid;
-	int ret;
-
-	DBG("telephony-maemo: dial request to %s", number);
-
-	if (strncmp(number, "*31#", 4) == 0) {
-		number += 4;
-		flags = CALL_FLAG_PRESENTATION_ALLOWED;
-	} else if (strncmp(number, "#31#", 4) == 0) {
-		number += 4;
-		flags = CALL_FLAG_PRESENTATION_RESTRICTED;
-	} else if (number[0] == '>') {
-		const char *location = &number[1];
-
-		number = memory_dial_lookup(strtol(&number[1], NULL, 0));
-		if (!number) {
-			error("No number at memory location %s", location);
-			telephony_dial_number_rsp(telephony_device,
-						CME_ERROR_INVALID_INDEX);
-			return;
-		}
-	}
-
-	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-				CSD_CALL_INTERFACE, "CreateWith",
-				NULL, NULL,
-				DBUS_TYPE_STRING, &number,
-				DBUS_TYPE_UINT32, &flags,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		telephony_dial_number_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-		return;
-	}
-
-	telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
-	int ret;
-	char buf[2] = { tone, '\0' }, *buf_ptr = buf;
-
-	DBG("telephony-maemo: transmit dtmf: %s", buf);
-
-	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-				CSD_CALL_INTERFACE, "SendDTMF",
-				NULL, NULL,
-				DBUS_TYPE_STRING, &buf_ptr,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		telephony_transmit_dtmf_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-		return;
-	}
-
-	telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
-	DBG("telephony-maemo: subscriber number request");
-	if (msisdn)
-		telephony_subscriber_number_ind(msisdn,
-						number_type(msisdn),
-						SUBSCRIBER_SERVICE_VOICE);
-	telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int csd_status_to_hfp(struct csd_call *call)
-{
-	switch (call->status) {
-	case CSD_CALL_STATUS_IDLE:
-	case CSD_CALL_STATUS_MO_RELEASE:
-	case CSD_CALL_STATUS_MT_RELEASE:
-	case CSD_CALL_STATUS_TERMINATED:
-		return -1;
-	case CSD_CALL_STATUS_CREATE:
-		return CALL_STATUS_DIALING;
-	case CSD_CALL_STATUS_WAITING:
-		return CALL_STATUS_WAITING;
-	case CSD_CALL_STATUS_PROCEEDING:
-		/* PROCEEDING can happen in outgoing/incoming */
-		if (call->originating)
-			return CALL_STATUS_DIALING;
-		else
-			return CALL_STATUS_INCOMING;
-	case CSD_CALL_STATUS_COMING:
-		return CALL_STATUS_INCOMING;
-	case CSD_CALL_STATUS_MO_ALERTING:
-		return CALL_STATUS_ALERTING;
-	case CSD_CALL_STATUS_MT_ALERTING:
-		return CALL_STATUS_INCOMING;
-	case CSD_CALL_STATUS_ANSWERED:
-	case CSD_CALL_STATUS_ACTIVE:
-	case CSD_CALL_STATUS_RECONNECT_PENDING:
-	case CSD_CALL_STATUS_SWAP_INITIATED:
-	case CSD_CALL_STATUS_HOLD_INITIATED:
-		return CALL_STATUS_ACTIVE;
-	case CSD_CALL_STATUS_RETRIEVE_INITIATED:
-	case CSD_CALL_STATUS_HOLD:
-		return CALL_STATUS_HELD;
-	default:
-		return -1;
-	}
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
-	GSList *l;
-	int i;
-
-	DBG("telephony-maemo: list current calls request");
-
-	for (l = calls, i = 1; l != NULL; l = l->next, i++) {
-		struct csd_call *call = l->data;
-		int status, direction, multiparty;
-
-		status = csd_status_to_hfp(call);
-		if (status < 0)
-			continue;
-
-		direction = call->originating ?
-				CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
-		multiparty = call->conference ?
-				CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
-		telephony_list_current_call_ind(i, direction, status,
-						CALL_MODE_VOICE, multiparty,
-						call->number,
-						number_type(call->number));
-	}
-
-	telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
-	telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
-				net.operator_name ? net.operator_name : "");
-	telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void foreach_call_with_status(int status,
-					int (*func)(struct csd_call *call))
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (call->status == status)
-			func(call);
-	}
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
-	const char *idx;
-	struct csd_call *call;
-	int err = 0;
-
-	DBG("telephony-maemo: got call hold request %s", cmd);
-
-	if (strlen(cmd) > 1)
-		idx = &cmd[1];
-	else
-		idx = NULL;
-
-	if (idx)
-		call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
-	else
-		call = NULL;
-
-	switch (cmd[0]) {
-	case '0':
-		foreach_call_with_status(CSD_CALL_STATUS_HOLD, release_call);
-		foreach_call_with_status(CSD_CALL_STATUS_WAITING,
-								release_call);
-		break;
-	case '1':
-		if (idx) {
-			if (call)
-				err = release_call(call);
-			break;
-		}
-		foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
-		call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-		if (call)
-			err = answer_call(call);
-		break;
-	case '2':
-		if (idx) {
-			if (call)
-				err = split_call(call);
-		} else {
-			struct csd_call *held, *wait;
-
-			call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-			held = find_call_with_status(CSD_CALL_STATUS_HOLD);
-			wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
-			if (wait)
-				err = answer_call(wait);
-			else if (call && held)
-				err = swap_calls();
-			else {
-				if (call)
-					err = hold_call(call);
-				if (held)
-					err = unhold_call(held);
-			}
-		}
-		break;
-	case '3':
-		if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
-				find_call_with_status(CSD_CALL_STATUS_WAITING))
-			err = create_conference();
-		break;
-	case '4':
-		err = call_transfer();
-		break;
-	default:
-		DBG("Unknown call hold request");
-		break;
-	}
-
-	if (err)
-		telephony_call_hold_rsp(telephony_device,
-					CME_ERROR_AG_FAILURE);
-	else
-		telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
-	DBG("telephony-maemo: got %s NR and EC request",
-			enable ? "enable" : "disable");
-	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
-	struct csd_call *active, *waiting;
-	int err;
-
-	DBG("telephony-maemo: got key press request for %s", keys);
-
-	waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
-	if (!waiting)
-		waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-	if (!waiting)
-		waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
-	active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-
-	if (waiting)
-		err = answer_call(waiting);
-	else if (active)
-		err = release_call(active);
-	else
-		err = 0;
-
-	if (err < 0)
-		telephony_key_press_rsp(telephony_device,
-							CME_ERROR_AG_FAILURE);
-	else
-		telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
-	DBG("telephony-maemo: got %s voice dial request",
-			enable ? "enable" : "disable");
-
-	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static void handle_incoming_call(DBusMessage *msg)
-{
-	const char *number, *call_path;
-	struct csd_call *call;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_OBJECT_PATH, &call_path,
-					DBUS_TYPE_STRING, &number,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in Call.Coming() signal");
-		return;
-	}
-
-	call = find_call(call_path);
-	if (!call) {
-		error("Didn't find any matching call object for %s",
-				call_path);
-		return;
-	}
-
-	DBG("Incoming call to %s from number %s", call_path, number);
-
-	g_free(call->number);
-	call->number = g_strdup(number);
-
-	telephony_update_indicator(maemo_indicators, "callsetup",
-					EV_CALLSETUP_INCOMING);
-
-	if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-		telephony_call_waiting_ind(call->number,
-						number_type(call->number));
-	else
-		telephony_incoming_call_ind(call->number,
-						number_type(call->number));
-}
-
-static void handle_outgoing_call(DBusMessage *msg)
-{
-	const char *number, *call_path;
-	struct csd_call *call;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_OBJECT_PATH, &call_path,
-					DBUS_TYPE_STRING, &number,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in Call.Created() signal");
-		return;
-	}
-
-	call = find_call(call_path);
-	if (!call) {
-		error("Didn't find any matching call object for %s",
-				call_path);
-		return;
-	}
-
-	DBG("Outgoing call from %s to number %s", call_path, number);
-
-	g_free(call->number);
-	call->number = g_strdup(number);
-
-	g_free(last_dialed_number);
-	last_dialed_number = g_strdup(number);
-
-	if (create_request_timer) {
-		g_source_remove(create_request_timer);
-		create_request_timer = 0;
-	}
-}
-
-static gboolean create_timeout(gpointer user_data)
-{
-	telephony_update_indicator(maemo_indicators, "callsetup",
-					EV_CALLSETUP_INACTIVE);
-	create_request_timer = 0;
-	return FALSE;
-}
-
-static void handle_create_requested(DBusMessage *msg)
-{
-	DBG("Call.CreateRequested()");
-
-	if (create_request_timer)
-		g_source_remove(create_request_timer);
-
-	create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
-
-	telephony_update_indicator(maemo_indicators, "callsetup",
-					EV_CALLSETUP_OUTGOING);
-}
-
-static void handle_call_status(DBusMessage *msg, const char *call_path)
-{
-	struct csd_call *call;
-	dbus_uint32_t status, cause_type, cause;
-	int callheld = telephony_get_indicator(maemo_indicators, "callheld");
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_UINT32, &status,
-					DBUS_TYPE_UINT32, &cause_type,
-					DBUS_TYPE_UINT32, &cause,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in Instance.CallStatus() signal");
-		return;
-	}
-
-	call = find_call(call_path);
-	if (!call) {
-		error("Didn't find any matching call object for %s",
-				call_path);
-		return;
-	}
-
-	if (status > 16) {
-		error("Invalid call status %u", status);
-		return;
-	}
-
-	DBG("Call %s changed from %s to %s", call_path,
-		call_status_str[call->status], call_status_str[status]);
-
-	if (call->status == (int) status) {
-		DBG("Ignoring CSD Call state change to existing state");
-		return;
-	}
-
-	call->status = (int) status;
-
-	switch (status) {
-	case CSD_CALL_STATUS_IDLE:
-		if (call->setup) {
-			telephony_update_indicator(maemo_indicators,
-							"callsetup",
-							EV_CALLSETUP_INACTIVE);
-			if (!call->originating)
-				telephony_calling_stopped_ind();
-		}
-
-		g_free(call->number);
-		call->number = NULL;
-		call->originating = FALSE;
-		call->emergency = FALSE;
-		call->on_hold = FALSE;
-		call->conference = FALSE;
-		call->setup = FALSE;
-		break;
-	case CSD_CALL_STATUS_CREATE:
-		call->originating = TRUE;
-		call->setup = TRUE;
-		break;
-	case CSD_CALL_STATUS_COMING:
-		call->originating = FALSE;
-		call->setup = TRUE;
-		break;
-	case CSD_CALL_STATUS_PROCEEDING:
-		break;
-	case CSD_CALL_STATUS_MO_ALERTING:
-		telephony_update_indicator(maemo_indicators, "callsetup",
-						EV_CALLSETUP_ALERTING);
-		break;
-	case CSD_CALL_STATUS_MT_ALERTING:
-		break;
-	case CSD_CALL_STATUS_WAITING:
-		break;
-	case CSD_CALL_STATUS_ANSWERED:
-		break;
-	case CSD_CALL_STATUS_ACTIVE:
-		if (call->on_hold) {
-			call->on_hold = FALSE;
-			if (find_call_with_status(CSD_CALL_STATUS_HOLD))
-				telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_MULTIPLE);
-			else
-				telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_NONE);
-		} else {
-			if (!g_slist_find(active_calls, call))
-				active_calls = g_slist_prepend(active_calls, call);
-			if (g_slist_length(active_calls) == 1)
-				telephony_update_indicator(maemo_indicators,
-								"call",
-								EV_CALL_ACTIVE);
-			/* Upgrade callheld status if necessary */
-			if (callheld == EV_CALLHELD_ON_HOLD)
-				telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_MULTIPLE);
-			telephony_update_indicator(maemo_indicators,
-							"callsetup",
-							EV_CALLSETUP_INACTIVE);
-			if (!call->originating)
-				telephony_calling_stopped_ind();
-			call->setup = FALSE;
-		}
-		break;
-	case CSD_CALL_STATUS_MO_RELEASE:
-	case CSD_CALL_STATUS_MT_RELEASE:
-		active_calls = g_slist_remove(active_calls, call);
-		if (g_slist_length(active_calls) == 0)
-			telephony_update_indicator(maemo_indicators, "call",
-							EV_CALL_INACTIVE);
-		break;
-	case CSD_CALL_STATUS_HOLD_INITIATED:
-		break;
-	case CSD_CALL_STATUS_HOLD:
-		call->on_hold = TRUE;
-		if (find_non_held_call())
-			telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_MULTIPLE);
-		else
-			telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_ON_HOLD);
-		break;
-	case CSD_CALL_STATUS_RETRIEVE_INITIATED:
-		break;
-	case CSD_CALL_STATUS_RECONNECT_PENDING:
-		break;
-	case CSD_CALL_STATUS_TERMINATED:
-		if (call->on_hold &&
-				!find_call_with_status(CSD_CALL_STATUS_HOLD))
-			telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_NONE);
-		else if (callheld == EV_CALLHELD_MULTIPLE &&
-				find_call_with_status(CSD_CALL_STATUS_HOLD))
-			telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_ON_HOLD);
-		break;
-	case CSD_CALL_STATUS_SWAP_INITIATED:
-		break;
-	default:
-		error("Unknown call status %u", status);
-		break;
-	}
-}
-
-static void handle_conference(DBusMessage *msg, gboolean joined)
-{
-	const char *path;
-	struct csd_call *call;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_OBJECT_PATH, &path,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in Conference.%s",
-					dbus_message_get_member(msg));
-		return;
-	}
-
-	call = find_call(path);
-	if (!call) {
-		error("Conference signal for unknown call %s", path);
-		return;
-	}
-
-	DBG("Call %s %s the conference", path, joined ? "joined" : "left");
-
-	call->conference = joined;
-}
-
-static void get_operator_name_reply(DBusPendingCall *pending_call,
-					void *user_data)
-{
-	DBusMessage *reply;
-	DBusError err;
-	const char *name;
-	dbus_int32_t net_err;
-
-	reply = dbus_pending_call_steal_reply(pending_call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("get_operator_name failed: %s, %s",
-			err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	dbus_error_init(&err);
-	if (!dbus_message_get_args(reply, &err,
-					DBUS_TYPE_STRING, &name,
-					DBUS_TYPE_INT32, &net_err,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected get_operator_name reply parameters: %s, %s",
-			err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	if (net_err != 0) {
-		error("get_operator_name failed with code %d", net_err);
-		goto done;
-	}
-
-	if (strlen(name) == 0)
-		goto done;
-
-	g_free(net.operator_name);
-	net.operator_name = g_strdup(name);
-
-	DBG("telephony-maemo: operator name updated: %s", name);
-
-done:
-	dbus_message_unref(reply);
-}
-
-static void resolve_operator_name(uint32_t operator, uint32_t country)
-{
-	uint8_t name_type = NETWORK_HARDCODED_LATIN_OPER_NAME;
-
-	send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-				NETWORK_INTERFACE, "get_operator_name",
-				get_operator_name_reply, NULL,
-				DBUS_TYPE_BYTE, &name_type,
-				DBUS_TYPE_UINT32, &operator,
-				DBUS_TYPE_UINT32, &country,
-				DBUS_TYPE_INVALID);
-}
-
-static void update_registration_status(uint8_t status, uint16_t lac,
-					uint32_t cell_id,
-					uint32_t operator_code,
-					uint32_t country_code,
-					uint8_t network_type,
-					uint8_t supported_services)
-{
-	if (net.status != status) {
-		switch (status) {
-		case NETWORK_REG_STATUS_HOME:
-			telephony_update_indicator(maemo_indicators, "roam",
-							EV_ROAM_INACTIVE);
-			if (net.status >= NETWORK_REG_STATUS_NOSERV)
-				telephony_update_indicator(maemo_indicators,
-							"service",
-							EV_SERVICE_PRESENT);
-			break;
-		case NETWORK_REG_STATUS_ROAM:
-		case NETWORK_REG_STATUS_ROAM_BLINK:
-			telephony_update_indicator(maemo_indicators, "roam",
-							EV_ROAM_ACTIVE);
-			if (net.status >= NETWORK_REG_STATUS_NOSERV)
-				telephony_update_indicator(maemo_indicators,
-							"service",
-							EV_SERVICE_PRESENT);
-			break;
-		case NETWORK_REG_STATUS_NOSERV:
-		case NETWORK_REG_STATUS_NOSERV_SEARCHING:
-		case NETWORK_REG_STATUS_NOSERV_NOTSEARCHING:
-		case NETWORK_REG_STATUS_NOSERV_NOSIM:
-		case NETWORK_REG_STATUS_POWER_OFF:
-		case NETWORK_REG_STATUS_NSPS:
-		case NETWORK_REG_STATUS_NSPS_NO_COVERAGE:
-		case NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW:
-			if (net.status < NETWORK_REG_STATUS_NOSERV)
-				telephony_update_indicator(maemo_indicators,
-							"service",
-							EV_SERVICE_NONE);
-			break;
-		}
-
-		net.status = status;
-	}
-
-	net.lac = lac;
-	net.cell_id = cell_id;
-
-	if (net.operator_code != operator_code ||
-			net.country_code != country_code) {
-		g_free(net.operator_name);
-		net.operator_name = NULL;
-		resolve_operator_name(operator_code, country_code);
-		net.operator_code = operator_code;
-		net.country_code = country_code;
-	}
-
-	net.network_type = network_type;
-	net.supported_services = supported_services;
-}
-
-static void handle_registration_status_change(DBusMessage *msg)
-{
-	uint8_t status;
-	dbus_uint16_t lac, network_type, supported_services;
-	dbus_uint32_t cell_id, operator_code, country_code;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_BYTE, &status,
-					DBUS_TYPE_UINT16, &lac,
-					DBUS_TYPE_UINT32, &cell_id,
-					DBUS_TYPE_UINT32, &operator_code,
-					DBUS_TYPE_UINT32, &country_code,
-					DBUS_TYPE_BYTE, &network_type,
-					DBUS_TYPE_BYTE, &supported_services,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in registration_status_change");
-		return;
-	}
-
-	update_registration_status(status, lac, cell_id, operator_code,
-					country_code, network_type,
-					supported_services);
-}
-
-static void update_signal_strength(uint8_t signals_bar)
-{
-	int signal;
-
-	if (signals_bar > 100) {
-		DBG("signals_bar greater than expected: %u", signals_bar);
-		signals_bar = 100;
-	}
-
-	if (net.signals_bar == signals_bar)
-		return;
-
-	/* A simple conversion from 0-100 to 0-5 (used by HFP) */
-	signal = (signals_bar + 20) / 21;
-
-	telephony_update_indicator(maemo_indicators, "signal", signal);
-
-	net.signals_bar = signals_bar;
-
-	DBG("Signal strength updated: %u/100, %d/5", signals_bar, signal);
-}
-
-static void handle_signal_strength_change(DBusMessage *msg)
-{
-	uint8_t signals_bar, rssi_in_dbm;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_BYTE, &signals_bar,
-					DBUS_TYPE_BYTE, &rssi_in_dbm,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in signal_strength_change");
-		return;
-	}
-
-	update_signal_strength(signals_bar);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
-					int first_arg_type, ...)
-{
-	int type;
-	va_list ap;
-
-	va_start(ap, first_arg_type);
-
-	for (type = first_arg_type; type != DBUS_TYPE_INVALID;
-			type = va_arg(ap, int)) {
-		void *value = va_arg(ap, void *);
-		int real_type = dbus_message_iter_get_arg_type(iter);
-
-		if (real_type != type) {
-			error("iter_get_basic_args: expected %c but got %c",
-					(char) type, (char) real_type);
-			break;
-		}
-
-		dbus_message_iter_get_basic(iter, value);
-		dbus_message_iter_next(iter);
-	}
-
-	va_end(ap);
-
-	return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	dbus_int32_t level;
-	int *value = user_data;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("hald replied with an error: %s, %s",
-				err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	dbus_error_init(&err);
-	if (dbus_message_get_args(reply, &err,
-				DBUS_TYPE_INT32, &level,
-				DBUS_TYPE_INVALID) == FALSE) {
-		error("Unable to parse GetPropertyInteger reply: %s, %s",
-							err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	*value = (int) level;
-
-	if (value == &battchg_last)
-		DBG("telephony-maemo: battery.charge_level.last_full is %d",
-				*value);
-	else if (value == &battchg_design)
-		DBG("telephony-maemo: battery.charge_level.design is %d",
-				*value);
-	else
-		DBG("telephony-maemo: battery.charge_level.current is %d",
-				*value);
-
-	if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
-		int new, max;
-
-		if (battchg_last > 0)
-			max = battchg_last;
-		else
-			max = battchg_design;
-
-		new = battchg_cur * 5 / max;
-
-		telephony_update_indicator(maemo_indicators, "battchg", new);
-	}
-done:
-	dbus_message_unref(reply);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
-	send_method_call("org.freedesktop.Hal", path,
-				"org.freedesktop.Hal.Device",
-				"GetPropertyInteger",
-				hal_battery_level_reply, user_data,
-				DBUS_TYPE_STRING, &key,
-				DBUS_TYPE_INVALID);
-}
-
-static void handle_hal_property_modified(DBusMessage *msg)
-{
-	DBusMessageIter iter, array;
-	dbus_int32_t num_changes;
-	const char *path;
-
-	path = dbus_message_get_path(msg);
-
-	dbus_message_iter_init(msg, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
-		error("Unexpected signature in hal PropertyModified signal");
-		return;
-	}
-
-	dbus_message_iter_get_basic(&iter, &num_changes);
-	dbus_message_iter_next(&iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in hal PropertyModified signal");
-		return;
-	}
-
-	dbus_message_iter_recurse(&iter, &array);
-
-	while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-		DBusMessageIter prop;
-		const char *name;
-		dbus_bool_t added, removed;
-
-		dbus_message_iter_recurse(&array, &prop);
-
-		if (!iter_get_basic_args(&prop,
-					DBUS_TYPE_STRING, &name,
-					DBUS_TYPE_BOOLEAN, &added,
-					DBUS_TYPE_BOOLEAN, &removed,
-					DBUS_TYPE_INVALID)) {
-			error("Invalid hal PropertyModified parameters");
-			break;
-		}
-
-		if (g_str_equal(name, "battery.charge_level.last_full"))
-			hal_get_integer(path, name, &battchg_last);
-		else if (g_str_equal(name, "battery.charge_level.current"))
-			hal_get_integer(path, name, &battchg_cur);
-		else if (g_str_equal(name, "battery.charge_level.design"))
-			hal_get_integer(path, name, &battchg_design);
-
-		dbus_message_iter_next(&array);
-	}
-}
-
-static void csd_call_free(struct csd_call *call)
-{
-	if (!call)
-		return;
-
-	g_free(call->object_path);
-	g_free(call->number);
-
-	g_free(call);
-}
-
-static void parse_call_list(DBusMessageIter *iter)
-{
-	do {
-		DBusMessageIter call_iter;
-		struct csd_call *call;
-		const char *object_path, *number;
-		dbus_uint32_t status;
-		dbus_bool_t originating, terminating, emerg, on_hold, conf;
-
-		if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
-			error("Unexpected signature in GetCallInfoAll reply");
-			break;
-		}
-
-		dbus_message_iter_recurse(iter, &call_iter);
-
-		if (!iter_get_basic_args(&call_iter,
-					DBUS_TYPE_OBJECT_PATH, &object_path,
-					DBUS_TYPE_UINT32, &status,
-					DBUS_TYPE_BOOLEAN, &originating,
-					DBUS_TYPE_BOOLEAN, &terminating,
-					DBUS_TYPE_BOOLEAN, &emerg,
-					DBUS_TYPE_BOOLEAN, &on_hold,
-					DBUS_TYPE_BOOLEAN, &conf,
-					DBUS_TYPE_STRING, &number,
-					DBUS_TYPE_INVALID)) {
-			error("Parsing call D-Bus parameters failed");
-			break;
-		}
-
-		call = find_call(object_path);
-		if (!call) {
-			call = g_new0(struct csd_call, 1);
-			call->object_path = g_strdup(object_path);
-			call->status = (int) status;
-			calls = g_slist_append(calls, call);
-			DBG("telephony-maemo: new csd call instance at %s",
-								object_path);
-		}
-
-		if (call->status == CSD_CALL_STATUS_IDLE)
-			continue;
-
-		/* CSD gives incorrect call_hold property sometimes */
-		if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
-				(call->status == CSD_CALL_STATUS_HOLD &&
-								!on_hold)) {
-			error("Conflicting call status and on_hold property!");
-			on_hold = call->status == CSD_CALL_STATUS_HOLD;
-		}
-
-		call->originating = originating;
-		call->on_hold = on_hold;
-		call->conference = conf;
-		g_free(call->number);
-		call->number = g_strdup(number);
-
-	} while (dbus_message_iter_next(iter));
-}
-
-static void signal_strength_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	uint8_t signals_bar, rssi_in_dbm;
-	dbus_int32_t net_err;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("Unable to get signal strength: %s, %s",
-			err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	dbus_error_init(&err);
-	if (!dbus_message_get_args(reply, &err,
-					DBUS_TYPE_BYTE, &signals_bar,
-					DBUS_TYPE_BYTE, &rssi_in_dbm,
-					DBUS_TYPE_INT32, &net_err,
-					DBUS_TYPE_INVALID)) {
-		error("Unable to parse signal_strength reply: %s, %s",
-							err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	if (net_err != 0) {
-		error("get_signal_strength failed with code %d", net_err);
-		goto done;
-	}
-
-	update_signal_strength(signals_bar);
-
-done:
-	dbus_message_unref(reply);
-}
-
-static int get_signal_strength(void)
-{
-	return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-				NETWORK_INTERFACE, "get_signal_strength",
-				signal_strength_reply, NULL,
-				DBUS_TYPE_INVALID);
-}
-
-static void registration_status_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	uint8_t status;
-	dbus_uint16_t lac, network_type, supported_services;
-	dbus_uint32_t cell_id, operator_code, country_code;
-	dbus_int32_t net_err;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("Unable to get registration status: %s, %s",
-				err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	dbus_error_init(&err);
-	if (!dbus_message_get_args(reply, &err,
-					DBUS_TYPE_BYTE, &status,
-					DBUS_TYPE_UINT16, &lac,
-					DBUS_TYPE_UINT32, &cell_id,
-					DBUS_TYPE_UINT32, &operator_code,
-					DBUS_TYPE_UINT32, &country_code,
-					DBUS_TYPE_BYTE, &network_type,
-					DBUS_TYPE_BYTE, &supported_services,
-					DBUS_TYPE_INT32, &net_err,
-					DBUS_TYPE_INVALID)) {
-		error("Unable to parse registration_status_change reply:"
-					" %s, %s", err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	if (net_err != 0) {
-		error("get_registration_status failed with code %d", net_err);
-		goto done;
-	}
-
-	update_registration_status(status, lac, cell_id, operator_code,
-					country_code, network_type,
-					supported_services);
-
-	get_signal_strength();
-
-done:
-	dbus_message_unref(reply);
-}
-
-static int get_registration_status(void)
-{
-	return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-				NETWORK_INTERFACE, "get_registration_status",
-				registration_status_reply, NULL,
-				DBUS_TYPE_INVALID);
-}
-
-static void call_info_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	DBusMessageIter iter, sub;
-
-	get_calls_active = FALSE;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("csd 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 in GetCallInfoAll return");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &sub);
-
-	parse_call_list(&sub);
-
-	get_registration_status();
-
-done:
-	dbus_message_unref(reply);
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	DBusMessageIter iter, sub;
-	const char *path;
-	char match_string[256];
-	int type;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("hald 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 in FindDeviceByCapability return");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &sub);
-
-	type = dbus_message_iter_get_arg_type(&sub);
-
-	if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
-		error("No hal device with battery capability found");
-		goto done;
-	}
-
-	dbus_message_iter_get_basic(&sub, &path);
-
-	DBG("telephony-maemo: found battery device at %s", path);
-
-	snprintf(match_string, sizeof(match_string),
-			"type='signal',"
-			"path='%s',"
-			"interface='org.freedesktop.Hal.Device',"
-			"member='PropertyModified'", path);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
-	hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
-	hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-
-done:
-	dbus_message_unref(reply);
-}
-
-static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError derr;
-	DBusMessage *reply;
-	const char *name, *number;
-	char **number_type = user_data;
-	dbus_int32_t current_location, err;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		error("SIM.Phonebook replied with an error: %s, %s",
-				derr.name, derr.message);
-		dbus_error_free(&derr);
-		goto done;
-	}
-
-	dbus_error_init(&derr);
-	if (dbus_message_get_args(reply, &derr,
-				DBUS_TYPE_STRING, &name,
-				DBUS_TYPE_STRING, &number,
-				DBUS_TYPE_INT32, &current_location,
-				DBUS_TYPE_INT32, &err,
-				DBUS_TYPE_INVALID) == FALSE) {
-		error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
-				derr.name, derr.message);
-		dbus_error_free(&derr);
-		goto done;
-	}
-
-	if (err != 0) {
-		error("SIM.Phonebook.read failed with error %d", err);
-		if (number_type == &vmbx)
-			vmbx = g_strdup(getenv("VMBX_NUMBER"));
-		goto done;
-	}
-
-	if (number_type == &msisdn) {
-		g_free(msisdn);
-		msisdn = g_strdup(number);
-		DBG("Got MSISDN %s (%s)", number, name);
-	} else {
-		g_free(vmbx);
-		vmbx = g_strdup(number);
-		DBG("Got voice mailbox number %s (%s)", number, name);
-	}
-
-done:
-	dbus_message_unref(reply);
-}
-
-static void csd_init(void)
-{
-	dbus_uint32_t location;
-	uint8_t pb_type, location_type;
-	int ret;
-
-	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-				CSD_CALL_INTERFACE, "GetCallInfoAll",
-				call_info_reply, NULL, DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		error("Unable to sent GetCallInfoAll method call");
-		return;
-	}
-
-	get_calls_active = TRUE;
-
-	pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
-	location = PHONEBOOK_INDEX_FIRST_ENTRY;
-	location_type = SIM_PHONEBOOK_LOCATION_NEXT;
-
-	ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
-				SIM_PHONEBOOK_INTERFACE, "read",
-				phonebook_read_reply, &msisdn,
-				DBUS_TYPE_BYTE, &pb_type,
-				DBUS_TYPE_INT32, &location,
-				DBUS_TYPE_BYTE, &location_type,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
-		return;
-	}
-
-	pb_type = SIM_PHONEBOOK_TYPE_MBDN;
-	location = PHONEBOOK_INDEX_FIRST_ENTRY;
-	location_type = SIM_PHONEBOOK_LOCATION_NEXT;
-
-	ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
-				SIM_PHONEBOOK_INTERFACE, "read",
-				phonebook_read_reply, &vmbx,
-				DBUS_TYPE_BYTE, &pb_type,
-				DBUS_TYPE_INT32, &location,
-				DBUS_TYPE_BYTE, &location_type,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
-		return;
-	}
-}
-
-static uint32_t get_callflag(const char *callerid_setting)
-{
-	if (callerid_setting != NULL) {
-		if (g_str_equal(callerid_setting, "allowed"))
-			return CALL_FLAG_PRESENTATION_ALLOWED;
-		else if (g_str_equal(callerid_setting, "restricted"))
-			return CALL_FLAG_PRESENTATION_RESTRICTED;
-		else
-			return CALL_FLAG_NONE;
-	} else
-		return CALL_FLAG_NONE;
-}
-
-static void generate_flag_file(const char *filename)
-{
-	int fd;
-
-	if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
-			g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
-			g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
-		return;
-
-	fd = open(filename, O_WRONLY | O_CREAT, 0);
-	if (fd >= 0)
-		close(fd);
-}
-
-static void save_callerid_to_file(const char *callerid_setting)
-{
-	char callerid_file[FILENAME_MAX];
-
-	snprintf(callerid_file, sizeof(callerid_file), "%s%s",
-					CALLERID_BASE, callerid_setting);
-
-	if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
-		rename(ALLOWED_FLAG_FILE, callerid_file);
-	else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
-		rename(RESTRICTED_FLAG_FILE, callerid_file);
-	else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
-		rename(NONE_FLAG_FILE, callerid_file);
-	else
-		generate_flag_file(callerid_file);
-}
-
-static uint32_t callerid_from_file(void)
-{
-	if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
-		return CALL_FLAG_PRESENTATION_ALLOWED;
-	else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
-		return CALL_FLAG_PRESENTATION_RESTRICTED;
-	else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
-		return CALL_FLAG_NONE;
-	else
-		return CALL_FLAG_NONE;
-}
-
-static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	const char *callerid_setting;
-
-	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING,
-						&callerid_setting,
-						DBUS_TYPE_INVALID) == FALSE)
-		return btd_error_invalid_args(msg);
-
-	if (g_str_equal(callerid_setting, "allowed") ||
-			g_str_equal(callerid_setting, "restricted") ||
-			g_str_equal(callerid_setting, "none")) {
-		save_callerid_to_file(callerid_setting);
-		callerid = get_callflag(callerid_setting);
-		DBG("telephony-maemo setting callerid flag: %s",
-							callerid_setting);
-		return dbus_message_new_method_return(msg);
-	}
-
-	error("telephony-maemo: invalid argument %s for method call"
-					" SetCallerId", callerid_setting);
-		return btd_error_invalid_args(msg);
-}
-
-static const GDBusMethodTable telephony_maemo_methods[] = {
-	{ GDBUS_ASYNC_METHOD("SetCallerId",
-				GDBUS_ARGS({ "id", "s" }), NULL,
-				set_callerid) },
-	{ }
-};
-
-static void handle_modem_state(DBusMessage *msg)
-{
-	const char *state;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
-							DBUS_TYPE_INVALID)) {
-		error("Unexpected modem state parameters");
-		return;
-	}
-
-	DBG("SSC modem state: %s", state);
-
-	if (calls != NULL || get_calls_active)
-		return;
-
-	if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
-		csd_init();
-}
-
-static void modem_state_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	DBusError err;
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("get_modem_status: %s, %s", err.name, err.message);
-		dbus_error_free(&err);
-	} else
-		handle_modem_state(reply);
-
-	dbus_message_unref(reply);
-}
-
-static DBusHandlerResult signal_filter(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	const char *path = dbus_message_get_path(msg);
-
-	if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-	if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
-		handle_incoming_call(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
-		handle_outgoing_call(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
-							"CreateRequested"))
-		handle_create_requested(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
-		handle_call_status(msg, path);
-	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
-		handle_conference(msg, TRUE);
-	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
-		handle_conference(msg, FALSE);
-	else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
-					"registration_status_change"))
-		handle_registration_status_change(msg);
-	else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
-					"signal_strength_change"))
-		handle_signal_strength_change(msg);
-	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
-					"PropertyModified"))
-		handle_hal_property_modified(msg);
-	else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
-						"modem_state_changed_ind"))
-		handle_modem_state(msg);
-
-	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-int telephony_init(void)
-{
-	const char *battery_cap = "battery";
-	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
-				AG_FEATURE_INBAND_RINGTONE |
-				AG_FEATURE_REJECT_A_CALL |
-				AG_FEATURE_ENHANCED_CALL_STATUS |
-				AG_FEATURE_ENHANCED_CALL_CONTROL |
-				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
-				AG_FEATURE_THREE_WAY_CALLING;
-
-	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
-	if (!dbus_connection_add_filter(connection, signal_filter,
-						NULL, NULL))
-		error("Can't add signal filter");
-
-	dbus_bus_add_match(connection,
-			"type=signal,interface=" CSD_CALL_INTERFACE, NULL);
-	dbus_bus_add_match(connection,
-			"type=signal,interface=" CSD_CALL_INSTANCE, NULL);
-	dbus_bus_add_match(connection,
-			"type=signal,interface=" CSD_CALL_CONFERENCE, NULL);
-	dbus_bus_add_match(connection,
-			"type=signal,interface=" NETWORK_INTERFACE, NULL);
-	dbus_bus_add_match(connection,
-				"type=signal,interface=" SSC_DBUS_IFACE
-				",member=modem_state_changed_ind", NULL);
-
-	if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
-					"get_modem_state", modem_state_reply,
-					NULL, DBUS_TYPE_INVALID) < 0)
-		error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
-
-	generate_flag_file(NONE_FLAG_FILE);
-	callerid = callerid_from_file();
-
-	if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH,
-			TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods,
-			NULL, NULL, NULL, NULL)) {
-		error("telephony-maemo interface %s init failed on path %s",
-			TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
-	}
-
-	DBG("telephony-maemo registering %s interface on path %s",
-			TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
-
-	telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
-								chld_str);
-	if (send_method_call("org.freedesktop.Hal",
-				"/org/freedesktop/Hal/Manager",
-				"org.freedesktop.Hal.Manager",
-				"FindDeviceByCapability",
-				hal_find_device_reply, NULL,
-				DBUS_TYPE_STRING, &battery_cap,
-				DBUS_TYPE_INVALID) < 0)
-		error("Unable to send HAL method call");
-
-	return 0;
-}
-
-void telephony_exit(void)
-{
-	g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
-	g_slist_free(calls);
-	calls = NULL;
-
-	dbus_connection_remove_filter(connection, signal_filter, NULL);
-
-	dbus_connection_unref(connection);
-	connection = NULL;
-
-	telephony_deinit();
-}
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 07/15] audio: Remove maemo6 telephony driver
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (5 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 06/15] audio: Remove maemo5 " Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 08/15] audio: Remove oFono " Frédéric Danis
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Remove Maemo 6 telephony driver which has been deprecated by
org.bluez.Telephony interface.
---
 audio/telephony-maemo6.c | 2200 ----------------------------------------------
 1 file changed, 2200 deletions(-)
 delete mode 100644 audio/telephony-maemo6.c

diff --git a/audio/telephony-maemo6.c b/audio/telephony-maemo6.c
deleted file mode 100644
index 0727ffe..0000000
--- a/audio/telephony-maemo6.c
+++ /dev/null
@@ -1,2200 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include <bluetooth/sdp.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-/* SSC D-Bus definitions */
-#define SSC_DBUS_NAME  "com.nokia.phone.SSC"
-#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
-#define SSC_DBUS_PATH  "/com/nokia/phone/SSC"
-
-/* libcsnet D-Bus definitions */
-#define CSD_CSNET_BUS_NAME	"com.nokia.csd.CSNet"
-#define CSD_CSNET_PATH		"/com/nokia/csd/csnet"
-#define CSD_CSNET_IFACE		"com.nokia.csd.CSNet"
-#define CSD_CSNET_REGISTRATION	"com.nokia.csd.CSNet.NetworkRegistration"
-#define CSD_CSNET_OPERATOR	"com.nokia.csd.CSNet.NetworkOperator"
-#define CSD_CSNET_SIGNAL	"com.nokia.csd.CSNet.SignalStrength"
-
-enum net_registration_status {
-	NETWORK_REG_STATUS_HOME,
-	NETWORK_REG_STATUS_ROAMING,
-	NETWORK_REG_STATUS_OFFLINE,
-	NETWORK_REG_STATUS_SEARCHING,
-	NETWORK_REG_STATUS_NO_SIM,
-	NETWORK_REG_STATUS_POWEROFF,
-	NETWORK_REG_STATUS_POWERSAFE,
-	NETWORK_REG_STATUS_NO_COVERAGE,
-	NETWORK_REG_STATUS_REJECTED,
-	NETWORK_REG_STATUS_UNKOWN
-};
-
-/* CSD CALL plugin D-Bus definitions */
-#define CSD_CALL_BUS_NAME	"com.nokia.csd.Call"
-#define CSD_CALL_INTERFACE	"com.nokia.csd.Call"
-#define CSD_CALL_INSTANCE	"com.nokia.csd.Call.Instance"
-#define CSD_CALL_CONFERENCE	"com.nokia.csd.Call.Conference"
-#define CSD_CALL_PATH		"/com/nokia/csd/call"
-#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
-
-/* Call status values as exported by the CSD CALL plugin */
-#define CSD_CALL_STATUS_IDLE			0
-#define CSD_CALL_STATUS_CREATE			1
-#define CSD_CALL_STATUS_COMING			2
-#define CSD_CALL_STATUS_PROCEEDING		3
-#define CSD_CALL_STATUS_MO_ALERTING		4
-#define CSD_CALL_STATUS_MT_ALERTING		5
-#define CSD_CALL_STATUS_WAITING			6
-#define CSD_CALL_STATUS_ANSWERED		7
-#define CSD_CALL_STATUS_ACTIVE			8
-#define CSD_CALL_STATUS_MO_RELEASE		9
-#define CSD_CALL_STATUS_MT_RELEASE		10
-#define CSD_CALL_STATUS_HOLD_INITIATED		11
-#define CSD_CALL_STATUS_HOLD			12
-#define CSD_CALL_STATUS_RETRIEVE_INITIATED	13
-#define CSD_CALL_STATUS_RECONNECT_PENDING	14
-#define CSD_CALL_STATUS_TERMINATED		15
-#define CSD_CALL_STATUS_SWAP_INITIATED		16
-
-#define CALL_FLAG_NONE				0
-#define CALL_FLAG_PRESENTATION_ALLOWED		0x01
-#define CALL_FLAG_PRESENTATION_RESTRICTED	0x02
-
-/* SIM Phonebook D-Bus definitions */
-#define CSD_SIMPB_BUS_NAME			"com.nokia.csd.SIM"
-#define CSD_SIMPB_INTERFACE			"com.nokia.csd.SIM.Phonebook"
-#define CSD_SIMPB_PATH				"/com/nokia/csd/sim/phonebook"
-
-#define CSD_SIMPB_TYPE_ADN			"ADN"
-#define CSD_SIMPB_TYPE_FDN			"FDN"
-#define CSD_SIMPB_TYPE_SDN			"SDN"
-#define CSD_SIMPB_TYPE_VMBX			"VMBX"
-#define CSD_SIMPB_TYPE_MBDN			"MBDN"
-#define CSD_SIMPB_TYPE_EN			"EN"
-#define CSD_SIMPB_TYPE_MSISDN			"MSISDN"
-
-/* OHM plugin D-Bus definitions */
-#define OHM_BUS_NAME		"com.nokia.NonGraphicFeedback1"
-#define OHM_INTERFACE		"com.nokia.NonGraphicFeedback1"
-#define OHM_PATH		"/com/nokia/NonGraphicFeedback1"
-
-/* tone-genenerator D-Bus definitions */
-#define TONEGEN_BUS_NAME	"com.Nokia.Telephony.Tones"
-#define TONEGEN_INTERFACE	"com.Nokia.Telephony.Tones"
-#define TONEGEN_PATH		"/com/Nokia/Telephony/Tones"
-
-/* tone-generator DTMF definitions */
-#define DTMF_ASTERISK   10
-#define DTMF_HASHMARK   11
-#define DTMF_A          12
-#define DTMF_B          13
-#define DTMF_C          14
-#define DTMF_D          15
-
-#define FEEDBACK_TONE_DURATION			200
-
-struct csd_call {
-	char *object_path;
-	int status;
-	gboolean originating;
-	gboolean emergency;
-	gboolean on_hold;
-	gboolean conference;
-	char *number;
-	gboolean setup;
-};
-
-static struct {
-	char *operator_name;
-	uint8_t status;
-	int32_t signal_bars;
-} net = {
-	.operator_name = NULL,
-	.status = NETWORK_REG_STATUS_UNKOWN,
-	/* Init as 0 meaning inactive mode. In modem power off state
-	 * can be be -1, but we treat all values as 0s regardless
-	 * inactive or power off. */
-	.signal_bars = 0,
-};
-
-struct pending_req {
-	DBusPendingCall *call;
-	void *user_data;
-};
-
-static int get_property(const char *iface, const char *prop);
-
-static DBusConnection *connection = NULL;
-
-static GSList *calls = NULL;
-static GSList *watches = NULL;
-static GSList *pending = NULL;
-
-/* Reference count for determining the call indicator status */
-static GSList *active_calls = NULL;
-
-/* Queue of DTMF tones to play */
-static GSList *tones = NULL;
-static guint create_tones_timer = 0;
-
-static char *msisdn = NULL;	/* Subscriber number */
-static char *vmbx = NULL;	/* Voice mailbox number */
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1;	/* "battery.charge_level.current" */
-static int battchg_last = -1;	/* "battery.charge_level.last_full" */
-static int battchg_design = -1;	/* "battery.charge_level.design" */
-
-static gboolean get_calls_active = FALSE;
-
-static gboolean events_enabled = FALSE;
-
-/* Supported set of call hold operations */
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-
-/* Timer for tracking call creation requests */
-static guint create_request_timer = 0;
-
-static struct indicator maemo_indicators[] =
-{
-	{ "battchg",	"0-5",	5,	TRUE },
-	/* signal strength in terms of bars */
-	{ "signal",	"0-5",	0,	TRUE },
-	{ "service",	"0,1",	0,	TRUE },
-	{ "call",	"0,1",	0,	TRUE },
-	{ "callsetup",	"0-3",	0,	TRUE },
-	{ "callheld",	"0-2",	0,	FALSE },
-	{ "roam",	"0,1",	0,	TRUE },
-	{ NULL }
-};
-
-static char *call_status_str[] = {
-	"IDLE",
-	"CREATE",
-	"COMING",
-	"PROCEEDING",
-	"MO_ALERTING",
-	"MT_ALERTING",
-	"WAITING",
-	"ANSWERED",
-	"ACTIVE",
-	"MO_RELEASE",
-	"MT_RELEASE",
-	"HOLD_INITIATED",
-	"HOLD",
-	"RETRIEVE_INITIATED",
-	"RECONNECT_PENDING",
-	"TERMINATED",
-	"SWAP_INITIATED",
-	"???"
-};
-
-static int send_method_call(const char *dest, const char *path,
-				const char *interface, const char *method,
-				DBusPendingCallNotifyFunction cb,
-				void *user_data, int type, ...)
-{
-	DBusMessage *msg;
-	DBusPendingCall *call;
-	va_list args;
-	struct pending_req *req;
-
-	msg = dbus_message_new_method_call(dest, path, interface, method);
-	if (!msg) {
-		error("Unable to allocate new D-Bus %s message", method);
-		return -ENOMEM;
-	}
-
-	va_start(args, type);
-
-	if (!dbus_message_append_args_valist(msg, type, args)) {
-		dbus_message_unref(msg);
-		va_end(args);
-		return -EIO;
-	}
-
-	va_end(args);
-
-	if (!cb) {
-		g_dbus_send_message(connection, msg);
-		return 0;
-	}
-
-	if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
-		error("Sending %s failed", method);
-		dbus_message_unref(msg);
-		return -EIO;
-	}
-
-	dbus_pending_call_set_notify(call, cb, user_data, NULL);
-
-	req = g_new0(struct pending_req, 1);
-	req->call = call;
-	req->user_data = user_data;
-
-	pending = g_slist_prepend(pending, req);
-	dbus_message_unref(msg);
-
-	return 0;
-}
-
-static struct csd_call *find_call(const char *path)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (g_str_equal(call->object_path, path))
-			return call;
-	}
-
-	return NULL;
-}
-
-static struct csd_call *find_non_held_call(void)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (call->status == CSD_CALL_STATUS_IDLE)
-			continue;
-
-		if (call->status != CSD_CALL_STATUS_HOLD)
-			return call;
-	}
-
-	return NULL;
-}
-
-static struct csd_call *find_non_idle_call(void)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (call->status != CSD_CALL_STATUS_IDLE)
-			return call;
-	}
-
-	return NULL;
-}
-
-static struct csd_call *find_call_with_status(int status)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (call->status == status)
-			return call;
-	}
-
-	return NULL;
-}
-
-static int release_conference(void)
-{
-	DBusMessage *msg;
-
-	DBG("telephony-maemo6: releasing conference call");
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-						CSD_CALL_CONFERENCE_PATH,
-						CSD_CALL_INSTANCE,
-						"Release");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int release_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-						call->object_path,
-						CSD_CALL_INSTANCE,
-						"Release");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int answer_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-						call->object_path,
-						CSD_CALL_INSTANCE,
-						"Answer");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static struct pending_req *find_request(const DBusPendingCall *call)
-{
-	GSList *l;
-
-	for (l = pending; l; l = l->next) {
-		struct pending_req *req = l->data;
-
-		if (req->call == call)
-			return req;
-	}
-
-	return NULL;
-}
-
-static void pending_req_finalize(void *data)
-{
-	struct pending_req *req = data;
-
-	if (!dbus_pending_call_get_completed(req->call))
-		dbus_pending_call_cancel(req->call);
-
-	dbus_pending_call_unref(req->call);
-	g_free(req);
-}
-
-static void remove_pending(DBusPendingCall *call)
-{
-	struct pending_req *req = find_request(call);
-
-	pending = g_slist_remove(pending, req);
-	pending_req_finalize(req);
-}
-
-static void stop_ringtone_reply(DBusPendingCall *call, void *user_data)
-{
-	struct csd_call *coming = user_data;
-
-	remove_pending(call);
-	answer_call(coming);
-}
-
-static int stop_ringtone_and_answer(struct csd_call *call)
-{
-	int ret;
-
-	ret = send_method_call(OHM_BUS_NAME, OHM_PATH,
-				OHM_INTERFACE, "StopRingtone",
-				stop_ringtone_reply, call,
-				DBUS_TYPE_INVALID);
-	if (ret < 0)
-		return answer_call(call);
-
-	return 0;
-}
-
-static int split_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-						call->object_path,
-						CSD_CALL_INSTANCE,
-						"Split");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int unhold_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Unhold");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int hold_call(struct csd_call *call)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Hold");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int swap_calls(void)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Swap");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int create_conference(void)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Conference");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-static int call_transfer(void)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-						CSD_CALL_INTERFACE,
-						"Transfer");
-	if (!msg) {
-		error("Unable to allocate new D-Bus message");
-		return -ENOMEM;
-	}
-
-	g_dbus_send_message(connection, msg);
-
-	return 0;
-}
-
-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 csd_call *coming;
-
-	DBG("telephony-maemo6: device %p connected", telephony_device);
-
-	coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-	if (coming) {
-		if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-			telephony_call_waiting_ind(coming->number,
-						number_type(coming->number));
-		else
-			telephony_incoming_call_ind(coming->number,
-						number_type(coming->number));
-	}
-}
-
-static void remove_pending_by_data(gpointer data, gpointer user_data)
-{
-	struct pending_req *req = data;
-
-	if (req->user_data == user_data) {
-		pending = g_slist_remove(pending, req);
-		pending_req_finalize(req);
-	}
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
-	DBG("telephony-maemo6: device %p disconnected", telephony_device);
-	events_enabled = FALSE;
-
-	g_slist_foreach(pending, remove_pending_by_data, telephony_device);
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
-	events_enabled = ind == 1 ? TRUE : FALSE;
-
-	telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
-	telephony_response_and_hold_rsp(telephony_device,
-						CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
-	struct csd_call *call;
-	struct csd_call *alerting;
-	int err;
-
-	call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-	if (!call)
-		call = find_non_idle_call();
-
-	if (!call) {
-		error("No active call");
-		telephony_terminate_call_rsp(telephony_device,
-						CME_ERROR_NOT_ALLOWED);
-		return;
-	}
-
-	alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING);
-	if (call->on_hold && alerting)
-		err = release_call(alerting);
-	else if (call->conference)
-		err = release_conference();
-	else
-		err = release_call(call);
-
-	if (err < 0)
-		telephony_terminate_call_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-	else
-		telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
-	struct csd_call *call;
-
-	call = find_call_with_status(CSD_CALL_STATUS_COMING);
-	if (!call)
-		call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-
-	if (!call)
-		call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
-	if (!call)
-		call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
-	if (!call) {
-		telephony_answer_call_rsp(telephony_device,
-						CME_ERROR_NOT_ALLOWED);
-		return;
-	}
-
-	if (stop_ringtone_and_answer(call) < 0)
-		telephony_answer_call_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-	else
-		telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void create_call_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	void *telephony_device = user_data;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("csd replied with an error: %s, %s",
-				err.name, err.message);
-		if (g_strcmp0(err.name,
-				"com.nokia.csd.Call.Error.CSInactive") == 0)
-			telephony_dial_number_rsp(telephony_device,
-						CME_ERROR_NO_NETWORK_SERVICE);
-		else
-			telephony_dial_number_rsp(telephony_device,
-							CME_ERROR_AG_FAILURE);
-		dbus_error_free(&err);
-	} else
-		telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
-	int ret;
-
-	DBG("telephony-maemo6: last dialed number request");
-
-	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-				CSD_CALL_INTERFACE, "CreateFromLast",
-				create_call_reply, telephony_device,
-				DBUS_TYPE_INVALID);
-	if (ret < 0)
-		telephony_dial_number_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-}
-
-static const char *memory_dial_lookup(int location)
-{
-	if (location == 1)
-		return vmbx;
-	else
-		return NULL;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
-	int ret;
-
-	DBG("telephony-maemo6: dial request to %s", number);
-
-	if (strncmp(number, "*31#", 4) == 0)
-		number += 4;
-	else if (strncmp(number, "#31#", 4) == 0)
-		number += 4;
-	else if (number[0] == '>') {
-		const char *location = &number[1];
-
-		number = memory_dial_lookup(strtol(&number[1], NULL, 0));
-		if (!number) {
-			error("No number at memory location %s", location);
-			telephony_dial_number_rsp(telephony_device,
-						CME_ERROR_INVALID_INDEX);
-			return;
-		}
-	}
-
-	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-				CSD_CALL_INTERFACE, "Create",
-				create_call_reply, telephony_device,
-				DBUS_TYPE_STRING, &number,
-				DBUS_TYPE_INVALID);
-	if (ret < 0)
-		telephony_dial_number_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-}
-
-static void start_dtmf_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("csd replied with an error: %s, %s",
-				err.name, err.message);
-
-		dbus_error_free(&err);
-	} else
-		send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-				CSD_CALL_INTERFACE, "StopDTMF",
-				NULL, NULL,
-				DBUS_TYPE_INVALID);
-
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-static void start_dtmf(void *telephony_device, char tone)
-{
-	int ret;
-
-	/*
-	 * Stop tone immediately, modem will place it in queue and play
-	 * required time.
-	 */
-	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-				CSD_CALL_INTERFACE, "StartDTMF",
-				start_dtmf_reply, NULL,
-				DBUS_TYPE_BYTE, &tone,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		telephony_transmit_dtmf_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-		return;
-	}
-
-	telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int tonegen_startevent(char tone)
-{
-	int ret;
-	dbus_uint32_t event_tone;
-	dbus_int32_t dbm0 = -15;
-	dbus_uint32_t duration = 150;
-
-	switch (tone) {
-	case '*':
-		event_tone = DTMF_ASTERISK;
-		break;
-	case '#':
-		event_tone = DTMF_HASHMARK;
-		break;
-	case 'A':
-		event_tone = DTMF_A;
-		break;
-	case 'B':
-		event_tone = DTMF_B;
-		break;
-	case 'C':
-		event_tone = DTMF_C;
-		break;
-	case 'D':
-		event_tone = DTMF_D;
-		break;
-	default:
-		ret = g_ascii_digit_value(tone);
-		if (ret < 0)
-			return -EINVAL;
-		event_tone = ret;
-	}
-
-	ret = send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
-				TONEGEN_INTERFACE, "StartEventTone",
-				NULL, NULL,
-				DBUS_TYPE_UINT32, &event_tone,
-				DBUS_TYPE_INT32, &dbm0,
-				DBUS_TYPE_UINT32, &duration,
-				DBUS_TYPE_INVALID);
-	return ret;
-}
-
-static gboolean stop_feedback_tone(gpointer user_data)
-{
-	if (g_slist_length(tones) > 0) {
-		gpointer ptone;
-		int ret;
-
-		send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
-				TONEGEN_INTERFACE, "StopTone",
-				NULL, NULL,
-				DBUS_TYPE_INVALID);
-
-		ptone = g_slist_nth_data(tones, 0);
-		tones = g_slist_remove(tones, ptone);
-
-		ret = tonegen_startevent(GPOINTER_TO_UINT(ptone));
-		if (ret < 0)
-			goto done;
-
-		return TRUE;
-	}
-done:
-	return FALSE;
-}
-
-static void tones_timer_notify(gpointer data)
-{
-	send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
-				TONEGEN_INTERFACE, "StopTone",
-				NULL, NULL,
-				DBUS_TYPE_INVALID);
-	g_slist_free(tones);
-	tones = NULL;
-
-	create_tones_timer = 0;
-}
-
-static void start_feedback_tone(char tone)
-{
-	if (!create_tones_timer) {
-		int ret;
-
-		ret = tonegen_startevent(tone);
-		if (ret < 0)
-			return;
-
-		create_tones_timer = g_timeout_add_full(G_PRIORITY_DEFAULT,
-						FEEDBACK_TONE_DURATION,
-						stop_feedback_tone,
-						NULL,
-						tones_timer_notify);
-	} else {
-		glong dtmf_tone = tone;
-
-		DBG("add %c to queue", tone);
-		tones = g_slist_append(tones, GUINT_TO_POINTER(dtmf_tone));
-	}
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
-	DBG("telephony-maemo6: transmit dtmf: %c", tone);
-
-	start_dtmf(telephony_device, tone);
-
-	if (!find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-		error("No active call");
-	else
-		start_feedback_tone(tone);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
-	DBG("telephony-maemo6: subscriber number request");
-	if (msisdn)
-		telephony_subscriber_number_ind(msisdn,
-						number_type(msisdn),
-						SUBSCRIBER_SERVICE_VOICE);
-	telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int csd_status_to_hfp(struct csd_call *call)
-{
-	switch (call->status) {
-	case CSD_CALL_STATUS_IDLE:
-	case CSD_CALL_STATUS_MO_RELEASE:
-	case CSD_CALL_STATUS_MT_RELEASE:
-	case CSD_CALL_STATUS_TERMINATED:
-		return -1;
-	case CSD_CALL_STATUS_CREATE:
-		return CALL_STATUS_DIALING;
-	case CSD_CALL_STATUS_WAITING:
-		return CALL_STATUS_WAITING;
-	case CSD_CALL_STATUS_PROCEEDING:
-		/* PROCEEDING can happen in outgoing/incoming */
-		if (call->originating)
-			return CALL_STATUS_DIALING;
-
-		/*
-		 * PROCEEDING is followed by WAITING CSD status, therefore
-		 * second incoming call status indication is set immediately
-		 * to waiting.
-		 */
-		if (g_slist_length(active_calls) > 0)
-			return CALL_STATUS_WAITING;
-
-		return CALL_STATUS_INCOMING;
-	case CSD_CALL_STATUS_COMING:
-		if (g_slist_length(active_calls) > 0)
-			return CALL_STATUS_WAITING;
-
-		return CALL_STATUS_INCOMING;
-	case CSD_CALL_STATUS_MO_ALERTING:
-		return CALL_STATUS_ALERTING;
-	case CSD_CALL_STATUS_MT_ALERTING:
-		return CALL_STATUS_INCOMING;
-	case CSD_CALL_STATUS_ANSWERED:
-	case CSD_CALL_STATUS_ACTIVE:
-	case CSD_CALL_STATUS_RECONNECT_PENDING:
-	case CSD_CALL_STATUS_SWAP_INITIATED:
-	case CSD_CALL_STATUS_HOLD_INITIATED:
-		return CALL_STATUS_ACTIVE;
-	case CSD_CALL_STATUS_RETRIEVE_INITIATED:
-	case CSD_CALL_STATUS_HOLD:
-		return CALL_STATUS_HELD;
-	default:
-		return -1;
-	}
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
-	GSList *l;
-	int i;
-
-	DBG("telephony-maemo6: list current calls request");
-
-	for (l = calls, i = 1; l != NULL; l = l->next, i++) {
-		struct csd_call *call = l->data;
-		int status, direction, multiparty;
-
-		status = csd_status_to_hfp(call);
-		if (status < 0)
-			continue;
-
-		direction = call->originating ?
-				CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
-		multiparty = call->conference ?
-				CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
-		telephony_list_current_call_ind(i, direction, status,
-						CALL_MODE_VOICE, multiparty,
-						call->number,
-						number_type(call->number));
-	}
-
-	telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
-	telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
-				net.operator_name ? net.operator_name : "");
-	telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void foreach_call_with_status(int status,
-					int (*func)(struct csd_call *call))
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct csd_call *call = l->data;
-
-		if (call->status == status)
-			func(call);
-	}
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
-	const char *idx;
-	struct csd_call *call;
-	int err = 0;
-
-	DBG("telephony-maemo6: got call hold request %s", cmd);
-
-	if (strlen(cmd) > 1)
-		idx = &cmd[1];
-	else
-		idx = NULL;
-
-	if (idx)
-		call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
-	else
-		call = NULL;
-
-	switch (cmd[0]) {
-	case '0':
-		if (find_call_with_status(CSD_CALL_STATUS_WAITING))
-			foreach_call_with_status(CSD_CALL_STATUS_WAITING,
-								release_call);
-		else
-			foreach_call_with_status(CSD_CALL_STATUS_HOLD,
-								release_call);
-		break;
-	case '1':
-		if (idx) {
-			if (call)
-				err = release_call(call);
-			break;
-		}
-		foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
-		call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-		if (call)
-			err = answer_call(call);
-		break;
-	case '2':
-		if (idx) {
-			if (call)
-				err = split_call(call);
-		} else {
-			struct csd_call *held, *wait;
-
-			call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-			held = find_call_with_status(CSD_CALL_STATUS_HOLD);
-			wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
-			if (wait)
-				err = answer_call(wait);
-			else if (call && held)
-				err = swap_calls();
-			else {
-				if (call)
-					err = hold_call(call);
-				if (held)
-					err = unhold_call(held);
-			}
-		}
-		break;
-	case '3':
-		if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
-				find_call_with_status(CSD_CALL_STATUS_WAITING))
-			err = create_conference();
-		break;
-	case '4':
-		err = call_transfer();
-		break;
-	default:
-		DBG("Unknown call hold request");
-		break;
-	}
-
-	if (err)
-		telephony_call_hold_rsp(telephony_device,
-					CME_ERROR_AG_FAILURE);
-	else
-		telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
-	DBG("telephony-maemo6: got %s NR and EC request",
-			enable ? "enable" : "disable");
-	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
-	struct csd_call *active, *waiting;
-	int err;
-
-	DBG("telephony-maemo6: got key press request for %s", keys);
-
-	waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
-	if (!waiting)
-		waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-	if (!waiting)
-		waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
-	active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-
-	if (waiting)
-		err = answer_call(waiting);
-	else if (active)
-		err = release_call(active);
-	else
-		err = 0;
-
-	if (err < 0)
-		telephony_key_press_rsp(telephony_device,
-							CME_ERROR_AG_FAILURE);
-	else
-		telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
-	DBG("telephony-maemo6: got %s voice dial request",
-			enable ? "enable" : "disable");
-
-	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static void handle_incoming_call(DBusMessage *msg)
-{
-	const char *number, *call_path;
-	struct csd_call *call;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_OBJECT_PATH, &call_path,
-					DBUS_TYPE_STRING, &number,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in Call.Coming() signal");
-		return;
-	}
-
-	call = find_call(call_path);
-	if (!call) {
-		error("Didn't find any matching call object for %s",
-				call_path);
-		return;
-	}
-
-	DBG("Incoming call to %s from number %s", call_path, number);
-
-	g_free(call->number);
-	call->number = g_strdup(number);
-
-	if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
-			find_call_with_status(CSD_CALL_STATUS_HOLD))
-		telephony_call_waiting_ind(call->number,
-						number_type(call->number));
-	else
-		telephony_incoming_call_ind(call->number,
-						number_type(call->number));
-
-	telephony_update_indicator(maemo_indicators, "callsetup",
-					EV_CALLSETUP_INCOMING);
-}
-
-static void handle_outgoing_call(DBusMessage *msg)
-{
-	const char *number, *call_path;
-	struct csd_call *call;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_OBJECT_PATH, &call_path,
-					DBUS_TYPE_STRING, &number,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in Call.Created() signal");
-		return;
-	}
-
-	call = find_call(call_path);
-	if (!call) {
-		error("Didn't find any matching call object for %s",
-				call_path);
-		return;
-	}
-
-	DBG("Outgoing call from %s to number %s", call_path, number);
-
-	g_free(call->number);
-	call->number = g_strdup(number);
-
-	if (create_request_timer) {
-		g_source_remove(create_request_timer);
-		create_request_timer = 0;
-	}
-}
-
-static gboolean create_timeout(gpointer user_data)
-{
-	telephony_update_indicator(maemo_indicators, "callsetup",
-					EV_CALLSETUP_INACTIVE);
-	create_request_timer = 0;
-	return FALSE;
-}
-
-static void handle_create_requested(DBusMessage *msg)
-{
-	DBG("Call.CreateRequested()");
-
-	if (create_request_timer)
-		g_source_remove(create_request_timer);
-
-	create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
-
-	telephony_update_indicator(maemo_indicators, "callsetup",
-					EV_CALLSETUP_OUTGOING);
-}
-
-static void call_set_status(struct csd_call *call, dbus_uint32_t status)
-{
-	dbus_uint32_t prev_status;
-	int callheld = telephony_get_indicator(maemo_indicators, "callheld");
-
-	prev_status = call->status;
-	DBG("Call %s changed from %s to %s", call->object_path,
-		call_status_str[prev_status], call_status_str[status]);
-
-	if (prev_status == status) {
-		DBG("Ignoring CSD Call state change to existing state");
-		return;
-	}
-
-	call->status = (int) status;
-
-	switch (status) {
-	case CSD_CALL_STATUS_IDLE:
-		if (call->setup) {
-			telephony_update_indicator(maemo_indicators,
-							"callsetup",
-							EV_CALLSETUP_INACTIVE);
-			if (!call->originating)
-				telephony_calling_stopped_ind();
-		}
-
-		g_free(call->number);
-		call->number = NULL;
-		call->originating = FALSE;
-		call->emergency = FALSE;
-		call->on_hold = FALSE;
-		call->conference = FALSE;
-		call->setup = FALSE;
-		break;
-	case CSD_CALL_STATUS_CREATE:
-		call->originating = TRUE;
-		call->setup = TRUE;
-		break;
-	case CSD_CALL_STATUS_COMING:
-		call->originating = FALSE;
-		call->setup = TRUE;
-		break;
-	case CSD_CALL_STATUS_PROCEEDING:
-		break;
-	case CSD_CALL_STATUS_MO_ALERTING:
-		telephony_update_indicator(maemo_indicators, "callsetup",
-						EV_CALLSETUP_ALERTING);
-		break;
-	case CSD_CALL_STATUS_MT_ALERTING:
-		/* Some headsets expect incoming call notification before they
-		 * can send ATA command. When call changed status from waiting
-		 * to alerting we need to send missing notification. Otherwise
-		 * headsets like Nokia BH-108 or BackBeat 903 are unable to
-		 * answer incoming call that was previously waiting. */
-		if (prev_status == CSD_CALL_STATUS_WAITING)
-			telephony_incoming_call_ind(call->number,
-						number_type(call->number));
-		break;
-	case CSD_CALL_STATUS_WAITING:
-		break;
-	case CSD_CALL_STATUS_ANSWERED:
-		break;
-	case CSD_CALL_STATUS_ACTIVE:
-		if (call->on_hold) {
-			call->on_hold = FALSE;
-			if (find_call_with_status(CSD_CALL_STATUS_HOLD))
-				telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_MULTIPLE);
-			else
-				telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_NONE);
-		} else {
-			if (!g_slist_find(active_calls, call))
-				active_calls = g_slist_prepend(active_calls, call);
-			if (g_slist_length(active_calls) == 1)
-				telephony_update_indicator(maemo_indicators,
-								"call",
-								EV_CALL_ACTIVE);
-			/* Upgrade callheld status if necessary */
-			if (callheld == EV_CALLHELD_ON_HOLD)
-				telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_MULTIPLE);
-			telephony_update_indicator(maemo_indicators,
-							"callsetup",
-							EV_CALLSETUP_INACTIVE);
-			if (!call->originating)
-				telephony_calling_stopped_ind();
-			call->setup = FALSE;
-		}
-		break;
-	case CSD_CALL_STATUS_MO_RELEASE:
-	case CSD_CALL_STATUS_MT_RELEASE:
-		active_calls = g_slist_remove(active_calls, call);
-		if (g_slist_length(active_calls) == 0)
-			telephony_update_indicator(maemo_indicators, "call",
-							EV_CALL_INACTIVE);
-
-		if (create_tones_timer)
-			g_source_remove(create_tones_timer);
-		break;
-	case CSD_CALL_STATUS_HOLD_INITIATED:
-		break;
-	case CSD_CALL_STATUS_HOLD:
-		call->on_hold = TRUE;
-		if (find_non_held_call())
-			telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_MULTIPLE);
-		else
-			telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_ON_HOLD);
-		break;
-	case CSD_CALL_STATUS_RETRIEVE_INITIATED:
-		break;
-	case CSD_CALL_STATUS_RECONNECT_PENDING:
-		break;
-	case CSD_CALL_STATUS_TERMINATED:
-		if (call->on_hold &&
-				!find_call_with_status(CSD_CALL_STATUS_HOLD)) {
-			telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_NONE);
-			return;
-		}
-
-		if (callheld == EV_CALLHELD_MULTIPLE &&
-				find_call_with_status(CSD_CALL_STATUS_HOLD) &&
-				!find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-			telephony_update_indicator(maemo_indicators,
-							"callheld",
-							EV_CALLHELD_ON_HOLD);
-		break;
-	case CSD_CALL_STATUS_SWAP_INITIATED:
-		break;
-	default:
-		error("Unknown call status %u", status);
-		break;
-	}
-}
-
-static void handle_call_status(DBusMessage *msg, const char *call_path)
-{
-	struct csd_call *call;
-	dbus_uint32_t status, cause_type, cause;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_UINT32, &status,
-					DBUS_TYPE_UINT32, &cause_type,
-					DBUS_TYPE_UINT32, &cause,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in Instance.CallStatus() signal");
-		return;
-	}
-
-	call = find_call(call_path);
-	if (!call) {
-		error("Didn't find any matching call object for %s",
-				call_path);
-		return;
-	}
-
-	if (status > 16) {
-		error("Invalid call status %u", status);
-		return;
-	}
-
-	call_set_status(call, status);
-}
-
-static void handle_conference(DBusMessage *msg, gboolean joined)
-{
-	const char *path;
-	struct csd_call *call;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_OBJECT_PATH, &path,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in Conference.%s",
-					dbus_message_get_member(msg));
-		return;
-	}
-
-	call = find_call(path);
-	if (!call) {
-		error("Conference signal for unknown call %s", path);
-		return;
-	}
-
-	DBG("Call %s %s the conference", path, joined ? "joined" : "left");
-
-	call->conference = joined;
-}
-
-static uint8_t str2status(const char *state)
-{
-	if (g_strcmp0(state, "Home") == 0)
-		return NETWORK_REG_STATUS_HOME;
-	else if (g_strcmp0(state, "Roaming") == 0)
-		return NETWORK_REG_STATUS_ROAMING;
-	else if (g_strcmp0(state, "Offline") == 0)
-		return NETWORK_REG_STATUS_OFFLINE;
-	else if (g_strcmp0(state, "Searching") == 0)
-		return NETWORK_REG_STATUS_SEARCHING;
-	else if (g_strcmp0(state, "NoSim") == 0)
-		return NETWORK_REG_STATUS_NO_SIM;
-	else if (g_strcmp0(state, "Poweroff") == 0)
-		return NETWORK_REG_STATUS_POWEROFF;
-	else if (g_strcmp0(state, "Powersafe") == 0)
-		return NETWORK_REG_STATUS_POWERSAFE;
-	else if (g_strcmp0(state, "NoCoverage") == 0)
-		return NETWORK_REG_STATUS_NO_COVERAGE;
-	else if (g_strcmp0(state, "Reject") == 0)
-		return NETWORK_REG_STATUS_REJECTED;
-	else
-		return NETWORK_REG_STATUS_UNKOWN;
-}
-
-static void update_registration_status(const char *status)
-{
-	uint8_t new_status;
-
-	new_status = str2status(status);
-
-	if (net.status == new_status)
-		return;
-
-	switch (new_status) {
-	case NETWORK_REG_STATUS_HOME:
-		telephony_update_indicator(maemo_indicators, "roam",
-							EV_ROAM_INACTIVE);
-		if (net.status > NETWORK_REG_STATUS_ROAMING)
-			telephony_update_indicator(maemo_indicators,
-							"service",
-							EV_SERVICE_PRESENT);
-		break;
-	case NETWORK_REG_STATUS_ROAMING:
-		telephony_update_indicator(maemo_indicators, "roam",
-							EV_ROAM_ACTIVE);
-		if (net.status > NETWORK_REG_STATUS_ROAMING)
-			telephony_update_indicator(maemo_indicators,
-							"service",
-							EV_SERVICE_PRESENT);
-		break;
-	case NETWORK_REG_STATUS_OFFLINE:
-	case NETWORK_REG_STATUS_SEARCHING:
-	case NETWORK_REG_STATUS_NO_SIM:
-	case NETWORK_REG_STATUS_POWEROFF:
-	case NETWORK_REG_STATUS_POWERSAFE:
-	case NETWORK_REG_STATUS_NO_COVERAGE:
-	case NETWORK_REG_STATUS_REJECTED:
-	case NETWORK_REG_STATUS_UNKOWN:
-		if (net.status < NETWORK_REG_STATUS_OFFLINE)
-			telephony_update_indicator(maemo_indicators,
-							"service",
-							EV_SERVICE_NONE);
-		break;
-	}
-
-	net.status = new_status;
-
-	DBG("telephony-maemo6: registration status changed: %s", status);
-}
-
-static void handle_registration_changed(DBusMessage *msg)
-{
-	const char *status;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_STRING, &status,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in RegistrationChanged");
-		return;
-	}
-
-	update_registration_status(status);
-}
-
-static void update_signal_strength(int32_t signal_bars)
-{
-	if (signal_bars < 0) {
-		DBG("signal strength smaller than expected: %d < 0",
-								signal_bars);
-		signal_bars = 0;
-	} else if (signal_bars > 5) {
-		DBG("signal strength greater than expected: %d > 5",
-								signal_bars);
-		signal_bars = 5;
-	}
-
-	if (net.signal_bars == signal_bars)
-		return;
-
-	telephony_update_indicator(maemo_indicators, "signal", signal_bars);
-
-	net.signal_bars = signal_bars;
-	DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
-}
-
-static void handle_signal_bars_changed(DBusMessage *msg)
-{
-	int32_t signal_bars;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_INT32, &signal_bars,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in SignalBarsChanged");
-		return;
-	}
-
-	update_signal_strength(signal_bars);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
-					int first_arg_type, ...)
-{
-	int type;
-	va_list ap;
-
-	va_start(ap, first_arg_type);
-
-	for (type = first_arg_type; type != DBUS_TYPE_INVALID;
-			type = va_arg(ap, int)) {
-		void *value = va_arg(ap, void *);
-		int real_type = dbus_message_iter_get_arg_type(iter);
-
-		if (real_type != type) {
-			error("iter_get_basic_args: expected %c but got %c",
-					(char) type, (char) real_type);
-			break;
-		}
-
-		dbus_message_iter_get_basic(iter, value);
-		dbus_message_iter_next(iter);
-	}
-
-	va_end(ap);
-
-	return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	dbus_int32_t level;
-	int *value = user_data;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("hald replied with an error: %s, %s",
-				err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	if (!dbus_message_get_args(reply, NULL,
-				DBUS_TYPE_INT32, &level,
-				DBUS_TYPE_INVALID)) {
-		error("Unexpected args in hald reply");
-		goto done;
-	}
-
-	*value = (int) level;
-
-	if (value == &battchg_last)
-		DBG("telephony-maemo6: battery.charge_level.last_full is %d",
-				*value);
-	else if (value == &battchg_design)
-		DBG("telephony-maemo6: battery.charge_level.design is %d",
-				*value);
-	else
-		DBG("telephony-maemo6: battery.charge_level.current is %d",
-				*value);
-
-	if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
-		int new, max;
-
-		if (battchg_last > 0)
-			max = battchg_last;
-		else
-			max = battchg_design;
-
-		new = battchg_cur * 5 / max;
-
-		telephony_update_indicator(maemo_indicators, "battchg", new);
-	}
-
-done:
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
-	send_method_call("org.freedesktop.Hal", path,
-				"org.freedesktop.Hal.Device",
-				"GetPropertyInteger",
-				hal_battery_level_reply, user_data,
-				DBUS_TYPE_STRING, &key,
-				DBUS_TYPE_INVALID);
-}
-
-static void handle_hal_property_modified(DBusMessage *msg)
-{
-	DBusMessageIter iter, array;
-	dbus_int32_t num_changes;
-	const char *path;
-
-	path = dbus_message_get_path(msg);
-
-	dbus_message_iter_init(msg, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
-		error("Unexpected signature in hal PropertyModified signal");
-		return;
-	}
-
-	dbus_message_iter_get_basic(&iter, &num_changes);
-	dbus_message_iter_next(&iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in hal PropertyModified signal");
-		return;
-	}
-
-	dbus_message_iter_recurse(&iter, &array);
-
-	while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-		DBusMessageIter prop;
-		const char *name;
-		dbus_bool_t added, removed;
-
-		dbus_message_iter_recurse(&array, &prop);
-
-		if (!iter_get_basic_args(&prop,
-					DBUS_TYPE_STRING, &name,
-					DBUS_TYPE_BOOLEAN, &added,
-					DBUS_TYPE_BOOLEAN, &removed,
-					DBUS_TYPE_INVALID)) {
-			error("Invalid hal PropertyModified parameters");
-			break;
-		}
-
-		if (g_str_equal(name, "battery.charge_level.last_full"))
-			hal_get_integer(path, name, &battchg_last);
-		else if (g_str_equal(name, "battery.charge_level.current"))
-			hal_get_integer(path, name, &battchg_cur);
-		else if (g_str_equal(name, "battery.charge_level.design"))
-			hal_get_integer(path, name, &battchg_design);
-
-		dbus_message_iter_next(&array);
-	}
-}
-
-static void csd_call_free(void *data)
-{
-	struct csd_call *call = data;
-
-	if (!call)
-		return;
-
-	g_free(call->object_path);
-	g_free(call->number);
-
-	g_slist_foreach(pending, remove_pending_by_data, call);
-
-	g_free(call);
-}
-
-static void parse_call_list(DBusMessageIter *iter)
-{
-	do {
-		DBusMessageIter call_iter;
-		struct csd_call *call;
-		const char *object_path, *number;
-		dbus_uint32_t status;
-		dbus_bool_t originating, terminating, emerg, on_hold, conf;
-
-		if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
-			error("Unexpected signature in GetCallInfoAll reply");
-			break;
-		}
-
-		dbus_message_iter_recurse(iter, &call_iter);
-
-		if (!iter_get_basic_args(&call_iter,
-					DBUS_TYPE_OBJECT_PATH, &object_path,
-					DBUS_TYPE_UINT32, &status,
-					DBUS_TYPE_BOOLEAN, &originating,
-					DBUS_TYPE_BOOLEAN, &terminating,
-					DBUS_TYPE_BOOLEAN, &emerg,
-					DBUS_TYPE_BOOLEAN, &on_hold,
-					DBUS_TYPE_BOOLEAN, &conf,
-					DBUS_TYPE_STRING, &number,
-					DBUS_TYPE_INVALID)) {
-			error("Parsing call D-Bus parameters failed");
-			break;
-		}
-
-		call = find_call(object_path);
-		if (!call) {
-			call = g_new0(struct csd_call, 1);
-			call->object_path = g_strdup(object_path);
-			calls = g_slist_append(calls, call);
-			DBG("telephony-maemo6: new csd call instance at %s",
-								object_path);
-		}
-
-		if (status == CSD_CALL_STATUS_IDLE)
-			continue;
-
-		/* CSD gives incorrect call_hold property sometimes */
-		if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
-				(call->status == CSD_CALL_STATUS_HOLD &&
-								!on_hold)) {
-			error("Conflicting call status and on_hold property!");
-			on_hold = call->status == CSD_CALL_STATUS_HOLD;
-		}
-
-		call->originating = originating;
-		call->on_hold = on_hold;
-		call->conference = conf;
-		g_free(call->number);
-		call->number = g_strdup(number);
-
-		/* Update indicators */
-		call_set_status(call, status);
-
-	} while (dbus_message_iter_next(iter));
-}
-
-static void update_operator_name(const char *name)
-{
-	if (name == NULL)
-		return;
-
-	g_free(net.operator_name);
-	net.operator_name = g_strndup(name, 16);
-	DBG("telephony-maemo6: operator name updated: %s", name);
-}
-
-static void get_property_reply(DBusPendingCall *call, void *user_data)
-{
-	char *prop = user_data;
-	DBusError err;
-	DBusMessage *reply;
-	DBusMessageIter iter, sub;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("csd 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_VARIANT) {
-		error("Unexpected signature in Get return");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &sub);
-
-	if (g_strcmp0(prop, "RegistrationStatus") == 0) {
-		const char *status;
-
-		dbus_message_iter_get_basic(&sub, &status);
-		update_registration_status(status);
-
-		get_property(CSD_CSNET_OPERATOR, "OperatorName");
-		get_property(CSD_CSNET_SIGNAL, "SignalBars");
-	} else if (g_strcmp0(prop, "OperatorName") == 0) {
-		const char *name;
-
-		dbus_message_iter_get_basic(&sub, &name);
-		update_operator_name(name);
-	} else if (g_strcmp0(prop, "SignalBars") == 0) {
-		int32_t signal_bars;
-
-		dbus_message_iter_get_basic(&sub, &signal_bars);
-		update_signal_strength(signal_bars);
-	}
-
-done:
-	g_free(prop);
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-static int get_property(const char *iface, const char *prop)
-{
-	return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH,
-				DBUS_INTERFACE_PROPERTIES, "Get",
-				get_property_reply, g_strdup(prop),
-				DBUS_TYPE_STRING, &iface,
-				DBUS_TYPE_STRING, &prop,
-				DBUS_TYPE_INVALID);
-}
-
-static void handle_operator_name_changed(DBusMessage *msg)
-{
-	const char *name;
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_STRING, &name,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in OperatorNameChanged");
-		return;
-	}
-
-	update_operator_name(name);
-}
-
-static void call_info_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	DBusMessageIter iter, sub;
-
-	get_calls_active = FALSE;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("csd 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 in GetCallInfoAll return");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &sub);
-
-	parse_call_list(&sub);
-
-	get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
-
-done:
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-
-static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError derr;
-	DBusMessage *reply;
-	const char *name, *number, *secondname, *additionalnumber, *email;
-	int index;
-	char **number_type = user_data;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		error("%s.ReadFirst replied with an error: %s, %s",
-				CSD_SIMPB_INTERFACE, derr.name, derr.message);
-		dbus_error_free(&derr);
-		if (number_type == &vmbx)
-			vmbx = g_strdup(getenv("VMBX_NUMBER"));
-		goto done;
-	}
-
-	dbus_error_init(&derr);
-	if (dbus_message_get_args(reply, NULL,
-				DBUS_TYPE_INT32, &index,
-				DBUS_TYPE_STRING, &name,
-				DBUS_TYPE_STRING, &number,
-				DBUS_TYPE_STRING, &secondname,
-				DBUS_TYPE_STRING, &additionalnumber,
-				DBUS_TYPE_STRING, &email,
-				DBUS_TYPE_INVALID) == FALSE) {
-		error("Unable to parse %s.ReadFirst arguments: %s, %s",
-				CSD_SIMPB_INTERFACE, derr.name, derr.message);
-		dbus_error_free(&derr);
-		goto done;
-	}
-
-	if (number_type == &msisdn) {
-		g_free(msisdn);
-		msisdn = g_strdup(number);
-		DBG("Got MSISDN %s (%s)", number, name);
-	} else {
-		g_free(vmbx);
-		vmbx = g_strdup(number);
-		DBG("Got voice mailbox number %s (%s)", number, name);
-	}
-
-done:
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-static void csd_init(void)
-{
-	const char *pb_type;
-	int ret;
-
-	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-				CSD_CALL_INTERFACE, "GetCallInfoAll",
-				call_info_reply, NULL, DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		error("Unable to sent GetCallInfoAll method call");
-		return;
-	}
-
-	get_calls_active = TRUE;
-
-	pb_type = CSD_SIMPB_TYPE_MSISDN;
-
-	ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
-				CSD_SIMPB_INTERFACE, "ReadFirst",
-				phonebook_read_reply, &msisdn,
-				DBUS_TYPE_STRING, &pb_type,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
-		return;
-	}
-
-	/* Voicemail should be in MBDN index 0 */
-	pb_type = CSD_SIMPB_TYPE_MBDN;
-
-	ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
-				CSD_SIMPB_INTERFACE, "ReadFirst",
-				phonebook_read_reply, &vmbx,
-				DBUS_TYPE_STRING, &pb_type,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
-		return;
-	}
-}
-
-static void handle_modem_state(DBusMessage *msg)
-{
-	const char *state;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
-							DBUS_TYPE_INVALID)) {
-		error("Unexpected modem state parameters");
-		return;
-	}
-
-	DBG("SSC modem state: %s", state);
-
-	if (calls != NULL || get_calls_active)
-		return;
-
-	if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
-		csd_init();
-}
-
-static void modem_state_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	DBusError err;
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("get_modem_state: %s, %s", err.name, err.message);
-		dbus_error_free(&err);
-	} else
-		handle_modem_state(reply);
-
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
-								void *data)
-{
-	const char *path = dbus_message_get_path(msg);
-
-	if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
-		handle_incoming_call(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
-		handle_outgoing_call(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
-							"CreateRequested"))
-		handle_create_requested(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
-		handle_call_status(msg, path);
-	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
-		handle_conference(msg, TRUE);
-	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
-		handle_conference(msg, FALSE);
-	else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
-				"RegistrationChanged"))
-		handle_registration_changed(msg);
-	else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
-				"OperatorNameChanged"))
-		handle_operator_name_changed(msg);
-	else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
-				"SignalBarsChanged"))
-		handle_signal_bars_changed(msg);
-	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
-					"PropertyModified"))
-		handle_hal_property_modified(msg);
-	else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
-						"modem_state_changed_ind"))
-		handle_modem_state(msg);
-
-	return TRUE;
-}
-
-static void add_watch(const char *sender, const char *path,
-				const char *interface, const char *member)
-{
-	guint watch;
-
-	watch = g_dbus_add_signal_watch(connection, sender, path, interface,
-					member, signal_filter, NULL, NULL);
-
-	watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	DBusMessageIter iter, sub;
-	const char *path;
-	int type;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("hald 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 in FindDeviceByCapability return");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &sub);
-
-	type = dbus_message_iter_get_arg_type(&sub);
-
-	if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
-		error("No hal device with battery capability found");
-		goto done;
-	}
-
-	dbus_message_iter_get_basic(&sub, &path);
-
-	DBG("telephony-maemo6: found battery device at %s", path);
-
-	add_watch(NULL, path, "org.freedesktop.Hal.Device",
-							"PropertyModified");
-
-	hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
-	hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
-	hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-
-done:
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-int telephony_init(void)
-{
-	const char *battery_cap = "battery";
-	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
-				AG_FEATURE_INBAND_RINGTONE |
-				AG_FEATURE_REJECT_A_CALL |
-				AG_FEATURE_ENHANCED_CALL_STATUS |
-				AG_FEATURE_ENHANCED_CALL_CONTROL |
-				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
-				AG_FEATURE_THREE_WAY_CALLING;
-	int i;
-
-	DBG("");
-
-	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
-	add_watch(NULL, NULL, CSD_CALL_INTERFACE, NULL);
-	add_watch(NULL, NULL, CSD_CALL_INSTANCE, NULL);
-	add_watch(NULL, NULL, CSD_CALL_CONFERENCE, NULL);
-	add_watch(NULL, NULL, CSD_CSNET_REGISTRATION, "RegistrationChanged");
-	add_watch(NULL, NULL, CSD_CSNET_OPERATOR, "OperatorNameChanged");
-	add_watch(NULL, NULL, CSD_CSNET_SIGNAL, "SignalBarsChanged");
-	add_watch(NULL, NULL, SSC_DBUS_IFACE, "modem_state_changed_ind");
-
-	if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
-					"get_modem_state", modem_state_reply,
-					NULL, DBUS_TYPE_INVALID) < 0)
-		error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
-
-	/* Reset indicators */
-	for (i = 0; maemo_indicators[i].desc != NULL; i++) {
-		if (g_str_equal(maemo_indicators[i].desc, "battchg"))
-			maemo_indicators[i].val = 5;
-		else
-			maemo_indicators[i].val = 0;
-	}
-
-	telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
-								chld_str);
-	if (send_method_call("org.freedesktop.Hal",
-				"/org/freedesktop/Hal/Manager",
-				"org.freedesktop.Hal.Manager",
-				"FindDeviceByCapability",
-				hal_find_device_reply, NULL,
-				DBUS_TYPE_STRING, &battery_cap,
-				DBUS_TYPE_INVALID) < 0)
-		error("Unable to send HAL method call");
-
-	return 0;
-}
-
-static void remove_watch(gpointer data)
-{
-	g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
-}
-
-void telephony_exit(void)
-{
-	DBG("");
-
-	g_free(net.operator_name);
-	net.operator_name = NULL;
-
-	net.status = NETWORK_REG_STATUS_UNKOWN;
-	net.signal_bars = 0;
-
-	g_slist_free(active_calls);
-	active_calls = NULL;
-
-	g_slist_free_full(calls, csd_call_free);
-	calls = NULL;
-
-	g_slist_free_full(pending, pending_req_finalize);
-	pending = NULL;
-
-	g_slist_free_full(watches, remove_watch);
-	watches = NULL;
-
-	dbus_connection_unref(connection);
-	connection = NULL;
-
-	telephony_deinit();
-}
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 08/15] audio: Remove oFono telephony driver
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (6 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 07/15] audio: Remove maemo6 " Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 09/15] audio: Move HFP/HSP AG servers to telephony.c Frédéric Danis
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Remove oFono telephony driver which has been deprecated by
org.bluez.Telephony interface.
---
 audio/telephony-ofono.c | 1637 -----------------------------------------------
 1 file changed, 1637 deletions(-)
 delete mode 100644 audio/telephony-ofono.c

diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
deleted file mode 100644
index 961fedd..0000000
--- a/audio/telephony-ofono.c
+++ /dev/null
@@ -1,1637 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2009-2010  Intel Corporation
- *  Copyright (C) 2006-2009  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include <bluetooth/sdp.h>
-
-#include "log.h"
-#include "telephony.h"
-
-enum net_registration_status {
-	NETWORK_REG_STATUS_HOME = 0x00,
-	NETWORK_REG_STATUS_ROAM,
-	NETWORK_REG_STATUS_NOSERV
-};
-
-struct voice_call {
-	char *obj_path;
-	int status;
-	gboolean originating;
-	gboolean conference;
-	char *number;
-	guint watch;
-};
-
-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"
-#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"
-#define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1;    /* "battery.charge_level.current" */
-static int battchg_last = -1;   /* "battery.charge_level.last_full" */
-static int battchg_design = -1; /* "battery.charge_level.design" */
-
-static struct {
-	uint8_t status;
-	uint32_t signals_bar;
-	char *operator_name;
-} net = {
-	.status = NETWORK_REG_STATUS_NOSERV,
-	.signals_bar = 0,
-	.operator_name = NULL,
-};
-
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-static char *subscriber_number = NULL;
-
-static gboolean events_enabled = FALSE;
-
-static struct indicator ofono_indicators[] =
-{
-	{ "battchg",	"0-5",	5,	TRUE },
-	{ "signal",	"0-5",	5,	TRUE },
-	{ "service",	"0,1",	1,	TRUE },
-	{ "call",	"0,1",	0,	TRUE },
-	{ "callsetup",	"0-3",	0,	TRUE },
-	{ "callheld",	"0-2",	0,	FALSE },
-	{ "roam",	"0,1",	0,	TRUE },
-	{ NULL }
-};
-
-static struct voice_call *find_vc(const char *path)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct voice_call *vc = l->data;
-
-		if (g_str_equal(vc->obj_path, path))
-			return vc;
-	}
-
-	return NULL;
-}
-
-static struct voice_call *find_vc_with_status(int status)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct voice_call *vc = l->data;
-
-		if (vc->status == status)
-			return vc;
-	}
-
-	return NULL;
-}
-
-static struct voice_call *find_vc_without_status(int status)
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct voice_call *call = l->data;
-
-		if (call->status != status)
-			return call;
-	}
-
-	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)
-{
-	DBG("telephony-ofono: device %p disconnected", telephony_device);
-	events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
-	events_enabled = ind == 1 ? TRUE : FALSE;
-
-	telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
-	telephony_response_and_hold_rsp(telephony_device,
-						CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
-	DBG("telephony-ofono: last dialed number request");
-
-	if (last_dialed_number)
-		telephony_dial_number_req(telephony_device, last_dialed_number);
-	else
-		telephony_last_dialed_number_rsp(telephony_device,
-				CME_ERROR_NOT_ALLOWED);
-}
-
-static int send_method_call(const char *dest, const char *path,
-                                const char *interface, const char *method,
-                                DBusPendingCallNotifyFunction cb,
-                                void *user_data, int type, ...)
-{
-	DBusMessage *msg;
-	DBusPendingCall *call;
-	va_list args;
-
-	msg = dbus_message_new_method_call(dest, path, interface, method);
-	if (!msg) {
-		error("Unable to allocate new D-Bus %s message", method);
-		return -ENOMEM;
-	}
-
-	va_start(args, type);
-
-	if (!dbus_message_append_args_valist(msg, type, args)) {
-		dbus_message_unref(msg);
-		va_end(args);
-		return -EIO;
-	}
-
-	va_end(args);
-
-	if (!cb) {
-		g_dbus_send_message(connection, msg);
-		return 0;
-	}
-
-	if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
-		error("Sending %s failed", method);
-		dbus_message_unref(msg);
-		return -EIO;
-	}
-
-	dbus_pending_call_set_notify(call, cb, user_data, NULL);
-	pending = g_slist_prepend(pending, call);
-	dbus_message_unref(msg);
-
-	return 0;
-}
-
-static int answer_call(struct voice_call *vc)
-{
-	DBG("%s", vc->number);
-	return send_method_call(OFONO_BUS_NAME, vc->obj_path,
-						OFONO_VC_INTERFACE, "Answer",
-						NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_call(struct voice_call *vc)
-{
-	DBG("%s", vc->number);
-	return send_method_call(OFONO_BUS_NAME, vc->obj_path,
-						OFONO_VC_INTERFACE, "Hangup",
-						NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_answer_calls(void)
-{
-	DBG("");
-	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-						OFONO_VCMANAGER_INTERFACE,
-						"ReleaseAndAnswer",
-						NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int split_call(struct voice_call *call)
-{
-	DBG("%s", call->number);
-	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-						OFONO_VCMANAGER_INTERFACE,
-						"PrivateChat",
-						NULL, NULL,
-						DBUS_TYPE_OBJECT_PATH,
-						call->obj_path,
-						DBUS_TYPE_INVALID);
-	return -1;
-}
-
-static int swap_calls(void)
-{
-	DBG("");
-	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-						OFONO_VCMANAGER_INTERFACE,
-						"SwapCalls",
-						NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int create_conference(void)
-{
-	DBG("");
-	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-						OFONO_VCMANAGER_INTERFACE,
-						"CreateMultiparty",
-						NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_conference(void)
-{
-	DBG("");
-	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-						OFONO_VCMANAGER_INTERFACE,
-						"HangupMultiparty",
-						NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int call_transfer(void)
-{
-	DBG("");
-	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-						OFONO_VCMANAGER_INTERFACE,
-						"Transfer",
-						NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
-	struct voice_call *call;
-	struct voice_call *alerting;
-	int err;
-
-	call = find_vc_with_status(CALL_STATUS_ACTIVE);
-	if (!call)
-		call = calls->data;
-
-	if (!call) {
-		error("No active call");
-		telephony_terminate_call_rsp(telephony_device,
-						CME_ERROR_NOT_ALLOWED);
-		return;
-	}
-
-	alerting = find_vc_with_status(CALL_STATUS_ALERTING);
-	if (call->status == CALL_STATUS_HELD && alerting)
-		err = release_call(alerting);
-	else if (call->conference)
-		err = release_conference();
-	else
-		err = release_call(call);
-
-	if (err < 0)
-		telephony_terminate_call_rsp(telephony_device,
-						CME_ERROR_AG_FAILURE);
-	else
-		telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
-	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);
-		return;
-	}
-
-	ret = answer_call(vc);
-	if (ret < 0) {
-		telephony_answer_call_rsp(telephony_device,
-					CME_ERROR_AG_FAILURE);
-		return;
-	}
-
-	telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
-	const char *clir;
-	int ret;
-
-	DBG("telephony-ofono: dial request to %s", number);
-
-	if (!modem_obj_path) {
-		telephony_dial_number_rsp(telephony_device,
-					CME_ERROR_AG_FAILURE);
-		return;
-	}
-
-	if (!strncmp(number, "*31#", 4)) {
-		number += 4;
-		clir = "enabled";
-	} else if (!strncmp(number, "#31#", 4)) {
-		number += 4;
-		clir =  "disabled";
-	} else
-		clir = "default";
-
-	ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
-			OFONO_VCMANAGER_INTERFACE,
-                        "Dial", NULL, NULL,
-			DBUS_TYPE_STRING, &number,
-			DBUS_TYPE_STRING, &clir,
-			DBUS_TYPE_INVALID);
-
-	if (ret < 0)
-		telephony_dial_number_rsp(telephony_device,
-			CME_ERROR_AG_FAILURE);
-	else
-		telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
-	char *tone_string;
-	int ret;
-
-	DBG("telephony-ofono: transmit dtmf: %c", tone);
-
-	if (!modem_obj_path) {
-		telephony_transmit_dtmf_rsp(telephony_device,
-					CME_ERROR_AG_FAILURE);
-		return;
-	}
-
-	tone_string = g_strdup_printf("%c", tone);
-	ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
-			OFONO_VCMANAGER_INTERFACE,
-			"SendTones", NULL, NULL,
-			DBUS_TYPE_STRING, &tone_string,
-			DBUS_TYPE_INVALID);
-	g_free(tone_string);
-
-	if (ret < 0)
-		telephony_transmit_dtmf_rsp(telephony_device,
-			CME_ERROR_AG_FAILURE);
-	else
-		telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
-	DBG("telephony-ofono: subscriber number request");
-
-	if (subscriber_number)
-		telephony_subscriber_number_ind(subscriber_number,
-						NUMBER_TYPE_TELEPHONY,
-						SUBSCRIBER_SERVICE_VOICE);
-	telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
-	GSList *l;
-	int i;
-
-	DBG("telephony-ofono: list current calls request");
-
-	for (l = calls, i = 1; l != NULL; l = l->next, i++) {
-		struct voice_call *vc = l->data;
-		int direction, multiparty;
-
-		direction = vc->originating ?
-				CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
-		multiparty = vc->conference ?
-				CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
-		DBG("call %s direction %d multiparty %d", vc->number,
-							direction, multiparty);
-
-		telephony_list_current_call_ind(i, direction, vc->status,
-					CALL_MODE_VOICE, multiparty,
-					vc->number, number_type(vc->number));
-	}
-
-	telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
-	DBG("telephony-ofono: operator selection request");
-
-	telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
-				net.operator_name ? net.operator_name : "");
-	telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void foreach_vc_with_status(int status,
-					int (*func)(struct voice_call *vc))
-{
-	GSList *l;
-
-	for (l = calls; l != NULL; l = l->next) {
-		struct voice_call *call = l->data;
-
-		if (call->status == status)
-			func(call);
-	}
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
-	const char *idx;
-	struct voice_call *call;
-	int err = 0;
-
-	DBG("telephony-ofono: got call hold request %s", cmd);
-
-	if (strlen(cmd) > 1)
-		idx = &cmd[1];
-	else
-		idx = NULL;
-
-	if (idx)
-		call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
-	else
-		call = NULL;
-
-	switch (cmd[0]) {
-	case '0':
-		if (find_vc_with_status(CALL_STATUS_WAITING))
-			foreach_vc_with_status(CALL_STATUS_WAITING,
-								release_call);
-		else
-			foreach_vc_with_status(CALL_STATUS_HELD, release_call);
-		break;
-	case '1':
-		if (idx) {
-			if (call)
-				err = release_call(call);
-			break;
-		}
-		err = release_answer_calls();
-		break;
-	case '2':
-		if (idx) {
-			if (call)
-				err = split_call(call);
-		} else {
-			call = find_vc_with_status(CALL_STATUS_WAITING);
-
-			if (call)
-				err = answer_call(call);
-			else
-				err = swap_calls();
-		}
-		break;
-	case '3':
-		if (find_vc_with_status(CALL_STATUS_HELD) ||
-				find_vc_with_status(CALL_STATUS_WAITING))
-			err = create_conference();
-		break;
-	case '4':
-		err = call_transfer();
-		break;
-	default:
-		DBG("Unknown call hold request");
-		break;
-	}
-
-	if (err)
-		telephony_call_hold_rsp(telephony_device,
-					CME_ERROR_AG_FAILURE);
-	else
-		telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
-	DBG("telephony-ofono: got %s NR and EC request",
-			enable ? "enable" : "disable");
-
-	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
-	struct voice_call *active, *incoming;
-	int err;
-
-	DBG("telephony-ofono: got key press request for %s", keys);
-
-	incoming = find_vc_with_status(CALL_STATUS_INCOMING);
-
-	active = find_vc_with_status(CALL_STATUS_ACTIVE);
-
-	if (incoming)
-		err = answer_call(incoming);
-	else if (active)
-		err = release_call(active);
-	else
-		err = 0;
-
-	if (err < 0)
-		telephony_key_press_rsp(telephony_device,
-							CME_ERROR_AG_FAILURE);
-	else
-		telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
-	DBG("telephony-ofono: got %s voice dial request",
-			enable ? "enable" : "disable");
-
-	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
-					int first_arg_type, ...)
-{
-	int type;
-	va_list ap;
-
-	va_start(ap, first_arg_type);
-
-	for (type = first_arg_type; type != DBUS_TYPE_INVALID;
-		type = va_arg(ap, int)) {
-		void *value = va_arg(ap, void *);
-		int real_type = dbus_message_iter_get_arg_type(iter);
-
-		if (real_type != type) {
-			error("iter_get_basic_args: expected %c but got %c",
-				(char) type, (char) real_type);
-			break;
-		}
-
-		dbus_message_iter_get_basic(iter, value);
-		dbus_message_iter_next(iter);
-	}
-
-	va_end(ap);
-
-	return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void call_free(void *data)
-{
-	struct voice_call *vc = data;
-
-	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);
-	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")) {
-			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;
-		} else if (g_str_equal(state, "held")) {
-			vc->status = CALL_STATUS_HELD;
-			if (find_vc_without_status(CALL_STATUS_HELD))
-				telephony_update_indicator(ofono_indicators,
-							"callheld",
-							EV_CALLHELD_MULTIPLE);
-			else
-				telephony_update_indicator(ofono_indicators,
-							"callheld",
-							EV_CALLHELD_ON_HOLD);
-		}
-	} else if (g_str_equal(property, "Multiparty")) {
-		dbus_bool_t multiparty;
-
-		dbus_message_iter_get_basic(&sub, &multiparty);
-		DBG("Multiparty %s", multiparty ? "True" : "False");
-		vc->conference = multiparty;
-	}
-
-	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_bool_t multiparty;
-
-		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;
-			else if (g_str_equal(state, "held"))
-				vc->status = CALL_STATUS_HELD;
-		} else if (g_str_equal(property, "Multiparty")) {
-			dbus_message_iter_get_basic(&value, &multiparty);
-			DBG("Multipary %s", multiparty ? "True" : "False");
-			vc->conference = multiparty;
-		}
-
-		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 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;
-
-	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);
-	remove_pending(call);
-}
-
-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(variant, &status);
-		DBG("Status is %s", status);
-		if (g_str_equal(status, "registered")) {
-			net.status = NETWORK_REG_STATUS_HOME;
-			telephony_update_indicator(ofono_indicators,
-						"roam", EV_ROAM_INACTIVE);
-			telephony_update_indicator(ofono_indicators,
-						"service", EV_SERVICE_PRESENT);
-		} else if (g_str_equal(status, "roaming")) {
-			net.status = NETWORK_REG_STATUS_ROAM;
-			telephony_update_indicator(ofono_indicators,
-						"roam", EV_ROAM_ACTIVE);
-			telephony_update_indicator(ofono_indicators,
-						"service", EV_SERVICE_PRESENT);
-		} else {
-			net.status = NETWORK_REG_STATUS_NOSERV;
-			telephony_update_indicator(ofono_indicators,
-						"roam", EV_ROAM_INACTIVE);
-			telephony_update_indicator(ofono_indicators,
-						"service", EV_SERVICE_NONE);
-		}
-	} 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(variant, &signals_bar);
-		DBG("SignalStrength is %d", signals_bar);
-		net.signals_bar = signals_bar;
-		telephony_update_indicator(ofono_indicators, "signal",
-						(signals_bar + 20) / 21);
-	}
-}
-
-static int parse_network_properties(DBusMessageIter *properties)
-{
-	int i;
-
-	/* Reset indicators */
-	for (i = 0; ofono_indicators[i].desc != NULL; i++) {
-		if (g_str_equal(ofono_indicators[i].desc, "battchg"))
-			ofono_indicators[i].val = 5;
-		else
-			ofono_indicators[i].val = 0;
-	}
-
-	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);
-	}
-
-	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);
-	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, &properties);
-
-	ret = parse_network_properties(&properties);
-	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);
-	remove_pending(call);
-}
-
-static void network_found(const char *path)
-{
-	int ret;
-
-	DBG("%s", path);
-
-	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 modem_removed(const char *path)
-{
-	if (g_strcmp0(modem_obj_path, path) != 0)
-		return;
-
-	DBG("%s", path);
-
-	g_slist_free_full(calls, call_free);
-	calls = NULL;
-
-	g_free(net.operator_name);
-	net.operator_name = NULL;
-	net.status = NETWORK_REG_STATUS_NOSERV;
-	net.signals_bar = 0;
-
-	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;
-
-	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;
-	}
-
-	/* 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) {
-		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 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);
-
-		modem_added(path, &properties);
-		if (modem_obj_path != NULL)
-			break;
-
-		dbus_message_iter_next(&entry);
-	}
-
-done:
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-static gboolean handle_network_property_changed(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	DBusMessageIter iter, variant;
-	const char *property;
-
-	dbus_message_iter_init(msg, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
-		error("Unexpected signature in networkregistration"
-					" PropertyChanged signal");
-		return TRUE;
-	}
-	dbus_message_iter_get_basic(&iter, &property);
-	DBG("in handle_registration_property_changed(),"
-					" the property is %s", property);
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &variant);
-
-	handle_network_property(property, &variant);
-
-	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)
-{
-	DBusMessageIter iter, properties;
-	const char *path = dbus_message_get_path(msg);
-
-	/* Ignore call if modem path doesn't math */
-	if (g_strcmp0(modem_obj_path, path) != 0)
-		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_next(&iter);
-	dbus_message_iter_recurse(&iter, &properties);
-
-	call_added(path, &properties);
-
-	return TRUE;
-}
-
-static void call_removed(const char *path)
-{
-	struct voice_call *vc;
-
-	DBG("%s", path);
-
-	vc = find_vc(path);
-	if (vc == NULL)
-		return;
-
-	calls = g_slist_remove(calls, vc);
-	call_free(vc);
-}
-
-static gboolean handle_vcmanager_call_removed(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	const char *path = dbus_message_get_path(msg);
-
-	/* Ignore call if modem path doesn't math */
-	if (g_strcmp0(modem_obj_path, path) != 0)
-		return TRUE;
-
-	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;
-	}
-
-	call_removed(path);
-
-	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_next(&iter);
-	dbus_message_iter_recurse(&iter, &properties);
-
-	modem_added(path, &properties);
-
-	return TRUE;
-}
-
-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;
-	DBusError err;
-	dbus_int32_t level;
-	int *value = user_data;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("hald replied with an error: %s, %s",
-				err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	dbus_error_init(&err);
-	if (dbus_message_get_args(reply, &err,
-				DBUS_TYPE_INT32, &level,
-				DBUS_TYPE_INVALID) == FALSE) {
-		error("Unable to parse GetPropertyInteger reply: %s, %s",
-							err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	*value = (int) level;
-
-	if (value == &battchg_last)
-		DBG("telephony-ofono: battery.charge_level.last_full"
-					" is %d", *value);
-	else if (value == &battchg_design)
-		DBG("telephony-ofono: battery.charge_level.design"
-					" is %d", *value);
-	else
-		DBG("telephony-ofono: battery.charge_level.current"
-					" is %d", *value);
-
-	if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
-		int new, max;
-
-		if (battchg_last > 0)
-			max = battchg_last;
-		else
-			max = battchg_design;
-
-		new = battchg_cur * 5 / max;
-
-		telephony_update_indicator(ofono_indicators, "battchg", new);
-	}
-done:
-	dbus_message_unref(reply);
-	remove_pending(call);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
-	send_method_call("org.freedesktop.Hal", path,
-			"org.freedesktop.Hal.Device",
-			"GetPropertyInteger",
-			hal_battery_level_reply, user_data,
-			DBUS_TYPE_STRING, &key,
-			DBUS_TYPE_INVALID);
-}
-
-static gboolean handle_hal_property_modified(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	const char *path;
-	DBusMessageIter iter, array;
-	dbus_int32_t num_changes;
-
-	path = dbus_message_get_path(msg);
-
-	dbus_message_iter_init(msg, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
-		error("Unexpected signature in hal PropertyModified signal");
-		return TRUE;
-	}
-
-	dbus_message_iter_get_basic(&iter, &num_changes);
-	dbus_message_iter_next(&iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in hal PropertyModified signal");
-		return TRUE;
-	}
-
-	dbus_message_iter_recurse(&iter, &array);
-
-	while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-		DBusMessageIter prop;
-		const char *name;
-		dbus_bool_t added, removed;
-
-		dbus_message_iter_recurse(&array, &prop);
-
-		if (!iter_get_basic_args(&prop,
-					DBUS_TYPE_STRING, &name,
-					DBUS_TYPE_BOOLEAN, &added,
-					DBUS_TYPE_BOOLEAN, &removed,
-					DBUS_TYPE_INVALID)) {
-			error("Invalid hal PropertyModified parameters");
-			break;
-		}
-
-		if (g_str_equal(name, "battery.charge_level.last_full"))
-			hal_get_integer(path, name, &battchg_last);
-		else if (g_str_equal(name, "battery.charge_level.current"))
-			hal_get_integer(path, name, &battchg_cur);
-		else if (g_str_equal(name, "battery.charge_level.design"))
-			hal_get_integer(path, name, &battchg_design);
-
-		dbus_message_iter_next(&array);
-	}
-
-	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;
-	DBusError err;
-	DBusMessageIter iter, sub;
-	int type;
-	const char *path;
-
-	DBG("begin of hal_find_device_reply()");
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("hald 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 in hal_find_device_reply()");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &sub);
-
-	type = dbus_message_iter_get_arg_type(&sub);
-
-	if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
-		error("No hal device with battery capability found");
-		goto done;
-	}
-
-	dbus_message_iter_get_basic(&sub, &path);
-
-	DBG("telephony-ofono: found battery device at %s", path);
-
-	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);
-	hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-done:
-	dbus_message_unref(reply);
-	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)
-{
-	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
-				AG_FEATURE_INBAND_RINGTONE |
-				AG_FEATURE_REJECT_A_CALL |
-				AG_FEATURE_ENHANCED_CALL_STATUS |
-				AG_FEATURE_ENHANCED_CALL_CONTROL |
-				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
-				AG_FEATURE_THREE_WAY_CALLING;
-	const char *battery_cap = "battery";
-	int ret;
-	guint watch;
-
-	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,
-			"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);
-
-	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",
-				"org.freedesktop.Hal.Manager",
-				"FindDeviceByCapability",
-				hal_find_device_reply, NULL,
-				DBUS_TYPE_STRING, &battery_cap,
-				DBUS_TYPE_INVALID);
-	if (ret < 0)
-		return ret;
-
-	DBG("telephony_init() successfully");
-
-	telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
-								chld_str);
-
-	return ret;
-}
-
-static void remove_watch(gpointer data)
-{
-	g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
-}
-
-static void pending_free(void *data)
-{
-	DBusPendingCall *call = data;
-
-	if (!dbus_pending_call_get_completed(call))
-		dbus_pending_call_cancel(call);
-
-	dbus_pending_call_unref(call);
-}
-
-void telephony_exit(void)
-{
-	DBG("");
-
-	g_free(last_dialed_number);
-	last_dialed_number = NULL;
-
-	if (modem_obj_path)
-		modem_removed(modem_obj_path);
-
-	g_slist_free_full(watches, remove_watch);
-	watches = NULL;
-
-	g_slist_free_full(pending, pending_free);
-	pending = NULL;
-
-	dbus_connection_unref(connection);
-	connection = NULL;
-
-	telephony_deinit();
-}
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 09/15] audio: Move HFP/HSP AG servers to telephony.c
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (7 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 08/15] audio: Remove oFono " Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 10/15] audio: Send transport path to telephony agent Frédéric Danis
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Move HeadSet/HandsFree AudioGateway RFComm servers from audio/manager.c
to audio/telephony.c.
Doing this, each RfComm server is started (and the related SDP record
advertised) only when an agent registers for its specific profile.
---
 audio/headset.c   |   48 +++----
 audio/headset.h   |    5 +-
 audio/manager.c   |  386 +----------------------------------------------------
 audio/telephony.c |  315 ++++++++++++++++++++++++++++++++++++++++++-
 audio/telephony.h |    2 -
 5 files changed, 332 insertions(+), 424 deletions(-)

diff --git a/audio/headset.c b/audio/headset.c
index 0070953..ec4db59 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -389,7 +389,6 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	struct audio_device *dev = user_data;
 	struct headset *hs = dev->headset;
 	struct btd_device *btd_dev = dev->btd_dev;
-	struct btd_adapter *adapter;
 	struct pending_connect *p = hs->pending;
 	char hs_address[18];
 
@@ -398,15 +397,6 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 		goto failed;
 	}
 
-	adapter = device_get_adapter(btd_dev);
-
-	/* For HFP telephony isn't ready just disconnect */
-	if (hs->hfp_active && !telephony_is_ready(adapter)) {
-		error("Unable to accept HFP connection since the telephony "
-				"subsystem isn't initialized");
-		goto failed;
-	}
-
 	hs->tel_dev = telephony_device_connecting(chan, btd_dev, dev,
 							hs->connecting_uuid);
 	if (hs->tel_dev == NULL)
@@ -561,20 +551,30 @@ static int get_records(struct audio_device *device, headset_stream_cb_t cb,
 			void *user_data, unsigned int *cb_id)
 {
 	struct headset *hs = device->headset;
-	uint16_t svclass;
+	struct btd_adapter *adapter;
+	gboolean hsp_ag_supported, hfp_ag_supported;
+	uint16_t svclass = 0;
 	uuid_t uuid;
 	int err;
 
-	if (hs->pending && hs->pending->svclass == HANDSFREE_SVCLASS_ID)
-		svclass = HEADSET_SVCLASS_ID;
-	else
-		svclass = hs->search_hfp ? HANDSFREE_SVCLASS_ID :
-							HEADSET_SVCLASS_ID;
+	adapter = device_get_adapter(device->btd_dev);
+
+	hsp_ag_supported = telephony_is_uuid_supported(adapter, HSP_AG_UUID);
+	hfp_ag_supported = telephony_is_uuid_supported(adapter, HFP_AG_UUID);
 
-	if (svclass == HANDSFREE_SVCLASS_ID)
+	if (hfp_ag_supported && hs->search_hfp && hs->pending == NULL) {
+		svclass = HANDSFREE_SVCLASS_ID;
 		hs->connecting_uuid = HFP_AG_UUID;
-	else
+	} else if (hsp_ag_supported) {
+		svclass = HEADSET_SVCLASS_ID;
 		hs->connecting_uuid = HSP_AG_UUID;
+	} else {
+		if (hs->pending) {
+			pending_connect_finalize(device);
+			headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+		}
+		return -1;
+	}
 
 	sdp_uuid16_create(&uuid, svclass);
 
@@ -700,7 +700,6 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
 {
 	struct audio_device *device = data;
 	struct headset *hs = device->headset;
-	struct btd_adapter *adapter;
 	int err;
 
 	if (hs->state == HEADSET_STATE_CONNECTING)
@@ -708,11 +707,6 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
 	else if (hs->state > HEADSET_STATE_CONNECTING)
 		return btd_error_already_connected(msg);
 
-	adapter = device_get_adapter(device->btd_dev);
-
-	if (hs->hfp_handle && !telephony_is_ready(adapter))
-		return btd_error_not_ready(msg);
-
 	device->auto_connect = FALSE;
 
 	err = rfcomm_connect(device, NULL, NULL, NULL);
@@ -922,14 +916,14 @@ register_iface:
 	return hs;
 }
 
-uint32_t headset_config_init(GKeyFile *config)
+void headset_config_init(GKeyFile *config)
 {
 	GError *err = NULL;
 	char *str;
 
 	/* Use the default values if there is no config file */
 	if (config == NULL)
-		return telephony_get_ag_features();
+		return;
 
 	str = g_key_file_get_string(config, "General", "SCORouting",
 					&err);
@@ -945,8 +939,6 @@ uint32_t headset_config_init(GKeyFile *config)
 			error("Invalid Headset Routing value: %s", str);
 		g_free(str);
 	}
-
-	return telephony_get_ag_features();
 }
 
 static gboolean hs_dc_timeout(struct audio_device *dev)
diff --git a/audio/headset.h b/audio/headset.h
index 61e63c8..2915495 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -24,9 +24,6 @@
 
 #define AUDIO_HEADSET_INTERFACE "org.bluez.Headset"
 
-#define DEFAULT_HS_AG_CHANNEL 12
-#define DEFAULT_HF_AG_CHANNEL 13
-
 typedef enum {
 	HEADSET_STATE_DISCONNECTED,
 	HEADSET_STATE_CONNECTING,
@@ -62,7 +59,7 @@ struct headset *headset_init(struct audio_device *dev, uint16_t svc,
 
 void headset_unregister(struct audio_device *dev);
 
-uint32_t headset_config_init(GKeyFile *config);
+void headset_config_init(GKeyFile *config);
 
 void headset_update(struct audio_device *dev, uint16_t svc,
 			const char *uuidstr);
diff --git a/audio/manager.c b/audio/manager.c
index 2b125a0..4ab0186 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -89,11 +89,7 @@ typedef enum {
 struct audio_adapter {
 	struct btd_adapter *btd_adapter;
 	gboolean powered;
-	uint32_t hsp_ag_record_id;
-	uint32_t hfp_ag_record_id;
 	uint32_t hfp_hs_record_id;
-	GIOChannel *hsp_ag_server;
-	GIOChannel *hfp_ag_server;
 	GIOChannel *hfp_hs_server;
 	gint ref;
 };
@@ -226,62 +222,6 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
 	}
 }
 
-static sdp_record_t *hsp_ag_record(uint8_t ch)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
-	uuid_t l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_record_t *record;
-	sdp_list_t *aproto, *proto[2];
-	sdp_data_t *channel;
-
-	record = sdp_record_alloc();
-	if (!record)
-		return NULL;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(record, root);
-
-	sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
-	profile.version = 0x0102;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &ch);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(record, aproto);
-
-	sdp_set_info_attr(record, "Headset Audio Gateway", 0, 0);
-
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(pfseq, 0);
-	sdp_list_free(aproto, 0);
-	sdp_list_free(root, 0);
-	sdp_list_free(svclass_id, 0);
-
-	return record;
-}
-
 static sdp_record_t *hfp_hs_record(uint8_t ch)
 {
 	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
@@ -338,201 +278,6 @@ static sdp_record_t *hfp_hs_record(uint8_t ch)
 	return record;
 }
 
-static sdp_record_t *hfp_ag_record(uint8_t ch, uint32_t feat)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
-	uuid_t l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t *record;
-	sdp_data_t *channel, *features;
-	uint8_t netid = 0x01;
-	uint16_t sdpfeat;
-	sdp_data_t *network;
-
-	record = sdp_record_alloc();
-	if (!record)
-		return NULL;
-
-	network = sdp_data_alloc(SDP_UINT8, &netid);
-	if (!network) {
-		sdp_record_free(record);
-		return NULL;
-	}
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(record, root);
-
-	sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
-	profile.version = 0x0105;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &ch);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	sdpfeat = (uint16_t) feat & 0xF;
-	features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
-	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(record, aproto);
-
-	sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
-
-	sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
-
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(pfseq, 0);
-	sdp_list_free(aproto, 0);
-	sdp_list_free(root, 0);
-	sdp_list_free(svclass_id, 0);
-
-	return record;
-}
-
-static void headset_auth_cb(DBusError *derr, void *user_data)
-{
-	struct audio_device *device = user_data;
-	GError *err = NULL;
-	GIOChannel *io;
-
-	if (device->hs_preauth_id) {
-		g_source_remove(device->hs_preauth_id);
-		device->hs_preauth_id = 0;
-	}
-
-	if (derr && dbus_error_is_set(derr)) {
-		error("Access denied: %s", derr->message);
-		headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-		return;
-	}
-
-	io = headset_get_rfcomm(device);
-
-	if (!bt_io_accept(io, headset_connect_cb, device, NULL, &err)) {
-		error("bt_io_accept: %s", err->message);
-		g_error_free(err);
-		headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-		return;
-	}
-}
-
-static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond,
-							gpointer user_data)
-{
-	struct audio_device *device = user_data;
-
-	DBG("Headset disconnected during authorization");
-
-	audio_device_cancel_authorization(device, headset_auth_cb, device);
-
-	headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-
-	device->hs_preauth_id = 0;
-
-	return FALSE;
-}
-
-static void ag_confirm(GIOChannel *chan, gpointer data)
-{
-	const char *server_uuid, *remote_uuid;
-	struct audio_device *device;
-	gboolean hfp_active;
-	bdaddr_t src, dst;
-	int perr;
-	GError *err = NULL;
-	uint8_t ch;
-
-	bt_io_get(chan, BT_IO_RFCOMM, &err,
-			BT_IO_OPT_SOURCE_BDADDR, &src,
-			BT_IO_OPT_DEST_BDADDR, &dst,
-			BT_IO_OPT_CHANNEL, &ch,
-			BT_IO_OPT_INVALID);
-	if (err) {
-		error("%s", err->message);
-		g_error_free(err);
-		goto drop;
-	}
-
-	if (ch == DEFAULT_HS_AG_CHANNEL) {
-		hfp_active = FALSE;
-		server_uuid = HSP_AG_UUID;
-		remote_uuid = HSP_HS_UUID;
-	} else {
-		hfp_active = TRUE;
-		server_uuid = HFP_AG_UUID;
-		remote_uuid = HFP_HS_UUID;
-	}
-
-	device = manager_get_device(&src, &dst, TRUE);
-	if (!device)
-		goto drop;
-
-	if (!manager_allow_headset_connection(device)) {
-		DBG("Refusing headset: too many existing connections");
-		goto drop;
-	}
-
-	if (!device->headset) {
-		btd_device_add_uuid(device->btd_dev, remote_uuid);
-		if (!device->headset)
-			goto drop;
-	}
-
-	if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
-		DBG("Refusing new connection since one already exists");
-		goto drop;
-	}
-
-	headset_set_hfp_active(device, hfp_active);
-	headset_set_rfcomm_initiator(device, TRUE);
-
-	if (headset_connect_rfcomm(device, chan) < 0) {
-		error("headset_connect_rfcomm failed");
-		goto drop;
-	}
-
-	headset_set_state(device, HEADSET_STATE_CONNECTING);
-
-	perr = audio_device_request_authorization(device, server_uuid,
-						headset_auth_cb, device);
-	if (perr < 0) {
-		DBG("Authorization denied: %s", strerror(-perr));
-		headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-		return;
-	}
-
-	device->hs_preauth_id = g_io_add_watch(chan,
-					G_IO_NVAL | G_IO_HUP | G_IO_ERR,
-					hs_preauth_cb, device);
-
-	device->auto_connect = auto_connect;
-
-	return;
-
-drop:
-	g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
 static void gateway_auth_cb(DBusError *derr, void *user_data)
 {
 	struct audio_device *device = user_data;
@@ -608,108 +353,6 @@ drop:
 	g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
-static int headset_server_init(struct audio_adapter *adapter)
-{
-	uint8_t chan = DEFAULT_HS_AG_CHANNEL;
-	sdp_record_t *record;
-	gboolean master = TRUE;
-	GError *err = NULL;
-	uint32_t features;
-	GIOChannel *io;
-	bdaddr_t src;
-
-	if (config) {
-		gboolean tmp;
-
-		tmp = g_key_file_get_boolean(config, "General", "Master",
-						&err);
-		if (err) {
-			DBG("audio.conf: %s", err->message);
-			g_clear_error(&err);
-		} else
-			master = tmp;
-	}
-
-	adapter_get_address(adapter->btd_adapter, &src);
-
-	io =  bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, adapter, NULL, &err,
-				BT_IO_OPT_SOURCE_BDADDR, &src,
-				BT_IO_OPT_CHANNEL, chan,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_MASTER, master,
-				BT_IO_OPT_INVALID);
-	if (!io)
-		goto failed;
-
-	adapter->hsp_ag_server = io;
-
-	record = hsp_ag_record(chan);
-	if (!record) {
-		error("Unable to allocate new service record");
-		goto failed;
-	}
-
-	if (add_record_to_server(&src, record) < 0) {
-		error("Unable to register HS AG service record");
-		sdp_record_free(record);
-		goto failed;
-	}
-	adapter->hsp_ag_record_id = record->handle;
-
-	features = headset_config_init(config);
-
-	if (!enabled.hfp)
-		return 0;
-
-	chan = DEFAULT_HF_AG_CHANNEL;
-
-	io = bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, adapter, NULL, &err,
-				BT_IO_OPT_SOURCE_BDADDR, &src,
-				BT_IO_OPT_CHANNEL, chan,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_MASTER, master,
-				BT_IO_OPT_INVALID);
-	if (!io)
-		goto failed;
-
-	adapter->hfp_ag_server = io;
-
-	record = hfp_ag_record(chan, features);
-	if (!record) {
-		error("Unable to allocate new service record");
-		goto failed;
-	}
-
-	if (add_record_to_server(&src, record) < 0) {
-		error("Unable to register HF AG service record");
-		sdp_record_free(record);
-		goto failed;
-	}
-	adapter->hfp_ag_record_id = record->handle;
-
-	return 0;
-
-failed:
-	if (err) {
-		error("%s", err->message);
-		g_error_free(err);
-	}
-
-	if (adapter->hsp_ag_server) {
-		g_io_channel_shutdown(adapter->hsp_ag_server, TRUE, NULL);
-		g_io_channel_unref(adapter->hsp_ag_server);
-		adapter->hsp_ag_server = NULL;
-	}
-
-	if (adapter->hfp_ag_server) {
-		g_io_channel_shutdown(adapter->hfp_ag_server, TRUE, NULL);
-		g_io_channel_unref(adapter->hfp_ag_server);
-		adapter->hfp_ag_server = NULL;
-	}
-
-	return -1;
-}
-
 static int gateway_server_init(struct audio_adapter *adapter)
 {
 	uint8_t chan = DEFAULT_HFP_HS_CHANNEL;
@@ -903,7 +546,6 @@ static int headset_server_probe(struct btd_adapter *adapter)
 {
 	struct audio_adapter *adp;
 	const gchar *path = adapter_get_path(adapter);
-	int err;
 
 	DBG("path %s", path);
 
@@ -911,11 +553,7 @@ static int headset_server_probe(struct btd_adapter *adapter)
 	if (!adp)
 		return -EINVAL;
 
-	err = headset_server_init(adp);
-	if (err < 0) {
-		audio_adapter_unref(adp);
-		return err;
-	}
+	headset_config_init(config);
 
 	btd_adapter_register_powered_callback(adapter, state_changed);
 
@@ -935,28 +573,6 @@ static void headset_server_remove(struct btd_adapter *adapter)
 	if (!adp)
 		return;
 
-	if (adp->hsp_ag_record_id) {
-		remove_record_from_server(adp->hsp_ag_record_id);
-		adp->hsp_ag_record_id = 0;
-	}
-
-	if (adp->hsp_ag_server) {
-		g_io_channel_shutdown(adp->hsp_ag_server, TRUE, NULL);
-		g_io_channel_unref(adp->hsp_ag_server);
-		adp->hsp_ag_server = NULL;
-	}
-
-	if (adp->hfp_ag_record_id) {
-		remove_record_from_server(adp->hfp_ag_record_id);
-		adp->hfp_ag_record_id = 0;
-	}
-
-	if (adp->hfp_ag_server) {
-		g_io_channel_shutdown(adp->hfp_ag_server, TRUE, NULL);
-		g_io_channel_unref(adp->hfp_ag_server);
-		adp->hfp_ag_server = NULL;
-	}
-
 	audio_adapter_unref(adp);
 }
 
diff --git a/audio/telephony.c b/audio/telephony.c
index 49ccafd..943c3aa 100644
--- a/audio/telephony.c
+++ b/audio/telephony.c
@@ -43,18 +43,24 @@
 
 #include "log.h"
 #include "device.h"
+#include "manager.h"
 #include "error.h"
 #include "glib-helper.h"
 #include "sdp-client.h"
 #include "headset.h"
 #include "telephony.h"
 #include "dbus-common.h"
+#include "sdpd.h"
 
 #define AUDIO_TELEPHONY_INTERFACE "org.bluez.Telephony"
 #define AUDIO_TELEPHONY_AGENT_INTERFACE "org.bluez.TelephonyAgent"
 
 #define DEFAULT_HS_HS_CHANNEL 6
+#define DEFAULT_HS_AG_CHANNEL 12
 #define DEFAULT_HF_HS_CHANNEL 7
+#define DEFAULT_HF_AG_CHANNEL 13
+
+struct telephony_agent;
 
 /*
  * Profile configuration
@@ -62,6 +68,8 @@
  * It describes for each supported profile:
  *  - UUID, RFCOMM channel and security level
  *  - remote UUID, service class and profile descriptor if they exist
+ *  - SDP record create function
+ *  - RFCOMM connection approval callback
  *  - profile connection complete callback called when agent replied to
  *    NewConnection method call
  */
@@ -71,13 +79,17 @@ struct profile_config {
 	const char		*r_uuid;
 	uint16_t		r_class;
 	uint16_t		r_profile;
+	sdp_record_t		*(*record_init)(struct telephony_agent *agent);
+	BtIOConfirm		confirm;
 	DBusPendingCallNotifyFunction connection_reply;
 };
 
 /*
  * Telephony agent
  *
- * It represents the telephony agent with provided version and features.
+ * It represents the telephony agent for which BlueZ will publish an
+ * SDP record (record_id) with provided version and features.
+ * BlueZ will also listen for incoming connection on io.
  *
  * This is done by adapter.
  */
@@ -89,6 +101,8 @@ struct telephony_agent {
 	uint16_t		version;	/* agent profile version */
 	uint16_t		features;	/* agent supported features */
 	guint			watch;		/* agent disconnect watcher */
+	GIOChannel		*io;		/* listener channel */
+	uint32_t		record_id;	/* SDP record id */
 };
 
 /*
@@ -149,6 +163,14 @@ static void free_agent(struct telephony_agent *agent)
 {
 	DBusMessage *msg;
 
+	if (agent->record_id)
+		remove_record_from_server(agent->record_id);
+
+	if (agent->io) {
+		g_io_channel_shutdown(agent->io, TRUE, NULL);
+		g_io_channel_unref(agent->io);
+	}
+
 	if (agent->watch) {
 		msg = dbus_message_new_method_call(agent->name, agent->path,
 				AUDIO_TELEPHONY_AGENT_INTERFACE, "Release");
@@ -428,14 +450,255 @@ void telephony_device_disconnect(struct telephony_device *device)
 	g_free(device);
 }
 
-gboolean telephony_is_ready(struct btd_adapter *adapter)
+static sdp_record_t *hsp_ag_record(struct telephony_agent *agent)
 {
-	return find_agent(adapter, NULL, NULL, HFP_AG_UUID) ? TRUE : FALSE;
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+	uuid_t l2cap_uuid, rfcomm_uuid;
+	sdp_profile_desc_t profile;
+	sdp_record_t *record;
+	sdp_list_t *aproto, *proto[2];
+	sdp_data_t *channel;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(0, &root_uuid);
+	sdp_set_browse_groups(record, root);
+
+	sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &svclass_uuid);
+	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+	sdp_set_service_classes(record, svclass_id);
+
+	sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+	profile.version = agent->version;
+	pfseq = sdp_list_append(0, &profile);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	apseq = sdp_list_append(0, proto[0]);
+
+	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+	proto[1] = sdp_list_append(0, &rfcomm_uuid);
+	channel = sdp_data_alloc(SDP_UINT8, &agent->config->channel);
+	proto[1] = sdp_list_append(proto[1], channel);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	sdp_set_info_attr(record, "Headset Audio Gateway", 0, 0);
+
+	sdp_data_free(channel);
+	sdp_list_free(proto[0], 0);
+	sdp_list_free(proto[1], 0);
+	sdp_list_free(apseq, 0);
+	sdp_list_free(pfseq, 0);
+	sdp_list_free(aproto, 0);
+	sdp_list_free(root, 0);
+	sdp_list_free(svclass_id, 0);
+
+	return record;
 }
 
-uint32_t telephony_get_ag_features(void)
+static sdp_record_t *hfp_ag_record(struct telephony_agent *agent)
 {
-	return 0;
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+	uuid_t l2cap_uuid, rfcomm_uuid;
+	sdp_profile_desc_t profile;
+	sdp_list_t *aproto, *proto[2];
+	sdp_record_t *record;
+	sdp_data_t *channel, *features;
+	uint8_t netid;
+	uint16_t sdpfeat;
+	sdp_data_t *network;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	netid = agent->features & AG_FEATURE_REJECT_A_CALL ? 1 : 0;
+	network = sdp_data_alloc(SDP_UINT8, &netid);
+	if (!network) {
+		sdp_record_free(record);
+		return NULL;
+	}
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(0, &root_uuid);
+	sdp_set_browse_groups(record, root);
+
+	sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &svclass_uuid);
+	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+	sdp_set_service_classes(record, svclass_id);
+
+	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+	profile.version = agent->version;
+	pfseq = sdp_list_append(0, &profile);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	apseq = sdp_list_append(0, proto[0]);
+
+	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+	proto[1] = sdp_list_append(0, &rfcomm_uuid);
+	channel = sdp_data_alloc(SDP_UINT8, &agent->config->channel);
+	proto[1] = sdp_list_append(proto[1], channel);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	sdpfeat = agent->features & 0x1F;
+	features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
+	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
+
+	sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+	sdp_data_free(channel);
+	sdp_list_free(proto[0], 0);
+	sdp_list_free(proto[1], 0);
+	sdp_list_free(apseq, 0);
+	sdp_list_free(pfseq, 0);
+	sdp_list_free(aproto, 0);
+	sdp_list_free(root, 0);
+	sdp_list_free(svclass_id, 0);
+
+	return record;
+}
+
+static void headset_auth_cb(DBusError *derr, void *user_data)
+{
+	struct audio_device *au_dev = user_data;
+	GError *err = NULL;
+	GIOChannel *io;
+
+	if (au_dev->hs_preauth_id) {
+		g_source_remove(au_dev->hs_preauth_id);
+		au_dev->hs_preauth_id = 0;
+	}
+
+	if (derr && dbus_error_is_set(derr)) {
+		error("Access denied: %s", derr->message);
+		headset_set_state(au_dev, HEADSET_STATE_DISCONNECTED);
+		return;
+	}
+
+	io = headset_get_rfcomm(au_dev);
+
+	if (!bt_io_accept(io, headset_connect_cb, au_dev, NULL, &err)) {
+		error("bt_io_accept: %s", err->message);
+		g_error_free(err);
+		headset_set_state(au_dev, HEADSET_STATE_DISCONNECTED);
+		return;
+	}
+}
+
+static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	struct audio_device *au_dev = user_data;
+
+	DBG("Headset disconnected during authorization");
+
+	audio_device_cancel_authorization(au_dev, headset_auth_cb, au_dev);
+
+	headset_set_state(au_dev, HEADSET_STATE_DISCONNECTED);
+
+	au_dev->hs_preauth_id = 0;
+
+	return FALSE;
+}
+
+static void ag_confirm(GIOChannel *chan, gpointer data)
+{
+	struct telephony_agent *agent = data;
+	struct audio_device *au_dev;
+	gboolean hfp_active;
+	bdaddr_t src, dst;
+	int perr;
+	GError *err = NULL;
+	uint8_t ch;
+
+	bt_io_get(chan, BT_IO_RFCOMM, &err,
+			BT_IO_OPT_SOURCE_BDADDR, &src,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_CHANNEL, &ch,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	/* TODO: to remove ? */
+	if (ch == DEFAULT_HS_AG_CHANNEL)
+		hfp_active = FALSE;
+	else
+		hfp_active = TRUE;
+
+	au_dev = manager_get_device(&src, &dst, TRUE);
+	if (!au_dev)
+		goto drop;
+
+	if (!manager_allow_headset_connection(au_dev)) {
+		DBG("Refusing headset: too many existing connections");
+		goto drop;
+	}
+
+	if (!au_dev->headset) {
+		btd_device_add_uuid(au_dev->btd_dev, agent->config->r_uuid);
+		if (!au_dev->headset)
+			goto drop;
+	}
+
+	if (headset_get_state(au_dev) > HEADSET_STATE_DISCONNECTED) {
+		DBG("Refusing new connection since one already exists");
+		goto drop;
+	}
+
+	headset_set_hfp_active(au_dev, hfp_active);
+	headset_set_rfcomm_initiator(au_dev, TRUE);
+	headset_set_connecting_uuid(au_dev, agent->config->uuid);
+
+	if (headset_connect_rfcomm(au_dev, chan) < 0) {
+		error("headset_connect_rfcomm failed");
+		goto drop;
+	}
+
+	headset_set_state(au_dev, HEADSET_STATE_CONNECTING);
+
+	perr = audio_device_request_authorization(au_dev, agent->config->uuid,
+						headset_auth_cb, au_dev);
+	if (perr < 0) {
+		DBG("Authorization denied: %s", strerror(-perr));
+		headset_set_state(au_dev, HEADSET_STATE_DISCONNECTED);
+		return;
+	}
+
+	au_dev->hs_preauth_id = g_io_add_watch(chan,
+					G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+					hs_preauth_cb, au_dev);
+
+#if 0
+	device->auto_connect = auto_connect;
+#endif
+
+	return;
+
+drop:
+	g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
 static struct profile_config default_configs[] = {
@@ -444,12 +707,16 @@ static struct profile_config default_configs[] = {
 		HSP_HS_UUID,
 		HEADSET_SVCLASS_ID,
 		HEADSET_PROFILE_ID,
+		hsp_ag_record,
+		ag_confirm,
 		hs_newconnection_reply },
 	{ HFP_AG_UUID,
 		DEFAULT_HF_AG_CHANNEL,
 		HFP_HS_UUID,
 		HANDSFREE_SVCLASS_ID,
 		HANDSFREE_PROFILE_ID,
+		hfp_ag_record,
+		ag_confirm,
 		hs_newconnection_reply },
 };
 
@@ -499,6 +766,10 @@ static DBusMessage *register_agent(DBusConnection *conn,
 	uint16_t version = 0;
 	uint16_t features = 0xFFFF;
 	struct telephony_agent *agent;
+	sdp_record_t *record;
+	bdaddr_t src;
+	gboolean master = TRUE;
+	GError *err = NULL;
 
 	sender = dbus_message_get_sender(msg);
 
@@ -529,9 +800,43 @@ static DBusMessage *register_agent(DBusConnection *conn,
 							agent_disconnect_cb,
 							agent, NULL);
 
+	record = agent->config->record_init(agent);
+	if (!record) {
+		error("Unable to allocate new service record");
+		return btd_error_failed(msg, "Unable to allocate new service " \
+						"record");
+	}
+
 	DBG("Register agent : %s%s for %s version 0x%04X with features 0x%02X",
 					sender, path, uuid, version, features);
 
+	/* start RFComm agent server */
+	adapter_get_address(adapter, &src);
+
+	agent->io = bt_io_listen(BT_IO_RFCOMM, NULL, agent->config->confirm,
+				agent, NULL, &err,
+				BT_IO_OPT_SOURCE_BDADDR, &src,
+				BT_IO_OPT_CHANNEL, agent->config->channel,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+				BT_IO_OPT_MASTER, master,
+				BT_IO_OPT_INVALID);
+	if (agent->io == NULL) {
+		error("Unable to register server");
+		sdp_record_free(record);
+		free_agent(agent);
+		return btd_error_failed(msg, "Failed to register server");
+	}
+
+	/* advertise agent sdp record */
+	if (add_record_to_server(&src, record) < 0) {
+		error("Unable to register service record");
+		sdp_record_free(record);
+		free_agent(agent);
+		return btd_error_failed(msg, "Failed to register sdp record");
+	}
+
+	agent->record_id = record->handle;
+
 	agents = g_slist_append(agents, agent);
 
 	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
diff --git a/audio/telephony.h b/audio/telephony.h
index 1a4ab06..1e20087 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -53,8 +53,6 @@ struct telephony_device *telephony_device_connecting(GIOChannel *io,
 					const char *uuid);
 void telephony_device_disconnect(struct telephony_device *device);
 
-gboolean telephony_is_ready(struct btd_adapter *adapter);
-uint32_t telephony_get_ag_features(void);
 gboolean telephony_is_uuid_supported(struct btd_adapter *adapter,
 						const char *uuid);
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 10/15] audio: Send transport path to telephony agent
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (8 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 09/15] audio: Move HFP/HSP AG servers to telephony.c Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 11/15] audio: Move HFP HF server to telephony.c Frédéric Danis
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Add the ability to set MediaTransport path to the HSP/HFP agent during
the call of the NewConnection method.
Accept MediaTransport property change from telephony agent in addition
to Media Endpoint.

This allows external program, implementing telephony agent, to change
Noise Reduction/Echo Cancellation (ECNR), Inband ringtone, speaker
and microphone volume settings of the audio system (i.e. Pulse Audio)
through the MediaTransport.
---
 audio/headset.c   |   31 +++++++++++++++++++++++++++++++
 audio/headset.h   |    3 +++
 audio/media.c     |   17 +++++++++++++++++
 audio/telephony.c |   18 ++++++++++++++++++
 audio/telephony.h |    3 +++
 audio/transport.c |   23 +++++++++++++++++++++--
 6 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/audio/headset.c b/audio/headset.c
index ec4db59..fe4e62d 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -109,6 +109,7 @@ struct headset {
 
 	GIOChannel *tmp_rfcomm;
 	const char *connecting_uuid;
+	const char *connecting_transport_path;
 	GIOChannel *sco;
 	guint sco_id;
 
@@ -403,6 +404,9 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 		goto failed;
 
 	hs->connecting_uuid = NULL;
+	telephony_set_media_transport_path(hs->tel_dev,
+						hs->connecting_transport_path);
+	hs->connecting_transport_path = NULL;
 
 	g_io_channel_unref(hs->tmp_rfcomm);
 	hs->tmp_rfcomm = NULL;
@@ -582,6 +586,7 @@ static int get_records(struct audio_device *device, headset_stream_cb_t cb,
 						get_record_cb, device, NULL);
 	if (err < 0) {
 		hs->connecting_uuid = NULL;
+		hs->connecting_transport_path = NULL;
 		return err;
 	}
 
@@ -1137,6 +1142,31 @@ void headset_set_connecting_uuid(struct audio_device *dev, const char *uuid)
 	hs->connecting_uuid = uuid;
 }
 
+void headset_set_media_transport_path(struct audio_device *dev,
+							const char *path)
+{
+	struct headset *hs = dev->headset;
+
+	DBG("MediaTransport path: %s", path);
+
+	if (hs->tel_dev == NULL) {
+		hs->connecting_transport_path = path;
+		return;
+	}
+
+	telephony_set_media_transport_path(hs->tel_dev, path);
+}
+
+const char *headset_get_telephony_agent_name(struct audio_device *dev)
+{
+	struct headset *hs = dev->headset;
+
+	if (hs == NULL || hs->tel_dev == NULL)
+		return NULL;
+
+	return telephony_get_agent_name(hs->tel_dev);
+}
+
 int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
 {
 	struct headset *hs = dev->headset;
@@ -1183,6 +1213,7 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
 		}
 
 		dev->headset->connecting_uuid = NULL;
+		dev->headset->connecting_transport_path = NULL;
 
 		headset_close_rfcomm(dev);
 		emit_property_changed(dev->conn, dev->path,
diff --git a/audio/headset.h b/audio/headset.h
index 2915495..a20b587 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -105,3 +105,6 @@ void headset_shutdown(struct audio_device *dev);
 
 void headset_profile_connection_complete(struct audio_device *dev);
 void headset_set_connecting_uuid(struct audio_device *dev, const char *uuid);
+void headset_set_media_transport_path(struct audio_device *dev,
+							const char *path);
+const char *headset_get_telephony_agent_name(struct audio_device *dev);
diff --git a/audio/media.c b/audio/media.c
index ea6d582..c608c41 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -475,6 +475,7 @@ static void headset_state_changed(struct audio_device *dev,
 {
 	struct media_endpoint *endpoint = user_data;
 	struct media_transport *transport;
+	const char *path;
 
 	DBG("");
 
@@ -493,6 +494,13 @@ static void headset_state_changed(struct audio_device *dev,
 	case HEADSET_STATE_CONNECTING:
 		set_configuration(endpoint, dev, NULL, 0, headset_setconf_cb,
 								dev, NULL);
+
+		transport = find_device_transport(endpoint, dev);
+		if (transport == NULL)
+			break;
+
+		path = media_transport_get_path(transport);
+		headset_set_media_transport_path(dev, path);
 		break;
 	case HEADSET_STATE_CONNECTED:
 		break;
@@ -704,9 +712,18 @@ static gboolean endpoint_init_ag(struct media_endpoint *endpoint, int *err)
 
 	for (l = list; l != NULL; l = l->next) {
 		struct audio_device *dev = l->data;
+		struct media_transport *transport;
+		const char *path;
 
 		set_configuration(endpoint, dev, NULL, 0,
 						headset_setconf_cb, dev, NULL);
+
+		transport = find_device_transport(endpoint, dev);
+		if (transport == NULL)
+			break;
+
+		path = media_transport_get_path(transport);
+		headset_set_media_transport_path(dev, path);
 	}
 
 	g_slist_free(list);
diff --git a/audio/telephony.c b/audio/telephony.c
index 943c3aa..da1797f 100644
--- a/audio/telephony.c
+++ b/audio/telephony.c
@@ -111,6 +111,8 @@ struct telephony_agent {
  * It represents the connection between telephony agent (name, path and config)
  * and remote device (with its profile version and supported features if they
  * can be retrieved).
+ * If audio is used by profile, Media Transport path is stored to be sent to
+ * telephony agent during NewConnection method call.
  *
  * This is used after authentication completion and remote SDP record retrieval
  * (if supported by profile, i.e. HFP/HSP) until disconnection.
@@ -124,6 +126,7 @@ struct telephony_device {
 	uint16_t		version;	/* remote profile version */
 	uint16_t		features;	/* remote supported features */
 	GIOChannel		*rfcomm;	/* connected RFCOMM channel */
+	const char		*transport_path; /* MediaTransport path */
 	gboolean		pending_sdp;	/* SDP request is pending */
 	DBusPendingCall		*call;		/* D-Bus pending call */
 };
@@ -276,6 +279,10 @@ static gboolean agent_sendfd(struct telephony_device *tel_dev, int fd,
 		dict_append_entry(&dict, "Features", DBUS_TYPE_UINT16,
 							&tel_dev->features);
 
+	if (tel_dev->transport_path != NULL)
+		dict_append_entry(&dict, "Transport", DBUS_TYPE_OBJECT_PATH,
+						&tel_dev->transport_path);
+
 	dbus_message_iter_close_container(&iter, &dict);
 
 	if (!dbus_connection_send_with_reply(connection, msg,
@@ -450,6 +457,17 @@ void telephony_device_disconnect(struct telephony_device *device)
 	g_free(device);
 }
 
+void telephony_set_media_transport_path(struct telephony_device *device,
+						const char *path)
+{
+	device->transport_path = path;
+}
+
+const char *telephony_get_agent_name(struct telephony_device *device)
+{
+	return device->name;
+}
+
 static sdp_record_t *hsp_ag_record(struct telephony_agent *agent)
 {
 	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
diff --git a/audio/telephony.h b/audio/telephony.h
index 1e20087..42ce580 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -52,6 +52,9 @@ struct telephony_device *telephony_device_connecting(GIOChannel *io,
 					struct audio_device *au_dev,
 					const char *uuid);
 void telephony_device_disconnect(struct telephony_device *device);
+void telephony_set_media_transport_path(struct telephony_device *device,
+						const char *path);
+const char *telephony_get_agent_name(struct telephony_device *device);
 
 gboolean telephony_is_uuid_supported(struct btd_adapter *adapter,
 						const char *uuid);
diff --git a/audio/transport.c b/audio/transport.c
index 6d4ad55..7236e43 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -857,6 +857,18 @@ static int set_property_gateway(struct media_transport *transport,
 	return -EINVAL;
 }
 
+static gboolean check_telephony_agent_name(struct media_transport *transport,
+							const char *sender)
+{
+	const char *tel_agent;
+
+	tel_agent = headset_get_telephony_agent_name(transport->device);
+	if (tel_agent != NULL && g_strcmp0(tel_agent, sender) == 0)
+		return TRUE;
+
+	return FALSE;
+}
+
 static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
@@ -865,6 +877,7 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
 	DBusMessageIter value;
 	const char *property, *sender;
 	GSList *l;
+	gboolean sender_ok = FALSE;
 	int err;
 
 	if (!dbus_message_iter_init(msg, &iter))
@@ -888,12 +901,18 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
 		struct media_owner *owner = l->data;
 
 		if (g_strcmp0(owner->name, sender) == 0) {
-			err = transport->set_property(transport, property,
-								&value);
+			sender_ok = TRUE;
 			break;
 		}
 	}
 
+	/* Check if Telephony agent does this request */
+	if (!sender_ok)
+		sender_ok = check_telephony_agent_name(transport, sender);
+
+	if (sender_ok)
+		err = transport->set_property(transport, property, &value);
+
 	if (err < 0) {
 		if (err == -EINVAL)
 			return btd_error_invalid_args(msg);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 11/15] audio: Move HFP HF server to telephony.c
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (9 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 10/15] audio: Send transport path to telephony agent Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 12/15] audio: Add DUN GW to org.bluez.Telephony Frédéric Danis
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

Move HandsFree HF RFComm server from audio/manager.c to
audio/telephony.c.
Update the HandsfreeGateway API to reflect this change (remove agent
related methods).
Doing this, RFComm server related to HandsfreeGateway is only started
when an agent registers for this role of HandsFree Profile.
---
 audio/device.h    |    1 +
 audio/gateway.c   |  436 +++++++++++++++--------------------------------------
 audio/gateway.h   |    8 +
 audio/manager.c   |  210 +-------------------------
 audio/media.c     |   17 +++
 audio/telephony.c |  217 +++++++++++++++++++++++++-
 audio/transport.c |    4 +
 doc/hfp-api.txt   |   46 ------
 8 files changed, 366 insertions(+), 573 deletions(-)

diff --git a/audio/device.h b/audio/device.h
index 75f1da9..1e260e3 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -48,6 +48,7 @@ struct audio_device {
 	struct target *target;
 
 	guint hs_preauth_id;
+	guint gw_preauth_id;
 
 	struct dev_priv *priv;
 };
diff --git a/audio/gateway.c b/audio/gateway.c
index 6162948..125cb02 100644
--- a/audio/gateway.c
+++ b/audio/gateway.c
@@ -41,21 +41,20 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
+
+#include "btio.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
 
 #include "sdp-client.h"
 #include "device.h"
 #include "gateway.h"
+#include "telephony.h"
 #include "log.h"
 #include "error.h"
-#include "btio.h"
 #include "dbus-common.h"
 
-struct hf_agent {
-	char *name;	/* Bus id */
-	char *path;	/* D-Bus path */
-	guint watch;	/* Disconnect watch */
-};
-
 struct connect_cb {
 	unsigned int id;
 	gateway_stream_cb_t cb;
@@ -64,14 +63,14 @@ struct connect_cb {
 
 struct gateway {
 	gateway_state_t state;
-	GIOChannel *rfcomm;
+	GIOChannel *tmp_rfcomm;
 	GIOChannel *sco;
-	GIOChannel *incoming;
+	const char *connecting_uuid;
+	const char *connecting_transport_path;
 	GSList *callbacks;
-	struct hf_agent *agent;
 	DBusMessage *msg;
-	int version;
 	gateway_lock_t lock;
+	struct telephony_device *tel_dev;
 };
 
 struct gateway_state_callback {
@@ -105,16 +104,6 @@ static const char *state2str(gateway_state_t state)
 	}
 }
 
-static void agent_free(struct hf_agent *agent)
-{
-	if (!agent)
-		return;
-
-	g_free(agent->name);
-	g_free(agent->path);
-	g_free(agent);
-}
-
 static void change_state(struct audio_device *dev, gateway_state_t new_state)
 {
 	struct gateway *gw = dev->gateway;
@@ -141,8 +130,19 @@ static void change_state(struct audio_device *dev, gateway_state_t new_state)
 
 void gateway_set_state(struct audio_device *dev, gateway_state_t new_state)
 {
+	struct gateway *gw = dev->gateway;
+
 	switch (new_state) {
 	case GATEWAY_STATE_DISCONNECTED:
+		if (gw->msg) {
+			DBusMessage *reply;
+
+			reply = btd_error_failed(gw->msg, "Connect failed");
+			g_dbus_send_message(dev->conn, reply);
+			dbus_message_unref(gw->msg);
+			gw->msg = NULL;
+		}
+
 		gateway_close(dev);
 		break;
 	case GATEWAY_STATE_CONNECTING:
@@ -152,44 +152,6 @@ void gateway_set_state(struct audio_device *dev, gateway_state_t new_state)
 	}
 }
 
-static void agent_disconnect(struct audio_device *dev, struct hf_agent *agent)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(agent->name, agent->path,
-			"org.bluez.HandsfreeAgent", "Release");
-
-	g_dbus_send_message(dev->conn, msg);
-}
-
-static gboolean agent_sendfd(struct hf_agent *agent, int fd,
-		DBusPendingCallNotifyFunction notify, void *data)
-{
-	struct audio_device *dev = data;
-	struct gateway *gw = dev->gateway;
-	DBusMessage *msg;
-	DBusPendingCall *call;
-
-	msg = dbus_message_new_method_call(agent->name, agent->path,
-			"org.bluez.HandsfreeAgent", "NewConnection");
-
-	dbus_message_append_args(msg, DBUS_TYPE_UNIX_FD, &fd,
-					DBUS_TYPE_UINT16, &gw->version,
-					DBUS_TYPE_INVALID);
-
-	if (dbus_connection_send_with_reply(dev->conn, msg,
-							&call, -1) == FALSE) {
-		dbus_message_unref(msg);
-		return FALSE;
-	}
-
-	dbus_pending_call_set_notify(call, notify, dev, NULL);
-	dbus_pending_call_unref(call);
-	dbus_message_unref(msg);
-
-	return TRUE;
-}
-
 static unsigned int connect_cb_new(struct gateway *gw,
 					gateway_stream_cb_t func,
 					void *user_data)
@@ -264,175 +226,59 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	run_connect_cb(dev, NULL);
 }
 
-static gboolean rfcomm_disconnect_cb(GIOChannel *chan, GIOCondition cond,
-			struct audio_device *dev)
+void gateway_slc_complete(struct audio_device *dev)
 {
-	if (cond & G_IO_NVAL)
-		return FALSE;
-
-	gateway_close(dev);
-
-	return FALSE;
-}
-
-static void newconnection_reply(DBusPendingCall *call, void *data)
-{
-	struct audio_device *dev = data;
-	struct gateway *gw = dev->gateway;
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	DBusError derr;
-
-	if (!dev->gateway->rfcomm) {
-		DBG("RFCOMM disconnected from server before agent reply");
-		goto done;
-	}
-
-	dbus_error_init(&derr);
-	if (!dbus_set_error_from_message(&derr, reply)) {
-		DBG("Agent reply: file descriptor passed successfully");
-		g_io_add_watch(gw->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-					(GIOFunc) rfcomm_disconnect_cb, dev);
-		change_state(dev, GATEWAY_STATE_CONNECTED);
-		goto done;
-	}
-
-	DBG("Agent reply: %s", derr.message);
-
-	dbus_error_free(&derr);
-	gateway_close(dev);
-
-done:
-	dbus_message_unref(reply);
-}
-
-static void rfcomm_connect_cb(GIOChannel *chan, GError *err,
-				gpointer user_data)
-{
-	struct audio_device *dev = user_data;
 	struct gateway *gw = dev->gateway;
 	DBusMessage *reply;
-	int sk, ret;
 
-	if (err) {
-		error("connect(): %s", err->message);
-		goto fail;
-	}
+	DBG("Service Level Connection established");
 
-	if (!gw->agent) {
-		error("Handsfree Agent not registered");
-		goto fail;
-	}
-
-	sk = g_io_channel_unix_get_fd(chan);
-
-	if (gw->rfcomm == NULL)
-		gw->rfcomm = g_io_channel_ref(chan);
-
-	ret = agent_sendfd(gw->agent, sk, newconnection_reply, dev);
+	change_state(dev, GATEWAY_STATE_CONNECTED);
 
 	if (!gw->msg)
 		return;
 
-	if (ret)
-		reply = dbus_message_new_method_return(gw->msg);
-	else
-		reply = btd_error_failed(gw->msg, "Can't pass file descriptor");
-
+	reply = dbus_message_new_method_return(gw->msg);
 	g_dbus_send_message(dev->conn, reply);
-
-	return;
-
-fail:
-	if (gw->msg) {
-		DBusMessage *reply;
-		reply = btd_error_failed(gw->msg, "Connect failed");
-		g_dbus_send_message(dev->conn, reply);
-	}
-
-	gateway_close(dev);
-}
-
-static int get_remote_profile_version(sdp_record_t *rec)
-{
-	uuid_t uuid;
-	sdp_list_t *profiles;
-	sdp_profile_desc_t *desc;
-	int ver = 0;
-
-	sdp_uuid16_create(&uuid, HANDSFREE_PROFILE_ID);
-
-	sdp_get_profile_descs(rec, &profiles);
-	if (profiles == NULL)
-		goto done;
-
-	desc = profiles->data;
-
-	if (sdp_uuid16_cmp(&desc->uuid, &uuid) == 0)
-		ver = desc->version;
-
-	sdp_list_free(profiles, free);
-
-done:
-	return ver;
+	dbus_message_unref(gw->msg);
+	gw->msg = NULL;
 }
 
-static void get_incoming_record_cb(sdp_list_t *recs, int err,
-					gpointer user_data)
+void gateway_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 {
 	struct audio_device *dev = user_data;
 	struct gateway *gw = dev->gateway;
-	GError *gerr = NULL;
+	char hs_address[18];
 
-	if (err < 0) {
-		error("Unable to get service record: %s (%d)", strerror(-err),
-					-err);
-		goto fail;
+	if (err) {
+		error("%s", err->message);
+		goto failed;
 	}
 
-	if (!recs || !recs->data) {
-		error("No records found");
-		goto fail;
-	}
+	ba2str(&dev->dst, hs_address);
 
-	gw->version = get_remote_profile_version(recs->data);
-	if (gw->version == 0)
-		goto fail;
+	if (!telephony_is_uuid_supported(device_get_adapter(dev->btd_dev),
+							gw->connecting_uuid))
+		goto failed;
 
-	rfcomm_connect_cb(gw->incoming, gerr, dev);
-	return;
+	gw->tel_dev = telephony_device_connecting(chan, dev->btd_dev, dev,
+							gw->connecting_uuid);
+	gw->connecting_uuid = NULL;
+	telephony_set_media_transport_path(gw->tel_dev,
+						gw->connecting_transport_path);
+	gw->connecting_transport_path = NULL;
 
-fail:
-	gateway_close(dev);
-}
-
-static void unregister_incoming(gpointer user_data)
-{
-	struct audio_device *dev = user_data;
-	struct gateway *gw = dev->gateway;
-
-	if (gw->incoming) {
-		g_io_channel_unref(gw->incoming);
-		gw->incoming = NULL;
+	if (gw->tmp_rfcomm) {
+		g_io_channel_unref(gw->tmp_rfcomm);
+		gw->tmp_rfcomm = NULL;
 	}
-}
 
-static void rfcomm_incoming_cb(GIOChannel *chan, GError *err,
-				gpointer user_data)
-{
-	struct audio_device *dev = user_data;
-	struct gateway *gw = dev->gateway;
-	uuid_t uuid;
-
-	gw->incoming = g_io_channel_ref(chan);
+	DBG("%s: Connected to %s", dev->path, hs_address);
 
-	sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID);
-	if (bt_search_service(&dev->src, &dev->dst, &uuid,
-						get_incoming_record_cb, dev,
-						unregister_incoming) == 0)
-		return;
+	return;
 
-	unregister_incoming(dev);
-	gateway_close(dev);
+failed:
+	gateway_set_state(dev, GATEWAY_STATE_DISCONNECTED);
 }
 
 static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
@@ -469,13 +315,6 @@ static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
 		goto fail;
 	}
 
-	gw->version = get_remote_profile_version(recs->data);
-	if (gw->version == 0) {
-		error("Unable to get profile version from record");
-		err = -EINVAL;
-		goto fail;
-	}
-
 	memcpy(&uuid, classes->data, sizeof(uuid));
 	sdp_list_free(classes, free);
 
@@ -496,7 +335,7 @@ static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
 		goto fail;
 	}
 
-	io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, dev, NULL, &gerr,
+	io = bt_io_connect(BT_IO_RFCOMM, gateway_connect_cb, dev, NULL, &gerr,
 				BT_IO_OPT_SOURCE_BDADDR, &dev->src,
 				BT_IO_OPT_DEST_BDADDR, &dev->dst,
 				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
@@ -515,6 +354,8 @@ fail:
 		DBusMessage *reply = btd_error_failed(gw->msg,
 					gerr ? gerr->message : strerror(-err));
 		g_dbus_send_message(dev->conn, reply);
+		dbus_message_unref(gw->msg);
+		gw->msg = NULL;
 	}
 
 	gateway_close(dev);
@@ -540,12 +381,22 @@ static DBusMessage *ag_connect(DBusConnection *conn, DBusMessage *msg,
 	struct gateway *gw = au_dev->gateway;
 	int err;
 
-	if (!gw->agent)
+	if (gw->state == GATEWAY_STATE_CONNECTING)
+		return btd_error_in_progress(msg);
+	else if (gw->state > GATEWAY_STATE_CONNECTING)
+		return btd_error_already_connected(msg);
+
+	if (!telephony_is_uuid_supported(device_get_adapter(au_dev->btd_dev),
+								HFP_HS_UUID))
 		return btd_error_agent_not_available(msg);
 
+	gw->connecting_uuid = HFP_HS_UUID;
+
 	err = get_records(au_dev);
-	if (err < 0)
+	if (err < 0) {
+		gw->connecting_uuid = NULL;
 		return btd_error_failed(msg, strerror(-err));
+	}
 
 	gw->msg = dbus_message_ref(msg);
 
@@ -558,13 +409,13 @@ int gateway_close(struct audio_device *device)
 	struct gateway *gw = device->gateway;
 	int sock;
 
-	if (gw->rfcomm) {
-		sock = g_io_channel_unix_get_fd(gw->rfcomm);
+	if (gw->tmp_rfcomm) {
+		sock = g_io_channel_unix_get_fd(gw->tmp_rfcomm);
 		shutdown(sock, SHUT_RDWR);
 
-		g_io_channel_shutdown(gw->rfcomm, TRUE, NULL);
-		g_io_channel_unref(gw->rfcomm);
-		gw->rfcomm = NULL;
+		g_io_channel_shutdown(gw->tmp_rfcomm, TRUE, NULL);
+		g_io_channel_unref(gw->tmp_rfcomm);
+		gw->tmp_rfcomm = NULL;
 	}
 
 	if (gw->sco) {
@@ -573,6 +424,14 @@ int gateway_close(struct audio_device *device)
 		gw->sco = NULL;
 	}
 
+	if (gw->tel_dev) {
+		telephony_device_disconnect(gw->tel_dev);
+		gw->tel_dev = NULL;
+	}
+
+	gw->connecting_uuid = NULL;
+	gw->connecting_transport_path = NULL;
+
 	change_state(device, GATEWAY_STATE_DISCONNECTED);
 	g_set_error(&gerr, GATEWAY_ERROR,
 			GATEWAY_ERROR_DISCONNECTED, "Disconnected");
@@ -586,16 +445,12 @@ static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
 	struct audio_device *device = data;
-	struct gateway *gw = device->gateway;
 	DBusMessage *reply = NULL;
 	char gw_addr[18];
 
 	if (!device->conn)
 		return NULL;
 
-	if (!gw->rfcomm)
-		return btd_error_not_connected(msg);
-
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return NULL;
@@ -607,17 +462,6 @@ static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg,
 	return reply;
 }
 
-static void agent_exited(DBusConnection *conn, void *data)
-{
-	struct gateway *gateway = data;
-	struct hf_agent *agent = gateway->agent;
-
-	DBG("Agent %s exited", agent->name);
-
-	agent_free(agent);
-	gateway->agent = NULL;
-}
-
 static DBusMessage *ag_get_properties(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
@@ -649,75 +493,12 @@ static DBusMessage *ag_get_properties(DBusConnection *conn, DBusMessage *msg,
 	return reply;
 }
 
-static DBusMessage *register_agent(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	struct audio_device *device = data;
-	struct gateway *gw = device->gateway;
-	struct hf_agent *agent;
-	const char *path, *name;
-
-	if (gw->agent)
-		return btd_error_already_exists(msg);
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-						DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	name = dbus_message_get_sender(msg);
-	agent = g_new0(struct hf_agent, 1);
-
-	agent->name = g_strdup(name);
-	agent->path = g_strdup(path);
-
-	agent->watch = g_dbus_add_disconnect_watch(conn, name,
-						agent_exited, gw, NULL);
-
-	gw->agent = agent;
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *unregister_agent(DBusConnection *conn,
-				DBusMessage *msg, void *data)
-{
-	struct audio_device *device = data;
-	struct gateway *gw = device->gateway;
-	const char *path;
-
-	if (!gw->agent)
-		goto done;
-
-	if (strcmp(gw->agent->name, dbus_message_get_sender(msg)) != 0)
-		return btd_error_not_authorized(msg);
-
-	if (!dbus_message_get_args(msg, NULL,
-				DBUS_TYPE_OBJECT_PATH, &path,
-				DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	if (strcmp(gw->agent->path, path) != 0)
-		return btd_error_does_not_exist(msg);
-
-	g_dbus_remove_watch(device->conn, gw->agent->watch);
-
-	agent_free(gw->agent);
-	gw->agent = NULL;
-
-done:
-	return dbus_message_new_method_return(msg);
-}
-
 static const GDBusMethodTable gateway_methods[] = {
 	{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, ag_connect) },
 	{ GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, ag_disconnect) },
 	{ GDBUS_METHOD("GetProperties",
 			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
 			ag_get_properties) },
-	{ GDBUS_METHOD("RegisterAgent",
-			GDBUS_ARGS({ "agent", "o" }), NULL, register_agent) },
-	{ GDBUS_METHOD("UnregisterAgent",
-			GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
 	{ }
 };
 
@@ -742,9 +523,6 @@ static void path_unregister(void *data)
 
 void gateway_unregister(struct audio_device *dev)
 {
-	if (dev->gateway->agent)
-		agent_disconnect(dev, dev->gateway->agent);
-
 	g_dbus_unregister_interface(dev->conn, dev->path,
 						AUDIO_GATEWAY_INTERFACE);
 }
@@ -785,13 +563,52 @@ int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
 	if (!io)
 		return -EINVAL;
 
-	dev->gateway->rfcomm = g_io_channel_ref(io);
+	dev->gateway->tmp_rfcomm = g_io_channel_ref(io);
 
 	change_state(dev, GATEWAY_STATE_CONNECTING);
 
 	return 0;
 }
 
+GIOChannel *gateway_get_rfcomm(struct audio_device *dev)
+{
+	struct gateway *gw = dev->gateway;
+
+	return gw->tmp_rfcomm;
+}
+
+void gateway_set_connecting_uuid(struct audio_device *dev, const char *uuid)
+{
+	struct gateway *gw = dev->gateway;
+
+	gw->connecting_uuid = uuid;
+}
+
+void gateway_set_media_transport_path(struct audio_device *dev,
+							const char *path)
+{
+	struct gateway *gw = dev->gateway;
+
+	DBG("MediaTransport path: %s", path);
+
+	if (gw->tel_dev == NULL) {
+		gw->connecting_transport_path = path;
+		return;
+	}
+
+	telephony_set_media_transport_path(gw->tel_dev, path);
+}
+
+const char *gateway_get_telephony_agent_name(struct audio_device *dev)
+{
+	struct gateway *gw = dev->gateway;
+
+	if (gw == NULL || gw->tel_dev == NULL)
+		return NULL;
+
+	return telephony_get_agent_name(gw->tel_dev);
+}
+
 int gateway_connect_sco(struct audio_device *dev, GIOChannel *io)
 {
 	struct gateway *gw = dev->gateway;
@@ -809,21 +626,6 @@ int gateway_connect_sco(struct audio_device *dev, GIOChannel *io)
 	return 0;
 }
 
-void gateway_start_service(struct audio_device *dev)
-{
-	struct gateway *gw = dev->gateway;
-	GError *err = NULL;
-
-	if (gw->rfcomm == NULL)
-		return;
-
-	if (!bt_io_accept(gw->rfcomm, rfcomm_incoming_cb, dev, NULL, &err)) {
-		error("bt_io_accept: %s", err->message);
-		g_error_free(err);
-		gateway_close(dev);
-	}
-}
-
 static gboolean request_stream_cb(gpointer data)
 {
 	run_connect_cb(data, NULL);
@@ -839,7 +641,7 @@ unsigned int gateway_request_stream(struct audio_device *dev,
 	GError *err = NULL;
 	GIOChannel *io;
 
-	if (!gw->rfcomm)
+	if (!gw->tel_dev)
 		get_records(dev);
 	else if (!gw->sco) {
 		io = bt_io_connect(BT_IO_SCO, sco_connect_cb, dev, NULL, &err,
@@ -866,7 +668,7 @@ int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t cb,
 
 	id = connect_cb_new(gw, cb, user_data);
 
-	if (!gw->rfcomm)
+	if (!gw->tel_dev)
 		get_records(dev);
 	else if (cb)
 		g_idle_add(request_stream_cb, dev);
diff --git a/audio/gateway.h b/audio/gateway.h
index 77f5787..b42fdf1 100644
--- a/audio/gateway.h
+++ b/audio/gateway.h
@@ -74,3 +74,11 @@ gboolean gateway_remove_state_cb(unsigned int id);
 gateway_lock_t gateway_get_lock(struct audio_device *dev);
 gboolean gateway_lock(struct audio_device *dev, gateway_lock_t lock);
 gboolean gateway_unlock(struct audio_device *dev, gateway_lock_t lock);
+
+void gateway_connect_cb(GIOChannel *chan, GError *err, gpointer user_data);
+void gateway_slc_complete(struct audio_device *dev);
+void gateway_set_connecting_uuid(struct audio_device *dev, const char *uuid);
+GIOChannel *gateway_get_rfcomm(struct audio_device *dev);
+void gateway_set_media_transport_path(struct audio_device *dev,
+							const char *path);
+const char *gateway_get_telephony_agent_name(struct audio_device *dev);
diff --git a/audio/manager.c b/audio/manager.c
index 4ab0186..5dcf52d 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -89,8 +89,6 @@ typedef enum {
 struct audio_adapter {
 	struct btd_adapter *btd_adapter;
 	gboolean powered;
-	uint32_t hfp_hs_record_id;
-	GIOChannel *hfp_hs_server;
 	gint ref;
 };
 
@@ -222,196 +220,6 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
 	}
 }
 
-static sdp_record_t *hfp_hs_record(uint8_t ch)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
-	uuid_t l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_record_t *record;
-	sdp_list_t *aproto, *proto[2];
-	sdp_data_t *channel;
-
-	record = sdp_record_alloc();
-	if (!record)
-		return NULL;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(record, root);
-
-	sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
-	profile.version = 0x0105;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &ch);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(record, aproto);
-
-	sdp_set_info_attr(record, "Hands-Free", 0, 0);
-
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(pfseq, 0);
-	sdp_list_free(aproto, 0);
-	sdp_list_free(root, 0);
-	sdp_list_free(svclass_id, 0);
-
-	return record;
-}
-
-static void gateway_auth_cb(DBusError *derr, void *user_data)
-{
-	struct audio_device *device = user_data;
-
-	if (derr && dbus_error_is_set(derr)) {
-		error("Access denied: %s", derr->message);
-		gateway_set_state(device, GATEWAY_STATE_DISCONNECTED);
-	} else {
-		char ag_address[18];
-
-		ba2str(&device->dst, ag_address);
-		DBG("Accepted AG connection from %s for %s",
-			ag_address, device->path);
-
-		gateway_start_service(device);
-	}
-}
-
-static void hf_io_cb(GIOChannel *chan, gpointer data)
-{
-	bdaddr_t src, dst;
-	GError *err = NULL;
-	uint8_t ch;
-	const char *server_uuid, *remote_uuid;
-	struct audio_device *device;
-	int perr;
-
-	bt_io_get(chan, BT_IO_RFCOMM, &err,
-			BT_IO_OPT_SOURCE_BDADDR, &src,
-			BT_IO_OPT_DEST_BDADDR, &dst,
-			BT_IO_OPT_CHANNEL, &ch,
-			BT_IO_OPT_INVALID);
-
-	if (err) {
-		error("%s", err->message);
-		g_error_free(err);
-		return;
-	}
-
-	server_uuid = HFP_HS_UUID;
-	remote_uuid = HFP_AG_UUID;
-
-	device = manager_get_device(&src, &dst, TRUE);
-	if (!device)
-		goto drop;
-
-	if (!device->gateway) {
-		btd_device_add_uuid(device->btd_dev, remote_uuid);
-		if (!device->gateway)
-			goto drop;
-	}
-
-	if (gateway_is_active(device)) {
-		DBG("Refusing new connection since one already exists");
-		goto drop;
-	}
-
-	if (gateway_connect_rfcomm(device, chan) < 0) {
-		error("Allocating new GIOChannel failed!");
-		goto drop;
-	}
-
-	perr = audio_device_request_authorization(device, server_uuid,
-						gateway_auth_cb, device);
-	if (perr < 0) {
-		DBG("Authorization denied: %s", strerror(-perr));
-		gateway_set_state(device, GATEWAY_STATE_DISCONNECTED);
-	}
-
-	return;
-
-drop:
-	g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
-static int gateway_server_init(struct audio_adapter *adapter)
-{
-	uint8_t chan = DEFAULT_HFP_HS_CHANNEL;
-	sdp_record_t *record;
-	gboolean master = TRUE;
-	GError *err = NULL;
-	GIOChannel *io;
-	bdaddr_t src;
-
-	if (config) {
-		gboolean tmp;
-
-		tmp = g_key_file_get_boolean(config, "General", "Master",
-						&err);
-		if (err) {
-			DBG("audio.conf: %s", err->message);
-			g_clear_error(&err);
-		} else
-			master = tmp;
-	}
-
-	adapter_get_address(adapter->btd_adapter, &src);
-
-	io = bt_io_listen(BT_IO_RFCOMM, NULL, hf_io_cb, adapter, NULL, &err,
-				BT_IO_OPT_SOURCE_BDADDR, &src,
-				BT_IO_OPT_CHANNEL, chan,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_MASTER, master,
-				BT_IO_OPT_INVALID);
-	if (!io) {
-		error("%s", err->message);
-		g_error_free(err);
-		return -1;
-	}
-
-	adapter->hfp_hs_server = io;
-	record = hfp_hs_record(chan);
-	if (!record) {
-		error("Unable to allocate new service record");
-		goto failed;
-	}
-
-	if (add_record_to_server(&src, record) < 0) {
-		error("Unable to register HFP HS service record");
-		sdp_record_free(record);
-		goto failed;
-	}
-
-	adapter->hfp_hs_record_id = record->handle;
-
-	return 0;
-
-failed:
-	g_io_channel_shutdown(adapter->hfp_hs_server, TRUE, NULL);
-	g_io_channel_unref(adapter->hfp_hs_server);
-	adapter->hfp_hs_server = NULL;
-	return -1;
-}
-
 static int audio_probe(struct btd_device *device, GSList *uuids)
 {
 	struct btd_adapter *adapter = device_get_adapter(device);
@@ -579,17 +387,12 @@ static void headset_server_remove(struct btd_adapter *adapter)
 static int gateway_server_probe(struct btd_adapter *adapter)
 {
 	struct audio_adapter *adp;
-	int err;
 
 	adp = audio_adapter_get(adapter);
 	if (!adp)
 		return -EINVAL;
 
-	err = gateway_server_init(adp);
-	if (err < 0)
-		audio_adapter_unref(adp);
-
-	return err;
+	return 0;
 }
 
 static void gateway_server_remove(struct btd_adapter *adapter)
@@ -603,17 +406,6 @@ static void gateway_server_remove(struct btd_adapter *adapter)
 	if (!adp)
 		return;
 
-	if (adp->hfp_hs_record_id) {
-		remove_record_from_server(adp->hfp_hs_record_id);
-		adp->hfp_hs_record_id = 0;
-	}
-
-	if (adp->hfp_hs_server) {
-		g_io_channel_shutdown(adp->hfp_hs_server, TRUE, NULL);
-		g_io_channel_unref(adp->hfp_hs_server);
-		adp->hfp_hs_server = NULL;
-	}
-
 	audio_adapter_unref(adp);
 }
 
diff --git a/audio/media.c b/audio/media.c
index c608c41..3e5d12d 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -647,6 +647,7 @@ static void gateway_state_changed(struct audio_device *dev,
 {
 	struct media_endpoint *endpoint = user_data;
 	struct media_transport *transport;
+	const char *path;
 
 	DBG("");
 
@@ -664,6 +665,13 @@ static void gateway_state_changed(struct audio_device *dev,
 	case GATEWAY_STATE_CONNECTING:
 		set_configuration(endpoint, dev, NULL, 0,
 					gateway_setconf_cb, dev, NULL);
+
+		transport = find_device_transport(endpoint, dev);
+		if (transport == NULL)
+			break;
+
+		path = media_transport_get_path(transport);
+		gateway_set_media_transport_path(dev, path);
 		break;
 	case GATEWAY_STATE_CONNECTED:
 		break;
@@ -743,9 +751,18 @@ static gboolean endpoint_init_hs(struct media_endpoint *endpoint, int *err)
 
 	for (l = list; l != NULL; l = l->next) {
 		struct audio_device *dev = l->data;
+		struct media_transport *transport;
+		const char *path;
 
 		set_configuration(endpoint, dev, NULL, 0,
 						gateway_setconf_cb, dev, NULL);
+
+		transport = find_device_transport(endpoint, dev);
+		if (transport == NULL)
+			break;
+
+		path = media_transport_get_path(transport);
+		gateway_set_media_transport_path(dev, path);
 	}
 
 	g_slist_free(list);
diff --git a/audio/telephony.c b/audio/telephony.c
index da1797f..dc76d60 100644
--- a/audio/telephony.c
+++ b/audio/telephony.c
@@ -48,6 +48,7 @@
 #include "glib-helper.h"
 #include "sdp-client.h"
 #include "headset.h"
+#include "gateway.h"
 #include "telephony.h"
 #include "dbus-common.h"
 #include "sdpd.h"
@@ -335,6 +336,44 @@ done:
 	dbus_message_unref(reply);
 }
 
+static gboolean ag_dev_disconnect_cb(GIOChannel *chan, GIOCondition cond,
+					gpointer data)
+{
+	struct telephony_device *tel_dev = data;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	gateway_set_state(tel_dev->au_dev, GATEWAY_STATE_DISCONNECTED);
+
+	return FALSE;
+}
+
+static void ag_newconnection_reply(DBusPendingCall *call, void *user_data)
+{
+	struct telephony_device *tel_dev = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		DBG("Agent reply: %s", derr.message);
+		dbus_error_free(&derr);
+		gateway_set_state(tel_dev->au_dev, GATEWAY_STATE_DISCONNECTED);
+		goto done;
+	}
+
+	DBG("Agent reply: file descriptor passed successfully");
+	g_io_add_watch(tel_dev->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			ag_dev_disconnect_cb, tel_dev);
+	gateway_slc_complete(tel_dev->au_dev);
+
+done:
+	dbus_pending_call_unref(tel_dev->call);
+	tel_dev->call = NULL;
+	dbus_message_unref(reply);
+}
+
 static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
 {
 	struct telephony_device *tel_dev = user_data;
@@ -390,7 +429,11 @@ static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
 	return;
 
 failed:
-	headset_set_state(tel_dev->au_dev, HEADSET_STATE_DISCONNECTED);
+	if (g_strcmp0(tel_dev->config->uuid, HSP_AG_UUID) == 0 ||
+			g_strcmp0(tel_dev->config->uuid, HFP_AG_UUID) == 0)
+		headset_set_state(tel_dev->au_dev, HEADSET_STATE_DISCONNECTED);
+	else if (g_strcmp0(tel_dev->config->uuid, HFP_HS_UUID) == 0)
+		gateway_set_state(tel_dev->au_dev, GATEWAY_STATE_DISCONNECTED);
 }
 
 struct telephony_device *telephony_device_connecting(GIOChannel *io,
@@ -468,6 +511,170 @@ const char *telephony_get_agent_name(struct telephony_device *device)
 	return device->name;
 }
 
+static sdp_record_t *hfp_hs_record(struct telephony_agent *agent)
+{
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+	uuid_t l2cap_uuid, rfcomm_uuid;
+	sdp_profile_desc_t profile;
+	sdp_list_t *aproto, *proto[2];
+	sdp_record_t *record;
+	sdp_data_t *channel, *features;
+	uint16_t sdpfeat;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(0, &root_uuid);
+	sdp_set_browse_groups(record, root);
+
+	sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &svclass_uuid);
+	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+	sdp_set_service_classes(record, svclass_id);
+
+	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+	profile.version = agent->version;
+	pfseq = sdp_list_append(0, &profile);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	apseq = sdp_list_append(0, proto[0]);
+
+	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+	proto[1] = sdp_list_append(0, &rfcomm_uuid);
+	channel = sdp_data_alloc(SDP_UINT8, &agent->config->channel);
+	proto[1] = sdp_list_append(proto[1], channel);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	sdpfeat = agent->features & 0x1F;
+	features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
+	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	sdp_set_info_attr(record, "Hands-Free", 0, 0);
+
+	sdp_data_free(channel);
+	sdp_list_free(proto[0], 0);
+	sdp_list_free(proto[1], 0);
+	sdp_list_free(apseq, 0);
+	sdp_list_free(pfseq, 0);
+	sdp_list_free(aproto, 0);
+	sdp_list_free(root, 0);
+	sdp_list_free(svclass_id, 0);
+
+	return record;
+}
+
+static void gateway_auth_cb(DBusError *derr, void *user_data)
+{
+	struct audio_device *au_dev = user_data;
+	GError *err = NULL;
+	GIOChannel *io;
+
+	if (au_dev->gw_preauth_id) {
+		g_source_remove(au_dev->gw_preauth_id);
+		au_dev->gw_preauth_id = 0;
+	}
+
+	if (derr && dbus_error_is_set(derr)) {
+		error("Access denied: %s", derr->message);
+		gateway_set_state(au_dev, GATEWAY_STATE_DISCONNECTED);
+		return;
+	}
+
+	io = gateway_get_rfcomm(au_dev);
+
+	if (!bt_io_accept(io, gateway_connect_cb, au_dev, NULL, &err)) {
+		error("bt_io_accept: %s", err->message);
+		g_error_free(err);
+		gateway_set_state(au_dev, GATEWAY_STATE_DISCONNECTED);
+		return;
+	}
+}
+
+static gboolean gateway_preauth_cb(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	struct audio_device *au_dev = user_data;
+
+	DBG("Gateway disconnected during authorization");
+
+	audio_device_cancel_authorization(au_dev, gateway_auth_cb, au_dev);
+
+	gateway_set_state(au_dev, GATEWAY_STATE_DISCONNECTED);
+
+	au_dev->gw_preauth_id = 0;
+
+	return FALSE;
+}
+
+static void hf_confirm(GIOChannel *chan, gpointer data)
+{
+	struct telephony_agent *agent = data;
+	struct audio_device *au_dev;
+	bdaddr_t src, dst;
+	int perr;
+	GError *err = NULL;
+	uint8_t ch;
+
+	bt_io_get(chan, BT_IO_RFCOMM, &err,
+			BT_IO_OPT_SOURCE_BDADDR, &src,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_CHANNEL, &ch,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	au_dev = manager_get_device(&src, &dst, TRUE);
+	if (!au_dev)
+		goto drop;
+
+	if (!au_dev->gateway) {
+		btd_device_add_uuid(au_dev->btd_dev, agent->config->r_uuid);
+		if (!au_dev->gateway)
+			goto drop;
+	}
+
+	if (gateway_is_active(au_dev)) {
+		DBG("Refusing new connection since one already exists");
+		goto drop;
+	}
+
+	gateway_set_connecting_uuid(au_dev, agent->config->uuid);
+
+	if (gateway_connect_rfcomm(au_dev, chan) < 0) {
+		error("Allocating new GIOChannel failed!");
+		goto drop;
+	}
+
+	perr = audio_device_request_authorization(au_dev, agent->config->uuid,
+						gateway_auth_cb, au_dev);
+	if (perr < 0) {
+		DBG("Authorization denied: %s", strerror(-perr));
+		gateway_set_state(au_dev, GATEWAY_STATE_DISCONNECTED);
+		return;
+	}
+
+	au_dev->gw_preauth_id = g_io_add_watch(chan,
+					G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+					gateway_preauth_cb, au_dev);
+
+	return;
+
+drop:
+	g_io_channel_shutdown(chan, TRUE, NULL);
+}
+
 static sdp_record_t *hsp_ag_record(struct telephony_agent *agent)
 {
 	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
@@ -728,6 +935,14 @@ static struct profile_config default_configs[] = {
 		hsp_ag_record,
 		ag_confirm,
 		hs_newconnection_reply },
+	{ HFP_HS_UUID,
+		DEFAULT_HF_HS_CHANNEL,
+		HFP_AG_UUID,
+		HANDSFREE_AGW_SVCLASS_ID,
+		HANDSFREE_PROFILE_ID,
+		hfp_hs_record,
+		hf_confirm,
+		ag_newconnection_reply },
 	{ HFP_AG_UUID,
 		DEFAULT_HF_AG_CHANNEL,
 		HFP_HS_UUID,
diff --git a/audio/transport.c b/audio/transport.c
index 7236e43..7a9b5ea 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -866,6 +866,10 @@ static gboolean check_telephony_agent_name(struct media_transport *transport,
 	if (tel_agent != NULL && g_strcmp0(tel_agent, sender) == 0)
 		return TRUE;
 
+	tel_agent = gateway_get_telephony_agent_name(transport->device);
+	if (tel_agent != NULL && g_strcmp0(tel_agent, sender) == 0)
+		return TRUE;
+
 	return FALSE;
 }
 
diff --git a/doc/hfp-api.txt b/doc/hfp-api.txt
index fad89ae..afc1277 100644
--- a/doc/hfp-api.txt
+++ b/doc/hfp-api.txt
@@ -22,24 +22,6 @@ Methods		void Connect()
 			Returns all properties for the interface. See the
 			properties section for available properties.
 
-		void RegisterAgent(object path)
-
-			The object path defines the path the of the agent
-			that will be called when a new Handsfree connection
-			is established.
-
-			If an application disconnects from the bus all of its
-			registered agents will be removed.
-
-		void UnregisterAgent(object path)
-
-			This unregisters the agent that has been previously
-			registered. The object path parameter must match the
-			same value that has been used on registration.
-
-			Possible Errors: org.bluez.Error.Failed
-					 org.bluez.Error.InvalidArguments
-
 
 Signals		PropertyChanged(string name, variant value)
 
@@ -54,31 +36,3 @@ Properties	string State [readonly]
 				"connecting"
 				"connected"
 				"playing"
-
-HandsfreeAgent hierarchy
-===============
-
-Service         unique name
-Interface       org.bluez.HandsfreeAgent
-Object path     freely definable
-
-Methods		void NewConnection(filedescriptor fd, uint16 version)
-
-			This method gets called whenever a new handsfree
-			connection has been established.  The objectpath
-			contains the object path of the remote device.
-
-			The agent should only return successfully once the
-			establishment of the service level connection (SLC)
-			has been completed.  In the case of Handsfree this
-			means that BRSF exchange has been performed and
-			necessary initialization has been done.
-
-			Possible Errors: org.bluez.Error.InvalidArguments
-					 org.bluez.Error.Failed
-
-		void Release()
-
-			This method gets called whenever the service daemon
-			unregisters the agent or whenever the Adapter where
-			the HandsfreeAgent registers itself is removed.
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 12/15] audio: Add DUN GW to org.bluez.Telephony
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (10 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 11/15] audio: Move HFP HF server to telephony.c Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 13/15] audio: Add SAP " Frédéric Danis
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

---
 audio/telephony.c |  302 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 295 insertions(+), 7 deletions(-)

diff --git a/audio/telephony.c b/audio/telephony.c
index dc76d60..f80986b 100644
--- a/audio/telephony.c
+++ b/audio/telephony.c
@@ -39,6 +39,7 @@
 
 #include "btio.h"
 #include "../src/adapter.h"
+#include "../src/manager.h"
 #include "../src/device.h"
 
 #include "log.h"
@@ -56,6 +57,7 @@
 #define AUDIO_TELEPHONY_INTERFACE "org.bluez.Telephony"
 #define AUDIO_TELEPHONY_AGENT_INTERFACE "org.bluez.TelephonyAgent"
 
+#define DEFAULT_DUN_GW_CHANNEL 1
 #define DEFAULT_HS_HS_CHANNEL 6
 #define DEFAULT_HS_AG_CHANNEL 12
 #define DEFAULT_HF_HS_CHANNEL 7
@@ -123,7 +125,8 @@ struct telephony_device {
 	struct profile_config	*config;	/* default configuration */
 	char			*name;		/* agent DBus bus id */
 	char			*path;		/* agent object path */
-	struct audio_device	*au_dev;	/* Audio device for HSP/HFP */
+	struct audio_device	*au_dev;	/* Audio device for HSP/HFP
+						 * or NULL for DUN/SAP */
 	uint16_t		version;	/* remote profile version */
 	uint16_t		features;	/* remote supported features */
 	GIOChannel		*rfcomm;	/* connected RFCOMM channel */
@@ -132,6 +135,21 @@ struct telephony_device {
 	DBusPendingCall		*call;		/* D-Bus pending call */
 };
 
+/*
+ * Connecting device
+ *
+ * Used for DUN and SAP gateway profiles in place of the audio device structure
+ * to store informations during connection phase, from device connection up to
+ * authentication completion.
+ */
+struct connecting_device {
+	const char		*uuid;
+	struct btd_device	*btd_dev;
+	bdaddr_t		src, dst;
+	GIOChannel		*tmp_rfcomm;
+	guint			preauth_id;
+};
+
 static DBusConnection *connection = NULL;
 
 static GSList *agents = NULL;	/* server list */
@@ -298,6 +316,201 @@ static gboolean agent_sendfd(struct telephony_device *tel_dev, int fd,
 	return TRUE;
 }
 
+static void rfcomm_channel_close(GIOChannel *chan)
+{
+	int sock;
+
+	sock = g_io_channel_unix_get_fd(chan);
+	shutdown(sock, SHUT_RDWR);
+
+	g_io_channel_shutdown(chan, TRUE, NULL);
+	g_io_channel_unref(chan);
+}
+
+static gboolean client_dev_disconnect_cb(GIOChannel *chan, GIOCondition cond,
+						gpointer data)
+{
+	struct telephony_device *tel_dev = data;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	rfcomm_channel_close(tel_dev->rfcomm);
+	tel_dev->rfcomm = NULL;
+	telephony_device_disconnect(tel_dev);
+
+	return FALSE;
+}
+
+static void client_newconnection_reply(DBusPendingCall *call,
+					void *user_data)
+{
+	struct telephony_device *tel_dev = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		DBG("Agent reply: %s", derr.message);
+		dbus_error_free(&derr);
+		rfcomm_channel_close(tel_dev->rfcomm);
+		tel_dev->rfcomm = NULL;
+		telephony_device_disconnect(tel_dev);
+		goto done;
+	}
+
+	DBG("Agent reply: file descriptor passed successfully");
+	g_io_add_watch(tel_dev->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			client_dev_disconnect_cb, tel_dev);
+
+done:
+	dbus_pending_call_unref(tel_dev->call);
+	tel_dev->call = NULL;
+	dbus_message_unref(reply);
+}
+
+static void client_connect_cb(GIOChannel *chan, GError *err,
+				gpointer user_data)
+{
+	struct connecting_device *client = user_data;
+	struct telephony_device *tel_dev;
+	char hs_address[18];
+
+	if (err) {
+		error("%s", err->message);
+		rfcomm_channel_close(client->tmp_rfcomm);
+		goto done;
+	}
+
+	ba2str(&client->dst, hs_address);
+
+	tel_dev = telephony_device_connecting(chan, client->btd_dev, NULL,
+						client->uuid);
+	if (tel_dev == NULL) {
+		rfcomm_channel_close(client->tmp_rfcomm);
+		goto done;
+	}
+
+	g_io_channel_unref(client->tmp_rfcomm);
+	client->tmp_rfcomm = NULL;
+
+	DBG("%s: Connected to %s", device_get_path(client->btd_dev),
+								hs_address);
+
+done:
+	g_free(client);
+
+	return;
+}
+
+static void client_auth_cb(DBusError *derr, void *user_data)
+{
+	struct connecting_device *client = user_data;
+	GError *err = NULL;
+
+	if (client->preauth_id) {
+		g_source_remove(client->preauth_id);
+		client->preauth_id = 0;
+	}
+
+	if (derr && dbus_error_is_set(derr)) {
+		error("Access denied: %s", derr->message);
+		goto failed;
+	}
+
+	if (!bt_io_accept(client->tmp_rfcomm, client_connect_cb, client, NULL,
+			  &err)) {
+		error("bt_io_accept: %s", err->message);
+		g_error_free(err);
+		goto failed;
+	}
+
+	return;
+
+failed:
+	rfcomm_channel_close(client->tmp_rfcomm);
+	g_free(client);
+}
+
+static gboolean client_preauth_cb(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	struct connecting_device *client = user_data;
+
+	DBG("Client for %s disconnected during authorization", client->uuid);
+
+	btd_cancel_authorization(&client->src, &client->dst);
+
+	rfcomm_channel_close(client->tmp_rfcomm);
+	g_free(client);
+
+	return FALSE;
+}
+
+static void client_confirm(GIOChannel *chan, gpointer data)
+{
+	struct telephony_agent *agent = data;
+	struct connecting_device *client;
+	struct btd_adapter *adapter;
+	struct btd_device *btd_dev;
+	char addr[18];
+	int perr;
+	GError *err = NULL;
+	uint8_t ch;
+
+	client = g_new0(struct connecting_device, 1);
+	client->tmp_rfcomm = g_io_channel_ref(chan);
+
+	bt_io_get(chan, BT_IO_RFCOMM, &err,
+			BT_IO_OPT_SOURCE_BDADDR, &client->src,
+			BT_IO_OPT_DEST_BDADDR, &client->dst,
+			BT_IO_OPT_CHANNEL, &ch,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	ba2str(&client->src, addr);
+
+	adapter = manager_find_adapter(&client->src);
+	if (!adapter) {
+		error("Unable to get a btd_adapter object for %s", addr);
+		goto drop;
+	}
+
+	ba2str(&client->dst, addr);
+
+	btd_dev = adapter_get_device(connection, adapter, addr);
+	if (!btd_dev) {
+		error("Unable to get btd_device object for %s", addr);
+		goto drop;
+	}
+
+	client->uuid = agent->config->uuid;
+	client->btd_dev = btd_dev;
+
+	perr = btd_request_authorization(&client->src, &client->dst,
+						agent->config->uuid,
+						client_auth_cb, client);
+	if (perr < 0) {
+		DBG("Authorization denied: %s", strerror(-perr));
+		goto drop;
+	}
+
+	client->preauth_id = g_io_add_watch(chan,
+					G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+					client_preauth_cb, client);
+
+	return;
+
+drop:
+	rfcomm_channel_close(client->tmp_rfcomm);
+
+	g_free(client);
+}
+
 static gboolean hs_dev_disconnect_cb(GIOChannel *chan, GIOCondition cond,
 					gpointer data)
 {
@@ -445,7 +658,8 @@ struct telephony_device *telephony_device_connecting(GIOChannel *io,
 	struct telephony_agent *agent;
 	struct telephony_device *tel_dev;
 	uuid_t r_uuid;
-	int err;
+	int sk;
+	int err = 0;
 
 	adapter = device_get_adapter(btd_dev);
 	agent = find_agent(adapter, NULL, NULL, uuid);
@@ -461,17 +675,29 @@ struct telephony_device *telephony_device_connecting(GIOChannel *io,
 	tel_dev->rfcomm = g_io_channel_ref(io);
 	tel_dev->features = 0xFFFF;
 
-	sdp_uuid16_create(&r_uuid, tel_dev->config->r_class);
+	if (tel_dev->config->r_class == 0) {
+		sk = g_io_channel_unix_get_fd(tel_dev->rfcomm);
+
+		if (agent_sendfd(tel_dev, sk, tel_dev->config->connection_reply)
+								== FALSE) {
+			error("Failed to send RFComm socket to agent %s," \
+				" path %s", tel_dev->name, tel_dev->path);
+			err = -1;
+		}
+	} else {
+		sdp_uuid16_create(&r_uuid, tel_dev->config->r_class);
+
+		err = bt_search_service(&au_dev->src, &au_dev->dst, &r_uuid,
+						get_record_cb, tel_dev, NULL);
+		if (!err)
+			tel_dev->pending_sdp = TRUE;
+	}
 
-	err = bt_search_service(&au_dev->src, &au_dev->dst, &r_uuid,
-				get_record_cb, tel_dev, NULL);
 	if (err < 0) {
 		telephony_device_disconnect(tel_dev);
 		return NULL;
 	}
 
-	tel_dev->pending_sdp = TRUE;
-
 	return tel_dev;
 }
 
@@ -511,6 +737,60 @@ const char *telephony_get_agent_name(struct telephony_device *device)
 	return device->name;
 }
 
+static sdp_record_t *dun_gw_record(struct telephony_agent *agent)
+{
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, svclass_uuid;
+	uuid_t l2cap_uuid, rfcomm_uuid;
+	sdp_profile_desc_t profile;
+	sdp_list_t *aproto, *proto[2];
+	sdp_record_t *record;
+	sdp_data_t *channel;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(0, &root_uuid);
+	sdp_set_browse_groups(record, root);
+
+	sdp_uuid16_create(&svclass_uuid, DIALUP_NET_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &svclass_uuid);
+	sdp_set_service_classes(record, svclass_id);
+
+	sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
+	profile.version = agent->version;
+	pfseq = sdp_list_append(0, &profile);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	apseq = sdp_list_append(0, proto[0]);
+
+	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+	proto[1] = sdp_list_append(0, &rfcomm_uuid);
+	channel = sdp_data_alloc(SDP_UINT8, &agent->config->channel);
+	proto[1] = sdp_list_append(proto[1], channel);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	sdp_set_info_attr(record, "Dial-up Networking", 0, 0);
+
+	sdp_data_free(channel);
+	sdp_list_free(proto[0], 0);
+	sdp_list_free(proto[1], 0);
+	sdp_list_free(apseq, 0);
+	sdp_list_free(pfseq, 0);
+	sdp_list_free(aproto, 0);
+	sdp_list_free(root, 0);
+	sdp_list_free(svclass_id, 0);
+
+	return record;
+}
+
 static sdp_record_t *hfp_hs_record(struct telephony_agent *agent)
 {
 	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
@@ -927,6 +1207,14 @@ drop:
 }
 
 static struct profile_config default_configs[] = {
+	{ DUN_GW_UUID,
+		DEFAULT_DUN_GW_CHANNEL,
+		NULL,
+		0,
+		0,
+		dun_gw_record,
+		client_confirm,
+		client_newconnection_reply },
 	{ HSP_AG_UUID,
 		DEFAULT_HS_AG_CHANNEL,
 		HSP_HS_UUID,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 13/15] audio: Add SAP GW to org.bluez.Telephony
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (11 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 12/15] audio: Add DUN GW to org.bluez.Telephony Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 14/15] adapter: Add API to get fast connectable mode Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 15/15] audio: Add fast connectable to telephony interface Frédéric Danis
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

---
 audio/telephony.c        |   72 +++++++++++++++++++++++++++++++++++++++++++++-
 doc/assigned-numbers.txt |    1 +
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/audio/telephony.c b/audio/telephony.c
index f80986b..5626985 100644
--- a/audio/telephony.c
+++ b/audio/telephony.c
@@ -62,6 +62,7 @@
 #define DEFAULT_HS_AG_CHANNEL 12
 #define DEFAULT_HF_HS_CHANNEL 7
 #define DEFAULT_HF_AG_CHANNEL 13
+#define DEFAULT_SAP_GW_CHANNEL 8
 
 struct telephony_agent;
 
@@ -79,6 +80,7 @@ struct telephony_agent;
 struct profile_config {
 	const char		*uuid;		/* agent property UUID */
 	uint8_t			channel;
+	BtIOSecLevel		sec_level;
 	const char		*r_uuid;
 	uint16_t		r_class;
 	uint16_t		r_profile;
@@ -852,6 +854,61 @@ static sdp_record_t *hfp_hs_record(struct telephony_agent *agent)
 	return record;
 }
 
+static sdp_record_t *sap_gw_record(struct telephony_agent *agent)
+{
+	sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
+	uuid_t sap_uuid, gt_uuid, root_uuid, l2cap, rfcomm;
+	sdp_profile_desc_t profile;
+	sdp_record_t *record;
+	sdp_data_t *ch;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(NULL, &root_uuid);
+	sdp_set_browse_groups(record, root);
+	sdp_list_free(root, NULL);
+
+	sdp_uuid16_create(&sap_uuid, SAP_SVCLASS_ID);
+	svclass_id = sdp_list_append(NULL, &sap_uuid);
+	sdp_uuid16_create(&gt_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &gt_uuid);
+
+	sdp_set_service_classes(record, svclass_id);
+	sdp_list_free(svclass_id, NULL);
+
+	sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID);
+	profile.version = agent->version;
+	profiles = sdp_list_append(NULL, &profile);
+	sdp_set_profile_descs(record, profiles);
+	sdp_list_free(profiles, NULL);
+
+	sdp_uuid16_create(&l2cap, L2CAP_UUID);
+	proto[0] = sdp_list_append(NULL, &l2cap);
+	apseq = sdp_list_append(NULL, proto[0]);
+
+	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+	proto[1] = sdp_list_append(NULL, &rfcomm);
+	ch = sdp_data_alloc(SDP_UINT8, &agent->config->channel);
+	proto[1] = sdp_list_append(proto[1], ch);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(NULL, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	sdp_set_info_attr(record, "SIM Access Server", NULL, NULL);
+
+	sdp_data_free(ch);
+	sdp_list_free(proto[0], NULL);
+	sdp_list_free(proto[1], NULL);
+	sdp_list_free(apseq, NULL);
+	sdp_list_free(aproto, NULL);
+
+	return record;
+}
+
 static void gateway_auth_cb(DBusError *derr, void *user_data)
 {
 	struct audio_device *au_dev = user_data;
@@ -1209,6 +1266,7 @@ drop:
 static struct profile_config default_configs[] = {
 	{ DUN_GW_UUID,
 		DEFAULT_DUN_GW_CHANNEL,
+		BT_IO_SEC_MEDIUM,
 		NULL,
 		0,
 		0,
@@ -1217,6 +1275,7 @@ static struct profile_config default_configs[] = {
 		client_newconnection_reply },
 	{ HSP_AG_UUID,
 		DEFAULT_HS_AG_CHANNEL,
+		BT_IO_SEC_MEDIUM,
 		HSP_HS_UUID,
 		HEADSET_SVCLASS_ID,
 		HEADSET_PROFILE_ID,
@@ -1225,6 +1284,7 @@ static struct profile_config default_configs[] = {
 		hs_newconnection_reply },
 	{ HFP_HS_UUID,
 		DEFAULT_HF_HS_CHANNEL,
+		BT_IO_SEC_MEDIUM,
 		HFP_AG_UUID,
 		HANDSFREE_AGW_SVCLASS_ID,
 		HANDSFREE_PROFILE_ID,
@@ -1233,12 +1293,22 @@ static struct profile_config default_configs[] = {
 		ag_newconnection_reply },
 	{ HFP_AG_UUID,
 		DEFAULT_HF_AG_CHANNEL,
+		BT_IO_SEC_MEDIUM,
 		HFP_HS_UUID,
 		HANDSFREE_SVCLASS_ID,
 		HANDSFREE_PROFILE_ID,
 		hfp_ag_record,
 		ag_confirm,
 		hs_newconnection_reply },
+	{ SAP_UUID,
+		DEFAULT_SAP_GW_CHANNEL,
+		BT_IO_SEC_HIGH,
+		NULL,
+		0,
+		0,
+		sap_gw_record,
+		client_confirm,
+		client_newconnection_reply },
 };
 
 static void agent_disconnect_cb(DBusConnection *conn, void *user_data)
@@ -1338,7 +1408,7 @@ static DBusMessage *register_agent(DBusConnection *conn,
 				agent, NULL, &err,
 				BT_IO_OPT_SOURCE_BDADDR, &src,
 				BT_IO_OPT_CHANNEL, agent->config->channel,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+				BT_IO_OPT_SEC_LEVEL, agent->config->sec_level,
 				BT_IO_OPT_MASTER, master,
 				BT_IO_OPT_INVALID);
 	if (agent->io == NULL) {
diff --git a/doc/assigned-numbers.txt b/doc/assigned-numbers.txt
index 120d7ea..bc85cf6 100644
--- a/doc/assigned-numbers.txt
+++ b/doc/assigned-numbers.txt
@@ -10,6 +10,7 @@ Profile		Channel
 DUN		1
 HSP HS		6
 HFP HF		7
+SAP		8
 OPP		9
 FTP		10
 BIP		11
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 14/15] adapter: Add API to get fast connectable mode
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (12 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 13/15] audio: Add SAP " Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  2012-08-03 12:07 ` [PATCH v17 15/15] audio: Add fast connectable to telephony interface Frédéric Danis
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

---
 src/adapter.c |   15 ++++++++++++++-
 src/adapter.h |    1 +
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/adapter.c b/src/adapter.c
index b7691d0..24fa704 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -151,6 +151,8 @@ struct btd_adapter {
 	GSList *pin_callbacks;
 
 	GSList *loaded_drivers;
+
+	gboolean fast_connectable;
 };
 
 static void dev_info_free(void *data)
@@ -3391,10 +3393,21 @@ void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
 int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
 							gboolean enable)
 {
+	int ret;
+
 	if (!adapter->up)
 		return -EINVAL;
 
-	return mgmt_set_fast_connectable(adapter->dev_id, enable);
+	ret = mgmt_set_fast_connectable(adapter->dev_id, enable);
+	if (ret == 0)
+		adapter->fast_connectable = enable;
+
+	return ret;
+}
+
+gboolean btd_adapter_get_fast_connectable(struct btd_adapter *adapter)
+{
+	return adapter->fast_connectable;
 }
 
 int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr,
diff --git a/src/adapter.h b/src/adapter.h
index d8a1bb1..6e22dbc 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -185,6 +185,7 @@ void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
  * type to default values. Valid for both connectable and discoverable modes. */
 int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
 							gboolean enable);
+gboolean btd_adapter_get_fast_connectable(struct btd_adapter *adapter);
 
 int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 				int which, int timeout, uint32_t *clock,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v17 15/15] audio: Add fast connectable to telephony interface
  2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
                   ` (13 preceding siblings ...)
  2012-08-03 12:07 ` [PATCH v17 14/15] adapter: Add API to get fast connectable mode Frédéric Danis
@ 2012-08-03 12:07 ` Frédéric Danis
  14 siblings, 0 replies; 21+ messages in thread
From: Frédéric Danis @ 2012-08-03 12:07 UTC (permalink / raw)
  To: linux-bluetooth

---
 audio/telephony.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 doc/audio-api.txt |   26 +++++++++++++
 2 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/audio/telephony.c b/audio/telephony.c
index 5626985..8efc520 100644
--- a/audio/telephony.c
+++ b/audio/telephony.c
@@ -185,8 +185,19 @@ static struct telephony_agent *find_agent(struct btd_adapter *adapter,
 
 static void free_agent(struct telephony_agent *agent)
 {
+	struct btd_adapter *adapter = agent->btd_adapter;
 	DBusMessage *msg;
 
+	/* if there is no more agent for this adapter and it has been set to
+	 * fast connectable mode, reset it to FALSE
+	 */
+	if (find_agent(adapter, NULL, NULL, NULL) == NULL &&
+			btd_adapter_get_fast_connectable(adapter)) {
+		if (btd_adapter_set_fast_connectable(adapter, FALSE))
+			error("Changing fast connectable for hci%d failed",
+				adapter_get_dev_id(adapter));
+	}
+
 	if (agent->record_id)
 		remove_record_from_server(agent->record_id);
 
@@ -1460,12 +1471,106 @@ static DBusMessage *unregister_agent(DBusConnection *conn,
 	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
+static DBusMessage *telephony_get_properties(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct btd_adapter *adapter = data;
+	gboolean fast_connectable;
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	/* FastConnectable */
+	fast_connectable = btd_adapter_get_fast_connectable(adapter);
+	dict_append_entry(&dict, "FastConnectable", DBUS_TYPE_BOOLEAN,
+			  &fast_connectable);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
+static DBusMessage *telephony_set_property(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct btd_adapter *adapter = data;
+	const char *property;
+	DBusMessageIter iter;
+	DBusMessageIter sub;
+	gboolean enable;
+	DBusMessage *reply;
+
+	if (!dbus_message_iter_init(msg, &iter))
+		return btd_error_invalid_args(msg);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&iter, &property);
+	dbus_message_iter_next(&iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+		return btd_error_invalid_args(msg);
+	dbus_message_iter_recurse(&iter, &sub);
+
+	if (g_str_equal("FastConnectable", property)) {
+		if (dbus_message_iter_get_arg_type(&sub) !=
+				DBUS_TYPE_BOOLEAN)
+			return btd_error_invalid_args(msg);
+
+		dbus_message_iter_get_basic(&sub, &enable);
+
+		reply = dbus_message_new_method_return(msg);
+		if (!reply)
+			return NULL;
+
+		if (btd_adapter_set_fast_connectable(adapter, enable)) {
+			error("Changing fast connectable for hci%d failed",
+				adapter_get_dev_id(adapter));
+			dbus_message_unref(reply);
+			return btd_error_failed(msg,
+					"Changing to fast connectable failed");
+		}
+
+		emit_property_changed(conn, adapter_get_path(adapter),
+					AUDIO_TELEPHONY_INTERFACE,
+					"FastConnectable",
+					DBUS_TYPE_BOOLEAN, &enable);
+		return reply;
+	}
+
+	return btd_error_invalid_args(msg);
+}
+
 static const GDBusMethodTable telsrv_methods[] = {
 	{ GDBUS_METHOD("RegisterAgent",
 			GDBUS_ARGS({ "agent", "o" }, { "properties", "a{sv}" }),
 			NULL, register_agent) },
 	{ GDBUS_METHOD("UnregisterAgent",
 			GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
+	{ GDBUS_METHOD("GetProperties",
+			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+			telephony_get_properties) },
+	{ GDBUS_METHOD("SetProperty",
+			GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+			telephony_set_property) },
+	{ }
+};
+
+static const GDBusSignalTable telsrv_signals[] = {
+	{ GDBUS_SIGNAL("PropertyChanged",
+			GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
 	{ }
 };
 
@@ -1484,7 +1589,7 @@ int telephony_adapter_init(struct btd_adapter *adapter)
 
 	if (!g_dbus_register_interface(connection, path,
 					AUDIO_TELEPHONY_INTERFACE,
-					telsrv_methods, NULL,
+					telsrv_methods, telsrv_signals,
 					NULL, adapter, path_unregister)) {
 		error("D-Bus failed to register %s interface",
 				AUDIO_TELEPHONY_INTERFACE);
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index e8bb210..3dd497f 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -335,6 +335,32 @@ Methods		void RegisterAgent(object path, dict properties)
 
 			Unregister sender agent.
 
+		dict GetProperties()
+
+			Returns all properties for the interface. See the
+			properties section for available properties.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void SetProperty(string name, variant value)
+
+			Changes the value of the specified property. Only
+			properties that are listed as read-write are changeable.
+			On success this will emit a PropertyChanged signal.
+
+			Possible Errors: org.bluez.Error.DoesNotExist
+					 org.bluez.Error.InvalidArguments
+
+Signals		void PropertyChanged(string name, variant value)
+
+			This signal indicates a changed value of the given
+			property.
+
+Properties	boolean FastConnectable  [readwrite]
+
+			Indicates if there is adapter is in fast connectable
+			mode.
+
 TelephonyAgent hierarchy
 ========================
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v17 01/15] doc: Add telephony interface documents
  2012-08-03 12:07 ` [PATCH v17 01/15] doc: Add telephony interface documents Frédéric Danis
@ 2012-08-05  4:37   ` Marcel Holtmann
  2012-08-06 20:30     ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 21+ messages in thread
From: Marcel Holtmann @ 2012-08-05  4:37 UTC (permalink / raw)
  To: Frédéric Danis; +Cc: linux-bluetooth

Hi Fred,

>  Makefile.am                    |    2 +-
>  doc/audio-api.txt              |   87 +++++++++++++++++++++++++++++++++
>  doc/audio-telephony-design.txt |  106 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 194 insertions(+), 1 deletion(-)
>  create mode 100644 doc/audio-telephony-design.txt

I looked at this, and we should split this into two patches as well. And
it should be leading with the design document.

> diff --git a/doc/audio-telephony-design.txt b/doc/audio-telephony-design.txt
> new file mode 100644
> index 0000000..a5936f6
> --- /dev/null
> +++ b/doc/audio-telephony-design.txt
> @@ -0,0 +1,106 @@

Can we please get a proper design document. Something that introduces
the problem, describes the goal and how we are trying to achieve it.

> +The org.bluez.Telephony interface will simplify BlueZ code by focusing on
> +the Bluetooth communication part and by letting the external application (i.e.
> +oFono) take charge of the Telephony tasks (AT parsing and modem specific code).
> +So, it becomes simpler, easier to maintain and debug.
> +
> +External applications, which should implement AT parsing and telephony
> +part of HeadSet or HandsFree Profiles, will have to register an

Please use Headset and Handsfree in writing. And unless part of the
profile name itself, it is lower case profiles.

> +org.bluez.TelephonyAgent using this new interface. This will setup a SDP record
> +for the profile and a RFCOMM server listening for incoming connection.
> +
> +When a new device is connected, NewConnection method of TelephonyAgent is
> +called. The telephony agent should reply to it after proper communication
> +establishment (directly for HSP or after SLC setup completes for HFP).

We need to describe on how HFP 1.6 with wideband speech is handled as
well.

> +Interaction with the audio component (i.e. PulseAudio) will be done through the
> +MediaTransport object (passed to telephony agent during NewConnection call).

This is the one thing that is really unclear to me. How does this
actually help. The MediaTransport and TelephonyAgent should be
independent.

> +Here is some flowcharts of interactions between BlueZ, telephony agent (oFono)
> +and audio component (PulseAudio):
> +
> +        .....>  Bluetooth communication between headset and phone
> +        ----->  Dbus messages and signals
> +
> +SCO connection - AG initiated
> +
> +	PulseAudio              BlueZ             HF
> +	|                         |               |
> +	|    transport acquire    |               |
> +	|------------------------>|               |
> +	|                         |  connect SCO  |
> +	|                         |<.............>|
> +	|      return SCO fd      |               |
> +	|<------------------------|               |
> +	|                         |               |

For every diagram it needs to have some sort of description.

> +
> +SCO connection - HF initiated
> +
> +	PulseAudio              BlueZ             HF
> +	|                         |               |
> +	|                         |  connect SCO  |
> +	|                         |<.............>|
> +	|  state changed signal   |               |
> +	|<------------------------|               |
> +	|                         |               |
> +	|    transport acquire    |               |
> +	|------------------------>|               |
> +	|                         |               |
> +	|      return SCO fd      |               |
> +	|<------------------------|               |
> +	|                         |               |
> +
> +AT+NREC
> +
> +	HF              oFono           BlueZ           PulseAudio
> +	|     AT+NREC     |               |                  |
> +	|................>|               |                  |
> +	|                 |  SetProperty  |                  |
> +	|                 |-------------->|                  |
> +	|                 |               | property changed |
> +	|                 |               |      signal      |
> +	|                 |               |----------------->|
> +
> +
> ++BSIR
> +
> +	HF          oFono         BlueZ        PulseAudio        app
> +	|             |             |               |             |
> +	|             |             |               |<------------|
> +	|             |             |  SetProperty  |             |
> +	|             |             |<--------------|             |
> +	|             |             |               |             |
> +	|             |   property changed signal   |             |
> +	|             |<------------*-------------->|             |
> +	|   +BSIR:x   |             |               |             |
> +	|<............|             |               |             |
> +	|             |             |               |             |
> +
> +
> +AT+VGS,AT+VGM
> +
> +	HF          oFono         BlueZ        PulseAudio        app
> +	|             |             |               |             |
> +	|  AT+VGS=xx  |             |               |             |
> +	|............>|             |               |             |
> +	|             | SetProperty |               |             |
> +	|             |------------>|               |             |
> +	|             |             |               |             |
> +	|             |   property changed signal   |             |
> +	|             |<------------*-------------->|             |
> +	|             |             |               |------------>|
> +	|             |             |               |             |
> +
> +
> ++VGS,+VGM
> +
> +	HF          oFono         BlueZ        PulseAudio        app
> +	|             |             |               |             |
> +	|             |             |               |<------------|
> +	|             |             |  SetProperty  |             |
> +	|             |             |<--------------|             |
> +	|             |             |               |             |
> +	|             |   property changed signal   |             |
> +	|             |<------------*-------------->|             |
> +	|   +VGS:xx   |             |               |             |
> +	|<............|             |               |------------>|
> +	|             |             |               |             |

Regards

Marcel



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v17 01/15] doc: Add telephony interface documents
  2012-08-05  4:37   ` Marcel Holtmann
@ 2012-08-06 20:30     ` Luiz Augusto von Dentz
  2012-08-09 10:03       ` Frederic Danis
  0 siblings, 1 reply; 21+ messages in thread
From: Luiz Augusto von Dentz @ 2012-08-06 20:30 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: Frédéric Danis, linux-bluetooth

Hi Marcel,

On Sun, Aug 5, 2012 at 7:37 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
>> +org.bluez.TelephonyAgent using this new interface. This will setup a SDP record
>> +for the profile and a RFCOMM server listening for incoming connection.
>> +
>> +When a new device is connected, NewConnection method of TelephonyAgent is
>> +called. The telephony agent should reply to it after proper communication
>> +establishment (directly for HSP or after SLC setup completes for HFP).
>
> We need to describe on how HFP 1.6 with wideband speech is handled as
> well.

I need to look in detail when the audio configuration is done in HFP
1.6, in any case a the transport object can be used to signal wideband
speech which PulseAudio should be able to catch and setup sbc
encoder/decoder, iirc the parameters are fixed so there is no need to
negotiate parameters with the endpoint as in A2DP so oFono only need
to know if the transport is capable of wideband speech or not.

>> +Interaction with the audio component (i.e. PulseAudio) will be done through the
>> +MediaTransport object (passed to telephony agent during NewConnection call).
>
> This is the one thing that is really unclear to me. How does this
> actually help. The MediaTransport and TelephonyAgent should be
> independent.

They are mostly independent, oFono will never really acquire or
anything like that, but there are some AT commands (+VGS,+VGM) that
does notify PA about volume gain changes and as I said above it could
be useful to notify about wideband speech in the same way.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v17 01/15] doc: Add telephony interface documents
  2012-08-06 20:30     ` Luiz Augusto von Dentz
@ 2012-08-09 10:03       ` Frederic Danis
  2012-08-09 14:42         ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 21+ messages in thread
From: Frederic Danis @ 2012-08-09 10:03 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, Marcel Holtmann; +Cc: linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 2468 bytes --]

Hello Marcel and Luiz,

On 06/08/2012 22:30, Luiz Augusto von Dentz wrote:
> Hi Marcel,
>
> On Sun, Aug 5, 2012 at 7:37 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
>>> +org.bluez.TelephonyAgent using this new interface. This will setup a SDP record
>>> +for the profile and a RFCOMM server listening for incoming connection.
>>> +
>>> +When a new device is connected, NewConnection method of TelephonyAgent is
>>> +called. The telephony agent should reply to it after proper communication
>>> +establishment (directly for HSP or after SLC setup completes for HFP).
>>
>> We need to describe on how HFP 1.6 with wideband speech is handled as
>> well.
>
> I need to look in detail when the audio configuration is done in HFP
> 1.6, in any case a the transport object can be used to signal wideband
> speech which PulseAudio should be able to catch and setup sbc
> encoder/decoder, iirc the parameters are fixed so there is no need to
> negotiate parameters with the endpoint as in A2DP so oFono only need
> to know if the transport is capable of wideband speech or not.
>
>>> +Interaction with the audio component (i.e. PulseAudio) will be done through the
>>> +MediaTransport object (passed to telephony agent during NewConnection call).
>>
>> This is the one thing that is really unclear to me. How does this
>> actually help. The MediaTransport and TelephonyAgent should be
>> independent.
>
> They are mostly independent, oFono will never really acquire or
> anything like that, but there are some AT commands (+VGS,+VGM) that
> does notify PA about volume gain changes and as I said above it could
> be useful to notify about wideband speech in the same way.
>

It is also possible that telephony agent implements a TelephonyClient 
interface for each connection, object which should be returned by 
NewConnection method.
In this case BlueZ will listen to properties changes on this interface 
(like for remote volume change) or call SetProperty (when receiving 
volume change from PulseAudio).

As MediaTransport may change during wideband speech HFP session, due to 
codec re-negotiation, this architecture may simplify media transport code.

You can find attached design documentation and telephony interfaces APIs 
proposal for this new architecture.

What are your advices regarding this ?

Regards

Fred

-- 
Frederic Danis                            Open Source Technology Center
frederic.danis@intel.com                              Intel Corporation


[-- Attachment #2: audio-telephony-design-new.txt --]
[-- Type: text/plain, Size: 14532 bytes --]

Telephony Interface Design
**************************

Introduction
============

The aim of this document is to briefly describe the telephony interface which
will allow external application to implement telephony related profiles
(headset, handsfree, dial-up networking and sim access).


The goal
========

Previous version of headset code in BlueZ needs the implementation of an AT
parser for each modem target or external telephony application (Maemo, oFono)
which is not the aim of Bluez.

The telephony interface allows BlueZ to focus on Bluetooth communication part
(connection, disconnection, authentication, authorization) and let external
application (i.e. oFono) take charge of the Telephony tasks (AT parsing and
modem specific code).
This will allow code to be simpler, easier to maintain and debug in both BlueZ
and telephony application.


Design
======

External applications, which should implement AT parsing and telephony part
will have to register an org.bluez.TelephonyAgent using this new interface.
This will setup a SDP record for the profile and a RFCOMM server listening for
incoming connection.

When a new device is connected, NewConnection method of TelephonyAgent is
called. The telephony agent must reply with a TelephonyClient object after
proper communication establishment (after SLC setup completes for HFP, or
directly for other profiles).

For Headset and Handsfree profiles, the interaction with the audio component
(i.e. PulseAudio) will be done by listening to TelephonyClient properties
changes.


Flow charts
===========

Here is some flowcharts of interactions between BlueZ, telephony agent (oFono)
and audio component (PulseAudio):

        .....>  Bluetooth communication between headset and phone
        ----->  Dbus messages and signals

Outgoing SCO connection - HFP <= 1.5
------------------------------------

When PulseAudio needs to setup the audio connection it will call media
transport acquire method. This will perform a SCO connection and return the SCO
socket file descriptor to PulseAUdio.

	PulseAudio              BlueZ           HF/AG
	|                         |               |
	|    transport acquire    |               |
	|------------------------>|               |
	|                         |  connect SCO  |
	|                         |..............>|
	|      return SCO fd      |               |
	|<------------------------|               |
	|                         |               |

Incoming SCO connection - HFP <= 1.5
------------------------------------

On an incoming SCO connection the profile will change to playing state.
On reception of this state change, PulseAudio will call media transport acquire
method to retrieve the SCO socket file descriptor.

	PulseAudio              BlueZ           HF/AG
	|                         |               |
	|                         |  connect SCO  |
	|                         |<..............|
	|  state changed signal   |               |
	|<------------------------|               |
	|                         |               |
	|    transport acquire    |               |
	|------------------------>|               |
	|                         |               |
	|      return SCO fd      |               |
	|<------------------------|               |
	|                         |               |

Outgoing SCO connection - HFP AG - HFP v1.6
-------------------------------------------

On media transport acquire, the TelephonyClient is called to perform codec
negociation with the headset (if needed) and return the id of selected codec.
If current media transport does not use this codec it will be re-configured
with the correct one.
Then SCO link will be connected and its socket file descriptor will be returned
to PulseAudio.

	PulseAudio             BlueZ             oFono        HF
	|                        |                 |           |
	|   transport acquire    |                 |           |
	|----------------------->|                 |           |
	|                        |    get codec    |           |
	|                        |---------------->|           |
	|                        |                 |  +BCS:id  |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 | AT+BCS=id |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |..........>|
	|                        | return codec id |           |
	|                        |<----------------|           |
	| re-configure Transport |                 |           |
	|        if needed       |                 |           |
	|<-----------------------|                 |           |
	|                        |         connect SCO         |
	|                        |............................>|
	|      return SCO fd     |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |

Incoming SCO connection - HFP AG - HFP v1.6
-------------------------------------------

It is pretty the same here as for outgoing SCO connection, except that it is
started upon reception of AT+BCC from the headset.

	PulseAudio           BlueZ              oFono         HF
	|                      |                  |            |
	|                      |                  |   AT+BCC   |
	|                      |                  |<...........|
	|                      |                  |            |
	|                      |                  |     OK     |
	|                      |                  |...........>|
	|                      |    connection    |            |
	|                      | requested signal |            |
	|                      |<-----------------|            |
	| state changed signal |                  |            |
	|<---------------------|                  |            |
	|                      |                  |            |
	| /--------------------------------------------------\ |
	|/    Outgoing SCO connection - HFP AG - HFP v1.6     \|
	|\                                                    /|
	| \--------------------------------------------------/ |


Outgoing SCO connection - HFP HF - HFP v1.6
-------------------------------------------

On media transport acquire, the TelephonyClient is called to perform codec
negociation with the gateway (if needed) and return the id of selected codec.
If current media transport does not use this codec it will be re-configured
with the right one.
Then incoming SCO socket file descriptor will be returned to PulseAudio.

	PulseAudio             BlueZ             oFono        AG
	|                        |                 |           |
	|   transport acquire    |                 |           |
	|----------------------->|                 |           |
	|                        |    get codec    |           |
	|                        |---------------->|           |
	|                        |                 |  AT+BCC   |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |                 |  +BCS:id  |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |                 | AT+BCS=id |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |<..........|
	|                        | return codec id |           |
	|                        |<----------------|           |
	| re-configure Transport |                 |           |
	|        if needed       |                 |           |
	|<-----------------------|                 |           |
	|                        |          connect SCO        |
	|                        |<............................|
	|      return SCO fd     |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |

Incoming SCO connection - HFP HF - HFP v1.6
-------------------------------------------

When codec negotiation is completed, TelephonyClient will signal the
selected codec to BlueZ.
If current media transport does not use this codec it will be re-configured
with the correct one.
Next incoming SCO connection will change profile to playing state.
Upon reception of this state change, PulseAudio will call media transport
acquire method to retrieve the SCO socket file descriptor.

	PulseAudio             BlueZ             oFono        AG
	|                        |                 |           |
	|                        |                 |  +BCS:id  |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |                 | AT+BCS=id |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |<..........|
	|                        | codec property  |           |
	|                        | changed signal  |           |
	|                        |<----------------|           |
	| re-configure Transport |                 |           |
	|        if needed       |                 |           |
	|<-----------------------|                 |           |
	|                        |          connect SCO        |
	|                        |<............................|
	|  state changed signal  |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |
	|   transport acquire    |                 |           |
	|----------------------->|                 |           |
	|                        |                 |           |
	|     return SCO fd      |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |

AT+NREC - HFP AG
----------------

Reception of AT+NREC will be signaled to Bluez by TelephonyClient.
This will update the NREC property of media transport interface (listened by
PulseAudio).

	HF          oFono            BlueZ         PulseAudio
	|   AT+NREC   |                |                |
	|............>|                |                |
	|             |    property    |                |
	|             | changed signal |                |
	|             |--------------->|                |
	|     OK      |                |    property    |
	|<............|                | changed signal |
	|             |                |--------------->|
	|             |                |                |

+BSIR - HFP AG
--------------

PulseAudio can change in-band ring tone by calling SetProperty method of media
transport interface.
This will call SetProperty of TelephonyClient interface, which will send the
proper +BSIR unsollicited event.

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|             |                |                |<------------|
	|             |                |  SetProperty   |             |
	|             |                |<---------------|             |
	|             |  SetProperty   |                |             |
	|             |<---------------|                |             |
	|   +BSIR:x   |                |                |             |
	|<............|                |                |             |
	|             |    property    |                |             |
	|             | changed signal |                |             |
	|             |--------------->|                |             |
	|             |                |                |             |

AT+VGS,AT+VGM - HFP AG
----------------------

Reception of volume management command will be signaled to Bluez by
TelephonyClient.
This will update the corresponding volume property of media transport interface
(listened by PulseAudio).

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|  AT+VGS=xx  |                |                |             |
	|............>|                |                |             |
	|             |    property    |                |             |
	|             | changed signal |                |             |
	|             |--------------->|                |             |
	|     OK      |                |                |             |
	|<............|                |    property    |             |
	|             |                | changed signal |             |
	|             |                |--------------->|             |
	|             |                |                |------------>|
	|             |                |                |             |

+VGS,+VGM - HFP AG
------------------

PulseAudio can change volume by calling SetProperty method of media transport
interface.
This will call SetProperty of TelephonyClient interface, which will send the
proper +VGx unsollicited event.

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|             |                |                |<------------|
	|             |                |  SetProperty   |             |
	|             |                |<---------------|             |
	|             |  SetProperty   |                |             |
	|             |<---------------|                |             |
	|   +VGS:xx   |                |    property    |             |
	|<............|                | changed signal |             |
	|             |    property    |--------------->|             |
	|             | changed signal |                |------------>|
	|             |--------------->|                |             |
	|             |                |                |             |

[-- Attachment #3: audio-api-new.txt --]
[-- Type: text/plain, Size: 4333 bytes --]

Telephony hierarchy
===================

Service		org.bluez
Interface	org.bluez.Telephony
Object path	[variable prefix]/{hci0,hci1,...}

Methods		void RegisterAgent(object path, dict properties)

			Register a TelephonyAgent to sender, the sender can
			register as many agents as it likes.
			Object path should be unique for an agent and a UUID.

			Note: If the sender disconnects its agents are
			automatically unregistered.

			possible properties:

				string UUID:

					UUID of the profile which the agent is
					for.

				uint16 Version:

					Version of the profile which the agent
					implements.

				uint16 Features:

					Agent supported features as defined in
					profile spec e.g. HFP.

			Possible Errors: org.bluez.Error.InvalidArguments

		void UnregisterAgent(object path)

			Unregister sender agent.

		dict GetProperties()

			Returns all properties for the interface. See the
			properties section for available properties.

			Possible Errors: org.bluez.Error.InvalidArguments

		void SetProperty(string name, variant value)

			Changes the value of the specified property. Only
			properties that are listed as read-write are changeable.
			On success this will emit a PropertyChanged signal.

			Possible Errors: org.bluez.Error.DoesNotExist
					 org.bluez.Error.InvalidArguments

Signals		void PropertyChanged(string name, variant value)

			This signal indicates a changed value of the given
			property.

Properties	boolean FastConnectable  [readwrite]

			Indicates if there is adapter in fast connectable mode.

TelephonyAgent hierarchy
========================

Service		unique name
Interface	org.bluez.TelephonyAgent
Object path	freely definable

Methods		object NewConnection(filedescriptor fd, dict properties)

			Returns a TelephonyClient object for the connection.

			This method gets called whenever a new connection
			has been established. This method assumes that D-Bus
			daemon with file descriptor passing capability is
			being used.

			The agent should only return successfully once the
			establishment of the service level connection (SLC)
			has been completed.  In the case of Handsfree this
			means that BRSF exchange has been performed and
			necessary initialization has been done.

			possible properties:

				object Device:

					BlueZ remote device object.

				uint16 Version:

					Remote profile version.

				uint16 Features:

					Optional. Remote profile features.

				string Codecs:

					Optional. List of supported audio
					codec ids separeted by a comma.

			Possible Errors: org.bluez.Error.InvalidArguments
					 org.bluez.Error.Failed

		void Release()

			This method gets called whenever the service daemon
			unregisters the agent or whenever the Adapter where
			the TelephonyAgent registers itself is removed.

TelephonyClient hierarchy
========================

Service		unique name
Interface	org.bluez.TelephonyClient
Object path	freely definable

Methods		dict GetProperties()

			Returns all properties for the interface. See the
			properties section for available properties.

			Possible Errors: org.bluez.Error.InvalidArguments

		void SetProperty(string name, variant value)

			Changes the value of the specified property. Only
			properties that are listed as read-write are changeable.
			On success this will emit a PropertyChanged signal.

			Possible Errors: org.bluez.Error.DoesNotExist
					 org.bluez.Error.InvalidArguments

		byte GetAudioCodec()

			Returns the codec to use for upcoming audio connection.
			This may start a new codec negotiation if needed.

Signals		void PropertyChanged(string name, variant value)

			This signal indicates a changed value of the given
			property.

		void AudioConnectionRequested()

			This signal indicates that remote has requested an audio
			connection.

Properties	byte	AudioCodec [readonly]

			Optional. Indicates the currently selected audio codec.

		boolean NREC [readwrite]

			Optional. Indicates if echo cancelling and noise
			reduction functions are active.

		boolean InbandRingtone [readwrite]

			Optional. Indicates if sending ringtones is supported.

		uint16 OutputGain  [readwrite]

			Optional. The speaker gain when available.

			Possible values: 0-15

		uint16 InputGain  [readwrite]

			Optional. The microphone gain when available.

			Possible values: 0-15

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v17 01/15] doc: Add telephony interface documents
  2012-08-09 10:03       ` Frederic Danis
@ 2012-08-09 14:42         ` Luiz Augusto von Dentz
  2012-08-10 10:09           ` Frederic Danis
  0 siblings, 1 reply; 21+ messages in thread
From: Luiz Augusto von Dentz @ 2012-08-09 14:42 UTC (permalink / raw)
  To: Frederic Danis; +Cc: Marcel Holtmann, linux-bluetooth

Hi Frederic,

On Thu, Aug 9, 2012 at 1:03 PM, Frederic Danis
<frederic.danis@linux.intel.com> wrote:
>> They are mostly independent, oFono will never really acquire or
>> anything like that, but there are some AT commands (+VGS,+VGM) that
>> does notify PA about volume gain changes and as I said above it could
>> be useful to notify about wideband speech in the same way.
>>
>
> It is also possible that telephony agent implements a TelephonyClient
> interface for each connection, object which should be returned by
> NewConnection method.

You should return the properties as well to avoid another round trip
to get the properties of the client. Btw this requires yet another
object and interface that increases the complexity of the solution.

> In this case BlueZ will listen to properties changes on this interface (like
> for remote volume change) or call SetProperty (when receiving volume change
> from PulseAudio).
>
> As MediaTransport may change during wideband speech HFP session, due to
> codec re-negotiation, this architecture may simplify media transport code.

I don't think we need to do the codec negotiation on acquire, it
actually doesn't work since the transport cannot be reconfigured with
another codec as by design the endpoints can only have 1 codec, so I
suggest having the list of available codecs be given upfront in
NewConnection then you actually negotiate the codec before responding.
If the remote device attempts to change the codec oFono then can check
if the codec is available in the list of available codecs given on
NewConnection, if it find a match then it accepts and emit a signal of
codec changes that triggers a new transport to be configured.

Btw, Im not sure if this is really productive to discuss before we
even have this working with 1.5, IMO is easier to do things step by
step and the first step should be to get HFP 1.5 working as the
current upstream does then we think about 1.6 and other profiles such
as DUN and SAP.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v17 01/15] doc: Add telephony interface documents
  2012-08-09 14:42         ` Luiz Augusto von Dentz
@ 2012-08-10 10:09           ` Frederic Danis
  0 siblings, 0 replies; 21+ messages in thread
From: Frederic Danis @ 2012-08-10 10:09 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: Marcel Holtmann, linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 2931 bytes --]

Hello Luiz,

On 09/08/2012 16:42, Luiz Augusto von Dentz wrote:
> Hi Frederic,
>
> On Thu, Aug 9, 2012 at 1:03 PM, Frederic Danis
> <frederic.danis@linux.intel.com> wrote:
>>> They are mostly independent, oFono will never really acquire or
>>> anything like that, but there are some AT commands (+VGS,+VGM) that
>>> does notify PA about volume gain changes and as I said above it could
>>> be useful to notify about wideband speech in the same way.
>>>
>>
>> It is also possible that telephony agent implements a TelephonyClient
>> interface for each connection, object which should be returned by
>> NewConnection method.
>
> You should return the properties as well to avoid another round trip
> to get the properties of the client. Btw this requires yet another
> object and interface that increases the complexity of the solution.

OK, I add the client properties to return of NewConnection.

I agree with you this increase complexity, but as media transport is 
linked to the codec it uses I do not find another solution.

>> In this case BlueZ will listen to properties changes on this interface (like
>> for remote volume change) or call SetProperty (when receiving volume change
>> from PulseAudio).
>>
>> As MediaTransport may change during wideband speech HFP session, due to
>> codec re-negotiation, this architecture may simplify media transport code.
>
> I don't think we need to do the codec negotiation on acquire, it
> actually doesn't work since the transport cannot be reconfigured with
> another codec as by design the endpoints can only have 1 codec, so I
> suggest having the list of available codecs be given upfront in
> NewConnection then you actually negotiate the codec before responding.

Yes , I pass them in NewConnection method.

> If the remote device attempts to change the codec oFono then can check
> if the codec is available in the list of available codecs given on
> NewConnection, if it find a match then it accepts and emit a signal of
> codec changes that triggers a new transport to be configured.

In HFP 1.6 specs (chapter 4.11.3, page 32) I saw that after codec 
negotiation "the AG shall open the synchronous connection". This may 
imply that we will need to do it when PA tries to use HFP audio connection.

> Btw, Im not sure if this is really productive to discuss before we
> even have this working with 1.5, IMO is easier to do things step by
> step and the first step should be to get HFP 1.5 working as the
> current upstream does then we think about 1.6 and other profiles such
> as DUN and SAP.

I agree with you that most important point is to get a working HFP 1.5, 
but moving to HFP 1.6 may break the telephony interface if we do not 
take a look at it now.

Find attached new version of documents proposal.

Regards

Fred

-- 
Frederic Danis                            Open Source Technology Center
frederic.danis@intel.com                              Intel Corporation


[-- Attachment #2: audio-telephony-design-new.txt --]
[-- Type: text/plain, Size: 14300 bytes --]

Telephony Interface Design
**************************

Introduction
============

The aim of this document is to briefly describe the telephony interface which
will allow external application to implement telephony related profiles
(headset, handsfree, dial-up networking and sim access).


The goal
========

Previous version of headset code in BlueZ needs the implementation of an AT
parser for each modem target or external telephony application (Maemo, oFono)
which is not the aim of Bluez.

The telephony interface allows BlueZ to focus on Bluetooth communication part
(connection, disconnection, authentication, authorization) and let external
application (i.e. oFono) take charge of the Telephony tasks (AT parsing and
modem specific code).
This will allow code to be simpler, easier to maintain and debug in both BlueZ
and telephony application.


Design
======

External applications, which should implement AT parsing and telephony part
will have to register an org.bluez.TelephonyAgent using this new interface.
This will setup a SDP record for the profile and a RFCOMM server listening for
incoming connection.

When a new device is connected, NewConnection method of TelephonyAgent is
called. The telephony agent must reply with a TelephonyClient object after
proper communication establishment (after SLC setup completes for HFP, or
directly for other profiles).

For Headset and Handsfree profiles, the interaction with the audio component
(i.e. PulseAudio) will be done by listening to TelephonyClient properties
changes.


Flow charts
===========

Here is some flowcharts of interactions between BlueZ, telephony agent (oFono)
and audio component (PulseAudio):

        .....>  Bluetooth communication between headset and phone
        ----->  Dbus messages and signals

Outgoing SCO connection - HFP <= 1.5
------------------------------------

When PulseAudio needs to setup the audio connection it will call media
transport acquire method. This will perform a SCO connection and return the SCO
socket file descriptor to PulseAUdio.

	PulseAudio              BlueZ           HF/AG
	|                         |               |
	|    transport acquire    |               |
	|------------------------>|               |
	|                         |  connect SCO  |
	|                         |..............>|
	|      return SCO fd      |               |
	|<------------------------|               |
	|                         |               |

Incoming SCO connection - HFP <= 1.5
------------------------------------

On an incoming SCO connection the profile will change to playing state.
On reception of this state change, PulseAudio will call media transport acquire
method to retrieve the SCO socket file descriptor.

	PulseAudio              BlueZ           HF/AG
	|                         |               |
	|                         |  connect SCO  |
	|                         |<..............|
	|  state changed signal   |               |
	|<------------------------|               |
	|                         |               |
	|    transport acquire    |               |
	|------------------------>|               |
	|                         |               |
	|      return SCO fd      |               |
	|<------------------------|               |
	|                         |               |

Codec negotiation - HFP AG - HFP v1.6
-------------------------------------------

On reception of HF available codecs command (AT+BAC), the gateway may start a
codec selection procedure which will end up by codec property update and setup
of the correct media transport.
When a media transport already exists and it uses a different codec, it should
be closed before correct one is setup. 

	PulseAudio          BlueZ            oFono           HF
	|                     |                |              |
	|                     |                | AT+BAC=u1,u2 |
	|                     |                |<.............|
	|                     |                |              |
	|                     |                |      OK      |
	|                     |                |.............>|
	|                     |                |              |
	|                     |                |   +BCS:id    |
	|                     |                |.............>|
	|                     |                |              |
	|                     |                |  AT+BCS=id   |
	|                     |                |<.............|
	|                     |                |              |
	|                     |                |      OK      |
	|                     |                |.............>|
	|                     | codec property |              |
	|                     | changed signal |              |
	|                     |<---------------|              |
	| configure Transport |                |              |
	|<--------------------|                |              |
	|                     |                |              |

It may also ne possible to force a codec selection procedure by calling "get
audio codec" procedure of TelephonyClient.

	PulseAudio          BlueZ             oFono          HF
	|                     |                 |             |
	|                     |    get codec    |             |
	|                     |---------------->|             |
	|                     |                 |   +BCS:id   |
	|                     |                 |............>|
	|                     |                 |             |
	|                     |                 |  AT+BCS=id  |
	|                     |                 |<............|
	|                     |                 |             |
	|                     |                 |      OK     |
	|                     |                 |............>|
	|                     | codec property  |             |
	|                     | changed signal  |             |
	|                     |<----------------|             |
	| configure Transport |                 |             |
	|<--------------------|                 |             |
	|                     |                 |             |

Outgoing SCO connection - HFP AG - HFP v1.6
-------------------------------------------

Idem than for HFP v1.5

Incoming SCO connection - HFP AG - HFP v1.6
-------------------------------------------

It is pretty the same here as for outgoing SCO connection, except that it is
started upon reception of AT+BCC from the headset.

	PulseAudio           BlueZ              oFono         HF
	|                      |                  |            |
	|                      |                  |   AT+BCC   |
	|                      |                  |<...........|
	|                      |                  |            |
	|                      |                  |     OK     |
	|                      |                  |...........>|
	|                      |    connection    |            |
	|                      | requested signal |            |
	|                      |<-----------------|            |
	|                      |                  |            |
	|                      |          connect SCO          |
	|                      |..............................>|
	| state changed signal |                  |            |
	|<---------------------|                  |            |
	|                      |                  |            |
	|  transport acquire   |                  |            |
	|--------------------->|                  |            |
	|                      |                  |            |
	|    return SCO fd     |                  |            |
	|<---------------------|                  |            |


Codec negotiation - HFP HF - HFP v1.6
-------------------------------------------

Codec selection procedure started by gateway will end up by codec property
update and setup of the correct media transport.
When a media transport already exists and it uses a different codec, it should
be closed before correct one is setup. 

	PulseAudio          BlueZ            oFono           HF
	|                     |                |              |
	|                     |                |   +BCS:id    |
	|                     |                |<.............|
	|                     |                |              |
	|                     |                |  AT+BCS=id   |
	|                     |                |.............>|
	|                     |                |              |
	|                     |                |      OK      |
	|                     |                |<.............|
	|                     | codec property |              |
	|                     | changed signal |              |
	|                     |<---------------|              |
	| configure Transport |                |              |
	|<--------------------|                |              |
	|                     |                |              |

Outgoing SCO connection - HFP HF - HFP v1.6
-------------------------------------------

On media transport acquire, the TelephonyClient is called to request connection
from the gateway.
Then incoming SCO socket file descriptor will be returned to PulseAudio.

	PulseAudio             BlueZ             oFono        AG
	|                        |                 |           |
	|   transport acquire    |                 |           |
	|----------------------->|                 |           |
	|                        |    request      |           |
	|                        |   connection    |           |
	|                        |---------------->|           |
	|                        |                 |  AT+BCC   |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |          connect SCO        |
	|                        |<............................|
	|      return SCO fd     |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |

Incoming SCO connection - HFP HF - HFP v1.6
-------------------------------------------

Idem than for HFP v1.5

AT+NREC - HFP AG
----------------

Reception of AT+NREC will be signaled to Bluez by TelephonyClient.
This will update the NREC property of media transport interface (listened by
PulseAudio).

	HF          oFono            BlueZ         PulseAudio
	|   AT+NREC   |                |                |
	|............>|                |                |
	|             |    property    |                |
	|             | changed signal |                |
	|             |--------------->|                |
	|     OK      |                |    property    |
	|<............|                | changed signal |
	|             |                |--------------->|
	|             |                |                |

+BSIR - HFP AG
--------------

PulseAudio can change in-band ring tone by calling SetProperty method of media
transport interface.
This will call SetProperty of TelephonyClient interface, which will send the
proper +BSIR unsollicited event.

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|             |                |                |<------------|
	|             |                |  SetProperty   |             |
	|             |                |<---------------|             |
	|             |  SetProperty   |                |             |
	|             |<---------------|                |             |
	|   +BSIR:x   |                |                |             |
	|<............|                |                |             |
	|             |    property    |                |             |
	|             | changed signal |                |             |
	|             |--------------->|                |             |
	|             |                |                |             |

AT+VGS,AT+VGM - HFP AG
----------------------

Reception of volume management command will be signaled to Bluez by
TelephonyClient.
This will update the corresponding volume property of media transport interface
(listened by PulseAudio).

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|  AT+VGS=xx  |                |                |             |
	|............>|                |                |             |
	|             |    property    |                |             |
	|             | changed signal |                |             |
	|             |--------------->|                |             |
	|     OK      |                |                |             |
	|<............|                |    property    |             |
	|             |                | changed signal |             |
	|             |                |--------------->|             |
	|             |                |                |------------>|
	|             |                |                |             |

+VGS,+VGM - HFP AG
------------------

PulseAudio can change volume by calling SetProperty method of media transport
interface.
This will call SetProperty of TelephonyClient interface, which will send the
proper +VGx unsollicited event.

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|             |                |                |<------------|
	|             |                |  SetProperty   |             |
	|             |                |<---------------|             |
	|             |  SetProperty   |                |             |
	|             |<---------------|                |             |
	|   +VGS:xx   |                |    property    |             |
	|<............|                | changed signal |             |
	|             |    property    |--------------->|             |
	|             | changed signal |                |------------>|
	|             |--------------->|                |             |
	|             |                |                |             |

[-- Attachment #3: audio-api-new.txt --]
[-- Type: text/plain, Size: 4413 bytes --]

Telephony hierarchy
===================

Service		org.bluez
Interface	org.bluez.Telephony
Object path	[variable prefix]/{hci0,hci1,...}

Methods		void RegisterAgent(object path, dict properties)

			Register a TelephonyAgent to sender, the sender can
			register as many agents as it likes.
			Object path should be unique for an agent and a UUID.

			Note: If the sender disconnects its agents are
			automatically unregistered.

			possible properties:

				string UUID:

					UUID of the profile which the agent is
					for.

				uint16 Version:

					Version of the profile which the agent
					implements.

				uint16 Features:

					Agent supported features as defined in
					profile spec e.g. HFP.

			Possible Errors: org.bluez.Error.InvalidArguments

		void UnregisterAgent(object path)

			Unregister sender agent.

		dict GetProperties()

			Returns all properties for the interface. See the
			properties section for available properties.

			Possible Errors: org.bluez.Error.InvalidArguments

		void SetProperty(string name, variant value)

			Changes the value of the specified property. Only
			properties that are listed as read-write are changeable.
			On success this will emit a PropertyChanged signal.

			Possible Errors: org.bluez.Error.DoesNotExist
					 org.bluez.Error.InvalidArguments

Signals		void PropertyChanged(string name, variant value)

			This signal indicates a changed value of the given
			property.

Properties	boolean FastConnectable  [readwrite]

			Indicates if there is adapter in fast connectable mode.

TelephonyAgent hierarchy
========================

Service		unique name
Interface	org.bluez.TelephonyAgent
Object path	freely definable

Methods		object, dict properties NewConnection(filedescriptor fd,
		                                      dict properties)

			Returns a TelephonyClient object for the connection
			with its properties.

			This method gets called whenever a new connection
			has been established. This method assumes that D-Bus
			daemon with file descriptor passing capability is
			being used.

			The agent should only return successfully once the
			establishment of the service level connection (SLC)
			has been completed.  In the case of Handsfree this
			means that BRSF exchange has been performed and
			necessary initialization has been done.

			possible properties:

				object Device:

					BlueZ remote device object.

				uint16 Version:

					Remote profile version.

				uint16 Features:

					Optional. Remote profile features.

				string Codecs:

					Optional. List of supported audio
					codec ids separeted by a comma.

			Possible Errors: org.bluez.Error.InvalidArguments
					 org.bluez.Error.Failed

		void Release()

			This method gets called whenever the service daemon
			unregisters the agent or whenever the Adapter where
			the TelephonyAgent registers itself is removed.

TelephonyClient hierarchy
========================

Service		unique name
Interface	org.bluez.TelephonyClient
Object path	freely definable

Methods		dict GetProperties()

			Returns all properties for the interface. See the
			properties section for available properties.

			Possible Errors: org.bluez.Error.InvalidArguments

		void SetProperty(string name, variant value)

			Changes the value of the specified property. Only
			properties that are listed as read-write are changeable.
			On success this will emit a PropertyChanged signal.

			Possible Errors: org.bluez.Error.DoesNotExist
					 org.bluez.Error.InvalidArguments

		byte GetAudioCodec()

			Returns the codec to use for upcoming audio connection.
			This may start a new codec negotiation if needed.

Signals		void PropertyChanged(string name, variant value)

			This signal indicates a changed value of the given
			property.

		void AudioConnectionRequested()

			This signal indicates that remote has requested an audio
			connection.

Properties	byte	AudioCodec [readonly]

			Optional. Indicates the currently selected audio codec.

		boolean NREC [readwrite]

			Optional. Indicates if echo cancelling and noise
			reduction functions are active.

		boolean InbandRingtone [readwrite]

			Optional. Indicates if sending ringtones is supported.

		uint16 OutputGain  [readwrite]

			Optional. The speaker gain when available.

			Possible values: 0-15

		uint16 InputGain  [readwrite]

			Optional. The microphone gain when available.

			Possible values: 0-15

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2012-08-10 10:09 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-03 12:07 [PATCH v17 00/15] Add org.bluez.Telephony interface Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 01/15] doc: Add telephony interface documents Frédéric Danis
2012-08-05  4:37   ` Marcel Holtmann
2012-08-06 20:30     ` Luiz Augusto von Dentz
2012-08-09 10:03       ` Frederic Danis
2012-08-09 14:42         ` Luiz Augusto von Dentz
2012-08-10 10:09           ` Frederic Danis
2012-08-03 12:07 ` [PATCH v17 02/15] doc: Add HSP HS channel to assigned numbers Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 03/15] audio: Move telephony drivers to D-Bus interface Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 04/15] audio: Simplify org.bluez.Headset Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 05/15] audio: Remove dummy telephony driver Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 06/15] audio: Remove maemo5 " Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 07/15] audio: Remove maemo6 " Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 08/15] audio: Remove oFono " Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 09/15] audio: Move HFP/HSP AG servers to telephony.c Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 10/15] audio: Send transport path to telephony agent Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 11/15] audio: Move HFP HF server to telephony.c Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 12/15] audio: Add DUN GW to org.bluez.Telephony Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 13/15] audio: Add SAP " Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 14/15] adapter: Add API to get fast connectable mode Frédéric Danis
2012-08-03 12:07 ` [PATCH v17 15/15] audio: Add fast connectable to telephony interface Frédéric Danis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.