[PATCH 2/4] add the basic framework support for HFP Audio Gateway

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



diff --git a/audio/device.c b/audio/device.c
index a5cfc88..38a9c11 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -52,6 +52,7 @@
 #include "avdtp.h"
 #include "control.h"
 #include "headset.h"
+#include "gateway.h"
 #include "sink.h"

 #define CONTROL_CONNECT_TIMEOUT 2
@@ -141,6 +142,9 @@ gboolean audio_device_is_connected(struct audio_device *dev,
 	else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&
 			headset_is_active(dev))
 		return TRUE;
+	else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway &&
+			gateway_is_connected(dev))
+		return TRUE;
 	else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->headset &&
 			control_is_active(dev))
 		return TRUE;
diff --git a/audio/gateway.c b/audio/gateway.c
index edf38de..cf37e4b 100644
--- a/audio/gateway.c
+++ b/audio/gateway.c
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2006-2007  Nokia Corporation
  *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@xxxxxxxxxxxx>
+ *  Copyright (C) 2008-2009  Leonid Movshovich <event.riga@xxxxxxxxx>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -27,8 +28,71 @@
 #endif

 #include <stdint.h>
+#include <errno.h>

 #include <glib.h>
 #include <dbus/dbus.h>
+#include <gdbus.h>

+#include <bluetooth/bluetooth.h>
+
+#include "device.h"
 #include "gateway.h"
+
+struct gateway {
+	GIOChannel *rfcomm;
+	guint rfcomm_watch_id;
+	GIOChannel *sco;
+	GIOChannel *sco_server;
+	gateway_stream_cb_t sco_start_cb;
+	void *sco_start_cb_data;
+	DBusMessage *connect_message;
+	guint ag_features;
+	guint hold_multiparty_features;
+	GSList *indies;
+	gboolean is_dialing;
+};
+
+static GDBusMethodTable gateway_methods[] = {
+	{ NULL, NULL, NULL, NULL }
+};
+
+static GDBusSignalTable gateway_signals[] = {
+	{ NULL, NULL }
+};
+
+struct gateway *gateway_init(struct audio_device *dev)
+{
+	struct gateway *gw;
+
+	if (!g_dbus_register_interface(dev->conn, dev->path,
+					AUDIO_GATEWAY_INTERFACE,
+					gateway_methods, gateway_signals,
+					NULL, dev, NULL))
+		return NULL;
+
+	gw = g_new0(struct gateway, 1);
+	gw->indies = NULL;
+	gw->is_dialing = FALSE;
+	return gw;
+
+}
+
+gboolean gateway_is_connected(struct audio_device *dev)
+{
+	return (dev && dev->gateway && dev->gateway->rfcomm);
+}
+
+int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
+{
+	if (!io)
+		return -EINVAL;
+
+	dev->gateway->rfcomm = io;
+
+	return 0;
+}
+
+void gateway_start_service(struct audio_device *device)
+{
+}
diff --git a/audio/gateway.h b/audio/gateway.h
index e93406b..78eef87 100644
--- a/audio/gateway.h
+++ b/audio/gateway.h
@@ -22,13 +22,13 @@
  *
  */

-#define AUDIO_GATEWAY_INTERFACE "org.bluez.Gateway"
+#define AUDIO_GATEWAY_INTERFACE "org.bluez.HeadsetGateway"

 #define DEFAULT_HSP_HS_CHANNEL 6
 #define DEFAULT_HFP_HS_CHANNEL 7

-int gateway_init(DBusConnection *conn, gboolean disable_hfp, gboolean sco_hci);
-
-void gateway_exit(void);
-
-gboolean gateway_is_enabled(uint16_t svc);
+typedef void (*gateway_stream_cb_t) (struct audio_device *dev, void
*user_data);
+struct gateway *gateway_init(struct audio_device *device);
+gboolean gateway_is_connected(struct audio_device *dev);
+int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *chan);
+void gateway_start_service(struct audio_device *device);
diff --git a/audio/manager.c b/audio/manager.c
index 77de287..662e1fd 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -92,10 +92,10 @@ struct audio_adapter {
 	char	*path;
 	uint32_t hsp_ag_record_id;
 	uint32_t hfp_ag_record_id;
-	uint32_t hsp_hs_record_id;
+	uint32_t hfp_hs_record_id;
 	GIOChannel *hsp_ag_server;
 	GIOChannel *hfp_ag_server;
-	GIOChannel *hsp_hs_server;
+	GIOChannel *hfp_hs_server;
 };

 static int max_connected_headsets = 1;
@@ -107,7 +107,7 @@ static GSList *devices = NULL;
 static struct enabled_interfaces enabled = {
 	.hfp		= TRUE,
 	.headset	= TRUE,
-	.gateway	= FALSE,
+	.gateway	= TRUE,
 	.sink		= TRUE,
 	.source		= FALSE,
 	.control	= TRUE,
@@ -133,11 +133,11 @@ gboolean server_is_enabled(bdaddr_t *src, uint16_t svc)
 	case HEADSET_SVCLASS_ID:
 		return enabled.headset;
 	case HEADSET_AGW_SVCLASS_ID:
-		return enabled.gateway;
+		return  FALSE;
 	case HANDSFREE_SVCLASS_ID:
 		return enabled.headset && enabled.hfp;
 	case HANDSFREE_AGW_SVCLASS_ID:
-		return  FALSE;
+		return enabled.gateway;
 	case AUDIO_SINK_SVCLASS_ID:
 		return enabled.sink;
 	case AV_REMOTE_TARGET_SVCLASS_ID:
@@ -193,6 +193,8 @@ 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)
+			device->gateway = gateway_init(device);
 		break;
 	case AUDIO_SINK_SVCLASS_ID:
 		debug("Found Audio Sink");
@@ -278,7 +280,7 @@ static sdp_record_t *hsp_ag_record(uint8_t ch)
 	return record;
 }

-static sdp_record_t *hsp_hs_record(uint8_t ch)
+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;
@@ -296,13 +298,13 @@ static sdp_record_t *hsp_hs_record(uint8_t ch)
 	root = sdp_list_append(0, &root_uuid);
 	sdp_set_browse_groups(record, root);

-	sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
+	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, HEADSET_PROFILE_ID);
+	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
 	profile.version = 0x0100;
 	pfseq = sdp_list_append(0, &profile);
 	sdp_set_profile_descs(record, pfseq);
@@ -320,7 +322,7 @@ static sdp_record_t *hsp_hs_record(uint8_t ch)
 	aproto = sdp_list_append(0, apseq);
 	sdp_set_access_protos(record, aproto);

-	sdp_set_info_attr(record, "Headset", 0, 0);
+	sdp_set_info_attr(record, "Hands-Free", 0, 0);

 	sdp_data_free(channel);
 	sdp_list_free(proto[0], 0);
@@ -399,7 +401,7 @@ static sdp_record_t *hfp_ag_record(uint8_t ch,
uint32_t feat)
 	return record;
 }

-static void auth_cb(DBusError *derr, void *user_data)
+static void headset_auth_cb(DBusError *derr, void *user_data)
 {
 	struct audio_device *device = user_data;
 	const char *uuid;
@@ -491,7 +493,7 @@ static void ag_confirm(GIOChannel *chan, gpointer data)
 	headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);

 	perr = btd_request_authorization(&device->src, &device->dst,
-					server_uuid, auth_cb, device);
+					server_uuid, headset_auth_cb, device);
 	if (perr < 0) {
 		debug("Authorization denied: %s", strerror(-perr));
 		headset_set_state(device, HEADSET_STATE_DISCONNECTED);
@@ -504,9 +506,81 @@ drop:
 	g_io_channel_shutdown(chan, TRUE, NULL);
 }

-static void hs_io_cb(GIOChannel *chan, GError *err, void *data)
+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);
+	else {
+		char ag_address[18];
+
+		ba2str(&device->dst, ag_address);
+		debug("Accepted AG connection from %s for %s",
+			ag_address, device->path);
+
+		gateway_start_service(device);
+	}
+}
+
+static void hf_io_cb(GIOChannel *chan, gpointer data)
 {
-	/*Stub*/
+	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);
+	if (!device)
+		goto drop;
+
+	if (!device->gateway) {
+		btd_device_add_uuid(device->btd_dev, remote_uuid);
+		if (!device->gateway)
+			goto drop;
+	}
+
+	if (gateway_is_connected(device)) {
+		debug("Refusing new connection since one already exists");
+		goto drop;
+	}
+
+	if (gateway_connect_rfcomm(device, chan) < 0) {
+		error("Allocating new GIOChannel failed!");
+		goto drop;
+	}
+
+	perr = btd_request_authorization(&device->src, &device->dst,
+				server_uuid, gateway_auth_cb, device);
+	if (perr < 0) {
+		debug("Authorization denied!");
+		goto drop;
+	}
+
+	return;
+
+drop:
+	g_io_channel_close(chan);
+	g_io_channel_unref(chan);
 	return;
 }

@@ -608,7 +682,7 @@ failed:

 static int gateway_server_init(struct audio_adapter *adapter)
 {
-	uint8_t chan = DEFAULT_HSP_HS_CHANNEL;
+	uint8_t chan = DEFAULT_HFP_HS_CHANNEL;
 	sdp_record_t *record;
 	gboolean master = TRUE;
 	GError *err = NULL;
@@ -626,7 +700,7 @@ static int gateway_server_init(struct
audio_adapter *adapter)
 			master = tmp;
 	}

-	io = bt_io_listen(BT_IO_RFCOMM, hs_io_cb, NULL, adapter, NULL, &err,
+	io = bt_io_listen(BT_IO_RFCOMM, NULL, hf_io_cb, adapter, NULL, &err,
 				BT_IO_OPT_SOURCE_BDADDR, &adapter->src,
 				BT_IO_OPT_CHANNEL, chan,
 				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
@@ -638,23 +712,22 @@ static int gateway_server_init(struct
audio_adapter *adapter)
 		return -1;
 	}

-	adapter->hsp_hs_server = io;
-
-	record = hsp_hs_record(chan);
+	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(&adapter->src, record) < 0) {
-		error("Unable to register HSP HS service record");
+		error("Unable to register HFP HS service record");
 		sdp_record_free(record);
-		g_io_channel_unref(adapter->hsp_hs_server);
-		adapter->hsp_hs_server = NULL;
+		g_io_channel_unref(adapter->hfp_hs_server);
+		adapter->hfp_hs_server = NULL;
 		return -1;
 	}

-	adapter->hsp_hs_record_id = record->handle;
+	adapter->hfp_hs_record_id = record->handle;

 	return 0;
 }
@@ -796,14 +869,14 @@ static void gateway_server_remove(struct
btd_adapter *adapter)
 	if (!adp)
 		return;

-	if (adp->hsp_hs_record_id) {
-		remove_record_from_server(adp->hsp_hs_record_id);
-		adp->hsp_hs_record_id = 0;
+	if (adp->hfp_hs_record_id) {
+		remove_record_from_server(adp->hfp_hs_record_id);
+		adp->hfp_hs_record_id = 0;
 	}

-	if (adp->hsp_hs_server) {
-		g_io_channel_unref(adp->hsp_hs_server);
-		adp->hsp_hs_server = NULL;
+	if (adp->hfp_hs_server) {
+		g_io_channel_unref(adp->hfp_hs_server);
+		adp->hfp_hs_server = NULL;
 	}
 }

@@ -1021,6 +1094,10 @@ struct audio_device *manager_find_device(const
bdaddr_t *bda, const char *interf
 				&& !dev->headset)
 			continue;

+		if (interface && !strcmp(AUDIO_GATEWAY_INTERFACE, interface)
+				&& !dev->gateway)
+			continue;
+
 		if (interface && !strcmp(AUDIO_SINK_INTERFACE, interface)
 				&& !dev->sink)
 			continue;
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux