Files
99_7018_lmx/cpu/br28/a2dp_dec.c
2025-10-29 13:10:02 +08:00

2872 lines
80 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*************************************************************************************************/
/*!
* \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);
}
}
}