pinebuds/apps/audioplayers/a2dp_decoder/a2dp_decoder_scalable.cpp

756 lines
24 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 "a2dp_decoder_internal.h"
#include "app_audio.h"
#include "cmsis.h"
#include "hal_location.h"
#include "heap_api.h"
#include "plat_types.h"
#include <string.h>
#if defined(A2DP_SCALABLE_ON)
#include "heap_api.h"
#include "ssc.h"
#define SCALABLE_MTU_LIMITER (32)
#define SCALABLE_MEMPOOL_SIZE 1024
#define SCALABLE_OUTPUT_FRAME_SAMPLES (SCALABLE_FRAME_SIZE)
typedef void *HANDLE_DECODER;
static A2DP_AUDIO_CONTEXT_T *a2dp_audio_context_p = NULL;
static A2DP_AUDIO_OUTPUT_CONFIG_T output_config;
static unsigned char *scalable_decoder_place = NULL;
static unsigned char *scalable_decoder_temp_buf = NULL;
static short ss_pcm_buff[SCALABLE_FRAME_SIZE * 4];
static int scalable_uhq_flag __attribute__((unused)) = 0;
static HANDLE_DECODER scalableDec_handle = NULL;
static A2DP_AUDIO_DECODER_LASTFRAME_INFO_T lastframe_info;
typedef struct {
uint16_t sequenceNumber;
uint32_t timestamp;
uint8_t *buffer;
int buffer_len;
} a2dp_audio_scalable_decoder_frame_t;
static void ss_to_24bit_buf(int32_t *out, int32_t *in, int size) {
for (int i = 0; i < size; i++) {
out[i] = in[i];
}
}
static void a2dp_audio_scalable_decoder_init(void) {
if (scalableDec_handle == NULL) {
scalableDec_handle = scalable_decoder_place;
ssc_decoder_init(scalableDec_handle, output_config.num_channels,
output_config.sample_rate);
}
}
static int scalableDecoder_Close(HANDLE_DECODER handle) {
if (handle) {
a2dp_audio_heap_free(handle);
a2dp_audio_heap_free(scalable_decoder_temp_buf);
}
return 0;
}
static void a2dp_audio_scalable_decoder_deinit(void) {
if (scalableDec_handle) {
scalableDecoder_Close(scalableDec_handle);
scalableDec_handle = NULL;
}
}
static void a2dp_audio_scalable_decoder_reinit(void) {
if (scalableDec_handle) {
a2dp_audio_scalable_decoder_deinit();
}
a2dp_audio_scalable_decoder_init();
}
static bool
is_valid_frame(a2dp_audio_scalable_decoder_frame_t *decoder_frame_p) {
int hw_tmp, len, bitrate_bps, frame_len, frame_size;
int sampling_rate = 44100;
unsigned char *input_buf = decoder_frame_p->buffer;
if (decoder_frame_p->buffer_len < SCALABLE_HEAD_SIZE) {
TRACE_A2DP_DECODER_E(
"invalid scalable a2dp frame, length < SCALABLE_HEAD_SIZE !!!!!!!");
return false;
}
scalable_uhq_flag = 0;
switch ((input_buf[3] & 0xf7)) {
case 0xF0:
bitrate_bps = 88000;
break;
case 0xF1:
bitrate_bps = 96000;
break;
case 0xF2:
bitrate_bps = 128000;
break;
case 0xF3:
bitrate_bps = 192000;
break;
case 0xF4:
bitrate_bps = 229000;
break;
case 0xF5:
scalable_uhq_flag = 1;
bitrate_bps = 328000;
sampling_rate = 96000;
break;
default:
bitrate_bps = 192000;
break;
}
frame_size = SCALABLE_FRAME_SIZE;
len = bitrate_bps * frame_size / sampling_rate / 8;
if (scalable_uhq_flag == 0) {
hw_tmp = (len * 3) >> 7;
len = hw_tmp + len;
len = len + ((len & 1) ^ 1);
} else {
len = 369; // 744/2-4+1
}
TRACE_A2DP_DECODER_D(
"scalable a2dp frame, length:%d bitrate:%d sampling_rate:%d",
decoder_frame_p->buffer_len, bitrate_bps, sampling_rate);
frame_len = SCALABLE_HEAD_SIZE + len - 1;
if (decoder_frame_p->buffer_len < frame_len) {
TRACE_A2DP_DECODER_E(
"invalid scalable a2dp frame, length:%d < %d !!!!!!!",
decoder_frame_p->buffer_len, frame_len);
return false;
}
return true;
}
#ifdef A2DP_CP_ACCEL
struct A2DP_CP_scalable_IN_FRM_INFO_T {
uint16_t sequenceNumber;
uint32_t timestamp;
};
struct A2DP_CP_scalable_OUT_FRM_INFO_T {
struct A2DP_CP_scalable_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 uint32_t app_bt_stream_get_dma_buffer_samples(void);
TEXT_SSC_LOC static int a2dp_cp_scalable_mcu_decode(uint8_t *buffer,
uint32_t buffer_bytes) {
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = 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_scalable_IN_FRM_INFO_T in_info;
struct A2DP_CP_scalable_OUT_FRM_INFO_T *p_out_info;
uint8_t *out;
uint32_t out_len;
uint32_t out_frame_len;
uint32_t cp_buffer_frames_max = 0;
cp_buffer_frames_max = app_bt_stream_get_dma_buffer_samples() / 2;
if (cp_buffer_frames_max % (lastframe_info.frame_samples)) {
cp_buffer_frames_max =
cp_buffer_frames_max / (lastframe_info.frame_samples) + 1;
} else {
cp_buffer_frames_max =
cp_buffer_frames_max / (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);
ASSERT(ret == 0, "%s: a2dp_cp_decoder_init() failed: ret=%d", __func__, ret);
while ((node = a2dp_audio_list_begin(list)) != NULL) {
decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
if (false == is_valid_frame(decoder_frame_p)) {
return A2DP_DECODER_DECODE_ERROR;
}
in_info.sequenceNumber = decoder_frame_p->sequenceNumber;
in_info.timestamp = decoder_frame_p->timestamp;
ret =
a2dp_cp_put_in_frame(&in_info, sizeof(in_info), decoder_frame_p->buffer,
decoder_frame_p->buffer_len);
if (ret) {
break;
}
a2dp_audio_list_remove(list, decoder_frame_p);
}
ret = a2dp_cp_get_full_out_frame((void **)&out, &out_len);
if (ret) {
return A2DP_DECODER_DECODE_ERROR;
}
if (out_len == 0) {
memset(buffer, 0, buffer_bytes);
a2dp_cp_consume_full_out_frame();
return A2DP_DECODER_NO_ERROR;
}
ASSERT(out_len == out_frame_len, "%s: Bad out len %u (should be %u)",
__func__, out_len, out_frame_len);
p_out_info = (struct A2DP_CP_scalable_OUT_FRM_INFO_T *)out;
if (p_out_info->pcm_len) {
lastframe_info.sequenceNumber = p_out_info->in_info.sequenceNumber;
lastframe_info.timestamp = p_out_info->in_info.timestamp;
lastframe_info.curSubSequenceNumber = 0;
lastframe_info.totalSubSequenceNumber = 0;
lastframe_info.frame_samples = p_out_info->frame_samples;
lastframe_info.decoded_frames += p_out_info->decoded_frames;
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_decoder_internal_lastframe_info_set(&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 {
dec_ret = A2DP_DECODER_DECODE_ERROR;
}
ret = a2dp_cp_consume_full_out_frame();
ASSERT(ret == 0, "%s: a2dp_cp_consume_full_out_frame() failed: ret=%d",
__func__, ret);
return dec_ret;
}
TEXT_SSC_LOC int a2dp_cp_scalable_cp_decode(void) {
int ret;
enum CP_EMPTY_OUT_FRM_T out_frm_st;
uint8_t *out;
uint32_t out_len;
uint8_t *dec_start;
uint32_t dec_len;
struct A2DP_CP_scalable_IN_FRM_INFO_T *p_in_info;
struct A2DP_CP_scalable_OUT_FRM_INFO_T *p_out_info;
uint8_t *in_buf;
uint32_t in_len;
uint32_t dec_sum;
int error, output_samples = 0, output_byte = 0;
if (cp_codec_reset) {
cp_codec_reset = false;
a2dp_audio_scalable_decoder_init();
}
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(out_len > sizeof(*p_out_info), "%s: Bad out_len %u (should > %u)",
__func__, out_len, sizeof(*p_out_info));
p_out_info = (struct A2DP_CP_scalable_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(out_len > sizeof(*p_out_info) + p_out_info->pcm_len,
"%s: Bad out_len %u (should > %u + %u)", __func__, 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);
if (!scalableDec_handle) {
TRACE(0, "scalable_decode not ready");
return 3;
}
dec_sum = 0;
error = 0;
while (dec_sum < dec_len && error == 0) {
ret = a2dp_cp_get_in_frame((void **)&in_buf, &in_len);
if (ret) {
break;
}
ASSERT(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_scalable_IN_FRM_INFO_T *)in_buf;
in_buf += sizeof(*p_in_info);
in_len -= sizeof(*p_in_info);
/* decode one SSC frame */
output_samples =
ssc_decode(scalableDec_handle, (const unsigned char *)in_buf,
ss_pcm_buff, SCALABLE_FRAME_SIZE, 0, 2);
if (0 == output_samples) {
a2dp_audio_scalable_decoder_reinit();
TRACE(0, "scalable_decode reinin codec \n");
error = A2DP_DECODER_DECODE_ERROR;
goto exit;
}
ss_to_24bit_buf((int32_t *)(dec_start + dec_sum), (int32_t *)ss_pcm_buff,
output_samples);
output_byte = output_samples * 4;
dec_sum += output_byte;
exit:
memcpy(&p_out_info->in_info, ss_pcm_buff, sizeof(*p_in_info));
p_out_info->decoded_frames++;
p_out_info->frame_samples = SCALABLE_OUTPUT_FRAME_SAMPLES;
p_out_info->frame_idx = a2dp_cp_get_in_frame_index();
ret = a2dp_cp_consume_in_frame();
ASSERT(ret == 0, "%s: a2dp_cp_consume_in_frame() failed: ret=%d", __func__,
ret);
}
p_out_info->pcm_len += dec_sum;
if (error || out_len <= sizeof(*p_out_info) + p_out_info->pcm_len) {
ret = a2dp_cp_consume_emtpy_out_frame();
ASSERT(ret == 0, "%s: a2dp_cp_consume_emtpy_out_frame() failed: ret=%d",
__func__, ret);
}
return error;
}
#endif
static int a2dp_audio_scalable_init(A2DP_AUDIO_OUTPUT_CONFIG_T *config,
void *context) {
TRACE_A2DP_DECODER_D("%s", __func__);
TRACE(0, "\n\nA2DP SSC-LC INIT\n");
a2dp_audio_context_p = (A2DP_AUDIO_CONTEXT_T *)context;
memcpy(&output_config, config, sizeof(A2DP_AUDIO_OUTPUT_CONFIG_T));
memset(&lastframe_info, 0, sizeof(A2DP_AUDIO_DECODER_LASTFRAME_INFO_T));
lastframe_info.stream_info = output_config;
lastframe_info.frame_samples = SCALABLE_FRAME_SIZE;
lastframe_info.list_samples = SCALABLE_FRAME_SIZE;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
ASSERT(a2dp_audio_context_p->dest_packet_mut < SCALABLE_MTU_LIMITER,
"%s MTU OVERFLOW:%u/%u", __func__,
a2dp_audio_context_p->dest_packet_mut, SCALABLE_MTU_LIMITER);
int decoder_size;
decoder_size = ssc_decoder_get_size(
output_config.num_channels); // todo: get size with codec capability
TRACE(0, "decoder size %d", decoder_size);
scalable_decoder_place =
(unsigned char *)a2dp_audio_heap_malloc(decoder_size);
ASSERT_A2DP_DECODER(scalable_decoder_place,
"no memory resource for scalable_decoder_place");
scalable_decoder_temp_buf =
(unsigned char *)a2dp_audio_heap_malloc(SCALABLE_FRAME_SIZE * 16);
ASSERT_A2DP_DECODER(scalable_decoder_temp_buf,
"no memory resource for scalable_decoder_temp_buf");
#ifdef A2DP_CP_ACCEL
int ret;
cp_codec_reset = true;
ret = a2dp_cp_init(a2dp_cp_scalable_cp_decode, CP_PROC_DELAY_1_FRAME);
ASSERT(ret == 0, "%s: a2dp_cp_init() failed: ret=%d", __func__, ret);
#else
a2dp_audio_scalable_decoder_init();
#endif
return A2DP_DECODER_NO_ERROR;
}
static int a2dp_audio_scalable_deinit(void) {
#ifdef A2DP_CP_ACCEL
a2dp_cp_deinit();
#endif
a2dp_audio_scalable_decoder_deinit();
TRACE(0, "\n\nA2DP SCALABLE DEINIT\n");
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_scalable_mcu_decode_frame(uint8_t *buffer,
uint32_t buffer_bytes) {
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
int ret = A2DP_DECODER_NO_ERROR;
bool cache_underflow = false;
int output_byte = 0, output_samples = 0;
uint8_t *output = buffer;
// TRACE(1,"bbd %d",buffer_bytes );
if (buffer_bytes < (SCALABLE_FRAME_SIZE * output_config.num_channels *
output_config.bits_depth / 8)) {
TRACE(1, "scalable_decode pcm_len = %d \n", buffer_bytes);
return A2DP_DECODER_NO_ERROR;
}
if (!scalableDec_handle) {
TRACE(0, "scalable_decode not ready");
return A2DP_DECODER_NO_ERROR;
}
while (output < buffer + buffer_bytes) {
node = a2dp_audio_list_begin(list);
if (!node) {
TRACE(0, "scalable_decode cache underflow");
cache_underflow = true;
goto exit;
} else {
decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
if (false == is_valid_frame(decoder_frame_p)) {
TRACE_A2DP_DECODER_E("%s %d invalid a2dp frame", __func__, __LINE__);
ret = A2DP_DECODER_DECODE_ERROR;
goto exit;
}
/* decode one SSC frame */
output_samples = ssc_decode(scalableDec_handle, decoder_frame_p->buffer,
ss_pcm_buff, SCALABLE_FRAME_SIZE, 0, 2);
TRACE_A2DP_DECODER_D("scalable_decode seq:%d len:%d output_samples:%d",
decoder_frame_p->sequenceNumber,
decoder_frame_p->buffer_len, output_samples);
if (0 == output_samples) {
TRACE(0, "scalable_decode failed !!!!!!");
// if failed reopen it again
a2dp_audio_scalable_decoder_reinit();
TRACE(0, "scalable_decode reinin codec \n");
ret = A2DP_DECODER_DECODE_ERROR;
goto exit;
}
ss_to_24bit_buf((int32_t *)output, (int32_t *)ss_pcm_buff,
output_samples * 2);
output_byte = output_samples * 8;
output += output_byte;
ASSERT(SCALABLE_FRAME_SIZE == output_samples,
"scalable_decode output mismatch samples:%d", output_samples);
lastframe_info.sequenceNumber = decoder_frame_p->sequenceNumber;
lastframe_info.timestamp = decoder_frame_p->timestamp;
lastframe_info.curSubSequenceNumber = 0;
lastframe_info.totalSubSequenceNumber = 0;
lastframe_info.frame_samples = SCALABLE_FRAME_SIZE;
lastframe_info.decoded_frames++;
lastframe_info.undecode_frames = a2dp_audio_list_length(list) - 1;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
a2dp_audio_list_remove(list, decoder_frame_p);
}
}
exit:
if (cache_underflow) {
lastframe_info.undecode_frames = 0;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
ret = A2DP_DECODER_CACHE_UNDERFLOW_ERROR;
}
// TRACE(0,"abd");
return ret;
}
static int a2dp_audio_scalable_decode_frame(uint8_t *buffer,
uint32_t buffer_bytes) {
#ifdef A2DP_CP_ACCEL
return a2dp_cp_scalable_mcu_decode(buffer, buffer_bytes);
#else
return a2dp_audio_scalable_mcu_decode_frame(buffer, buffer_bytes);
#endif
}
static int a2dp_audio_scalable_preparse_packet(btif_media_header_t *header,
uint8_t *buffer,
uint32_t buffer_bytes) {
lastframe_info.sequenceNumber = header->sequenceNumber;
lastframe_info.timestamp = header->timestamp;
lastframe_info.curSubSequenceNumber = 0;
lastframe_info.totalSubSequenceNumber = 0;
lastframe_info.frame_samples = SCALABLE_FRAME_SIZE;
lastframe_info.list_samples = SCALABLE_FRAME_SIZE;
lastframe_info.decoded_frames = 0;
lastframe_info.undecode_frames = 0;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
TRACE(3, "%s seq:%d timestamp:%08x", __func__, header->sequenceNumber,
header->timestamp);
return A2DP_DECODER_NO_ERROR;
}
static void *a2dp_audio_scalable_frame_malloc(uint32_t packet_len) {
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
uint8_t *buffer = NULL;
buffer = (uint8_t *)a2dp_audio_heap_malloc(SCALABLE_READBUF_SIZE);
decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_heap_malloc(
sizeof(a2dp_audio_scalable_decoder_frame_t));
decoder_frame_p->buffer = buffer;
decoder_frame_p->buffer_len = packet_len;
return (void *)decoder_frame_p;
}
static void a2dp_audio_scalable_free(void *packet) {
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)packet;
a2dp_audio_heap_free(decoder_frame_p->buffer);
a2dp_audio_heap_free(decoder_frame_p);
}
static int a2dp_audio_scalable_store_packet(btif_media_header_t *header,
uint8_t *buffer,
uint32_t buffer_bytes) {
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
int nRet = A2DP_DECODER_NO_ERROR;
if (a2dp_audio_list_length(list) < SCALABLE_MTU_LIMITER) {
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_scalable_frame_malloc(
buffer_bytes);
TRACE_A2DP_DECODER_D("%s seq:%d len:%d", __func__, header->sequenceNumber,
buffer_bytes);
decoder_frame_p->sequenceNumber = header->sequenceNumber;
decoder_frame_p->timestamp = header->timestamp;
memcpy(decoder_frame_p->buffer, buffer, buffer_bytes);
decoder_frame_p->buffer_len = buffer_bytes;
a2dp_audio_list_append(list, decoder_frame_p);
nRet = A2DP_DECODER_NO_ERROR;
} else {
TRACE(2, "%s list full current len:%d", __func__,
a2dp_audio_list_length(list));
nRet = A2DP_DECODER_MTU_LIMTER_ERROR;
}
return nRet;
}
static int a2dp_audio_scalable_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_scalable_decoder_frame_t *decoder_frame_p = NULL;
#ifdef A2DP_CP_ACCEL
a2dp_cp_reset_frame();
#endif
if (packets <= a2dp_audio_list_length(list)) {
for (uint8_t i = 0; i < packets; i++) {
if ((node = a2dp_audio_list_begin(list)) != NULL) {
decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, decoder_frame_p);
}
}
nRet = A2DP_DECODER_NO_ERROR;
}
TRACE(3, "%s packets:%d nRet:%d", __func__, packets, nRet);
return nRet;
}
static int a2dp_audio_scalable_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_scalable_decoder_frame_t *decoder_frame_p = NULL;
if (a2dp_audio_list_length(list)) {
if ((node = a2dp_audio_list_begin(list)) != NULL) {
decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
headframe_info->sequenceNumber = decoder_frame_p->sequenceNumber;
headframe_info->timestamp = decoder_frame_p->timestamp;
headframe_info->curSubSequenceNumber = 0;
headframe_info->totalSubSequenceNumber = 0;
}
} else {
memset(headframe_info, 0, sizeof(A2DP_AUDIO_HEADFRAME_INFO_T));
}
return A2DP_DECODER_NO_ERROR;
}
static int a2dp_audio_scalable_info_get(void *info) {
return A2DP_DECODER_NO_ERROR;
}
static int
a2dp_audio_scalable_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_scalable_decoder_frame_t *decoder_frame_p = 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++) {
if ((node = a2dp_audio_list_begin(list)) != NULL) {
decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
if (A2DP_AUDIO_SYNCFRAME_CHK(decoder_frame_p->sequenceNumber ==
sync_info->sequenceNumber,
A2DP_AUDIO_SYNCFRAME_MASK_SEQ, mask) &&
A2DP_AUDIO_SYNCFRAME_CHK(decoder_frame_p->timestamp ==
sync_info->timestamp,
A2DP_AUDIO_SYNCFRAME_MASK_TIMESTAMP, mask)) {
nRet = A2DP_DECODER_NO_ERROR;
break;
}
a2dp_audio_list_remove(list, decoder_frame_p);
}
}
node = a2dp_audio_list_begin(list);
if (node) {
decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
TRACE(4, "%s nRet:%d SEQ:%d timestamp:%d", __func__, nRet,
decoder_frame_p->sequenceNumber, decoder_frame_p->timestamp);
} else {
TRACE(2, "%s nRet:%d", __func__, nRet);
}
return nRet;
}
static int
a2dp_audio_scalable_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_scalable_decoder_frame_t *decoder_frame_p = NULL;
list_len = a2dp_audio_list_length(list);
if (list_len > packet_mut) {
do {
node = a2dp_audio_list_begin(list);
if (node) {
decoder_frame_p =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, decoder_frame_p);
}
} while (a2dp_audio_list_length(list) > packet_mut);
}
TRACE(2, "%s list:%d", __func__, a2dp_audio_list_length(list));
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_scalable_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 = SCALABLE_FRAME_SIZE * list_len;
TRACE(3, "%s list:%d samples:%d", __func__, list_len, *samples);
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_scalable_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_scalable_decoder_frame_t *scalable_decoder_frame = NULL;
list_node_t *node = NULL;
int need_remove_list = 0;
uint32_t list_samples = 0;
ASSERT(!(samples % SCALABLE_FRAME_SIZE), "%s samples err:%d", __func__,
samples);
a2dp_audio_scalable_convert_list_to_samples(&list_samples);
if (list_samples >= samples) {
need_remove_list = samples / SCALABLE_FRAME_SIZE;
for (int i = 0; i < need_remove_list; i++) {
node = a2dp_audio_list_begin(list);
if (node) {
scalable_decoder_frame =
(a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, scalable_decoder_frame);
}
}
nRet = A2DP_DECODER_NO_ERROR;
}
return nRet;
}
A2DP_AUDIO_DECODER_T a2dp_audio_scalable_decoder_config = {
{44100, 2, 16},
1,
a2dp_audio_scalable_init,
a2dp_audio_scalable_deinit,
a2dp_audio_scalable_decode_frame,
a2dp_audio_scalable_preparse_packet,
a2dp_audio_scalable_store_packet,
a2dp_audio_scalable_discards_packet,
a2dp_audio_scalable_synchronize_packet,
a2dp_audio_scalable_synchronize_dest_packet_mut,
a2dp_audio_scalable_convert_list_to_samples,
a2dp_audio_scalable_discards_samples,
a2dp_audio_scalable_headframe_info_get,
a2dp_audio_scalable_info_get,
a2dp_audio_scalable_free,
};
#else
A2DP_AUDIO_DECODER_T a2dp_audio_scalable_decoder_config = {
0,
};
#endif