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
prev parent 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