Files
99_7018_lmx/cpu/br28/a2dp_dec.c

2872 lines
80 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
/*************************************************************************************************/
/*!
* \file a2dp_dec.c
*
* \brief
*
* Copyright (c) 2011-2022 ZhuHai Jieli Technology Co.,Ltd.
*
*/
/*************************************************************************************************/
#include "sound_device.h"
#include "media/bt_audio_timestamp.h"
#include "media/a2dp_sample_detect.h"
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
#include "spatial_effect/spatial_effect.h"
#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
#define A2DP_AUDIO_PLC_ENABLE 1
#if A2DP_AUDIO_PLC_ENABLE
#include "media/tech_lib/LFaudio_plc_api.h"
#endif
#if TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
#include "icsd_adt_app.h"
#endif
#if AUDIO_VBASS_CONFIG
#include "application/audio_vbass.h"
#endif
#if TCFG_AUDIO_CVP_DUT_ENABLE
#include "audio_cvp_dut.h"
#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
#include "audio_effect_develop.h"
#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE)
#define CONFIG_AUDIO_EFFECT_TASK_ENABLE TCFG_AUDIO_EFFECT_TASK_EBABLE
#else
#define CONFIG_AUDIO_EFFECT_TASK_ENABLE 0
#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
#define A2DP_FLUENT_STREAM_MODE 1//流畅模式
#define A2DP_FLUENT_DETECT_INTERVAL 100000//ms 流畅播放延时检测时长
#if A2DP_FLUENT_STREAM_MODE
#define A2DP_MAX_PENDING_TIME 120
#else
#define A2DP_MAX_PENDING_TIME 40
#endif
#define A2DP_STREAM_NO_ERR 0
#define A2DP_STREAM_UNDERRUN 1
#define A2DP_STREAM_OVERRUN 2
#define A2DP_STREAM_MISSED 3
#define A2DP_STREAM_DECODE_ERR 4
#define A2DP_STREAM_LOW_UNDERRUN 5
#ifdef TCFG_AUDIO_MUSIC_SAMPLE_RATE
#define A2DP_SOUND_SAMPLE_RATE TCFG_AUDIO_MUSIC_SAMPLE_RATE
#else
#define A2DP_SOUND_SAMPLE_RATE 0
#endif
#if TCFG_USER_TWS_ENABLE && TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
#define CONFIG_TWS_SPATIAL_AUDIO_ENABLE 1
#else
#define CONFIG_TWS_SPATIAL_AUDIO_ENABLE 0
#endif
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
static u8 spatial_audio_enable = 1;
static u8 spatial_audio_head_tracked = 0;
void a2dp_spatial_audio_head_tracked_en(u8 en);
int aud_spatial_sensor_init();
int aud_spatial_sensor_exit();
int aud_spatial_sensor_run(void *priv, void *data, int len);
#endif
int aud_effect_push_data(void *priv, s16 *data, u16 len);
/**************************************************************************************************
* A2DP音频数据流异步任务处理说明
*
* 1
* A2DP解码后的数据流会按照以下顺序进行流数据处理
* PLC -> (Spatial audio) -> (Digtal vol) -> (Surround) ->
* (Vbass) -> bass_boost-> (ANC) -> (Syncts) -> EQ/DRC -> (mixer) -> DAC
*
*
* 2
* a2dp_decoder_effect_task_enter();
*
*
*
* a2dp_decoder_effect_task_output();
*
* effect task中执行
*
**************************************************************************************************/
#define A2DP_NODE_BEGIN 0x1
#define A2DP_NODE_END 0x2
#define A2DP_NODE_BLOCK 0x4
#define A2DP_NODE_SUB_STREAM_BEGIN 0x8
#define A2DP_NODE_SUB_STREAM_END 0x10
enum a2dp_stream_id {
A2DP_NODE_DECODER = 0x0,
#if A2DP_AUDIO_PLC_ENABLE
A2DP_NODE_PLC,
#endif
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
A2DP_NODE_SPATIAL_AUDIO,
#if TCFG_SENSOR_DATA_READ_IN_DEC_TASK
A2DP_NODE_SENSOR_DATA_STREAM,
#endif /*TCFG_SENSOR_DATA_READ_IN_DEC_TASK*/
#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
A2DP_NODE_DIGITAL_VOLUME,
#endif
#if (AUDIO_SURROUND_CONFIG || AUDIO_VBASS_CONFIG)
A2DP_NODE_SURROUND_VBASS,
#endif
#if defined(TCFG_AUDIO_BASS_BOOST)&&TCFG_AUDIO_BASS_BOOST
A2DP_NODE_BASS_BOOST,
#endif
#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
A2DP_NODE_DYNAMIC_GAIN,
#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
#if AUDIO_CODEC_SUPPORT_SYNC
A2DP_NODE_BEFORE_SYNCTS,
A2DP_NODE_SYNCTS,
#endif
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
A2DP_NODE_EFFECT_TASK_ENTER,
#endif
#if (TCFG_EQ_ENABLE && TCFG_BT_MUSIC_EQ_ENABLE)
A2DP_NODE_EQ_DRC,
#endif
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
A2DP_NODE_EFFECT_TASK_OUT,
#endif
#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
A2DP_NODE_EFFECT_DEVELOP,
#endif
A2DP_NODE_MIXER,
A2DP_NODE_MAX,
};
struct a2dp_stream_node {
enum a2dp_stream_id id;
u8 attribute;
u8 remain;
void *priv;
int (*data_handler)(void *priv, void *data, int len);
void (*wakeup)(void *stream);
int (*set_wakeup_handler)(void *priv, void *stream, void (*wakeup)(void *));
};
struct a2dp_dec_hdl {
struct audio_decoder decoder;
struct audio_res_wait wait;
struct audio_mixer_ch mix_ch;
enum audio_channel channel;
u8 start;
u8 ch;
s16 header_len;
u8 remain;
u8 eq_remain;
u8 fetch_lock;
u8 preempt;
u8 stream_error;
u8 new_frame;
u8 repair;
u8 dut_enable;
void *sample_detect;
void *syncts;
void *repair_pkt;
s16 repair_pkt_len;
u16 missed_num;
u16 repair_frames;
u16 overrun_seqn;
u16 slience_frames;
#if AUDIO_CODEC_SUPPORT_SYNC
u8 ts_start;
u8 sync_step;
void *ts_handle;
u32 timestamp;
u32 base_time;
#endif /*AUDIO_CODEC_SUPPORT_SYNC*/
#if A2DP_AUDIO_PLC_ENABLE
LFaudio_PLC_API *plc_ops;
void *plc_mem;
#endif /*A2DP_AUDIO_PLC_ENABLE*/
u32 mix_ch_event_params[3];
u32 pending_time;
u16 seqn;
u32 sample_rate;
int timer;
u32 coding_type;
u16 delay_time;
u16 detect_timer;
u8 underrun_feedback;
/*
u8 underrun_count;
u32 underrun_time;
u32 underrun_cool_time;
*/
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
void *spatial_audio;
s16 spatial_data_len;
u8 spatial_node_id;
u16 spatial_data_offset;
#endif
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
void *aud_effect;
#endif
#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
struct dec_eq_drc *eq_drc;
#endif//TCFG_BT_MUSIC_EQ_ENABLE
#if AUDIO_SURROUND_CONFIG
struct dec_sur *sur;
#endif//AUDIO_SURROUND_CONFIG
#if AUDIO_VBASS_CONFIG
vbass_hdl *vbass; //虚拟低音句柄
#endif//AUDIO_VBASS_CONFIG
#if defined(TCFG_AUDIO_BASS_BOOST)&&TCFG_AUDIO_BASS_BOOST
struct audio_drc *bass_boost;
#endif
#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
void *effect_develop;
#endif
struct a2dp_stream_node stream_node[A2DP_NODE_MAX + 1];
u8 node_num;
};
extern const int CONFIG_LOW_LATENCY_ENABLE;
extern const int CONFIG_A2DP_DELAY_TIME;
extern const int CONFIG_A2DP_DELAY_TIME_LO;
extern const int CONFIG_A2DP_SBC_DELAY_TIME_LO;
static u16 a2dp_delay_time;
static u8 a2dp_low_latency = 0;
static u16 drop_a2dp_timer;
static u16 a2dp_low_latency_seqn = 0;
struct a2dp_dec_hdl *a2dp_dec = NULL;
static void a2dp_stream_node_init(struct a2dp_dec_hdl *dec);
static void a2dp_stream_node_add(struct a2dp_dec_hdl *dec,
void *priv,
int (*data_handler)(void *, void *, int),
void (*wakeup)(void *),
int (*set_wakeup_handler)(void *, void *, void (*wakeup)(void *)),
u8 attribute);
static void a2dp_stream_node_wakeup(void *priv);
extern u32 bt_audio_sync_lat_time(void);
extern void bt_audio_sync_nettime_select(u8 base);
void audio_mix_ch_event_handler(void *priv, int event)
{
switch (event) {
case MIXER_EVENT_CH_OPEN:
if (priv) {
u32 *params = (u32 *)priv;
struct audio_mixer_ch *ch = (struct audio_mixer_ch *)params[0];
u32 base_time = params[2];
sound_pcm_dev_add_syncts((void *)params[1]);
u32 current_time = (bt_audio_sync_lat_time() * 625 * TIME_US_FACTOR);
u32 time_diff = ((base_time - current_time) & 0xffffffff) / TIME_US_FACTOR;
printf("-----base time : %u, current_time : %u------\n", base_time, current_time);
if (time_diff < 500000) {
int buf_frame = sound_pcm_dev_buffered_frames();
int slience_frames = (u64)time_diff * audio_mixer_get_sample_rate(&mixer) / 1000000 - buf_frame;
if (slience_frames < 0) {
slience_frames = 0;
}
printf("-------slience_frames : %d-------\n", slience_frames);
sound_pcm_update_frame_num((void *)params[1], -slience_frames);
audio_mixer_ch_add_slience_samples(ch, slience_frames * sound_pcm_dev_channel_mapping(0));
}
}
break;
case MIXER_EVENT_CH_CLOSE:
if (priv) {
u32 *params = (u32 *)priv;
sound_pcm_dev_remove_syncts((void *)params[1]);
}
break;
}
}
#define RB16(b) (u16)(((u8 *)b)[0] << 8 | (((u8 *)b))[1])
#define RB32(b) (u32)(((u8 *)b)[0] << 24 | (((u8 *)b))[1] << 16 | (((u8 *)b))[2] << 8 | (((u8 *)b))[3])
static int get_rtp_header_len(u8 new_frame, u8 *buf, int len)
{
int ext, csrc;
int byte_len;
int header_len = 0;
u8 *data = buf;
csrc = buf[0] & 0x0f;
ext = buf[0] & 0x10;
byte_len = 12 + 4 * csrc;
buf += byte_len;
if (ext) {
ext = (RB16(buf + 2) + 1) << 2;
}
if (new_frame) {
header_len = byte_len + ext + (a2dp_dec->coding_type == AUDIO_CODING_AAC ? 0 : 1);
} else {
header_len = byte_len + ext;
}
if (header_len > len - 1) {
return len;
}
if (a2dp_dec->coding_type == AUDIO_CODING_SBC) {
for (; header_len < len; header_len++) {
if (data[header_len] == 0x9c) {
return header_len;
}
}
log_e("==== find sbc header error === \n");
put_buf(data, len);
}
return header_len;
}
__attribute__((weak))
int audio_dac_get_channel(struct audio_dac_hdl *p)
{
return 0;
}
void __a2dp_drop_frame(void *p)
{
int len;
u8 *frame;
#if 0
int num = a2dp_media_get_packet_num();
if (num > 1) {
for (int i = 0; i < num; i++) {
len = a2dp_media_get_packet(&frame);
if (len <= 0) {
break;
}
//printf("a2dp_drop_frame: %d\n", len);
a2dp_media_free_packet(frame);
}
}
#else
while (1) {
len = a2dp_media_try_get_packet(&frame);
if (len <= 0) {
break;
}
a2dp_media_free_packet(frame);
}
#endif
}
static void __a2dp_clean_frame_by_number(struct a2dp_dec_hdl *dec, u16 num)
{
u16 end_seqn = dec->seqn + num;
if (end_seqn == 0) {
end_seqn++;
}
/*__a2dp_drop_frame(NULL);*/
/*dec->drop_seqn = end_seqn;*/
a2dp_media_clear_packet_before_seqn(end_seqn);
}
static void a2dp_tws_clean_frame(void *arg)
{
u8 master = 0;
#if TCFG_USER_TWS_ENABLE
if (tws_api_get_role() == TWS_ROLE_MASTER) {
master = 1;
}
#else
master = 1;
#endif
if (!master) {
return;
}
int msecs = a2dp_media_get_remain_play_time(0);
if (msecs <= 0) {
return;
}
if (a2dp_dec && a2dp_dec->fetch_lock) {
return;
}
int len = 0;
u16 seqn = 0;
u8 *packet = a2dp_media_fetch_packet(&len, NULL);
if (!packet) {
return;
}
seqn = RB16(packet + 2) + 10;
if (seqn == 0) {
seqn = 1;
}
a2dp_media_clear_packet_before_seqn(seqn);
}
static u8 a2dp_suspend = 0;
static u32 a2dp_resume_time = 0;
int a2dp_decoder_pause(void)
{
if (a2dp_dec) {
return audio_decoder_pause(&(a2dp_dec->decoder));
}
return 0;
}
int a2dp_decoder_start(void)
{
if (a2dp_dec) {
return audio_decoder_start(&(a2dp_dec->decoder));
}
return 0;
}
u8 get_a2dp_drop_frame_flag()
{
if (a2dp_dec) {
return a2dp_dec->timer;
}
return 0;
}
void a2dp_drop_frame_start()
{
if (a2dp_dec && (a2dp_dec->timer == 0)) {
a2dp_dec->timer = sys_timer_add(NULL, __a2dp_drop_frame, 50);
a2dp_tws_audio_conn_offline();
}
}
void a2dp_drop_frame_stop()
{
if (a2dp_dec && a2dp_dec->timer) {
sys_timer_del(a2dp_dec->timer);
a2dp_tws_audio_conn_delete();
a2dp_dec->timer = 0;
}
}
static void a2dp_dec_set_output_channel(struct a2dp_dec_hdl *dec)
{
int state = 0;
enum audio_channel channel;
u8 dac_connect_mode = 0;
u8 ch_num = sound_pcm_dev_channel_mapping(1);
#if TCFG_USER_TWS_ENABLE
state = tws_api_get_tws_state();
if (state & TWS_STA_SIBLING_CONNECTED) {
if (ch_num == 2) {
channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_DUAL_L : AUDIO_CH_DUAL_R;
} else {
channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
}
} else {
if (ch_num == 2) {
channel = AUDIO_CH_LR;
} else {
channel = AUDIO_CH_DIFF;
}
}
dec->ch = ch_num;
#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
if (spatial_audio_enable || dec->spatial_audio) {
channel = AUDIO_CH_LR;
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
dec->ch = 2;
#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
//printf("Spatial Effect,ch:%d,%d\n",dec->ch,channel);
}
#endif/*CONFIG_TWS_SPATIAL_AUDIO_ENABLE*/
#else
if (ch_num == 2) {
channel = AUDIO_CH_LR;
} else {
channel = AUDIO_CH_DIFF;
}
dec->ch = ch_num;
#endif
#if TCFG_APP_FM_EMITTER_EN
channel = AUDIO_CH_LR;
#endif
if (channel != dec->channel) {
printf("set_channel: %d\n", channel);
#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
if (dec->spatial_audio) {
if (state & TWS_STA_SIBLING_CONNECTED) {
spatial_audio_set_mapping_channel(dec->spatial_audio, tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R);
} else {
spatial_audio_set_mapping_channel(dec->spatial_audio, AUDIO_CH_MIX_MONO);
}
}
#endif
audio_decoder_set_output_channel(&dec->decoder, channel);
dec->channel = channel;
#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
if (dec->eq_drc && dec->eq_drc->eq) {
audio_eq_set_channel(dec->eq_drc->eq, dec->ch);
}
#endif//TCFG_BT_MUSIC_EQ_ENABLE
/* #if TCFG_USER_TWS_ENABLE */
#if AUDIO_SURROUND_CONFIG
if (dec->sur) {
audio_surround_set_ch(dec->sur, channel);
}
#endif//AUDIO_SURROUND_CONFIG
/* #endif//TCFG_USER_TWS_ENABLE */
}
}
/*
*
*/
static int a2dp_decoder_set_timestamp(struct a2dp_dec_hdl *dec, u16 seqn)
{
#if AUDIO_CODEC_SUPPORT_SYNC
u32 timestamp;
timestamp = a2dp_audio_update_timestamp(dec->ts_handle, seqn, audio_syncts_get_dts(dec->syncts));
if (!dec->ts_start) {
dec->ts_start = 1;
dec->mix_ch_event_params[2] = timestamp;
} else {
audio_syncts_next_pts(dec->syncts, timestamp);
audio_syncts_update_sample_rate(dec->syncts, a2dp_audio_sample_rate(dec->ts_handle));;
}
dec->timestamp = timestamp;
/* printf("timestamp : %d, %d\n", seqn, timestamp / TIME_US_FACTOR / 625); */
#endif
return 0;
}
static bool a2dp_audio_is_underrun(struct a2dp_dec_hdl *dec)
{
#if AUDIO_CODEC_SUPPORT_SYNC
if (dec->ts_start != 2) {
return false;
}
#endif
int underrun_time = a2dp_low_latency ? 1 : 20;
if (sound_pcm_dev_buffered_time() < underrun_time) {
return true;
}
return false;
}
static bool a2dp_bt_rx_overrun(void)
{
return a2dp_media_get_remain_buffer_size() < 768 ? true : false;
}
static void a2dp_decoder_stream_free(struct a2dp_dec_hdl *dec, void *packet)
{
if (packet) {
a2dp_media_free_packet(packet);
}
if ((void *)packet == (void *)dec->repair_pkt) {
dec->repair_pkt = NULL;
}
if (dec->repair_pkt) {
a2dp_media_free_packet(dec->repair_pkt);
dec->repair_pkt = NULL;
}
dec->repair_pkt_len = 0;
}
static void a2dp_stream_underrun_feedback(void *priv);
static int a2dp_audio_delay_time(struct a2dp_dec_hdl *dec);
#define a2dp_seqn_before(a, b) ((a < b && (u16)(b - a) < 1000) || (a > b && (u16)(a - b) > 1000))
static int a2dp_buffered_stream_sample_rate(struct a2dp_dec_hdl *dec, u8 *from_packet, u16 *end_seqn)
{
u8 *packet = from_packet;
int len = 0;
int sample_rate = 0;
if (!dec->sample_detect) {
return dec->sample_rate;
}
a2dp_frame_sample_detect_start(dec->sample_detect, a2dp_media_dump_rx_time(packet));
while (1) {
packet = a2dp_media_fetch_packet(&len, packet);
if (!packet) {
break;
}
sample_rate = a2dp_frame_sample_detect(dec->sample_detect, packet, len, a2dp_media_dump_rx_time(packet));
*end_seqn = RB16(packet + 2);
}
/*printf("A2DP sample detect : %d - %d\n", sample_rate, dec->sample_rate);*/
return sample_rate;
}
static int a2dp_stream_overrun_handler(struct a2dp_dec_hdl *dec, u8 **frame, int *len)
{
u8 *packet = NULL;
int rlen = 0;
int msecs = 0;
int overrun = 0;
int sample_rate = 0;
u16 from_seqn = RB16(dec->repair_pkt + 2);
u16 seqn = from_seqn;
u16 end_seqn = 0;
overrun = 1;
while (1) {
msecs = a2dp_audio_delay_time(dec);
if (msecs < (CONFIG_A2DP_DELAY_TIME + 50) && !a2dp_bt_rx_overrun()) {
break;
}
overrun = 0;
rlen = a2dp_media_try_get_packet(&packet);
if (rlen <= 0) {
break;
}
sample_rate = a2dp_buffered_stream_sample_rate(dec, dec->repair_pkt, &end_seqn);
a2dp_decoder_stream_free(dec, NULL);
dec->repair_pkt = packet;
dec->repair_pkt_len = rlen;
seqn = RB16(packet + 2);
if (!a2dp_seqn_before(seqn, dec->overrun_seqn)) {
*frame = packet;
*len = rlen;
/*printf("------> end frame : %d\n", dec->overrun_seqn);*/
return 1;
}
if (/*sample_rate < (dec->sample_rate * 4 / 5) || */sample_rate > (dec->sample_rate * 4 / 3)) {
if (a2dp_seqn_before(dec->overrun_seqn, end_seqn)) {
dec->overrun_seqn = end_seqn;
}
continue;
}
}
if (overrun) {
/*putchar('+');*/
/* dec->overrun_seqn++; */
} else {
/*putchar('-');*/
}
*frame = dec->repair_pkt;
*len = dec->repair_pkt_len;
return 0;
}
static int a2dp_stream_missed_handler(struct a2dp_dec_hdl *dec, u8 **frame, int *len)
{
int msecs = a2dp_audio_delay_time(dec);
*frame = dec->repair_pkt;
*len = dec->repair_pkt_len;
if ((msecs >= (dec->delay_time + 50) || a2dp_bt_rx_overrun()) || --dec->missed_num == 0) {
/*putchar('M');*/
return 1;
}
/*putchar('m');*/
return 0;
}
static int a2dp_stream_underrun_handler(struct a2dp_dec_hdl *dec, u8 **packet)
{
if (!a2dp_audio_is_underrun(dec)) {
putchar('x');
return 0;
}
putchar('X');
if (dec->stream_error != A2DP_STREAM_UNDERRUN) {
if (!dec->stream_error) {
a2dp_stream_underrun_feedback(dec);
}
dec->stream_error = a2dp_low_latency ? A2DP_STREAM_LOW_UNDERRUN : A2DP_STREAM_UNDERRUN;
dec->repair = a2dp_low_latency ? 0 : 1;
}
*packet = dec->repair_pkt;
dec->repair_frames++;
return dec->repair_pkt_len;
}
static int a2dp_stream_error_filter(struct a2dp_dec_hdl *dec, u8 new_packet, u8 *packet, int len)
{
int err = 0;
if (dec->coding_type == AUDIO_CODING_AAC) {
dec->header_len = get_rtp_header_len(dec->new_frame, packet, len);
dec->new_frame = 0;
} else {
dec->header_len = get_rtp_header_len(1, packet, len);
}
if (dec->header_len >= len) {
printf("##A2DP header error : %d\n", dec->header_len);
a2dp_decoder_stream_free(dec, packet);
return -EFAULT;
}
u16 seqn = RB16(packet + 2);
if (new_packet) {
if (dec->stream_error == A2DP_STREAM_UNDERRUN) {
int missed_frames = (u16)(seqn - dec->seqn) - 1;
if (missed_frames > dec->repair_frames) {
dec->stream_error = A2DP_STREAM_MISSED;
dec->missed_num = missed_frames - dec->repair_frames + 1;
/*printf("case 0 : %d, %d\n", missed_frames, dec->repair_frames);*/
err = -EAGAIN;
} else if (missed_frames < dec->repair_frames) {
dec->stream_error = A2DP_STREAM_OVERRUN;
dec->overrun_seqn = seqn + dec->repair_frames - missed_frames;
/*printf("case 1 : %d, %d, seqn : %d, %d\n", missed_frames, dec->repair_frames, seqn, dec->overrun_seqn);*/
err = -EAGAIN;
}
} else if (!dec->stream_error && (u16)(seqn - dec->seqn) > 1) {
dec->stream_error = A2DP_STREAM_MISSED;
if (a2dp_audio_delay_time(dec) < dec->delay_time) {
dec->missed_num = (u16)(seqn - dec->seqn);
err = -EAGAIN;
}
int pkt_len;
void *head = a2dp_media_fetch_packet(&pkt_len, NULL);
/*printf("case 2 : %d, %d, pkt : 0x%x, 0x%x\n", seqn, dec->seqn, (u32)head, (u32)packet);*/
if (dec->missed_num > 30) {
printf("##A serious mistake : A2DP stream missed too much, %d\n", dec->missed_num);
dec->missed_num = 30;
}
}
dec->repair_frames = 0;
}
if (!err && new_packet) {
dec->seqn = seqn;
}
dec->repair_pkt = packet;
dec->repair_pkt_len = len;
return err;
}
static int a2dp_dec_get_frame(struct audio_decoder *decoder, u8 **frame)
{
struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
u8 *packet = NULL;
int len = 0;
u8 new_packet = 0;
try_again:
switch (dec->stream_error) {
case A2DP_STREAM_OVERRUN:
new_packet = a2dp_stream_overrun_handler(dec, &packet, &len);
break;
case A2DP_STREAM_MISSED:
new_packet = a2dp_stream_missed_handler(dec, &packet, &len);
break;
default:
len = a2dp_media_try_get_packet(&packet);
if (len <= 0) {
len = a2dp_stream_underrun_handler(dec, &packet);
} else {
a2dp_decoder_stream_free(dec, NULL);
new_packet = 1;
}
break;
}
if (len <= 0) {
return 0;
}
int err = a2dp_stream_error_filter(dec, new_packet, packet, len);
if (err) {
if (-err == EAGAIN) {
dec->new_frame = 1;
goto try_again;
}
return 0;
}
*frame = packet + dec->header_len;
len -= dec->header_len;
if (dec->stream_error && new_packet) {
#if AUDIO_CODEC_SUPPORT_SYNC && TCFG_USER_TWS_ENABLE
if (dec->ts_handle) {
tws_a2dp_share_timestamp(dec->ts_handle);
}
#endif
dec->stream_error = 0;
}
if (dec->slience_frames) {
dec->slience_frames--;
}
a2dp_decoder_set_timestamp(dec, dec->seqn);
return len;
}
static void a2dp_dec_put_frame(struct audio_decoder *decoder, u8 *frame)
{
struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
if (frame) {
if (!a2dp_media_channel_exist() || app_var.goto_poweroff_flag) {
a2dp_decoder_stream_free(dec, (void *)(frame - dec->header_len));
}
/*a2dp_media_free_packet((void *)(frame - dec->header_len));*/
}
}
static int a2dp_dec_fetch_frame(struct audio_decoder *decoder, u8 **frame)
{
struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
u8 *packet = NULL;
int len = 0;
u32 wait_timeout = 0;
if (!dec->start) {
wait_timeout = jiffies + msecs_to_jiffies(500);
}
dec->fetch_lock = 1;
__retry_fetch:
packet = a2dp_media_fetch_packet(&len, NULL);
if (packet) {
dec->header_len = get_rtp_header_len(1, packet, len);
*frame = packet + dec->header_len;
len -= dec->header_len;
} else if (!dec->start) {
if (time_before(jiffies, wait_timeout)) {
os_time_dly(1);
goto __retry_fetch;
}
}
dec->fetch_lock = 0;
return len;
}
static const struct audio_dec_input a2dp_input = {
.coding_type = AUDIO_CODING_SBC,
.data_type = AUDIO_INPUT_FRAME,
.ops = {
.frame = {
.fget = a2dp_dec_get_frame,
.fput = a2dp_dec_put_frame,
.ffetch = a2dp_dec_fetch_frame,
}
}
};
#define bt_time_before(t1, t2) \
(((t1 < t2) && ((t2 - t1) & 0x7ffffff) < 0xffff) || \
((t1 > t2) && ((t1 - t2) & 0x7ffffff) > 0xffff))
#define bt_time_to_msecs(clk) (((clk) * 625) / 1000)
#define msecs_to_bt_time(m) (((m + 1)* 1000) / 625)
static int a2dp_audio_delay_time(struct a2dp_dec_hdl *dec)
{
/*struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);*/
int msecs = 0;
#if TCFG_USER_TWS_ENABLE
msecs = a2dp_media_get_remain_play_time(1);
#else
msecs = a2dp_media_get_remain_play_time(0);
#endif
if (dec->syncts) {
msecs += sound_buffered_between_syncts_and_device(dec->syncts, 0);
}
msecs += sound_pcm_dev_buffered_time();
return msecs;
}
static int a2dp_dec_rx_delay_monitor(struct audio_decoder *decoder, struct rt_stream_info *info)
{
struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
int msecs = 0;
int err = 0;
#if AUDIO_CODEC_SUPPORT_SYNC
msecs = a2dp_audio_delay_time(dec);
if (dec->stream_error) {
return 0;
}
if (dec->sync_step == 2) {
int distance_time = msecs - a2dp_delay_time;
if (a2dp_bt_rx_overrun() && distance_time < 50) {
distance_time = 50;
}
if (dec->ts_handle) {
a2dp_audio_delay_offset_update(dec->ts_handle, distance_time);
}
}
#endif
/*printf("%d -> %dms, delay_time : %dms\n", msecs1, msecs, a2dp_delay_time);*/
return 0;
}
static int a2dp_decoder_stream_delay_update(struct audio_decoder *decoder)
{
struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
int msecs = 0;
int err = 0;
#if AUDIO_CODEC_SUPPORT_SYNC
msecs = a2dp_audio_delay_time(dec);
if (dec->stream_error) {
return 0;
}
if (dec->sync_step == 2) {
int distance_time = msecs - a2dp_delay_time;
if (a2dp_bt_rx_overrun() && distance_time < 50) {
distance_time = 50;
}
if (dec->ts_handle) {
a2dp_audio_delay_offset_update(dec->ts_handle, distance_time);
}
}
#endif
/*printf("%d -> %dms, delay_time : %dms\n", msecs1, msecs, a2dp_delay_time);*/
return 0;
}
/*
* A2DP
* 1.;
* 2.;
* 3.;
* 4.TWS从机加入与解码被打断的情况
*
*/
static int a2dp_decoder_audio_sync_handler(struct audio_decoder *decoder)
{
struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
int err;
if (!dec->syncts) {
return 0;
}
err = a2dp_decoder_stream_delay_update(decoder);
if (err) {
audio_decoder_suspend(decoder, 0);
return -EAGAIN;
}
return 0;
}
static u16 a2dp_max_interval = 0;
#define A2DP_EST_AUDIO_CAPACITY 550//ms
static void a2dp_stream_underrun_feedback(void *priv)
{
struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)priv;
dec->underrun_feedback = 1;
if (a2dp_delay_time < a2dp_max_interval + 50) {
a2dp_delay_time = a2dp_max_interval + 50;
} else {
a2dp_delay_time += 50;
}
if (a2dp_delay_time > A2DP_EST_AUDIO_CAPACITY) {
a2dp_delay_time = A2DP_EST_AUDIO_CAPACITY;
}
}
/*void a2dp_stream_interval_time_handler(int time)*/
void reset_a2dp_sbc_instant_time(u16 time)
{
if (a2dp_max_interval < time) {
a2dp_max_interval = time;
if (a2dp_max_interval > 350) {
a2dp_max_interval = 350;
}
#if A2DP_FLUENT_STREAM_MODE
if (a2dp_max_interval > a2dp_delay_time) {
a2dp_delay_time = a2dp_max_interval + 5;
if (a2dp_delay_time > A2DP_EST_AUDIO_CAPACITY) {
a2dp_delay_time = A2DP_EST_AUDIO_CAPACITY;
}
}
#endif
/*printf("Max : %dms\n", time);*/
}
}
static void a2dp_stream_stability_detect(void *priv)
{
struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)priv;
if (dec->underrun_feedback) {
dec->underrun_feedback = 0;
return;
}
if (a2dp_delay_time > dec->delay_time) {
if (a2dp_max_interval < a2dp_delay_time) {
a2dp_delay_time -= 50;
if (a2dp_delay_time < dec->delay_time) {
a2dp_delay_time = dec->delay_time;
}
if (a2dp_delay_time < a2dp_max_interval) {
a2dp_delay_time = a2dp_max_interval + 5;
}
}
a2dp_max_interval = dec->delay_time;
}
}
#if AUDIO_CODEC_SUPPORT_SYNC
static void a2dp_decoder_update_base_time(struct a2dp_dec_hdl *dec)
{
int distance_time = a2dp_low_latency ? a2dp_delay_time : (a2dp_delay_time - a2dp_media_get_remain_play_time(1));
if (!a2dp_low_latency) {
distance_time = a2dp_delay_time;
} else if (distance_time < 20) {
distance_time = 20;
}
dec->base_time = bt_audio_sync_lat_time() + msecs_to_bt_time(distance_time);
}
#endif
static int a2dp_decoder_stream_is_available(struct a2dp_dec_hdl *dec)
{
int err = 0;
u8 *packet = NULL;
int len = 0;
int drop = 0;
#if AUDIO_CODEC_SUPPORT_SYNC
if (dec->sync_step) {
return 0;
}
packet = (u8 *)a2dp_media_fetch_packet(&len, NULL);
if (!packet) {
return -EINVAL;
}
dec->seqn = RB16(packet + 2);
if (dec->ts_handle) {
#if TCFG_USER_TWS_ENABLE
if (!tws_network_audio_was_started() && !a2dp_audio_timestamp_is_available(dec->ts_handle, dec->seqn, 0, &drop)) {
if (drop) {
local_irq_disable();
u8 *check_packet = (u8 *)a2dp_media_fetch_packet(&len, NULL);
if (check_packet && RB16(check_packet + 2) == dec->seqn) {
a2dp_media_free_packet(packet);
}
local_irq_enable();
a2dp_decoder_update_base_time(dec);
a2dp_audio_set_base_time(dec->ts_handle, dec->base_time);
}
return -EINVAL;
}
#endif
}
dec->sync_step = 2;
#endif
return 0;
}
static int a2dp_dec_probe_handler(struct audio_decoder *decoder)
{
struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
int err = 0;
err = a2dp_decoder_stream_is_available(dec);
if (err) {
audio_decoder_suspend(decoder, 0);
return err;
}
err = a2dp_decoder_audio_sync_handler(decoder);
if (err) {
audio_decoder_suspend(decoder, 0);
return err;
}
dec->new_frame = 1;
a2dp_dec_set_output_channel(dec);
return err;
}
/*
*********************************************************************
*
* Description: a2dp高级音频解码输出句柄
* Arguments :
* Return :
* Note(s) : None.
*********************************************************************
*/
#if 0
static int a2dp_output_after_syncts_filter(void *priv, void *data, int len)
{
int wlen = 0;
int drop_len = 0;
struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)priv;
#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
if (dec->eq_drc && dec->eq_drc->async) {//异步方式eq
return eq_drc_run(dec->eq_drc, data, len);
}
#endif//TCFG_BT_MUSIC_EQ_ENABLE
return audio_mixer_ch_write(&dec->mix_ch, data, len);
}
#endif
static int a2dp_output_before_syncts_handler(struct a2dp_dec_hdl *dec, void *data, int len)
{
#if AUDIO_CODEC_SUPPORT_SYNC
if (dec->ts_start == 1) {
u32 timestamp = dec->timestamp;
u32 current_time = ((bt_audio_sync_lat_time() + (30000 / 625)) & 0x7ffffff) * 625 * TIME_US_FACTOR;
#define time_after_timestamp(t1, t2) \
((t1 > t2 && ((t1 - t2) < (10000000L * TIME_US_FACTOR))) || (t1 < t2 && ((t2 - t1) > (10000000L * TIME_US_FACTOR))))
if (!time_after_timestamp(timestamp, current_time)) {//时间戳与当前解码时间相差太近,直接丢掉
audio_syncts_resample_suspend(dec->syncts);
} else {
audio_syncts_resample_resume(dec->syncts);
dec->mix_ch_event_params[2] = timestamp;
dec->ts_start = 2;
}
}
#endif
return len;
}
static void audio_filter_resume_decoder(void *priv)
{
struct audio_decoder *decoder = (struct audio_decoder *)priv;
audio_decoder_resume(decoder);
}
static int a2dp_decoder_slience_plc_filter(struct a2dp_dec_hdl *dec, void *data, int len)
{
if (len == 0) {
a2dp_decoder_stream_free(dec, NULL);
if (!dec->stream_error) {
dec->stream_error = A2DP_STREAM_DECODE_ERR;
dec->repair = 1;
}
return 0;
}
if (dec->stream_error) {
memset(data, 0x0, len);
}
#if TCFG_USER_TWS_ENABLE
u8 tws_pairing = 0;
if (dec->preempt || tws_network_audio_was_started()) {
/*a2dp播放中副机加入声音淡入进去*/
tws_network_local_audio_start();
dec->preempt = 0;
tws_pairing = 1;
memset(data, 0x0, len);
dec->slience_frames = 30;
}
#endif
#if A2DP_AUDIO_PLC_ENABLE
if (dec->plc_ops) {
if (dec->slience_frames) {
dec->plc_ops->run(dec->plc_mem, data, data, len >> 1, 2);
} else if (dec->stream_error) {
dec->plc_ops->run(dec->plc_mem, data, data, len >> 1, dec->repair ? 1 : 2);
dec->repair = 0;
} else {
dec->plc_ops->run(dec->plc_mem, data, data, len >> 1, 0);
}
}
#else
if (dec->slience_frames) {
memset(data, 0x0, len);
}
#endif
return len;
}
#if 0
static int a2dp_output_async_data_handler(struct a2dp_dec_hdl *dec, s16 *data, int len)
{
int offset = 0;
int wlen = 0;
int data_len = len;
#if (CONFIG_AUDIO_EFFECT_TASK_ENABLE == 0)
#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
if (dec->spatial_audio) {
data_len = dec->spatial_data_len;
}
#endif
#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
#if AUDIO_CODEC_SUPPORT_SYNC
if (dec->syncts) {
int wlen = audio_syncts_frame_filter(dec->syncts, data, data_len);
if (wlen < data_len) {
audio_syncts_trigger_resume(dec->syncts, (void *)&dec->decoder, audio_filter_resume_decoder);
}
#if (CONFIG_AUDIO_EFFECT_TASK_ENABLE == 0)
#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
if (dec->spatial_audio) {
dec->spatial_data_len -= wlen;
}
#endif /*CONFIG_TWS_SPATIAL_AUDIO_ENABLE*/
#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
dec->remain = wlen < data_len ? 1 : 0;
return dec->remain ? wlen : len;
}
#endif
wlen = a2dp_output_after_syncts_filter(dec, data, data_len);
#if (CONFIG_AUDIO_EFFECT_TASK_ENABLE == 0)
#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
dec->spatial_data_len -= wlen;
#endif
#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
dec->remain = wlen < data_len ? 1 : 0;
return dec->remain ? wlen : len;
}
#endif
static void a2dp_stream_node_init(struct a2dp_dec_hdl *dec)
{
struct a2dp_stream_node *node = &dec->stream_node[A2DP_NODE_DECODER];
memset(dec->stream_node, 0x0, sizeof(dec->stream_node));
node->priv = (void *)&dec->decoder;
node->id = A2DP_NODE_DECODER;
node->wakeup = (void (*)(void *))audio_decoder_resume;
node->attribute = A2DP_NODE_BEGIN;
node = &dec->stream_node[A2DP_NODE_MAX];
node->attribute = A2DP_NODE_END;
node->id = A2DP_NODE_MAX;
dec->node_num = 1;
}
static void a2dp_stream_node_add(struct a2dp_dec_hdl *dec,
void *priv,
int (*data_handler)(void *, void *, int),
void (*wakeup)(void *),
int (*set_wakeup_handler)(void *, void *, void (*wakeup)(void *)),
u8 attribute)
{
struct a2dp_stream_node *node = &dec->stream_node[dec->node_num++];
node->id = dec->node_num - 1;
node->priv = priv;
node->data_handler = data_handler;
node->wakeup = wakeup;
node->set_wakeup_handler = set_wakeup_handler;
node->attribute |= attribute;
}
static void a2dp_stream_node_wakeup(void *priv)
{
struct a2dp_stream_node *node = (struct a2dp_stream_node *)priv;
struct a2dp_stream_node *prev_node = node - 1;
while (1) {
if (prev_node->wakeup) {
prev_node->wakeup(prev_node->priv);
break;
}
if (prev_node->attribute & A2DP_NODE_BEGIN) {
break;
}
prev_node--;
}
}
static void a2dp_stream_node_block_and_remain(struct a2dp_stream_node *node)
{
struct a2dp_stream_node *prev_node = node - 1;
if (node->set_wakeup_handler) {
node->set_wakeup_handler(node->priv, node, a2dp_stream_node_wakeup);
}
while (1) {
prev_node->remain = 1;
if ((prev_node->attribute & A2DP_NODE_BEGIN) || (prev_node->attribute & A2DP_NODE_BLOCK)) {
break;
}
prev_node--;
}
}
static int a2dp_stream_node_data_handler(void *priv, void *data, int len)
{
struct a2dp_stream_node *node = (struct a2dp_stream_node *)priv;
if (node->attribute & A2DP_NODE_END) {
return len;
}
while (1) {
node++;
if ((node->attribute & A2DP_NODE_END)) {
break;
}
if (!node->data_handler) {
continue;
}
if ((node->attribute & A2DP_NODE_BLOCK)) {
int wlen = node->data_handler(node->priv, data, len);
if (wlen < len) {
a2dp_stream_node_block_and_remain(node);
}
return wlen;
}
if (!node->remain) {
node->data_handler(node->priv, data, len);
}
node->remain = 0;
if (node->attribute & A2DP_NODE_SUB_STREAM_END) {
break;
}
}
return len;
}
static int a2dp_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
{
int wlen = 0;
struct a2dp_dec_hdl *dec = container_of(decoder, struct a2dp_dec_hdl, decoder);
return a2dp_stream_node_data_handler(&dec->stream_node[A2DP_NODE_DECODER], data, len);
#if 0
if (!dec->remain) {
wlen = a2dp_decoder_slience_plc_filter(dec, data, len);
if (wlen < len) {
return wlen;
}
#if (CONFIG_AUDIO_EFFECT_TASK_ENABLE == 0)
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
if (dec->spatial_audio) {
dec->spatial_data_len = spatial_audio_filter(dec->spatial_audio, data, len);
}
#endif
#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK)
aud_spatial_sensor_run();
#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK*/
//开空间音效的时候,软件数字音量在空间音效处理后面做
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
if (!spatial_audio_enable) {
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_run(MUSIC_DVOL, data, len);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
}
#endif /*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
a2dp_surround_vbass_handler(dec, data, len);
#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
if (dec->eq_drc && !dec->eq_drc->async) {//同步方式eq
eq_drc_run(dec->eq_drc, data, len);
}
#endif//TCFG_BT_MUSIC_EQ_ENABLE
a2dp_output_before_syncts_handler(dec, data, len);
}
#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
audio_anc_music_dynamic_gain_det(data, len);
#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
return a2dp_output_async_data_handler(dec, data, len);
#endif
}
static int a2dp_dec_post_handler(struct audio_decoder *decoder)
{
return 0;
}
static const struct audio_dec_handler a2dp_dec_handler = {
.dec_probe = a2dp_dec_probe_handler,
.dec_output = a2dp_dec_output_handler,
.dec_post = a2dp_dec_post_handler,
};
void a2dp_dec_close();
static void a2dp_dec_release()
{
audio_decoder_task_del_wait(&decode_task, &a2dp_dec->wait);
a2dp_drop_frame_stop();
local_irq_disable();
free(a2dp_dec);
a2dp_dec = NULL;
local_irq_enable();
}
static void a2dp_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
puts("AUDIO_DEC_EVENT_END\n");
a2dp_dec_close();
break;
}
}
static void a2dp_decoder_delay_time_setup(struct a2dp_dec_hdl *dec)
{
#if TCFG_USER_TWS_ENABLE
int a2dp_low_latency = tws_api_get_low_latency_state();
#endif
if (a2dp_low_latency) {
a2dp_delay_time = a2dp_dec->coding_type == AUDIO_CODING_AAC ? CONFIG_A2DP_DELAY_TIME_LO : CONFIG_A2DP_SBC_DELAY_TIME_LO;
/*空间音频跑异步任务时开低延时初始延时需要多10ms*/
#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && CONFIG_AUDIO_EFFECT_TASK_ENABLE)
a2dp_delay_time += 10;
#endif
} else {
a2dp_delay_time = CONFIG_A2DP_DELAY_TIME;
}
a2dp_max_interval = 0;
dec->delay_time = a2dp_delay_time;
dec->detect_timer = sys_timer_add((void *)dec, a2dp_stream_stability_detect, A2DP_FLUENT_DETECT_INTERVAL);
}
static int a2dp_decoder_syncts_setup(struct a2dp_dec_hdl *dec)
{
int err = 0;
#if AUDIO_CODEC_SUPPORT_SYNC
a2dp_stream_node_add(dec, dec, a2dp_output_before_syncts_handler, NULL, NULL, 0);
struct audio_syncts_params params = {0};
params.nch = dec->ch;
params.pcm_device = sound_pcm_sync_device_select();//PCM_INSIDE_DAC;
if (audio_mixer_get_sample_rate(&mixer)) {
params.rout_sample_rate = audio_mixer_get_sample_rate(&mixer);
} else {
params.rout_sample_rate = sound_pcm_match_sample_rate(dec->sample_rate);
}
params.network = AUDIO_NETWORK_BT2_1;
params.rin_sample_rate = dec->sample_rate;
params.priv = (void *)&dec->stream_node[dec->node_num];
params.factor = TIME_US_FACTOR;
params.output = a2dp_stream_node_data_handler;//a2dp_output_after_syncts_filter;
bt_audio_sync_nettime_select(0);//0 - a2dp主机1 - tws, 2 - BLE
a2dp_decoder_update_base_time(dec);
dec->ts_handle = a2dp_audio_timestamp_create(dec->sample_rate, dec->base_time, TIME_US_FACTOR);
err = audio_syncts_open(&dec->syncts, &params);
if (!err) {
dec->mix_ch_event_params[0] = (u32)&dec->mix_ch;
dec->mix_ch_event_params[1] = (u32)dec->syncts;
dec->mix_ch_event_params[2] = dec->base_time * 625 * TIME_US_FACTOR;
audio_mixer_ch_set_event_handler(&dec->mix_ch, (void *)dec->mix_ch_event_params, audio_mix_ch_event_handler);
}
dec->sync_step = 0;
a2dp_stream_node_add(dec, dec->syncts, audio_syncts_frame_filter, NULL, audio_syncts_trigger_resume, A2DP_NODE_BLOCK);
#endif
return err;
}
static void a2dp_decoder_syncts_free(struct a2dp_dec_hdl *dec)
{
#if AUDIO_CODEC_SUPPORT_SYNC
if (dec->ts_handle) {
a2dp_audio_timestamp_close(dec->ts_handle);
dec->ts_handle = NULL;
}
if (dec->syncts) {
audio_syncts_close(dec->syncts);
dec->syncts = NULL;
}
#endif
}
static int a2dp_decoder_plc_setup(struct a2dp_dec_hdl *dec)
{
#if A2DP_AUDIO_PLC_ENABLE
int plc_mem_size;
/*开空间音频没有使用独立任务处理时*/
#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && (!CONFIG_AUDIO_EFFECT_TASK_ENABLE))
u8 ch = 2;
#else
u8 ch = dec->ch;
#endif
dec->plc_ops = get_lfaudioPLC_api();
plc_mem_size = dec->plc_ops->need_buf(ch); // 3660bytes请衡量是否使用该空间换取PLC处理
dec->plc_mem = malloc(plc_mem_size);
if (!dec->plc_mem) {
dec->plc_ops = NULL;
return -ENOMEM;
}
dec->plc_ops->open(dec->plc_mem, ch, a2dp_low_latency ? 4 : 0);
a2dp_stream_node_add(dec, dec, a2dp_decoder_slience_plc_filter, NULL, NULL, 0);
#endif
return 0;
}
static void a2dp_decoder_plc_free(struct a2dp_dec_hdl *dec)
{
#if A2DP_AUDIO_PLC_ENABLE
if (dec->plc_mem) {
free(dec->plc_mem);
dec->plc_mem = NULL;
}
#endif
}
void a2dp_decoder_sample_detect_setup(struct a2dp_dec_hdl *dec)
{
dec->sample_detect = a2dp_sample_detect_open(dec->sample_rate, dec->coding_type);
}
void a2dp_decoder_sample_detect_free(struct a2dp_dec_hdl *dec)
{
if (dec->sample_detect) {
a2dp_sample_detect_close(dec->sample_detect);
dec->sample_detect = NULL;
}
}
static int a2dp_decoder_spatial_data_handler(void *priv, void *data, int len)
{
struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)priv;
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
if (!dec->spatial_data_len) {
dec->spatial_data_len = spatial_audio_filter(dec->spatial_audio, data, len);
dec->spatial_data_offset = 0;
}
if (dec->spatial_data_len) {
int wlen = a2dp_stream_node_data_handler(&dec->stream_node[dec->spatial_node_id], (u8 *)data + dec->spatial_data_offset, dec->spatial_data_len);
dec->spatial_data_offset += wlen;
dec->spatial_data_len -= wlen;
return dec->spatial_data_len ? 0 : len;
}
return 0;
#endif
}
void a2dp_decoder_spatial_audio_setup(struct a2dp_dec_hdl *dec)
{
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
if (spatial_audio_enable) {
dec->spatial_audio = spatial_audio_open();
a2dp_spatial_audio_head_tracked_en(spatial_audio_head_tracked);
/*clk_set("sys", SYS_128M);*/
#if CONFIG_TWS_SPATIAL_AUDIO_ENABLE
if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
spatial_audio_set_mapping_channel(dec->spatial_audio, tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R);
} else {
spatial_audio_set_mapping_channel(dec->spatial_audio, AUDIO_CH_MIX_MONO);
}
#endif
a2dp_stream_node_add(dec, dec, a2dp_decoder_spatial_data_handler, NULL, NULL, A2DP_NODE_BLOCK);
dec->spatial_node_id = dec->node_num - 1;
}
#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
}
static void a2dp_stream_read_spatial_audio_setup(struct a2dp_dec_hdl *dec)
{
#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK)
if (spatial_audio_head_tracked) {
aud_spatial_sensor_init();
a2dp_stream_node_add(dec, NULL, aud_spatial_sensor_run, NULL, NULL, 0);
}
#endif /*TCFG_SENSOR_DATA_READ_IN_DEC_TASK*/
}
#if (TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK)
typedef struct {
s16 sensor_buf[512];
cbuffer_t sensor_cbuf;
u16 period;
u32 next_period;
} aud_sensor_t;
aud_sensor_t *aud_sensor = NULL;
int aud_spatial_sensor_init()
{
int err = 0;
aud_sensor = zalloc(sizeof(aud_sensor_t));
printf("aud_spatial_sensor_init,need bufsize:%d\n", sizeof(aud_sensor_t));
if (aud_sensor) {
cbuf_init(&aud_sensor->sensor_cbuf, aud_sensor->sensor_buf, sizeof(aud_sensor->sensor_buf));
aud_sensor->period = TCFG_SENSOR_DATA_READ_INTERVAL;
aud_sensor->next_period = jiffies;
}
return err;
}
int aud_spatial_sensor_exit()
{
int err = 0;
printf("aud_spatial_sensor_exit\n");
if (aud_sensor) {
free(aud_sensor);
aud_sensor = NULL;
}
return err;
}
extern int spatial_audio_space_data_read(void *data);
/*定时读取传感器数据到cbuf*/
static s16 sensor_tmp_data[320];
int aud_spatial_sensor_run(void *priv, void *data, int len)
{
if (aud_sensor) {
if (time_after(jiffies, aud_sensor->next_period)) {
aud_sensor->next_period = jiffies + msecs_to_jiffies(aud_sensor->period);
int len = spatial_audio_space_data_read(sensor_tmp_data);
if (len) {
int wlen = cbuf_write(&aud_sensor->sensor_cbuf, sensor_tmp_data, len);
}
}
}
return len;
}
/*从cbuf读取传感器数据*/
int aud_spatial_sensor_data_read(s16 *data, int len)
{
int rlen = 0;
if (aud_sensor) {
local_irq_disable();
rlen = cbuf_read(&aud_sensor->sensor_cbuf, data, len);
local_irq_enable();
}
return rlen;
}
/*当前传感器数据量*/
int aud_spatial_sensor_get_data_len()
{
int len = 0;
if (aud_sensor) {
len = cbuf_get_data_len(&aud_sensor->sensor_cbuf);
}
return len;
}
#endif /*(TCFG_AUDIO_SPATIAL_EFFECT_ENABLE && TCFG_SENSOR_DATA_READ_IN_DEC_TASK)*/
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
#define AUD_EFFECT_INBUF_POINTS 1024
#else
#define AUD_EFFECT_INBUF_POINTS 512
#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
#define AUD_EFFECT_INBUF_SIZE (AUD_EFFECT_INBUF_POINTS << 1)
#define A2DP_AUDIO_EFFECT_RUN 1
#define A2DP_AUDIO_EFFECT_FLUSH 2
#define A2DP_AUDIO_EFFECT_STOP 3
#define AUDIO_EFFECT_RUN_LEN (AUD_EFFECT_INBUF_SIZE / 2)
typedef struct {
volatile u8 run_flush;
volatile u8 need_wakeup;
u8 output;
u8 trigger_resume;
u8 *buff;
u16 remain;
u16 run_len;
s16 *run_buff;
s16 output_buf[AUD_EFFECT_INBUF_POINTS];
s16 source_buf[AUD_EFFECT_INBUF_POINTS * 2];
cbuffer_t source_cbuf;
cbuffer_t output_cbuf;
void *entry_stream;
int (*entry_data_handler)(void *priv, void *data, int len);
void *output_priv;
int (*output_data_handler)(void *priv, void *data, int len);
void *resume_priv;
void (*resume_handler)(void *priv);
void *parent;
spinlock_t lock;
} aud_effect_t;
/*aud_effect_t *aud_effect = NULL;*/
int aud_effect_push_data(void *priv, s16 *data, u16 len)
{
int wlen = 0;
aud_effect_t *effect = (struct aud_effect *)priv;
if (!effect) {
return 0;
}
/*数据写入音效task的音源缓冲*/
wlen = cbuf_write(&effect->source_cbuf, data, len);
if (wlen < len) {
spin_lock(&effect->lock);
effect->trigger_resume = 1;
spin_unlock(&effect->lock);
} else {
os_taskq_post_msg("aud_effect", 2, A2DP_AUDIO_EFFECT_RUN, (int)effect);
}
do {
if (!effect->output) { /*还未确认运行数据长度*/
break;
}
if (!effect->remain) {
effect->run_len = AUDIO_EFFECT_RUN_LEN;
/*上次输出缓冲已消耗完*/
if (cbuf_get_data_len(&effect->output_cbuf) < effect->run_len) {
/*输出缓冲不足一次音效run的长度,这里主要使用音效一次run的长度作为运行的基数*/
break;
}
/*复用循环buffer作为输出的缓冲暂存*/
effect->buff = cbuf_get_readptr(&effect->output_cbuf);
effect->remain = effect->run_len;
}
int output_len = effect->output_data_handler(effect->output_priv, effect->buff, effect->remain);
/*printf("%d - %d\n", effect->remain, output_len);*/
effect->remain -= output_len;
effect->buff += output_len;
if (effect->remain) {
break;
}
/*输出完成后更新读指针并刷新至音效task*/
cbuf_read_updata(&effect->output_cbuf, effect->run_len);
spin_lock(&effect->lock);
if (effect->need_wakeup) {
effect->need_wakeup = 0;
os_taskq_post_msg("aud_effect", 2, A2DP_AUDIO_EFFECT_RUN, (int)effect);
}
spin_unlock(&effect->lock);
} while (1);
return wlen;
}
static void aud_effect_data_flush(aud_effect_t *effect)
{
if (effect->need_wakeup) {
effect->need_wakeup = 0;
}
}
static int aud_effect_output_data_handler(void *priv, void *data, int len)
{
aud_effect_t *effect = (aud_effect_t *)priv;
if (!effect->output) {
effect->output = 1;
}
spin_lock(&effect->lock);
if (!cbuf_is_write_able(&effect->output_cbuf, len)) {
effect->need_wakeup = 1;
spin_unlock(&effect->lock);
return 0;
}
spin_unlock(&effect->lock);
return cbuf_write(&effect->output_cbuf, data, len);
}
static void aud_effect_data_handler(void *priv)
{
aud_effect_t *effect = (aud_effect_t *)priv;
struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)effect->parent;
if (!effect) {
return;
}
while (1) {
if (cbuf_get_data_len(&effect->source_cbuf) < AUDIO_EFFECT_RUN_LEN) {
return;
}
effect->run_buff = cbuf_get_readptr(&effect->source_cbuf);
int run_len = AUDIO_EFFECT_RUN_LEN;
#if 0
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
if (dec->spatial_audio) {
run_len = spatial_audio_filter(dec->spatial_audio, effect->run_buff, run_len);
}
#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
#else
if (effect->entry_data_handler) {
run_len = effect->entry_data_handler(effect->entry_stream, effect->run_buff, run_len);
}
#endif
/*run_len = aud_effect_output_data_handler(effect, effect->run_buff, run_len);*/
/*printf("run : %d\n", run_len);*/
cbuf_read_updata(&effect->source_cbuf, run_len);
spin_lock(&effect->lock);
if (effect->trigger_resume) {
if (run_len) {
effect->resume_handler(effect->resume_priv);
}
effect->trigger_resume = 0;
}
spin_unlock(&effect->lock);
if (run_len < AUDIO_EFFECT_RUN_LEN) {
break;
}
}
}
static void aud_effect_task(void *p)
{
printf("===Audio Effect Task===\n");
int wlen = 0;
u8 pend = 1;
int msg[16];
int res;
while (1) {
if (pend) {
res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
} else {
res = os_taskq_accept(ARRAY_SIZE(msg), msg);
}
if (res == OS_TASKQ) {
switch (msg[1]) {
case A2DP_AUDIO_EFFECT_RUN:
aud_effect_data_handler((void *)msg[2]);
break;
case A2DP_AUDIO_EFFECT_FLUSH:
aud_effect_data_flush((aud_effect_t *)msg[2]);
break;
case A2DP_AUDIO_EFFECT_STOP:
os_taskq_flush();
os_sem_post((OS_SEM *)msg[2]);
break;
default:
break;
}
}
}
}
#endif /*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
int a2dp_decoder_effect_task_enter(struct a2dp_dec_hdl *dec)
{
int err = 0;
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
aud_effect_t *aud_effect = zalloc(sizeof(aud_effect_t));
printf("audio_dec_effect_process_start,need bufsize:%d\n", sizeof(aud_effect_t));
if (aud_effect) {
cbuf_init(&aud_effect->source_cbuf, aud_effect->source_buf, sizeof(aud_effect->source_buf));
cbuf_init(&aud_effect->output_cbuf, aud_effect->output_buf, sizeof(aud_effect->output_buf));
err = task_create(aud_effect_task, NULL, "aud_effect");
aud_effect->parent = (void *)dec;
aud_effect->resume_handler = (void (*)(void *))a2dp_stream_node_wakeup;
aud_effect->resume_priv = (void *)&dec->stream_node[dec->node_num];
aud_effect->entry_stream = (void *)&dec->stream_node[dec->node_num];
aud_effect->entry_data_handler = a2dp_stream_node_data_handler;
spin_lock_init(&aud_effect->lock);
dec->aud_effect = aud_effect;
a2dp_stream_node_add(dec, aud_effect, aud_effect_push_data, NULL, NULL, A2DP_NODE_SUB_STREAM_BEGIN | A2DP_NODE_BLOCK);
}
#endif
return err;
}
int a2dp_decoder_effect_task_output(struct a2dp_dec_hdl *dec)
{
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
if (dec->aud_effect) {
aud_effect_t *aud_effect = (aud_effect_t *)dec->aud_effect;
aud_effect->output_data_handler = a2dp_stream_node_data_handler;
aud_effect->output_priv = (void *)&dec->stream_node[dec->node_num];
a2dp_stream_node_add(dec, aud_effect, aud_effect_output_data_handler, NULL, NULL, A2DP_NODE_SUB_STREAM_END | A2DP_NODE_BLOCK);
}
#endif
return 0;
}
int audio_effect_process_stop(struct a2dp_dec_hdl *dec)
{
int err = 0;
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
aud_effect_t *aud_effect = (aud_effect_t *)dec->aud_effect;
printf("audio_effect_process_stop\n");
if (aud_effect) {
OS_SEM *sem = (OS_SEM *)malloc(sizeof(OS_SEM));
os_sem_create(sem, 0);
/*处理消息队列满了的情况*/
while (os_taskq_post_msg("aud_effect", 2, A2DP_AUDIO_EFFECT_STOP, (int)sem)) {
os_time_dly(2);
}
os_sem_pend(sem, 0);
free(sem);
task_kill("aud_effect");
free(aud_effect);
aud_effect = NULL;
}
dec->aud_effect = NULL;
#endif
return err;
}
static int a2dp_decoder_volume_run(void *priv, void *data, int len)
{
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_run((u8)priv, data, len);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
return len;
}
static void a2dp_decoder_volume_setup(struct a2dp_dec_hdl *dec)
{
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
a2dp_stream_node_add(dec, (void *)MUSIC_DVOL, a2dp_decoder_volume_run, NULL, NULL, 0);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
}
static int a2dp_anc_dynamic_gain_handler(void *priv, void *data, int len)
{
#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
audio_anc_music_dynamic_gain_det(data, len);
#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
return len;
}
static void a2dp_anc_dynamic_gain_setup(struct a2dp_dec_hdl *dec)
{
#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
audio_anc_music_dynamic_gain_init(dec->sample_rate);
a2dp_stream_node_add(dec, 0, a2dp_anc_dynamic_gain_handler, NULL, NULL, 0);
#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
}
static int a2dp_surround_vbass_handler(struct a2dp_dec_hdl *dec, void *data, int len);
static void a2dp_surround_vbass_setup(struct a2dp_dec_hdl *dec)
{
#if AUDIO_SURROUND_CONFIG
dec->sur = audio_surround_setup(dec->channel, a2dp_surround_eff);
#endif//AUDIO_SURROUND_CONFIG
#if AUDIO_VBASS_CONFIG
dec->vbass = audio_vbass_setup(dec->sample_rate, dec->ch);
#endif//AUDIO_VBASS_CONFIG
#if AUDIO_SURROUND_CONFIG || AUDIO_VBASS_CONFIG
a2dp_stream_node_add(dec, dec, a2dp_surround_vbass_handler, NULL, NULL, 0);
#endif
}
static int a2dp_surround_vbass_handler(struct a2dp_dec_hdl *dec, void *data, int len)
{
#if AUDIO_SURROUND_CONFIG
if (dec->sur && dec->sur->surround) {
audio_surround_run(dec->sur->surround, data, len);
}
#endif/*AUDIO_SURROUND_CONFIG*/
#if AUDIO_VBASS_CONFIG
if (dec->vbass) {
if (!dec->vbass->status) {
struct virtual_bass_tool_set *parm = get_vbass_parm();
GainProcess_16Bit(data, data, powf(10, parm->prev_gain / 20.0f), dec->ch, (dec->ch == 1 ? 1 : 2), (dec->ch == 1 ? 1 : 2), (len >> 1) / dec->ch);
}
audio_vbass_run(dec->vbass, data, len);
}
#endif/*AUDIO_VBASS_CONFIG*/
return len;
}
static void a2dp_eq_drc_setup(struct a2dp_dec_hdl *dec)
{
#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
u8 drc_en = 0;
#if TCFG_DRC_ENABLE&&TCFG_BT_MUSIC_DRC_ENABLE
drc_en = 1;
#endif//TCFG_BT_MUSIC_DRC_ENABLE
a2dp_decoder_sample_detect_setup(dec);
int async = 1;
#if defined(AUDIO_GAME_EFFECT_CONFIG) && AUDIO_GAME_EFFECT_CONFIG
if (a2dp_low_latency) {
drc_en |= BIT(1);
async = 0;
}
#endif /*AUDIO_GAME_EFFECT_CONFIG*/
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
async = 0;
#endif
u32 sample_rate = dec->sample_rate;
if (audio_mixer_get_sample_rate(&mixer)) {
sample_rate = audio_mixer_get_sample_rate(&mixer);
}
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
if (1) {//spatial_audio_enable) {
/*audio_effect_process_start(dec, &dec->mix_ch, audio_mixer_ch_write);*/
dec->eq_drc = dec_eq_drc_setup((void *)&dec->stream_node[dec->node_num], (eq_output_cb)a2dp_stream_node_data_handler, sample_rate, dec->ch, async, drc_en);
a2dp_stream_node_add(dec, dec->eq_drc, eq_drc_run, NULL, NULL, async ? A2DP_NODE_BLOCK : 0);
} else
#endif/*CONFIG_AUDIO_EFFECT_TASK_ENABLE*/
{
dec->eq_drc = dec_eq_drc_setup((void *)&dec->stream_node[dec->node_num], (eq_output_cb)a2dp_stream_node_data_handler, sample_rate, dec->ch, async, drc_en);
a2dp_stream_node_add(dec, dec->eq_drc, eq_drc_run, NULL, NULL, async ? A2DP_NODE_BLOCK : 0);
}
#endif//TCFG_BT_MUSIC_EQ_ENABLE
}
static void a2dp_bass_bost_setup(struct a2dp_dec_hdl *dec)
{
#if defined(TCFG_AUDIO_BASS_BOOST)&&TCFG_AUDIO_BASS_BOOST
dec->bass_boost = audio_bass_boost_open(dec->sample_rate, dec->ch);
a2dp_stream_node_add(dec, dec->bass_boost, audio_bass_boost_run, NULL, NULL, 0);
#endif
}
static int a2dp_effect_develop_setup(struct a2dp_dec_hdl *dec)
{
#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
dec->effect_develop = audio_effect_develop_open(dec->sample_rate, dec->ch, 16);
a2dp_stream_node_add(dec, dec->effect_develop, audio_effect_develop_data_handler, NULL, NULL, 0);
#endif
return 0;
}
static void a2dp_effect_develop_close(struct a2dp_dec_hdl *dec)
{
#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
if (dec->effect_develop) {
audio_effect_develop_close(dec->effect_develop);
dec->effect_develop = NULL;
}
#endif
}
void audio_overlay_load_code(u32 type);
int a2dp_dec_start()
{
int err;
struct audio_fmt *fmt;
enum audio_channel channel;
struct a2dp_dec_hdl *dec = a2dp_dec;
if (!a2dp_dec) {
return -EINVAL;
}
a2dp_drop_frame_stop();
puts("a2dp_dec_start: in\n");
if (a2dp_dec->coding_type == AUDIO_CODING_AAC) {
audio_overlay_load_code(a2dp_dec->coding_type);
}
err = audio_decoder_open(&dec->decoder, &a2dp_input, &decode_task);
if (err) {
goto __err1;
}
dec->channel = AUDIO_CH_MAX;
audio_decoder_set_handler(&dec->decoder, &a2dp_dec_handler);
audio_decoder_set_event_handler(&dec->decoder, a2dp_dec_event_handler, 0);
if (a2dp_dec->coding_type != a2dp_input.coding_type) {
struct audio_fmt f = {0};
f.coding_type = a2dp_dec->coding_type;
err = audio_decoder_set_fmt(&dec->decoder, &f);
if (err) {
goto __err2;
}
}
err = audio_decoder_get_fmt(&dec->decoder, &fmt);
if (err) {
goto __err2;
}
if (fmt->sample_rate == 0) {
log_w("A2DP stream maybe error\n");
goto __err2;
}
//dac_hdl.dec_channel_num = fmt->channel;
dec->sample_rate = fmt->sample_rate;
a2dp_dec_set_output_channel(dec);
a2dp_stream_node_init(dec);
a2dp_decoder_delay_time_setup(dec);
a2dp_decoder_plc_setup(dec);
#if !CONFIG_AUDIO_EFFECT_TASK_ENABLE /*当空间音效不在异步task中时放在解码后第二个节点效率最高*/
a2dp_decoder_spatial_audio_setup(dec);
#endif
a2dp_stream_read_spatial_audio_setup(dec);
set_source_sample_rate(fmt->sample_rate);
/*sound_pcm_set_underrun_params(3, dec, NULL);//a2dp_stream_underrun_feedback);*/
audio_mixer_ch_open(&dec->mix_ch, &mixer);
audio_mixer_ch_set_sample_rate(&dec->mix_ch, A2DP_SOUND_SAMPLE_RATE ? A2DP_SOUND_SAMPLE_RATE : sound_pcm_match_sample_rate(fmt->sample_rate));
#if !CONFIG_AUDIO_EFFECT_TASK_ENABLE
a2dp_decoder_volume_setup(dec);
#endif
a2dp_effect_develop_setup(dec);
a2dp_surround_vbass_setup(dec);
a2dp_bass_bost_setup(dec);
a2dp_anc_dynamic_gain_setup(dec);
a2dp_decoder_syncts_setup(dec);
a2dp_eq_drc_setup(dec);
a2dp_decoder_effect_task_enter(dec); /*enter到output的节点全部在effect task中执行*/
#if CONFIG_AUDIO_EFFECT_TASK_ENABLE
a2dp_decoder_spatial_audio_setup(dec);
a2dp_decoder_volume_setup(dec); /*数字音量处理放在空间音频之后处理*/
#endif
a2dp_decoder_effect_task_output(dec);
a2dp_stream_node_add(dec, &dec->mix_ch, (int (*)(void *, void *, int))audio_mixer_ch_write, NULL, NULL, A2DP_NODE_BLOCK);
audio_mixer_ch_set_resume_handler(&dec->mix_ch, &dec->stream_node[dec->node_num - 1], a2dp_stream_node_wakeup);
a2dp_drop_frame_stop();
dec->remain = 0;
audio_codec_clock_set(AUDIO_A2DP_MODE, dec->coding_type, dec->wait.preemption);
/* dec->state = A2DP_STREAM_START; */
err = audio_decoder_start(&dec->decoder);
if (err) {
goto __err3;
}
if (get_sniff_out_status()) {
clear_sniff_out_status();
}
sound_pcm_dev_try_power_on();
dec->start = 1;
return 0;
__err3:
audio_mixer_ch_close(&a2dp_dec->mix_ch);
__err2:
audio_decoder_close(&dec->decoder);
__err1:
a2dp_dec_release();
return err;
}
static int a2dp_dut_dec_start(void)
{
int err;
struct audio_fmt *fmt;
enum audio_channel channel;
struct a2dp_dec_hdl *dec = a2dp_dec;
if (!a2dp_dec) {
return -EINVAL;
}
a2dp_drop_frame_stop();
puts("a2dp_dut_dec_start: in\n");
if (a2dp_dec->coding_type == AUDIO_CODING_AAC) {
audio_overlay_load_code(a2dp_dec->coding_type);
}
err = audio_decoder_open(&dec->decoder, &a2dp_input, &decode_task);
if (err) {
goto __err1;
}
dec->channel = AUDIO_CH_MAX;
audio_decoder_set_handler(&dec->decoder, &a2dp_dec_handler);
audio_decoder_set_event_handler(&dec->decoder, a2dp_dec_event_handler, 0);
if (a2dp_dec->coding_type != a2dp_input.coding_type) {
struct audio_fmt f = {0};
f.coding_type = a2dp_dec->coding_type;
err = audio_decoder_set_fmt(&dec->decoder, &f);
if (err) {
goto __err2;
}
}
err = audio_decoder_get_fmt(&dec->decoder, &fmt);
if (err) {
goto __err2;
}
if (fmt->sample_rate == 0) {
log_w("A2DP stream maybe error\n");
goto __err2;
}
//dac_hdl.dec_channel_num = fmt->channel;
dec->sample_rate = fmt->sample_rate;
a2dp_dec_set_output_channel(dec);
a2dp_stream_node_init(dec);
a2dp_decoder_delay_time_setup(dec);
a2dp_decoder_plc_setup(dec);
set_source_sample_rate(fmt->sample_rate);
audio_mixer_ch_open(&dec->mix_ch, &mixer);
audio_mixer_ch_set_sample_rate(&dec->mix_ch, A2DP_SOUND_SAMPLE_RATE ? A2DP_SOUND_SAMPLE_RATE : sound_pcm_match_sample_rate(fmt->sample_rate));
//dut 需添加数字音量处理
a2dp_decoder_volume_setup(dec);
#if TCFG_AUDIO_CVP_DUT_ENABLE
if (audio_dec_dut_en_get(0) == AUDIO_DEC_DUT_MODE_SPK_EQ) {
a2dp_eq_drc_setup(dec);
}
#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
a2dp_decoder_syncts_setup(dec);
a2dp_stream_node_add(dec, &dec->mix_ch, (int (*)(void *, void *, int))audio_mixer_ch_write, NULL, NULL, A2DP_NODE_BLOCK);
audio_mixer_ch_set_resume_handler(&dec->mix_ch, &dec->stream_node[dec->node_num - 1], a2dp_stream_node_wakeup);
dec->remain = 0;
audio_codec_clock_set(AUDIO_A2DP_MODE, dec->coding_type, dec->wait.preemption);
err = audio_decoder_start(&dec->decoder);
if (err) {
goto __err3;
}
sound_pcm_dev_try_power_on();
dec->start = 1;
return 0;
__err3:
audio_mixer_ch_close(&a2dp_dec->mix_ch);
__err2:
audio_decoder_close(&dec->decoder);
__err1:
a2dp_dec_release();
return err;
}
static int __a2dp_audio_res_close(void)
{
a2dp_dec->start = 0;
if (a2dp_dec->detect_timer) {
sys_timer_del(a2dp_dec->detect_timer);
}
a2dp_decoder_sample_detect_free(a2dp_dec);
audio_decoder_close(&a2dp_dec->decoder);
audio_effect_process_stop(a2dp_dec);
audio_mixer_ch_close(&a2dp_dec->mix_ch);
a2dp_decoder_syncts_free(a2dp_dec);
a2dp_decoder_plc_free(a2dp_dec);
a2dp_effect_develop_close(a2dp_dec);
a2dp_decoder_stream_free(a2dp_dec, NULL);
#if TCFG_EQ_ENABLE&&TCFG_BT_MUSIC_EQ_ENABLE
if (a2dp_dec->eq_drc) {
dec_eq_drc_free(a2dp_dec->eq_drc);
a2dp_dec->eq_drc = NULL;
}
#endif//TCFG_BT_MUSIC_EQ_ENABLE
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
if (a2dp_dec->spatial_audio) {
spatial_audio_close(a2dp_dec->spatial_audio);
a2dp_dec->spatial_audio = NULL;
}
#if TCFG_SENSOR_DATA_READ_IN_DEC_TASK
aud_spatial_sensor_exit();
#endif /*TCFG_SENSOR_DATA_READ_IN_DEC_TASK*/
#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
#if AUDIO_SURROUND_CONFIG
if (a2dp_dec->sur) {
audio_surround_free(a2dp_dec->sur);
a2dp_dec->sur = NULL;
}
#endif//AUDIO_SURROUND_CONFIG
#if AUDIO_VBASS_CONFIG
if (a2dp_dec->vbass) {
audio_vbass_free(a2dp_dec->vbass);
a2dp_dec->vbass = NULL;
}
#endif//AUDIO_VBASS_CONFIG
#if defined(TCFG_AUDIO_BASS_BOOST) && TCFG_AUDIO_BASS_BOOST
if (a2dp_dec->bass_boost) {
audio_bass_boost_close(a2dp_dec->bass_boost);
a2dp_dec->bass_boost = NULL;
}
#endif
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_close(MUSIC_DVOL);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
#if 0
clk_set_sys_lock(BT_NORMAL_HZ, 0);
#else
audio_codec_clock_del(AUDIO_A2DP_MODE);
#endif
a2dp_dec->preempt = 1;
app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
return 0;
}
static int a2dp_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
if (event == AUDIO_RES_GET) {
printf("a2dp_res:Get\n");
if (a2dp_dec->dut_enable) {
err = a2dp_dut_dec_start();
} else {
err = a2dp_dec_start();
}
} else if (event == AUDIO_RES_PUT) {
printf("a2dp_res:Put\n");
if (a2dp_dec->start) {
__a2dp_audio_res_close();
a2dp_drop_frame_start();
}
}
return err;
}
#define A2DP_CODEC_SBC 0x00
#define A2DP_CODEC_MPEG12 0x01
#define A2DP_CODEC_MPEG24 0x02
#define A2DP_CODEC_LDAC 0x0B
int __a2dp_dec_open(int media_type, u8 resume, u8 dut_enable)
{
#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_MUSIC_MUTEX)
/*辅听与播歌互斥时,关闭辅听*/
if (get_hearing_aid_fitting_state() == 0) {
audio_hearing_aid_suspend();
}
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
struct a2dp_dec_hdl *dec;
if (strcmp(os_current_task(), "app_core") != 0) {
log_e("a2dp dec open in task : %s\n", os_current_task());
}
if (a2dp_suspend) {
if (tws_api_get_role() == TWS_ROLE_MASTER) {
if (drop_a2dp_timer == 0) {
drop_a2dp_timer = sys_timer_add(NULL,
a2dp_media_clear_packet_before_seqn, 100);
}
}
return 0;
}
if (a2dp_dec) {
return 0;
}
media_type = a2dp_media_get_codec_type();
printf("a2dp_dec_open: %d\n", media_type);
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
switch (media_type) {
case A2DP_CODEC_SBC:
printf("a2dp_media_type:SBC");
dec->coding_type = AUDIO_CODING_SBC;
break;
case A2DP_CODEC_MPEG24:
printf("a2dp_media_type:AAC");
dec->coding_type = AUDIO_CODING_AAC;
break;
case A2DP_CODEC_LDAC:
printf("a2dp_media_type:LDAC");
dec->coding_type = AUDIO_CODING_LDAC;
break;
default:
printf("a2dp_media_type unsupoport:%d", media_type);
free(dec);
return -EINVAL;
}
#if TCFG_USER_TWS_ENABLE
if (CONFIG_LOW_LATENCY_ENABLE) {
a2dp_low_latency = tws_api_get_low_latency_state();
}
#endif
a2dp_dec = dec;
dec->preempt = resume ? 1 : 0;
dec->wait.priority = 0;
dec->wait.preemption = 1;
dec->wait.handler = a2dp_wait_res_handler;
dec->dut_enable = dut_enable;
audio_decoder_task_add_wait(&decode_task, &dec->wait);
#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE)
/*辅听验配过程不允许播放歌曲*/
extern u8 get_hearing_aid_fitting_state(void);
if (get_hearing_aid_fitting_state()) {
printf("hearing aid fitting : %d\n !!!", get_hearing_aid_fitting_state());
extern a2dp_tws_dec_suspend(void *p);
a2dp_tws_dec_suspend(NULL);
return 0;
}
#endif /*TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_FITTING_ENABLE*/
if (a2dp_dec && (a2dp_dec->start == 0)) {
a2dp_drop_frame_start();
}
return 0;
}
int a2dp_dec_open(int media_type)
{
#if TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
if (get_speak_to_chat_state() == AUDIO_ADT_CHAT) {
audio_speak_to_char_sync_suspend();
}
#endif
return __a2dp_dec_open(media_type, 0, 0);
}
int a2dp_dut_dec_open(int media_type)
{
return __a2dp_dec_open(media_type, 0, 1);
}
void a2dp_dec_close()
{
if (!a2dp_dec) {
if (CONFIG_LOW_LATENCY_ENABLE) {
a2dp_low_latency_seqn = 0;
}
if (drop_a2dp_timer) {
sys_timer_del(drop_a2dp_timer);
drop_a2dp_timer = 0;
}
return;
}
if (a2dp_dec->start) {
__a2dp_audio_res_close();
}
a2dp_dec_release();
#if TCFG_AUDIO_ANC_ENABLE && ANC_MUSIC_DYNAMIC_GAIN_EN
audio_anc_music_dynamic_gain_reset(1);
#endif/*ANC_MUSIC_DYNAMIC_GAIN_EN*/
#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_MUSIC_MUTEX)
audio_hearing_aid_resume();
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
puts("a2dp_dec_close: exit\n");
}
void a2dp_dec_dut_enable(u8 dut_enable)
{
if (!a2dp_dec) {
return;
}
if (a2dp_dec->start) {
a2dp_dec_close();
if (dut_enable) {
a2dp_dut_dec_open(0);
} else {
a2dp_dec_open(0);
}
}
}
//*********************************************************************************//
// 空间音效接口(Spatial Effect APIs) //
//*********************************************************************************//
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
int a2dp_spatial_audio_open(void)
{
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
spatial_audio_enable = 1;
if (a2dp_dec && !a2dp_dec->spatial_audio) {
a2dp_dec->spatial_audio = spatial_audio_open();
}
#endif
return 0;
}
void a2dp_spatial_audio_close(void)
{
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
local_irq_disable();
if (a2dp_dec && a2dp_dec->spatial_audio) {
spatial_audio_close(a2dp_dec->spatial_audio);
a2dp_dec->spatial_audio = NULL;
}
spatial_audio_enable = 0;
spatial_audio_head_tracked = 0;
local_irq_enable();
#endif
}
u8 get_a2dp_spatial_audio_status(void)
{
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
if (a2dp_dec) {
return (a2dp_dec->spatial_audio != NULL) ? 1 : 0;
}
#endif
return 0;
}
u8 get_spatial_audio_enable()
{
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
return spatial_audio_enable;
#endif
return 0;
}
void a2dp_spatial_audio_head_tracked_en(u8 en)
{
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
if (a2dp_dec && a2dp_dec->spatial_audio) {
spatial_audio_head_tracked = en;
spatial_audio_head_tracked_en(a2dp_dec->spatial_audio, en);
}
#endif
}
u8 get_a2dp_spatial_audio_head_tracked(void)
{
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
return spatial_audio_head_tracked;
#endif
return 0;
}
void a2dp_spatial_audio_setup(u8 en, u8 head_track)
{
spatial_audio_enable = en;
spatial_audio_head_tracked = head_track;
}
int a2dp_tws_dec_suspend(void *p);
void a2dp_tws_dec_resume(void);
/*
mode:
0:
1:
2:
tone_play:
1 :
0 :
*/
void audio_spatial_effects_mode_switch(u8 mode, u8 tone_play)
{
u8 tone_index = 0;
if (a2dp_dec) {
/*先挂起再改变标志*/
a2dp_tws_dec_suspend(a2dp_dec);
if (mode == 0) {
printf("SpatialAudio:close_fixed");
a2dp_spatial_audio_setup(0, 0);
tone_index = IDEX_TONE_NUM_0;
} else if (mode == 1) {
printf("SpatialAudio:open_fixed");
a2dp_spatial_audio_setup(1, 0);
tone_index = IDEX_TONE_NUM_1;
} else if (mode == 2) {
printf("SpatialAudio:open_tracked");
a2dp_spatial_audio_setup(1, 1);
tone_index = IDEX_TONE_NUM_2;
}
a2dp_tws_dec_resume();
if (tone_play) {
tone_play_index(tone_index, 1);
}
}
}
#endif/*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
static void a2dp_low_latency_clear_a2dp_packet(u8 *data, int len, int rx)
{
if (rx) {
a2dp_low_latency_seqn = (data[0] << 8) | data[1];
}
}
REGISTER_TWS_FUNC_STUB(audio_dec_clear_a2dp_packet) = {
.func_id = 0x132A6578,
.func = a2dp_low_latency_clear_a2dp_packet,
};
static void low_latency_drop_a2dp_frame(void *p)
{
int len;
/*y_printf("low_latency_drop_a2dp_frame\n");*/
if (a2dp_low_latency_seqn == 0) {
a2dp_media_clear_packet_before_seqn(0);
return;
}
while (1) {
u8 *packet = a2dp_media_fetch_packet(&len, NULL);
if (!packet) {
return;
}
u16 seqn = (packet[2] << 8) | packet[3];
if (seqn_after(seqn, a2dp_low_latency_seqn)) {
printf("clear_end: %d\n", seqn);
break;
}
a2dp_media_free_packet(packet);
/*printf("clear: %d\n", seqn);*/
}
if (drop_a2dp_timer) {
sys_timer_del(drop_a2dp_timer);
drop_a2dp_timer = 0;
}
int type = a2dp_media_get_codec_type();
if (type >= 0) {
/*a2dp_dec_open(type);*/
__a2dp_dec_open(type, 1, 0);
}
if (a2dp_low_latency == 0) {
tws_api_auto_role_switch_enable();
}
printf("a2dp_delay: %d\n", a2dp_media_get_remain_play_time(1));
}
int earphone_a2dp_codec_set_low_latency_mode(int enable, int msec)
{
int ret = 0;
int len, err;
if (CONFIG_LOW_LATENCY_ENABLE == 0) {
return -EINVAL;
}
if (esco_dec) {
return -EINVAL;
}
if (drop_a2dp_timer) {
return -EINVAL;
}
if (a2dp_suspend) {
return -EINVAL;
}
a2dp_low_latency = enable;
a2dp_low_latency_seqn = 0;
r_printf("a2dp_low_latency: %d, %d, %d\n", a2dp_dec->seqn, a2dp_delay_time, enable);
if (!a2dp_dec || a2dp_dec->start == 0) {
#if TCFG_USER_TWS_ENABLE
tws_api_low_latency_enable(enable);
#endif
return 0;
}
if (a2dp_dec->coding_type == AUDIO_CODING_SBC) {
a2dp_low_latency_seqn = a2dp_dec->seqn + (msec + a2dp_delay_time) / 15;
} else {
a2dp_low_latency_seqn = a2dp_dec->seqn + (msec + a2dp_delay_time) / 20;
}
#if TCFG_USER_TWS_ENABLE
u8 data[2];
data[0] = a2dp_low_latency_seqn >> 8;
data[1] = a2dp_low_latency_seqn;
err = tws_api_send_data_to_slave(data, 2, 0x132A6578);
if (err == -ENOMEM) {
return -EINVAL;
}
#endif
a2dp_dec_close();
a2dp_media_clear_packet_before_seqn(0);
#if TCFG_USER_TWS_ENABLE
if (enable) {
tws_api_auto_role_switch_disable();
}
tws_api_low_latency_enable(enable);
#endif
drop_a2dp_timer = sys_timer_add(NULL, low_latency_drop_a2dp_frame, 40);
/*r_printf("clear_to_seqn: %d\n", a2dp_low_latency_seqn);*/
return 0;
}
int earphone_a2dp_codec_get_low_latency_mode()
{
#if TCFG_USER_TWS_ENABLE
return tws_api_get_low_latency_state();
#endif
return a2dp_low_latency;
}
int a2dp_tws_dec_suspend(void *p)
{
r_printf("a2dp_tws_dec_suspend\n");
/*mem_stats();*/
if (a2dp_suspend) {
return -EINVAL;
}
a2dp_suspend = 1;
if (a2dp_dec) {
a2dp_dec_close();
a2dp_media_clear_packet_before_seqn(0);
if (tws_api_get_role() == 0) {
drop_a2dp_timer = sys_timer_add(NULL, (void (*)(void *))a2dp_media_clear_packet_before_seqn, 100);
}
}
int err = audio_decoder_fmt_lock(&decode_task, AUDIO_CODING_AAC);
if (err) {
log_e("AAC_dec_lock_faild\n");
}
return err;
}
void a2dp_tws_dec_resume(void)
{
r_printf("a2dp_tws_dec_resume\n");
if (a2dp_suspend) {
a2dp_suspend = 0;
if (drop_a2dp_timer) {
sys_timer_del(drop_a2dp_timer);
drop_a2dp_timer = 0;
}
audio_decoder_fmt_unlock(&decode_task, AUDIO_CODING_AAC);
int type = a2dp_media_get_codec_type();
printf("codec_type: %d\n", type);
if (type >= 0) {
if (tws_api_get_role() == 0) {
a2dp_media_clear_packet_before_seqn(0);
}
a2dp_resume_time = jiffies + msecs_to_jiffies(80);
/*a2dp_dec_open(type);*/
__a2dp_dec_open(type, 1, 0);
}
}
}