Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH 4/9] android/hal-audio: Initialize SBC encoder
From: Marcel Holtmann @ 2014-01-17 19:28 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <CAF3PWx3PZuAaJWacG77GSD7PRAaFuXi_o6LMe1zTWMrW1qYKaA@mail.gmail.com>

Hi Andrezj,

>>> ---
>>> android/hal-audio.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 72 insertions(+)
>>> 
>>> diff --git a/android/hal-audio.c b/android/hal-audio.c
>>> index f53dba0..e5c646c 100644
>>> --- a/android/hal-audio.c
>>> +++ b/android/hal-audio.c
>>> @@ -32,6 +32,7 @@
>>> #include "hal-log.h"
>>> #include "hal-msg.h"
>>> #include "../profiles/audio/a2dp-codecs.h"
>>> +#include <sbc/sbc.h>
>>> 
>>> static const uint8_t a2dp_src_uuid[] = {
>>>              0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x10, 0x00,
>>> @@ -53,6 +54,8 @@ struct audio_input_config {
>>> 
>>> struct sbc_data {
>>>      a2dp_sbc_t sbc;
>>> +
>>> +     sbc_t enc;
>>> };
>>> 
>>> static int sbc_get_presets(struct audio_preset *preset, size_t *len);
>>> @@ -184,6 +187,70 @@ static int sbc_get_presets(struct audio_preset *preset, size_t *len)
>>>      return i;
>>> }
>>> 
>>> +static void sbc_init_encoder(struct sbc_data *sbc_data)
>>> +{
>>> +     a2dp_sbc_t *in = &sbc_data->sbc;
>>> +     sbc_t *out = &sbc_data->enc;
>>> +
>>> +     DBG("");
>>> +
>>> +     sbc_init(out, 0L);
>>> +
>>> +     switch (in->frequency) {
>>> +     case SBC_SAMPLING_FREQ_16000:
>>> +             out->frequency = SBC_FREQ_16000;
>>> +             break;
>>> +     case SBC_SAMPLING_FREQ_32000:
>>> +             out->frequency = SBC_FREQ_32000;
>>> +             break;
>>> +     case SBC_SAMPLING_FREQ_44100:
>>> +             out->frequency = SBC_FREQ_44100;
>>> +             break;
>>> +     case SBC_SAMPLING_FREQ_48000:
>>> +             out->frequency = SBC_FREQ_48000;
>>> +             break;
>>> +     }
>>> +
>>> +     out->subbands = in->subbands == SBC_SUBBANDS_4 ? SBC_SB_4 : SBC_SB_8;
>>> +
>>> +     switch (in->channel_mode) {
>>> +     case SBC_CHANNEL_MODE_MONO:
>>> +             out->mode = SBC_MODE_MONO;
>>> +             break;
>>> +     case SBC_CHANNEL_MODE_DUAL_CHANNEL:
>>> +             out->mode = SBC_MODE_DUAL_CHANNEL;
>>> +             break;
>>> +     case SBC_CHANNEL_MODE_JOINT_STEREO:
>>> +             out->mode = SBC_MODE_JOINT_STEREO;
>>> +             break;
>>> +     case SBC_CHANNEL_MODE_STEREO:
>>> +             out->mode = SBC_MODE_STEREO;
>>> +             break;
>>> +     }
>>> +
>>> +     out->endian = SBC_LE;
>>> +
>>> +     out->bitpool = in->max_bitpool;
>>> +
>>> +     out->allocation = in->allocation_method == SBC_ALLOCATION_SNR ?
>>> +                             SBC_AM_SNR : SBC_AM_LOUDNESS;
>>> +
>>> +     switch (in->block_length) {
>>> +     case SBC_BLOCK_LENGTH_4:
>>> +             out->blocks = SBC_BLK_4;
>>> +             break;
>>> +     case SBC_BLOCK_LENGTH_8:
>>> +             out->blocks = SBC_BLK_8;
>>> +             break;
>>> +     case SBC_BLOCK_LENGTH_12:
>>> +             out->blocks = SBC_BLK_12;
>>> +             break;
>>> +     case SBC_BLOCK_LENGTH_16:
>>> +             out->blocks = SBC_BLK_16;
>>> +             break;
>>> +     }
>> 
>> aren’t the values all the same? This looks pretty complicated for something that should be dead simple. Does Android really had to duplicate every single definition with the same prefix?
> 
> Actually symbols for 'in' come from a2dp-codecs.h and 'out' from sbc.h
> ;-) And they have different values since A2DP uses shifted-bit values
> while sbc.h are just ordinal values so cannot assign them directly.

so this a problem we created by ourselves. Yeah. Seems no cookie for me tonight ;)

We need to start fixing a2dp-codecs.h then and prefix it with A2DP. This current situation is bad. Luiz?

Regards

Marcel



^ permalink raw reply

* Re: [PATCH 4/9] android/hal-audio: Initialize SBC encoder
From: Andrzej Kaczmarek @ 2014-01-17 19:26 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <D34DEF28-690B-4697-B88F-B224F7583782@holtmann.org>

Hi Marcel,

On 17 January 2014 19:24, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Andrzej,
>
>> ---
>> android/hal-audio.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++=
++++++
>> 1 file changed, 72 insertions(+)
>>
>> diff --git a/android/hal-audio.c b/android/hal-audio.c
>> index f53dba0..e5c646c 100644
>> --- a/android/hal-audio.c
>> +++ b/android/hal-audio.c
>> @@ -32,6 +32,7 @@
>> #include "hal-log.h"
>> #include "hal-msg.h"
>> #include "../profiles/audio/a2dp-codecs.h"
>> +#include <sbc/sbc.h>
>>
>> static const uint8_t a2dp_src_uuid[] =3D {
>>               0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x10, 0x00,
>> @@ -53,6 +54,8 @@ struct audio_input_config {
>>
>> struct sbc_data {
>>       a2dp_sbc_t sbc;
>> +
>> +     sbc_t enc;
>> };
>>
>> static int sbc_get_presets(struct audio_preset *preset, size_t *len);
>> @@ -184,6 +187,70 @@ static int sbc_get_presets(struct audio_preset *pre=
set, size_t *len)
>>       return i;
>> }
>>
>> +static void sbc_init_encoder(struct sbc_data *sbc_data)
>> +{
>> +     a2dp_sbc_t *in =3D &sbc_data->sbc;
>> +     sbc_t *out =3D &sbc_data->enc;
>> +
>> +     DBG("");
>> +
>> +     sbc_init(out, 0L);
>> +
>> +     switch (in->frequency) {
>> +     case SBC_SAMPLING_FREQ_16000:
>> +             out->frequency =3D SBC_FREQ_16000;
>> +             break;
>> +     case SBC_SAMPLING_FREQ_32000:
>> +             out->frequency =3D SBC_FREQ_32000;
>> +             break;
>> +     case SBC_SAMPLING_FREQ_44100:
>> +             out->frequency =3D SBC_FREQ_44100;
>> +             break;
>> +     case SBC_SAMPLING_FREQ_48000:
>> +             out->frequency =3D SBC_FREQ_48000;
>> +             break;
>> +     }
>> +
>> +     out->subbands =3D in->subbands =3D=3D SBC_SUBBANDS_4 ? SBC_SB_4 : =
SBC_SB_8;
>> +
>> +     switch (in->channel_mode) {
>> +     case SBC_CHANNEL_MODE_MONO:
>> +             out->mode =3D SBC_MODE_MONO;
>> +             break;
>> +     case SBC_CHANNEL_MODE_DUAL_CHANNEL:
>> +             out->mode =3D SBC_MODE_DUAL_CHANNEL;
>> +             break;
>> +     case SBC_CHANNEL_MODE_JOINT_STEREO:
>> +             out->mode =3D SBC_MODE_JOINT_STEREO;
>> +             break;
>> +     case SBC_CHANNEL_MODE_STEREO:
>> +             out->mode =3D SBC_MODE_STEREO;
>> +             break;
>> +     }
>> +
>> +     out->endian =3D SBC_LE;
>> +
>> +     out->bitpool =3D in->max_bitpool;
>> +
>> +     out->allocation =3D in->allocation_method =3D=3D SBC_ALLOCATION_SN=
R ?
>> +                             SBC_AM_SNR : SBC_AM_LOUDNESS;
>> +
>> +     switch (in->block_length) {
>> +     case SBC_BLOCK_LENGTH_4:
>> +             out->blocks =3D SBC_BLK_4;
>> +             break;
>> +     case SBC_BLOCK_LENGTH_8:
>> +             out->blocks =3D SBC_BLK_8;
>> +             break;
>> +     case SBC_BLOCK_LENGTH_12:
>> +             out->blocks =3D SBC_BLK_12;
>> +             break;
>> +     case SBC_BLOCK_LENGTH_16:
>> +             out->blocks =3D SBC_BLK_16;
>> +             break;
>> +     }
>
> aren=92t the values all the same? This looks pretty complicated for somet=
hing that should be dead simple. Does Android really had to duplicate every=
 single definition with the same prefix?

Actually symbols for 'in' come from a2dp-codecs.h and 'out' from sbc.h
;-) And they have different values since A2DP uses shifted-bit values
while sbc.h are just ordinal values so cannot assign them directly.


BR,
Andrzej

^ permalink raw reply

* Re: [PATCH 2/9] android: Build Audio HAL with SBC
From: Marcel Holtmann @ 2014-01-17 19:22 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <CAF3PWx2XmgedAh3owiGN3JQzQZo8gNNRcph7kx=252Uo1yFyuw@mail.gmail.com>

Hi Andrzej,

>>> Build for Android requires libsbc sources to be available in
>>> external/bluetooth/sbc. Build for host requires libsbc package to be
>>> installed.
>>> ---
>>> android/Android.mk  | 14 +++++++++++---
>>> android/Makefile.am |  2 ++
>>> configure.ac        |  7 +++++++
>>> 3 files changed, 20 insertions(+), 3 deletions(-)
>>> 
>>> diff --git a/android/Android.mk b/android/Android.mk
>>> index 7e97ec8..63a4a24 100644
>>> --- a/android/Android.mk
>>> +++ b/android/Android.mk
>>> @@ -3,8 +3,9 @@ LOCAL_PATH := $(call my-dir)
>>> # Retrieve BlueZ version from configure.ac file
>>> BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D'AC_INIT(_,v)=v')
>>> 
>>> -# Specify pathmap for glib
>>> -pathmap_INCL += glib:external/bluetooth/glib
>>> +# Specify pathmap for glib and sbc
>>> +pathmap_INCL += glib:external/bluetooth/glib \
>>> +     sbc:external/bluetooth/sbc
>>> 
>>> # Specify common compiler flags
>>> BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
>>> @@ -220,11 +221,18 @@ include $(BUILD_EXECUTABLE)
>>> 
>>> include $(CLEAR_VARS)
>>> 
>>> -LOCAL_SRC_FILES := hal-audio.c
>>> +LOCAL_SRC_FILES := hal-audio.c \
>>> +     ../../sbc/sbc/sbc.c \
>>> +     ../../sbc/sbc/sbc_primitives.c \
>>> +     ../../sbc/sbc/sbc_primitives_armv6.c \
>>> +     ../../sbc/sbc/sbc_primitives_iwmmxt.c \
>>> +     ../../sbc/sbc/sbc_primitives_mmx.c \
>>> +     ../../sbc/sbc/sbc_primitives_neon.c \
>> 
>> why? Can we not just build libsbc for Android?
> 
> This way we can use upstream sbc git without forking it to add Android.mk.

