KT25-0812_82A-UART/cpu/br25/audio_dec/audio_dec_bt.c
2025-08-12 18:09:23 +08:00

1381 lines
38 KiB
C
Raw Permalink 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.

#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "media/a2dp_decoder.h"
#include "media/esco_decoder.h"
#include "classic/tws_api.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "audio_digital_vol.h"
#include "clock_cfg.h"
#include "btstack/a2dp_media_codec.h"
#include "application/audio_eq_drc_apply.h"
#include "application/audio_equalloudness.h"
#include "application/audio_surround.h"
#include "application/audio_vbass.h"
#include "aec_user.h"
#include "audio_enc.h"
#include "bt_tws.h"
#if TCFG_ESCO_PLC
#include "PLC.h"
#define PLC_FRAME_LEN 60
#endif/*TCFG_ESCO_PLC*/
#if TCFG_ESCO_LIMITER
#include "limiter_noiseGate_api.h"
/*限幅器上限*/
#define LIMITER_THR -10000 /*-12000 = -12dB,放大1000倍,(-10000参考)*/
/*小于CONST_NOISE_GATE的当成噪声处理,防止清0近端声音*/
#define LIMITER_NOISE_GATE -30000 /*-12000 = -12dB,放大1000倍,(-30000参考)*/
/*低于噪声门限阈值的增益 */
#define LIMITER_NOISE_GAIN (0 << 30) /*(0~1)*2^30*/
#endif/*TCFG_ESCO_LIMITER*/
#define TCFG_ESCO_USE_SPEC_MIX_LEN 0
extern const int CONFIG_A2DP_DELAY_TIME;
extern const int config_mixer_en;
#define AUDIO_DEC_BT_MIXER_EN config_mixer_en
//////////////////////////////////////////////////////////////////////////////
struct a2dp_dec_hdl {
struct a2dp_decoder dec; // a2dp解码句柄
struct audio_res_wait wait; // 资源等待句柄
struct audio_mixer_ch mix_ch; // 叠加句柄
#if (RECORDER_MIX_EN)
struct audio_mixer_ch rec_mix_ch; // 叠加句柄
#endif//RECORDER_MIX_EN
struct audio_stream *stream; // 音频流
struct audio_eq_drc *eq_drc; //eq drc句柄
#if AUDIO_EQUALLOUDNESS_CONFIG
equal_loudness_hdl *loudness; //等响度句柄
#endif
#if AUDIO_SURROUND_CONFIG
surround_hdl *surround; //环绕音效句柄
#endif
#if AUDIO_VBASS_CONFIG
vbass_hdl *vbass; //虚拟低音句柄
#endif
struct audio_wireless_sync *sync;
};
struct esco_dec_hdl {
struct esco_decoder dec; // esco解码句柄
struct audio_res_wait wait; // 资源等待句柄
struct audio_mixer_ch mix_ch; // 叠加句柄
#if (RECORDER_MIX_EN)
struct audio_mixer_ch rec_mix_ch; // 叠加句柄
#endif//RECORDER_MIX_EN
struct audio_stream *stream; // 音频流
struct audio_eq_drc *eq_drc; //eq drc句柄
u32 tws_mute_en : 1; // 静音
u32 remain : 1; // 未输出完成
#if TCFG_ESCO_PLC
void *plc; // 丢包修护
#endif
#if TCFG_ESCO_LIMITER
void *limiter; // 限福器
#endif
struct audio_wireless_sync *sync;
};
//////////////////////////////////////////////////////////////////////////////
struct a2dp_dec_hdl *bt_a2dp_dec = NULL;
struct esco_dec_hdl *bt_esco_dec = NULL;
extern s16 mix_buff[];
extern s16 recorder_mix_buff[];
extern struct audio_dac_hdl dac_hdl;
//////////////////////////////////////////////////////////////////////////////
void *a2dp_eq_drc_open(u16 sample_rate, u8 ch_num);
void a2dp_eq_drc_close(struct audio_eq_drc *eq_drc);
void *esco_eq_drc_open(u16 sample_rate, u8 ch_num);
void esco_eq_drc_close(struct audio_eq_drc *eq_drc);
struct audio_wireless_sync *a2dp_output_sync_open(u8 entry_select);
void a2dp_output_sync_close(struct audio_wireless_sync *a2dp_sync);
struct audio_wireless_sync *esco_output_sync_open(u8 entry_select);
void esco_output_sync_close(struct audio_wireless_sync *esco_sync);
extern int lmp_private_esco_suspend_resume(int flag);
surround_hdl *surround_open_demo(u8 ch_num);
void surround_close(surround_hdl *surround);
vbass_hdl *vbass_open_demo(u16 sample_rate, u8 ch_num);
void vbass_close_demo(vbass_hdl *vbass);
/*----------------------------------------------------------------------------*/
/**@brief a2dp解码close
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void a2dp_audio_res_close(void)
{
if (bt_a2dp_dec->dec.start == 0) {
log_i("bt_a2dp_dec->dec.start == 0");
return ;
}
bt_a2dp_dec->dec.start = 0;
a2dp_decoder_close(&bt_a2dp_dec->dec);
a2dp_eq_drc_close(bt_a2dp_dec->eq_drc);
if (AUDIO_DEC_BT_MIXER_EN) {
audio_mixer_ch_close(&bt_a2dp_dec->mix_ch);
} else {
dac_hdl.entry.prob_handler = NULL;
audio_dac_stop(&dac_hdl);
}
#if (RECORDER_MIX_EN)
audio_mixer_ch_close(&bt_a2dp_dec->rec_mix_ch);
#endif//RECORDER_MIX_EN
a2dp_output_sync_close(bt_a2dp_dec->sync);
bt_a2dp_dec->sync = NULL;
if (bt_a2dp_dec->stream) {
audio_stream_close(bt_a2dp_dec->stream);
bt_a2dp_dec->stream = NULL;
}
app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
}
/*----------------------------------------------------------------------------*/
/**@brief a2dp解码释放
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void a2dp_dec_release()
{
audio_decoder_task_del_wait(&decode_task, &bt_a2dp_dec->wait);
a2dp_drop_frame_stop();
if (bt_a2dp_dec->dec.coding_type == AUDIO_CODING_SBC) {
clock_remove(DEC_SBC_CLK);
} else if (bt_a2dp_dec->dec.coding_type == AUDIO_CODING_AAC) {
clock_remove(DEC_AAC_CLK);
}
local_irq_disable();
free(bt_a2dp_dec);
bt_a2dp_dec = NULL;
local_irq_enable();
}
/*----------------------------------------------------------------------------*/
/**@brief a2dp解码事件返回
@param *decoder: 解码器句柄
@param argc: 参数个数
@param *argv: 参数
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void a2dp_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
log_i("AUDIO_DEC_EVENT_END\n");
a2dp_dec_close();
break;
}
}
/*----------------------------------------------------------------------------*/
/**@brief a2dp解码数据流激活
@param *p: 私有句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void a2dp_dec_out_stream_resume(void *p)
{
struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)p;
audio_decoder_resume(&dec->dec.decoder);
}
void a2dp_rx_notice_to_decode(void)
{
if (bt_a2dp_dec && bt_a2dp_dec->dec.start) {
a2dp_decoder_resume_from_bluetooth(&bt_a2dp_dec->dec);
}
}
static int a2dp_to_dac_probe_handler(struct audio_stream_entry *entry, struct audio_data_frame *in)
{
if (!in->stop/* && in->data_len*/) {
if (bt_a2dp_dec->sync) {
in->data_sync = 1;
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief 开始a2dp解码
@param
@return 0: 成功
@note
*/
/*----------------------------------------------------------------------------*/
static int a2dp_dec_start(void)
{
int err;
struct audio_fmt *fmt;
struct a2dp_dec_hdl *dec = bt_a2dp_dec;
u8 ch_num = 0;
u8 ch_type = 0;
if (!bt_a2dp_dec) {
return -EINVAL;
}
log_i("a2dp_dec_start: in\n");
err = a2dp_decoder_open(&dec->dec, &decode_task);
if (err) {
goto __err1;
}
audio_decoder_set_event_handler(&dec->dec.decoder, a2dp_dec_event_handler, 0);
err = audio_decoder_get_fmt(&dec->dec.decoder, &fmt);
if (err) {
goto __err2;
}
ch_num = audio_output_channel_num();
ch_type = audio_output_channel_type();
a2dp_decoder_set_output_channel(&dec->dec, ch_num, ch_type);
if (AUDIO_DEC_BT_MIXER_EN) {
audio_mode_main_dec_open(AUDIO_MODE_MAIN_STATE_DEC_A2DP);
audio_mixer_ch_open_head(&dec->mix_ch, &mixer); // 挂载到mixer最前面
audio_mixer_ch_set_src(&dec->mix_ch, 1, 0);
audio_mixer_ch_set_no_wait(&dec->mix_ch, 1, 10); // 超时自动丢数
audio_mixer_ch_sample_sync_enable(&dec->mix_ch, 1);
}
#if (RECORDER_MIX_EN)
audio_mixer_ch_open_head(&dec->rec_mix_ch, &recorder_mixer); // 挂载到mixer最前面
audio_mixer_ch_set_src(&dec->rec_mix_ch, 1, 0);
audio_mixer_ch_set_no_wait(&dec->rec_mix_ch, 1, 10); // 超时自动丢数
/* audio_mixer_ch_sample_sync_enable(&dec->rec_mix_ch, 1); */
#endif//RECORDER_MIX_EN
dec->eq_drc = a2dp_eq_drc_open(fmt->sample_rate, ch_num);
//dec->surround = surround_open_demo(ch_num);
//dec->vbass = vbass_open_demo(fmt->sample_rate, ch_num);
dec->sync = a2dp_output_sync_open(0);
/*使能同步,配置延时时间*/
a2dp_decoder_stream_sync_enable(&dec->dec, dec->sync->context, fmt->sample_rate, CONFIG_A2DP_DELAY_TIME);
// 数据流串联
struct audio_stream_entry *entries[8] = {NULL};
u8 entry_cnt = 0;
entries[entry_cnt++] = &dec->dec.decoder.entry;
if (dec->sync) {
entries[entry_cnt++] = dec->sync->entry;
}
#if TCFG_EQ_ENABLE && TCFG_BT_MUSIC_EQ_ENABLE
if (dec->eq_drc) {
entries[entry_cnt++] = &dec->eq_drc->entry;
}
#endif
/* entries[entry_cnt++] = &dec->loudness->entry; */
/* entries[entry_cnt++] = &dec->surround->entry; */
/* entries[entry_cnt++] = &dec->vbass->entry; */
if (AUDIO_DEC_BT_MIXER_EN) {
entries[entry_cnt++] = &dec->mix_ch.entry;
} else {
dac_hdl.entry.prob_handler = a2dp_to_dac_probe_handler;
entries[entry_cnt++] = &dac_hdl.entry;
}
dec->stream = audio_stream_open(dec, a2dp_dec_out_stream_resume);
audio_stream_add_list(dec->stream, entries, entry_cnt);
#if (RECORDER_MIX_EN)
audio_stream_add_entry(entries[entry_cnt - 2], &dec->rec_mix_ch.entry);
#endif//RECORDER_MIX_EN
audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC);
log_i("dec->ch:%d, fmt->channel:%d\n", dec->dec.ch, fmt->channel);
a2dp_drop_frame_stop();
#if TCFG_USER_TWS_ENABLE
if (tws_network_audio_was_started()) {
/*a2dp播放中副机加入*/
tws_network_local_audio_start();
a2dp_decoder_join_tws(&dec->dec);
}
#endif
dec->dec.start = 1;
err = audio_decoder_start(&dec->dec.decoder);
if (err) {
goto __err3;
}
clock_set_cur();
return 0;
__err3:
dec->dec.start = 0;
a2dp_eq_drc_close(dec->eq_drc);
if (AUDIO_DEC_BT_MIXER_EN) {
audio_mixer_ch_close(&dec->mix_ch);
} else {
audio_dac_stop(&dac_hdl);
}
#if (RECORDER_MIX_EN)
audio_mixer_ch_close(&dec->rec_mix_ch);
#endif//RECORDER_MIX_EN
if (dec->sync) {
a2dp_output_sync_close(dec->sync);
dec->sync = NULL;
}
if (dec->stream) {
audio_stream_close(dec->stream);
dec->stream = NULL;
}
__err2:
a2dp_decoder_close(&dec->dec);
__err1:
a2dp_dec_release();
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief a2dp解码资源等待
@param *wait: 句柄
@param event: 事件
@return 0成功
@note 用于多解码打断处理
*/
/*----------------------------------------------------------------------------*/
static int a2dp_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
log_i("a2dp_wait_res_handler: %d\n", event);
if (event == AUDIO_RES_GET) {
err = a2dp_dec_start();
} else if (event == AUDIO_RES_PUT) {
if (bt_a2dp_dec->dec.start) {
a2dp_audio_res_close();
a2dp_drop_frame_start();
}
}
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 打开a2dp解码
@param media_type: 媒体类型
@return 0: 成功
@note
*/
/*----------------------------------------------------------------------------*/
int a2dp_dec_open(int media_type)
{
struct a2dp_dec_hdl *dec;
if (bt_a2dp_dec) {
return 0;
}
log_i("a2dp_dec_open: %d\n", media_type);
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
switch (media_type) {
case A2DP_CODEC_SBC:
log_i("a2dp_media_type:SBC");
dec->dec.coding_type = AUDIO_CODING_SBC;
clock_add(DEC_SBC_CLK);
break;
case A2DP_CODEC_MPEG24:
log_i("a2dp_media_type:AAC");
dec->dec.coding_type = AUDIO_CODING_AAC;
clock_add(DEC_AAC_CLK);
break;
default:
log_i("a2dp_media_type unsupoport:%d", media_type);
free(dec);
return -EINVAL;
}
bt_a2dp_dec = dec;
dec->wait.priority = 1;
dec->wait.preemption = 0;
dec->wait.snatch_same_prio = 1;
dec->wait.handler = a2dp_wait_res_handler;
audio_decoder_task_add_wait(&decode_task, &dec->wait);
if (bt_a2dp_dec && (bt_a2dp_dec->dec.start == 0)) {
a2dp_drop_frame_start();
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief 关闭a2dp解码
@param
@return 0: 没有a2dp解码
@return 1: 成功
@note
*/
/*----------------------------------------------------------------------------*/
int a2dp_dec_close(void)
{
if (!bt_a2dp_dec) {
return 0;
}
if (bt_a2dp_dec->dec.start) {
a2dp_audio_res_close();
}
a2dp_dec_release();/*free bt_a2dp_dec*/
clock_set_cur();
log_i("a2dp_dec_close: exit\n");
return 1;
}
#if TCFG_ESCO_PLC
/*----------------------------------------------------------------------------*/
/**@brief esco丢包修护初始化
@param
@return 丢包修护句柄
@note
*/
/*----------------------------------------------------------------------------*/
static void *esco_plc_init(void)
{
void *plc = malloc(PLC_query()); /*buf_size:1040*/
//plc = zalloc_mux(PLC_query());
log_i("PLC_buf:0x%x,size:%d\n", (int)plc, PLC_query());
if (!plc) {
return NULL;
}
int err = PLC_init(plc);
if (err) {
log_i("PLC_init err:%d", err);
free(plc);
plc = NULL;
}
return plc;
}
/*----------------------------------------------------------------------------*/
/**@brief esco丢包修护关闭
@param *plc: 丢包修护句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void esco_plc_close(void *plc)
{
free(plc);
}
/*----------------------------------------------------------------------------*/
/**@brief esco丢包修护运行
@param *data: 数据
@param len: 数据长度
@param repair: 修护标记
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void esco_plc_run(s16 *data, u16 len, u8 repair)
{
u16 repair_point, tmp_point;
s16 *p_in, *p_out;
p_in = data;
p_out = data;
tmp_point = len / 2;
#if 0 //debug
static u16 repair_cnt = 0;
if (repair) {
repair_cnt++;
y_printf("[E%d]", repair_cnt);
} else {
repair_cnt = 0;
}
//log_i("[%d]",point);
#endif/*debug*/
while (tmp_point) {
repair_point = (tmp_point > PLC_FRAME_LEN) ? PLC_FRAME_LEN : tmp_point;
tmp_point = tmp_point - repair_point;
PLC_run(p_in, p_out, repair_point, repair);
p_in += repair_point;
p_out += repair_point;
}
}
#endif
#if TCFG_ESCO_LIMITER
/*----------------------------------------------------------------------------*/
/**@brief esco限福器初始化
@param sample_rate: 解码采样率
@return 限福器句柄
@note
*/
/*----------------------------------------------------------------------------*/
static void *esco_limiter_init(u16 sample_rate)
{
void *limiter = malloc(need_limiter_noiseGate_buf(1));
log_i("limiter size:%d\n", need_limiter_noiseGate_buf(1));
if (!limiter) {
return NULL;
}
//限幅器启动因子 int32(exp(-0.65/(16000 * 0.005))*2^30) 16000为采样率 0.005 为启动时间(s)
int limiter_attfactor = 1065053018;
//限幅器释放因子 int32(exp(-0.15/(16000 * 0.1))*2^30) 16000为采样率 0.1 为释放时间(s)
int limiter_relfactor = 1073641165;
//限幅器阈值(mdb)
//int limiter_threshold = CONST_LIMITER_THR;
//噪声门限启动因子 int32(exp(-1/(16000 * 0.1))*2^30) 16000为采样率 0.1 为释放时间(s)
int noiseGate_attfactor = 1073070945;
//噪声门限释放因子 int32(exp(-1/(16000 * 0.005))*2^30) 16000为采样率 0.005 为启动时间(s)
int noiseGate_relfactor = 1060403589;
//噪声门限(mdb)
//int noiseGate_threshold = -25000;
//低于噪声门限阈值的增益 (0~1)*2^30
//int noise
//Gate_low_thr_gain = 0 << 30;
if (sample_rate == 8000) {
limiter_attfactor = 1056434522;
limiter_relfactor = 1073540516;
noiseGate_attfactor = 1072400485;
noiseGate_relfactor = 1047231044;
}
limiter_noiseGate_init(limiter,
limiter_attfactor,
limiter_relfactor,
noiseGate_attfactor,
noiseGate_relfactor,
LIMITER_THR,
LIMITER_NOISE_GATE,
LIMITER_NOISE_GAIN,
sample_rate, 1);
return limiter;
}
/*----------------------------------------------------------------------------*/
/**@brief esco限福器关闭
@param *limiter: 限福器句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void esco_limiter_close(void *limiter)
{
free(limiter);
}
#endif /* TCFG_ESCO_LIMITER */
/*----------------------------------------------------------------------------*/
/**@brief esco解码输出数据处理
@param *entry: 数据流入口
@param *in: 输入数据
@param *out: 输出数据
@return 处理了多长数据
@note
*/
/*----------------------------------------------------------------------------*/
static int esco_dec_data_handler(struct audio_stream_entry *entry,
struct audio_data_frame *in,
struct audio_data_frame *out)
{
struct audio_decoder *decoder = container_of(entry, struct audio_decoder, entry);
struct esco_decoder *esco_dec = container_of(decoder, struct esco_decoder, decoder);
struct esco_dec_hdl *dec = container_of(esco_dec, struct esco_dec_hdl, dec);
if (dec->remain == 0) {
if (dec->tws_mute_en) {
memset(in->data, 0, in->data_len);
}
#if TCFG_ESCO_PLC
if (dec->plc && out && out->data) {
esco_plc_run(in->data, in->data_len, *(u8 *)out->data);
}
#endif/*TCFG_ESCO_PLC*/
#if TCFG_ESCO_LIMITER
if (dec->limiter) {
limiter_noiseGate_run(dec->limiter, in->data, in->data, in->data_len / 2);
}
#endif/*TCFG_ESCO_LIMITER*/
}
int wlen = esco_decoder_output_handler(&dec->dec, in);
if (in->data_len != wlen) {
dec->remain = 1;
} else {
dec->remain = 0;
}
return wlen;
}
/*----------------------------------------------------------------------------*/
/**@brief esco解码释放
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void esco_dec_release()
{
audio_decoder_task_del_wait(&decode_task, &bt_esco_dec->wait);
if (bt_esco_dec->dec.coding_type == AUDIO_CODING_MSBC) {
clock_remove(DEC_MSBC_CLK);
} else if (bt_esco_dec->dec.coding_type == AUDIO_CODING_CVSD) {
clock_remove(DEC_CVSD_CLK);
}
local_irq_disable();
free(bt_esco_dec);
bt_esco_dec = NULL;
local_irq_enable();
}
/*----------------------------------------------------------------------------*/
/**@brief esco解码事件返回
@param *decoder: 解码器句柄
@param argc: 参数个数
@param *argv: 参数
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void esco_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
log_i("AUDIO_DEC_EVENT_END\n");
esco_dec_close();
break;
}
}
static int esco_to_dac_probe_handler(struct audio_stream_entry *entry, struct audio_data_frame *in)
{
if (!in->stop) {
if (bt_esco_dec->sync) {
in->data_sync = 1;
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief esco解码close
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void esco_audio_res_close(void)
{
/*
*先关闭aec里面有复用到enc的buff再关闭enc
*如果没有buf复用则没有先后顺序要求。
*/
if (!bt_esco_dec->dec.start) {
return ;
}
bt_esco_dec->dec.start = 0;
bt_esco_dec->dec.enc_start = 0;
audio_aec_close();
esco_enc_close();
esco_decoder_close(&bt_esco_dec->dec);
esco_eq_drc_close(bt_esco_dec->eq_drc);
if (AUDIO_DEC_BT_MIXER_EN) {
audio_mixer_ch_close(&bt_esco_dec->mix_ch);
} else {
dac_hdl.entry.prob_handler = NULL;
audio_dac_stop(&dac_hdl);
}
#if (RECORDER_MIX_EN)
audio_mixer_ch_close(&bt_esco_dec->rec_mix_ch);
#endif//RECORDER_MIX_EN
esco_output_sync_close(bt_esco_dec->sync);
bt_esco_dec->sync = NULL;
#if TCFG_ESCO_PLC
if (bt_esco_dec->plc) {
esco_plc_close(bt_esco_dec->plc);
bt_esco_dec->plc = NULL;
}
#endif/*TCFG_ESCO_PLC*/
#if TCFG_ESCO_LIMITER
if (bt_esco_dec->limiter) {
esco_limiter_close(bt_esco_dec->limiter);
bt_esco_dec->limiter = NULL;
}
#endif /*TCFG_ESCO_LIMITER*/
if (bt_esco_dec->stream) {
audio_stream_close(bt_esco_dec->stream);
bt_esco_dec->stream = NULL;
}
#if TCFG_ESCO_USE_SPEC_MIX_LEN
/*恢复mix_buf的长度*/
audio_mixer_set_output_buf(&mixer, mix_buff, AUDIO_MIXER_LEN);
#endif /*TCFG_ESCO_USE_SPEC_MIX_LEN*/
app_audio_state_exit(APP_AUDIO_STATE_CALL);
bt_esco_dec->dec.start = 0;
}
/*----------------------------------------------------------------------------*/
/**@brief esco解码数据流激活
@param *p: 私有句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void esco_dec_out_stream_resume(void *p)
{
struct esco_dec_hdl *dec = (struct esco_dec_hdl *)p;
audio_decoder_resume(&dec->dec.decoder);
}
void esco_rx_notice_to_decode(void)
{
if (bt_esco_dec && bt_esco_dec->dec.start) {
audio_decoder_resume(&bt_esco_dec->dec.decoder);
}
}
/*----------------------------------------------------------------------------*/
/**@brief 开始esco解码
@param
@return 0: 成功
@note
*/
/*----------------------------------------------------------------------------*/
static int esco_dec_start()
{
int err;
struct esco_dec_hdl *dec = bt_esco_dec;
if (!bt_esco_dec) {
return -EINVAL;
}
err = esco_decoder_open(&dec->dec, &decode_task);
if (err) {
goto __err1;
}
audio_decoder_set_event_handler(&dec->dec.decoder, esco_dec_event_handler, 0);
#if TCFG_ESCO_USE_SPEC_MIX_LEN
/*
*(1)bt_esco_dec输出是120或者240所以通话的时候修改mix_buff的长度提高效率
*(2)其他大部分时候解码输出是512的倍数通话结束恢复mix_buff的长度提高效率
*/
audio_mixer_set_output_buf(&mixer, mix_buff, AUDIO_MIXER_LEN / 240 * 240);
#endif /*TCFG_ESCO_USE_SPEC_MIX_LEN*/
if (AUDIO_DEC_BT_MIXER_EN) {
audio_mode_main_dec_open(AUDIO_MODE_MAIN_STATE_DEC_ESCO);
audio_mixer_ch_open_head(&dec->mix_ch, &mixer); // 挂载到mixer最前面
audio_mixer_ch_set_src(&dec->mix_ch, 1, 0);
audio_mixer_ch_set_no_wait(&dec->mix_ch, 1, 10); // 超时自动丢数
audio_mixer_ch_sample_sync_enable(&dec->mix_ch, 1);
}
#if (RECORDER_MIX_EN)
audio_mixer_ch_open_head(&dec->rec_mix_ch, &recorder_mixer); // 挂载到mixer最前面
audio_mixer_ch_set_src(&dec->rec_mix_ch, 1, 0);
audio_mixer_ch_set_no_wait(&dec->rec_mix_ch, 1, 10); // 超时自动丢数
audio_mixer_ch_sample_sync_enable(&dec->rec_mix_ch, 1);
audio_mixer_ch_set_sample_rate(&dec->mix_ch, dec->dec.sample_rate);
/* audio_mixer_ch_set_sample_rate(&dec->rec_mix_ch, dec->dec.sample_rate); */
printf("[%s], dec->dec.sample_rate = %d\n", __FUNCTION__, dec->dec.sample_rate);
#endif//RECORDER_MIX_EN
dec->eq_drc = esco_eq_drc_open(dec->dec.sample_rate, dec->dec.out_ch_num);
dec->dec.decoder.entry.data_handler = esco_dec_data_handler;
dec->sync = esco_output_sync_open(0);
/*使能同步,配置延时时间*/
esco_decoder_stream_sync_enable(&dec->dec, dec->sync->context, dec->dec.sample_rate, 25);
// 数据流串联
struct audio_stream_entry *entries[8] = {NULL};
u8 entry_cnt = 0;
entries[entry_cnt++] = &dec->dec.decoder.entry;
if (dec->sync) {
entries[entry_cnt++] = dec->sync->entry;
}
#if TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE
if (dec->eq_drc) {
entries[entry_cnt++] = &dec->eq_drc->entry;
}
#endif
if (AUDIO_DEC_BT_MIXER_EN) {
entries[entry_cnt++] = &dec->mix_ch.entry;
} else {
dac_hdl.entry.prob_handler = esco_to_dac_probe_handler;
entries[entry_cnt++] = &dac_hdl.entry;
}
dec->stream = audio_stream_open(dec, esco_dec_out_stream_resume);
audio_stream_add_list(dec->stream, entries, entry_cnt);
#if (RECORDER_MIX_EN)
audio_stream_add_entry(entries[entry_cnt - 2], &dec->rec_mix_ch.entry);
#endif//RECORDER_MIX_EN
audio_output_set_start_volume(APP_AUDIO_STATE_CALL);
#if TCFG_ESCO_PLC
dec->plc = esco_plc_init();
#endif
#if TCFG_ESCO_LIMITER
dec->limiter = esco_limiter_init(dec->dec.sample_rate);
#endif /* TCFG_ESCO_LIMITER */
#if TCFG_USER_TWS_ENABLE
if (tws_network_audio_was_started()) {
tws_network_local_audio_start();
esco_decoder_join_tws(&dec->dec);
}
#endif
lmp_private_esco_suspend_resume(2);
dec->dec.start = 1;
err = audio_decoder_start(&dec->dec.decoder);
if (err) {
goto __err3;
}
dec->dec.frame_get = 0;
err = audio_aec_init(dec->dec.sample_rate);
if (err) {
log_i("audio_aec_init failed:%d", err);
//goto __err3;
}
err = esco_enc_open(dec->dec.coding_type, dec->dec.esco_len);
if (err) {
log_i("audio_enc_open failed:%d", err);
//goto __err3;
}
dec->dec.enc_start = 1;
clock_set_cur();
return 0;
__err3:
dec->dec.start = 0;
esco_eq_drc_close(dec->eq_drc);
if (AUDIO_DEC_BT_MIXER_EN) {
audio_mixer_ch_close(&dec->mix_ch);
} else {
audio_dac_stop(&dac_hdl);
}
#if (RECORDER_MIX_EN)
audio_mixer_ch_close(&dec->rec_mix_ch);
#endif//RECORDER_MIX_EN
if (dec->sync) {
esco_output_sync_close(dec->sync);
dec->sync = NULL;
}
if (dec->stream) {
audio_stream_close(dec->stream);
dec->stream = NULL;
}
__err2:
esco_decoder_close(&dec->dec);
__err1:
esco_dec_release();
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief esco解码资源等待
@param *wait: 句柄
@param event: 事件
@return 0成功
@note 用于多解码打断处理
*/
/*----------------------------------------------------------------------------*/
static int esco_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
log_d("esco_wait_res_handler %d\n", event);
if (event == AUDIO_RES_GET) {
err = esco_dec_start();
} else if (event == AUDIO_RES_PUT) {
if (bt_esco_dec->dec.start) {
lmp_private_esco_suspend_resume(1);
esco_audio_res_close();
}
}
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 打开esco解码
@param *param: 媒体信息
@param mutw: 静音
@return 0: 成功
@note
*/
/*----------------------------------------------------------------------------*/
int esco_dec_open(void *param, u8 mute)
{
int err;
struct esco_dec_hdl *dec;
u32 esco_param = *(u32 *)param;
int esco_len = esco_param >> 16;
int codec_type = esco_param & 0x000000ff;
log_i("esco_dec_open, type=%d,len=%d\n", codec_type, esco_len);
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
#if TCFG_DEC2TWS_ENABLE
localtws_media_disable();
#endif
bt_esco_dec = dec;
dec->tws_mute_en = mute;
dec->dec.esco_len = esco_len;
dec->dec.out_ch_num = audio_output_channel_num();
if (codec_type == 3) {
dec->dec.coding_type = AUDIO_CODING_MSBC;
dec->dec.sample_rate = 16000;
dec->dec.ch_num = 1;
clock_add(DEC_MSBC_CLK);
} else if (codec_type == 2) {
dec->dec.coding_type = AUDIO_CODING_CVSD;
dec->dec.sample_rate = 8000;
dec->dec.ch_num = 1;
clock_add(DEC_CVSD_CLK);
}
dec->wait.priority = 2;
dec->wait.preemption = 0;
dec->wait.snatch_same_prio = 1;
dec->wait.handler = esco_wait_res_handler;
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
if (bt_esco_dec->dec.start == 0) {
lmp_private_esco_suspend_resume(1);
}
#if AUDIO_OUTPUT_AUTOMUTE
extern void mix_out_automute_skip(u8 skip);
mix_out_automute_skip(1);
#endif
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 关闭esco解码
@param :
@return
@note
*/
/*----------------------------------------------------------------------------*/
void esco_dec_close()
{
if (!bt_esco_dec) {
return;
}
esco_audio_res_close();
esco_dec_release();
log_i("esco_dec_close: exit\n");
#if AUDIO_OUTPUT_AUTOMUTE
extern void mix_out_automute_skip(u8 skip);
mix_out_automute_skip(0);
#endif
clock_set_cur();
#if TCFG_DEC2TWS_ENABLE
localtws_media_enable();
#endif
}
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙音频正在运行
@param
@return 1: 正在运行
@note
*/
/*----------------------------------------------------------------------------*/
u8 bt_audio_is_running(void)
{
return (bt_a2dp_dec || bt_esco_dec);
}
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙播放正在运行
@param
@return 1: 正在运行
@note
*/
/*----------------------------------------------------------------------------*/
u8 bt_media_is_running(void)
{
return bt_a2dp_dec != NULL;
}
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙电话正在运行
@param
@return 1: 正在运行
@note
*/
/*----------------------------------------------------------------------------*/
u8 bt_phone_dec_is_running()
{
return bt_esco_dec != NULL;
}
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙解码idle判断
@param
@return 1: idle
@return 0: busy
@note
*/
/*----------------------------------------------------------------------------*/
static u8 bt_dec_idle_query()
{
if (bt_audio_is_running()) {
return 0;
}
return 1;
}
REGISTER_LP_TARGET(bt_dec_lp_target) = {
.name = "bt_dec",
.is_idle = bt_dec_idle_query,
};
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙模式 eq drc 打开
@param sample_rate:采样率
@param ch_num:通道个数
@return 句柄
@note
*/
/*----------------------------------------------------------------------------*/
void *a2dp_eq_drc_open(u16 sample_rate, u8 ch_num)
{
#if TCFG_EQ_ENABLE
struct audio_eq_drc *eq_drc = NULL;
struct audio_eq_drc_parm effect_parm = {0};
#if TCFG_BT_MUSIC_EQ_ENABLE
effect_parm.eq_en = 1;
#if TCFG_DRC_ENABLE
#if TCFG_BT_MUSIC_DRC_ENABLE
effect_parm.drc_en = 1;
effect_parm.drc_cb = drc_get_filter_info;
#endif
#endif
if (effect_parm.eq_en) {
effect_parm.async_en = 1;
effect_parm.out_32bit = 1;
effect_parm.online_en = 1;
effect_parm.mode_en = 1;
}
effect_parm.eq_name = song_eq_mode;
#if TCFG_EQ_DIVIDE_ENABLE
effect_parm.divide_en = 1;
#endif
effect_parm.ch_num = ch_num;
effect_parm.sr = sample_rate;
effect_parm.eq_cb = eq_get_filter_info;
eq_drc = audio_eq_drc_open(&effect_parm);
clock_add(EQ_CLK);
if (effect_parm.drc_en) {
clock_add(EQ_DRC_CLK);
}
#endif
return eq_drc;
#endif//TCFG_EQ_ENABLE
return NULL;
}
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙模式 eq drc 关闭
@param 句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
void a2dp_eq_drc_close(struct audio_eq_drc *eq_drc)
{
#if TCFG_EQ_ENABLE
#if TCFG_BT_MUSIC_EQ_ENABLE
if (eq_drc) {
audio_eq_drc_close(eq_drc);
eq_drc = NULL;
clock_remove(EQ_CLK);
#if TCFG_DRC_ENABLE
#if TCFG_BT_MUSIC_DRC_ENABLE
clock_remove(EQ_DRC_CLK);
#endif
#endif
}
#endif
#endif
return;
}
/*----------------------------------------------------------------------------*/
/**@brief 通话模式 eq drc 打开
@param sample_rate:采样率
@param ch_num:通道个数
@return 句柄
@note
*/
/*----------------------------------------------------------------------------*/
void *esco_eq_drc_open(u16 sample_rate, u8 ch_num)
{
mix_out_high_bass_dis(AUDIO_EQ_HIGH_BASS_DIS, 1);
#if TCFG_EQ_ENABLE
struct audio_eq_drc *eq_drc = NULL;
struct audio_eq_drc_parm effect_parm = {0};
#if TCFG_PHONE_EQ_ENABLE
effect_parm.eq_en = 1;
if (effect_parm.eq_en) {
effect_parm.async_en = 1;
effect_parm.online_en = 1;
effect_parm.mode_en = 0;
}
effect_parm.eq_name = call_eq_mode;
effect_parm.ch_num = ch_num;
effect_parm.sr = sample_rate;
effect_parm.eq_cb = eq_phone_get_filter_info;
eq_drc = audio_eq_drc_open(&effect_parm);
clock_add(EQ_CLK);
#endif
return eq_drc;
#endif//TCFG_EQ_ENABLE
return NULL;
}
/*----------------------------------------------------------------------------*/
/**@brief 通话模式 eq drc 关闭
@param 句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
void esco_eq_drc_close(struct audio_eq_drc *eq_drc)
{
#if TCFG_EQ_ENABLE
#if TCFG_PHONE_EQ_ENABLE
if (eq_drc) {
audio_eq_drc_close(eq_drc);
eq_drc = NULL;
clock_remove(EQ_CLK);
}
#endif
#endif
mix_out_high_bass_dis(AUDIO_EQ_HIGH_BASS_DIS, 0);
return;
}
/*----------------------------------------------------------------------------*/
/**@brief 环绕音效切换测试例子
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void surround_switch_test(void *p)
{
if (!p) {
return;
}
static u8 cnt_type = 0;
if (EFFECT_OFF == cnt_type) {
//中途关开测试
static u8 en = 0;
en = !en;
audio_surround_parm_update(p, cnt_type, (surround_update_parm *)en);
} else {
//音效切换测试
audio_surround_parm_update(p, cnt_type, NULL);
}
if (++cnt_type > EFFECT_OFF) {
cnt_type = EFFECT_3D_PANORAMA;
}
}
/*----------------------------------------------------------------------------*/
/**@brief 环绕音效模块打开例子
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
surround_hdl *surround_open_demo(u8 ch_num)
{
surround_hdl *surround = NULL;
#if AUDIO_SURROUND_CONFIG
surround_open_parm parm = {0};
if (ch_num == 1) {
ch_num = EFFECT_CH_L;//单声道时,默认做左声道
}
parm.channel = ch_num;
parm.surround_effect_type = EFFECT_3D_PANORAMA;//打开时默认使用3d全景音,使用者,根据需求修改
surround = audio_surround_open(&parm);
#if 0
if (surround) {
audio_surround_parm_update(surround, EFFECT_3D_PANORAMA, NULL);
}
#endif
clock_add(DEC_3D_CLK);
#endif
/* sys_timer_add(surround, surround_switch_test, 10000); */
return surround;
}
/*----------------------------------------------------------------------------*/
/**@brief 环绕音效关闭例子
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void surround_close(surround_hdl *surround)
{
#if AUDIO_SURROUND_CONFIG
if (surround) {
audio_surround_close(surround);
surround = NULL;
}
clock_remove(DEC_3D_CLK);
#endif
}
/*----------------------------------------------------------------------------*/
/**@brief 虚拟低音打开例子
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
vbass_hdl *vbass_open_demo(u16 sample_rate, u8 ch_num)
{
vbass_hdl *vbass = NULL;
#if AUDIO_VBASS_CONFIG
vbass_open_parm parm = {0};
parm.sr = sample_rate;
parm.channel = ch_num;
vbass = audio_vbass_open(&parm);
#if 0
if (vbass) {
vbass_update_parm def_parm = {0};
def_parm.bass_f = 300;
def_parm.level = 8192;
audio_vbass_parm_update(vbass, 0, &def_parm);
}
#endif
clock_add(DEC_VBASS_CLK);
#endif
return vbass;
}
/*----------------------------------------------------------------------------*/
/**@brief 虚拟低音关闭例子
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void vbass_close_demo(vbass_hdl *vbass)
{
#if AUDIO_VBASS_CONFIG
if (vbass) {
audio_vbass_close(vbass);
vbass = NULL;
}
clock_remove(DEC_VBASS_CLK);
#endif
}