1381 lines
38 KiB
C
1381 lines
38 KiB
C
|
#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
|
|||
|
}
|