2012-10-09 11:35:44

by Chan-yeol Park

[permalink] [raw]
Subject: [PATCH v3 1/5] audio: Add check for vendor specific A2DP codec

From: Chan-yeol Park <[email protected]>

This patch adds checks(vendor ID, vendor specific codec ID) to make sure of
vendor specific A2DP codec selection.
---
audio/a2dp-codecs.h | 6 +++++
audio/a2dp.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/audio/a2dp-codecs.h b/audio/a2dp-codecs.h
index 51c796a..2afafa5 100644
--- a/audio/a2dp-codecs.h
+++ b/audio/a2dp-codecs.h
@@ -26,6 +26,7 @@
#define A2DP_CODEC_MPEG12 0x01
#define A2DP_CODEC_MPEG24 0x02
#define A2DP_CODEC_ATRAC 0x03
+#define A2DP_CODEC_VENDOR 0xFF

#define SBC_SAMPLING_FREQ_16000 (1 << 3)
#define SBC_SAMPLING_FREQ_32000 (1 << 2)
@@ -114,3 +115,8 @@ typedef struct {
#else
#error "Unknown byte order"
#endif
+
+typedef struct {
+ uint8_t vendor_id[4];
+ uint8_t codec_id[2];
+} __attribute__ ((packed)) a2dp_vendor_codec_t;
diff --git a/audio/a2dp.c b/audio/a2dp.c
index fd1c494..2c9251a 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -44,6 +44,7 @@
#include "sink.h"
#include "source.h"
#include "a2dp.h"
+#include "a2dp-codecs.h"
#include "sdpd.h"

/* The duration that streams without users are allowed to stay in
@@ -1427,11 +1428,62 @@ done:
finalize_select(setup);
}

+static gboolean vendor_codec_is_matched(uint8_t *remote_cap,
+ size_t remote_cap_len, struct a2dp_sep *sep)
+{
+ uint8_t *capabilities;
+ size_t length;
+
+ a2dp_vendor_codec_t *local_codec;
+ a2dp_vendor_codec_t *remote_codec;
+
+ if (remote_cap_len < sizeof(a2dp_vendor_codec_t))
+ return FALSE;
+
+ remote_codec = (a2dp_vendor_codec_t *) remote_cap;
+
+ DBG("Remote vendor 0x%02x%02x%02x%02x codec 0x%02x%02x",
+ remote_codec->vendor_id[0], remote_codec->vendor_id[1],
+ remote_codec->vendor_id[2], remote_codec->vendor_id[3],
+ remote_codec->codec_id[0], remote_codec->codec_id[1]);
+
+ if (sep->endpoint == NULL)
+ return FALSE;
+
+ length = sep->endpoint->get_capabilities(sep,
+ &capabilities, sep->user_data);
+
+ if (length < sizeof(a2dp_vendor_codec_t))
+ return FALSE;
+
+ local_codec = (a2dp_vendor_codec_t *) capabilities;
+
+ DBG("Registered vendor 0x%02x%02x%02x%02x codec 0x%02x%02x",
+ local_codec->vendor_id[0], local_codec->vendor_id[1],
+ local_codec->vendor_id[2], local_codec->vendor_id[3],
+ local_codec->codec_id[0], local_codec->codec_id[1]);
+
+ if (memcmp(remote_codec->vendor_id, local_codec->vendor_id,
+ sizeof(local_codec->vendor_id)))
+ return FALSE;
+
+ if (memcmp(remote_codec->codec_id, local_codec->codec_id,
+ sizeof(local_codec->codec_id)))
+ return FALSE;
+
+ DBG("Vendor Codec info is matched");
+
+ return TRUE;
+}
+
static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
const char *sender)
{
for (; list; list = list->next) {
struct a2dp_sep *sep = list->data;
+ struct avdtp_remote_sep *rsep;
+ struct avdtp_media_codec_capability *rsep_codec;
+ struct avdtp_service_capability *service;

/* Use sender's endpoint if available */
if (sender) {
@@ -1445,7 +1497,17 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
continue;
}

- if (avdtp_find_remote_sep(session, sep->lsep) == NULL)
+ rsep = avdtp_find_remote_sep(session, sep->lsep);
+ if (rsep == NULL)
+ continue;
+
+ service = avdtp_get_codec(rsep);
+ rsep_codec = (struct avdtp_media_codec_capability *)
+ service->data;
+
+ if (rsep_codec->media_codec_type == A2DP_CODEC_VENDOR &&
+ !vendor_codec_is_matched(rsep_codec->data,
+ service->length - sizeof(*rsep_codec), sep))
continue;

return sep;
--
1.7.9.5



2012-10-09 21:33:05

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v3 1/5] audio: Add check for vendor specific A2DP codec

Hi Chanyeol,

On Tue, Oct 9, 2012 at 1:35 PM, <[email protected]> wrote:
> From: Chan-yeol Park <[email protected]>
>
> This patch adds checks(vendor ID, vendor specific codec ID) to make sure of
> vendor specific A2DP codec selection.
> ---
> audio/a2dp-codecs.h | 6 +++++
> audio/a2dp.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 69 insertions(+), 1 deletion(-)
>
> diff --git a/audio/a2dp-codecs.h b/audio/a2dp-codecs.h
> index 51c796a..2afafa5 100644
> --- a/audio/a2dp-codecs.h
> +++ b/audio/a2dp-codecs.h
> @@ -26,6 +26,7 @@
> #define A2DP_CODEC_MPEG12 0x01
> #define A2DP_CODEC_MPEG24 0x02
> #define A2DP_CODEC_ATRAC 0x03
> +#define A2DP_CODEC_VENDOR 0xFF
>
> #define SBC_SAMPLING_FREQ_16000 (1 << 3)
> #define SBC_SAMPLING_FREQ_32000 (1 << 2)
> @@ -114,3 +115,8 @@ typedef struct {
> #else
> #error "Unknown byte order"
> #endif
> +
> +typedef struct {
> + uint8_t vendor_id[4];
> + uint8_t codec_id[2];
> +} __attribute__ ((packed)) a2dp_vendor_codec_t;
> diff --git a/audio/a2dp.c b/audio/a2dp.c
> index fd1c494..2c9251a 100644
> --- a/audio/a2dp.c
> +++ b/audio/a2dp.c
> @@ -44,6 +44,7 @@
> #include "sink.h"
> #include "source.h"
> #include "a2dp.h"
> +#include "a2dp-codecs.h"
> #include "sdpd.h"
>
> /* The duration that streams without users are allowed to stay in
> @@ -1427,11 +1428,62 @@ done:
> finalize_select(setup);
> }
>
> +static gboolean vendor_codec_is_matched(uint8_t *remote_cap,
> + size_t remote_cap_len, struct a2dp_sep *sep)
> +{
> + uint8_t *capabilities;
> + size_t length;
> +
> + a2dp_vendor_codec_t *local_codec;
> + a2dp_vendor_codec_t *remote_codec;
> +
> + if (remote_cap_len < sizeof(a2dp_vendor_codec_t))
> + return FALSE;
> +
> + remote_codec = (a2dp_vendor_codec_t *) remote_cap;
> +
> + DBG("Remote vendor 0x%02x%02x%02x%02x codec 0x%02x%02x",
> + remote_codec->vendor_id[0], remote_codec->vendor_id[1],
> + remote_codec->vendor_id[2], remote_codec->vendor_id[3],
> + remote_codec->codec_id[0], remote_codec->codec_id[1]);
> +
> + if (sep->endpoint == NULL)
> + return FALSE;
> +
> + length = sep->endpoint->get_capabilities(sep,
> + &capabilities, sep->user_data);
> +
> + if (length < sizeof(a2dp_vendor_codec_t))
> + return FALSE;
> +
> + local_codec = (a2dp_vendor_codec_t *) capabilities;
> +
> + DBG("Registered vendor 0x%02x%02x%02x%02x codec 0x%02x%02x",
> + local_codec->vendor_id[0], local_codec->vendor_id[1],
> + local_codec->vendor_id[2], local_codec->vendor_id[3],
> + local_codec->codec_id[0], local_codec->codec_id[1]);
> +
> + if (memcmp(remote_codec->vendor_id, local_codec->vendor_id,
> + sizeof(local_codec->vendor_id)))
> + return FALSE;
> +
> + if (memcmp(remote_codec->codec_id, local_codec->codec_id,
> + sizeof(local_codec->codec_id)))
> + return FALSE;
> +
> + DBG("Vendor Codec info is matched");
> +
> + return TRUE;
> +}
> +
> static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
> const char *sender)
> {
> for (; list; list = list->next) {
> struct a2dp_sep *sep = list->data;
> + struct avdtp_remote_sep *rsep;
> + struct avdtp_media_codec_capability *rsep_codec;
> + struct avdtp_service_capability *service;
>
> /* Use sender's endpoint if available */
> if (sender) {
> @@ -1445,7 +1497,17 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
> continue;
> }
>
> - if (avdtp_find_remote_sep(session, sep->lsep) == NULL)
> + rsep = avdtp_find_remote_sep(session, sep->lsep);
> + if (rsep == NULL)
> + continue;
> +
> + service = avdtp_get_codec(rsep);
> + rsep_codec = (struct avdtp_media_codec_capability *)
> + service->data;
> +
> + if (rsep_codec->media_codec_type == A2DP_CODEC_VENDOR &&
> + !vendor_codec_is_matched(rsep_codec->data,
> + service->length - sizeof(*rsep_codec), sep))
> continue;
>
> return sep;
> --
> 1.7.9.5

All 5 patches are now upstream, I hope you don't mind but I did some
minor changes before pushing so we only print the vendor and codec
when it matches and other small tweaks to avoid too much indentation
which should make the code easier to read.

--
Luiz Augusto von Dentz

2012-10-09 11:35:48

by Chan-yeol Park

[permalink] [raw]
Subject: [PATCH v3 5/5] audio: Remove redundant procedure when a2dp connect

From: Chan-yeol Park <[email protected]>

This patch fixes the bug that when remote host is down a2dp connection failure
is handled like XCASE
---
audio/avdtp.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/audio/avdtp.c b/audio/avdtp.c
index d905db3..ae1ab7b 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -2411,9 +2411,10 @@ static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
struct avdtp *session = user_data;
char address[18];
- GError *gerr = NULL;
+ int err_no = EIO;

if (err) {
+ err_no = err->code;
error("%s", err->message);
goto failed;
}
@@ -2421,13 +2422,13 @@ static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
if (!session->io)
session->io = g_io_channel_ref(chan);

- bt_io_get(chan, &gerr,
+ bt_io_get(chan, &err,
BT_IO_OPT_OMTU, &session->omtu,
BT_IO_OPT_IMTU, &session->imtu,
BT_IO_OPT_INVALID);
- if (gerr) {
- error("%s", gerr->message);
- g_error_free(gerr);
+ if (err) {
+ err_no = err->code;
+ error("%s", err->message);
goto failed;
}

@@ -2481,7 +2482,7 @@ failed:
avdtp_sep_set_state(session, stream->lsep,
AVDTP_STATE_IDLE);
} else
- connection_lost(session, EIO);
+ connection_lost(session, err_no);
}

static void auth_cb(DBusError *derr, void *user_data)
--
1.7.9.5


2012-10-09 11:35:46

by Chan-yeol Park

[permalink] [raw]
Subject: [PATCH v3 3/5] avinfo: Print a2dp vendor codec info

From: Chan-yeol Park <[email protected]>

---
tools/avinfo.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/tools/avinfo.c b/tools/avinfo.c
index 78a1544..f036cf8 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -158,6 +158,18 @@ struct getcap_resp {
uint8_t caps[0];
} __attribute__ ((packed));

+static void print_vendor(a2dp_vendor_codec_t *vendor)
+{
+ printf("\tMedia Codec: Vendor Specific A2DP Codec");
+
+ printf("\n\t\tVendor ID 0x%02x%02x%02x%02x", vendor->vendor_id[0],
+ vendor->vendor_id[1], vendor->vendor_id[2],
+ vendor->vendor_id[3]);
+
+ printf("\n\t\tVendor Specific Codec ID 0x%02x%02x\n",
+ vendor->codec_id[0], vendor->codec_id[1]);
+}
+

static void print_mpeg12(a2dp_mpeg_t *mpeg)
{
@@ -292,6 +304,9 @@ static void print_media_codec(struct avdtp_media_codec_capability *cap)
case A2DP_CODEC_MPEG12:
print_mpeg12((void *) cap->data);
break;
+ case A2DP_CODEC_VENDOR:
+ print_vendor((void *) cap->data);
+ break;
default:
printf("\tMedia Codec: Unknown\n");
}
--
1.7.9.5


2012-10-09 11:35:47

by Chan-yeol Park

[permalink] [raw]
Subject: [PATCH v3 4/5] audio: Fix audio driver is not probed

From: Chan-yeol Park <[email protected]>

This patch fix the bugs that when handling an AVDTP incoming connection,
audio-a2dp driver is not probed because advanced audio UUID is missed.
---
audio/manager.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/audio/manager.c b/audio/manager.c
index 26cd9bf..b052009 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -1093,7 +1093,8 @@ static struct btd_profile gateway_profile = {
static struct btd_profile a2dp_profile = {
.name = "audio-a2dp",

- .remote_uuids = BTD_UUIDS(A2DP_SOURCE_UUID, A2DP_SINK_UUID),
+ .remote_uuids = BTD_UUIDS(A2DP_SOURCE_UUID, A2DP_SINK_UUID,
+ ADVANCED_AUDIO_UUID),
.device_probe = a2dp_probe,
.device_remove = audio_remove,

--
1.7.9.5


2012-10-09 11:35:45

by Chan-yeol Park

[permalink] [raw]
Subject: [PATCH v3 2/5] avinfo: Replace definitions with a2dp-codecs.h's

From: Chan-yeol Park <[email protected]>

---
audio/a2dp-codecs.h | 21 +++++++++-
tools/avinfo.c | 113 +++------------------------------------------------
2 files changed, 25 insertions(+), 109 deletions(-)

diff --git a/audio/a2dp-codecs.h b/audio/a2dp-codecs.h
index 2afafa5..3dc31cb 100644
--- a/audio/a2dp-codecs.h
+++ b/audio/a2dp-codecs.h
@@ -49,6 +49,9 @@
#define SBC_ALLOCATION_SNR (1 << 1)
#define SBC_ALLOCATION_LOUDNESS 1

+#define MAX_BITPOOL 64
+#define MIN_BITPOOL 2
+
#define MPEG_CHANNEL_MODE_MONO (1 << 3)
#define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
#define MPEG_CHANNEL_MODE_STEREO (1 << 1)
@@ -65,8 +68,22 @@
#define MPEG_SAMPLING_FREQ_44100 (1 << 1)
#define MPEG_SAMPLING_FREQ_48000 1

-#define MAX_BITPOOL 64
-#define MIN_BITPOOL 2
+#define MPEG_BIT_RATE_VBR 0x8000
+#define MPEG_BIT_RATE_320000 0x4000
+#define MPEG_BIT_RATE_256000 0x2000
+#define MPEG_BIT_RATE_224000 0x1000
+#define MPEG_BIT_RATE_192000 0x0800
+#define MPEG_BIT_RATE_160000 0x0400
+#define MPEG_BIT_RATE_128000 0x0200
+#define MPEG_BIT_RATE_112000 0x0100
+#define MPEG_BIT_RATE_96000 0x0080
+#define MPEG_BIT_RATE_80000 0x0040
+#define MPEG_BIT_RATE_64000 0x0020
+#define MPEG_BIT_RATE_56000 0x0010
+#define MPEG_BIT_RATE_48000 0x0008
+#define MPEG_BIT_RATE_40000 0x0004
+#define MPEG_BIT_RATE_32000 0x0002
+#define MPEG_BIT_RATE_FREE 0x0001

#if __BYTE_ORDER == __LITTLE_ENDIAN

diff --git a/tools/avinfo.c b/tools/avinfo.c
index 63b0da6..78a1544 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -39,6 +39,8 @@
#include <sys/ioctl.h>
#include <sys/socket.h>

+#include <a2dp-codecs.h>
+
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
@@ -72,65 +74,6 @@
#define AVDTP_MEDIA_TYPE_VIDEO 0x01
#define AVDTP_MEDIA_TYPE_MULTIMEDIA 0x02

-#define A2DP_CODEC_SBC 0x00
-#define A2DP_CODEC_MPEG12 0x01
-#define A2DP_CODEC_MPEG24 0x02
-#define A2DP_CODEC_ATRAC 0x03
-
-#define SBC_SAMPLING_FREQ_16000 (1 << 3)
-#define SBC_SAMPLING_FREQ_32000 (1 << 2)
-#define SBC_SAMPLING_FREQ_44100 (1 << 1)
-#define SBC_SAMPLING_FREQ_48000 (1 << 0)
-
-#define SBC_CHANNEL_MODE_MONO (1 << 3)
-#define SBC_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
-#define SBC_CHANNEL_MODE_STEREO (1 << 1)
-#define SBC_CHANNEL_MODE_JOINT_STEREO (1 << 0)
-
-#define SBC_BLOCK_LENGTH_4 (1 << 3)
-#define SBC_BLOCK_LENGTH_8 (1 << 2)
-#define SBC_BLOCK_LENGTH_12 (1 << 1)
-#define SBC_BLOCK_LENGTH_16 (1 << 0)
-
-#define SBC_SUBBANDS_4 (1 << 1)
-#define SBC_SUBBANDS_8 (1 << 0)
-
-#define SBC_ALLOCATION_SNR (1 << 1)
-#define SBC_ALLOCATION_LOUDNESS (1 << 0)
-
-#define MPEG_CHANNEL_MODE_MONO (1 << 3)
-#define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
-#define MPEG_CHANNEL_MODE_STEREO (1 << 1)
-#define MPEG_CHANNEL_MODE_JOINT_STEREO (1 << 0)
-
-#define MPEG_LAYER_MP1 (1 << 2)
-#define MPEG_LAYER_MP2 (1 << 1)
-#define MPEG_LAYER_MP3 (1 << 0)
-
-#define MPEG_SAMPLING_FREQ_16000 (1 << 5)
-#define MPEG_SAMPLING_FREQ_22050 (1 << 4)
-#define MPEG_SAMPLING_FREQ_24000 (1 << 3)
-#define MPEG_SAMPLING_FREQ_32000 (1 << 2)
-#define MPEG_SAMPLING_FREQ_44100 (1 << 1)
-#define MPEG_SAMPLING_FREQ_48000 (1 << 0)
-
-#define MPEG_BIT_RATE_VBR 0x8000
-#define MPEG_BIT_RATE_320000 0x4000
-#define MPEG_BIT_RATE_256000 0x2000
-#define MPEG_BIT_RATE_224000 0x1000
-#define MPEG_BIT_RATE_192000 0x0800
-#define MPEG_BIT_RATE_160000 0x0400
-#define MPEG_BIT_RATE_128000 0x0200
-#define MPEG_BIT_RATE_112000 0x0100
-#define MPEG_BIT_RATE_96000 0x0080
-#define MPEG_BIT_RATE_80000 0x0040
-#define MPEG_BIT_RATE_64000 0x0020
-#define MPEG_BIT_RATE_56000 0x0010
-#define MPEG_BIT_RATE_48000 0x0008
-#define MPEG_BIT_RATE_40000 0x0004
-#define MPEG_BIT_RATE_32000 0x0002
-#define MPEG_BIT_RATE_FREE 0x0001
-
struct avdtp_service_capability {
uint8_t category;
uint8_t length;
@@ -169,28 +112,6 @@ struct avdtp_media_codec_capability {
uint8_t data[0];
} __attribute__ ((packed));

-struct sbc_codec_cap {
- struct avdtp_media_codec_capability cap;
- uint8_t channel_mode:4;
- uint8_t frequency:4;
- uint8_t allocation_method:2;
- uint8_t subbands:2;
- uint8_t block_length:4;
- uint8_t min_bitpool;
- uint8_t max_bitpool;
-} __attribute__ ((packed));
-
-struct mpeg_codec_cap {
- struct avdtp_media_codec_capability cap;
- uint8_t channel_mode:4;
- uint8_t crc:1;
- uint8_t layer:3;
- uint8_t frequency:6;
- uint8_t mpf:1;
- uint8_t rfa:1;
- uint16_t bitrate;
-} __attribute__ ((packed));
-
#elif __BYTE_ORDER == __BIG_ENDIAN

struct avdtp_header {
@@ -223,28 +144,6 @@ struct avdtp_media_codec_capability {
uint8_t data[0];
} __attribute__ ((packed));

-struct sbc_codec_cap {
- struct avdtp_media_codec_capability cap;
- uint8_t frequency:4;
- uint8_t channel_mode:4;
- uint8_t block_length:4;
- uint8_t subbands:2;
- uint8_t allocation_method:2;
- uint8_t min_bitpool;
- uint8_t max_bitpool;
-} __attribute__ ((packed));
-
-struct mpeg_codec_cap {
- struct avdtp_media_codec_capability cap;
- uint8_t layer:3;
- uint8_t crc:1;
- uint8_t channel_mode:4;
- uint8_t rfa:1;
- uint8_t mpf:1;
- uint8_t frequency:6;
- uint16_t bitrate;
-} __attribute__ ((packed));
-
#else
#error "Unknown byte order"
#endif
@@ -260,7 +159,7 @@ struct getcap_resp {
} __attribute__ ((packed));


-static void print_mpeg12(struct mpeg_codec_cap *mpeg)
+static void print_mpeg12(a2dp_mpeg_t *mpeg)
{
printf("\tMedia Codec: MPEG12\n\t\tChannel Modes: ");

@@ -341,7 +240,7 @@ static void print_mpeg12(struct mpeg_codec_cap *mpeg)
printf("RFC-2250\n");
}

-static void print_sbc(struct sbc_codec_cap *sbc)
+static void print_sbc(a2dp_sbc_t *sbc)
{
printf("\tMedia Codec: SBC\n\t\tChannel Modes: ");

@@ -388,10 +287,10 @@ static void print_media_codec(struct avdtp_media_codec_capability *cap)
{
switch (cap->media_codec_type) {
case A2DP_CODEC_SBC:
- print_sbc((void *) cap);
+ print_sbc((void *) cap->data);
break;
case A2DP_CODEC_MPEG12:
- print_mpeg12((void *) cap);
+ print_mpeg12((void *) cap->data);
break;
default:
printf("\tMedia Codec: Unknown\n");
--
1.7.9.5