From 42c434de1d933571aeab541f429c6b318b5dd50d Mon Sep 17 00:00:00 2001 From: =?utf8?q?K=C3=A9vin=20THIERRY?= Date: Wed, 12 Nov 2014 16:14:49 +0100 Subject: [PATCH] Imported Upstream version 1.2 --- ChangeLog | 4 ++ Makefile.am | 4 +- Makefile.in | 4 +- TODO | 51 +++++++------ config.h.in | 3 + configure | 33 ++++++--- configure.ac | 10 ++- sbc/sbc.c | 181 +++++++++++++++++++++++++++++++++++++++++++---- sbc/sbc.h | 5 ++ sbc/sbc.sym | 10 ++- sbc/sbc_tables.h | 4 -- 11 files changed, 254 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index b1b71f3..5c0a274 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +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. diff --git a/Makefile.am b/Makefile.am index 5954c32..8eb687c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,9 +6,9 @@ AM_MAKEFLAGS = --no-print-directory # 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 diff --git a/Makefile.in b/Makefile.in index 385a38d..6914933 100644 --- a/Makefile.in +++ b/Makefile.in @@ -328,9 +328,9 @@ AM_MAKEFLAGS = --no-print-directory # 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 \ diff --git a/TODO b/TODO index 09832a9..a0b53ce 100644 --- a/TODO +++ b/TODO @@ -14,36 +14,41 @@ Background 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 diff --git a/config.h.in b/config.h.in index 423fcf8..80600c0 100644 --- a/config.h.in +++ b/config.h.in @@ -55,6 +55,9 @@ /* 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 diff --git a/configure b/configure index c27cca1..8d3c600 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /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. @@ -587,8 +587,8 @@ MAKEFLAGS= # 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='' @@ -773,6 +773,7 @@ enable_libtool_lock enable_optimization enable_debug enable_pie +enable_high_precision enable_tools enable_tester ' @@ -1330,7 +1331,7 @@ if test "$ac_init_help" = "long"; then # 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]... @@ -1400,7 +1401,7 @@ fi 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 @@ -1422,6 +1423,7 @@ Optional Features: --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 @@ -1519,7 +1521,7 @@ fi 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. @@ -1797,7 +1799,7 @@ cat >config.log <<_ACEOF 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 $@ @@ -2613,7 +2615,7 @@ fi # Define the identity of the package. PACKAGE='sbc' - VERSION='1.1' + VERSION='1.2' cat >>confdefs.h <<_ACEOF @@ -11358,6 +11360,17 @@ if test "${enable_pie+set}" = set; then : 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} @@ -12117,7 +12130,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # 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 @@ -12183,7 +12196,7 @@ _ACEOF 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\\" diff --git a/configure.ac b/configure.ac index c052616..77c15e8 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ 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) @@ -44,6 +44,14 @@ AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie], 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") diff --git a/sbc/sbc.c b/sbc/sbc.c index c589217..534027e 100644 --- a/sbc/sbc.c +++ b/sbc/sbc.c @@ -25,14 +25,6 @@ * */ -/* 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 #endif @@ -57,6 +49,55 @@ #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 { @@ -954,7 +995,7 @@ static void sbc_encoder_init(bool msbc, struct sbc_encoder_state *state, } struct sbc_priv { - int init; + bool init; bool msbc; struct SBC_ALIGNED sbc_frame frame; struct SBC_ALIGNED sbc_decoder_state dec_state; @@ -1046,6 +1087,122 @@ SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags) 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); @@ -1067,7 +1224,7 @@ SBC_EXPORT ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len, 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; @@ -1155,7 +1312,7 @@ SBC_EXPORT ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len, 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; @@ -1339,7 +1496,7 @@ SBC_EXPORT int sbc_reinit(sbc_t *sbc, unsigned long flags) priv = sbc->priv; - if (priv->init == 1) + if (priv->init) memset(sbc->priv, 0, sizeof(struct sbc_priv)); sbc_set_defaults(sbc, flags); diff --git a/sbc/sbc.h b/sbc/sbc.h index 5f8a1fc..d6f123e 100644 --- a/sbc/sbc.h +++ b/sbc/sbc.h @@ -3,6 +3,7 @@ * 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 * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley @@ -84,6 +85,10 @@ typedef struct sbc_struct sbc_t; 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); diff --git a/sbc/sbc.sym b/sbc/sbc.sym index 3a47c12..0642a0b 100644 --- a/sbc/sbc.sym +++ b/sbc/sbc.sym @@ -1,7 +1,6 @@ SBC_1.0 { global: sbc_init; - sbc_init_msbc; sbc_reinit; sbc_finish; @@ -16,3 +15,12 @@ global: local: *; }; +SBC_1.1 { +global: + sbc_init_msbc; +} SBC_1.0; +SBC_1.2 { +global: + sbc_init_a2dp; + sbc_reinit_a2dp; +} SBC_1.1; diff --git a/sbc/sbc_tables.h b/sbc/sbc_tables.h index 25e24e6..24a8bff 100644 --- a/sbc/sbc_tables.h +++ b/sbc/sbc_tables.h @@ -136,10 +136,6 @@ static const int32_t synmatrix8[16][8] = { 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 */ -- 2.34.1