diff --git a/3rd-party/bluedroid/encoder/include/sbc_encoder.h b/3rd-party/bluedroid/encoder/include/sbc_encoder.h index 755c27ff9..19cc6ee68 100644 --- a/3rd-party/bluedroid/encoder/include/sbc_encoder.h +++ b/3rd-party/bluedroid/encoder/include/sbc_encoder.h @@ -161,7 +161,9 @@ typedef struct SBC_ENC_PARAMS_TAG SINT16 s16AllocationMethod; /* loudness or SNR*/ SINT16 s16BitPool; /* 16*numOfSb for mono & dual; 32*numOfSb for stereo & joint stereo */ - UINT16 u16BitRate; + /* BK4BTSTACK_CHANGE START */ + // UINT16 u16BitRate; + /* BK4BTSTACK_CHANGE END */ UINT8 u8NumPacketToEncode; /* number of sbc frame to encode. Default is 1 */ #if (SBC_JOINT_STE_INCLUDED == TRUE) SINT16 as16Join[SBC_MAX_NUM_OF_SUBBANDS]; /*1 if JS, 0 otherwise*/ diff --git a/3rd-party/bluedroid/encoder/srce/sbc_encoder.c b/3rd-party/bluedroid/encoder/srce/sbc_encoder.c index eb31e8877..63e7b36ff 100644 --- a/3rd-party/bluedroid/encoder/srce/sbc_encoder.c +++ b/3rd-party/bluedroid/encoder/srce/sbc_encoder.c @@ -325,14 +325,16 @@ void SBC_Encoder_Init(SBC_ENC_PARAMS *pstrEncParams) if ( (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) || (pstrEncParams->s16ChannelMode == SBC_STEREO) ) { - s16Bitpool = (SINT16)( (pstrEncParams->u16BitRate * - pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq) - -( (32 + (4 * pstrEncParams->s16NumOfSubBands * - pstrEncParams->s16NumOfChannels) - + ( (pstrEncParams->s16ChannelMode - 2) * - pstrEncParams->s16NumOfSubBands ) ) - / pstrEncParams->s16NumOfBlocks) ); - + /* BK4BTSTACK_CHANGE START */ + // s16Bitpool = (SINT16)( (pstrEncParams->u16BitRate * + // pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq) + // -( (32 + (4 * pstrEncParams->s16NumOfSubBands * + // pstrEncParams->s16NumOfChannels) + // + ( (pstrEncParams->s16ChannelMode - 2) * + // pstrEncParams->s16NumOfSubBands ) ) + // / pstrEncParams->s16NumOfBlocks) ); + s16Bitpool = pstrEncParams->s16BitPool; + /* BK4BTSTACK_CHANGE END */ s16FrameLen = 4 + (4*pstrEncParams->s16NumOfSubBands* pstrEncParams->s16NumOfChannels)/8 + ( ((pstrEncParams->s16ChannelMode - 2) * @@ -343,8 +345,10 @@ void SBC_Encoder_Init(SBC_ENC_PARAMS *pstrEncParams) / (pstrEncParams->s16NumOfSubBands * pstrEncParams->s16NumOfBlocks * 1000); - if (s16BitRate > pstrEncParams->u16BitRate) - s16Bitpool--; + /* BK4BTSTACK_CHANGE START */ + // if (s16BitRate > pstrEncParams->u16BitRate) + // s16Bitpool--; + /* BK4BTSTACK_CHANGE END */ if(pstrEncParams->s16NumOfSubBands == 8) pstrEncParams->s16BitPool = (s16Bitpool > 255) ? 255 : s16Bitpool; @@ -352,17 +356,21 @@ void SBC_Encoder_Init(SBC_ENC_PARAMS *pstrEncParams) pstrEncParams->s16BitPool = (s16Bitpool > 128) ? 128 : s16Bitpool; } else - { - s16Bitpool = (SINT16)( ((pstrEncParams->s16NumOfSubBands * - pstrEncParams->u16BitRate * 1000) - / (s16SamplingFreq * pstrEncParams->s16NumOfChannels)) - -( ( (32 / pstrEncParams->s16NumOfChannels) + - (4 * pstrEncParams->s16NumOfSubBands) ) - / pstrEncParams->s16NumOfBlocks ) ); - - pstrEncParams->s16BitPool = (s16Bitpool > - (16 * pstrEncParams->s16NumOfSubBands)) - ? (16*pstrEncParams->s16NumOfSubBands) : s16Bitpool; + { + if (!pstrEncParams->mSBCEnabled){ + /* BK4BTSTACK_CHANGE START */ + // s16Bitpool = (SINT16)( ((pstrEncParams->s16NumOfSubBands * + // pstrEncParams->u16BitRate * 1000) + // / (s16SamplingFreq * pstrEncParams->s16NumOfChannels)) + // -( ( (32 / pstrEncParams->s16NumOfChannels) + + // (4 * pstrEncParams->s16NumOfSubBands) ) + // / pstrEncParams->s16NumOfBlocks ) ); + s16Bitpool = pstrEncParams->s16BitPool; + /* BK4BTSTACK_CHANGE END */ + pstrEncParams->s16BitPool = (s16Bitpool > + (16 * pstrEncParams->s16NumOfSubBands)) + ? (16*pstrEncParams->s16NumOfSubBands) : s16Bitpool; + } } if (pstrEncParams->s16BitPool < 0) diff --git a/example/Makefile.inc b/example/Makefile.inc index c29fed8f9..efadc7f2e 100644 --- a/example/Makefile.inc +++ b/example/Makefile.inc @@ -76,6 +76,9 @@ SBC_DECODER += \ ${BTSTACK_ROOT}/src/classic/sbc_plc.c \ ${BTSTACK_ROOT}/src/classic/sbc_decoder_bludroid.c \ +SBC_ENCODER += \ + ${BTSTACK_ROOT}/src/classic/sbc_encoder_bludroid.c \ + EXAMPLES = \ ancs_client_demo \ gap_dedicated_bonding \ @@ -204,7 +207,7 @@ hsp_ag_demo: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} ${SBC_DECODER_OBJ} sco_demo hfp_ag_demo: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} ${SBC_DECODER_OBJ} sco_demo_util.o hfp.o hfp_gsm_model.o hfp_ag.o hfp_ag_demo.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ -hfp_hf_demo: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} ${SBC_DECODER_OBJ} sco_demo_util.o hfp.o hfp_hf.o hfp_hf_demo.c +hfp_hf_demo: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} sco_demo_util.o hfp.o hfp_hf.o hfp_hf_demo.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ clean: diff --git a/src/classic/btstack_sbc.h b/src/classic/btstack_sbc.h new file mode 100644 index 000000000..0260dfc4d --- /dev/null +++ b/src/classic/btstack_sbc.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/* + * btstack_sbc.h + * + */ + +#ifndef __BTSTACK_SBC_H +#define __BTSTACK_SBC_H + +#include + +typedef enum{ + SBC_MODE_STANDARD, + SBC_MODE_mSBC +} sbc_mode_t; + +#if defined __cplusplus +} +#endif + +#endif // __BTSTACK_SBC_H \ No newline at end of file diff --git a/src/classic/btstack_sbc_encoder.h b/src/classic/btstack_sbc_encoder.h new file mode 100644 index 000000000..a21db24f1 --- /dev/null +++ b/src/classic/btstack_sbc_encoder.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/* + * btstack_sbc_encoder.h + * + */ + +#ifndef __BTSTACK_SBC_ENCODER_H +#define __BTSTACK_SBC_ENCODER_H + +#include +#include "btstack_sbc.h" + +#if defined __cplusplus +extern "C" { +#endif + +typedef struct { + // private + void * encoder_state; + sbc_mode_t mode; +} btstack_sbc_encoder_state_t; + +void btstack_sbc_encoder_init(btstack_sbc_encoder_state_t * state, sbc_mode_t mode, + int blocks, int subbands, int allmethod, int sample_rate, int bitpool); + +void btstack_sbc_encoder_process_data(int16_t * input_buffer); + + +uint8_t * btstack_sbc_encoder_sbc_buffer(void); +uint16_t btstack_sbc_encoder_sbc_buffer_length(void); + +int btstack_sbc_encoder_num_subband_samples(void); +void btstack_sbc_encoder_dump_context(void); + +#if defined __cplusplus +} +#endif + +#endif // __BTSTACK_SBC_ENCODER_H \ No newline at end of file diff --git a/src/classic/sbc_encoder_bludroid.c b/src/classic/sbc_encoder_bludroid.c new file mode 100644 index 000000000..4ca8e9342 --- /dev/null +++ b/src/classic/sbc_encoder_bludroid.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +// ***************************************************************************** +// +// SBC encoder based on Bludroid library +// +// ***************************************************************************** + +#include "btstack_config.h" + +#include +#include +#include +#include +#include +#include + +#include "btstack_sbc_encoder.h" +#include "sbc_encoder.h" +#include "btstack.h" + +#define SBC_MAX_CHANNELS 2 + +#define mSBC_SYNCWORD 0xad +#define SBC_SYNCWORD 0x9c + +// #define LOG_FRAME_STATUS + +typedef struct { + SBC_ENC_PARAMS context; + int num_data_bytes; + uint8_t sbc_packet[1000]; +} bludroid_encoder_state_t; + + +static btstack_sbc_encoder_state_t * sbc_state_singelton = NULL; +static bludroid_encoder_state_t bd_state; + +void btstack_sbc_encoder_dump_context(void){ + SBC_ENC_PARAMS * context = &((bludroid_encoder_state_t *)sbc_state_singelton->encoder_state)->context; + + printf("Blocks %d\n", context->s16NumOfBlocks); + printf("SubBands %d\n", context->s16NumOfSubBands); + printf("Allocation Method %d\n", context->s16AllocationMethod); + printf("BitPool %d\n", context->s16BitPool); + printf("Channel Mode %d\n", context->s16ChannelMode); + + printf("Sample Rate "); + switch (context->s16SamplingFreq){ + case 0: printf("16000\n"); break; + case 1: printf("32000\n"); break; + case 2: printf("44100\n"); break; + case 3: printf("48000\n"); break; + default: printf("not defined\n"); break; + } + printf("mSBC Enabled %d\n", context->mSBCEnabled); + printf("\n"); +} + + +int btstack_sbc_encoder_num_subband_samples(void){ + SBC_ENC_PARAMS * context = &((bludroid_encoder_state_t *)sbc_state_singelton->encoder_state)->context; + return context->s16NumOfSubBands * context->s16NumOfBlocks * context->s16NumOfChannels; +} + +uint8_t * btstack_sbc_encoder_sbc_buffer(void){ + SBC_ENC_PARAMS * context = &((bludroid_encoder_state_t *)sbc_state_singelton->encoder_state)->context; + return context->pu8Packet; +} + + +uint16_t btstack_sbc_encoder_sbc_buffer_length(void){ + SBC_ENC_PARAMS * context = &((bludroid_encoder_state_t *)sbc_state_singelton->encoder_state)->context; + return context->u16PacketLength; +} + + +void btstack_sbc_encoder_init(btstack_sbc_encoder_state_t * state, sbc_mode_t mode, + int blocks, int subbands, int allmethod, int sample_rate, int bitpool){ + + if (sbc_state_singelton && sbc_state_singelton != state ){ + log_error("SBC encoder: different sbc decoder state is allready registered"); + } + + sbc_state_singelton = state; + sbc_state_singelton->mode = mode; + + switch (sbc_state_singelton->mode){ + case SBC_MODE_STANDARD: + bd_state.context.s16NumOfBlocks = blocks; + bd_state.context.s16NumOfSubBands = subbands; + bd_state.context.s16AllocationMethod = allmethod; + bd_state.context.s16BitPool = 31; + bd_state.context.mSBCEnabled = 0; + + switch(sample_rate){ + case 16000: bd_state.context.s16SamplingFreq = SBC_sf16000; break; + case 32000: bd_state.context.s16SamplingFreq = SBC_sf32000; break; + case 44100: bd_state.context.s16SamplingFreq = SBC_sf44100; break; + case 48000: bd_state.context.s16SamplingFreq = SBC_sf48000; break; + default: bd_state.context.s16SamplingFreq = 0; break; + } + break; + case SBC_MODE_mSBC: + bd_state.context.s16NumOfBlocks = 15; + bd_state.context.s16NumOfSubBands = 8; + bd_state.context.s16AllocationMethod = SBC_LOUDNESS; + bd_state.context.s16BitPool = 26; + bd_state.context.s16ChannelMode = SBC_MONO; + bd_state.context.s16NumOfChannels = 1; + bd_state.context.mSBCEnabled = 1; + bd_state.context.s16SamplingFreq = SBC_sf16000; + break; + } + bd_state.context.pu8Packet = bd_state.sbc_packet; + + sbc_state_singelton->encoder_state = &bd_state; + SBC_ENC_PARAMS * context = &((bludroid_encoder_state_t *)sbc_state_singelton->encoder_state)->context; + SBC_Encoder_Init(context); +} + + +void btstack_sbc_encoder_process_data(int16_t * input_buffer){ + if (!sbc_state_singelton){ + log_error("SBC encoder: sbc state is NULL, call btstack_sbc_encoder_init to initialize it"); + } + SBC_ENC_PARAMS * context = &((bludroid_encoder_state_t *)sbc_state_singelton->encoder_state)->context; + context->ps16PcmBuffer = input_buffer; + if (context->mSBCEnabled){ + context->pu8Packet[0] = 0xad; + } + SBC_Encoder(context); +} diff --git a/test/sbc/Makefile b/test/sbc/Makefile index 12c914321..6e28a95a7 100644 --- a/test/sbc/Makefile +++ b/test/sbc/Makefile @@ -11,6 +11,9 @@ SBC_DECODER += \ ${BTSTACK_ROOT}/src/classic/sbc_plc.c \ ${BTSTACK_ROOT}/src/classic/sbc_decoder_bludroid.c \ +SBC_ENCODER += \ + ${BTSTACK_ROOT}/src/classic/sbc_encoder_bludroid.c \ + SBC_DECODER_OBJ = $(SBC_DECODER:.c=.o) SBC_ENCODER_OBJ = $(SBC_ENCODER:.c=.o) @@ -37,7 +40,7 @@ all: ${SBC_TESTS} sbc_decoder_test: ${SBC_DECODER_OBJ} ${COMMON_OBJ} sbc_decoder_test.o ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ -sbc_encoder_test: ${SBC_ENCODER_OBJ} sbc_encoder_test.o +sbc_encoder_test: ${SBC_ENCODER_OBJ} ${COMMON_OBJ} sbc_encoder_test.o ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ test: all diff --git a/test/sbc/sbc_encoder_test.c b/test/sbc/sbc_encoder_test.c index 0627aa80b..3e25d463d 100644 --- a/test/sbc/sbc_encoder_test.c +++ b/test/sbc/sbc_encoder_test.c @@ -47,40 +47,82 @@ #include #include #include -#include "sbc_encoder.h" -static SBC_ENC_PARAMS context; -static int16_t data[8*16*2]; +#include "btstack.h" +#include "btstack_sbc_encoder.h" + +static int16_t read_buffer[8*16*2]; static int num_data_bytes = 0; -static uint8_t sbc_packet[1000]; -static uint8_t buf[4]; - -static uint16_t little_endian_read_16(const uint8_t * buffer, int pos){ - return ((uint16_t) buffer[pos]) | (((uint16_t)buffer[(pos)+1]) << 8); +static int byte_rate = 0; +static int sampling_frequency = -1; +static int channel_mode = -1; + + +#define MSBC_FRAME_SIZE 57 + +static btstack_sbc_encoder_state_t state; +static uint8_t msbc_padding[] = {0,0,0}; + +static uint8_t msbc_buffer[2*(MSBC_FRAME_SIZE + sizeof(msbc_padding))]; +static int msbc_buffer_offset = 0; + +void hfp_msbc_init(void); +int hfp_msbc_can_encode_audio(void); +void hfp_msbc_encode_audio_frame(int16_t * pcm_samples); +void hfp_msbc_read_encoded_stream(uint8_t * buf, int size); + +void hfp_msbc_init(void){ + btstack_sbc_encoder_init(&state, SBC_MODE_mSBC, 16, 8, 0, 16000, 26); + msbc_buffer_offset = 0; } -static uint32_t little_endian_read_32(const uint8_t * buffer, int pos){ - return ((uint32_t) buffer[pos]) | (((uint32_t)buffer[(pos)+1]) << 8) | (((uint32_t)buffer[(pos)+2]) << 16) | (((uint32_t) buffer[(pos)+3]) << 24); +int hfp_msbc_can_encode_audio(void){ + return sizeof(msbc_buffer) - msbc_buffer_offset >= MSBC_FRAME_SIZE + sizeof(msbc_padding); +} + +void hfp_msbc_encode_audio_frame(int16_t * pcm_samples){ + if (!hfp_msbc_can_encode_audio()) return; + + btstack_sbc_encoder_process_data(pcm_samples); + + memcpy(msbc_buffer + msbc_buffer_offset, msbc_padding, sizeof(msbc_padding)); + msbc_buffer_offset += sizeof(msbc_padding); + + memcpy(msbc_buffer + msbc_buffer_offset, btstack_sbc_encoder_sbc_buffer(), MSBC_FRAME_SIZE); + msbc_buffer_offset += MSBC_FRAME_SIZE; + msbc_buffer_free_bytes = sizeof(msbc_buffer) - msbc_buffer_offset; +} + +void hfp_msbc_read_encoded_stream(uint8_t * buf, int size){ + int bytes_to_copy = size; + if (size > msbc_buffer_offset){ + bytes_to_copy = msbc_buffer_offset; + log_error("sbc frame storage is smaller then the output buffer"); + } + + memcpy(buf, msbc_buffer, bytes_to_copy); + memmv(msbc_buffer, msbc_buffer + bytes_to_copy, bytes_to_copy); + msbc_buffer_offset -= bytes_to_copy; } static uint16_t little_endian_fread_16(FILE * fd){ + uint8_t buf[2]; fread(&buf, 1, 2, fd); return little_endian_read_16(buf, 0); } static uint32_t little_endian_fread_32(FILE * fd){ + uint8_t buf[4]; fread(&buf, 1, 4, fd); return little_endian_read_32(buf, 0); } -static void read_wav_header(FILE * wav_fd, SBC_ENC_PARAMS *context){ +static void read_wav_header(FILE * wav_fd){ /* write RIFF header */ uint8_t buf[10]; - fread(&buf, 1, 4, wav_fd); - buf[4] = 0; - // printf("%s\n", buf ); // RIFF + fread(&buf, 1, 4, wav_fd); buf[4] = 0; // RIFF little_endian_fread_32(wav_fd); // 36 + bytes_per_sample * num_samples * frame_count @@ -98,28 +140,13 @@ static void read_wav_header(FILE * wav_fd, SBC_ENC_PARAMS *context){ little_endian_fread_16(wav_fd); // printf("fmt_length %d == 16, format %d == 1\n", fmt_length, fmt_format_tag); - - context->s16NumOfChannels = little_endian_fread_16(wav_fd); - if (context->s16NumOfChannels == 1){ - context->s16ChannelMode = SBC_MONO; - } else { - context->s16ChannelMode = SBC_STEREO; - } - - int sample_rate = little_endian_fread_32(wav_fd); - - if (sample_rate == 16000) - context->s16SamplingFreq = SBC_sf16000; - else if (sample_rate == 32000) - context->s16SamplingFreq = SBC_sf32000; - else if (sample_rate == 44100) - context->s16SamplingFreq = SBC_sf44100; - else - context->s16SamplingFreq = SBC_sf48000; - - int byte_rate = little_endian_fread_32(wav_fd); - context->u16BitRate = byte_rate * 8; - + // chanel mode: + channel_mode = little_endian_fread_16(wav_fd); + // sampling frequency: + sampling_frequency = little_endian_fread_32(wav_fd); + // byte rate: + byte_rate = little_endian_fread_32(wav_fd); + // int block_align = little_endian_fread_16(wav_fd); // int bits_per_sample = @@ -131,50 +158,16 @@ static void read_wav_header(FILE * wav_fd, SBC_ENC_PARAMS *context){ num_data_bytes = little_endian_fread_32(wav_fd); } -static void read_audio_frame(FILE * wav_fd, SBC_ENC_PARAMS * context){ - int num_samples = context->s16NumOfSubBands * context->s16NumOfBlocks * context->s16NumOfChannels; +static void read_audio_frame(FILE * wav_fd){ int i; - for (i=0; i < num_samples; i++){ - data[i] = little_endian_fread_16(wav_fd); + for (i=0; i < btstack_sbc_encoder_num_subband_samples(); i++){ + read_buffer[i] = little_endian_fread_16(wav_fd); } - context->ps16PcmBuffer = data; } -static int sbc_num_frames(SBC_ENC_PARAMS * context){ - int num_subband_samples = context->s16NumOfSubBands * context->s16NumOfBlocks * context->s16NumOfChannels; +static int sbc_num_frames(){ int num_all_samples = num_data_bytes / 2; - return num_all_samples / num_subband_samples; -} - -static void write_sbc_file(FILE * sbc_fd, SBC_ENC_PARAMS * context){ - // int i; - // for (i=0;iu16PacketLength;i++){ - // printf("%02x ", context->pu8Packet[i]); - // } - // printf("\n"); - printf("write %u bytes\n", context->u16PacketLength); - fwrite(context->pu8Packet, 1, context->u16PacketLength, sbc_fd); -} - -static void SBC_Encoder_Context_Init(SBC_ENC_PARAMS * context, FILE * fd, int blocks, int subbands, int allmethod, int bitpool, int chmode, int mSBCEnabled){ - - if (mSBCEnabled){ - blocks = 15; - subbands = 8; - allmethod = SBC_LOUDNESS; - bitpool = 26; - chmode = SBC_MONO; - } - - context->s16NumOfSubBands = subbands; - context->s16NumOfBlocks = blocks; - context->s16AllocationMethod = allmethod; - context->s16BitPool = bitpool; - context->pu8Packet = sbc_packet; - context->s16ChannelMode = chmode; - context->mSBCEnabled = mSBCEnabled; - - read_wav_header(fd, context); + return num_all_samples / btstack_sbc_encoder_num_subband_samples(); } int main (int argc, const char * argv[]){ @@ -197,22 +190,22 @@ int main (int argc, const char * argv[]){ return -1; } - SBC_Encoder_Context_Init(&context, wav_fd, SBC_BLOCK_3, SUB_BANDS_4, SBC_LOUDNESS, 31, SBC_MONO, 1); - SBC_Encoder_Init(&context); - - printf("channels %d, subbands %d, blocks %d\n", context.s16NumOfChannels, context.s16NumOfSubBands, context.s16NumOfBlocks); - int num_frames = sbc_num_frames(&context); + + read_wav_header(wav_fd); + btstack_sbc_encoder_init(&state, SBC_MODE_STANDARD, 16, 4, channel_mode, sampling_frequency, 31); + + int num_frames = sbc_num_frames(); int frame_count = 0; - printf("num frames %d\n", num_frames); + while (frame_count < num_frames){ - read_audio_frame(wav_fd, &context); - SBC_Encoder(&context); - if (context.mSBCEnabled){ - context.pu8Packet[0] = 0xad; - } - write_sbc_file(sbc_fd, &context); + read_audio_frame(wav_fd); + + btstack_sbc_encoder_process_data(read_buffer); + fwrite(btstack_sbc_encoder_sbc_buffer(), 1, btstack_sbc_encoder_sbc_buffer_length(), sbc_fd); frame_count++; } + btstack_sbc_encoder_dump_context(); + printf("Done, frame count %d\n", frame_count); fclose(wav_fd); fclose(sbc_fd);