+ver 1.2:
+ Add support for setup from A2DP configuration data.
+ Add support for enabling high precision build.
+
ver 1.1:
Add support for mSBC encoding and decoding functionality.
# Interfaces added: CURRENT++ REVISION=0 AGE++
# Interfaces removed: CURRENT++ REVISION=0 AGE=0
-SBC_CURRENT = 2
+SBC_CURRENT = 3
SBC_REVISION = 0
-SBC_AGE = 1
+SBC_AGE = 2
sbc_headers = sbc/sbc.h
# Interfaces changed: CURRENT++ REVISION=0
# Interfaces added: CURRENT++ REVISION=0 AGE++
# Interfaces removed: CURRENT++ REVISION=0 AGE=0
-SBC_CURRENT = 2
+SBC_CURRENT = 3
SBC_REVISION = 0
-SBC_AGE = 1
+SBC_AGE = 2
sbc_headers = sbc/sbc.h
sbc_sources = sbc/sbc.c sbc/sbc_private.h sbc/sbc_math.h sbc/sbc_tables.h \
sbc/sbc_primitives.h sbc/sbc_primitives.c \
Higher complexity tasks should be refined into several lower complexity tasks
once the task is better understood.
-NEON instruction set
-====================
+Encoder optimizations
+=====================
-- The neon optimization code is split in two parts. Sample reordering and blocks
-encoding. There is a neon optimization for encoding SBC. But mSBC is not
-supported by this optimizer because the reordering has been specifically for
-mSBC.
+- Currently, only the decoder is optimized to take advantage of advanced
+ processor instruction sets. In use cases like HFP 1.6, optimizing the
+ encoder will bring a significant latency, power and performance advantage.
+ For example, the MMX encoder is 3 to 6 time faster than the SIMD encoder.
+
+ Priority: High
+ Complexity: C8
+
+- Use a log2 table for byte integer scale factors calculation (sum log2
+ results for high and low bytes) fill bitpool by 16 bits instead of one
+ at a time in bits allocation/bitpool generation port to the dsp
+
+ Priority: Medium
+ Complexity: C2
+
+- The neon optimization code is split in two parts. Sample reordering and
+ blocks encoding. There is a neon optimization for encoding SBC. But mSBC
+ is not supported by this optimizer because the reordering has been
+ specifically for mSBC.
Priority: Low
Complexity: C2
-SSE instruction set
-===================
+Decoder optimizations
+=====================
-- The decoder is optimized to take advantage of advanced processor instruction
-sets. Currently implemented are MMX, arm neon, arm v6 and iwmmxt. SSE3 is
-is available since almost 10 years now, on a large range of Intel processors.
-It should be interesting to implement it and to compare with MMX implementation
-on Intel processors.
+- The decoder is optimized to take advantage of advanced processor
+ instruction sets. Currently implemented are MMX, arm neon, arm v6
+ and iwmmxt. SSE3 is available since almost 10 years now, on a large
+ range of Intel processors. It should be interesting to implement it
+ and to compare with MMX implementation on Intel processors.
Priority: Medium
Complexity: C4
-Decoder improvements
-====================
-
-- Currently, only the decoder is optimized to take advantage of advanced
-processor instruction sets. In use cases like HFP 1.6, optimizing the encoder
-will bring a significant latency, power and performance advantage. For exemple,
-the MMX encoder is 3 to 6 time faster than the SIMD encoder.
-
- Priority: High
- Complexity: C8
/* Define to the version of this package. */
#undef PACKAGE_VERSION
+/* Define to 1 to enable high precision build of SBC encoder */
+#undef SBC_HIGH_PRECISION
+
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sbc 1.1.
+# Generated by GNU Autoconf 2.69 for sbc 1.2.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
# Identity of this package.
PACKAGE_NAME='sbc'
PACKAGE_TARNAME='sbc'
-PACKAGE_VERSION='1.1'
-PACKAGE_STRING='sbc 1.1'
+PACKAGE_VERSION='1.2'
+PACKAGE_STRING='sbc 1.2'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
enable_optimization
enable_debug
enable_pie
+enable_high_precision
enable_tools
enable_tester
'
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sbc 1.1 to adapt to many kinds of systems.
+\`configure' configures sbc 1.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sbc 1.1:";;
+ short | recursive ) echo "Configuration of sbc 1.2:";;
esac
cat <<\_ACEOF
--disable-optimization disable code optimization through compiler
--enable-debug enable compiling with debugging information
--enable-pie enable position independent executables flag
+ --enable-high-precision enable SBC high precision support
--disable-tools disable SBC tools
--disable-tester disable SBC tester
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sbc configure 1.1
+sbc configure 1.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sbc $as_me 1.1, which was
+It was created by sbc $as_me 1.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
# Define the identity of the package.
PACKAGE='sbc'
- VERSION='1.1'
+ VERSION='1.2'
cat >>confdefs.h <<_ACEOF
fi
+# Check whether --enable-high-precision was given.
+if test "${enable_high_precision+set}" = set; then :
+ enableval=$enable_high_precision; enable_high_precision=${enableval}
+fi
+
+if (test "${enable_high_precision}" = "yes"); then
+
+$as_echo "#define SBC_HIGH_PRECISION 1" >>confdefs.h
+
+fi
+
# Check whether --enable-tools was given.
if test "${enable_tools+set}" = set; then :
enableval=$enable_tools; enable_tools=${enableval}
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sbc $as_me 1.1, which was
+This file was extended by sbc $as_me 1.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-sbc config.status 1.1
+sbc config.status 1.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
AC_PREREQ(2.60)
-AC_INIT(sbc, 1.1)
+AC_INIT(sbc, 1.2)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)
fi
])
+AC_ARG_ENABLE(high-precision, AC_HELP_STRING([--enable-high-precision],
+ [enable SBC high precision support]),
+ [enable_high_precision=${enableval}])
+if (test "${enable_high_precision}" = "yes"); then
+ AC_DEFINE(SBC_HIGH_PRECISION, 1,
+ [Define to 1 to enable high precision build of SBC encoder])
+fi
+
AC_ARG_ENABLE(tools, AC_HELP_STRING([--disable-tools],
[disable SBC tools]), [enable_tools=${enableval}])
AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no")
*
*/
-/* todo items:
-
- use a log2 table for byte integer scale factors calculation (sum log2 results
- for high and low bytes) fill bitpool by 16 bits instead of one at a time in
- bits allocation/bitpool generation port to the dsp
-
-*/
-
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define MSBC_SYNCWORD 0xAD
#define MSBC_BLOCKS 15
+#define A2DP_SAMPLING_FREQ_16000 (1 << 3)
+#define A2DP_SAMPLING_FREQ_32000 (1 << 2)
+#define A2DP_SAMPLING_FREQ_44100 (1 << 1)
+#define A2DP_SAMPLING_FREQ_48000 (1 << 0)
+
+#define A2DP_CHANNEL_MODE_MONO (1 << 3)
+#define A2DP_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define A2DP_CHANNEL_MODE_STEREO (1 << 1)
+#define A2DP_CHANNEL_MODE_JOINT_STEREO (1 << 0)
+
+#define A2DP_BLOCK_LENGTH_4 (1 << 3)
+#define A2DP_BLOCK_LENGTH_8 (1 << 2)
+#define A2DP_BLOCK_LENGTH_12 (1 << 1)
+#define A2DP_BLOCK_LENGTH_16 (1 << 0)
+
+#define A2DP_SUBBANDS_4 (1 << 1)
+#define A2DP_SUBBANDS_8 (1 << 0)
+
+#define A2DP_ALLOCATION_SNR (1 << 1)
+#define A2DP_ALLOCATION_LOUDNESS (1 << 0)
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct a2dp_sbc {
+ uint8_t channel_mode:4;
+ uint8_t frequency:4;
+ uint8_t allocation_method:2;
+ uint8_t subbands:2;
+ uint8_t block_length:4;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct a2dp_sbc {
+ uint8_t frequency:4;
+ uint8_t channel_mode:4;
+ uint8_t block_length:4;
+ uint8_t subbands:2;
+ uint8_t allocation_method:2;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
/* This structure contains an unpacked SBC frame.
Yes, there is probably quite some unused space herein */
struct sbc_frame {
}
struct sbc_priv {
- int init;
+ bool init;
bool msbc;
struct SBC_ALIGNED sbc_frame frame;
struct SBC_ALIGNED sbc_decoder_state dec_state;
return 0;
}
+static int sbc_set_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len)
+{
+ const struct a2dp_sbc *a2dp;
+
+ if (conf_len != sizeof(*a2dp))
+ return -EINVAL;
+
+ a2dp = conf;
+
+ switch (a2dp->frequency) {
+ case A2DP_SAMPLING_FREQ_16000:
+ sbc->frequency = SBC_FREQ_16000;
+ break;
+ case A2DP_SAMPLING_FREQ_32000:
+ sbc->frequency = SBC_FREQ_32000;
+ break;
+ case A2DP_SAMPLING_FREQ_44100:
+ sbc->frequency = SBC_FREQ_44100;
+ break;
+ case A2DP_SAMPLING_FREQ_48000:
+ sbc->frequency = SBC_FREQ_48000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (a2dp->channel_mode) {
+ case A2DP_CHANNEL_MODE_MONO:
+ sbc->mode = SBC_MODE_MONO;
+ break;
+ case A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+ sbc->mode = SBC_MODE_DUAL_CHANNEL;
+ break;
+ case A2DP_CHANNEL_MODE_STEREO:
+ sbc->mode = SBC_MODE_STEREO;
+ break;
+ case A2DP_CHANNEL_MODE_JOINT_STEREO:
+ sbc->mode = SBC_MODE_JOINT_STEREO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (a2dp->allocation_method) {
+ case A2DP_ALLOCATION_SNR:
+ sbc->allocation = SBC_AM_SNR;
+ break;
+ case A2DP_ALLOCATION_LOUDNESS:
+ sbc->allocation = SBC_AM_LOUDNESS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (a2dp->subbands) {
+ case A2DP_SUBBANDS_4:
+ sbc->subbands = SBC_SB_4;
+ break;
+ case A2DP_SUBBANDS_8:
+ sbc->subbands = SBC_SB_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (a2dp->block_length) {
+ case A2DP_BLOCK_LENGTH_4:
+ sbc->blocks = SBC_BLK_4;
+ break;
+ case A2DP_BLOCK_LENGTH_8:
+ sbc->blocks = SBC_BLK_8;
+ break;
+ case A2DP_BLOCK_LENGTH_12:
+ sbc->blocks = SBC_BLK_12;
+ break;
+ case A2DP_BLOCK_LENGTH_16:
+ sbc->blocks = SBC_BLK_16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len)
+{
+ int err;
+
+ err = sbc_init(sbc, flags);
+ if (err < 0)
+ return err;
+
+ err = sbc_set_a2dp(sbc, flags, conf, conf_len);
+ if (err < 0) {
+ sbc_finish(sbc);
+ return err;
+ }
+
+ return 0;
+}
+
+int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len)
+{
+ int err;
+
+ err = sbc_reinit(sbc, flags);
+ if (err < 0)
+ return err;
+
+ return sbc_set_a2dp(sbc, flags, conf, conf_len);
+}
+
SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
{
return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
if (!priv->init) {
sbc_decoder_init(&priv->dec_state, &priv->frame);
- priv->init = 1;
+ priv->init = true;
sbc->frequency = priv->frame.frequency;
sbc->mode = priv->frame.mode;
priv->frame.length = sbc_get_frame_length(sbc);
sbc_encoder_init(priv->msbc, &priv->enc_state, &priv->frame);
- priv->init = 1;
+ priv->init = true;
} else if (priv->frame.bitpool != sbc->bitpool) {
priv->frame.length = sbc_get_frame_length(sbc);
priv->frame.bitpool = sbc->bitpool;
priv = sbc->priv;
- if (priv->init == 1)
+ if (priv->init)
memset(sbc->priv, 0, sizeof(struct sbc_priv));
sbc_set_defaults(sbc, flags);
* Bluetooth low-complexity, subband codec (SBC) library
*
* Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2012-2014 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
* Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
int sbc_init(sbc_t *sbc, unsigned long flags);
int sbc_reinit(sbc_t *sbc, unsigned long flags);
int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
+int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len);
+int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len);
ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
SBC_1.0 {
global:
sbc_init;
- sbc_init_msbc;
sbc_reinit;
sbc_finish;
local:
*;
};
+SBC_1.1 {
+global:
+ sbc_init_msbc;
+} SBC_1.0;
+SBC_1.2 {
+global:
+ sbc_init_a2dp;
+ sbc_reinit_a2dp;
+} SBC_1.1;
SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }
};
-/* Uncomment the following line to enable high precision build of SBC encoder */
-
-/* #define SBC_HIGH_PRECISION */
-
#ifdef SBC_HIGH_PRECISION
#define FIXED_A int64_t /* data type for fixed point accumulator */
#define FIXED_T int32_t /* data type for fixed point constants */