2014-05-26 13:16:26

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 00/26] android: Add aptX support

Hi,

Here are "few" patches which at the end of series add aptX support to BfA.
Of course, since aptX is a proprietary codec, this is only wrapper around
encoder library which has to be provided by platform vendor since it needs
to be licensed. Once one has library, aptX can be enabled in following way:

adb shell setprop persist.sys.bluetooth.codecs aptx
adb shell setprop persist.sys.bluetooth.aptxlib <aptx-library>.so

Note that this works with headsets which have aptX codec registered as
0x0000004f/0x0001 vendor specific codec info which seems to be most common.
However, there is (are?) headset like Kinivo BTH410 which claims aptX support
but has only SEP with vendor codec 0x0000000a/0x0001 which does not seem to
be compatible with first one. It won't work.

Apart from many fixes and aptX support, this patchset also adds definitions
and tools support for AAC. No codec support in HAL audio yet, this is wip
at the moment - there is AAC encoder available in AOSP which can be reused
here. And no pass-through for AAC since it does not seem to be possible,
at least not at the moment.


Andrzej Kaczmarek (26):
android/a2dp: Fix removing device on incoming connection
android: Fix missing include
android/hal-audio: Fix PT in media packets
android/hal-audio: Fix media_packet definition
android/hal-audio: Make RTP header optional
android/hal-audio: Make update_qos optional
android/hal-audio: Send packets only when data were encoded
android/hal-audio: Allow to autoselect endpoint in open_stream IPC
android/hal-audio: Make codecs configurable
android/hal-audio: Add load/unload methods for codec
android/hal-audio: Allow to return 0 from get_presets
audio: Fix a2dp_vendor_codec_t declaration
audio: Add definitions for MPEG-2,4 AAC codec
audio: Add macros to access MPEG-2,4 AAC codec info
audio: Add definitions for aptX
android/a2dp: Fix SEP selection
tools/hcidump: Decode MPEG-2,4 AAC codec capabilities
tools/hcidump: Decode aptX codec capabilities
tools/avinfo: Decode MPEG-2,4 AAC codec capabilities
tools/avinfo: Decode aptX codec capabilities
android: Add avinfo to makefile
android/a2dp: Add support to check MPEG-2,4 AAC caps
android/a2dp: Add support to check aptX capabilities
android/hal-audio-aptx: Add initial support for aptX codec
android/hal-audio-aptx: Load aptX encoder library
android/hal-audio-aptx: Add encoding

android/Android.mk | 29 +++++
android/Makefile.am | 2 +
android/a2dp.c | 134 ++++++++++++++++++++-
android/audio-msg.h | 1 +
android/avdtp.c | 23 ++++
android/avdtp.h | 2 +
android/cutils/properties.h | 1 +
android/hal-audio-aptx.c | 273 +++++++++++++++++++++++++++++++++++++++++++
android/hal-audio-sbc.c | 41 ++++++-
android/hal-audio.c | 185 +++++++++++++++++++++++------
android/hal-audio.h | 26 ++---
profiles/audio/a2dp-codecs.h | 102 +++++++++++++++-
profiles/audio/a2dp.c | 12 +-
tools/avinfo.c | 88 ++++++++++++--
tools/parser/avdtp.c | 103 +++++++++++++++-
15 files changed, 941 insertions(+), 81 deletions(-)
create mode 100644 android/hal-audio-aptx.c

--
1.9.3



2014-05-26 13:16:35

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 09/26] android/hal-audio: Make codecs configurable

When supporting more codecs we need way to easily configure which ones
should be registered as endpoints. This patch adds support to specify
list of codecs to be loaded in "persist.sys.bluetooth.codecs" property
which is comma-separated case-insensitive list.

Codecs shall be listed in order of preference, i.e. 1st one is most
preferred. SBC codec is always loaded and there's no need to specify
it.
---
android/Makefile.am | 1 +
android/hal-audio.c | 85 ++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 72 insertions(+), 14 deletions(-)

diff --git a/android/Makefile.am b/android/Makefile.am
index 2d74505..6891cbc 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -169,6 +169,7 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
android/hal-audio.h \
android/hal-audio.c \
android/hal-audio-sbc.c \
+ android/cutils/properties.h \
android/hardware/audio.h \
android/hardware/audio_effect.h \
android/hardware/hardware.h \
diff --git a/android/hal-audio.c b/android/hal-audio.c
index 8b82498..e6015f2 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -27,6 +27,7 @@
#include <arpa/inet.h>
#include <fcntl.h>

+#include <cutils/properties.h>
#include <hardware/audio.h>
#include <hardware/hardware.h>

@@ -96,8 +97,11 @@ extern int clock_nanosleep(clockid_t clock_id, int flags,
struct timespec *remain);
#endif

-static const audio_codec_get_t audio_codecs[] = {
- codec_sbc,
+static const struct audio_codec_info {
+ const char *name;
+ const struct audio_codec * (*get) (void);
+} audio_codecs[] = {
+ { "sbc", codec_sbc },
};

#define NUM_CODECS (sizeof(audio_codecs) / sizeof(audio_codecs[0]))
@@ -415,27 +419,80 @@ static int ipc_suspend_stream_cmd(uint8_t endpoint_id)
return result;
}

-static int register_endpoints(void)
+static void register_endpoint(const char *codec_name)
{
- struct audio_endpoint *ep = &audio_endpoints[0];
+ const struct audio_codec *codec = NULL;
+ struct audio_endpoint *ep;
size_t i;

- for (i = 0; i < NUM_CODECS; i++, ep++) {
- const struct audio_codec *codec = audio_codecs[i]();
+ for (i = 0; i < NUM_CODECS; i++)
+ if (!strcasecmp(audio_codecs[i].name, codec_name)) {
+ codec = audio_codecs[i].get();
+ break;
+ }

- if (!codec)
- return AUDIO_STATUS_FAILED;
+ if (!codec) {
+ error("Failed to register endpoint for %s", codec_name);
+ return;
+ }

- ep->id = ipc_open_cmd(codec);
+ for (i = 0; i < MAX_AUDIO_ENDPOINTS; i++) {
+ /* Do not register the same codec twice */
+ if (audio_endpoints[i].codec == codec)
+ return;

- if (!ep->id)
- return AUDIO_STATUS_FAILED;
+ if (!audio_endpoints[i].id)
+ break;
+ }

- ep->codec = codec;
- ep->codec_data = NULL;
- ep->fd = -1;
+ /* We have the same number of endpoints and codecs so we'll always find
+ * free endpoint - no need to check this here.
+ */
+
+ ep = &audio_endpoints[i];
+
+ ep->id = ipc_open_cmd(codec);
+
+ if (!ep->id) {
+ error("Failed to open endpoint for %s", codec_name);
+ return;
}

+ ep->codec = codec;
+ ep->codec_data = NULL;
+ ep->fd = -1;
+
+ info("Opened endpoint for %s", codec_name);
+}
+
+static int register_endpoints(void)
+{
+ char value[PROPERTY_VALUE_MAX];
+ char *name, *p;
+
+ if (property_get("persist.sys.bluetooth.codecs", value, "") < 0)
+ return AUDIO_STATUS_FAILED;
+
+ p = value;
+
+ do {
+ name = p;
+ p = strchr(name, ',');
+ if (p) {
+ *p = '\0';
+ p++;
+ }
+ if (!strlen(name))
+ continue;
+
+ register_endpoint(name);
+ } while (p);
+
+ /* SBC is mandatory and should always be registered, even if it's not
+ * specified in prop
+ */
+ register_endpoint("sbc");
+
return AUDIO_STATUS_SUCCESS;
}

--
1.9.3


2014-05-26 13:16:34

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 08/26] android/hal-audio: Allow to autoselect endpoint in open_stream IPC

audio_open_output_stream always tries to open 1st registered endpoint
based on assumption that there is only one endpoint registered anyway
(due to support for only one codec). With more endpoints available in
future we need to be able to retrieve endpoint id which is connected
and use it for streaming.

This patch adds special case for id=0 in open_stream IPC to return 1st
opened endpoint on BlueZ side which is enough for now since only one
headset can be connected at any time (i.e. we should not have more
than 1 endpoint opened).
---
android/a2dp.c | 6 +++++-
android/audio-msg.h | 1 +
android/hal-audio.c | 36 ++++++++++++++++++++++++++++--------
3 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 10141d1..c8119da 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1357,7 +1357,10 @@ static void bt_stream_open(const void *buf, uint16_t len)

DBG("");

- setup = find_setup(cmd->id);
+ if (cmd->id)
+ setup = find_setup(cmd->id);
+ else
+ setup = setups ? setups->data : NULL;
if (!setup) {
error("Unable to find stream for endpoint %u", cmd->id);
ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
@@ -1376,6 +1379,7 @@ static void bt_stream_open(const void *buf, uint16_t len)
len = sizeof(struct audio_rsp_open_stream) +
sizeof(struct audio_preset) + setup->preset->len;
rsp = g_malloc0(len);
+ rsp->id = setup->endpoint->id;
rsp->mtu = omtu;
rsp->preset->len = setup->preset->len;
memcpy(rsp->preset->data, setup->preset->data, setup->preset->len);
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 5981355..7b9553b 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -61,6 +61,7 @@ struct audio_cmd_open_stream {
} __attribute__((packed));

struct audio_rsp_open_stream {
+ uint16_t id;
uint16_t mtu;
struct audio_preset preset[0];
} __attribute__((packed));
diff --git a/android/hal-audio.c b/android/hal-audio.c
index 9807a5d..8b82498 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -337,7 +337,7 @@ static int ipc_close_cmd(uint8_t endpoint_id)
return result;
}

-static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu, int *fd,
+static int ipc_open_stream_cmd(uint8_t *endpoint_id, uint16_t *mtu, int *fd,
struct audio_preset **caps)
{
char buf[BLUEZ_AUDIO_MTU];
@@ -352,13 +352,14 @@ static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu, int *fd,
if (!caps)
return AUDIO_STATUS_FAILED;

- cmd.id = endpoint_id;
+ cmd.id = *endpoint_id;

result = audio_ipc_cmd(AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
sizeof(cmd), &cmd, &rsp_len, rsp, fd);
if (result == AUDIO_STATUS_SUCCESS) {
size_t buf_len = sizeof(struct audio_preset) +
rsp->preset[0].len;
+ *endpoint_id = rsp->id;
*mtu = rsp->mtu;
*caps = malloc(buf_len);
memcpy(*caps, &rsp->preset, buf_len);
@@ -452,20 +453,39 @@ static void unregister_endpoints(void)
}
}

-static bool open_endpoint(struct audio_endpoint *ep,
+static bool open_endpoint(struct audio_endpoint **epp,
struct audio_input_config *cfg)
{
struct audio_preset *preset;
+ struct audio_endpoint *ep = *epp;
const struct audio_codec *codec;
uint16_t mtu;
uint16_t payload_len;
int fd;
+ size_t i;
+ uint8_t ep_id = 0;
+
+ if (ep)
+ ep_id = ep->id;

- if (ipc_open_stream_cmd(ep->id, &mtu, &fd, &preset) !=
+ if (ipc_open_stream_cmd(&ep_id, &mtu, &fd, &preset) !=
AUDIO_STATUS_SUCCESS)
return false;

- DBG("mtu=%u", mtu);
+ DBG("ep_id=%d mtu=%u", ep_id, mtu);
+
+ for (i = 0; i < MAX_AUDIO_ENDPOINTS; i++)
+ if (audio_endpoints[i].id == ep_id) {
+ ep = &audio_endpoints[i];
+ break;
+ }
+
+ if (!ep) {
+ error("Cound not find opened endpoint");
+ return false;
+ }
+
+ *epp = ep;

payload_len = mtu;
if (ep->codec->use_rtp)
@@ -1096,10 +1116,10 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
out->stream.write = out_write;
out->stream.get_render_position = out_get_render_position;

- /* TODO: for now we always use endpoint 0 */
- out->ep = &audio_endpoints[0];
+ /* We want to autoselect opened endpoint */
+ out->ep = NULL;

- if (!open_endpoint(out->ep, &out->cfg))
+ if (!open_endpoint(&out->ep, &out->cfg))
goto fail;

DBG("rate=%d channels=%d format=%d", out->cfg.rate,
--
1.9.3


2014-05-26 13:16:29

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 03/26] android/hal-audio: Fix PT in media packets

According to A2DP 1.3 spec section 4.3.3.2:
"A payload type in the RTP dynamic range shall be chosen (see [22],
section 3)." - [22] = RFC3551

As per referenced RFC3551, values in range 96-127 are reserved for
dynamic assignment so we can set PT to 96.
---
android/hal-audio.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 49b829a..49393e2 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -479,7 +479,7 @@ static bool open_endpoint(struct audio_endpoint *ep,
if (!ep->mp)
goto failed;
ep->mp->hdr.v = 2;
- ep->mp->hdr.pt = 1;
+ ep->mp->hdr.pt = 0x60;
ep->mp->hdr.ssrc = htonl(1);

ep->mp_data_len = payload_len;
--
1.9.3


2014-05-26 13:16:40

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 14/26] audio: Add macros to access MPEG-2,4 AAC codec info

This patch provides helper macros to get, set and init-in-struct both
frequency and bitrate fields in codec info structs for MPEG-2,4 AAC.
---
profiles/audio/a2dp-codecs.h | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h
index e2e1a77..1106bd2 100644
--- a/profiles/audio/a2dp-codecs.h
+++ b/profiles/audio/a2dp-codecs.h
@@ -106,6 +106,30 @@
#define AAC_CHANNELS_1 0x02
#define AAC_CHANNELS_2 0x01

+#define AAC_GET_BITRATE(a) ((a).bitrate1 << 16 | \
+ (a).bitrate2 << 8 | (a).bitrate3)
+#define AAC_GET_FREQUENCY(a) ((a).frequency1 << 4 | (a).frequency2)
+
+#define AAC_SET_BITRATE(a, b) \
+ do { \
+ (a).bitrate1 = (b >> 16) & 0x7f; \
+ (a).bitrate2 = (b >> 8) & 0xff; \
+ (a).bitrate3 = b & 0xff; \
+ } while (0)
+#define AAC_SET_FREQUENCY(a, f) \
+ do { \
+ (a).frequency1 = (f >> 4) & 0xff; \
+ (a).frequency2 = f & 0x0f; \
+ } while (0)
+
+#define AAC_INIT_BITRATE(b) \
+ .bitrate1 = (b >> 16) & 0x7f, \
+ .bitrate2 = (b >> 8) & 0xff, \
+ .bitrate3 = b & 0xff,
+#define AAC_INIT_FREQUENCY(f) \
+ .frequency1 = (f >> 4) & 0xff, \
+ .frequency2 = f & 0x0f,
+
#if __BYTE_ORDER == __LITTLE_ENDIAN

typedef struct {
--
1.9.3


2014-05-26 13:16:39

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 13/26] audio: Add definitions for MPEG-2,4 AAC codec

frequency and bitrate bit-fields are splitted into separate bytes since
they span across byte-boundary and cannot be set easily on LE arch
anyway.
---
profiles/audio/a2dp-codecs.h | 45 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)

diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h
index 0f44b10..e2e1a77 100644
--- a/profiles/audio/a2dp-codecs.h
+++ b/profiles/audio/a2dp-codecs.h
@@ -85,6 +85,27 @@
#define MPEG_BIT_RATE_32000 0x0002
#define MPEG_BIT_RATE_FREE 0x0001

+#define AAC_OBJECT_TYPE_MPEG2_AAC_LC 0x80
+#define AAC_OBJECT_TYPE_MPEG4_AAC_LC 0x40
+#define AAC_OBJECT_TYPE_MPEG4_AAC_LTP 0x20
+#define AAC_OBJECT_TYPE_MPEG4_AAC_SCA 0x10
+
+#define AAC_SAMPLING_FREQ_8000 0x0800
+#define AAC_SAMPLING_FREQ_11025 0x0400
+#define AAC_SAMPLING_FREQ_12000 0x0200
+#define AAC_SAMPLING_FREQ_16000 0x0100
+#define AAC_SAMPLING_FREQ_22050 0x0080
+#define AAC_SAMPLING_FREQ_24000 0x0040
+#define AAC_SAMPLING_FREQ_32000 0x0020
+#define AAC_SAMPLING_FREQ_44100 0x0010
+#define AAC_SAMPLING_FREQ_48000 0x0008
+#define AAC_SAMPLING_FREQ_64000 0x0004
+#define AAC_SAMPLING_FREQ_88200 0x0002
+#define AAC_SAMPLING_FREQ_96000 0x0001
+
+#define AAC_CHANNELS_1 0x02
+#define AAC_CHANNELS_2 0x01
+
#if __BYTE_ORDER == __LITTLE_ENDIAN

typedef struct {
@@ -107,6 +128,18 @@ typedef struct {
uint16_t bitrate;
} __attribute__ ((packed)) a2dp_mpeg_t;

+typedef struct {
+ uint8_t object_type;
+ uint8_t frequency1;
+ uint8_t rfa:2;
+ uint8_t channels:2;
+ uint8_t frequency2:4;
+ uint8_t bitrate1:7;
+ uint8_t vbr:1;
+ uint8_t bitrate2;
+ uint8_t bitrate3;
+} __attribute__ ((packed)) a2dp_aac_t;
+
#elif __BYTE_ORDER == __BIG_ENDIAN

typedef struct {
@@ -129,6 +162,18 @@ typedef struct {
uint16_t bitrate;
} __attribute__ ((packed)) a2dp_mpeg_t;

+typedef struct {
+ uint8_t object_type;
+ uint8_t frequency1;
+ uint8_t frequency2:4;
+ uint8_t channels:2;
+ uint8_t rfa:2;
+ uint8_t vbr:1;
+ uint8_t bitrate1:7;
+ uint8_t bitrate2;
+ uint8_t bitrate3;
+} __attribute__ ((packed)) a2dp_aac_t;
+
#else
#error "Unknown byte order"
#endif
--
1.9.3


2014-05-26 13:16:38

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 12/26] audio: Fix a2dp_vendor_codec_t declaration

As per A2DP spec, both Vendor ID (4.7.2.1) and Codec ID (4.7.2.2) are
defined as 32-bit and 16-bit values respectively rather that array of
bytes. Also changing to uint types will make using these values in code
much easier.
---
profiles/audio/a2dp-codecs.h | 4 ++--
profiles/audio/a2dp.c | 12 ++++--------
tools/avinfo.c | 8 +++-----
3 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h
index 3dc31cb..0f44b10 100644
--- a/profiles/audio/a2dp-codecs.h
+++ b/profiles/audio/a2dp-codecs.h
@@ -134,6 +134,6 @@ typedef struct {
#endif

typedef struct {
- uint8_t vendor_id[4];
- uint8_t codec_id[2];
+ uint32_t vendor_id;
+ uint16_t codec_id;
} __attribute__ ((packed)) a2dp_vendor_codec_t;
diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index cabdd66..c9dac9a 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -1390,18 +1390,14 @@ static gboolean check_vendor_codec(struct a2dp_sep *sep, uint8_t *cap,

local_codec = (a2dp_vendor_codec_t *) capabilities;

- if (memcmp(remote_codec->vendor_id, local_codec->vendor_id,
- sizeof(local_codec->vendor_id)))
+ if (btohl(remote_codec->vendor_id) != btohl(local_codec->vendor_id))
return FALSE;

- if (memcmp(remote_codec->codec_id, local_codec->codec_id,
- sizeof(local_codec->codec_id)))
+ if (btohs(remote_codec->codec_id) != btohs(local_codec->codec_id))
return FALSE;

- DBG("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]);
+ DBG("vendor 0x%08x codec 0x%04x", btohl(remote_codec->vendor_id),
+ btohs(remote_codec->codec_id));

return TRUE;
}
diff --git a/tools/avinfo.c b/tools/avinfo.c
index a4deaac..e7747db 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -162,12 +162,10 @@ 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 ID 0x%08x", btohl(vendor->vendor_id));

- printf("\n\t\tVendor Specific Codec ID 0x%02x%02x\n",
- vendor->codec_id[0], vendor->codec_id[1]);
+ printf("\n\t\tVendor Specific Codec ID 0x%04x\n",
+ btohs(vendor->codec_id));
}

static void print_mpeg24(a2dp_mpeg_t *mpeg)
--
1.9.3


2014-05-26 13:16:37

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 11/26] android/hal-audio: Allow to return 0 from get_presets

This patch makes legal to return 0 from get_presets which is useful to
inform HAL core that codec is not initialized properly and codec should
not be used (it has no caps and no presets).
---
android/hal-audio.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 416a3ad..1ab4b01 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -315,6 +315,9 @@ static int ipc_open_cmd(const struct audio_codec *codec)
cmd->codec = codec->type;
cmd->presets = codec->get_presets(cmd->preset, &cmd_len);

+ if (!cmd->presets)
+ return 0;
+
cmd_len += sizeof(*cmd);

result = audio_ipc_cmd(AUDIO_SERVICE_ID, AUDIO_OP_OPEN, cmd_len, cmd,
--
1.9.3


2014-05-26 13:16:31

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 05/26] android/hal-audio: Make RTP header optional

Not every codec on A2DP will use RTP so it's now optional - codec can
be defined to use it and core will take care of filling the data.
---
android/hal-audio-sbc.c | 3 ++-
android/hal-audio.c | 30 ++++++++++++++++++++++--------
android/hal-audio.h | 5 +++++
3 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/android/hal-audio-sbc.c b/android/hal-audio-sbc.c
index 8366978..ad20f51 100644
--- a/android/hal-audio-sbc.c
+++ b/android/hal-audio-sbc.c
@@ -56,7 +56,7 @@ struct rtp_payload {
#endif

struct media_packet_sbc {
- struct media_packet hdr;
+ struct media_packet_rtp hdr;
struct rtp_payload payload;
uint8_t data[0];
};
@@ -405,6 +405,7 @@ static bool sbc_update_qos(void *codec_data, uint8_t op)

static const struct audio_codec codec = {
.type = A2DP_CODEC_SBC,
+ .use_rtp = true,

.get_presets = sbc_get_presets,

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 49393e2..946a835 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -467,7 +467,9 @@ static bool open_endpoint(struct audio_endpoint *ep,

DBG("mtu=%u", mtu);

- payload_len = mtu - sizeof(*ep->mp);
+ payload_len = mtu;
+ if (ep->codec->use_rtp)
+ payload_len -= sizeof(struct rtp_header);

ep->fd = fd;

@@ -478,9 +480,14 @@ static bool open_endpoint(struct audio_endpoint *ep,
ep->mp = calloc(mtu, 1);
if (!ep->mp)
goto failed;
- ep->mp->hdr.v = 2;
- ep->mp->hdr.pt = 0x60;
- ep->mp->hdr.ssrc = htonl(1);
+
+ if (ep->codec->use_rtp) {
+ struct media_packet_rtp *mp_rtp =
+ (struct media_packet_rtp *) ep->mp;
+ mp_rtp->hdr.v = 2;
+ mp_rtp->hdr.pt = 0x60;
+ mp_rtp->hdr.ssrc = htonl(1);
+ }

ep->mp_data_len = payload_len;

@@ -574,7 +581,7 @@ static bool write_to_endpoint(struct audio_endpoint *ep, size_t bytes)
int ret;

while (true) {
- ret = write(ep->fd, mp, sizeof(*mp) + bytes);
+ ret = write(ep->fd, mp, bytes);

if (ret >= 0)
break;
@@ -604,6 +611,7 @@ static bool write_data(struct a2dp_stream_out *out, const void *buffer,
{
struct audio_endpoint *ep = out->ep;
struct media_packet *mp = (struct media_packet *) ep->mp;
+ struct media_packet_rtp *mp_rtp = (struct media_packet_rtp *) ep->mp;
size_t free_space = ep->mp_data_len;
size_t consumed = 0;

@@ -620,8 +628,10 @@ static bool write_data(struct a2dp_stream_out *out, const void *buffer,
* prepare media packet in advance so we don't waste time after
* wakeup
*/
- mp->hdr.sequence_number = htons(ep->seq++);
- mp->hdr.timestamp = htonl(ep->samples);
+ if (ep->codec->use_rtp) {
+ mp_rtp->hdr.sequence_number = htons(ep->seq++);
+ mp_rtp->hdr.timestamp = htonl(ep->samples);
+ }
read = ep->codec->encode_mediapacket(ep->codec_data,
buffer + consumed,
bytes - consumed, mp,
@@ -687,9 +697,13 @@ static bool write_data(struct a2dp_stream_out *out, const void *buffer,
if (!wait_for_endpoint(ep, &do_write))
return false;

- if (do_write)
+ if (do_write) {
+ if (ep->codec->use_rtp)
+ written += sizeof(struct rtp_header);
+
if (!write_to_endpoint(ep, written))
return false;
+ }
}

/*
diff --git a/android/hal-audio.h b/android/hal-audio.h
index dc1a812..be71473 100644
--- a/android/hal-audio.h
+++ b/android/hal-audio.h
@@ -57,6 +57,10 @@ struct rtp_header {
#endif

struct media_packet {
+ uint8_t data[0];
+};
+
+struct media_packet_rtp {
struct rtp_header hdr;
uint8_t data[0];
};
@@ -69,6 +73,7 @@ struct audio_input_config {

struct audio_codec {
uint8_t type;
+ bool use_rtp;

int (*get_presets) (struct audio_preset *preset, size_t *len);

--
1.9.3


2014-05-26 13:16:32

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 06/26] android/hal-audio: Make update_qos optional

---
android/hal-audio.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 946a835..534620a 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -524,7 +524,8 @@ static bool resume_endpoint(struct audio_endpoint *ep)
ep->samples = 0;
ep->resync = false;

- ep->codec->update_qos(ep->codec_data, QOS_POLICY_DEFAULT);
+ if (ep->codec->update_qos)
+ ep->codec->update_qos(ep->codec_data, QOS_POLICY_DEFAULT);

return true;
}
@@ -683,7 +684,8 @@ static bool write_data(struct a2dp_stream_out *out, const void *buffer,
if (diff > MAX_DELAY) {
warn("lag is %jums, resyncing", diff / 1000);

- ep->codec->update_qos(ep->codec_data,
+ if (ep->codec->update_qos)
+ ep->codec->update_qos(ep->codec_data,
QOS_POLICY_DECREASE);
ep->resync = true;
}
--
1.9.3


2014-05-26 13:16:46

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 20/26] tools/avinfo: Decode aptX codec capabilities

---
tools/avinfo.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/tools/avinfo.c b/tools/avinfo.c
index 7e9dfd1..7d58e25 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -158,14 +158,42 @@ struct getcap_resp {
uint8_t caps[0];
} __attribute__ ((packed));

+static void print_aptx(a2dp_aptx_t *aptx)
+{
+ printf("\t\tVendor Specific Value (aptX)");
+
+ printf("\n\t\t\tFrequencies: ");
+ if (aptx->frequency & APTX_SAMPLING_FREQ_16000)
+ printf("16kHz ");
+ if (aptx->frequency & APTX_SAMPLING_FREQ_32000)
+ printf("32kHz ");
+ if (aptx->frequency & APTX_SAMPLING_FREQ_44100)
+ printf("44.1kHz ");
+ if (aptx->frequency & APTX_SAMPLING_FREQ_48000)
+ printf("48kHz ");
+
+ printf("\n\t\t\tChannel modes: ");
+ if (aptx->channel_mode & APTX_CHANNEL_MODE_MONO)
+ printf("Mono ");
+ if (aptx->channel_mode & APTX_CHANNEL_MODE_STEREO)
+ printf("Stereo ");
+
+ printf("\n");
+}
+
static void print_vendor(a2dp_vendor_codec_t *vendor)
{
+ uint32_t vendor_id = btohl(vendor->vendor_id);
+ uint16_t codec_id = btohs(vendor->codec_id);
+
printf("\tMedia Codec: Vendor Specific A2DP Codec");

- printf("\n\t\tVendor ID 0x%08x", btohl(vendor->vendor_id));
+ printf("\n\t\tVendor ID 0x%08x", vendor_id);
+
+ printf("\n\t\tVendor Specific Codec ID 0x%04x\n", codec_id);

- printf("\n\t\tVendor Specific Codec ID 0x%04x\n",
- btohs(vendor->codec_id));
+ if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+ print_aptx((void *) vendor);
}

static void print_mpeg24(a2dp_aac_t *aac)
--
1.9.3


2014-05-26 13:16:49

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 23/26] android/a2dp: Add support to check aptX capabilities

---
android/a2dp.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/android/a2dp.c b/android/a2dp.c
index a65c94d..f825cce 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -373,10 +373,40 @@ static int mpeg24_check_config(void *caps, uint8_t caps_len, void *conf,
return 0;
}

+static int aptx_check_config(void *caps, uint8_t caps_len, void *conf,
+ uint8_t conf_len)
+{
+ a2dp_aptx_t *cap, *config;
+
+ if (conf_len != caps_len || conf_len != sizeof(a2dp_aptx_t)) {
+ error("APTX: Invalid configuration size (%u)", conf_len);
+ return -EINVAL;
+ }
+
+ cap = caps;
+ config = conf;
+
+ if (!(cap->frequency & config->frequency)) {
+ error("APTX: Unsupported frequenct (%u) by endpoint",
+ config->frequency);
+ return -EINVAL;
+ }
+
+ if (!(cap->channel_mode & config->channel_mode)) {
+ error("AAC: Unsupported channel mode (%u) by endpoint",
+ config->channel_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int check_capabilities(struct a2dp_preset *preset,
struct avdtp_media_codec_capability *codec,
uint8_t codec_len)
{
+ a2dp_vendor_codec_t *vndcodec;
+
/* Codec specific */
switch (codec->media_codec_type) {
case A2DP_CODEC_SBC:
@@ -385,6 +415,13 @@ static int check_capabilities(struct a2dp_preset *preset,
case A2DP_CODEC_MPEG24:
return mpeg24_check_config(codec->data, codec_len, preset->data,
preset->len);
+ case A2DP_CODEC_VENDOR:
+ vndcodec = (void *) codec->data;
+ if (btohl(vndcodec->vendor_id) == APTX_VENDOR_ID &&
+ btohs(vndcodec->codec_id) == APTX_CODEC_ID)
+ return aptx_check_config(codec->data, codec_len,
+ preset->data, preset->len);
+ return -EINVAL;
default:
return -EINVAL;
}
--
1.9.3


2014-05-26 13:16:43

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 17/26] tools/hcidump: Decode MPEG-2,4 AAC codec capabilities

---
tools/parser/avdtp.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/tools/parser/avdtp.c b/tools/parser/avdtp.c
index 5a2ee55..5806c07 100644
--- a/tools/parser/avdtp.c
+++ b/tools/parser/avdtp.c
@@ -212,7 +212,9 @@ static void capabilities(int level, struct frame *frm)
len = get_u8(frm);

if (cat == 7) {
- uint8_t type, codec, tmp;
+ uint8_t type, codec;
+ uint16_t tmp, freq;
+ uint32_t bitrate;

type = get_u8(frm);
codec = get_u8(frm);
@@ -269,6 +271,59 @@ static void capabilities(int level, struct frame *frm)
p_indent(level + 1, frm);
printf("Bitpool Range %d-%d\n", tmp, get_u8(frm));
break;
+ case 2:
+ tmp = get_u8(frm);
+ p_indent(level + 1, frm);
+ if (tmp & 0x80)
+ printf("MPEG-2 AAC LC ");
+ if (tmp & 0x40)
+ printf("MPEG-4 AAC LC ");
+ if (tmp & 0x20)
+ printf("MPEG-4 AAC LTP ");
+ if (tmp & 0x10)
+ printf("MPEG-4 AAC scalable ");
+ printf("\n");
+ tmp = get_u16(frm);
+ freq = tmp >> 4;
+ p_indent(level + 1, frm);
+ if (freq & 0x0800)
+ printf("8kHz ");
+ if (freq & 0x0400)
+ printf("11.025kHz ");
+ if (freq & 0x0200)
+ printf("12kHz ");
+ if (freq & 0x0100)
+ printf("16kHz ");
+ if (freq & 0x0080)
+ printf("22.05kHz ");
+ if (freq & 0x0040)
+ printf("24kHz ");
+ if (freq & 0x0020)
+ printf("32kHz ");
+ if (freq & 0x0010)
+ printf("44.1kHz ");
+ if (freq & 0x0008)
+ printf("48kHz ");
+ if (freq & 0x0004)
+ printf("64kHz ");
+ if (freq & 0x0002)
+ printf("88.2kHz ");
+ if (freq & 0x0001)
+ printf("96kHz ");
+ printf("\n");
+ tmp >>= 2;
+ p_indent(level + 1, frm);
+ if (tmp & 0x02)
+ printf("1 ");
+ if (tmp & 0x01)
+ printf("2 ");
+ printf("Channels\n");
+ tmp = get_u8(frm);
+ bitrate = ((tmp & 0x7f) << 16) | get_u16(frm);
+ p_indent(level + 1, frm);
+ printf("%ubps ", bitrate);
+ printf("%s\n", tmp & 0x80 ? "VBR" : "");
+ break;
default:
hex_dump(level + 1, frm, len - 2);
frm->ptr += (len - 2);
--
1.9.3


2014-05-26 13:16:51

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 25/26] android/hal-audio-aptx: Load aptX encoder library

This patch adds loding of aptX encoder library which should be provided
by user. Name of library needs to be configured using system property
(persist.sys.bluetooth.aptxlib).
---
android/hal-audio-aptx.c | 54 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 3 deletions(-)

diff --git a/android/hal-audio-aptx.c b/android/hal-audio-aptx.c
index 1cf8afc..4099c07 100644
--- a/android/hal-audio-aptx.c
+++ b/android/hal-audio-aptx.c
@@ -63,15 +63,60 @@ static const a2dp_aptx_t aptx_presets[] = {
},
};

+static void *aptx_dl;
+static int aptx_sizeof = 0;
+static int (*aptx_init)(void *, short);
+static int (*aptx_encode)(void *, void *, void *, void *);
+
static bool aptx_load(void)
{
- /* TODO: load aptX codec library */
- return false;
+ const char * (*aptx_version)(void);
+ const char * (*aptx_build)(void);
+ int (*aptx_sizeofenc)(void);
+ char libname[PROPERTY_VALUE_MAX];
+
+ if (property_get("persist.sys.bluetooth.aptxlib", libname, "") < 0)
+ return AUDIO_STATUS_FAILED;
+
+ aptx_dl = dlopen(libname, RTLD_LAZY);
+ if (!aptx_dl) {
+ error("APTX: failed to open library %s (%s)", libname,
+ dlerror());
+ return false;
+ }
+
+ aptx_version = dlsym(aptx_dl, "aptxbtenc_version");
+ aptx_build = dlsym(aptx_dl, "aptxbtenc_build");
+
+ if (aptx_version && aptx_build)
+ info("APTX: using library version %s build %s", aptx_version(),
+ aptx_build());
+ else
+ warn("APTX: cannot retrieve library version");
+
+ aptx_sizeofenc = dlsym(aptx_dl, "SizeofAptxbtenc");
+ aptx_init = dlsym(aptx_dl, "aptxbtenc_init");
+ aptx_encode = dlsym(aptx_dl, "aptxbtenc_encodestereo");
+ if (!aptx_sizeofenc || !aptx_init || !aptx_encode) {
+ error("APTX: failed initialize library");
+ dlclose(aptx_dl);
+ aptx_dl = NULL;
+ return false;
+ }
+
+ aptx_sizeof = aptx_sizeofenc();
+
+ info("APTX: codec library initialized (size=%d)", aptx_sizeof);
+
+ return true;
}

static void aptx_unload(void)
{
- /* TODO: unload aptX codec library */
+ if (aptx_dl) {
+ dlclose(aptx_dl);
+ aptx_dl = NULL;
+ }
}

static int aptx_get_presets(struct audio_preset *preset, size_t *len)
@@ -84,6 +129,9 @@ static int aptx_get_presets(struct audio_preset *preset, size_t *len)

DBG("");

+ if (!aptx_dl)
+ return 0;
+
count = sizeof(aptx_presets) / sizeof(aptx_presets[0]);

for (i = 0; i < count; i++) {
--
1.9.3


2014-05-26 13:16:45

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 19/26] tools/avinfo: Decode MPEG-2,4 AAC codec capabilities

---
tools/avinfo.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/tools/avinfo.c b/tools/avinfo.c
index e7747db..7e9dfd1 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -168,9 +168,57 @@ static void print_vendor(a2dp_vendor_codec_t *vendor)
btohs(vendor->codec_id));
}

-static void print_mpeg24(a2dp_mpeg_t *mpeg)
+static void print_mpeg24(a2dp_aac_t *aac)
{
- printf("\tMedia Codec: MPEG24\n");
+ unsigned freq = AAC_GET_FREQUENCY(*aac);
+ unsigned bitrate = AAC_GET_BITRATE(*aac);
+
+ printf("\tMedia Codec: MPEG24\n\t\tObject Types: ");
+
+ if (aac->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC)
+ printf("MPEG-2 AAC LC ");
+ if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC)
+ printf("MPEG-4 AAC LC ");
+ if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP)
+ printf("MPEG-4 AAC LTP ");
+ if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCA)
+ printf("MPEG-4 AAC scalable ");
+
+ printf("\n\t\tFrequencies: ");
+ if (freq & AAC_SAMPLING_FREQ_8000)
+ printf("8kHz ");
+ if (freq & AAC_SAMPLING_FREQ_11025)
+ printf("11.025kHz ");
+ if (freq & AAC_SAMPLING_FREQ_12000)
+ printf("12kHz ");
+ if (freq & AAC_SAMPLING_FREQ_16000)
+ printf("16kHz ");
+ if (freq & AAC_SAMPLING_FREQ_22050)
+ printf("22.05kHz ");
+ if (freq & AAC_SAMPLING_FREQ_24000)
+ printf("24kHz ");
+ if (freq & AAC_SAMPLING_FREQ_32000)
+ printf("32kHz ");
+ if (freq & AAC_SAMPLING_FREQ_44100)
+ printf("44.1kHz ");
+ if (freq & AAC_SAMPLING_FREQ_48000)
+ printf("48kHz ");
+ if (freq & AAC_SAMPLING_FREQ_64000)
+ printf("64kHz ");
+ if (freq & AAC_SAMPLING_FREQ_88200)
+ printf("88.2kHz ");
+ if (freq & AAC_SAMPLING_FREQ_96000)
+ printf("96kHz ");
+
+ printf("\n\t\tChannels: ");
+ if (aac->channels & AAC_CHANNELS_1)
+ printf("1 ");
+ if (aac->channels & AAC_CHANNELS_2)
+ printf("2 ");
+
+ printf("\n\t\tBitrate: %u", bitrate);
+
+ printf("\n\t\tVBR: %s", aac->vbr ? "Yes\n" : "No\n");
}

static void print_mpeg12(a2dp_mpeg_t *mpeg)
--
1.9.3


2014-05-26 13:16:50

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 24/26] android/hal-audio-aptx: Add initial support for aptX codec

This patch adds support for aptX codec. Since this is proprietary codec
it requires to obtain license form vendor (CSR) in order to use it.
Also shared library which provices encoder implementation is required
since this implementation only wraps it into audio HAL.
---
android/Android.mk | 2 +
android/Makefile.am | 1 +
android/hal-audio-aptx.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++
android/hal-audio.c | 1 +
android/hal-audio.h | 1 +
5 files changed, 201 insertions(+)
create mode 100644 android/hal-audio-aptx.c

diff --git a/android/Android.mk b/android/Android.mk
index afd6e9c..e9a6c92 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -256,6 +256,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bluez/android/hal-audio.c \
bluez/android/hal-audio-sbc.c \
+ bluez/android/hal-audio-aptx.c \

LOCAL_C_INCLUDES = \
$(call include-path-for, system-core) \
@@ -267,6 +268,7 @@ LOCAL_SHARED_LIBRARIES := \
libsbc \

LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+LOCAL_LDFLAGS := -ldl

LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_MODULE_TAGS := optional
diff --git a/android/Makefile.am b/android/Makefile.am
index 6891cbc..c26680f 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -169,6 +169,7 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
android/hal-audio.h \
android/hal-audio.c \
android/hal-audio-sbc.c \
+ android/hal-audio-aptx.c \
android/cutils/properties.h \
android/hardware/audio.h \
android/hardware/audio_effect.h \
diff --git a/android/hal-audio-aptx.c b/android/hal-audio-aptx.c
new file mode 100644
index 0000000..1cf8afc
--- /dev/null
+++ b/android/hal-audio-aptx.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2014 Tieto Poland
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <malloc.h>
+#include <dlfcn.h>
+
+#include <cutils/properties.h>
+
+#include "audio-msg.h"
+#include "hal-audio.h"
+#include "hal-log.h"
+#include "../src/shared/util.h"
+#include "../profiles/audio/a2dp-codecs.h"
+
+struct aptx_data {
+ a2dp_aptx_t aptx;
+
+ void *enc;
+};
+
+static const a2dp_aptx_t aptx_presets[] = {
+ {
+ .info = {
+ .vendor_id = APTX_VENDOR_ID,
+ .codec_id = APTX_CODEC_ID,
+ },
+ .frequency = APTX_SAMPLING_FREQ_44100 |
+ APTX_SAMPLING_FREQ_48000,
+ .channel_mode = APTX_CHANNEL_MODE_STEREO,
+ },
+ {
+ .info = {
+ .vendor_id = APTX_VENDOR_ID,
+ .codec_id = APTX_CODEC_ID,
+ },
+ .frequency = APTX_SAMPLING_FREQ_48000,
+ .channel_mode = APTX_CHANNEL_MODE_STEREO,
+ },
+ {
+ .info = {
+ .vendor_id = APTX_VENDOR_ID,
+ .codec_id = APTX_CODEC_ID,
+ },
+ .frequency = APTX_SAMPLING_FREQ_44100,
+ .channel_mode = APTX_CHANNEL_MODE_STEREO,
+ },
+};
+
+static bool aptx_load(void)
+{
+ /* TODO: load aptX codec library */
+ return false;
+}
+
+static void aptx_unload(void)
+{
+ /* TODO: unload aptX codec library */
+}
+
+static int aptx_get_presets(struct audio_preset *preset, size_t *len)
+{
+ int i;
+ int count;
+ size_t new_len = 0;
+ uint8_t *ptr = (uint8_t *) preset;
+ size_t preset_size = sizeof(*preset) + sizeof(a2dp_aptx_t);
+
+ DBG("");
+
+ count = sizeof(aptx_presets) / sizeof(aptx_presets[0]);
+
+ for (i = 0; i < count; i++) {
+ preset = (struct audio_preset *) ptr;
+
+ if (new_len + preset_size > *len)
+ break;
+
+ preset->len = sizeof(a2dp_aptx_t);
+ memcpy(preset->data, &aptx_presets[i], preset->len);
+
+ new_len += preset_size;
+ ptr += preset_size;
+ }
+
+ *len = new_len;
+
+ return i;
+}
+
+static bool aptx_codec_init(struct audio_preset *preset, uint16_t payload_len,
+ void **codec_data)
+{
+ struct aptx_data *aptx_data;
+
+ DBG("");
+
+ if (preset->len != sizeof(a2dp_aptx_t)) {
+ error("APTX: preset size mismatch");
+ return false;
+ }
+
+ aptx_data = new0(struct aptx_data, 1);
+ if (!aptx_data)
+ return false;
+
+ memcpy(&aptx_data->aptx, preset->data, preset->len);
+
+ /* TODO: initialize encoder */
+
+ *codec_data = aptx_data;
+
+ return true;
+}
+
+static bool aptx_cleanup(void *codec_data)
+{
+ struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
+
+ free(aptx_data->enc);
+ free(codec_data);
+
+ return true;
+}
+
+static bool aptx_get_config(void *codec_data, struct audio_input_config *config)
+{
+ struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
+
+ config->rate = aptx_data->aptx.frequency & APTX_SAMPLING_FREQ_48000 ?
+ 48000 : 44100;
+ config->channels = AUDIO_CHANNEL_OUT_STEREO;
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+
+ return true;
+}
+
+static size_t aptx_get_buffer_size(void *codec_data)
+{
+ /* TODO: return actual value */
+ return 0;
+}
+
+static size_t aptx_get_mediapacket_duration(void *codec_data)
+{
+ /* TODO: return actual value */
+ return 0;
+}
+
+static ssize_t aptx_encode_mediapacket(void *codec_data, const uint8_t *buffer,
+ size_t len, struct media_packet *mp,
+ size_t mp_data_len, size_t *written)
+{
+ /* TODO: add encoding */
+
+ return len;
+}
+
+static const struct audio_codec codec = {
+ .type = A2DP_CODEC_VENDOR,
+ .use_rtp = false,
+
+ .load = aptx_load,
+ .unload = aptx_unload,
+
+ .get_presets = aptx_get_presets,
+
+ .init = aptx_codec_init,
+ .cleanup = aptx_cleanup,
+ .get_config = aptx_get_config,
+ .get_buffer_size = aptx_get_buffer_size,
+ .get_mediapacket_duration = aptx_get_mediapacket_duration,
+ .encode_mediapacket = aptx_encode_mediapacket,
+ .update_qos = NULL,
+};
+
+const struct audio_codec *codec_aptx(void)
+{
+ return &codec;
+}
diff --git a/android/hal-audio.c b/android/hal-audio.c
index 1ab4b01..9f73ce4 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -102,6 +102,7 @@ static const struct audio_codec_info {
const struct audio_codec * (*get) (void);
} audio_codecs[] = {
{ "sbc", codec_sbc },
+ { "aptx", codec_aptx },
};

#define NUM_CODECS (sizeof(audio_codecs) / sizeof(audio_codecs[0]))
diff --git a/android/hal-audio.h b/android/hal-audio.h
index decbdd8..2b47412 100644
--- a/android/hal-audio.h
+++ b/android/hal-audio.h
@@ -99,3 +99,4 @@ struct audio_codec {
typedef const struct audio_codec * (*audio_codec_get_t) (void);

const struct audio_codec *codec_sbc(void);
+const struct audio_codec *codec_aptx(void);
--
1.9.3


2014-05-26 13:16:52

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 26/26] android/hal-audio-aptx: Add encoding

---
android/hal-audio-aptx.c | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/android/hal-audio-aptx.c b/android/hal-audio-aptx.c
index 4099c07..6954c91 100644
--- a/android/hal-audio-aptx.c
+++ b/android/hal-audio-aptx.c
@@ -170,7 +170,15 @@ static bool aptx_codec_init(struct audio_preset *preset, uint16_t payload_len,

memcpy(&aptx_data->aptx, preset->data, preset->len);

- /* TODO: initialize encoder */
+ aptx_data->enc = calloc(1, aptx_sizeof);
+ if (!aptx_data->enc) {
+ error("APTX: failed to create encoder");
+ free(aptx_data);
+ return false;
+ }
+
+ /* 1 = big-endian, this is what devices are using */
+ aptx_init(aptx_data->enc, 1);

*codec_data = aptx_data;

@@ -215,9 +223,30 @@ static ssize_t aptx_encode_mediapacket(void *codec_data, const uint8_t *buffer,
size_t len, struct media_packet *mp,
size_t mp_data_len, size_t *written)
{
- /* TODO: add encoding */
+ struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
+ const int16_t *ptr = (const void *) buffer;
+ size_t bytes_in = 0;
+ size_t bytes_out = 0;
+
+ while ((len - bytes_in) >= 16 && (mp_data_len - bytes_out) >= 4) {
+ int pcm_l[4], pcm_r[4];
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ pcm_l[i] = ptr[0];
+ pcm_r[i] = ptr[1];
+ ptr += 2;
+ }
+
+ aptx_encode(aptx_data->enc, pcm_l, pcm_r, &mp->data[bytes_out]);
+
+ bytes_in += 16;
+ bytes_out += 4;
+ }
+
+ *written = bytes_out;

- return len;
+ return bytes_in;
}

static const struct audio_codec codec = {
--
1.9.3


2014-05-26 13:16:48

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 22/26] android/a2dp: Add support to check MPEG-2,4 AAC caps

---
android/a2dp.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)

diff --git a/android/a2dp.c b/android/a2dp.c
index 0b586a8..a65c94d 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -327,6 +327,52 @@ static int sbc_check_config(void *caps, uint8_t caps_len, void *conf,
return 0;
}

+static int mpeg24_check_config(void *caps, uint8_t caps_len, void *conf,
+ uint8_t conf_len)
+{
+ a2dp_aac_t *cap, *config;
+
+ if (conf_len != caps_len || conf_len != sizeof(a2dp_aac_t)) {
+ error("AAC: Invalid configuration size (%u)", conf_len);
+ return -EINVAL;
+ }
+
+ cap = caps;
+ config = conf;
+
+ if (!(cap->object_type & config->object_type)) {
+ error("AAC: Unsupported object type (%u) by endpoint",
+ config->object_type);
+ return -EINVAL;
+ }
+
+ if (!(AAC_GET_FREQUENCY(*cap) & AAC_GET_FREQUENCY(*config))) {
+ error("AAC: Unsupported frequency (%u) by endpoint",
+ AAC_GET_FREQUENCY(*config));
+ return -EINVAL;
+ }
+
+ if (!(cap->channels & config->channels)) {
+ error("AAC: Unsupported channels (%u) by endpoint",
+ config->channels);
+ return -EINVAL;
+ }
+
+ /* VBR support in SNK is mandatory but let's make sure we don't try to
+ * have VBR on remote which for some reason does not support it
+ */
+ if (!cap->vbr && config->vbr) {
+ error("AAC: Unsupported VBR (%u) by endpoint",
+ config->vbr);
+ return -EINVAL;
+ }
+
+ if (AAC_GET_BITRATE(*cap) < AAC_GET_BITRATE(*config))
+ return -ERANGE;
+
+ return 0;
+}
+
static int check_capabilities(struct a2dp_preset *preset,
struct avdtp_media_codec_capability *codec,
uint8_t codec_len)
@@ -336,6 +382,9 @@ static int check_capabilities(struct a2dp_preset *preset,
case A2DP_CODEC_SBC:
return sbc_check_config(codec->data, codec_len, preset->data,
preset->len);
+ case A2DP_CODEC_MPEG24:
+ return mpeg24_check_config(codec->data, codec_len, preset->data,
+ preset->len);
default:
return -EINVAL;
}
@@ -360,6 +409,26 @@ static struct a2dp_preset *sbc_select_range(void *caps, uint8_t caps_len,
return p;
}

+static struct a2dp_preset *mpeg24_select_range(void *caps, uint8_t caps_len,
+ void *conf, uint8_t conf_len)
+{
+ struct a2dp_preset *p;
+ a2dp_aac_t *cap, *config;
+ uint32_t bitrate;
+
+ cap = caps;
+ config = conf;
+
+ bitrate = MIN(AAC_GET_BITRATE(*cap), AAC_GET_BITRATE(*config));
+ AAC_SET_BITRATE(*config, bitrate);
+
+ p = g_new0(struct a2dp_preset, 1);
+ p->len = conf_len;
+ p->data = g_memdup(conf, p->len);
+
+ return p;
+}
+
static struct a2dp_preset *select_preset_range(struct a2dp_preset *preset,
struct avdtp_media_codec_capability *codec,
uint8_t codec_len)
@@ -369,6 +438,9 @@ static struct a2dp_preset *select_preset_range(struct a2dp_preset *preset,
case A2DP_CODEC_SBC:
return sbc_select_range(codec->data, codec_len, preset->data,
preset->len);
+ case A2DP_CODEC_MPEG24:
+ return mpeg24_select_range(codec->data, codec_len, preset->data,
+ preset->len);
default:
return NULL;
}
--
1.9.3


2014-05-26 13:16:47

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 21/26] android: Add avinfo to makefile

---
android/Android.mk | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)

diff --git a/android/Android.mk b/android/Android.mk
index f91c581..afd6e9c 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -584,3 +584,30 @@ $(foreach file,$(include_files),$(shell cp -u $(file) $(include_path)/bluetooth)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(include_path)

include $(BUILD_STATIC_LIBRARY)
+
+#
+# avtest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/avinfo.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := avinfo
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
--
1.9.3


2014-05-26 13:16:42

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 16/26] android/a2dp: Fix SEP selection

When matching remote SEP to local SEP we do not match vendor codecs
properly, i.e. neither vendor ID not codec ID are checked, which may
cause wrong endpoint to be selected in case there are more that one
endpoints using vendor codec on remote.

This patch fixes this by assinging vendor codec indentification to
local SEP after it's registered and uses this information when matching
SEPs.
---
android/a2dp.c | 8 ++++++++
android/avdtp.c | 23 +++++++++++++++++++++++
android/avdtp.h | 2 ++
3 files changed, 33 insertions(+)

diff --git a/android/a2dp.c b/android/a2dp.c
index c8119da..0b586a8 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1230,6 +1230,14 @@ static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
endpoint->caps = presets->data;
endpoint->presets = g_slist_copy(g_slist_nth(presets, 1));

+ if (endpoint->codec == A2DP_CODEC_VENDOR) {
+ a2dp_vendor_codec_t *vndcodec = (void *) endpoint->caps->data;
+
+ avdtp_sep_set_vendor_codec(endpoint->sep,
+ btohl(vndcodec->vendor_id),
+ btohs(vndcodec->codec_id));
+ }
+
endpoints = g_slist_append(endpoints, endpoint);

return endpoint->id;
diff --git a/android/avdtp.c b/android/avdtp.c
index 3d309b9..d6684bb 100644
--- a/android/avdtp.c
+++ b/android/avdtp.c
@@ -39,8 +39,10 @@

#include <glib.h>

+#include "lib/bluetooth.h"
#include "src/log.h"
#include "avdtp.h"
+#include "../profiles/audio/a2dp-codecs.h"

#define AVDTP_PSM 25

@@ -317,6 +319,8 @@ struct avdtp_local_sep {
struct avdtp_stream *stream;
struct seid_info info;
uint8_t codec;
+ uint32_t vndcodec_vendor;
+ uint16_t vndcodec_codec;
gboolean delay_reporting;
GSList *caps;
struct avdtp_sep_ind *ind;
@@ -1089,6 +1093,18 @@ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
if (codec_data->media_codec_type != lsep->codec)
continue;

+ /* Need also check for Vendor Specific Codec */
+ if (lsep->codec == A2DP_CODEC_VENDOR) {
+ a2dp_vendor_codec_t *vndcodec =
+ (void *) codec_data->data;
+
+ if (btohl(vndcodec->vendor_id) != lsep->vndcodec_vendor)
+ continue;
+
+ if (btohs(vndcodec->codec_id) != lsep->vndcodec_codec)
+ continue;
+ }
+
if (sep->stream == NULL)
return sep;
}
@@ -3349,6 +3365,13 @@ struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
return sep;
}

+void avdtp_sep_set_vendor_codec(struct avdtp_local_sep *sep, uint32_t vendor_id,
+ uint16_t codec_id)
+{
+ sep->vndcodec_vendor = vendor_id;
+ sep->vndcodec_codec = codec_id;
+}
+
int avdtp_unregister_sep(struct avdtp_local_sep *sep)
{
if (!sep)
diff --git a/android/avdtp.h b/android/avdtp.h
index 7fdf597..9d683c4 100644
--- a/android/avdtp.h
+++ b/android/avdtp.h
@@ -268,6 +268,8 @@ struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
struct avdtp_sep_ind *ind,
struct avdtp_sep_cfm *cfm,
void *user_data);
+void avdtp_sep_set_vendor_codec(struct avdtp_local_sep *sep, uint32_t vendor_id,
+ uint16_t codec_id);

/* Find a matching pair of local and remote SEP ID's */
struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
--
1.9.3


2014-05-26 13:16:44

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 18/26] tools/hcidump: Decode aptX codec capabilities

---
tools/parser/avdtp.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 47 insertions(+), 3 deletions(-)

diff --git a/tools/parser/avdtp.c b/tools/parser/avdtp.c
index 5806c07..14dc417 100644
--- a/tools/parser/avdtp.c
+++ b/tools/parser/avdtp.c
@@ -150,6 +150,13 @@ static char *codec2str(uint8_t type, uint8_t codec)
return "Unknown";
}

+static char *vndcodec2str(uint32_t vendor, uint16_t vndcodec)
+{
+ if (vendor == 0x0000004f && vndcodec == 0x0001)
+ return "aptX";
+ return "Unknown";
+}
+
static char *cat2str(uint8_t cat)
{
switch (cat) {
@@ -213,13 +220,23 @@ static void capabilities(int level, struct frame *frm)

if (cat == 7) {
uint8_t type, codec;
- uint16_t tmp, freq;
- uint32_t bitrate;
+ uint16_t tmp, freq, vndcodec = 0;
+ uint32_t bitrate, vendor = 0;

type = get_u8(frm);
codec = get_u8(frm);

- printf("%s - %s\n", cat2str(cat), codec2str(type, codec));
+ if (codec == 255) {
+ vendor = btohl(htonl(get_u32(frm)));
+ vndcodec = btohs(htons(get_u16(frm)));
+
+ printf("%s - %s (%s)\n", cat2str(cat),
+ codec2str(type, codec),
+ vndcodec2str(vendor, vndcodec));
+ } else {
+ printf("%s - %s\n", cat2str(cat),
+ codec2str(type, codec));
+ }

switch (codec) {
case 0:
@@ -324,6 +341,33 @@ static void capabilities(int level, struct frame *frm)
printf("%ubps ", bitrate);
printf("%s\n", tmp & 0x80 ? "VBR" : "");
break;
+ case 255:
+ if (vendor == 0x0000004f &&
+ vndcodec == 0x0001) {
+ tmp = get_u8(frm);
+ p_indent(level + 1, frm);
+ if (tmp & 0x80)
+ printf("16kHz ");
+ if (tmp & 0x40)
+ printf("32kHz ");
+ if (tmp & 0x20)
+ printf("44.1kHz ");
+ if (tmp & 0x10)
+ printf("48kHz ");
+ printf("\n");
+ p_indent(level + 1, frm);
+ if (tmp & 0x02)
+ printf("Stereo ");
+ if (tmp & 0x01)
+ printf("Mono ");
+ printf("\n");
+ break;
+ } else {
+ hex_dump(level + 1, frm, len - 8);
+ frm->ptr += (len - 8);
+ frm->len -= (len - 8);
+ }
+ break;
default:
hex_dump(level + 1, frm, len - 2);
frm->ptr += (len - 2);
--
1.9.3


2014-05-26 13:16:36

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 10/26] android/hal-audio: Add load/unload methods for codec

This patch adds optional load/unload methods for codec which can be
used to initialize some static data for codec, e.g. load shared library
which provides encoder. Unlike init/cleanup which are called on stream
open/close these methods are called when audio device is opened/closed
thus most likely only once.
---
android/hal-audio.c | 16 ++++++++++++++++
android/hal-audio.h | 3 +++
2 files changed, 19 insertions(+)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index e6015f2..416a3ad 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -1334,11 +1334,19 @@ static int audio_dump(const audio_hw_device_t *device, int fd)
static int audio_close(hw_device_t *device)
{
struct a2dp_audio_dev *a2dp_dev = (struct a2dp_audio_dev *)device;
+ size_t i;

DBG("");

unregister_endpoints();

+ for (i = 0; i < NUM_CODECS; i++) {
+ const struct audio_codec *codec = audio_codecs[i].get();
+
+ if (codec->unload)
+ codec->unload();
+ }
+
shutdown(listen_sk, SHUT_RDWR);
shutdown(audio_sk, SHUT_RDWR);

@@ -1478,6 +1486,7 @@ static int audio_open(const hw_module_t *module, const char *name,
hw_device_t **device)
{
struct a2dp_audio_dev *a2dp_dev;
+ size_t i;
int err;

DBG("");
@@ -1516,6 +1525,13 @@ static int audio_open(const hw_module_t *module, const char *name,
a2dp_dev->dev.close_input_stream = audio_close_input_stream;
a2dp_dev->dev.dump = audio_dump;

+ for (i = 0; i < NUM_CODECS; i++) {
+ const struct audio_codec *codec = audio_codecs[i].get();
+
+ if (codec->load)
+ codec->load();
+ }
+
/*
* Note that &a2dp_dev->dev.common is the same pointer as a2dp_dev.
* This results from the structure of following structs:a2dp_audio_dev,
diff --git a/android/hal-audio.h b/android/hal-audio.h
index be71473..decbdd8 100644
--- a/android/hal-audio.h
+++ b/android/hal-audio.h
@@ -75,6 +75,9 @@ struct audio_codec {
uint8_t type;
bool use_rtp;

+ bool (*load) (void);
+ void (*unload) (void);
+
int (*get_presets) (struct audio_preset *preset, size_t *len);

bool (*init) (struct audio_preset *preset, uint16_t mtu,
--
1.9.3


2014-05-26 13:16:41

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 15/26] audio: Add definitions for aptX

---
profiles/audio/a2dp-codecs.h | 33 ++++++++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h
index 1106bd2..4d2584d 100644
--- a/profiles/audio/a2dp-codecs.h
+++ b/profiles/audio/a2dp-codecs.h
@@ -130,6 +130,22 @@
.frequency1 = (f >> 4) & 0xff, \
.frequency2 = f & 0x0f,

+#define APTX_VENDOR_ID 0x0000004f
+#define APTX_CODEC_ID 0x0001
+
+#define APTX_CHANNEL_MODE_MONO 0x01
+#define APTX_CHANNEL_MODE_STEREO 0x02
+
+#define APTX_SAMPLING_FREQ_16000 0x08
+#define APTX_SAMPLING_FREQ_32000 0x04
+#define APTX_SAMPLING_FREQ_44100 0x02
+#define APTX_SAMPLING_FREQ_48000 0x01
+
+typedef struct {
+ uint32_t vendor_id;
+ uint16_t codec_id;
+} __attribute__ ((packed)) a2dp_vendor_codec_t;
+
#if __BYTE_ORDER == __LITTLE_ENDIAN

typedef struct {
@@ -164,6 +180,12 @@ typedef struct {
uint8_t bitrate3;
} __attribute__ ((packed)) a2dp_aac_t;

+typedef struct {
+ a2dp_vendor_codec_t info;
+ uint8_t channel_mode:4;
+ uint8_t frequency:4;
+} __attribute__ ((packed)) a2dp_aptx_t;
+
#elif __BYTE_ORDER == __BIG_ENDIAN

typedef struct {
@@ -198,11 +220,12 @@ typedef struct {
uint8_t bitrate3;
} __attribute__ ((packed)) a2dp_aac_t;

+typedef struct {
+ a2dp_vendor_codec_t info;
+ uint8_t frequency:4;
+ uint8_t channel_mode:4;
+} __attribute__ ((packed)) a2dp_aptx_t;
+
#else
#error "Unknown byte order"
#endif
-
-typedef struct {
- uint32_t vendor_id;
- uint16_t codec_id;
-} __attribute__ ((packed)) a2dp_vendor_codec_t;
--
1.9.3


2014-05-26 13:16:33

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 07/26] android/hal-audio: Send packets only when data were encoded

Codec may not return encoded packet on every encode_mediapacket call,
i.e. in case there's not enough data it may buffer data and encode on
subsequent calls when enough data were provided. We need to make sure
media packet is written only in case somethind was encoded so we don't
send empty packets.
---
android/hal-audio.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 534620a..9807a5d 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -691,8 +691,12 @@ static bool write_data(struct a2dp_stream_out *out, const void *buffer,
}
}

- /* in resync mode we'll just drop mediapackets */
- if (!ep->resync) {
+ /* we send data only in case codec encoded some data, i.e. some
+ * codecs do internal buffering and output data only if full
+ * frame can be encoded
+ * in resync mode we'll just drop mediapackets
+ */
+ if (written > 0 && !ep->resync) {
/* wait some time for socket to be ready for write,
* but we'll just skip writing data if timeout occurs
*/
--
1.9.3


2014-05-26 13:16:27

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 01/26] android/a2dp: Fix removing device on incoming connection

Connection state is not changed for incoming connection, i.e. during
discovery device is still in disconnected state and in case connection
fails for some reason, device won't be removed due to triggered state
change disconnected->disconnected which is silently ignored.

This patch fixes this problem by changing device state to connecting
immediately after signalling channel is connected. This allows device
to be removed properly in case something fails and is also consistent
with behaviour of Bluedroid.

In addition there's new flag added to device which stores information
whether we're initiator of connection. This is required because before
fix this property was decided based on HAL state which we can't now
use since it will be always connecting for both incoming and outgoing
connections.
---
android/a2dp.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 452fdab..10141d1 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -81,6 +81,7 @@ struct a2dp_endpoint {

struct a2dp_device {
bdaddr_t dst;
+ bool is_int;
uint8_t state;
GIOChannel *io;
struct avdtp *session;
@@ -183,13 +184,14 @@ static void a2dp_device_remove(struct a2dp_device *dev)
a2dp_device_free(dev);
}

-static struct a2dp_device *a2dp_device_new(const bdaddr_t *dst)
+static struct a2dp_device *a2dp_device_new(const bdaddr_t *dst, bool is_int)
{
struct a2dp_device *dev;

dev = g_new0(struct a2dp_device, 1);
bacpy(&dev->dst, dst);
devices = g_slist_prepend(devices, dev);
+ dev->is_int = is_int;

return dev;
}
@@ -547,7 +549,7 @@ static void signaling_connect_cb(GIOChannel *chan, GError *err,
}

/* Proceed to stream setup if initiator */
- if (dev->state == HAL_A2DP_STATE_CONNECTING) {
+ if (dev->is_int) {
int perr;

perr = avdtp_discover(dev->session, discover_cb, dev);
@@ -585,7 +587,7 @@ static void bt_a2dp_connect(const void *buf, uint16_t len)
goto failed;
}

- dev = a2dp_device_new(&dst);
+ dev = a2dp_device_new(&dst, true);
if (!a2dp_device_connect(dev, signaling_connect_cb)) {
a2dp_device_remove(dev);
status = HAL_STATUS_FAILED;
@@ -738,7 +740,8 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
return;
}

- dev = a2dp_device_new(&dst);
+ dev = a2dp_device_new(&dst, true);
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTING);
signaling_connect_cb(chan, err, dev);
}

--
1.9.3


2014-05-26 13:16:28

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 02/26] android: Fix missing include

It's needed for getenv().
---
android/cutils/properties.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/android/cutils/properties.h b/android/cutils/properties.h
index 8096b19..ef40f01 100644
--- a/android/cutils/properties.h
+++ b/android/cutils/properties.h
@@ -22,6 +22,7 @@
*/

#include <unistd.h>
+#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
--
1.9.3


2014-05-26 13:16:30

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 04/26] android/hal-audio: Fix media_packet definition

rtp_payload field in media_packet is specific for SBC codec thus it
should be moved to SBC codec implementation and removed from generic
structs.
---
android/hal-audio-sbc.c | 40 +++++++++++++++++++++++++++++++++++++---
android/hal-audio.h | 17 -----------------
2 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/android/hal-audio-sbc.c b/android/hal-audio-sbc.c
index a16cf73..8366978 100644
--- a/android/hal-audio-sbc.c
+++ b/android/hal-audio-sbc.c
@@ -30,6 +30,37 @@
#define SBC_QUALITY_MIN_BITPOOL 33
#define SBC_QUALITY_STEP 5

+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct rtp_payload {
+ unsigned frame_count:4;
+ unsigned rfa0:1;
+ unsigned is_last_fragment:1;
+ unsigned is_first_fragment:1;
+ unsigned is_fragmented:1;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct rtp_payload {
+ unsigned is_fragmented:1;
+ unsigned is_first_fragment:1;
+ unsigned is_last_fragment:1;
+ unsigned rfa0:1;
+ unsigned frame_count:4;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct media_packet_sbc {
+ struct media_packet hdr;
+ struct rtp_payload payload;
+ uint8_t data[0];
+};
+
struct sbc_data {
a2dp_sbc_t sbc;

@@ -306,10 +337,13 @@ static ssize_t sbc_encode_mediapacket(void *codec_data, const uint8_t *buffer,
size_t mp_data_len, size_t *written)
{
struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
+ struct media_packet_sbc *mp_sbc = (struct media_packet_sbc *) mp;
size_t consumed = 0;
size_t encoded = 0;
uint8_t frame_count = 0;

+ mp_data_len -= sizeof(mp_sbc->payload);
+
while (len - consumed >= sbc_data->in_frame_len &&
mp_data_len - encoded >= sbc_data->out_frame_len &&
frame_count < MAX_FRAMES_IN_PAYLOAD) {
@@ -317,7 +351,7 @@ static ssize_t sbc_encode_mediapacket(void *codec_data, const uint8_t *buffer,
ssize_t written = 0;

read = sbc_encode(&sbc_data->enc, buffer + consumed,
- sbc_data->in_frame_len, mp->data + encoded,
+ sbc_data->in_frame_len, mp_sbc->data + encoded,
mp_data_len - encoded, &written);

if (read < 0) {
@@ -331,8 +365,8 @@ static ssize_t sbc_encode_mediapacket(void *codec_data, const uint8_t *buffer,
encoded += written;
}

- *written = encoded;
- mp->payload.frame_count = frame_count;
+ *written = encoded + sizeof(mp_sbc->payload);
+ mp_sbc->payload.frame_count = frame_count;

return consumed;
}
diff --git a/android/hal-audio.h b/android/hal-audio.h
index cc1a81c..dc1a812 100644
--- a/android/hal-audio.h
+++ b/android/hal-audio.h
@@ -35,14 +35,6 @@ struct rtp_header {
uint32_t csrc[0];
} __attribute__ ((packed));

-struct rtp_payload {
- unsigned frame_count:4;
- unsigned rfa0:1;
- unsigned is_last_fragment:1;
- unsigned is_first_fragment:1;
- unsigned is_fragmented:1;
-} __attribute__ ((packed));
-
#elif __BYTE_ORDER == __BIG_ENDIAN

struct rtp_header {
@@ -60,21 +52,12 @@ struct rtp_header {
uint32_t csrc[0];
} __attribute__ ((packed));

-struct rtp_payload {
- unsigned is_fragmented:1;
- unsigned is_first_fragment:1;
- unsigned is_last_fragment:1;
- unsigned rfa0:1;
- unsigned frame_count:4;
-} __attribute__ ((packed));
-
#else
#error "Unknown byte order"
#endif

struct media_packet {
struct rtp_header hdr;
- struct rtp_payload payload;
uint8_t data[0];
};

--
1.9.3


2014-06-01 09:14:23

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 09/26] android/hal-audio: Make codecs configurable

Hi Andrzej,

On Mon, May 26, 2014 at 4:16 PM, Andrzej Kaczmarek
<[email protected]> wrote:
> When supporting more codecs we need way to easily configure which ones
> should be registered as endpoints. This patch adds support to specify
> list of codecs to be loaded in "persist.sys.bluetooth.codecs" property
> which is comma-separated case-insensitive list.
>
> Codecs shall be listed in order of preference, i.e. 1st one is most
> preferred. SBC codec is always loaded and there's no need to specify
> it.
> ---
> android/Makefile.am | 1 +
> android/hal-audio.c | 85 ++++++++++++++++++++++++++++++++++++++++++++---------
> 2 files changed, 72 insertions(+), 14 deletions(-)
>
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 2d74505..6891cbc 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -169,6 +169,7 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
> android/hal-audio.h \
> android/hal-audio.c \
> android/hal-audio-sbc.c \
> + android/cutils/properties.h \
> android/hardware/audio.h \
> android/hardware/audio_effect.h \
> android/hardware/hardware.h \
> diff --git a/android/hal-audio.c b/android/hal-audio.c
> index 8b82498..e6015f2 100644
> --- a/android/hal-audio.c
> +++ b/android/hal-audio.c
> @@ -27,6 +27,7 @@
> #include <arpa/inet.h>
> #include <fcntl.h>
>
> +#include <cutils/properties.h>
> #include <hardware/audio.h>
> #include <hardware/hardware.h>
>
> @@ -96,8 +97,11 @@ extern int clock_nanosleep(clockid_t clock_id, int flags,
> struct timespec *remain);
> #endif
>
> -static const audio_codec_get_t audio_codecs[] = {
> - codec_sbc,
> +static const struct audio_codec_info {
> + const char *name;
> + const struct audio_codec * (*get) (void);
> +} audio_codecs[] = {
> + { "sbc", codec_sbc },
> };
>
> #define NUM_CODECS (sizeof(audio_codecs) / sizeof(audio_codecs[0]))
> @@ -415,27 +419,80 @@ static int ipc_suspend_stream_cmd(uint8_t endpoint_id)
> return result;
> }
>
> -static int register_endpoints(void)
> +static void register_endpoint(const char *codec_name)
> {
> - struct audio_endpoint *ep = &audio_endpoints[0];
> + const struct audio_codec *codec = NULL;
> + struct audio_endpoint *ep;
> size_t i;
>
> - for (i = 0; i < NUM_CODECS; i++, ep++) {
> - const struct audio_codec *codec = audio_codecs[i]();
> + for (i = 0; i < NUM_CODECS; i++)
> + if (!strcasecmp(audio_codecs[i].name, codec_name)) {
> + codec = audio_codecs[i].get();
> + break;
> + }
>
> - if (!codec)
> - return AUDIO_STATUS_FAILED;
> + if (!codec) {
> + error("Failed to register endpoint for %s", codec_name);
> + return;
> + }
>
> - ep->id = ipc_open_cmd(codec);
> + for (i = 0; i < MAX_AUDIO_ENDPOINTS; i++) {
> + /* Do not register the same codec twice */
> + if (audio_endpoints[i].codec == codec)
> + return;
>
> - if (!ep->id)
> - return AUDIO_STATUS_FAILED;
> + if (!audio_endpoints[i].id)
> + break;
> + }
>
> - ep->codec = codec;
> - ep->codec_data = NULL;
> - ep->fd = -1;
> + /* We have the same number of endpoints and codecs so we'll always find
> + * free endpoint - no need to check this here.
> + */
> +
> + ep = &audio_endpoints[i];
> +
> + ep->id = ipc_open_cmd(codec);
> +
> + if (!ep->id) {
> + error("Failed to open endpoint for %s", codec_name);
> + return;
> }
>
> + ep->codec = codec;
> + ep->codec_data = NULL;
> + ep->fd = -1;
> +
> + info("Opened endpoint for %s", codec_name);
> +}
> +
> +static int register_endpoints(void)
> +{
> + char value[PROPERTY_VALUE_MAX];
> + char *name, *p;
> +
> + if (property_get("persist.sys.bluetooth.codecs", value, "") < 0)
> + return AUDIO_STATUS_FAILED;
> +
> + p = value;
> +
> + do {
> + name = p;
> + p = strchr(name, ',');
> + if (p) {
> + *p = '\0';
> + p++;
> + }
> + if (!strlen(name))
> + continue;
> +
> + register_endpoint(name);
> + } while (p);
> +
> + /* SBC is mandatory and should always be registered, even if it's not
> + * specified in prop
> + */
> + register_endpoint("sbc");
> +
> return AUDIO_STATUS_SUCCESS;
> }
>
> --
> 1.9.3

Ive stopped pushing here, I believe this makes it a little too
complicated and for now I would prefer we just hardcode the codecs we
support in the order we prefer, this is actually not that simple if we
were to mix with pass-through codecs. Furthermore I believe it is
better to load from a common location so we can just try to load
directly on codec_aptx and if that fails we proceed to the next.


--
Luiz Augusto von Dentz