public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
From: Alok <develnewbie@gmail.com>
To: BlueZ development <bluez-devel@lists.sourceforge.net>
Subject: [Bluez-devel] [Patch] Service Level Connection for HFP.
Date: Tue, 11 Dec 2007 21:14:04 +0530	[thread overview]
Message-ID: <1197387845.26216.22.camel@greatbear> (raw)
In-Reply-To: <47595288.5020200@access-company.com>

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

Hello, 

I am sending a patch for Service Level Connection(SLC) Establishment for
the HandsFree Profile. This patch includes: 

1. String table mechanism for headset/handsfree events. 

2. Callbacks in form of function pointers for the events. 

3. Basic event handling for SLC and complete event handling for
   Headset. 

4. Modification in get_record_reply for HFP.

Currently there are no extra signals/methods, for the sake of
simplicity.   

This patch requires Fredric's 1st patch(dated:07 Dec 2007) to be applied
first. 

Please let me know if any changes are required. 

Thanks, 
Alok.

[-- Attachment #2: SLC.patch --]
[-- Type: text/x-patch, Size: 8905 bytes --]

diff --git a/audio/headset.c b/audio/headset.c
index 7bb1746..98c4d4c 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -108,9 +108,27 @@ struct headset {
 	int sp_gain;
 	int mic_gain;
 
+	unsigned int hfp_features;
 	headset_lock_t lock;
 };
 
+struct event {
+	const char *cmd;
+	 int(*callback) (struct device *device, const char *buf);
+};
+
+static struct event event_callbacks[] = {
+	{"ATA", hf_answer_call},
+	{"AT+VG", hs_signal_gain_setting},
+	{"AT+BRSF", hf_supported_features},
+	{"AT+CIND", hf_report_indicators},
+	{"AT+CMER", hf_event_reporting},
+	{"AT+CHLD", hf_call_hold},
+	{"AT+CHUP", hf_terminate_call},
+	{"AT+CKPD", hf_answer_call},
+	{0}
+};
+
 static int rfcomm_connect(struct device *device, struct pending_connect *c);
 static int get_handles(struct device *device, struct pending_connect *c);
 
@@ -130,70 +148,114 @@ static void pending_connect_free(struct pending_connect *c)
 	g_free(c);
 }
 
-static void hs_signal_gain_setting(struct device *device, const char *buf)
+int handle_event(struct device *device, const char *buf)
+{
+	struct event *pt;
+	debug("Received %s", buf);
+	for (pt = event_callbacks; pt->cmd; pt++) {
+		if (!strncmp(buf, pt->cmd, strlen(pt->cmd)))
+			return pt->callback(device, buf);
+	}
+	debug("Invalid Event");
+	return -1;
+}
+
+int hf_supported_features(struct device *device, const char *buf)
+{
+	struct headset *hs = device->headset;
+
+	hs->hfp_features = strtoul(&buf[8], NULL, 10);
+	headset_send(hs, "\r\n+BRSF:0\r\n");
+	headset_send(device->headset, "\r\nOK\r\n");
+	return 0;
+}
+
+int hf_report_indicators(struct device *device, const char *buf)
+{
+	struct headset *hs = device->headset;
+
+	if (buf[7] == '=')
+		headset_send(hs, "\r\n+CIND:(\"service\",(0,1)),(\"call\",(0,1)),(\"callsetup\",(0-3))\r\n");
+	else
+		headset_send(hs, "\r\n+CIND:1, 0, 0\r\n");
+	headset_send(device->headset, "\r\nOK\r\n");
+	return 0;
+}
+
+int hf_event_reporting(struct device *device, const char *buf)
+{
+	struct headset *hs = device->headset;
+
+	headset_send(device->headset, "\r\nOK\r\n");
+	return 0;	
+}
+
+int hf_call_hold(struct device *device, const char *buf)
+{
+	struct headset *hs = device->headset;
+
+	headset_send(hs, "\r\n+CHLD:(0,1,1x,2,2x,3,4)\r\n");
+	headset_send(device->headset, "\r\nOK\r\n");
+	return 0;
+}
+
+int hf_answer_call(struct device *device, const char *buf)
+{
+	struct headset *hs = device->headset;
+
+	dbus_connection_emit_signal(device->conn,
+				    device->path, AUDIO_HEADSET_INTERFACE, "AnswerRequested", DBUS_TYPE_INVALID);
+	headset_send(device->headset, "\r\nOK\r\n");
+	return 0;
+}
+
+int hf_terminate_call(struct device *device, const char *buf)
+{
+	headset_send(device->headset, "\r\nOK\r\n");
+	return 0;
+}
+
+
+int hs_signal_gain_setting(struct device *device, const char *buf)
 {
 	const char *name;
 	dbus_uint16_t gain;
 
-	if (strlen(buf) < 6) {
+	if (strlen(buf) < 8) {
 		error("Too short string for Gain setting");
-		return;
+		return -1;
 	}
 
-	gain = (dbus_uint16_t) strtol(&buf[5], NULL, 10);
+	gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
 
 	if (gain > 15) {
 		error("Invalid gain value received: %u", gain);
-		return;
+		return -1;
 	}
 
-	switch (buf[3]) {
+	switch (buf[5]) {
 	case HEADSET_GAIN_SPEAKER:
 		if (device->headset->sp_gain == gain)
-			return;
+			break;
 		name = "SpeakerGainChanged";
 		device->headset->sp_gain = gain;
 		break;
 	case HEADSET_GAIN_MICROPHONE:
 		if (device->headset->mic_gain == gain)
-			return;
+			break;
 		name = "MicrophoneGainChanged";
 		device->headset->mic_gain = gain;
 		break;
 	default:
 		error("Unknown gain setting");
-		return;
-	}
-
-	dbus_connection_emit_signal(device->conn, device->path,
-					AUDIO_HEADSET_INTERFACE, name,
-					DBUS_TYPE_UINT16, &gain,
-					DBUS_TYPE_INVALID);
-}
-
-static headset_event_t parse_headset_event(const char *buf, char *rsp,
-						int rsp_len)
-{
-	printf("Received: %s\n", buf);
-
-	/* Return an error if this is not a proper AT command */
-	if (strncmp(buf, "AT", 2)) {
-		snprintf(rsp, rsp_len, "\r\nERROR\r\n");
-		return HEADSET_EVENT_INVALID;
+		return -1;
 	}
 
-	buf += 2;
-
-	if (!strncmp(buf, "+CKPD", 5)) {
-		snprintf(rsp, rsp_len, "\r\nOK\r\n");
-		return HEADSET_EVENT_KEYPRESS;
-	} else if (!strncmp(buf, "+VG", 3)) {
-		snprintf(rsp, rsp_len, "\r\nOK\r\n");
-		return HEADSET_EVENT_GAIN;
-	} else {
-		snprintf(rsp, rsp_len, "\r\nERROR\r\n");
-		return HEADSET_EVENT_UNKNOWN;
-	}
+	dbus_connection_emit_signal(device->conn,
+				    device->path,
+				    AUDIO_HEADSET_INTERFACE, name, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID);
+	headset_send(device->headset, "\r\nOK\r\n");
+	return 0;
 }
 
 static void close_sco(struct device *device)
@@ -214,9 +276,9 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
 {
 	struct headset *hs;
 	unsigned char buf[BUF_SIZE];
-	char *cr, rsp[BUF_SIZE];
+	char *cr;
 	gsize bytes_read = 0;
-	gsize free_space, count, bytes_written, total_bytes_written;
+	gsize free_space;
 	GIOError err;
 	off_t cmd_len;
 
@@ -256,46 +318,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
 	cmd_len	= 1 + (off_t) cr - (off_t) &hs->buf[hs->data_start];
 	*cr = '\0';
 
-	memset(rsp, 0, sizeof(rsp));
-
-	switch (parse_headset_event(&hs->buf[hs->data_start], rsp,
-					sizeof(rsp))) {
-	case HEADSET_EVENT_GAIN:
-		hs_signal_gain_setting(device, &hs->buf[hs->data_start] + 2);
-		break;
-
-	case HEADSET_EVENT_KEYPRESS:
-		if (hs->ring_timer) {
-			g_source_remove(hs->ring_timer);
-			hs->ring_timer = 0;
-		}
-
-		dbus_connection_emit_signal(device->conn, device->path,
-						AUDIO_HEADSET_INTERFACE,
-						"AnswerRequested",
-						DBUS_TYPE_INVALID);
-		break;
-
-	case HEADSET_EVENT_INVALID:
-	case HEADSET_EVENT_UNKNOWN:
-	default:
-		debug("Unknown headset event");
-		break;
-	}
-
-	count = strlen(rsp);
-	total_bytes_written = bytes_written = 0;
-	err = G_IO_ERROR_NONE;
-
-	while (err == G_IO_ERROR_NONE && total_bytes_written < count) {
-		err = g_io_channel_write(hs->rfcomm,
-						rsp + total_bytes_written, 
-						count - total_bytes_written,
-						&bytes_written);
-		if (err != G_IO_ERROR_NONE)
-			error("Error while writting to the audio output channel");
-		total_bytes_written += bytes_written;
-	};
+	if(handle_event(device, &hs->buf[hs->data_start]) == -1)
+		error("Error in event");
 
 	hs->data_start += cmd_len;
 	hs->data_length -= cmd_len;
@@ -593,6 +617,7 @@ static void get_record_reply(DBusPendingCall *call, void *data)
 	struct device *device = data;
 	struct headset *hs = device->headset;
 	struct pending_connect *c;
+	unsigned int SVCLASS_ID;
 
 	c = hs->pending->data;
 
@@ -642,21 +667,11 @@ static void get_record_reply(DBusPendingCall *call, void *data)
 		goto failed_not_supported;
 	}
 
-	if (hs->type == SVC_HEADSET &&
-			((uuid.type == SDP_UUID32 &&
-			uuid.value.uuid32 != HEADSET_SVCLASS_ID) ||
-			(uuid.type == SDP_UUID16 &&
-			 uuid.value.uuid16 != HEADSET_SVCLASS_ID))) {
-		error("Service classes did not contain the expected UUID hsp");
-		goto failed_not_supported;
-	}
+	SVCLASS_ID = hs->enable_hfp ? HANDSFREE_SVCLASS_ID : HEADSET_SVCLASS_ID;
 
-	if (hs->type == SVC_HANDSFREE &&
-			((uuid.type == SDP_UUID32 &&
-			uuid.value.uuid32 != HANDSFREE_SVCLASS_ID) ||
-			(uuid.type == SDP_UUID16 &&
-			 uuid.value.uuid16 != HANDSFREE_SVCLASS_ID))) {
-		error("Service classes did not contain the expected UUID hfp");
+	if ((uuid.type == SDP_UUID32 && uuid.value.uuid32 != SVCLASS_ID)
+	    || (uuid.type == SDP_UUID16 && uuid.value.uuid16 != SVCLASS_ID)) {
+		error("Service classes did not contain the expected UUID");
 		goto failed_not_supported;
 	}
 
diff --git a/audio/headset.h b/audio/headset.h
index b151dbd..86be42e 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -28,13 +28,6 @@
 #define DEFAULT_HF_AG_CHANNEL 13
 
 typedef enum {
-	HEADSET_EVENT_KEYPRESS,
-	HEADSET_EVENT_GAIN,
-	HEADSET_EVENT_UNKNOWN,
-	HEADSET_EVENT_INVALID
-} headset_event_t;
-
-typedef enum {
 	HEADSET_STATE_DISCONNECTED,
 	HEADSET_STATE_CONNECT_IN_PROGRESS,
 	HEADSET_STATE_CONNECTED,
@@ -84,3 +77,12 @@ gboolean headset_lock(struct device *dev, headset_lock_t lock);
 gboolean headset_unlock(struct device *dev, headset_lock_t lock);
 gboolean headset_suspend(struct device *dev, void *data);
 gboolean headset_play(struct device *dev, void *data);
+static GIOError headset_send(struct headset *hs, const char *str);
+int hs_signal_gain_setting(struct device *device, const char *buf);
+int hf_supported_features(struct device *device, const char *buf);
+int hf_report_indicators(struct device *device, const char *buf);
+int hf_event_reporting(struct device *device, const char *buf);
+int hf_answer_call(struct device *device, const char *buf);
+int hf_call_hold(struct device *device, const char *buf);
+int hf_terminate_call(struct device *device, const char *buf);
+int hf_answer_call(struct device *device, const char *buf);

[-- Attachment #3: Type: text/plain, Size: 277 bytes --]

-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel

      reply	other threads:[~2007-12-11 15:44 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-06 11:27 [Bluez-devel] [Patch] org.bluez.audio.headset.Connect() to handsfree Frédéric Dalleau
2007-12-06 11:30 ` Frédéric Dalleau
2007-12-06 11:40 ` Marcel Holtmann
2007-12-06 15:16   ` Frédéric Dalleau
2007-12-07 14:02     ` Frédéric Dalleau
2007-12-11 15:44       ` Alok [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1197387845.26216.22.camel@greatbear \
    --to=develnewbie@gmail.com \
    --cc=bluez-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox