public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] oFonoHFP profile to enable audio routing in BlueZ
@ 2009-11-12  7:50 Zhang, Zhenhua
  2009-11-12 16:48 ` Gustavo F. Padovan
  2009-11-13  1:01 ` Zhang, Zhenhua
  0 siblings, 2 replies; 5+ messages in thread
From: Zhang, Zhenhua @ 2009-11-12  7:50 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org

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

Hi,

These three patches are created to enable audio routing for Handsfree Profile.
It was created during the voicecall driver implementation in oFono so it does
not use the new hfp-api yet. You can take it as reference only since it will
not be commited into trunk.

Basically, a new profile oFonoHFP was added to create RFCOMM connection
and turn IO into TTY device for oFono. It sends TTY device string to oFono
through D-Bus. Meanwhile, it listens oFono property changes to emit CallStarted
and CallEnded signals. PulseAudio could listen these signals and redirect audio
source/sink to use bluetooth one.

If you are interested at it, you may apply 0001..0003 into BlueZ, oFono and PA
respectively. Last commit SHA-1 is in patch note.

And you need to enable oFonoHFP by modify audio.conf:
	Disable=Gateway
	Enable=oFonoHFP, Headset

In ofono modem.conf, specify device address like:
	[hfp]
	Driver=hfp
	Address=00:22:A9:8C:AF:34

And power on modem by:
	dbus-send --system --print-reply --dest=org.ofono /hfp0
org.ofono.Modem.SetProperty string:Powered variant:boolean:true

The PulseAudio will load module-bluetooth-discover automatically. If not,
please load it manually. This module listens BlueZ signal and load
module-bluetooth-device automatically. Unfortunately, you need to load
module-loopback manually to redirect bluez source/sink to alsa, e.g.:
	load-module module-loopback source="bluez_source.XX..XX"
sink="alsa_output.0.analog-stereo"
	load-module module-loopback source="alsa_input.0.analog-stereo"
sink="bluez_sink.XX..XX"

Feel free to let me know if any problems. Thanks.

Regards,
Zhenhua
 

[-- Attachment #2: 0001-oFonoHFP-Add-oFonoHFP-profile-in-BlueZ.patch --]
[-- Type: application/octet-stream, Size: 19430 bytes --]

From 32367e0f96b25a0c60a9fe5f3886484c54b840e3 Mon Sep 17 00:00:00 2001
From: Zhenhua Zhang <zhenhua.zhang@intel.com>
Date: Thu, 12 Nov 2009 22:24:15 +0800
Subject: [PATCH 1/3] oFonoHFP: Add oFonoHFP profile in BlueZ

The oFonoHFP profile is used to provide service for oFono HFP
telephony plugins. It exposes two methods: Connect and Disconnect,
and two properties: Device and Connected.

Once oFono request to create connection with Bluetooth device, it
creates the rfcomm connection and turns io into a TTY device. And
it returns TTY device name to oFono through D-Bus. It listens
oFono property changes to emit CallStarted and CallEnded signal
to PulseAudio.

Last commit: 515274df91e470472a
---
 Makefile.am       |    1 +
 audio/device.c    |    5 ++
 audio/device.h    |    3 +-
 audio/main.c      |   14 ++++
 audio/manager.c   |  193 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 audio/manager.h   |    1 +
 audio/unix.c      |  120 +++++++++++++++++++++++++++++++--
 doc/audio-api.txt |   37 ++++++++++
 8 files changed, 358 insertions(+), 16 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index d360acb..2aeba67 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -121,6 +121,7 @@ builtin_sources += audio/main.c \
 			audio/avdtp.h audio/avdtp.c \
 			audio/ipc.h audio/ipc.c \
 			audio/unix.h audio/unix.c \
+			audio/ofono-hfp.h audio/ofono-hfp.c \
 			audio/telephony.h
 builtin_nodist += audio/telephony.c
 
diff --git a/audio/device.c b/audio/device.c
index eef2aab..63af7b5 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -57,6 +57,7 @@
 #include "control.h"
 #include "headset.h"
 #include "gateway.h"
+#include "ofono-hfp.h"
 #include "sink.h"
 #include "source.h"
 
@@ -647,6 +648,10 @@ gboolean audio_device_is_active(struct audio_device *dev,
 	else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway &&
 				gateway_is_connected(dev))
 		return TRUE;
+	else if (!strcmp(interface, AUDIO_OFONO_HFP_INTERFACE)
+				&& dev->ofono_hfp
+				&& ofono_hfp_is_connected(dev))
+		return TRUE;
 
 	return FALSE;
 }
diff --git a/audio/device.h b/audio/device.h
index c899d20..05f7cff 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -48,6 +48,7 @@ struct target;
 struct sink;
 struct headset;
 struct gateway;
+struct ofono_hfp;
 struct dev_priv;
 
 struct audio_device {
@@ -62,11 +63,11 @@ struct audio_device {
 
 	struct headset *headset;
 	struct gateway *gateway;
+	struct ofono_hfp *ofono_hfp;
 	struct sink *sink;
 	struct source *source;
 	struct control *control;
 	struct target *target;
-
 	guint hs_preauth_id;
 
 	struct dev_priv *priv;
diff --git a/audio/main.c b/audio/main.c
index 9defe60..3a15709 100644
--- a/audio/main.c
+++ b/audio/main.c
@@ -46,6 +46,7 @@
 #include "headset.h"
 #include "manager.h"
 #include "gateway.h"
+#include "ofono-hfp.h"
 
 static GIOChannel *sco_server = NULL;
 
@@ -98,6 +99,11 @@ static void sco_server_cb(GIOChannel *chan, GError *err, gpointer data)
 						FALSE);
 
 	if (!device)
+		device = manager_find_device(NULL, &src, &dst,
+						AUDIO_OFONO_HFP_INTERFACE,
+						FALSE);
+
+	if (!device)
 		goto drop;
 
 	if (device->headset) {
@@ -124,6 +130,14 @@ static void sco_server_cb(GIOChannel *chan, GError *err, gpointer data)
 
 		if (gateway_connect_sco(device, chan) < 0)
 			goto drop;
+	} else if (device->ofono_hfp) {
+		if (!ofono_hfp_is_connected(device)) {
+			debug("Refusing SCO from non-connected AG");
+			goto drop;
+		}
+
+		if (ofono_hfp_connect_sco(device, chan) < 0)
+			goto drop;
 	} else
 		goto drop;
 
diff --git a/audio/manager.c b/audio/manager.c
index c63e98a..96a622f 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -64,6 +64,7 @@
 #include "a2dp.h"
 #include "headset.h"
 #include "gateway.h"
+#include "ofono-hfp.h"
 #include "sink.h"
 #include "source.h"
 #include "control.h"
@@ -74,11 +75,12 @@
 typedef enum {
 	HEADSET	= 1 << 0,
 	GATEWAY	= 1 << 1,
-	SINK	= 1 << 2,
-	SOURCE	= 1 << 3,
-	CONTROL	= 1 << 4,
-	TARGET	= 1 << 5,
-	INVALID	= 1 << 6
+	OFONO_HFP = 1 << 2,
+	SINK	= 1 << 3,
+	SOURCE	= 1 << 4,
+	CONTROL	= 1 << 5,
+	TARGET	= 1 << 6,
+	INVALID	= 1 << 7
 } audio_service_type;
 
 typedef enum {
@@ -110,6 +112,7 @@ static struct enabled_interfaces enabled = {
 	.hfp		= TRUE,
 	.headset	= TRUE,
 	.gateway	= FALSE,
+	.ofono_hfp	= FALSE,
 	.sink		= TRUE,
 	.source		= FALSE,
 	.control	= TRUE,
@@ -140,7 +143,7 @@ gboolean server_is_enabled(bdaddr_t *src, uint16_t svc)
 	case HANDSFREE_SVCLASS_ID:
 		return enabled.headset && enabled.hfp;
 	case HANDSFREE_AGW_SVCLASS_ID:
-		return enabled.gateway;
+		return enabled.gateway || enabled.ofono_hfp;
 	case AUDIO_SINK_SVCLASS_ID:
 		return enabled.sink;
 	case AUDIO_SOURCE_SVCLASS_ID:
@@ -198,8 +201,11 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
 		break;
 	case HANDSFREE_AGW_SVCLASS_ID:
 		debug("Found Handsfree AG record");
-		if (device->gateway == NULL)
+		if (enabled.gateway && (device->gateway == NULL))
 			device->gateway = gateway_init(device);
+
+		if (enabled.ofono_hfp && (device->ofono_hfp == NULL))
+			device->ofono_hfp = ofono_hfp_init(device);
 		break;
 	case AUDIO_SINK_SVCLASS_ID:
 		debug("Found Audio Sink");
@@ -545,6 +551,23 @@ static void gateway_auth_cb(DBusError *derr, void *user_data)
 	}
 }
 
+static void ofono_hfp_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);
+	else {
+		char ag_address[18];
+
+		ba2str(&device->dst, ag_address);
+		debug("Accepted AG connection from %s for %s",
+			ag_address, device->path);
+
+		ofono_hfp_start_service(device);
+	}
+}
+
 static void hf_io_cb(GIOChannel *chan, gpointer data)
 {
 	bdaddr_t src, dst;
@@ -606,6 +629,67 @@ drop:
 	return;
 }
 
+static void ofono_hf_io_cb(GIOChannel *chan, gpointer data)
+{
+	bdaddr_t src, dst;
+	GError *err = NULL;
+	uint8_t ch;
+	const char *server_uuid, *remote_uuid;
+	uint16_t svclass;
+	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;
+	svclass = HANDSFREE_AGW_SVCLASS_ID;
+
+	device = manager_get_device(&src, &dst, TRUE);
+	if (!device)
+		goto drop;
+
+	if (!device->ofono_hfp) {
+		btd_device_add_uuid(device->btd_dev, remote_uuid);
+		if (!device->ofono_hfp)
+			goto drop;
+	}
+
+	if (ofono_hfp_is_connected(device)) {
+		debug("Refusing new connection since one already exists");
+		goto drop;
+	}
+
+	if (ofono_hfp_connect_rfcomm(device, chan, ch) < 0) {
+		error("Allocating new GIOChannel failed!");
+		goto drop;
+	}
+
+	perr = audio_device_request_authorization(device, server_uuid,
+						ofono_hfp_auth_cb, device);
+	if (perr < 0) {
+		debug("Authorization denied!");
+		goto drop;
+	}
+
+	return;
+
+drop:
+	g_io_channel_shutdown(chan, TRUE, NULL);
+	g_io_channel_unref(chan);
+	return;
+}
+
 static int headset_server_init(struct audio_adapter *adapter)
 {
 	uint8_t chan = DEFAULT_HS_AG_CHANNEL;
@@ -760,6 +844,61 @@ static int gateway_server_init(struct audio_adapter *adapter)
 	return 0;
 }
 
+static int ofono_hfp_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) {
+			debug("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, ofono_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");
+		return -1;
+	}
+
+	if (add_record_to_server(&src, record) < 0) {
+		error("Unable to register HFP HS service record");
+		sdp_record_free(record);
+		g_io_channel_unref(adapter->hfp_hs_server);
+		adapter->hfp_hs_server = NULL;
+		return -1;
+	}
+
+	adapter->hfp_hs_record_id = record->handle;
+	return 0;
+}
+
 static int audio_probe(struct btd_device *device, GSList *uuids)
 {
 	struct btd_adapter *adapter = device_get_adapter(device);
@@ -1022,6 +1161,22 @@ static void avrcp_server_remove(struct btd_adapter *adapter)
 	audio_adapter_unref(adp);
 }
 
+static int ofono_hfp_server_probe(struct btd_adapter *adapter)
+{
+	struct audio_adapter *adp;
+
+	adp = audio_adapter_get(adapter);
+	if (!adp)
+		return -EINVAL;
+
+	return ofono_hfp_server_init(adp);
+}
+
+static void ofono_hfp_server_remove(struct btd_adapter *adapter)
+{
+	return gateway_server_remove(adapter);
+}
+
 static struct btd_device_driver audio_driver = {
 	.name	= "audio",
 	.uuids	= BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID,
@@ -1055,6 +1210,12 @@ static struct btd_adapter_driver avrcp_server_driver = {
 	.remove	= avrcp_server_remove,
 };
 
+static struct btd_adapter_driver ofono_hfp_server_driver = {
+	.name	= "ofono-handsfree",
+	.probe	= ofono_hfp_server_probe,
+	.remove	= ofono_hfp_server_remove,
+};
+
 int audio_manager_init(DBusConnection *conn, GKeyFile *conf,
 							gboolean *enable_sco)
 {
@@ -1083,6 +1244,8 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *conf,
 			enabled.source = TRUE;
 		else if (g_str_equal(list[i], "Control"))
 			enabled.control = TRUE;
+		else if (g_str_equal(list[i], "oFonoHFP"))
+			enabled.ofono_hfp = TRUE;
 	}
 	g_strfreev(list);
 
@@ -1099,6 +1262,8 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *conf,
 			enabled.source = FALSE;
 		else if (g_str_equal(list[i], "Control"))
 			enabled.control = FALSE;
+		else if (g_str_equal(list[i], "oFonoHFP"))
+			enabled.ofono_hfp = FALSE;
 	}
 	g_strfreev(list);
 
@@ -1140,9 +1305,12 @@ proceed:
 	if (enabled.control)
 		btd_register_adapter_driver(&avrcp_server_driver);
 
+	if (enabled.ofono_hfp)
+		btd_register_adapter_driver(&ofono_hfp_server_driver);
+
 	btd_register_device_driver(&audio_driver);
 
-	*enable_sco = (enabled.gateway || enabled.headset);
+	*enable_sco = (enabled.gateway || enabled.headset || enabled.ofono_hfp);
 
 	return 0;
 }
@@ -1169,6 +1337,11 @@ void audio_manager_exit(void)
 	if (enabled.gateway)
 		btd_unregister_adapter_driver(&gateway_server_driver);
 
+	if (enabled.ofono_hfp) {
+		btd_unregister_adapter_driver(&ofono_hfp_server_driver);
+		ofono_hfp_exit();
+	}
+
 	if (enabled.source || enabled.sink)
 		btd_unregister_adapter_driver(&a2dp_server_driver);
 
@@ -1218,6 +1391,10 @@ struct audio_device *manager_find_device(const char *path,
 				&& !dev->control)
 			continue;
 
+		if (interface && !strcmp(AUDIO_OFONO_HFP_INTERFACE, interface)
+				&& !dev->ofono_hfp)
+			continue;
+
 		if (connected && !audio_device_is_active(dev, interface))
 			continue;
 
diff --git a/audio/manager.h b/audio/manager.h
index cb9d63c..65ca419 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -26,6 +26,7 @@ struct enabled_interfaces {
 	gboolean hfp;
 	gboolean headset;
 	gboolean gateway;
+	gboolean ofono_hfp;
 	gboolean sink;
 	gboolean source;
 	gboolean control;
diff --git a/audio/unix.c b/audio/unix.c
index 6b43bd4..e4f4e4d 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -48,6 +48,7 @@
 #include "headset.h"
 #include "sink.h"
 #include "gateway.h"
+#include "ofono-hfp.h"
 #include "unix.h"
 #include "glib-helper.h"
 
@@ -57,8 +58,9 @@ typedef enum {
 	TYPE_NONE,
 	TYPE_HEADSET,
 	TYPE_GATEWAY,
+	TYPE_OFONO_HFP,
 	TYPE_SINK,
-	TYPE_SOURCE
+	TYPE_SOURCE,
 } service_type_t;
 
 typedef void (*notify_cb_t) (struct audio_device *dev, void *data);
@@ -196,6 +198,9 @@ static service_type_t select_service(struct audio_device *dev, const char *inter
 		return TYPE_HEADSET;
 	else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway)
 		return TYPE_GATEWAY;
+	else if (!strcmp(interface, AUDIO_OFONO_HFP_INTERFACE)
+					&& dev->ofono_hfp)
+		return TYPE_OFONO_HFP;
 
 	return TYPE_NONE;
 }
@@ -344,6 +349,32 @@ static void gateway_setup_complete(struct audio_device *dev, void *user_data)
 	unix_ipc_sendmsg(client, &rsp->h);
 }
 
+static void ofono_hfp_setup_complete(struct audio_device *dev, void *user_data)
+{
+	struct unix_client *client = user_data;
+	char buf[BT_SUGGESTED_BUFFER_SIZE];
+	struct bt_set_configuration_rsp *rsp = (void *) buf;
+
+	if (!dev) {
+		unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
+		return;
+	}
+
+	client->req_id = 0;
+
+	memset(buf, 0, sizeof(buf));
+
+	rsp->h.type = BT_RESPONSE;
+	rsp->h.name = BT_SET_CONFIGURATION;
+	rsp->h.length = sizeof(*rsp);
+
+	rsp->link_mtu = 48;
+
+	client->data_fd = ofono_hfp_get_sco_fd(dev);
+
+	unix_ipc_sendmsg(client, &rsp->h);
+}
+
 static void headset_resume_complete(struct audio_device *dev, void *user_data)
 {
 	struct unix_client *client = user_data;
@@ -418,6 +449,44 @@ static void gateway_resume_complete(struct audio_device *dev, void *user_data)
 	client->req_id = 0;
 }
 
+static void ofono_hfp_resume_complete(struct audio_device *dev, void *user_data)
+{
+	struct unix_client *client = user_data;
+	char buf[BT_SUGGESTED_BUFFER_SIZE];
+	struct bt_start_stream_rsp *rsp = (void *) buf;
+	struct bt_new_stream_ind *ind = (void *) buf;
+
+	if (!dev)
+		goto failed;
+
+	memset(buf, 0, sizeof(buf));
+	rsp->h.type = BT_RESPONSE;
+	rsp->h.name = BT_START_STREAM;
+	rsp->h.length = sizeof(*rsp);
+
+	unix_ipc_sendmsg(client, &rsp->h);
+
+	memset(buf, 0, sizeof(buf));
+	ind->h.type = BT_INDICATION;
+	ind->h.name = BT_NEW_STREAM;
+	ind->h.length = sizeof(*ind);
+
+	unix_ipc_sendmsg(client, &ind->h);
+
+	client->data_fd = ofono_hfp_get_sco_fd(dev);
+	if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
+		error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
+		unix_ipc_error(client, BT_START_STREAM, EIO);
+	}
+
+	client->req_id = 0;
+	return;
+
+failed:
+	error("ofono_hfp_resume_complete: resume failed");
+	unix_ipc_error(client, BT_START_STREAM, EIO);
+}
+
 static void headset_suspend_complete(struct audio_device *dev, void *user_data)
 {
 	struct unix_client *client = user_data;
@@ -870,6 +939,7 @@ static void start_discovery(struct audio_device *dev, struct unix_client *client
 
 	case TYPE_HEADSET:
 	case TYPE_GATEWAY:
+	case TYPE_OFONO_HFP:
 		headset_discovery_complete(dev, client);
 		break;
 
@@ -969,8 +1039,9 @@ static void start_open(struct audio_device *dev, struct unix_client *client)
 		}
 		break;
 
-        case TYPE_GATEWAY:
-                break;
+	case TYPE_GATEWAY:
+	case TYPE_OFONO_HFP:
+		break;
 	default:
 		error("No known services for device");
 		goto failed;
@@ -1038,7 +1109,14 @@ static void start_config(struct audio_device *dev, struct unix_client *client)
 		} else
 			id = 0;
 		break;
-
+	case TYPE_OFONO_HFP:
+		if (ofono_hfp_config_stream(dev, ofono_hfp_setup_complete,
+						client) >= 0) {
+			client->cancel = ofono_hfp_cancel_stream;
+			id = 1;
+		} else
+			id = 0;
+		break;
 	default:
 		error("No known services for device");
 		goto failed;
@@ -1111,6 +1189,15 @@ static void start_resume(struct audio_device *dev, struct unix_client *client)
 		client->cancel = gateway_cancel_stream;
 		break;
 
+	case TYPE_OFONO_HFP:
+		if (ofono_hfp_request_stream(dev, ofono_hfp_resume_complete,
+					client))
+			id = 1;
+		else
+			id = 0;
+		client->cancel = ofono_hfp_cancel_stream;
+		break;
+
 	default:
 		error("No known services for device");
 		goto failed;
@@ -1185,6 +1272,13 @@ static void start_suspend(struct audio_device *dev, struct unix_client *client)
 		id = 1;
 		break;
 
+	case TYPE_OFONO_HFP:
+		ofono_hfp_suspend_stream(dev);
+		client->cancel = ofono_hfp_cancel_stream;
+		headset_suspend_complete(dev, client);
+		id = 1;
+		break;
+
 	default:
 		error("No known services for device");
 		goto failed;
@@ -1241,7 +1335,8 @@ static void start_close(struct audio_device *dev, struct unix_client *client,
 		}
 		break;
         case TYPE_GATEWAY:
-                break;
+	case TYPE_OFONO_HFP:
+		break;
 	case TYPE_SOURCE:
 	case TYPE_SINK:
 		a2dp = &client->d.a2dp;
@@ -1317,6 +1412,13 @@ static void handle_getcapabilities_req(struct unix_client *client,
 			interface = NULL;
 		dev = manager_find_device(req->object, &src, &dst,
 							interface, TRUE);
+
+		if (!dev && (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)) {
+			interface = g_strdup(AUDIO_OFONO_HFP_INTERFACE);
+			dev = manager_find_device(req->object, &src, &dst,
+							interface, TRUE);
+		}
+
 		if (!dev && (req->flags & BT_FLAG_AUTOCONNECT))
 			dev = manager_find_device(req->object, &src, &dst,
 							interface, FALSE);
@@ -1353,7 +1455,8 @@ static int handle_sco_open(struct unix_client *client, struct bt_open_req *req)
 	if (!client->interface)
 		client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
 	else if (!g_str_equal(client->interface, AUDIO_HEADSET_INTERFACE) &&
-		!g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE))
+		!g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE) &&
+		!g_str_equal(client->interface, AUDIO_OFONO_HFP_INTERFACE))
 		return -EIO;
 
 	debug("open sco - object=%s source=%s destination=%s lock=%s%s",
@@ -1447,10 +1550,13 @@ static int handle_sco_transport(struct unix_client *client,
 			client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
 		else if (dev->gateway)
 			client->interface = g_strdup(AUDIO_GATEWAY_INTERFACE);
+		else if (dev->ofono_hfp)
+			client->interface = g_strdup(AUDIO_OFONO_HFP_INTERFACE);
 		else
 			return -EIO;
 	} else if (!g_str_equal(client->interface, AUDIO_HEADSET_INTERFACE) &&
-			!g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE))
+			!g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE) &&
+			!g_str_equal(client->interface, AUDIO_OFONO_HFP_INTERFACE))
 		return -EIO;
 
 	return 0;
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index 1f09cd5..5c4182c 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -456,3 +456,40 @@ properties	boolean Connected [readonly]
 		uint16 MicrophoneGain  [readonly]
 
 			The speaker gain when available.
+
+
+oFonoHFP hierarchy
+========================
+
+Service		org.bluez
+Interface	org.bluez.oFonoHFP
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+This interface is available for remote devices which can function in the Audio
+Gateway role of the HFP profiles. It provides connection service for oFono to
+create rfcomm connection with remote devices.
+
+Methods		void Connect()
+
+			Connect to the AG service on the remote device and
+			turn RFCOMM connection into TTY device. Send TTY
+			device name to oFono through D-Bus.
+
+		void Disconnect()
+
+			Disconnect from the AG service on the remote device.
+
+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.
+
+		string Device[readonly]
+
+			The TTY device name created from RFCOMM connection.
+
-- 
1.6.2.5


[-- Attachment #3: 0002-oFonoHFP-Add-oFonoHFP-support-in-oFono.patch --]
[-- Type: application/octet-stream, Size: 10252 bytes --]

From cc80eb3be64d5837e0469a85a15ec7038338d139 Mon Sep 17 00:00:00 2001
From: Zhenhua Zhang <zhenhua.zhang@intel.com>
Date: Thu, 12 Nov 2009 22:06:44 +0800
Subject: [PATCH 2/3] oFonoHFP: Add oFonoHFP support in oFono

It allows HFP plugin to communiate with BlueZ oFonoHFP profile.
The HFP plugin use Connect and Disconnect D-Bus methods of
oFonoHFP to get TTY device from oFonoHFP. The plugin also
watch property change of oFonoHFP if the device is disconnected.

Last commit: 7600c4b3ac93d1476d
---
 plugins/hfp.c       |  300 +++++++++++++++++++++++++++++++++++++++++++++++++-
 plugins/modemconf.c |    3 +-
 2 files changed, 295 insertions(+), 8 deletions(-)

diff --git a/plugins/hfp.c b/plugins/hfp.c
index fc29ad9..c0f8bc8 100644
--- a/plugins/hfp.c
+++ b/plugins/hfp.c
@@ -30,6 +30,7 @@
 #include <glib.h>
 #include <gatchat.h>
 #include <gattty.h>
+#include <gdbus.h>
 
 #define OFONO_API_SUBJECT_TO_CHANGE
 #include <ofono/plugin.h>
@@ -52,10 +53,26 @@
 
 #include <drivers/hfpmodem/hfpmodem.h>
 
+#include <ofono/dbus.h>
+
+#define BLUEZ_SERVICE "org.bluez"
+#define BLUEZ_PATH "/"
+#define BLUEZ_MANAGER_INTERFACE "org.bluez.Manager"
+#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter"
+#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device"
+#define BLUEZ_OFONO_HFP_INTERFACE "org.bluez.oFonoHFP"
+
+#define PROPERTY_CHANGED "PropertyChanged"
+
 static const char *brsf_prefix[] = { "+BRSF:", NULL };
 static const char *cind_prefix[] = { "+CIND:", NULL };
 static const char *cmer_prefix[] = { "+CMER:", NULL };
 
+static DBusConnection *connection;
+static char *ofono_handsfree_path;
+
+static int timeout;
+
 static int hfp_disable(struct ofono_modem *modem);
 
 static void hfp_debug(const char *str, void *user_data)
@@ -63,6 +80,60 @@ static void hfp_debug(const char *str, void *user_data)
 	ofono_info("%s", str);
 }
 
+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) {
+		ofono_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)) {
+		ofono_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 gboolean hfp_enable_timeout(gpointer user)
+{
+	struct ofono_modem *modem = user;
+
+	if (ofono_modem_get_powered(modem))
+		return FALSE;
+
+	hfp_disable(modem);
+	return FALSE;
+}
+
 static void cind_status_cb(gboolean ok, GAtResult *result,
 				gpointer user_data)
 {
@@ -240,6 +311,86 @@ static int service_level_connection(struct ofono_modem *modem,
 	return -EINPROGRESS;
 }
 
+static void handle_ofono_property(const char *property, DBusMessageIter sub,
+				void *user_data)
+{
+	struct ofono_modem *modem = user_data;
+	const char *tty;
+	gboolean connected;
+
+	if (g_str_equal(property, "Device")) {
+		dbus_message_iter_get_basic(&sub, &tty);
+
+		if (timeout)
+			g_source_remove(timeout);
+
+		service_level_connection(modem, tty);
+	}
+
+	if (g_str_equal(property, "Connected")) {
+		dbus_message_iter_get_basic(&sub, &connected);
+
+		if (!connected && ofono_modem_get_powered(modem))
+			hfp_disable(modem);
+	}
+}
+
+static void ofono_property_changed(DBusMessage *msg, void *user_data)
+{
+	DBusMessageIter iter, sub;
+	const char *property;
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+		ofono_error("Unexpected signature in "
+					"oFono PropertyChanged signal");
+		return;
+	}
+
+	dbus_message_iter_get_basic(&iter, &property);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_recurse(&iter, &sub);
+
+	handle_ofono_property(property, sub, user_data);
+}
+
+static DBusHandlerResult ofono_handsfree_signal(DBusConnection *conn,
+				DBusMessage *msg, void *user_data)
+{
+	if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	if (dbus_message_is_signal(msg, BLUEZ_OFONO_HFP_INTERFACE,
+				PROPERTY_CHANGED))
+		ofono_property_changed(msg, user_data);
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static int hfp_add_dbus_filter(struct ofono_modem *modem, void *filter)
+{
+	char match_string[128];
+
+	connection = ofono_dbus_get_connection();
+
+	dbus_connection_ref(connection);
+
+	if (!dbus_connection_add_filter(connection,
+				(DBusHandleMessageFunction)filter,
+				modem, NULL)) {
+		ofono_error("hfp_add_dbus_filter: Can't add signal filter");
+		return -EIO;
+	}
+
+	snprintf(match_string, sizeof(match_string), "type=signal,interface=%s",
+				BLUEZ_OFONO_HFP_INTERFACE);
+	dbus_bus_add_match(connection, match_string, NULL);
+
+	return 0;
+}
+
 static int hfp_probe(struct ofono_modem *modem)
 {
 	struct hfp_data *data;
@@ -256,9 +407,21 @@ static int hfp_probe(struct ofono_modem *modem)
 
 	ofono_modem_set_data(modem, data);
 
+	hfp_add_dbus_filter(modem, ofono_handsfree_signal);
+
 	return 0;
 }
 
+static void hfp_dbus_cleanup(void *filter)
+{
+	if (ofono_handsfree_path)
+		g_free(ofono_handsfree_path);
+
+	dbus_connection_remove_filter(connection,
+				(DBusHandleMessageFunction)filter, NULL);
+	dbus_connection_unref(connection);
+}
+
 static void hfp_remove(struct ofono_modem *modem)
 {
 	gpointer data = ofono_modem_get_data(modem);
@@ -267,23 +430,147 @@ static void hfp_remove(struct ofono_modem *modem)
 		g_free(data);
 
 	ofono_modem_set_data(modem, NULL);
+
+	hfp_dbus_cleanup(ofono_handsfree_signal);
+}
+
+static void port_connect_cb(DBusPendingCall *call, gpointer user_data)
+{
+	DBusError err;
+	DBusMessage *reply;
+	const char *msg;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	dbus_error_init(&err);
+
+	if (dbus_message_get_args(reply, &err, DBUS_TYPE_STRING,
+				&msg, DBUS_TYPE_INVALID) == FALSE) {
+		if (dbus_error_is_set(&err) == TRUE) {
+			ofono_error("%s", err.message);
+			dbus_error_free(&err);
+			goto done;
+		}
+	}
+
+	if (strcmp(msg, "ok"))
+		ofono_error("Connect failed: %s", msg);
+done:
+	dbus_message_unref(reply);
+}
+
+static void find_device_cb(DBusPendingCall *call, gpointer user_data)
+{
+	DBusError err;
+	DBusMessage *reply;
+	const char *device;
+	int ret;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	dbus_error_init(&err);
+
+	if (dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
+				&device, DBUS_TYPE_INVALID) == FALSE) {
+		if (dbus_error_is_set(&err) == TRUE) {
+			ofono_error("%s", err.message);
+			dbus_error_free(&err);
+		}
+		goto done;
+	}
+
+	ofono_debug("Using device %s", device);
+	ofono_handsfree_path = g_strdup(device);
+
+	ret = send_method_call(BLUEZ_SERVICE, device,
+				BLUEZ_OFONO_HFP_INTERFACE, "Connect",
+				port_connect_cb, NULL, DBUS_TYPE_INVALID);
+
+	if (ret < 0)
+		ofono_error("port_connect failed(%d)", ret);
+
+done:
+	dbus_message_unref(reply);;
+}
+
+static void get_adapter_cb(DBusPendingCall *call, gpointer user_data)
+{
+	DBusError err;
+	DBusMessage *reply;
+	const char *adapter;
+	const char *address = user_data;
+	int ret;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	dbus_error_init(&err);
+	if (dbus_message_get_args(reply, &err,
+				DBUS_TYPE_OBJECT_PATH,
+				&adapter, DBUS_TYPE_INVALID) == FALSE) {
+		if (adapter == NULL)
+			ofono_error("bluetooth adapter is not enabled");
+
+		if (dbus_error_is_set(&err) == TRUE) {
+			ofono_error("%s %s", adapter, err.message);
+			dbus_error_free(&err);
+		}
+		goto done;
+	}
+
+	ret = send_method_call(BLUEZ_SERVICE, adapter,
+				BLUEZ_ADAPTER_INTERFACE, "FindDevice",
+				find_device_cb, NULL,
+				DBUS_TYPE_STRING, &address,
+				DBUS_TYPE_INVALID);
+
+	if (ret < 0)
+		ofono_error("find_device failed(%d)", ret);
+
+done:
+	dbus_message_unref(reply);
+
+}
+
+static int hfp_connect_ofono_handsfree(const char *address)
+{
+	ofono_debug("Connect to bluetooth daemon");
+
+	return send_method_call(BLUEZ_SERVICE, BLUEZ_PATH,
+				BLUEZ_MANAGER_INTERFACE, "DefaultAdapter",
+				get_adapter_cb, (char *)address,
+				DBUS_TYPE_INVALID);
 }
 
 /* power up hardware */
 static int hfp_enable(struct ofono_modem *modem)
 {
-	const char *tty;
-	int ret;
+	const char *address;
 
 	DBG("%p", modem);
 
-	tty = ofono_modem_get_string(modem, "Device");
-	if (tty == NULL)
+	address = ofono_modem_get_string(modem, "Address");
+
+	DBG("address %s", address);
+
+	if (address == NULL)
 		return -EINVAL;
 
-	ret = service_level_connection(modem, tty);
+	timeout = g_timeout_add_seconds(10, hfp_enable_timeout, modem);
+
+	if (hfp_connect_ofono_handsfree(address) != 0)
+		return -EINVAL;
+
+	return -EINPROGRESS;
+}
+
+static int hfp_disconnect_ofono_handsfree()
+{
+	if (!ofono_handsfree_path || !connection)
+		return -1;
 
-	return ret;
+	return send_method_call(BLUEZ_SERVICE, ofono_handsfree_path,
+				BLUEZ_OFONO_HFP_INTERFACE, "Disconnect",
+				NULL, NULL, DBUS_TYPE_INVALID);
 }
 
 static int hfp_disable(struct ofono_modem *modem)
@@ -303,6 +590,7 @@ static int hfp_disable(struct ofono_modem *modem)
 
 	ofono_modem_set_powered(modem, FALSE);
 
+	hfp_disconnect_ofono_handsfree();
 	return 0;
 }
 
diff --git a/plugins/modemconf.c b/plugins/modemconf.c
index 39a62b8..e715822 100644
--- a/plugins/modemconf.c
+++ b/plugins/modemconf.c
@@ -122,12 +122,11 @@ static struct ofono_modem *create_modem(GKeyFile *keyfile, const char *group)
 
 	modem = ofono_modem_create(driver);
 
-	if (!g_strcmp0(driver, "phonesim"))
+	if (!g_strcmp0(driver, "phonesim") || !g_strcmp0(driver, "hfp"))
 		set_address(modem, keyfile, group);
 
 	if (!g_strcmp0(driver, "atgen") || !g_strcmp0(driver, "g1") ||
 						!g_strcmp0(driver, "calypso") ||
-						!g_strcmp0(driver, "hfp") ||
 						!g_strcmp0(driver, "palmpre"))
 		set_device(modem, keyfile, group);
 
-- 
1.6.2.5


[-- Attachment #4: 0003-oFonoHFP-Add-oFonoHFP-patch-in-PulseAudio.patch --]
[-- Type: application/octet-stream, Size: 7333 bytes --]

From b7df3f91562bee93af6ebf95d9096dec3e783ec3 Mon Sep 17 00:00:00 2001
From: Zhenhua Zhang <zhenhua.zhang@intel.com>
Date: Thu, 12 Nov 2009 19:27:17 +0800
Subject: [PATCH 3/3] oFonoHFP: Add oFonoHFP patch in PulseAudio

The patch listens CallStarted and CallEnded signal to enable PA
plugins for BlueZ. It creates BT source and sink in PA. It's not
a complete patch so you still need to load loopback module
manually. For example, redirect BT source to speaker:

	load-module module-loopback source="bluez_source.XX..XX"
sink="alsa_output.0.analog-stereo"

Last commit: afd1b6d355ef1a41cb (v0.9.19).
---
 src/modules/bluetooth/bluetooth-util.c          |   39 ++++++++++++++++++++---
 src/modules/bluetooth/module-bluetooth-device.c |   13 ++++++--
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index f8c5b77..d0cb4da 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -123,10 +123,11 @@ static pa_bool_t device_is_audio(pa_bluetooth_device *d) {
 
     return
         d->device_info_valid &&
-        (d->audio_state != PA_BT_AUDIO_STATE_INVALID &&
+        d->audio_state != PA_BT_AUDIO_STATE_INVALID;
+        /*(d->audio_state != PA_BT_AUDIO_STATE_INVALID &&
          (d->audio_sink_state != PA_BT_AUDIO_STATE_INVALID ||
           d->audio_source_state != PA_BT_AUDIO_STATE_INVALID ||
-          d->headset_state != PA_BT_AUDIO_STATE_INVALID));
+          d->headset_state != PA_BT_AUDIO_STATE_INVALID));*/
 }
 
 static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessageIter *i) {
@@ -577,7 +578,31 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
             dbus_message_get_path(m),
             dbus_message_get_member(m));
 
-    if (dbus_message_is_signal(m, "org.bluez.Adapter", "DeviceRemoved")) {
+    if (dbus_message_get_member(m) && !strcmp(dbus_message_get_member(m),"CallStarted")) {
+        pa_log_error("CallStarted");
+        pa_bluetooth_device *d;
+
+        if ((d = pa_hashmap_get(y->devices, dbus_message_get_path(m)))) {
+            if (dbus_message_has_interface(m, "org.bluez.oFonoHFP")) {
+                pa_log_error("oFonoHFP CallStarted detected\n");
+            }
+            d->audio_state = PA_BT_AUDIO_STATE_CONNECTED;
+            run_callback(y, d, FALSE);
+        }
+    }
+    else if (dbus_message_get_member(m) && !strcmp(dbus_message_get_member(m),"CallEnded")) {
+        pa_log_error("CallEnded");
+        pa_bluetooth_device *d;
+
+        if ((d = pa_hashmap_get(y->devices, dbus_message_get_path(m)))) {
+            if (dbus_message_has_interface(m, "org.bluez.oFonoHFP")) {
+                pa_log_error("oFonoHFP CallEnded detected\n");
+            }
+            d->audio_state = PA_BT_AUDIO_STATE_DISCONNECTED;
+            run_callback(y, d, TRUE);
+        }
+    }
+    else if (dbus_message_is_signal(m, "org.bluez.Adapter", "DeviceRemoved")) {
         const char *path;
         pa_bluetooth_device *d;
 
@@ -794,7 +819,9 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
                 "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",
                 "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
                 "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
-                "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'", NULL) < 0) {
+                "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
+                "type='signal',sender='org.bluez',interface='org.bluez.oFonoHFP',member='CallStarted'",
+                "type='signal',sender='org.bluez',interface='org.bluez.oFonoHFP',member='CallEnded'", NULL) < 0) {
         pa_log("Failed to add D-Bus matches: %s", err.message);
         goto fail;
     }
@@ -848,7 +875,9 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
                                "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",
                                "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
                                "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
-                               "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'", NULL);
+                               "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
+                               "type='signal',sender='org.bluez',interface='org.bluez.oFonoHFP',member='CallStarted'",
+                               "type='signal',sender='org.bluez',interface='org.bluez.oFonoHFP',member='CallEnded'", NULL);
 
         dbus_connection_remove_filter(pa_dbus_connection_get(y->connection), filter_cb, y);
 
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 4592fca..c8d66d4 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -676,6 +676,9 @@ static int set_conf(struct userdata *u) {
     msg.open_req.h.name = BT_OPEN;
     msg.open_req.h.length = sizeof(msg.open_req);
 
+    pa_assert(u->address);
+    pa_strlcpy(msg.open_req.destination, u->address, sizeof(msg.open_req.destination));
+
     pa_strlcpy(msg.open_req.object, u->path, sizeof(msg.open_req.object));
     msg.open_req.seid = (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) ? u->a2dp.sbc_capabilities.capability.seid : BT_A2DP_SEID_RANGE + 1;
     msg.open_req.lock = (u->profile == PROFILE_A2DP) ? BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK;
@@ -2209,7 +2212,11 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
     }
 
     if (pa_bluetooth_uuid_has(device->uuids, HSP_HS_UUID) ||
-        pa_bluetooth_uuid_has(device->uuids, HFP_HS_UUID)) {
+        pa_bluetooth_uuid_has(device->uuids, HFP_HS_UUID) ||
+		/////////////////////////////////////////////////
+        pa_bluetooth_uuid_has(device->uuids, HSP_AG_UUID) ||
+        pa_bluetooth_uuid_has(device->uuids, HFP_AG_UUID)) {
+		/////////////////////////////////////////////////
         p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(enum profile));
         p->priority = 20;
         p->n_sinks = 1;
@@ -2249,14 +2256,14 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
     u->card->set_profile = card_set_profile;
 
     d = PA_CARD_PROFILE_DATA(u->card->active_profile);
-
+/*
     if ((device->headset_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HSP) ||
         (device->audio_sink_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_A2DP)) {
         pa_log_warn("Default profile not connected, selecting off profile");
         u->card->active_profile = pa_hashmap_get(u->card->profiles, "off");
         u->card->save_profile = FALSE;
     }
-
+*/
     d = PA_CARD_PROFILE_DATA(u->card->active_profile);
     u->profile = *d;
 
-- 
1.6.2.5


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

end of thread, other threads:[~2009-11-13 13:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-12  7:50 [PATCH] oFonoHFP profile to enable audio routing in BlueZ Zhang, Zhenhua
2009-11-12 16:48 ` Gustavo F. Padovan
2009-11-13  1:01 ` Zhang, Zhenhua
2009-11-13 13:36   ` Luiz Augusto von Dentz
2009-11-13 13:54     ` Gustavo F. Padovan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox