Skip to content

Commit

Permalink
Add mSBC support into the SCO IO thread
Browse files Browse the repository at this point in the history
Add support for the mSBC codec for HFP into the SCO IO thread.
This support is optional, and is controlled by the --enable-msbc
configuration flag.

The receiving part of this mSBC support has been tested with Jabra
MOVE v2.3.0 headset and seems to work flawlessly. However, playback
does not work... Maybe it will work with some other BT device.

Note:
This commit is a rework of a pull request submitted by Juha Kuikka.

Fixes #29 and closes #37
  • Loading branch information
arkq committed Apr 10, 2018
1 parent 2faa68f commit 317eea9
Show file tree
Hide file tree
Showing 14 changed files with 547 additions and 9 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ Installation

$ autoreconf --install
$ mkdir build && cd build
$ ../configure --enable-aac --enable-debug
$ ../configure --enable-debug --enable-aac --enable-msbc

or if you intend to stream audio from a Linux distribution using PulseAudio (see [this
issue](https://github.com/Arkq/bluez-alsa/issues/13))

$ ../configure --enable-aac --enable-debug --disable-payloadcheck
$ ../configure --enable-debug --enable-aac --enable-msbc --disable-payloadcheck

then

Expand Down
7 changes: 7 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ AM_COND_IF([ENABLE_APTX], [
AC_DEFINE([ENABLE_APTX], [1], [Define to 1 if apt-X is enabled.])
])

AC_ARG_ENABLE([msbc],
[AS_HELP_STRING([--enable-msbc], [enable MSBC support])])
AM_CONDITIONAL([ENABLE_MSBC], [test "x$enable_msbc" = "xyes"])
AM_COND_IF([ENABLE_MSBC], [
AC_DEFINE([ENABLE_MSBC], [1], [Define to 1 if MSBC is enabled.])
])

AC_ARG_ENABLE([payloadcheck],
[AS_HELP_STRING([--disable-payloadcheck], [disable RTP payload type check (workaround for a PulseAudio bug)])])
AM_CONDITIONAL([ENABLE_PAYLOADCHECK], [test "x$enable_payloadcheck" != "xno"])
Expand Down
4 changes: 4 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ bluealsa_SOURCES = \
utils.c \
main.c

if ENABLE_MSBC
bluealsa_SOURCES += msbc.c
endif

AM_CFLAGS = \
@BLUEZ_CFLAGS@ \
@GLIB2_CFLAGS@ \
Expand Down
12 changes: 10 additions & 2 deletions src/bluealsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,16 @@ struct ba_config config = {

.hfp.features_sdp_hf =
SDP_HFP_HF_FEAT_CLI |
SDP_HFP_HF_FEAT_VOLUME,
.hfp.features_sdp_ag = 0,
SDP_HFP_HF_FEAT_VOLUME |
#if ENABLE_MSBC
SDP_HFP_HF_FEAT_WBAND |
#endif
0,
.hfp.features_sdp_ag =
#if ENABLE_MSBC
SDP_HFP_AG_FEAT_WBAND |
#endif
0,
.hfp.features_rfcomm_hf =
HFP_HF_FEAT_CLI |
HFP_HF_FEAT_VOLUME |
Expand Down
79 changes: 77 additions & 2 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "a2dp-codecs.h"
#include "a2dp-rtp.h"
#include "bluealsa.h"
#include "msbc.h"
#include "transport.h"
#include "utils.h"
#include "shared/ffb.h"
Expand Down Expand Up @@ -1129,6 +1130,11 @@ void *io_thread_sco(void *arg) {
pthread_cleanup_push(CANCEL_ROUTINE(ffb_free), &bt_in);
pthread_cleanup_push(CANCEL_ROUTINE(ffb_free), &bt_out);

#if ENABLE_MSBC
struct esco_msbc msbc = { .init = false };
pthread_cleanup_push(CANCEL_ROUTINE(msbc_finish), &msbc);
#endif

/* these buffers shall be bigger than the SCO MTU */
if (ffb_init(&bt_in, 128) == -1 || ffb_init(&bt_out, 128) == -1) {
error("Couldn't create data buffer: %s", strerror(ENOMEM));
Expand Down Expand Up @@ -1157,6 +1163,20 @@ void *io_thread_sco(void *arg) {
pfds[3].fd = pfds[4].fd = -1;

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
msbc_encode(&msbc);
msbc_decode(&msbc);
if (t->mtu_read > 0 && ffb_len_in(&msbc.dec_data) >= t->mtu_read)
pfds[1].fd = t->bt_fd;
if (t->mtu_write > 0 && ffb_len_out(&msbc.enc_data) >= t->mtu_write)
pfds[2].fd = t->bt_fd;
if (t->mtu_write > 0 && ffb_len_in(&msbc.enc_pcm) >= t->mtu_write)
pfds[3].fd = t->sco.spk_pcm.fd;
if (ffb_len_out(&msbc.dec_pcm) > 0)
pfds[4].fd = t->sco.mic_pcm.fd;
break;
#endif
case HFP_CODEC_CVSD:
default:
if (t->mtu_read > 0 && ffb_len_in(&bt_in) >= t->mtu_read)
Expand Down Expand Up @@ -1219,8 +1239,16 @@ void *io_thread_sco(void *arg) {
transport_release_bt_sco(t);
asrs.frames = 0;
}
else
else {
transport_acquire_bt_sco(t);
#if ENABLE_MSBC
/* this can be called again, make sure it is idempotent */
if (t->codec == HFP_CODEC_MSBC && msbc_init(&msbc) != 0) {
error("Couldn't initialize mSBC codec: %s", strerror(errno));
goto fail;
}
#endif
}

continue;
}
Expand All @@ -1236,6 +1264,12 @@ void *io_thread_sco(void *arg) {
ssize_t len;

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
buffer = msbc.dec_data.tail;
buffer_len = ffb_len_in(&msbc.dec_data);
break;
#endif
case HFP_CODEC_CVSD:
default:
buffer = bt_in.tail;
Expand All @@ -1259,6 +1293,11 @@ void *io_thread_sco(void *arg) {
}

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
ffb_seek(&msbc.dec_data, len);
break;
#endif
case HFP_CODEC_CVSD:
default:
ffb_seek(&bt_in, len);
Expand All @@ -1278,6 +1317,12 @@ void *io_thread_sco(void *arg) {
ssize_t len;

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
buffer = msbc.enc_data.data;
buffer_len = t->mtu_write;
break;
#endif
case HFP_CODEC_CVSD:
default:
buffer = bt_out.data;
Expand All @@ -1301,6 +1346,11 @@ void *io_thread_sco(void *arg) {
}

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
ffb_rewind(&msbc.enc_data, len);
break;
#endif
case HFP_CODEC_CVSD:
default:
ffb_rewind(&bt_out, len);
Expand All @@ -1315,6 +1365,12 @@ void *io_thread_sco(void *arg) {
ssize_t samples;

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
buffer = (int16_t *)msbc.enc_pcm.tail;
samples = ffb_len_in(&msbc.enc_pcm) / sizeof(int16_t);
break;
#endif
case HFP_CODEC_CVSD:
default:
buffer = (int16_t *)bt_out.tail;
Expand All @@ -1332,6 +1388,11 @@ void *io_thread_sco(void *arg) {
snd_pcm_scale_s16le(buffer, samples, 1, 0, 0);

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
ffb_seek(&msbc.enc_pcm, samples * sizeof(int16_t));
break;
#endif
case HFP_CODEC_CVSD:
default:
ffb_seek(&bt_out, samples * sizeof(int16_t));
Expand All @@ -1351,6 +1412,12 @@ void *io_thread_sco(void *arg) {
ssize_t samples;

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
buffer = (int16_t *)msbc.dec_pcm.data;
samples = ffb_len_out(&msbc.dec_pcm) / sizeof(int16_t);
break;
#endif
case HFP_CODEC_CVSD:
default:
buffer = (int16_t *)bt_in.data;
Expand All @@ -1364,6 +1431,11 @@ void *io_thread_sco(void *arg) {
error("FIFO write error: %s", strerror(errno));

switch (t->codec) {
#if ENABLE_MSBC
case HFP_CODEC_MSBC:
ffb_rewind(&msbc.dec_pcm, samples * sizeof(int16_t));
break;
#endif
case HFP_CODEC_CVSD:
default:
ffb_rewind(&bt_in, samples * sizeof(int16_t));
Expand All @@ -1372,13 +1444,16 @@ void *io_thread_sco(void *arg) {
}

/* keep data transfer at a constant bit rate */
asrsync_sync(&asrs, 48 / 2);
asrsync_sync(&asrs, t->mtu_write / 2);
t->delay = asrs.ts_busy.tv_nsec / 100000;

}

fail:
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
#if ENABLE_MSBC
pthread_cleanup_pop(1);
#endif
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
Expand Down
Loading

0 comments on commit 317eea9

Please sign in to comment.