pinebuds/apps/audioplayers/a2dp_decoder/a2dp_decoder_sbc.cpp

970 lines
38 KiB
C++

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
// Standard C Included Files
#include "cmsis.h"
#include "plat_types.h"
#include <string.h>
#include "heap_api.h"
#include "hal_location.h"
#include "codec_sbc.h"
#include "a2dp_decoder_internal.h"
#include "hal_timer.h"
#include "cmsis_os.h"
#ifndef SBC_MTU_LIMITER
#define SBC_MTU_LIMITER (250) /*must <= 332*/
#endif
#define SBC_PCMLEN_DEFAULT (512)
#define SBC_LIST_SAMPLES (128)
static A2DP_AUDIO_CONTEXT_T *a2dp_audio_context_p = NULL;
extern A2DP_AUDIO_DECODER_T a2dp_audio_sbc_decoder_config;
typedef struct {
btif_sbc_decoder_t *sbc_decoder;
btif_sbc_pcm_data_t *pcm_data;
} a2dp_audio_sbc_decoder_t;
typedef struct {
uint16_t sequenceNumber;
uint32_t timestamp;
uint16_t curSubSequenceNumber;
uint16_t totalSubSequenceNumber;
uint8_t *sbc_buffer;
uint32_t sbc_buffer_len;
} a2dp_audio_sbc_decoder_frame_t;
static a2dp_audio_sbc_decoder_t a2dp_audio_sbc_decoder;
static btif_sbc_decoder_t *a2dp_audio_sbc_decoder_preparse = NULL;
static A2DP_AUDIO_DECODER_LASTFRAME_INFO_T a2dp_audio_sbc_lastframe_info;
static uint16_t sbc_mtu_limiter = SBC_MTU_LIMITER;
static btif_media_header_t sbc_decoder_last_valid_frame = {0,};
static bool sbc_decoder_last_valid_frame_ready = false;
static bool sbc_chnl_mode_mono = false;
static int a2dp_audio_sbc_header_parser_init(void);
static void *a2dp_audio_sbc_subframe_malloc(uint32_t sbc_len)
{
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame_p = NULL;
uint8_t *sbc_buffer = NULL;
sbc_buffer = (uint8_t *)a2dp_audio_heap_malloc(sbc_len);
sbc_decoder_frame_p = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_heap_malloc(sizeof(a2dp_audio_sbc_decoder_frame_t));
sbc_decoder_frame_p->sbc_buffer = sbc_buffer;
sbc_decoder_frame_p->sbc_buffer_len = sbc_len;
return (void *)sbc_decoder_frame_p;
}
static void a2dp_audio_sbc_subframe_free(void *packet)
{
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame_p = (a2dp_audio_sbc_decoder_frame_t *)packet;
a2dp_audio_heap_free(sbc_decoder_frame_p->sbc_buffer);
a2dp_audio_heap_free(sbc_decoder_frame_p);
}
static void sbc_codec_init(void)
{
btif_sbc_init_decoder(a2dp_audio_sbc_decoder.sbc_decoder);
a2dp_audio_sbc_decoder.sbc_decoder->maxPcmLen = SBC_PCMLEN_DEFAULT;
a2dp_audio_sbc_decoder.pcm_data->data = NULL;
a2dp_audio_sbc_decoder.pcm_data->dataLen = 0;
}
#ifdef A2DP_CP_ACCEL
struct A2DP_CP_SBC_IN_FRM_INFO_T {
uint16_t sequenceNumber;
uint32_t timestamp;
uint16_t curSubSequenceNumber;
uint16_t totalSubSequenceNumber;
};
struct A2DP_CP_SBC_OUT_FRM_INFO_T {
struct A2DP_CP_SBC_IN_FRM_INFO_T in_info;
uint16_t frame_samples;
uint16_t decoded_frames;
uint16_t frame_idx;
uint16_t pcm_len;
};
static bool cp_codec_reset;
extern "C" uint32_t get_in_cp_frame_cnt(void);
extern "C" unsigned int set_cp_reset_flag(uint8_t evt);
int a2dp_cp_sbc_cp_decode(void);
extern uint32_t app_bt_stream_get_dma_buffer_samples(void);
static int TEXT_SBC_LOC a2dp_cp_sbc_after_cache_underflow(void)
{
#ifdef A2DP_CP_ACCEL
cp_codec_reset = true;
#endif
return 0;
}
static int a2dp_cp_sbc_mcu_decode(uint8_t *buffer, uint32_t buffer_bytes)
{
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
list_node_t *node = NULL;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
int ret, dec_ret;
struct A2DP_CP_SBC_IN_FRM_INFO_T in_info;
struct A2DP_CP_SBC_OUT_FRM_INFO_T *p_out_info = NULL;
uint8_t *out = NULL;
uint32_t out_len;
uint32_t out_frame_len;
uint32_t cp_buffer_frames_max = 0;
uint32_t check_sum = 0;
cp_buffer_frames_max = app_bt_stream_get_dma_buffer_samples()/2;
if (cp_buffer_frames_max %(a2dp_audio_sbc_lastframe_info.frame_samples) ){
cp_buffer_frames_max = cp_buffer_frames_max /(a2dp_audio_sbc_lastframe_info.frame_samples) +1 ;
}else{
cp_buffer_frames_max = cp_buffer_frames_max /(a2dp_audio_sbc_lastframe_info.frame_samples) ;
}
out_frame_len = sizeof(*p_out_info) + buffer_bytes;
ret = a2dp_cp_decoder_init(out_frame_len, cp_buffer_frames_max * 2);
if (ret){
TRACE_A2DP_DECODER_W("[SBC][INIT] cp_decoder_init() failed: ret=%d", ret);
set_cp_reset_flag(true);
return A2DP_DECODER_DECODE_ERROR;
}
while ((node = a2dp_audio_list_begin(list)) != NULL) {
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
in_info.sequenceNumber = sbc_decoder_frame->sequenceNumber;
in_info.timestamp = sbc_decoder_frame->timestamp;
in_info.curSubSequenceNumber = sbc_decoder_frame->curSubSequenceNumber;
in_info.totalSubSequenceNumber = sbc_decoder_frame->totalSubSequenceNumber;
ret = a2dp_cp_put_in_frame(&in_info, sizeof(in_info), sbc_decoder_frame->sbc_buffer, sbc_decoder_frame->sbc_buffer_len);
if (ret) {
TRACE_A2DP_DECODER_D("[MCU][SBC] piff !!!!!!ret: %d ", ret);
break;
}
check_sum = a2dp_audio_decoder_internal_check_sum_generate(sbc_decoder_frame->sbc_buffer, sbc_decoder_frame->sbc_buffer_len);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
ret = a2dp_cp_get_full_out_frame((void **)&out, &out_len);
if (ret) {
if (!get_in_cp_frame_cnt()){
TRACE_A2DP_DECODER_I("[MCU][SBC] cp cache underflow list:%d in_cp:%d",a2dp_audio_list_length(list), get_in_cp_frame_cnt());
return A2DP_DECODER_CACHE_UNDERFLOW_ERROR;
}
if (!a2dp_audio_sysfreq_boost_running()){
a2dp_audio_sysfreq_boost_start(1);
}
osDelay(8);
ret = a2dp_cp_get_full_out_frame((void **)&out, &out_len);
if (ret) {
TRACE_A2DP_DECODER_I("[MCU][SBC] cp cache underflow list:%d in_cp:%d",a2dp_audio_list_length(list), get_in_cp_frame_cnt());
a2dp_cp_sbc_after_cache_underflow();
return A2DP_DECODER_CACHE_UNDERFLOW_ERROR;
}
}
if (out_len == 0) {
TRACE_A2DP_DECODER_I("[MCU][SBC] olz!!!%d ",__LINE__);
memset(buffer, 0, buffer_bytes);
a2dp_cp_consume_full_out_frame();
return A2DP_DECODER_NO_ERROR;
}
if(out_len != out_frame_len){
TRACE_A2DP_DECODER_I("[MCU][SBC] Bad out len %u (should be %u)", out_len, out_frame_len);
set_cp_reset_flag(true);
return A2DP_DECODER_DECODE_ERROR;
}
p_out_info = (struct A2DP_CP_SBC_OUT_FRM_INFO_T *)out;
if (p_out_info->pcm_len) {
a2dp_audio_sbc_lastframe_info.sequenceNumber = p_out_info->in_info.sequenceNumber;
a2dp_audio_sbc_lastframe_info.timestamp = p_out_info->in_info.timestamp;
a2dp_audio_sbc_lastframe_info.curSubSequenceNumber = p_out_info->in_info.curSubSequenceNumber;
a2dp_audio_sbc_lastframe_info.totalSubSequenceNumber = p_out_info->in_info.totalSubSequenceNumber;
a2dp_audio_sbc_lastframe_info.frame_samples = p_out_info->frame_samples;
a2dp_audio_sbc_lastframe_info.decoded_frames += p_out_info->decoded_frames;
a2dp_audio_sbc_lastframe_info.undecode_frames =
a2dp_audio_list_length(list) + a2dp_cp_get_in_frame_cnt_by_index(p_out_info->frame_idx) - 1;
a2dp_audio_sbc_lastframe_info.check_sum= check_sum?check_sum:a2dp_audio_sbc_lastframe_info.check_sum;
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
}
if (p_out_info->pcm_len == buffer_bytes) {
memcpy(buffer, p_out_info + 1, p_out_info->pcm_len);
dec_ret = A2DP_DECODER_NO_ERROR;
} else {
TRACE_A2DP_DECODER_I("[MCU][SBC] line:%d cp decoder error !!!!!!", __LINE__);
set_cp_reset_flag(true);
return A2DP_DECODER_DECODE_ERROR;
}
ret = a2dp_cp_consume_full_out_frame();
if(ret){
TRACE_A2DP_DECODER_I("[MCU][SBC] cp_consume_full_out_frame failed: ret=%d", ret);
set_cp_reset_flag(true);
return A2DP_DECODER_DECODE_ERROR;
}
return dec_ret;
}
#ifdef __CP_EXCEPTION_TEST__
static bool _cp_assert = false;
int cp_assert_sbc(void)
{
_cp_assert = true;
return 0;
}
#endif
TEXT_SBC_LOC
int a2dp_cp_sbc_cp_decode(void)
{
int ret = 0;
enum CP_EMPTY_OUT_FRM_T out_frm_st;
uint8_t *out = NULL;
uint32_t out_len = 0;
uint8_t *dec_start = NULL;
uint32_t dec_len = 0;
struct A2DP_CP_SBC_IN_FRM_INFO_T *p_in_info = NULL;
struct A2DP_CP_SBC_OUT_FRM_INFO_T *p_out_info = NULL;
uint8_t *in_buf = NULL;
uint32_t in_len = 0;
uint16_t bytes_parsed = 0;
float sbc_subbands_gain[8]={1,1,1,1,1,1,1,1};
btif_sbc_decoder_t *sbc_decoder = NULL;
btif_sbc_pcm_data_t *pcm_data = NULL;
bt_status_t decoder_err = 0;
int error = 0;
if (cp_codec_reset) {
cp_codec_reset = false;
sbc_codec_init();
}
#ifdef __CP_EXCEPTION_TEST__
if (_cp_assert){
_cp_assert = false;
*(int*) 0 = 1;
//ASSERT_A2DP_DECODER(0, "ASSERT_A2DP_DECODER %s %d", __func__, __LINE__);
}
#endif
sbc_decoder = a2dp_audio_sbc_decoder.sbc_decoder;
pcm_data = a2dp_audio_sbc_decoder.pcm_data;
out_frm_st = a2dp_cp_get_emtpy_out_frame((void **)&out, &out_len);
if (out_frm_st != CP_EMPTY_OUT_FRM_OK && out_frm_st != CP_EMPTY_OUT_FRM_WORKING) {
return 1;
}
ASSERT_A2DP_DECODER(out_len > sizeof(*p_out_info), "[CP][SBC] Bad out_len %u (should > %u)", out_len, sizeof(*p_out_info));
p_out_info = (struct A2DP_CP_SBC_OUT_FRM_INFO_T *)out;
if (out_frm_st == CP_EMPTY_OUT_FRM_OK) {
p_out_info->pcm_len = 0;
p_out_info->decoded_frames = 0;
}
ASSERT_A2DP_DECODER(out_len > sizeof(*p_out_info) + p_out_info->pcm_len, "[CP][SBC] Bad out_len %u (should > %u + %u)", out_len, sizeof(*p_out_info), p_out_info->pcm_len);
dec_start = (uint8_t *)(p_out_info + 1) + p_out_info->pcm_len;
dec_len = out_len - (dec_start - (uint8_t *)out);
pcm_data->data = dec_start;
pcm_data->dataLen = 0;
error = 0;
while (pcm_data->dataLen < dec_len && error == 0) {
ret = a2dp_cp_get_in_frame((void **)&in_buf, &in_len);
if (ret) {
p_out_info->pcm_len += pcm_data->dataLen;
return 4;
}
ASSERT_A2DP_DECODER(in_len > sizeof(*p_in_info), "%s: Bad in_len %u (should > %u)", __func__, in_len, sizeof(*p_in_info));
p_in_info = (struct A2DP_CP_SBC_IN_FRM_INFO_T *)in_buf;
in_buf += sizeof(*p_in_info);
in_len -= sizeof(*p_in_info);
decoder_err = btif_sbc_decode_frames(sbc_decoder, in_buf, in_len,
&bytes_parsed,
pcm_data,
dec_len,
sbc_subbands_gain);
switch (decoder_err)
{
case BT_STS_SUCCESS:
case BT_STS_CONTINUE:
break;
case BT_STS_NO_RESOURCES:
error = 1;
ASSERT_A2DP_DECODER(0, "sbc_decode BT_STS_NO_RESOURCES pcm has no more buffer, i think can't reach here");
break;
case BT_STS_FAILED:
default:
error = 1;
sbc_codec_init();
break;
}
memcpy(&p_out_info->in_info, p_in_info, sizeof(*p_in_info));
p_out_info->decoded_frames++;
p_out_info->frame_samples = sbc_decoder->maxPcmLen/4;
p_out_info->frame_idx = a2dp_cp_get_in_frame_index();
ret = a2dp_cp_consume_in_frame();
ASSERT_A2DP_DECODER(ret == 0, "%s: a2dp_cp_consume_in_frame() failed: ret=%d", __func__, ret);
}
p_out_info->pcm_len += pcm_data->dataLen;
if (error || out_len <= sizeof(*p_out_info) + p_out_info->pcm_len) {
ret = a2dp_cp_consume_emtpy_out_frame();
ASSERT_A2DP_DECODER(ret == 0, "%s: a2dp_cp_consume_emtpy_out_frame() failed: ret=%d", __func__, ret);
}
return error;
}
#endif
static int a2dp_audio_sbc_list_checker(void)
{
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
int cnt = 0;
do {
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_sbc_subframe_malloc(SBC_LIST_SAMPLES);
if (sbc_decoder_frame){
a2dp_audio_list_append(list, sbc_decoder_frame);
}
cnt++;
}while(sbc_decoder_frame && cnt < SBC_MTU_LIMITER);
do {
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}while(node);
TRACE_A2DP_DECODER_I("[SBC][INIT] cnt:%d list:%d", cnt, a2dp_audio_list_length(list));
return 0;
}
int a2dp_audio_sbc_init(A2DP_AUDIO_OUTPUT_CONFIG_T *config, void *context)
{
TRACE_A2DP_DECODER_I("[SBC][INIT]");
a2dp_audio_context_p = (A2DP_AUDIO_CONTEXT_T *)context;
a2dp_audio_sbc_header_parser_init();
memset(&a2dp_audio_sbc_lastframe_info, 0, sizeof(A2DP_AUDIO_DECODER_LASTFRAME_INFO_T));
a2dp_audio_sbc_lastframe_info.stream_info = *config;
a2dp_audio_sbc_lastframe_info.frame_samples= SBC_LIST_SAMPLES;
a2dp_audio_sbc_lastframe_info.list_samples = SBC_LIST_SAMPLES;
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
ASSERT_A2DP_DECODER(a2dp_audio_context_p->dest_packet_mut < SBC_MTU_LIMITER, "%s MTU OVERFLOW:%u/%u", __func__, a2dp_audio_context_p->dest_packet_mut, SBC_MTU_LIMITER);
a2dp_audio_sbc_decoder.sbc_decoder = (btif_sbc_decoder_t *)a2dp_audio_heap_malloc(sizeof(btif_sbc_decoder_t));
a2dp_audio_sbc_decoder.pcm_data = (btif_sbc_pcm_data_t *)a2dp_audio_heap_malloc(sizeof(btif_sbc_pcm_data_t));
a2dp_audio_sbc_decoder_preparse = (btif_sbc_decoder_t *)a2dp_audio_heap_malloc(sizeof(btif_sbc_decoder_t));
#ifdef A2DP_CP_ACCEL
int ret;
cp_codec_reset = true;
ret = a2dp_cp_init(a2dp_cp_sbc_cp_decode, CP_PROC_DELAY_2_FRAMES);
ASSERT_A2DP_DECODER(ret == 0, "%s: a2dp_cp_init() failed: ret=%d", __func__, ret);
#else
sbc_codec_init();
#endif
a2dp_audio_sbc_list_checker();
sbc_chnl_mode_mono = false;
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_deinit(void)
{
#ifdef A2DP_CP_ACCEL
a2dp_cp_deinit();
#endif
a2dp_audio_heap_free(a2dp_audio_sbc_decoder_preparse);
a2dp_audio_heap_free(a2dp_audio_sbc_decoder.sbc_decoder);
a2dp_audio_heap_free(a2dp_audio_sbc_decoder.pcm_data);
TRACE_A2DP_DECODER_I("[SBC][DEINIT]");
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_mcu_decode_frame(uint8_t *buffer, uint32_t buffer_bytes)
{
bt_status_t ret = BT_STS_SUCCESS;
uint16_t bytes_parsed = 0;
float sbc_subbands_gain[8]={1,1,1,1,1,1,1,1};
btif_sbc_decoder_t *sbc_decoder = NULL;
btif_sbc_pcm_data_t *pcm_data = NULL;
uint16_t frame_pcmbyte = 0;
uint16_t pcm_output_byte = 0;
bool cache_underflow = false;
sbc_decoder = a2dp_audio_sbc_decoder.sbc_decoder;
pcm_data = a2dp_audio_sbc_decoder.pcm_data;
frame_pcmbyte = sbc_decoder->maxPcmLen;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
list_node_t *node = NULL;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
pcm_data->data = buffer;
pcm_data->dataLen = 0;
TRACE_A2DP_DECODER_D("[MCU][SBC] size:%d", a2dp_audio_list_length(list));
for (pcm_output_byte = 0; pcm_output_byte<buffer_bytes; pcm_output_byte += frame_pcmbyte){
node = a2dp_audio_list_begin(list);
if (node){
uint32_t lock;
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
lock = int_lock();
ret = btif_sbc_decode_frames(sbc_decoder, sbc_decoder_frame->sbc_buffer, sbc_decoder_frame->sbc_buffer_len,
&bytes_parsed,
pcm_data,
buffer_bytes,
sbc_subbands_gain);
int_unlock(lock);
TRACE_A2DP_DECODER_D("[MCU][SBC] seq:%d/%d/%d len:%d ret:%d used:%d",
sbc_decoder_frame->curSubSequenceNumber,
sbc_decoder_frame->totalSubSequenceNumber,
sbc_decoder_frame->sequenceNumber,
sbc_decoder_frame->sbc_buffer_len,
ret,
bytes_parsed);
a2dp_audio_sbc_lastframe_info.sequenceNumber = sbc_decoder_frame->sequenceNumber;
a2dp_audio_sbc_lastframe_info.timestamp = sbc_decoder_frame->timestamp;
a2dp_audio_sbc_lastframe_info.curSubSequenceNumber = sbc_decoder_frame->curSubSequenceNumber;
a2dp_audio_sbc_lastframe_info.totalSubSequenceNumber = sbc_decoder_frame->totalSubSequenceNumber;
a2dp_audio_sbc_lastframe_info.frame_samples = sbc_decoder->maxPcmLen/4;
a2dp_audio_sbc_lastframe_info.decoded_frames++;
a2dp_audio_sbc_lastframe_info.undecode_frames = a2dp_audio_list_length(list)-1;
a2dp_audio_sbc_lastframe_info.check_sum = a2dp_audio_decoder_internal_check_sum_generate(sbc_decoder_frame->sbc_buffer, sbc_decoder_frame->sbc_buffer_len);
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
a2dp_audio_list_remove(list, sbc_decoder_frame);
switch (ret)
{
case BT_STS_SUCCESS:
if (pcm_data->dataLen != buffer_bytes){
TRACE_A2DP_DECODER_W("[MCU][SBC] WARNING pcm buff mismatch %d/%d", pcm_data->dataLen, buffer_bytes);
}
if (pcm_data->dataLen == buffer_bytes){
if (pcm_output_byte+frame_pcmbyte != buffer_bytes){
TRACE_A2DP_DECODER_W("[MCU][SBC]WARNING loop not break %d/%d frame_pcm:%d", pcm_output_byte, buffer_bytes, frame_pcmbyte);
goto exit;
}
}
break;
case BT_STS_CONTINUE:
continue;
break;
case BT_STS_NO_RESOURCES:
ASSERT_A2DP_DECODER(0, "sbc_decode BT_STS_NO_RESOURCES pcm has no more buffer, i think can't reach here");
break;
case BT_STS_FAILED:
default:
sbc_codec_init();
goto exit;
}
}else{
TRACE_A2DP_DECODER_W("[MCU][SBC] A2DP PACKET CACHE UNDERFLOW");
ret = BT_STS_FAILED;
cache_underflow = true;
goto exit;
}
}
exit:
if (cache_underflow){
TRACE_A2DP_DECODER_W("[MCU][SBC] A2DP PACKET CACHE UNDERFLOW need add some process");
a2dp_audio_sbc_lastframe_info.undecode_frames = 0;
a2dp_audio_sbc_lastframe_info.check_sum = 0;
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
ret = A2DP_DECODER_CACHE_UNDERFLOW_ERROR;
}
return ret;
}
int a2dp_audio_sbc_decode_frame(uint8_t *buffer, uint32_t buffer_bytes)
{
int nRet = 0;
if (sbc_chnl_mode_mono){
int i = 0;
int16_t *src = NULL,*dest = NULL;
#ifdef A2DP_CP_ACCEL
nRet = a2dp_cp_sbc_mcu_decode(buffer, buffer_bytes/2);
#else
nRet = a2dp_audio_sbc_mcu_decode_frame(buffer, buffer_bytes/2);
#endif
i = buffer_bytes / 2;
dest = (int16_t *)buffer + i - 1;
i = i / 2;
src = (int16_t *)buffer + i - 1;
for (; i>=0; i--){
*dest = *src;
dest--;
*dest = *src;
dest--;
src--;
}
}else{
#ifdef A2DP_CP_ACCEL
nRet = a2dp_cp_sbc_mcu_decode(buffer, buffer_bytes);
#else
nRet = a2dp_audio_sbc_mcu_decode_frame(buffer, buffer_bytes);
#endif
}
return nRet;
}
int a2dp_audio_sbc_preparse_packet(btif_media_header_t * header, uint8_t *buffer, uint32_t buffer_bytes)
{
uint16_t bytes_parsed = 0;
uint32_t frame_num = 0;
uint8_t *parser_p = buffer;
frame_num = *parser_p;
parser_p++;
buffer_bytes--;
// TODO: Remove the following sbc init and decode codes. They might conflict with the calls
// during CP process. CP process is triggered by audioflinger PCM callback.
if (*parser_p != 0x9c){
TRACE_A2DP_DECODER_I("[SBC][PRE] ERROR SBC FRAME !!! frame_num:%d", frame_num);
DUMP8("%02x ", parser_p, 12);
}else{
btif_sbc_decode_frames_parser(a2dp_audio_sbc_decoder_preparse,parser_p, buffer_bytes, &bytes_parsed);
TRACE_A2DP_DECODER_I("[SBC][PRE] seq:%d tStmp:%08x smpR:%d ch:%d len:%d",
header->sequenceNumber,
header->timestamp,
a2dp_audio_sbc_decoder_preparse->streamInfo.sampleFreq,
a2dp_audio_sbc_decoder_preparse->streamInfo.channelMode,
a2dp_audio_sbc_decoder_preparse->maxPcmLen);
TRACE_A2DP_DECODER_I("[SBC][PRE] frmN:%d par:%d/%d", frame_num, buffer_bytes, bytes_parsed);
a2dp_audio_sbc_lastframe_info.sequenceNumber = header->sequenceNumber;
a2dp_audio_sbc_lastframe_info.timestamp = header->timestamp;
a2dp_audio_sbc_lastframe_info.curSubSequenceNumber = 0;
a2dp_audio_sbc_lastframe_info.totalSubSequenceNumber = frame_num;
a2dp_audio_sbc_lastframe_info.frame_samples = a2dp_audio_sbc_decoder_preparse->maxPcmLen/4;
a2dp_audio_sbc_lastframe_info.list_samples = SBC_LIST_SAMPLES;
a2dp_audio_sbc_lastframe_info.decoded_frames = 0;
a2dp_audio_sbc_lastframe_info.undecode_frames = 0;
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
}
if (a2dp_audio_sbc_decoder_preparse->streamInfo.channelMode == BTIF_SBC_CHNL_MODE_MONO){
sbc_chnl_mode_mono = true;
}
return A2DP_DECODER_NO_ERROR;
}
static int a2dp_audio_sbc_header_parser_init(void)
{
a2dp_audio_sbc_decoder_config.auto_synchronize_support = true;
sbc_decoder_last_valid_frame_ready = false;
memset(&sbc_decoder_last_valid_frame, 0, sizeof(sbc_decoder_last_valid_frame));
return 0;
}
static int a2dp_audio_sbc_packet_recover_save_last(btif_media_header_t *sbc_decoder_frame)
{
sbc_decoder_last_valid_frame = *sbc_decoder_frame;
sbc_decoder_last_valid_frame_ready = true;
return 0;
}
static int a2dp_audio_sbc_packet_recover_find_missing(btif_media_header_t *sbc_decoder_frame, uint8_t frame_cnt)
{
uint16_t diff_seq = 0;
uint32_t diff_timestamp = 0;
uint32_t diff = 0;
uint32_t need_recover_pkt = 0;
if (!sbc_decoder_last_valid_frame_ready){
return need_recover_pkt;
}
diff_seq = a2dp_audio_get_passed(sbc_decoder_frame->sequenceNumber, sbc_decoder_last_valid_frame.sequenceNumber, UINT16_MAX);
diff_timestamp = a2dp_audio_get_passed(sbc_decoder_frame->timestamp, sbc_decoder_last_valid_frame.timestamp, UINT32_MAX);
if (diff_seq > 1){
diff = diff_timestamp/diff_seq;
if (diff%SBC_LIST_SAMPLES == 0){
need_recover_pkt = diff_timestamp/SBC_LIST_SAMPLES;
if (need_recover_pkt > frame_cnt){
need_recover_pkt -= frame_cnt;
}
}else{
diff_seq--;
need_recover_pkt = diff_seq * frame_cnt;
}
TRACE_A2DP_DECODER_W("[SBC][INPUT][PLC] seq:%d/%d stmp:%d/%d", sbc_decoder_frame->sequenceNumber, sbc_decoder_last_valid_frame.sequenceNumber,
sbc_decoder_frame->timestamp, sbc_decoder_last_valid_frame.timestamp);
TRACE_A2DP_DECODER_W("[SBC][INPUT][PLC] diff_seq:%d diff_stmp:%d diff:%d missing:%d", diff_seq, diff_timestamp, diff, need_recover_pkt);
}
return need_recover_pkt;
}
static int a2dp_audio_sbc_packet_recover_proc(btif_media_header_t *sbc_decoder_frame, a2dp_audio_sbc_decoder_frame_t *sbc_raw_frame, uint8_t frame_cnt)
{
int nRet = A2DP_DECODER_NO_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
int missing_pkt_cnt = 0;
missing_pkt_cnt = a2dp_audio_sbc_packet_recover_find_missing(sbc_decoder_frame, frame_cnt);
if (missing_pkt_cnt && sbc_raw_frame &&
(a2dp_audio_list_length(list)+missing_pkt_cnt) < sbc_mtu_limiter){
for (uint8_t i =0; i<missing_pkt_cnt; i++){
a2dp_audio_sbc_decoder_frame_t *frame_p = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_sbc_subframe_malloc(sbc_raw_frame->sbc_buffer_len);
if (!frame_p){
nRet = A2DP_DECODER_MEMORY_ERROR;
goto exit;
}
frame_p->sequenceNumber = UINT16_MAX;
frame_p->timestamp = UINT32_MAX;
memcpy(frame_p->sbc_buffer, sbc_raw_frame->sbc_buffer, sbc_raw_frame->sbc_buffer_len);
frame_p->sbc_buffer_len = sbc_raw_frame->sbc_buffer_len;
a2dp_audio_list_append(list, frame_p);
}
}
exit:
return nRet;
}
#define FRAME_LIST_MAX (20)
int a2dp_audio_sbc_store_packet(btif_media_header_t * header, uint8_t *buffer, uint32_t buffer_bytes)
{
int nRet = A2DP_DECODER_NO_ERROR;
uint32_t frame_cnt = 0;
uint32_t frame_num = 0;
uint32_t frame_len = 0;
uint8_t *parser_p = buffer;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
uint16_t bytes_parsed = 0;
a2dp_audio_sbc_decoder_frame_t *frame_list[FRAME_LIST_MAX] = {0,};
uint8_t frame_list_idx = 0;
bool find_err = false;
uint32_t i = 0;
frame_num = *parser_p;
if (!frame_num){
TRACE_A2DP_DECODER_W("[SBC][INPUT] ERROR SBC FRAME !!! frame_num:%d", frame_num);
DUMP8("%02x ", parser_p, 12);
return A2DP_DECODER_DECODE_ERROR;
}
parser_p++;
buffer_bytes--;
frame_len = buffer_bytes/frame_num;
if ((a2dp_audio_list_length(list)+frame_num) < sbc_mtu_limiter){
for (i=0; i<buffer_bytes; i+=bytes_parsed, frame_cnt++){
bytes_parsed = 0;
if (*(parser_p+i) == 0x9c){
if (btif_sbc_decode_frames_parser(a2dp_audio_sbc_decoder_preparse, parser_p+i, buffer_bytes, &bytes_parsed) != BT_STS_SUCCESS){
bytes_parsed = frame_len;
TRACE_A2DP_DECODER_W("[SBC][INPUT] ERROR SBC FRAME PARSER !!!");
DUMP8("%02x ", parser_p+i, 12);
find_err = true;
break;
}
a2dp_audio_sbc_decoder_frame_t *frame_p = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_sbc_subframe_malloc(bytes_parsed);
if (!frame_p){
nRet = A2DP_DECODER_MEMORY_ERROR;
find_err = true;
break;
}
frame_p->sequenceNumber = header->sequenceNumber;
frame_p->timestamp = header->timestamp;
frame_p->curSubSequenceNumber = frame_cnt;
frame_p->totalSubSequenceNumber = frame_num;
memcpy(frame_p->sbc_buffer, (parser_p+i), bytes_parsed);
frame_p->sbc_buffer_len = bytes_parsed;
frame_list[frame_list_idx++] = frame_p;
if (frame_list_idx >= FRAME_LIST_MAX){
find_err = true;
break;
}
}else{
TRACE_A2DP_DECODER_W("[SBC][INPUT] ERROR SBC FRAME !!!");
DUMP8("%02x ", parser_p+i, 12);
find_err = true;
break;
}
}
if (find_err){
TRACE_A2DP_DECODER_W("[SBC][INPUT] FIND ERR !!!");
for (i = 0; i<frame_list_idx; i++){
a2dp_audio_sbc_subframe_free(frame_list[i]);
}
nRet = A2DP_DECODER_DECODE_ERROR;
}else{
a2dp_audio_sbc_packet_recover_proc(header, frame_list[0], frame_num);
a2dp_audio_sbc_packet_recover_save_last(header);
for (i = 0; i<frame_list_idx; i++){
a2dp_audio_list_append(list, frame_list[i]);
}
nRet = A2DP_DECODER_NO_ERROR;
}
}else{
TRACE_A2DP_DECODER_W("[SBC][INPUT] OVERFLOW list:%d", a2dp_audio_list_length(list));
nRet = A2DP_DECODER_MTU_LIMTER_ERROR;
}
return nRet;
}
int a2dp_audio_sbc_discards_packet(uint32_t packets)
{
int nRet = A2DP_DECODER_MEMORY_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
uint16_t totalSubSequenceNumber;
uint8_t j = 0;
#ifdef A2DP_CP_ACCEL
a2dp_cp_reset_frame();
#endif
node = a2dp_audio_list_begin(list);
if (!node){
goto exit;
}
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
for (j=0; j<a2dp_audio_list_length(list); j++){
node = a2dp_audio_list_begin(list);
if (!node){
goto exit;
}
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
if (sbc_decoder_frame->curSubSequenceNumber != 0){
a2dp_audio_list_remove(list, sbc_decoder_frame);
}else{
break;
}
}
node = a2dp_audio_list_begin(list);
if (!node){
goto exit;
}
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
ASSERT_A2DP_DECODER(sbc_decoder_frame->curSubSequenceNumber == 0, "sbc_discards_packet not align curSubSequenceNumber:%d",
sbc_decoder_frame->curSubSequenceNumber);
totalSubSequenceNumber = sbc_decoder_frame->totalSubSequenceNumber;
if (packets <= a2dp_audio_list_length(list)/totalSubSequenceNumber){
for (uint8_t i=0; i<packets; i++){
for (j=0; j<totalSubSequenceNumber; j++){
node = a2dp_audio_list_begin(list);
if (!node){
goto exit;
}
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}
nRet = A2DP_DECODER_NO_ERROR;
}
exit:
TRACE_A2DP_DECODER_I("[SBC][DISCARDS] packets:%d nRet:%d", packets, nRet);
return nRet;
}
int a2dp_audio_sbc_headframe_info_get(A2DP_AUDIO_HEADFRAME_INFO_T *headframe_info)
{
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
if (a2dp_audio_list_length(list) && ((node = a2dp_audio_list_begin(list)) != NULL)){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
headframe_info->sequenceNumber = sbc_decoder_frame->sequenceNumber;
headframe_info->timestamp = sbc_decoder_frame->timestamp;
headframe_info->curSubSequenceNumber = sbc_decoder_frame->curSubSequenceNumber;
headframe_info->totalSubSequenceNumber = sbc_decoder_frame->totalSubSequenceNumber;
}else{
memset(headframe_info, 0, sizeof(A2DP_AUDIO_HEADFRAME_INFO_T));
}
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_info_get(void *info)
{
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_synchronize_packet(A2DP_AUDIO_SYNCFRAME_INFO_T *sync_info, uint32_t mask)
{
int nRet = A2DP_DECODER_SYNC_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
int list_len;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
#ifdef A2DP_CP_ACCEL
a2dp_cp_reset_frame();
#endif
list_len = a2dp_audio_list_length(list);
for (uint16_t i=0; i<list_len; i++){
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
if (A2DP_AUDIO_SYNCFRAME_CHK(sbc_decoder_frame->sequenceNumber == sync_info->sequenceNumber, A2DP_AUDIO_SYNCFRAME_MASK_SEQ, mask)&&
A2DP_AUDIO_SYNCFRAME_CHK(sbc_decoder_frame->curSubSequenceNumber == sync_info->curSubSequenceNumber, A2DP_AUDIO_SYNCFRAME_MASK_CURRSUBSEQ, mask)&&
A2DP_AUDIO_SYNCFRAME_CHK(sbc_decoder_frame->totalSubSequenceNumber == sync_info->totalSubSequenceNumber,A2DP_AUDIO_SYNCFRAME_MASK_TOTALSUBSEQ,mask)){
nRet = A2DP_DECODER_NO_ERROR;
break;
}
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
TRACE_A2DP_DECODER_I("[MCU][SYNC][SBC] sync pkt nRet:%d SEQ:%d timestamp:%d %d/%d",
nRet, sbc_decoder_frame->sequenceNumber, sbc_decoder_frame->timestamp,
sbc_decoder_frame->curSubSequenceNumber, sbc_decoder_frame->totalSubSequenceNumber);
}else{
TRACE_A2DP_DECODER_I("[MCU][SYNC][SBC] sync pkt nRet:%d", nRet);
}
return nRet;
}
int a2dp_audio_sbc_synchronize_dest_packet_mut(uint16_t packet_mut)
{
list_node_t *node = NULL;
uint32_t list_len = 0;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
list_len = a2dp_audio_list_length(list);
if (list_len > packet_mut){
do{
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}while(a2dp_audio_list_length(list) > packet_mut);
}
TRACE_A2DP_DECODER_I("[MCU][SYNC][SBC] dest pkt list:%d", a2dp_audio_list_length(list));
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_convert_list_to_samples(uint32_t *samples)
{
uint32_t list_len = 0;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_len = a2dp_audio_list_length(list);
*samples = SBC_LIST_SAMPLES*list_len;
TRACE_A2DP_DECODER_I("[MCU][SBC] list:%d samples:%d", list_len, *samples);
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_discards_samples(uint32_t samples)
{
int nRet = A2DP_DECODER_SYNC_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
list_node_t *node = NULL;
int need_remove_list = 0;
uint32_t list_samples = 0;
ASSERT_A2DP_DECODER(!(samples%SBC_LIST_SAMPLES), "%s samples err:%d", __func__, samples);
a2dp_audio_sbc_convert_list_to_samples(&list_samples);
if (list_samples >= samples){
need_remove_list = samples/SBC_LIST_SAMPLES;
for (int i=0; i<need_remove_list; i++){
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}
nRet = A2DP_DECODER_NO_ERROR;
}
return nRet;
}
int a2dp_audio_sbc_channel_select(A2DP_AUDIO_CHANNEL_SELECT_E chnl_sel)
{
return A2DP_DECODER_NO_ERROR;
}
A2DP_AUDIO_DECODER_T a2dp_audio_sbc_decoder_config = {
{44100, 2, 16},
1,
a2dp_audio_sbc_init,
a2dp_audio_sbc_deinit,
a2dp_audio_sbc_decode_frame,
a2dp_audio_sbc_preparse_packet,
a2dp_audio_sbc_store_packet,
a2dp_audio_sbc_discards_packet,
a2dp_audio_sbc_synchronize_packet,
a2dp_audio_sbc_synchronize_dest_packet_mut,
a2dp_audio_sbc_convert_list_to_samples,
a2dp_audio_sbc_discards_samples,
a2dp_audio_sbc_headframe_info_get,
a2dp_audio_sbc_info_get,
a2dp_audio_sbc_subframe_free,
a2dp_audio_sbc_channel_select,
} ;