2011-08-03 13:34:17

by Frederic Danis

[permalink] [raw]
Subject: [PATCH v3] audio: add profile version to HandsfreeAgent

Some phones with HFP Audio Gateway version previous to 1.5 (i.e.
Samsung SGH-D600 returning 0x0101 as profile version) do not accept
an AT+BRSF with latest features.
The Handsfree agent should adapt its AT+BRSF command depending on the
remote version, so add version information as parameter of
NewConnection method.

Here is traces of buggy exchange:

< ACL data: handle 12 flags 0x02 dlen 20
L2CAP(d): cid 0x0046 len 16 [psm 3]
RFCOMM(d): UIH: cr 1 dlci 10 pf 0 ilen 12 fcs 0xb0
0000: 41 54 2b 42 52 53 46 3d 31 31 38 0d AT+BRSF=118.
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 12 packets 2
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 12 packets 2
> ACL data: handle 12 flags 0x02 dlen 14
L2CAP(s): Config rsp: scid 0x0042 flags 0x00 result 0 clen 0
Success
> ACL data: handle 12 flags 0x02 dlen 25
L2CAP(d): cid 0x0042 len 21 [psm 1]
SDP SSA Req: tid 0x0 len 0x10
pat uuid-16 0x111e (Handsfree)
max 240
aid(s) 0x0001 (SrvClassIDList) 0x0311 (SuppFeatures)
cont 00
< ACL data: handle 12 flags 0x02 dlen 27
L2CAP(d): cid 0x0040 len 23 [psm 1]
SDP SSA Rsp: tid 0x0 len 0x12
count 15
record #0
aid 0x0001 (SrvClassIDList)
< uuid-16 0x111e (Handsfree) uuid-16 0x1203 (Audio) >
cont 00
> ACL data: handle 12 flags 0x02 dlen 18
L2CAP(d): cid 0x0041 len 14 [psm 3]
RFCOMM(d): UIH: cr 0 dlci 10 pf 1 ilen 9 fcs 0x76 credits 1
0000: 0d 0a 45 52 52 4f 52 0d 0a ..ERROR..
< ACL data: handle 12 flags 0x02 dlen 8
L2CAP(d): cid 0x0046 len 4 [psm 3]
RFCOMM(s): DISC: cr 1 dlci 10 pf 1 ilen 0 fcs 0x6d



and after the fix (and corresponding fix in oFono):

< ACL data: handle 12 flags 0x02 dlen 19
L2CAP(d): cid 0x0048 len 15 [psm 3]
RFCOMM(d): UIH: cr 1 dlci 10 pf 0 ilen 11 fcs 0xb0
0000: 41 54 2b 42 52 53 46 3d 32 32 0d AT+BRSF=22.
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 12 packets 2
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 12 packets 2
> ACL data: handle 12 flags 0x02 dlen 12
L2CAP(s): Disconn req: dcid 0x0040 scid 0x0041
< ACL data: handle 12 flags 0x02 dlen 12
L2CAP(s): Disconn rsp: dcid 0x0040 scid 0x0041
> ACL data: handle 12 flags 0x02 dlen 28
L2CAP(d): cid 0x0041 len 24 [psm 3]
RFCOMM(d): UIH: cr 0 dlci 10 pf 1 ilen 19 fcs 0x76 credits 1
0000: 0d 0a 2b 42 52 53 46 3a 20 33 33 0d 0a 0d 0a 4f ..+BRSF: 33....O
0010: 4b 0d 0a K..
< ACL data: handle 12 flags 0x02 dlen 18
L2CAP(d): cid 0x0048 len 14 [psm 3]
RFCOMM(d): UIH: cr 1 dlci 10 pf 0 ilen 10 fcs 0xb0
0000: 41 54 2b 43 49 4e 44 3d 3f 0d AT+CIND=?.
---
audio/gateway.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
doc/hfp-api.txt | 2 +-
2 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/audio/gateway.c b/audio/gateway.c
index ec0ec5d..29d8c9c 100644
--- a/audio/gateway.c
+++ b/audio/gateway.c
@@ -64,10 +64,12 @@ struct gateway {
gateway_state_t state;
GIOChannel *rfcomm;
GIOChannel *sco;
+ GIOChannel *incoming;
gateway_stream_cb_t sco_start_cb;
void *sco_start_cb_data;
struct hf_agent *agent;
DBusMessage *msg;
+ int version;
};

int gateway_close(struct audio_device *device);
@@ -128,6 +130,7 @@ 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;

@@ -135,6 +138,7 @@ static gboolean agent_sendfd(struct hf_agent *agent, int fd,
"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)
@@ -263,6 +267,80 @@ fail:
change_state(dev, GATEWAY_STATE_DISCONNECTED);
}

+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;
+}
+
+static void get_incoming_record_cb(sdp_list_t *recs, int err,
+ gpointer user_data)
+{
+ struct audio_device *dev = user_data;
+ struct gateway *gw = dev->gateway;
+ GError *gerr = NULL;
+
+ if (err < 0) {
+ error("Unable to get service record: %s (%d)", strerror(-err),
+ -err);
+ return;
+ }
+
+ if (!recs || !recs->data) {
+ error("No records found");
+ return;
+ }
+
+ gw->version = get_remote_profile_version(recs->data);
+ if (gw->version > 0)
+ rfcomm_connect_cb(gw->incoming, gerr, 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;
+ }
+}
+
+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);
+
+ sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID);
+ if (bt_search_service(&dev->src, &dev->dst, &uuid,
+ get_incoming_record_cb, dev,
+ unregister_incoming))
+ unregister_incoming(dev);
+}
+
static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
{
struct audio_device *dev = user_data;
@@ -297,6 +375,13 @@ 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);

@@ -625,7 +710,7 @@ void gateway_start_service(struct audio_device *dev)
if (gw->rfcomm == NULL)
return;

- if (!bt_io_accept(gw->rfcomm, rfcomm_connect_cb, dev, NULL, &err)) {
+ if (!bt_io_accept(gw->rfcomm, rfcomm_incoming_cb, dev, NULL, &err)) {
error("bt_io_accept: %s", err->message);
g_error_free(err);
}
diff --git a/doc/hfp-api.txt b/doc/hfp-api.txt
index 93251e8..cf2e730 100644
--- a/doc/hfp-api.txt
+++ b/doc/hfp-api.txt
@@ -62,7 +62,7 @@ Service unique name
Interface org.bluez.HandsfreeAgent
Object path freely definable

-Methods void NewConnection(filedescriptor fd)
+Methods void NewConnection(filedescriptor fd, uint16 version)

This method gets called whenever a new handsfree
connection has been established. The objectpath
--
1.7.1



2011-08-04 11:03:49

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH v3] audio: add profile version to HandsfreeAgent

Hi Fr?d?ric,

On Wed, Aug 03, 2011, Fr?d?ric Danis wrote:
> Some phones with HFP Audio Gateway version previous to 1.5 (i.e.
> Samsung SGH-D600 returning 0x0101 as profile version) do not accept
> an AT+BRSF with latest features.
> The Handsfree agent should adapt its AT+BRSF command depending on the
> remote version, so add version information as parameter of
> NewConnection method.
> ---
> audio/gateway.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> doc/hfp-api.txt | 2 +-
> 2 files changed, 87 insertions(+), 2 deletions(-)

Applied. Thanks.

Johan