okay. Seems fine for now to get this started, but eventually we need to sort this out.

>> I rather install an extra library and not have to make this builtin.
> 
> Sure, this can be changed. Static or dynamic library?

I would build it at least as dynamic library. Even you build that from android/Android.mk file from bluez tree. If you make it static or include it then you have to worry about LGPL obligations. They are different for a shared library compared to a static library/include.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 5/9] android/hal-audio: Calculate SBC stream parameters
From: Andrzej Kaczmarek @ 2014-01-17 19:17 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <816CDF1A-CF41-445B-9CAF-CE5A1E06C940@holtmann.org>

Hi Marcel,

On 17 January 2014 19:25, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Andrzej,
>
>> This patch adds necessary calculations for SBC stream parameters.
>>
>> Both input and output buffers are expected to have exact amount of
>> data to fill single media packet (based on transport channel MTU).
>>
>> Frame duration will be used to synchronize input and output streams.
>> ---
>> android/hal-audio.c | 50 ++++++++++++++++++++++++++++++-----
>> android/rtp.h       | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 120 insertions(+), 6 deletions(-)
>> create mode 100644 android/rtp.h
>>
>> diff --git a/android/hal-audio.c b/android/hal-audio.c
>> index e5c646c..3f53295 100644
>> --- a/android/hal-audio.c
>> +++ b/android/hal-audio.c
>> @@ -33,6 +33,7 @@
>> #include "hal-msg.h"
>> #include "../profiles/audio/a2dp-codecs.h"
>> #include <sbc/sbc.h>
>> +#include "rtp.h"
>>
>> static const uint8_t a2dp_src_uuid[] = {
>>               0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x10, 0x00,
>> @@ -46,6 +47,12 @@ static pthread_t ipc_th = 0;
>> static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;
>> static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
>>
>> +struct media_packet {
>> +     struct rtp_header hdr;
>> +     struct rtp_payload payload;
>> +     uint8_t data[0];
>> +};
>> +
>> struct audio_input_config {
>>       uint32_t rate;
>>       uint32_t channels;
>> @@ -56,10 +63,19 @@ struct sbc_data {
>>       a2dp_sbc_t sbc;
>>
>>       sbc_t enc;
>> +
>> +     size_t in_frame_len;
>> +     size_t in_buf_size;
>> +
>> +     size_t out_buf_size;
>> +     uint8_t *out_buf;
>> +
>> +     unsigned frame_duration;
>> };
>>
>> static int sbc_get_presets(struct audio_preset *preset, size_t *len);
>> -static int sbc_codec_init(struct audio_preset *preset, void **codec_data);
>> +static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
>> +                             void **codec_data);
>> static int sbc_cleanup(void *codec_data);
>> static int sbc_get_config(void *codec_data,
>>                                       struct audio_input_config *config);
>> @@ -69,7 +85,8 @@ struct audio_codec {
>>
>>       int (*get_presets) (struct audio_preset *preset, size_t *len);
>>
>> -     int (*init) (struct audio_preset *preset, void **codec_data);
>> +     int (*init) (struct audio_preset *preset, uint16_t mtu,
>> +                             void **codec_data);
>>       int (*cleanup) (void *codec_data);
>>       int (*get_config) (void *codec_data,
>>                                       struct audio_input_config *config);
>> @@ -251,9 +268,14 @@ static void sbc_init_encoder(struct sbc_data *sbc_data)
>>       }
>> }
>>
>> -static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
>> +static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
>> +                             void **codec_data)
>> {
>>       struct sbc_data *sbc_data;
>> +     size_t hdr_len = sizeof(struct media_packet);
>> +     size_t in_frame_len;
>> +     size_t out_frame_len;
>> +     size_t num_frames;
>>
>>       DBG("");
>>
>> @@ -268,6 +290,18 @@ static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
>>
>>       sbc_init_encoder(sbc_data);
>>
>> +     in_frame_len = sbc_get_codesize(&sbc_data->enc);
>> +     out_frame_len = sbc_get_frame_length(&sbc_data->enc);
>> +     num_frames = (mtu - hdr_len) / out_frame_len;
>> +
>> +     sbc_data->in_frame_len = in_frame_len;
>> +     sbc_data->in_buf_size = num_frames * in_frame_len;
>> +
>> +     sbc_data->out_buf_size = hdr_len + num_frames * out_frame_len;
>> +     sbc_data->out_buf = calloc(1, sbc_data->out_buf_size);
>> +
>> +     sbc_data->frame_duration = sbc_get_frame_duration(&sbc_data->enc);
>> +
>>       *codec_data = sbc_data;
>>
>>       return AUDIO_STATUS_SUCCESS;
>> @@ -280,6 +314,7 @@ static int sbc_cleanup(void *codec_data)
>>       DBG("");
>>
>>       sbc_finish(&sbc_data->enc);
>> +     free(sbc_data->out_buf);
>>       free(codec_data);
>>
>>       return AUDIO_STATUS_SUCCESS;
>> @@ -511,7 +546,7 @@ static int ipc_close_cmd(uint8_t endpoint_id)
>>       return result;
>> }
>>
>> -static int ipc_open_stream_cmd(uint8_t endpoint_id,
>> +static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu,
>>                                       struct audio_preset **caps)
>> {
>>       char buf[BLUEZ_AUDIO_MTU];
>> @@ -534,6 +569,7 @@ static int ipc_open_stream_cmd(uint8_t endpoint_id,
>>       if (result == AUDIO_STATUS_SUCCESS) {
>>               size_t buf_len = sizeof(struct audio_preset) +
>>                                       rsp->preset[0].len;
>> +             *mtu = rsp->mtu;
>>               *caps = malloc(buf_len);
>>               memcpy(*caps, &rsp->preset, buf_len);
>>       } else {
>> @@ -919,6 +955,7 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
>>       struct a2dp_stream_out *out;
>>       struct audio_preset *preset;
>>       const struct audio_codec *codec;
>> +     uint16_t mtu;
>>
>>       out = calloc(1, sizeof(struct a2dp_stream_out));
>>       if (!out)
>> @@ -946,7 +983,8 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
>>       /* TODO: for now we always use endpoint 0 */
>>       out->ep = &audio_endpoints[0];
>>
>> -     if (ipc_open_stream_cmd(out->ep->id, &preset) != AUDIO_STATUS_SUCCESS)
>> +     if (ipc_open_stream_cmd(out->ep->id, &mtu, &preset) !=
>> +                     AUDIO_STATUS_SUCCESS)
>>               goto fail;
>>
>>       if (!preset)
>> @@ -954,7 +992,7 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
>>
>>       codec = out->ep->codec;
>>
>> -     codec->init(preset, &out->ep->codec_data);
>> +     codec->init(preset, mtu, &out->ep->codec_data);
>>       codec->get_config(out->ep->codec_data, &out->cfg);
>>
>>       DBG("rate=%d channels=%d format=%d", out->cfg.rate,
>> diff --git a/android/rtp.h b/android/rtp.h
>> new file mode 100644
>> index 0000000..45fddcf
>> --- /dev/null
>> +++ b/android/rtp.h
>> @@ -0,0 +1,76 @@
>> +/*
>> + *
>> + *  BlueZ - Bluetooth protocol stack for Linux
>> + *
>> + *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
>> + *
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2.1 of the License, or (at your option) any later version.
>> + *
>> + *  This library is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + *  Lesser General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU Lesser General Public
>> + *  License along with this library; if not, write to the Free Software
>> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
>> + *
>> + */
>
> where is this file coming from? Why do we need a copy of it?

>From BlueZ but it was removed (was used in pcm_bluetooth.c) so I just
added it again since we need RTP header structures. Or should these
just be added inline to hal-audio.c?


BR,
Andrzej

^ permalink raw reply

* Re: [PATCH 2/9] android: Build Audio HAL with SBC
From: Andrzej Kaczmarek @ 2014-01-17 19:09 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <04524385-0757-4DFE-B503-352781B4B9BA@holtmann.org>

Hi Marcel,

On 17 January 2014 19:27, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Andrzej,
>
>> Build for Android requires libsbc sources to be available in
>> external/bluetooth/sbc. Build for host requires libsbc package to be
>> installed.
>> ---
>> android/Android.mk  | 14 +++++++++++---
>> android/Makefile.am |  2 ++
>> configure.ac        |  7 +++++++
>> 3 files changed, 20 insertions(+), 3 deletions(-)
>>
>> diff --git a/android/Android.mk b/android/Android.mk
>> index 7e97ec8..63a4a24 100644
>> --- a/android/Android.mk
>> +++ b/android/Android.mk
>> @@ -3,8 +3,9 @@ LOCAL_PATH := $(call my-dir)
>> # Retrieve BlueZ version from configure.ac file
>> BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D'AC_INIT(_,v)=v')
>>
>> -# Specify pathmap for glib
>> -pathmap_INCL += glib:external/bluetooth/glib
>> +# Specify pathmap for glib and sbc
>> +pathmap_INCL += glib:external/bluetooth/glib \
>> +     sbc:external/bluetooth/sbc
>>
>> # Specify common compiler flags
>> BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
>> @@ -220,11 +221,18 @@ include $(BUILD_EXECUTABLE)
>>
>> include $(CLEAR_VARS)
>>
>> -LOCAL_SRC_FILES := hal-audio.c
>> +LOCAL_SRC_FILES := hal-audio.c \
>> +     ../../sbc/sbc/sbc.c \
>> +     ../../sbc/sbc/sbc_primitives.c \
>> +     ../../sbc/sbc/sbc_primitives_armv6.c \
>> +     ../../sbc/sbc/sbc_primitives_iwmmxt.c \
>> +     ../../sbc/sbc/sbc_primitives_mmx.c \
>> +     ../../sbc/sbc/sbc_primitives_neon.c \
>
> why? Can we not just build libsbc for Android?

This way we can use upstream sbc git without forking it to add Android.mk.

> I rather install an extra library and not have to make this builtin.

Sure, this can be changed. Static or dynamic library?


BR,
Andrzej

^ permalink raw reply

* Re: [PATCH v4 2/2] Bluetooth: Queue incoming ACL data until BT_CONNECTED state is reached
From: Marcel Holtmann @ 2014-01-17 19:06 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1389984311-10482-2-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> This patch adds a queue for incoming L2CAP data that's received before
> l2cap_connect_cfm is called and processes the data once
> l2cap_connect_cfm is called. This way we ensure that we have e.g. all
> remote features before processing L2CAP signaling data (which is very
> important for making the correct security decisions).
> 
> The processing of the pending rx data needs to be done through
> queue_work since unlike l2cap_recv_acldata, l2cap_connect_cfm is called
> with the hci_dev lock held which could cause potential deadlocks.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> include/net/bluetooth/l2cap.h |  3 +++
> net/bluetooth/l2cap_core.c    | 27 +++++++++++++++++++++++++++
> 2 files changed, 30 insertions(+)

both patches have been applied to bluetooth-next tree.

Regards

Marcel


^ permalink raw reply

* [PATCH v4 2/2] Bluetooth: Queue incoming ACL data until BT_CONNECTED state is reached
From: johan.hedberg @ 2014-01-17 18:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389984311-10482-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds a queue for incoming L2CAP data that's received before
l2cap_connect_cfm is called and processes the data once
l2cap_connect_cfm is called. This way we ensure that we have e.g. all
remote features before processing L2CAP signaling data (which is very
important for making the correct security decisions).

The processing of the pending rx data needs to be done through
queue_work since unlike l2cap_recv_acldata, l2cap_connect_cfm is called
with the hci_dev lock held which could cause potential deadlocks.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/l2cap.h |  3 +++
 net/bluetooth/l2cap_core.c    | 27 +++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index c695083eee2b..85cf40acc47e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -624,6 +624,9 @@ struct l2cap_conn {
 	__u32			rx_len;
 	__u8			tx_ident;
 
+	struct sk_buff_head	pending_rx;
+	struct work_struct	pending_rx_work;
+
 	__u8			disc_reason;
 
 	struct delayed_work	security_timer;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 317a5737daf6..cd534599fbfa 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1550,6 +1550,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 	}
 
 	mutex_unlock(&conn->chan_lock);
+
+	queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
 }
 
 /* Notify sockets that we cannot guaranty reliability anymore */
@@ -1675,6 +1677,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
 	kfree_skb(conn->rx_skb);
 
+	skb_queue_purge(&conn->pending_rx);
+	flush_work(&conn->pending_rx_work);
+
 	l2cap_unregister_all_users(conn);
 
 	mutex_lock(&conn->chan_lock);
@@ -6880,9 +6885,16 @@ drop:
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct l2cap_hdr *lh = (void *) skb->data;
+	struct hci_conn *hcon = conn->hcon;
 	u16 cid, len;
 	__le16 psm;
 
+	if (hcon->state != BT_CONNECTED) {
+		BT_DBG("queueing pending rx skb");
+		skb_queue_tail(&conn->pending_rx, skb);
+		return;
+	}
+
 	skb_pull(skb, L2CAP_HDR_SIZE);
 	cid = __le16_to_cpu(lh->cid);
 	len = __le16_to_cpu(lh->len);
@@ -6928,6 +6940,18 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 	}
 }
 
+static void process_pending_rx(struct work_struct *work)
+{
+	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+					       pending_rx_work);
+	struct sk_buff *skb;
+
+	BT_DBG("");
+
+	while ((skb = skb_dequeue(&conn->pending_rx)))
+		l2cap_recv_frame(conn, skb);
+}
+
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
 {
 	struct l2cap_conn *conn = hcon->l2cap_data;
@@ -6983,6 +7007,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
 	else
 		INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
 
+	skb_queue_head_init(&conn->pending_rx);
+	INIT_WORK(&conn->pending_rx_work, process_pending_rx);
+
 	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
 	return conn;
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v4 1/2] Bluetooth: Reorder L2CAP functions to avoid forward declarations
From: johan.hedberg @ 2014-01-17 18:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

This patch moves the l2cap_conn_add, is_valid_psm and l2cap_chan_connect
functions further down in l2cap_core.c. The patch doesn't contain
anything else except the relocation of these functions. By moving the
functions further down the patch enables a subsequent patch that adds a
pending RX queue to be implemented without a forward declaration of a
function.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 415 ++++++++++++++++++++++-----------------------
 1 file changed, 207 insertions(+), 208 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 3f0dd552cb2b..317a5737daf6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1722,66 +1722,6 @@ static void security_timeout(struct work_struct *work)
 	}
 }
 
-static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
-{
-	struct l2cap_conn *conn = hcon->l2cap_data;
-	struct hci_chan *hchan;
-
-	if (conn)
-		return conn;
-
-	hchan = hci_chan_create(hcon);
-	if (!hchan)
-		return NULL;
-
-	conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL);
-	if (!conn) {
-		hci_chan_del(hchan);
-		return NULL;
-	}
-
-	kref_init(&conn->ref);
-	hcon->l2cap_data = conn;
-	conn->hcon = hcon;
-	hci_conn_get(conn->hcon);
-	conn->hchan = hchan;
-
-	BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
-
-	switch (hcon->type) {
-	case LE_LINK:
-		if (hcon->hdev->le_mtu) {
-			conn->mtu = hcon->hdev->le_mtu;
-			break;
-		}
-		/* fall through */
-	default:
-		conn->mtu = hcon->hdev->acl_mtu;
-		break;
-	}
-
-	conn->feat_mask = 0;
-
-	if (hcon->type == ACL_LINK)
-		conn->hs_enabled = test_bit(HCI_HS_ENABLED,
-					    &hcon->hdev->dev_flags);
-
-	spin_lock_init(&conn->lock);
-	mutex_init(&conn->chan_lock);
-
-	INIT_LIST_HEAD(&conn->chan_l);
-	INIT_LIST_HEAD(&conn->users);
-
-	if (hcon->type == LE_LINK)
-		INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
-	else
-		INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
-
-	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
-
-	return conn;
-}
-
 static void l2cap_conn_free(struct kref *ref)
 {
 	struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref);
@@ -1852,154 +1792,6 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
 	return c1;
 }
 
-static bool is_valid_psm(u16 psm, u8 dst_type)
-{
-	if (!psm)
-		return false;
-
-	if (bdaddr_type_is_le(dst_type))
-		return (psm <= 0x00ff);
-
-	/* PSM must be odd and lsb of upper byte must be 0 */
-	return ((psm & 0x0101) == 0x0001);
-}
-
-int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
-		       bdaddr_t *dst, u8 dst_type)
-{
-	struct l2cap_conn *conn;
-	struct hci_conn *hcon;
-	struct hci_dev *hdev;
-	__u8 auth_type;
-	int err;
-
-	BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
-	       dst_type, __le16_to_cpu(psm));
-
-	hdev = hci_get_route(dst, &chan->src);
-	if (!hdev)
-		return -EHOSTUNREACH;
-
-	hci_dev_lock(hdev);
-
-	l2cap_chan_lock(chan);
-
-	if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
-	    chan->chan_type != L2CAP_CHAN_RAW) {
-		err = -EINVAL;
-		goto done;
-	}
-
-	if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
-		err = -EINVAL;
-		goto done;
-	}
-
-	switch (chan->mode) {
-	case L2CAP_MODE_BASIC:
-		break;
-	case L2CAP_MODE_LE_FLOWCTL:
-		l2cap_le_flowctl_init(chan);
-		break;
-	case L2CAP_MODE_ERTM:
-	case L2CAP_MODE_STREAMING:
-		if (!disable_ertm)
-			break;
-		/* fall through */
-	default:
-		err = -ENOTSUPP;
-		goto done;
-	}
-
-	switch (chan->state) {
-	case BT_CONNECT:
-	case BT_CONNECT2:
-	case BT_CONFIG:
-		/* Already connecting */
-		err = 0;
-		goto done;
-
-	case BT_CONNECTED:
-		/* Already connected */
-		err = -EISCONN;
-		goto done;
-
-	case BT_OPEN:
-	case BT_BOUND:
-		/* Can connect */
-		break;
-
-	default:
-		err = -EBADFD;
-		goto done;
-	}
-
-	/* Set destination address and psm */
-	bacpy(&chan->dst, dst);
-	chan->dst_type = dst_type;
-
-	chan->psm = psm;
-	chan->dcid = cid;
-
-	auth_type = l2cap_get_auth_type(chan);
-
-	if (bdaddr_type_is_le(dst_type))
-		hcon = hci_connect(hdev, LE_LINK, dst, dst_type,
-				   chan->sec_level, auth_type);
-	else
-		hcon = hci_connect(hdev, ACL_LINK, dst, dst_type,
-				   chan->sec_level, auth_type);
-
-	if (IS_ERR(hcon)) {
-		err = PTR_ERR(hcon);
-		goto done;
-	}
-
-	conn = l2cap_conn_add(hcon);
-	if (!conn) {
-		hci_conn_drop(hcon);
-		err = -ENOMEM;
-		goto done;
-	}
-
-	if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
-		hci_conn_drop(hcon);
-		err = -EBUSY;
-		goto done;
-	}
-
-	/* Update source addr of the socket */
-	bacpy(&chan->src, &hcon->src);
-	chan->src_type = bdaddr_type(hcon, hcon->src_type);
-
-	l2cap_chan_unlock(chan);
-	l2cap_chan_add(conn, chan);
-	l2cap_chan_lock(chan);
-
-	/* l2cap_chan_add takes its own ref so we can drop this one */
-	hci_conn_drop(hcon);
-
-	l2cap_state_change(chan, BT_CONNECT);
-	__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
-
-	if (hcon->state == BT_CONNECTED) {
-		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
-			__clear_chan_timer(chan);
-			if (l2cap_chan_check_security(chan))
-				l2cap_state_change(chan, BT_CONNECTED);
-		} else
-			l2cap_do_start(chan);
-	}
-
-	err = 0;
-
-done:
-	l2cap_chan_unlock(chan);
-	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-	return err;
-}
-
 static void l2cap_monitor_timeout(struct work_struct *work)
 {
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
@@ -7136,6 +6928,213 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 	}
 }
 
+static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
+{
+	struct l2cap_conn *conn = hcon->l2cap_data;
+	struct hci_chan *hchan;
+
+	if (conn)
+		return conn;
+
+	hchan = hci_chan_create(hcon);
+	if (!hchan)
+		return NULL;
+
+	conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL);
+	if (!conn) {
+		hci_chan_del(hchan);
+		return NULL;
+	}
+
+	kref_init(&conn->ref);
+	hcon->l2cap_data = conn;
+	conn->hcon = hcon;
+	hci_conn_get(conn->hcon);
+	conn->hchan = hchan;
+
+	BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
+
+	switch (hcon->type) {
+	case LE_LINK:
+		if (hcon->hdev->le_mtu) {
+			conn->mtu = hcon->hdev->le_mtu;
+			break;
+		}
+		/* fall through */
+	default:
+		conn->mtu = hcon->hdev->acl_mtu;
+		break;
+	}
+
+	conn->feat_mask = 0;
+
+	if (hcon->type == ACL_LINK)
+		conn->hs_enabled = test_bit(HCI_HS_ENABLED,
+					    &hcon->hdev->dev_flags);
+
+	spin_lock_init(&conn->lock);
+	mutex_init(&conn->chan_lock);
+
+	INIT_LIST_HEAD(&conn->chan_l);
+	INIT_LIST_HEAD(&conn->users);
+
+	if (hcon->type == LE_LINK)
+		INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
+	else
+		INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
+
+	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
+
+	return conn;
+}
+
+static bool is_valid_psm(u16 psm, u8 dst_type) {
+	if (!psm)
+		return false;
+
+	if (bdaddr_type_is_le(dst_type))
+		return (psm <= 0x00ff);
+
+	/* PSM must be odd and lsb of upper byte must be 0 */
+	return ((psm & 0x0101) == 0x0001);
+}
+
+int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
+		       bdaddr_t *dst, u8 dst_type)
+{
+	struct l2cap_conn *conn;
+	struct hci_conn *hcon;
+	struct hci_dev *hdev;
+	__u8 auth_type;
+	int err;
+
+	BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
+	       dst_type, __le16_to_cpu(psm));
+
+	hdev = hci_get_route(dst, &chan->src);
+	if (!hdev)
+		return -EHOSTUNREACH;
+
+	hci_dev_lock(hdev);
+
+	l2cap_chan_lock(chan);
+
+	if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
+	    chan->chan_type != L2CAP_CHAN_RAW) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	switch (chan->mode) {
+	case L2CAP_MODE_BASIC:
+		break;
+	case L2CAP_MODE_LE_FLOWCTL:
+		l2cap_le_flowctl_init(chan);
+		break;
+	case L2CAP_MODE_ERTM:
+	case L2CAP_MODE_STREAMING:
+		if (!disable_ertm)
+			break;
+		/* fall through */
+	default:
+		err = -ENOTSUPP;
+		goto done;
+	}
+
+	switch (chan->state) {
+	case BT_CONNECT:
+	case BT_CONNECT2:
+	case BT_CONFIG:
+		/* Already connecting */
+		err = 0;
+		goto done;
+
+	case BT_CONNECTED:
+		/* Already connected */
+		err = -EISCONN;
+		goto done;
+
+	case BT_OPEN:
+	case BT_BOUND:
+		/* Can connect */
+		break;
+
+	default:
+		err = -EBADFD;
+		goto done;
+	}
+
+	/* Set destination address and psm */
+	bacpy(&chan->dst, dst);
+	chan->dst_type = dst_type;
+
+	chan->psm = psm;
+	chan->dcid = cid;
+
+	auth_type = l2cap_get_auth_type(chan);
+
+	if (bdaddr_type_is_le(dst_type))
+		hcon = hci_connect(hdev, LE_LINK, dst, dst_type,
+				   chan->sec_level, auth_type);
+	else
+		hcon = hci_connect(hdev, ACL_LINK, dst, dst_type,
+				   chan->sec_level, auth_type);
+
+	if (IS_ERR(hcon)) {
+		err = PTR_ERR(hcon);
+		goto done;
+	}
+
+	conn = l2cap_conn_add(hcon);
+	if (!conn) {
+		hci_conn_drop(hcon);
+		err = -ENOMEM;
+		goto done;
+	}
+
+	if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
+		hci_conn_drop(hcon);
+		err = -EBUSY;
+		goto done;
+	}
+
+	/* Update source addr of the socket */
+	bacpy(&chan->src, &hcon->src);
+	chan->src_type = bdaddr_type(hcon, hcon->src_type);
+
+	l2cap_chan_unlock(chan);
+	l2cap_chan_add(conn, chan);
+	l2cap_chan_lock(chan);
+
+	/* l2cap_chan_add takes its own ref so we can drop this one */
+	hci_conn_drop(hcon);
+
+	l2cap_state_change(chan, BT_CONNECT);
+	__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
+
+	if (hcon->state == BT_CONNECTED) {
+		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+			__clear_chan_timer(chan);
+			if (l2cap_chan_check_security(chan))
+				l2cap_state_change(chan, BT_CONNECTED);
+		} else
+			l2cap_do_start(chan);
+	}
+
+	err = 0;
+
+done:
+	l2cap_chan_unlock(chan);
+	hci_dev_unlock(hdev);
+	hci_dev_put(hdev);
+	return err;
+}
+
 /* ---- L2CAP interface with lower layer (HCI) ---- */
 
 int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
-- 
1.8.4.2


^ permalink raw reply related

* Re: [PATCH 2/9] android: Build Audio HAL with SBC
From: Marcel Holtmann @ 2014-01-17 18:27 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1389973213-30251-3-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

> Build for Android requires libsbc sources to be available in
> external/bluetooth/sbc. Build for host requires libsbc package to be
> installed.
> ---
> android/Android.mk  | 14 +++++++++++---
> android/Makefile.am |  2 ++
> configure.ac        |  7 +++++++
> 3 files changed, 20 insertions(+), 3 deletions(-)
> 
> diff --git a/android/Android.mk b/android/Android.mk
> index 7e97ec8..63a4a24 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -3,8 +3,9 @@ LOCAL_PATH := $(call my-dir)
> # Retrieve BlueZ version from configure.ac file
> BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D'AC_INIT(_,v)=v')
> 
> -# Specify pathmap for glib
> -pathmap_INCL += glib:external/bluetooth/glib
> +# Specify pathmap for glib and sbc
> +pathmap_INCL += glib:external/bluetooth/glib \
> +	sbc:external/bluetooth/sbc
> 
> # Specify common compiler flags
> BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
> @@ -220,11 +221,18 @@ include $(BUILD_EXECUTABLE)
> 
> include $(CLEAR_VARS)
> 
> -LOCAL_SRC_FILES := hal-audio.c
> +LOCAL_SRC_FILES := hal-audio.c \
> +	../../sbc/sbc/sbc.c \
> +	../../sbc/sbc/sbc_primitives.c \
> +	../../sbc/sbc/sbc_primitives_armv6.c \
> +	../../sbc/sbc/sbc_primitives_iwmmxt.c \
> +	../../sbc/sbc/sbc_primitives_mmx.c \
> +	../../sbc/sbc/sbc_primitives_neon.c \

why? Can we not just build libsbc for Android?

I rather install an extra library and not have to make this builtin.

> 
> LOCAL_C_INCLUDES = \
> 	$(call include-path-for, system-core) \
> 	$(call include-path-for, libhardware) \
> +	$(call include-path-for, sbc) \
> 
> LOCAL_SHARED_LIBRARIES := \
> 	libcutils \
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 8d2714d..01d8996 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -130,6 +130,8 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
> 
> android_audio_a2dp_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
> 
> +android_audio_a2dp_default_la_LIBADD = @SBC_LIBS@
> +
> android_audio_a2dp_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
> 					-no-undefined -pthread
> 
> diff --git a/configure.ac b/configure.ac
> index c85f208..79c3705 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -252,6 +252,13 @@ AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android],
> 					[enable_android=${enableval}])
> AM_CONDITIONAL(ANDROID, test "${enable_android}" = "yes")
> 
> +if (test "${enable_android}" = "yes"); then
> +	PKG_CHECK_MODULES(SBC, sbc >= 1.0, dummy=yes,
> +					AC_MSG_ERROR(libsbc1 >= 1.0 is required))

This should not read libsbc1. There is no such thing as libsbc1. It should read SBC library.

> +	AC_SUBST(SBC_CFLAGS)
> +	AC_SUBST(SBC_LIBS)
> +fi
> +
> AC_DEFINE_UNQUOTED(ANDROID_STORAGEDIR, "${storagedir}/android",
> 			[Directory for the Android daemon storage files])

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 5/9] android/hal-audio: Calculate SBC stream parameters
From: Marcel Holtmann @ 2014-01-17 18:25 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1389973213-30251-6-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

> This patch adds necessary calculations for SBC stream parameters.
> 
> Both input and output buffers are expected to have exact amount of
> data to fill single media packet (based on transport channel MTU).
> 
> Frame duration will be used to synchronize input and output streams.
> ---
> android/hal-audio.c | 50 ++++++++++++++++++++++++++++++-----
> android/rtp.h       | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 120 insertions(+), 6 deletions(-)
> create mode 100644 android/rtp.h
> 
> diff --git a/android/hal-audio.c b/android/hal-audio.c
> index e5c646c..3f53295 100644
> --- a/android/hal-audio.c
> +++ b/android/hal-audio.c
> @@ -33,6 +33,7 @@
> #include "hal-msg.h"
> #include "../profiles/audio/a2dp-codecs.h"
> #include <sbc/sbc.h>
> +#include "rtp.h"
> 
> static const uint8_t a2dp_src_uuid[] = {
> 		0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x10, 0x00,
> @@ -46,6 +47,12 @@ static pthread_t ipc_th = 0;
> static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;
> static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
> 
> +struct media_packet {
> +	struct rtp_header hdr;
> +	struct rtp_payload payload;
> +	uint8_t data[0];
> +};
> +
> struct audio_input_config {
> 	uint32_t rate;
> 	uint32_t channels;
> @@ -56,10 +63,19 @@ struct sbc_data {
> 	a2dp_sbc_t sbc;
> 
> 	sbc_t enc;
> +
> +	size_t in_frame_len;
> +	size_t in_buf_size;
> +
> +	size_t out_buf_size;
> +	uint8_t *out_buf;
> +
> +	unsigned frame_duration;
> };
> 
> static int sbc_get_presets(struct audio_preset *preset, size_t *len);
> -static int sbc_codec_init(struct audio_preset *preset, void **codec_data);
> +static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
> +				void **codec_data);
> static int sbc_cleanup(void *codec_data);
> static int sbc_get_config(void *codec_data,
> 					struct audio_input_config *config);
> @@ -69,7 +85,8 @@ struct audio_codec {
> 
> 	int (*get_presets) (struct audio_preset *preset, size_t *len);
> 
> -	int (*init) (struct audio_preset *preset, void **codec_data);
> +	int (*init) (struct audio_preset *preset, uint16_t mtu,
> +				void **codec_data);
> 	int (*cleanup) (void *codec_data);
> 	int (*get_config) (void *codec_data,
> 					struct audio_input_config *config);
> @@ -251,9 +268,14 @@ static void sbc_init_encoder(struct sbc_data *sbc_data)
> 	}
> }
> 
> -static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
> +static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
> +				void **codec_data)
> {
> 	struct sbc_data *sbc_data;
> +	size_t hdr_len = sizeof(struct media_packet);
> +	size_t in_frame_len;
> +	size_t out_frame_len;
> +	size_t num_frames;
> 
> 	DBG("");
> 
> @@ -268,6 +290,18 @@ static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
> 
> 	sbc_init_encoder(sbc_data);
> 
> +	in_frame_len = sbc_get_codesize(&sbc_data->enc);
> +	out_frame_len = sbc_get_frame_length(&sbc_data->enc);
> +	num_frames = (mtu - hdr_len) / out_frame_len;
> +
> +	sbc_data->in_frame_len = in_frame_len;
> +	sbc_data->in_buf_size = num_frames * in_frame_len;
> +
> +	sbc_data->out_buf_size = hdr_len + num_frames * out_frame_len;
> +	sbc_data->out_buf = calloc(1, sbc_data->out_buf_size);
> +
> +	sbc_data->frame_duration = sbc_get_frame_duration(&sbc_data->enc);
> +
> 	*codec_data = sbc_data;
> 
> 	return AUDIO_STATUS_SUCCESS;
> @@ -280,6 +314,7 @@ static int sbc_cleanup(void *codec_data)
> 	DBG("");
> 
> 	sbc_finish(&sbc_data->enc);
> +	free(sbc_data->out_buf);
> 	free(codec_data);
> 
> 	return AUDIO_STATUS_SUCCESS;
> @@ -511,7 +546,7 @@ static int ipc_close_cmd(uint8_t endpoint_id)
> 	return result;
> }
> 
> -static int ipc_open_stream_cmd(uint8_t endpoint_id,
> +static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu,
> 					struct audio_preset **caps)
> {
> 	char buf[BLUEZ_AUDIO_MTU];
> @@ -534,6 +569,7 @@ static int ipc_open_stream_cmd(uint8_t endpoint_id,
> 	if (result == AUDIO_STATUS_SUCCESS) {
> 		size_t buf_len = sizeof(struct audio_preset) +
> 					rsp->preset[0].len;
> +		*mtu = rsp->mtu;
> 		*caps = malloc(buf_len);
> 		memcpy(*caps, &rsp->preset, buf_len);
> 	} else {
> @@ -919,6 +955,7 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
> 	struct a2dp_stream_out *out;
> 	struct audio_preset *preset;
> 	const struct audio_codec *codec;
> +	uint16_t mtu;
> 
> 	out = calloc(1, sizeof(struct a2dp_stream_out));
> 	if (!out)
> @@ -946,7 +983,8 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
> 	/* TODO: for now we always use endpoint 0 */
> 	out->ep = &audio_endpoints[0];
> 
> -	if (ipc_open_stream_cmd(out->ep->id, &preset) != AUDIO_STATUS_SUCCESS)
> +	if (ipc_open_stream_cmd(out->ep->id, &mtu, &preset) !=
> +			AUDIO_STATUS_SUCCESS)
> 		goto fail;
> 
> 	if (!preset)
> @@ -954,7 +992,7 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
> 
> 	codec = out->ep->codec;
> 
> -	codec->init(preset, &out->ep->codec_data);
> +	codec->init(preset, mtu, &out->ep->codec_data);
> 	codec->get_config(out->ep->codec_data, &out->cfg);
> 
> 	DBG("rate=%d channels=%d format=%d", out->cfg.rate,
> diff --git a/android/rtp.h b/android/rtp.h
> new file mode 100644
> index 0000000..45fddcf
> --- /dev/null
> +++ b/android/rtp.h
> @@ -0,0 +1,76 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
> + *
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> + *
> + */

where is this file coming from? Why do we need a copy of it?

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 4/9] android/hal-audio: Initialize SBC encoder
From: Marcel Holtmann @ 2014-01-17 18:24 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1389973213-30251-5-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

> ---
> android/hal-audio.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 72 insertions(+)
> 
> diff --git a/android/hal-audio.c b/android/hal-audio.c
> index f53dba0..e5c646c 100644
> --- a/android/hal-audio.c
> +++ b/android/hal-audio.c
> @@ -32,6 +32,7 @@
> #include "hal-log.h"
> #include "hal-msg.h"
> #include "../profiles/audio/a2dp-codecs.h"
> +#include <sbc/sbc.h>
> 
> static const uint8_t a2dp_src_uuid[] = {
> 		0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x10, 0x00,
> @@ -53,6 +54,8 @@ struct audio_input_config {
> 
> struct sbc_data {
> 	a2dp_sbc_t sbc;
> +
> +	sbc_t enc;
> };
> 
> static int sbc_get_presets(struct audio_preset *preset, size_t *len);
> @@ -184,6 +187,70 @@ static int sbc_get_presets(struct audio_preset *preset, size_t *len)
> 	return i;
> }
> 
> +static void sbc_init_encoder(struct sbc_data *sbc_data)
> +{
> +	a2dp_sbc_t *in = &sbc_data->sbc;
> +	sbc_t *out = &sbc_data->enc;
> +
> +	DBG("");
> +
> +	sbc_init(out, 0L);
> +
> +	switch (in->frequency) {
> +	case SBC_SAMPLING_FREQ_16000:
> +		out->frequency = SBC_FREQ_16000;
> +		break;
> +	case SBC_SAMPLING_FREQ_32000:
> +		out->frequency = SBC_FREQ_32000;
> +		break;
> +	case SBC_SAMPLING_FREQ_44100:
> +		out->frequency = SBC_FREQ_44100;
> +		break;
> +	case SBC_SAMPLING_FREQ_48000:
> +		out->frequency = SBC_FREQ_48000;
> +		break;
> +	}
> +
> +	out->subbands = in->subbands == SBC_SUBBANDS_4 ? SBC_SB_4 : SBC_SB_8;
> +
> +	switch (in->channel_mode) {
> +	case SBC_CHANNEL_MODE_MONO:
> +		out->mode = SBC_MODE_MONO;
> +		break;
> +	case SBC_CHANNEL_MODE_DUAL_CHANNEL:
> +		out->mode = SBC_MODE_DUAL_CHANNEL;
> +		break;
> +	case SBC_CHANNEL_MODE_JOINT_STEREO:
> +		out->mode = SBC_MODE_JOINT_STEREO;
> +		break;
> +	case SBC_CHANNEL_MODE_STEREO:
> +		out->mode = SBC_MODE_STEREO;
> +		break;
> +	}
> +
> +	out->endian = SBC_LE;
> +
> +	out->bitpool = in->max_bitpool;
> +
> +	out->allocation = in->allocation_method == SBC_ALLOCATION_SNR ?
> +				SBC_AM_SNR : SBC_AM_LOUDNESS;
> +
> +	switch (in->block_length) {
> +	case SBC_BLOCK_LENGTH_4:
> +		out->blocks = SBC_BLK_4;
> +		break;
> +	case SBC_BLOCK_LENGTH_8:
> +		out->blocks = SBC_BLK_8;
> +		break;
> +	case SBC_BLOCK_LENGTH_12:
> +		out->blocks = SBC_BLK_12;
> +		break;
> +	case SBC_BLOCK_LENGTH_16:
> +		out->blocks = SBC_BLK_16;
> +		break;
> +	}

aren’t the values all the same? This looks pretty complicated for something that should be dead simple. Does Android really had to duplicate every single definition with the same prefix?

> +}
> +
> static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
> {
> 	struct sbc_data *sbc_data;
> @@ -199,6 +266,8 @@ static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
> 
> 	memcpy(&sbc_data->sbc, preset->data, preset->len);
> 
> +	sbc_init_encoder(sbc_data);
> +
> 	*codec_data = sbc_data;
> 
> 	return AUDIO_STATUS_SUCCESS;
> @@ -206,8 +275,11 @@ static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
> 
> static int sbc_cleanup(void *codec_data)
> {
> +	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
> +
> 	DBG("");
> 
> +	sbc_finish(&sbc_data->enc);
> 	free(codec_data);
> 
> 	return AUDIO_STATUS_SUCCESS;

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 8/9] android/hal-audio: Read fd from Output Stream response
From: Szymon Janc @ 2014-01-17 18:13 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth
In-Reply-To: <1389973213-30251-9-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

On Friday 17 January 2014 16:40:12 Andrzej Kaczmarek wrote:
> ---
>  android/hal-audio.c | 11 +++++++----
>  1 file changed, 7 insertions(+), 4 deletions(-)
> 
> diff --git a/android/hal-audio.c b/android/hal-audio.c
> index f2cb12a..d8438f7 100644
> --- a/android/hal-audio.c
> +++ b/android/hal-audio.c
> @@ -575,7 +575,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,
> +static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu, int *fd,
> struct audio_preset **caps)
>  {
>  	char buf[BLUEZ_AUDIO_MTU];
> @@ -593,7 +593,7 @@ static int ipc_open_stream_cmd(uint8_t endpoint_id,
> uint16_t *mtu, cmd.id = endpoint_id;
> 
>  	result = audio_ipc_cmd(AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
> -				sizeof(cmd), &cmd, &rsp_len, rsp, NULL);
> +				sizeof(cmd), &cmd, &rsp_len, rsp, fd);
> 
>  	if (result == AUDIO_STATUS_SUCCESS) {
>  		size_t buf_len = sizeof(struct audio_preset) +
> @@ -990,6 +990,7 @@ static int audio_open_output_stream(struct
> audio_hw_device *dev, struct audio_preset *preset;
>  	const struct audio_codec *codec;
>  	uint16_t mtu;
> +	int fd;
> 
>  	out = calloc(1, sizeof(struct a2dp_stream_out));
>  	if (!out)
> @@ -1017,13 +1018,15 @@ static int audio_open_output_stream(struct
> audio_hw_device *dev, /* TODO: for now we always use endpoint 0 */
>  	out->ep = &audio_endpoints[0];
> 
> -	if (ipc_open_stream_cmd(out->ep->id, &mtu, &preset) !=
> +	if (ipc_open_stream_cmd(out->ep->id, &mtu, &fd, &preset) !=
>  			AUDIO_STATUS_SUCCESS)
>  		goto fail;
> 
> -	if (!preset)
> +	if (!preset || fd < 0)
>  		goto fail;

For sanity, code under fail label should be updated to handle that either 
preset or fd might be valid here.

> 
> +	out->ep->fd = fd;
> +

I might be missing something but fd is never closed. Should this be done in 
audio_close_output_stream() ?

>  	codec = out->ep->codec;
> 
>  	codec->init(preset, mtu, &out->ep->codec_data);

-- 
Szymon K. Janc
szymon.janc@gmail.com

^ permalink raw reply

* [PATCH 9/9] android/hal-audio: Add proper SBC encoding
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

Input and output stream is configured in a way that each input buffer
can be encoded to exactly one output buffer.

Reading from AudioFlinger is synchronized based on amounts of frames
which were expected to be sent since stream was resumed, i.e. as long
as we sent enough data we can wait for period of single media packet
before we need another buffer from input. Without synchronization
we'd receive next input buffer as soon as we process current one.
---
 android/hal-audio.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 93 insertions(+), 3 deletions(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index d8438f7..86ef97b 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -24,6 +24,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 
 #include <hardware/audio.h>
 #include <hardware/hardware.h>
@@ -74,8 +75,22 @@ struct sbc_data {
 
 	struct timespec start;
 	unsigned frames_sent;
+
+	uint16_t seq;
 };
 
+static inline void timespec_diff(struct timespec *a, struct timespec *b,
+					struct timespec *res)
+{
+	res->tv_sec = a->tv_sec - b->tv_sec;
+	res->tv_nsec = a->tv_nsec - b->tv_nsec;
+
+	if (res->tv_nsec < 0) {
+		res->tv_sec--;
+		res->tv_nsec += 1000000000; /* 1sec */
+	}
+}
+
 static int sbc_get_presets(struct audio_preset *preset, size_t *len);
 static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
 				void **codec_data);
@@ -84,6 +99,8 @@ static int sbc_get_config(void *codec_data,
 					struct audio_input_config *config);
 static size_t sbc_get_buffer_size(void *codec_data);
 static void sbc_resume(void *codec_data);
+static ssize_t sbc_write_data(void *codec_data, const void *buffer,
+					size_t bytes, int fd);
 
 struct audio_codec {
 	uint8_t type;
@@ -98,7 +115,7 @@ struct audio_codec {
 	size_t (*get_buffer_size) (void *codec_data);
 	void (*resume) (void *codec_data);
 	ssize_t (*write_data) (void *codec_data, const void *buffer,
-				size_t bytes);
+				size_t bytes, int fd);
 };
 
 static const struct audio_codec audio_codecs[] = {
@@ -112,6 +129,7 @@ static const struct audio_codec audio_codecs[] = {
 		.get_config = sbc_get_config,
 		.get_buffer_size = sbc_get_buffer_size,
 		.resume = sbc_resume,
+		.write_data = sbc_write_data,
 	}
 };
 
@@ -378,6 +396,74 @@ static void sbc_resume(void *codec_data)
 	sbc_data->frames_sent = 0;
 }
 
+static ssize_t sbc_write_data(void *codec_data, const void *buffer,
+				size_t bytes, int fd)
+{
+	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
+	size_t consumed = 0;
+	size_t encoded = 0;
+	struct media_packet *mp = (struct media_packet *) sbc_data->out_buf;
+	size_t free_space = sbc_data->out_buf_size - sizeof(*mp);
+	struct timespec cur;
+	struct timespec diff;
+	unsigned expected_frames;
+	int ret;
+
+	mp->hdr.v = 2;
+	mp->hdr.pt = 1;
+	mp->hdr.sequence_number = htons(sbc_data->seq++);
+	mp->hdr.ssrc = htonl(1);
+	mp->payload.frame_count = 0;
+
+	while (bytes - consumed >= sbc_data->in_frame_len) {
+		ssize_t written = 0;
+
+		ret = sbc_encode(&sbc_data->enc, buffer + consumed,
+					sbc_data->in_frame_len,
+					mp->data + encoded, free_space,
+					&written);
+
+		if (ret < 0) {
+			DBG("failed to encode block");
+			break;
+		}
+
+		mp->payload.frame_count++;
+
+		consumed += ret;
+		encoded += written;
+		free_space -= written;
+	}
+
+	ret = write(fd, mp, sizeof(*mp) + encoded);
+	if (ret < 0) {
+		int err = errno;
+		DBG("error writing data: %d (%s)", err, strerror(err));
+	}
+
+	if (consumed != bytes || free_space != 0) {
+		/*
+		 * we should encode all input data and fill output buffer
+		 * if we did not, something went wrong but we can't really
+		 * handle this so this is just sanity check
+		 */
+		DBG("some data were not encoded");
+	}
+
+	sbc_data->frames_sent += mp->payload.frame_count;
+
+	clock_gettime(CLOCK_MONOTONIC, &cur);
+	timespec_diff(&cur, &sbc_data->start, &diff);
+	expected_frames = (diff.tv_sec * 1000000 + diff.tv_nsec / 1000) /
+				sbc_data->frame_duration;
+
+	if (sbc_data->frames_sent >= expected_frames)
+		usleep(sbc_data->frame_duration * mp->payload.frame_count);
+
+	/* we always assume that all data was processed and sent */
+	return bytes;
+}
+
 static void audio_ipc_cleanup(void)
 {
 	if (audio_sk >= 0) {
@@ -710,9 +796,13 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 		return -1;
 	}
 
-	/* TODO: encode data using codec */
+	if (out->ep->fd < 0) {
+		DBG("no transport");
+		return -1;
+	}
 
-	return bytes;
+	return out->ep->codec->write_data(out->ep->codec_data, buffer,
+						bytes, out->ep->fd);
 }
 
 static uint32_t out_get_sample_rate(const struct audio_stream *stream)
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 8/9] android/hal-audio: Read fd from Output Stream response
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

diff --git a/android/hal-audio.c b/android/hal-audio.c
index f2cb12a..d8438f7 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -575,7 +575,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,
+static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu, int *fd,
 					struct audio_preset **caps)
 {
 	char buf[BLUEZ_AUDIO_MTU];
@@ -593,7 +593,7 @@ static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu,
 	cmd.id = endpoint_id;
 
 	result = audio_ipc_cmd(AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
-				sizeof(cmd), &cmd, &rsp_len, rsp, NULL);
+				sizeof(cmd), &cmd, &rsp_len, rsp, fd);
 
 	if (result == AUDIO_STATUS_SUCCESS) {
 		size_t buf_len = sizeof(struct audio_preset) +
@@ -990,6 +990,7 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 	struct audio_preset *preset;
 	const struct audio_codec *codec;
 	uint16_t mtu;
+	int fd;
 
 	out = calloc(1, sizeof(struct a2dp_stream_out));
 	if (!out)
@@ -1017,13 +1018,15 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 	/* TODO: for now we always use endpoint 0 */
 	out->ep = &audio_endpoints[0];
 
-	if (ipc_open_stream_cmd(out->ep->id, &mtu, &preset) !=
+	if (ipc_open_stream_cmd(out->ep->id, &mtu, &fd, &preset) !=
 			AUDIO_STATUS_SUCCESS)
 		goto fail;
 
-	if (!preset)
+	if (!preset || fd < 0)
 		goto fail;
 
+	out->ep->fd = fd;
+
 	codec = out->ep->codec;
 
 	codec->init(preset, mtu, &out->ep->codec_data);
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 7/9] android/hal-audio: Return proper buffer size to AudioFlinger
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 android/hal-audio.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index aeb6ea4..f2cb12a 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -82,6 +82,7 @@ static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
 static int sbc_cleanup(void *codec_data);
 static int sbc_get_config(void *codec_data,
 					struct audio_input_config *config);
+static size_t sbc_get_buffer_size(void *codec_data);
 static void sbc_resume(void *codec_data);
 
 struct audio_codec {
@@ -94,6 +95,7 @@ struct audio_codec {
 	int (*cleanup) (void *codec_data);
 	int (*get_config) (void *codec_data,
 					struct audio_input_config *config);
+	size_t (*get_buffer_size) (void *codec_data);
 	void (*resume) (void *codec_data);
 	ssize_t (*write_data) (void *codec_data, const void *buffer,
 				size_t bytes);
@@ -108,6 +110,7 @@ static const struct audio_codec audio_codecs[] = {
 		.init = sbc_codec_init,
 		.cleanup = sbc_cleanup,
 		.get_config = sbc_get_config,
+		.get_buffer_size = sbc_get_buffer_size,
 		.resume = sbc_resume,
 	}
 };
@@ -355,6 +358,15 @@ static int sbc_get_config(void *codec_data,
 	return AUDIO_STATUS_SUCCESS;
 }
 
+static size_t sbc_get_buffer_size(void *codec_data)
+{
+	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
+
+	DBG("");
+
+	return sbc_data->in_buf_size;
+}
+
 static void sbc_resume(void *codec_data)
 {
 	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
@@ -728,8 +740,11 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
 
 static size_t out_get_buffer_size(const struct audio_stream *stream)
 {
+	struct a2dp_stream_out *out = (struct a2dp_stream_out *) stream;
+
 	DBG("");
-	return 20 * 512;
+
+	return out->ep->codec->get_buffer_size(out->ep->codec_data);
 }
 
 static uint32_t out_get_channels(const struct audio_stream *stream)
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 6/9] android/hal-audio: Add resume to codec callbacks
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

Once stream is resumed it may be required to reset some state of codec,
i.e. in case of SBC we need to reset monotonic clock and frames count
which are used for synchronization.
---
 android/hal-audio.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 3f53295..aeb6ea4 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -71,6 +71,9 @@ struct sbc_data {
 	uint8_t *out_buf;
 
 	unsigned frame_duration;
+
+	struct timespec start;
+	unsigned frames_sent;
 };
 
 static int sbc_get_presets(struct audio_preset *preset, size_t *len);
@@ -79,6 +82,7 @@ static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
 static int sbc_cleanup(void *codec_data);
 static int sbc_get_config(void *codec_data,
 					struct audio_input_config *config);
+static void sbc_resume(void *codec_data);
 
 struct audio_codec {
 	uint8_t type;
@@ -90,6 +94,7 @@ struct audio_codec {
 	int (*cleanup) (void *codec_data);
 	int (*get_config) (void *codec_data,
 					struct audio_input_config *config);
+	void (*resume) (void *codec_data);
 	ssize_t (*write_data) (void *codec_data, const void *buffer,
 				size_t bytes);
 };
@@ -103,6 +108,7 @@ static const struct audio_codec audio_codecs[] = {
 		.init = sbc_codec_init,
 		.cleanup = sbc_cleanup,
 		.get_config = sbc_get_config,
+		.resume = sbc_resume,
 	}
 };
 
@@ -349,6 +355,17 @@ static int sbc_get_config(void *codec_data,
 	return AUDIO_STATUS_SUCCESS;
 }
 
+static void sbc_resume(void *codec_data)
+{
+	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
+
+	DBG("");
+
+	clock_gettime(CLOCK_MONOTONIC, &sbc_data->start);
+
+	sbc_data->frames_sent = 0;
+}
+
 static void audio_ipc_cleanup(void)
 {
 	if (audio_sk >= 0) {
@@ -671,6 +688,8 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 		if (ipc_resume_stream_cmd(out->ep->id) != AUDIO_STATUS_SUCCESS)
 			return -1;
 
+		out->ep->codec->resume(out->ep->codec_data);
+
 		out->audio_state = AUDIO_A2DP_STATE_STARTED;
 	}
 
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 5/9] android/hal-audio: Calculate SBC stream parameters
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds necessary calculations for SBC stream parameters.

Both input and output buffers are expected to have exact amount of
data to fill single media packet (based on transport channel MTU).

Frame duration will be used to synchronize input and output streams.
---
 android/hal-audio.c | 50 ++++++++++++++++++++++++++++++-----
 android/rtp.h       | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 6 deletions(-)
 create mode 100644 android/rtp.h

diff --git a/android/hal-audio.c b/android/hal-audio.c
index e5c646c..3f53295 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -33,6 +33,7 @@
 #include "hal-msg.h"
 #include "../profiles/audio/a2dp-codecs.h"
 #include <sbc/sbc.h>
+#include "rtp.h"
 
 static const uint8_t a2dp_src_uuid[] = {
 		0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x10, 0x00,
@@ -46,6 +47,12 @@ static pthread_t ipc_th = 0;
 static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+struct media_packet {
+	struct rtp_header hdr;
+	struct rtp_payload payload;
+	uint8_t data[0];
+};
+
 struct audio_input_config {
 	uint32_t rate;
 	uint32_t channels;
@@ -56,10 +63,19 @@ struct sbc_data {
 	a2dp_sbc_t sbc;
 
 	sbc_t enc;
+
+	size_t in_frame_len;
+	size_t in_buf_size;
+
+	size_t out_buf_size;
+	uint8_t *out_buf;
+
+	unsigned frame_duration;
 };
 
 static int sbc_get_presets(struct audio_preset *preset, size_t *len);
-static int sbc_codec_init(struct audio_preset *preset, void **codec_data);
+static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
+				void **codec_data);
 static int sbc_cleanup(void *codec_data);
 static int sbc_get_config(void *codec_data,
 					struct audio_input_config *config);
@@ -69,7 +85,8 @@ struct audio_codec {
 
 	int (*get_presets) (struct audio_preset *preset, size_t *len);
 
-	int (*init) (struct audio_preset *preset, void **codec_data);
+	int (*init) (struct audio_preset *preset, uint16_t mtu,
+				void **codec_data);
 	int (*cleanup) (void *codec_data);
 	int (*get_config) (void *codec_data,
 					struct audio_input_config *config);
@@ -251,9 +268,14 @@ static void sbc_init_encoder(struct sbc_data *sbc_data)
 	}
 }
 
-static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
+static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
+				void **codec_data)
 {
 	struct sbc_data *sbc_data;
+	size_t hdr_len = sizeof(struct media_packet);
+	size_t in_frame_len;
+	size_t out_frame_len;
+	size_t num_frames;
 
 	DBG("");
 
@@ -268,6 +290,18 @@ static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
 
 	sbc_init_encoder(sbc_data);
 
+	in_frame_len = sbc_get_codesize(&sbc_data->enc);
+	out_frame_len = sbc_get_frame_length(&sbc_data->enc);
+	num_frames = (mtu - hdr_len) / out_frame_len;
+
+	sbc_data->in_frame_len = in_frame_len;
+	sbc_data->in_buf_size = num_frames * in_frame_len;
+
+	sbc_data->out_buf_size = hdr_len + num_frames * out_frame_len;
+	sbc_data->out_buf = calloc(1, sbc_data->out_buf_size);
+
+	sbc_data->frame_duration = sbc_get_frame_duration(&sbc_data->enc);
+
 	*codec_data = sbc_data;
 
 	return AUDIO_STATUS_SUCCESS;
@@ -280,6 +314,7 @@ static int sbc_cleanup(void *codec_data)
 	DBG("");
 
 	sbc_finish(&sbc_data->enc);
+	free(sbc_data->out_buf);
 	free(codec_data);
 
 	return AUDIO_STATUS_SUCCESS;
@@ -511,7 +546,7 @@ static int ipc_close_cmd(uint8_t endpoint_id)
 	return result;
 }
 
-static int ipc_open_stream_cmd(uint8_t endpoint_id,
+static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu,
 					struct audio_preset **caps)
 {
 	char buf[BLUEZ_AUDIO_MTU];
@@ -534,6 +569,7 @@ static int ipc_open_stream_cmd(uint8_t endpoint_id,
 	if (result == AUDIO_STATUS_SUCCESS) {
 		size_t buf_len = sizeof(struct audio_preset) +
 					rsp->preset[0].len;
+		*mtu = rsp->mtu;
 		*caps = malloc(buf_len);
 		memcpy(*caps, &rsp->preset, buf_len);
 	} else {
@@ -919,6 +955,7 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 	struct a2dp_stream_out *out;
 	struct audio_preset *preset;
 	const struct audio_codec *codec;
+	uint16_t mtu;
 
 	out = calloc(1, sizeof(struct a2dp_stream_out));
 	if (!out)
@@ -946,7 +983,8 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 	/* TODO: for now we always use endpoint 0 */
 	out->ep = &audio_endpoints[0];
 
-	if (ipc_open_stream_cmd(out->ep->id, &preset) != AUDIO_STATUS_SUCCESS)
+	if (ipc_open_stream_cmd(out->ep->id, &mtu, &preset) !=
+			AUDIO_STATUS_SUCCESS)
 		goto fail;
 
 	if (!preset)
@@ -954,7 +992,7 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 
 	codec = out->ep->codec;
 
-	codec->init(preset, &out->ep->codec_data);
+	codec->init(preset, mtu, &out->ep->codec_data);
 	codec->get_config(out->ep->codec_data, &out->cfg);
 
 	DBG("rate=%d channels=%d format=%d", out->cfg.rate,
diff --git a/android/rtp.h b/android/rtp.h
new file mode 100644
index 0000000..45fddcf
--- /dev/null
+++ b/android/rtp.h
@@ -0,0 +1,76 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct rtp_header {
+	unsigned cc:4;
+	unsigned x:1;
+	unsigned p:1;
+	unsigned v:2;
+
+	unsigned pt:7;
+	unsigned m:1;
+
+	uint16_t sequence_number;
+	uint32_t timestamp;
+	uint32_t ssrc;
+	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 {
+	unsigned v:2;
+	unsigned p:1;
+	unsigned x:1;
+	unsigned cc:4;
+
+	unsigned m:1;
+	unsigned pt:7;
+
+	uint16_t sequence_number;
+	uint32_t timestamp;
+	uint32_t ssrc;
+	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
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 4/9] android/hal-audio: Initialize SBC encoder
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

diff --git a/android/hal-audio.c b/android/hal-audio.c
index f53dba0..e5c646c 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -32,6 +32,7 @@
 #include "hal-log.h"
 #include "hal-msg.h"
 #include "../profiles/audio/a2dp-codecs.h"
+#include <sbc/sbc.h>
 
 static const uint8_t a2dp_src_uuid[] = {
 		0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x10, 0x00,
@@ -53,6 +54,8 @@ struct audio_input_config {
 
 struct sbc_data {
 	a2dp_sbc_t sbc;
+
+	sbc_t enc;
 };
 
 static int sbc_get_presets(struct audio_preset *preset, size_t *len);
@@ -184,6 +187,70 @@ static int sbc_get_presets(struct audio_preset *preset, size_t *len)
 	return i;
 }
 
+static void sbc_init_encoder(struct sbc_data *sbc_data)
+{
+	a2dp_sbc_t *in = &sbc_data->sbc;
+	sbc_t *out = &sbc_data->enc;
+
+	DBG("");
+
+	sbc_init(out, 0L);
+
+	switch (in->frequency) {
+	case SBC_SAMPLING_FREQ_16000:
+		out->frequency = SBC_FREQ_16000;
+		break;
+	case SBC_SAMPLING_FREQ_32000:
+		out->frequency = SBC_FREQ_32000;
+		break;
+	case SBC_SAMPLING_FREQ_44100:
+		out->frequency = SBC_FREQ_44100;
+		break;
+	case SBC_SAMPLING_FREQ_48000:
+		out->frequency = SBC_FREQ_48000;
+		break;
+	}
+
+	out->subbands = in->subbands == SBC_SUBBANDS_4 ? SBC_SB_4 : SBC_SB_8;
+
+	switch (in->channel_mode) {
+	case SBC_CHANNEL_MODE_MONO:
+		out->mode = SBC_MODE_MONO;
+		break;
+	case SBC_CHANNEL_MODE_DUAL_CHANNEL:
+		out->mode = SBC_MODE_DUAL_CHANNEL;
+		break;
+	case SBC_CHANNEL_MODE_JOINT_STEREO:
+		out->mode = SBC_MODE_JOINT_STEREO;
+		break;
+	case SBC_CHANNEL_MODE_STEREO:
+		out->mode = SBC_MODE_STEREO;
+		break;
+	}
+
+	out->endian = SBC_LE;
+
+	out->bitpool = in->max_bitpool;
+
+	out->allocation = in->allocation_method == SBC_ALLOCATION_SNR ?
+				SBC_AM_SNR : SBC_AM_LOUDNESS;
+
+	switch (in->block_length) {
+	case SBC_BLOCK_LENGTH_4:
+		out->blocks = SBC_BLK_4;
+		break;
+	case SBC_BLOCK_LENGTH_8:
+		out->blocks = SBC_BLK_8;
+		break;
+	case SBC_BLOCK_LENGTH_12:
+		out->blocks = SBC_BLK_12;
+		break;
+	case SBC_BLOCK_LENGTH_16:
+		out->blocks = SBC_BLK_16;
+		break;
+	}
+}
+
 static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
 {
 	struct sbc_data *sbc_data;
@@ -199,6 +266,8 @@ static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
 
 	memcpy(&sbc_data->sbc, preset->data, preset->len);
 
+	sbc_init_encoder(sbc_data);
+
 	*codec_data = sbc_data;
 
 	return AUDIO_STATUS_SUCCESS;
@@ -206,8 +275,11 @@ static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
 
 static int sbc_cleanup(void *codec_data)
 {
+	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
+
 	DBG("");
 
+	sbc_finish(&sbc_data->enc);
 	free(codec_data);
 
 	return AUDIO_STATUS_SUCCESS;
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 3/9] android/hal-audio: Rename sbc_init to avoid collision with libsbc
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 2f6f8c2..f53dba0 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -56,7 +56,7 @@ struct sbc_data {
 };
 
 static int sbc_get_presets(struct audio_preset *preset, size_t *len);
-static int sbc_init(struct audio_preset *preset, void **codec_data);
+static int sbc_codec_init(struct audio_preset *preset, void **codec_data);
 static int sbc_cleanup(void *codec_data);
 static int sbc_get_config(void *codec_data,
 					struct audio_input_config *config);
@@ -80,7 +80,7 @@ static const struct audio_codec audio_codecs[] = {
 
 		.get_presets = sbc_get_presets,
 
-		.init = sbc_init,
+		.init = sbc_codec_init,
 		.cleanup = sbc_cleanup,
 		.get_config = sbc_get_config,
 	}
@@ -184,7 +184,7 @@ static int sbc_get_presets(struct audio_preset *preset, size_t *len)
 	return i;
 }
 
-static int sbc_init(struct audio_preset *preset, void **codec_data)
+static int sbc_codec_init(struct audio_preset *preset, void **codec_data)
 {
 	struct sbc_data *sbc_data;
 
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 2/9] android: Build Audio HAL with SBC
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

Build for Android requires libsbc sources to be available in
external/bluetooth/sbc. Build for host requires libsbc package to be
installed.
---
 android/Android.mk  | 14 +++++++++++---
 android/Makefile.am |  2 ++
 configure.ac        |  7 +++++++
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/android/Android.mk b/android/Android.mk
index 7e97ec8..63a4a24 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -3,8 +3,9 @@ LOCAL_PATH := $(call my-dir)
 # Retrieve BlueZ version from configure.ac file
 BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D'AC_INIT(_,v)=v')
 
-# Specify pathmap for glib
-pathmap_INCL += glib:external/bluetooth/glib
+# Specify pathmap for glib and sbc
+pathmap_INCL += glib:external/bluetooth/glib \
+	sbc:external/bluetooth/sbc
 
 # Specify common compiler flags
 BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
@@ -220,11 +221,18 @@ include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := hal-audio.c
+LOCAL_SRC_FILES := hal-audio.c \
+	../../sbc/sbc/sbc.c \
+	../../sbc/sbc/sbc_primitives.c \
+	../../sbc/sbc/sbc_primitives_armv6.c \
+	../../sbc/sbc/sbc_primitives_iwmmxt.c \
+	../../sbc/sbc/sbc_primitives_mmx.c \
+	../../sbc/sbc/sbc_primitives_neon.c \
 
 LOCAL_C_INCLUDES = \
 	$(call include-path-for, system-core) \
 	$(call include-path-for, libhardware) \
+	$(call include-path-for, sbc) \
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
diff --git a/android/Makefile.am b/android/Makefile.am
index 8d2714d..01d8996 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -130,6 +130,8 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
 
 android_audio_a2dp_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
 
+android_audio_a2dp_default_la_LIBADD = @SBC_LIBS@
+
 android_audio_a2dp_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
 					-no-undefined -pthread
 
diff --git a/configure.ac b/configure.ac
index c85f208..79c3705 100644
--- a/configure.ac
+++ b/configure.ac
@@ -252,6 +252,13 @@ AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android],
 					[enable_android=${enableval}])
 AM_CONDITIONAL(ANDROID, test "${enable_android}" = "yes")
 
+if (test "${enable_android}" = "yes"); then
+	PKG_CHECK_MODULES(SBC, sbc >= 1.0, dummy=yes,
+					AC_MSG_ERROR(libsbc1 >= 1.0 is required))
+	AC_SUBST(SBC_CFLAGS)
+	AC_SUBST(SBC_LIBS)
+fi
+
 AC_DEFINE_UNQUOTED(ANDROID_STORAGEDIR, "${storagedir}/android",
 			[Directory for the Android daemon storage files])
 
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 1/9] android: Add MTU data to Open Stream Audio IPC
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1389973213-30251-1-git-send-email-andrzej.kaczmarek@tieto.com>

MTU value for transport channel is sent in Open Stream response, which
is required to calculate number of frames which can be packed into
single media packet.

This is to avoid including GPLv2 licensed headers in Audio HAL
implementation.
---
 android/a2dp.c      | 8 ++++++--
 android/audio-msg.h | 1 +
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 2288912..e7ca8b8 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1252,6 +1252,7 @@ static void bt_stream_open(const void *buf, uint16_t len)
 	struct audio_rsp_open_stream *rsp;
 	struct a2dp_setup *setup;
 	int fd;
+	uint16_t omtu;
 
 	DBG("");
 
@@ -1262,14 +1263,17 @@ static void bt_stream_open(const void *buf, uint16_t len)
 		return;
 	}
 
-	if (!avdtp_stream_get_transport(setup->stream, &fd, NULL, NULL, NULL)) {
+	if (!avdtp_stream_get_transport(setup->stream, &fd, NULL, &omtu,
+						NULL)) {
 		error("avdtp_stream_get_transport: failed");
 		audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, AUDIO_STATUS_FAILED);
 		return;
 	}
 
-	len = sizeof(struct audio_preset) + setup->preset->len;
+	len = sizeof(struct audio_rsp_open_stream) +
+			sizeof(struct audio_preset) + setup->preset->len;
 	rsp = g_malloc0(len);
+	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 8f03274..17cde09 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -63,6 +63,7 @@ struct audio_cmd_open_stream {
 } __attribute__((packed));
 
 struct audio_rsp_open_stream {
+	uint16_t mtu;
 	struct audio_preset preset[0];
 } __attribute__((packed));
 
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 0/9] android: Add SBC encoding
From: Andrzej Kaczmarek @ 2014-01-17 15:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Hi,

This series of patches adds SBC encoding to Audio HAL.

There are 2 issues which I'm aware of, but at the moment I can't tell
whether it's something in code or it's because of incomplete A2DP HAL
implementation:
- when streaming and trying to change ringtone (on Nexus 4), ringtone
  sound playback using built-in speaker is choppy
- after disconnecting some A2DP devices AudioFliger crashes (seems like
  problem I worked around before with buffer size, yet I still have no
  idea why this happens)

It's possible that after proper A2DP audio state notification is done,
both issues will be "solved", but this still needs to be tested.



Andrzej Kaczmarek (9):
  android: Add MTU data to Open Stream Audio IPC
  android: Build Audio HAL with SBC
  android/hal-audio: Rename sbc_init to avoid collision with libsbc
  android/hal-audio: Initialize SBC encoder
  android/hal-audio: Calculate SBC stream parameters
  android/hal-audio: Add resume to codec callbacks
  android/hal-audio: Return proper buffer size to AudioFlinger
  android/hal-audio: Read fd from Output Stream response
  android/hal-audio: Add proper SBC encoding

 android/Android.mk  |  14 ++-
 android/Makefile.am |   2 +
 android/a2dp.c      |   8 +-
 android/audio-msg.h |   1 +
 android/hal-audio.c | 263 +++++++++++++++++++++++++++++++++++++++++++++++++---
 android/rtp.h       |  76 +++++++++++++++
 configure.ac        |   7 ++
 7 files changed, 353 insertions(+), 18 deletions(-)
 create mode 100644 android/rtp.h

-- 
1.8.5.2


^ permalink raw reply

* [RFC v2 6/6] android/snoop: Drop capabilities on startup
From: Szymon Janc @ 2014-01-17 15:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1389972646-3761-1-git-send-email-szymon.janc@tieto.com>

---
 android/bluetoothd-snoop.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/android/bluetoothd-snoop.c b/android/bluetoothd-snoop.c
index 9312c11..f69bc2c 100644
--- a/android/bluetoothd-snoop.c
+++ b/android/bluetoothd-snoop.c
@@ -29,6 +29,9 @@
 #include <ctype.h>
 #include <stdlib.h>
 #include <unistd.h>
+#if defined(ANDROID)
+#include <sys/capability.h>
+#endif
 
 #include "lib/bluetooth.h"
 #include "lib/hci.h"
@@ -188,11 +191,36 @@ static void close_monitor(void)
 	monitor_fd = -1;
 }
 
+static void set_capabilities(void)
+{
+#if defined(ANDROID)
+	struct __user_cap_header_struct header;
+	struct __user_cap_data_struct cap;
+
+	header.version = _LINUX_CAPABILITY_VERSION;
+	header.pid = 0;
+
+	/* CAP_NET_RAW: for snooping
+	 * CAP_DAC_READ_SEARCH: override path search permissions
+	 */
+	cap.effective = cap.permitted =
+		CAP_TO_MASK(CAP_NET_RAW) |
+		CAP_TO_MASK(CAP_DAC_READ_SEARCH) ;
+	cap.inheritable = 0;
+
+	/* TODO: Move to cap_set_proc once bionic support it */
+	if (capset(&header, &cap) < 0)
+		exit(EXIT_FAILURE);
+#endif
+}
+
 int main(int argc, char *argv[])
 {
 	const char *path;
 	sigset_t mask;
 
+	set_capabilities();
+
 	if (argc > 1)
 		path = argv[1];
 	else
-- 
1.8.3.2


^ permalink raw reply related

* [RFC v2 5/6] android: Change user to bluetooth when starting daemon
From: Szymon Janc @ 2014-01-17 15:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1389972646-3761-1-git-send-email-szymon.janc@tieto.com>

---
 android/main.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/android/main.c b/android/main.c
index 6324f31..8983a84 100644
--- a/android/main.c
+++ b/android/main.c
@@ -38,6 +38,7 @@
 #include <sys/signalfd.h>
 #if defined(ANDROID)
 #include <sys/capability.h>
+#include <linux/prctl.h>
 #endif
 
 #include <glib.h>
@@ -350,6 +351,18 @@ static bool set_capabilities(void)
 		CAP_TO_MASK(CAP_NET_BIND_SERVICE);
 	cap.inheritable = 0;
 
+	/* don't clear capabilities when dropping root */
+	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+		error("%s: prctl(): %s", __func__,strerror(errno));
+		return false;
+	}
+
+	/* Android bluetooth user UID=1002 */
+	if (setuid(1002) < 0) {
+		error("%s: setuid(): %s", __func__, strerror(errno));
+		return false;
+	}
+
 	/* TODO: Move to cap_set_proc once bionic support it */
 	if (capset(&header, &cap) < 0) {
 		error("%s: capset(): %s", __func__, strerror(errno));
-- 
1.8.3.2


^ permalink raw reply related

* [RFC v2 4/6] android: Update README with init.rc updates
From: Szymon Janc @ 2014-01-17 15:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1389972646-3761-1-git-send-email-szymon.janc@tieto.com>

---
 android/README | 32 +++++++-------------------------
 1 file changed, 7 insertions(+), 25 deletions(-)

diff --git a/android/README b/android/README
index 717ffa2..24ed703 100644
--- a/android/README
+++ b/android/README
@@ -36,31 +36,13 @@ Runtime requirements
 ====================
 
 BlueZ HAL library requires 'bluetoothd' and 'bluetoothd-snoop' services to be
-available on Android system. This can be done by defining following services in
-init.rc file of targeted board:
-
-service bluetoothd /system/bin/logwrapper /system/bin/bluetoothd
-  class main
-  group bluetooth net_admin
-  disabled
-  oneshot
-
-service bluetoothd-snoop /system/bin/bluetoothd-snoop
-  class main
-  group bluetooth net_admin
-  disabled
-  oneshot
-
-It is required that bluetooth user could start and stop bluetoothd and
-bluetoothd-snoop services by setting 'ctl.start' or 'ctl.stop' property. This
-can be achieved by whitelisting bluetooth user and bluetoothd and
-bluetoothd-snoop services in init source code.
-
-Required Android init system modifications can be found at
-https://code.google.com/p/aosp-bluez.platform-system-core/
-
-Some configuration changes like setting permissions, starting hciattach
-services etc. are device specific. For convenience examples are provided at:
+available on Android system. Some permissions settings are also required.
+
+This can be done by importing init.bluetooth.rc file in init.rc file of targeted
+board:
+import init.bluetooth.rc
+
+For convenience examples are provided at:
 https://code.google.com/p/aosp-bluez.device-lge-mako/    (Nexus 4)
 https://code.google.com/p/aosp-bluez.device-asus-flo/    (Nexus 7 2013)
 
-- 
1.8.3.2


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox