1164 lines
32 KiB
C
1164 lines
32 KiB
C
#include "asm/includes.h"
|
||
#include "media/includes.h"
|
||
#include "system/includes.h"
|
||
#include "classic/tws_api.h"
|
||
#include "classic/hci_lmp.h"
|
||
#include "effectrs_sync.h"
|
||
#include "audio_effect/audio_eq_drc_demo.h"
|
||
#include "app_config.h"
|
||
#include "audio_config.h"
|
||
#include "audio_enc.h"
|
||
#include "audio_dec.h"
|
||
#include "app_main.h"
|
||
#include "audio_digital_vol.h"
|
||
/* #include "fm_emitter/fm_emitter_manage.h" */
|
||
/* #include "asm/audio_spdif.h" */
|
||
#include "clock_cfg.h"
|
||
#include "btstack/avctp_user.h"
|
||
#include "application/audio_output_dac.h"
|
||
#include "application/audio_energy_detect.h"
|
||
#include "application/audio_dig_vol.h"
|
||
#include "audio_dongle_codec.h"
|
||
#include "media/audio_equalloudness_eq.h"
|
||
#include "audio_spectrum.h"
|
||
#include "application/audio_vocal_remove.h"
|
||
#include "audio_effect/audio_sound_track_2_p_x.h"
|
||
#include "audio_utils.h"
|
||
|
||
#ifndef CONFIG_LITE_AUDIO
|
||
#include "aec_user.h"
|
||
#include "encode/encode_write.h"
|
||
#include "common/Resample_api.h"
|
||
#include "audio_link.h"
|
||
#include "audio_sbc_codec.h"
|
||
|
||
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)
|
||
#include "fm_emitter/fm_emitter_manage.h"
|
||
#endif
|
||
|
||
#include "audio_common/audio_iis.h"
|
||
#endif /*CONFIG_LITE_AUDIO*/
|
||
|
||
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DONGLE)
|
||
void *dongle_digvol_last = NULL;
|
||
void *dongle_digvol_last_entry = NULL;
|
||
#endif
|
||
|
||
#if (AUDIO_OUTPUT_INCLUDE_IIS)
|
||
void *iis_digvol_last = NULL;
|
||
void *iis_digvol_last_entry = NULL;
|
||
struct audio_stream_entry *iis_last_entry = NULL;
|
||
#endif
|
||
|
||
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
|
||
void *bt_digvol_last = NULL;
|
||
void *bt_digvol_last_entry = NULL;
|
||
#endif
|
||
|
||
#if TCFG_USER_TWS_ENABLE
|
||
#include "bt_tws.h"
|
||
#endif
|
||
|
||
#if AUDIO_OUTPUT_AUTOMUTE
|
||
void *mix_out_automute_hdl = NULL;
|
||
struct list_head *mix_out_automute_entry = NULL;
|
||
extern void mix_out_automute_open();
|
||
extern void mix_out_automute_close();
|
||
#endif
|
||
|
||
#define AUDIO_CODEC_SUPPORT_SYNC 1 // 同步
|
||
|
||
|
||
#define AUDIO_DECODE_TASK_WAKEUP_TIME 0 // 解码定时唤醒 // ms
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
struct audio_decoder_task decode_task = {0};
|
||
struct audio_mixer mixer = {0};
|
||
|
||
#if TCFG_MIXER_CYCLIC_TASK_EN
|
||
struct audio_mixer_task mixer_task = {0};
|
||
#endif
|
||
|
||
#if TCFG_DEC2TWS_TASK_ENABLE
|
||
struct audio_decoder_task localtws_decode_task = {0};
|
||
#endif
|
||
|
||
u8 audio_dec_inited = 0;
|
||
|
||
#if AUDIO_EQUALLOUDNESS_CONFIG
|
||
loudness_hdl *loudness;
|
||
#endif
|
||
|
||
|
||
u8 audio_src_hw_filt[SRC_FILT_POINTS * SRC_CHI * 2 * MAX_SRC_NUMBER] ALIGNED(4); /*SRC的滤波器必须4个byte对齐*/
|
||
s16 mix_buff[AUDIO_MIXER_LEN / 2] SEC(.dec_mix_buff);
|
||
|
||
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DAC)
|
||
#if AUDIO_CODEC_SUPPORT_SYNC
|
||
s16 dac_sync_buff[256];
|
||
#endif
|
||
#endif
|
||
|
||
#if AUDIO_VOCAL_REMOVE_EN
|
||
vocal_remove_hdl *mix_vocal_remove_hdl = NULL;
|
||
void *vocal_remove_open(u8 ch_num);
|
||
struct channel_switch *vocal_remove_mix_ch_switch = NULL;//声道变换,单声道时,先让解码出立体声,做完人声消除,再变单声道
|
||
#endif
|
||
|
||
|
||
extern const int config_mixer_en;
|
||
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
#if AUDIO_SPECTRUM_CONFIG
|
||
extern spectrum_fft_hdl *spec_hdl;
|
||
#endif
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
struct _audio_phase_inver_hdl {
|
||
struct audio_stream_entry entry; // 音频流入口
|
||
} audio_phase_inver_hdl;
|
||
|
||
static void audio_phase_inver_output_data_process_len(struct audio_stream_entry *entry, int len)
|
||
{
|
||
}
|
||
|
||
static int audio_phase_inver_data_handler(struct audio_stream_entry *entry,
|
||
struct audio_data_frame *in,
|
||
struct audio_data_frame *out)
|
||
{
|
||
struct _audio_phase_inver_hdl *hdl = container_of(entry, struct _audio_phase_inver_hdl, entry);
|
||
out->data_len = in->data_len;
|
||
out->data = in->data;
|
||
out->data_sync = in->data_sync;
|
||
out->channel = in->channel;
|
||
if (in->data_len - in->offset > 0) {
|
||
digital_phase_inverter_s16(in->data + in->offset / 2, in->data_len - in->offset);
|
||
}
|
||
return in->data_len;
|
||
}
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 获取dac能量值
|
||
@param
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
int audio_dac_energy_get(void)
|
||
{
|
||
#if AUDIO_OUTPUT_AUTOMUTE
|
||
int audio_energy_detect_energy_get(void *_hdl, u8 ch);
|
||
if (mix_out_automute_hdl) {
|
||
return audio_energy_detect_energy_get(mix_out_automute_hdl, BIT(0));
|
||
}
|
||
|
||
return (-1);
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 激活所有解码
|
||
@param
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void audio_resume_all_decoder(void)
|
||
{
|
||
audio_decoder_resume_all(&decode_task);
|
||
#if TCFG_DEC2TWS_TASK_ENABLE
|
||
audio_decoder_resume_all(&localtws_decode_task);
|
||
#endif
|
||
}
|
||
|
||
#if AUDIO_DECODE_TASK_WAKEUP_TIME
|
||
#include "timer.h"
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 解码定时处理
|
||
@param *priv: 私有参数
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static void audio_decoder_wakeup_timer(void *priv)
|
||
{
|
||
//putchar('k');
|
||
struct audio_decoder_task *task = priv;
|
||
audio_decoder_resume_all(task);
|
||
}
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 添加一个解码预处理
|
||
@param *task: 解码任务
|
||
@return 0: ok
|
||
@note 弱函数重定义
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
int audio_decoder_task_add_probe(struct audio_decoder_task *task)
|
||
{
|
||
if (task->wakeup_timer == 0) {
|
||
task->wakeup_timer = sys_hi_timer_add(task, audio_decoder_wakeup_timer, AUDIO_DECODE_TASK_WAKEUP_TIME);
|
||
log_i("audio_decoder_task_add_probe:%d\n", task->wakeup_timer);
|
||
}
|
||
return 0;
|
||
}
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 删除一个解码预处理
|
||
@param *task: 解码任务
|
||
@return 0: ok
|
||
@note 弱函数重定义
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
int audio_decoder_task_del_probe(struct audio_decoder_task *task)
|
||
{
|
||
log_i("audio_decoder_task_del_probe\n");
|
||
if (audio_decoder_task_wait_state(task) > 0) {
|
||
/*解码任务列表还有任务*/
|
||
return 0;
|
||
}
|
||
if (task->wakeup_timer) {
|
||
log_i("audio_decoder_task_del_probe:%d\n", task->wakeup_timer);
|
||
sys_hi_timer_del(task->wakeup_timer);
|
||
task->wakeup_timer = 0;
|
||
}
|
||
return 0;
|
||
}
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 重定义唤醒时间
|
||
@param msecs: 唤醒时间ms
|
||
@return 0: ok
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
int audio_decoder_wakeup_modify(int msecs)
|
||
{
|
||
if (decode_task.wakeup_timer) {
|
||
sys_hi_timer_modify(decode_task.wakeup_timer, msecs);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
#endif/*AUDIO_DECODE_TASK_WAKEUP_TIME*/
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 各模式主解码open
|
||
@param state: 参数
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void audio_mode_main_dec_open(u32 state)
|
||
{
|
||
#if 0
|
||
// 等待提示音解码完
|
||
tone_dec_wait_stop(200);
|
||
// 等待当前dac中的数据输出完
|
||
os_time_dly(audio_output_buf_time() / 10 + 1);
|
||
#endif
|
||
}
|
||
|
||
static u8 dac_fixed_16k = 0;
|
||
void set_fixed_dac_output_rate16K(u8 mark)
|
||
{
|
||
dac_fixed_16k = mark ? 1 : 0;
|
||
}
|
||
u8 get_t_fixed_dac_output_rate16k(void)
|
||
{
|
||
return dac_fixed_16k;
|
||
}
|
||
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 获取输出默认采样率
|
||
@param
|
||
@return 0: 采样率可变
|
||
@return 非0: 固定采样率
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
u32 audio_output_nor_rate(void)
|
||
{
|
||
#if (TCFG_IIS_ENABLE && TCFG_IIS_OUTPUT_EN)
|
||
/* return 0; */
|
||
return TCFG_IIS_OUTPUT_SR;
|
||
#endif
|
||
#if TCFG_SPDIF_ENABLE
|
||
return 44100;
|
||
#endif
|
||
|
||
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DAC)
|
||
|
||
#if (TCFG_MIC_EFFECT_ENABLE)
|
||
if (dac_fixed_16k) {
|
||
return 16000;
|
||
} else {
|
||
return TCFG_REVERB_SAMPLERATE_DEFUAL;
|
||
}
|
||
#endif
|
||
/* return app_audio_output_samplerate_select(input_rate, 1); */
|
||
#elif (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
|
||
|
||
#elif (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)
|
||
return 41667;
|
||
#else
|
||
return 44100;
|
||
#endif
|
||
|
||
/* #if TCFG_VIR_UDISK_ENABLE */
|
||
/* return 44100; */
|
||
/* #endif */
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 获取输出采样率
|
||
@param input_rate: 输入采样率
|
||
@return 输出采样率
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
u32 audio_output_rate(int input_rate)
|
||
{
|
||
u32 out_rate = audio_output_nor_rate();
|
||
if (out_rate) {
|
||
return out_rate;
|
||
}
|
||
|
||
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
|
||
if ((bt_user_priv_var.emitter_or_receiver == BT_EMITTER_EN) && (!bt_phone_dec_is_running())
|
||
&& (!bt_media_is_running())) {
|
||
y_printf("+++ \n");
|
||
return audio_sbc_enc_get_rate();
|
||
}
|
||
#elif (AUDIO_OUTPUT_WAY_DONGLE && AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DONGLE)
|
||
return DONGLE_OUTPUT_SAMPLE_RATE;
|
||
#endif
|
||
|
||
#if (TCFG_MIC_EFFECT_ENABLE)
|
||
if (input_rate > 48000) {
|
||
return 48000;
|
||
}
|
||
#endif
|
||
return app_audio_output_samplerate_select(input_rate, 1);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 获取输出通道数
|
||
@param
|
||
@return 输出通道数
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
u32 audio_output_channel_num(void)
|
||
{
|
||
#if AUDIO_OUTPUT_INCLUDE_DAC
|
||
/*根据DAC输出的方式选择输出的声道*/
|
||
u8 dac_connect_mode = app_audio_output_mode_get();
|
||
if (dac_connect_mode == DAC_OUTPUT_LR || dac_connect_mode == DAC_OUTPUT_DUAL_LR_DIFF) {
|
||
return 2;
|
||
} else {
|
||
#if AUDIO_VOCAL_REMOVE_EN
|
||
return 2;
|
||
#endif
|
||
return 1;
|
||
}
|
||
#elif (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)
|
||
return 2;
|
||
|
||
#else
|
||
return 2;
|
||
#endif
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 获取输出通道类型
|
||
@param
|
||
@return 输出通道类型
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
u32 audio_output_channel_type(void)
|
||
{
|
||
#if AUDIO_OUTPUT_INCLUDE_DAC
|
||
/*根据DAC输出的方式选择输出的声道*/
|
||
u8 dac_connect_mode = app_audio_output_mode_get();
|
||
if (dac_connect_mode == DAC_OUTPUT_LR || dac_connect_mode == DAC_OUTPUT_DUAL_LR_DIFF) {
|
||
return AUDIO_CH_LR;
|
||
} else if (dac_connect_mode == DAC_OUTPUT_MONO_L) {
|
||
return AUDIO_CH_DIFF; //要输出左右合成的单声道数据选这个
|
||
|
||
/* return AUDIO_CH_L; */ //只要输出左声道的数据选这个
|
||
|
||
} else if (dac_connect_mode == DAC_OUTPUT_MONO_R) {
|
||
return AUDIO_CH_DIFF; //要输出左右合成的单声道数据选这个
|
||
|
||
/* return AUDIO_CH_R; */ //只要输出右声道的数据选这个
|
||
|
||
} else {
|
||
return AUDIO_CH_DIFF;
|
||
}
|
||
#elif (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)
|
||
return AUDIO_CH_LR;
|
||
#else
|
||
return AUDIO_CH_LR;
|
||
#endif
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 设置输出音量状态
|
||
@param state: 输出音量状态
|
||
@return 0: ok
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
int audio_output_set_start_volume(u8 state)
|
||
{
|
||
s16 vol_max = get_max_sys_vol();
|
||
if (state == APP_AUDIO_STATE_CALL) {
|
||
vol_max = app_var.aec_dac_gain;
|
||
}
|
||
app_audio_state_switch(state, vol_max);
|
||
return 0;
|
||
}
|
||
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 开始音频输出
|
||
@param sample_rate: 输出采样率
|
||
@param reset_rate: 更新输出采样率
|
||
@return 0: ok
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
u8 audio_output_flag = 0;
|
||
int audio_output_start(u32 sample_rate, u8 reset_rate)
|
||
{
|
||
if (reset_rate) {
|
||
app_audio_output_samplerate_set(sample_rate);
|
||
}
|
||
|
||
if (audio_output_flag) {
|
||
return 0;
|
||
}
|
||
|
||
audio_output_flag = 1;
|
||
app_audio_output_start();
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 关闭音频输出
|
||
@param
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void audio_output_stop(void)
|
||
{
|
||
audio_output_flag = 0;
|
||
|
||
app_audio_output_stop();
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 打开一个变采样通道
|
||
@param *priv: output回调私有句柄
|
||
@param *output_handler: 变采样输出回调
|
||
@param *channel: 声道数
|
||
@param *input_sample_rate: 输入采样率
|
||
@param *output_sample_rate: 输出采样率
|
||
@return 变采样句柄
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
struct audio_src_handle *audio_hw_resample_open(void *priv,
|
||
int (*output_handler)(void *, void *, int),
|
||
u8 channel,
|
||
u16 input_sample_rate,
|
||
u16 output_sample_rate)
|
||
{
|
||
struct audio_src_handle *hdl;
|
||
hdl = zalloc(sizeof(struct audio_src_handle));
|
||
if (hdl) {
|
||
audio_hw_src_open(hdl, channel, SRC_TYPE_RESAMPLE);
|
||
audio_hw_src_set_rate(hdl, input_sample_rate, output_sample_rate);
|
||
audio_src_set_output_handler(hdl, priv, output_handler);
|
||
}
|
||
|
||
return hdl;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 关闭变采样
|
||
@param *hdl: 变采样句柄
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void audio_hw_resample_close(struct audio_src_handle *hdl)
|
||
{
|
||
if (hdl) {
|
||
audio_hw_src_stop(hdl);
|
||
audio_hw_src_close(hdl);
|
||
free(hdl);
|
||
}
|
||
}
|
||
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief mixer事件处理
|
||
@param *mixer: 句柄
|
||
@param event: 事件
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static void mixer_event_handler(struct audio_mixer *mixer, int event)
|
||
{
|
||
switch (event) {
|
||
case MIXER_EVENT_OPEN:
|
||
if (audio_mixer_get_ch_num(mixer) >= 1) {
|
||
clock_add_set(DEC_MIX_CLK);
|
||
}
|
||
break;
|
||
case MIXER_EVENT_CLOSE:
|
||
if (audio_mixer_get_ch_num(mixer) == 0) {
|
||
clock_remove_set(DEC_MIX_CLK);
|
||
}
|
||
if (config_mixer_en) {
|
||
os_mutex_pend(&mixer->mutex, 0);
|
||
if (audio_mixer_get_active_ch_num(mixer) == 0) {
|
||
/*输出通道可以进行stop处理*/
|
||
audio_mixer_output_stop(mixer);
|
||
//通道关闭时,清掉节点记录的偏移,防止下个解码打开时,mix之后的同步节点断言
|
||
audio_stream_clear_from(&mixer->entry);
|
||
}
|
||
os_mutex_post(&mixer->mutex);
|
||
}
|
||
break;
|
||
case MIXER_EVENT_SR_CHANGE:
|
||
#if 0
|
||
y_printf("sr change:%d \n", mixer->sample_rate);
|
||
#endif
|
||
break;
|
||
}
|
||
|
||
}
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 检测mixer采样率支持
|
||
@param *mixer: 句柄
|
||
@param sr: 采样率
|
||
@return 支持的采样率
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static u32 audio_mixer_check_sr(struct audio_mixer *mixer, u32 sr)
|
||
{
|
||
return audio_output_rate(sr);;
|
||
}
|
||
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 重新设置mixer采样率
|
||
@param sr: 采样率
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void audio_mixer_reset_sample_rate(u32 sr)
|
||
{
|
||
audio_mixer_set_sample_rate(&mixer, MIXER_SR_SPEC, sr);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief audio解码任务cpu跟踪回调
|
||
@param idle_total 跟踪周期内的空闲时间统计
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
int audio_dec_occupy_trace_hdl(void *priv, u32 idle_total)
|
||
{
|
||
struct audio_decoder_occupy *occupy = priv;
|
||
if (idle_total < occupy->idle_expect) {
|
||
if (occupy->pend_time) {
|
||
os_time_dly(occupy->pend_time);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
extern void audio_adda_gain_dump(void);//打印所有adc,dac的增益
|
||
/*音频配置实时跟踪,可以用来查看ADC/DAC增益,或者其他寄存器配置*/
|
||
static void audio_config_trace(void *priv)
|
||
{
|
||
printf(">>Audio_Config_Trace:\n");
|
||
//audio_adda_gain_dump();
|
||
//audio_adda_dump();
|
||
//mem_stats();
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 音频解码初始化
|
||
@param
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
extern struct audio_dac_hdl dac_hdl;
|
||
struct audio_dac_channel default_dac = {0};
|
||
int audio_dec_init()
|
||
{
|
||
int err;
|
||
|
||
printf("audio_dec_init\n");
|
||
|
||
// 创建解码任务
|
||
err = audio_decoder_task_create(&decode_task, "audio_dec");
|
||
#if TCFG_AUDIO_DECODER_OCCUPY_TRACE
|
||
decode_task.occupy.pend_time = 1;
|
||
decode_task.occupy.idle_expect = 4;
|
||
decode_task.occupy.trace_period = 200;
|
||
//decode_task.occupy.trace_hdl = audio_dec_occupy_trace_hdl;
|
||
#endif/*TCFG_AUDIO_DECODER_OCCUPY_TRACE*/
|
||
|
||
#if TCFG_AUDIO_DEC_OUT_TASK
|
||
audio_decoder_out_task_create(&decode_task, "audio_out");
|
||
#endif
|
||
|
||
#if TCFG_DEC2TWS_TASK_ENABLE
|
||
// 创建本地转发解码任务
|
||
audio_decoder_task_create(&localtws_decode_task, "local_dec");
|
||
#endif
|
||
|
||
// 初始化音频输出
|
||
app_audio_output_init();
|
||
#if TCFG_KEY_TONE_EN
|
||
// 按键音初始化
|
||
audio_key_tone_init();
|
||
#endif
|
||
|
||
|
||
#if SYS_DIGVOL_GROUP_EN
|
||
sys_digvol_group_open();
|
||
#endif // SYS_DIGVOL_GROUP_EN
|
||
|
||
|
||
/*硬件SRC模块滤波器buffer设置,可根据最大使用数量设置整体buffer*/
|
||
audio_src_base_filt_init(audio_src_hw_filt, sizeof(audio_src_hw_filt));
|
||
|
||
if (!AUDIO_DEC_MIXER_EN) {
|
||
#if AUDIO_OUTPUT_INCLUDE_DAC
|
||
// 创建dac通道
|
||
audio_dac_new_channel(&dac_hdl, &default_dac);
|
||
struct audio_dac_channel_attr attr;
|
||
audio_dac_channel_get_attr(&default_dac, &attr);
|
||
attr.delay_time = 50;
|
||
attr.protect_time = 5;
|
||
attr.write_mode = WRITE_MODE_BLOCK;
|
||
audio_dac_channel_set_attr(&default_dac, &attr);
|
||
#endif
|
||
goto __mixer_init_end;
|
||
}
|
||
// 初始化mixer
|
||
audio_mixer_open(&mixer);
|
||
// 使能mixer事件回调
|
||
audio_mixer_set_event_handler(&mixer, mixer_event_handler);
|
||
// 使能mixer采样率检测
|
||
audio_mixer_set_check_sr_handler(&mixer, audio_mixer_check_sr);
|
||
if (config_mixer_en) {
|
||
/*初始化mix_buf的长度*/
|
||
audio_mixer_set_output_buf(&mixer, mix_buff, sizeof(mix_buff));
|
||
#ifdef CONFIG_MIXER_CYCLIC
|
||
#define MIXER_MIN_LEN (128*4*2)
|
||
// 设置mixer最小输出长度
|
||
audio_mixer_set_min_len(&mixer, sizeof(mix_buff) < (MIXER_MIN_LEN * 2) ? (sizeof(mix_buff) / 2) : MIXER_MIN_LEN);
|
||
#endif
|
||
}
|
||
// 获取音频输出声道数
|
||
u8 ch_num = audio_output_channel_num();
|
||
// 设置mixer输出声道数
|
||
audio_mixer_set_channel_num(&mixer, ch_num);
|
||
// 检测音频输出采样率是否为固定输出
|
||
u32 sr = audio_output_nor_rate();
|
||
if (sr) {
|
||
// 固定采样率输出
|
||
audio_mixer_set_sample_rate(&mixer, MIXER_SR_SPEC, sr);
|
||
}
|
||
|
||
#ifdef CONFIG_MIXER_CYCLIC
|
||
#if TCFG_MIXER_CYCLIC_TASK_EN
|
||
// mixer使用单独task输出
|
||
audio_mixer_task_init(&mixer_task, "mix_out");
|
||
audio_mixer_task_ch_open(&mixer, &mixer_task);
|
||
#endif
|
||
#endif
|
||
|
||
struct audio_stream_entry *entries[8] = {NULL};
|
||
|
||
|
||
|
||
#if AUDIO_OUTPUT_AUTOMUTE
|
||
// 自动mute
|
||
mix_out_automute_open();
|
||
#endif
|
||
|
||
#if AUDIO_SPECTRUM_CONFIG
|
||
//频响能量值获取接口
|
||
spec_hdl = spectrum_open_demo(sr, ch_num);
|
||
#endif
|
||
|
||
#if AUDIO_EQUALLOUDNESS_CONFIG
|
||
if (ch_num != 4) {
|
||
loudness_open_parm parm = {0};
|
||
parm.sr = sr;
|
||
parm.ch_num = ch_num;
|
||
parm.threadhold_vol = LOUDNESS_THREADHOLD_VOL;
|
||
parm.vol_cb = vol_get_test;
|
||
loudness = audio_equal_loudness_open(&parm);//不支持四声道
|
||
}
|
||
#endif
|
||
|
||
#if AUDIO_VOCAL_REMOVE_EN
|
||
mix_vocal_remove_hdl = vocal_remove_open(ch_num);
|
||
|
||
u8 dac_connect_mode = app_audio_output_mode_get();
|
||
if ((dac_connect_mode == DAC_OUTPUT_MONO_L)
|
||
|| (dac_connect_mode == DAC_OUTPUT_MONO_R)
|
||
|| (dac_connect_mode == DAC_OUTPUT_MONO_LR_DIFF)) {
|
||
vocal_remove_mix_ch_switch = channel_switch_open(AUDIO_CH_DIFF, 512);
|
||
}
|
||
#endif
|
||
|
||
|
||
// 数据流串联。可以在mixer和last中间添加其他的数据流,比如eq等
|
||
u8 entry_cnt = 0;
|
||
entries[entry_cnt++] = &mixer.entry;
|
||
|
||
#if TCFG_DIG_PHASE_INVERTER_EN
|
||
audio_phase_inver_hdl.entry.data_process_len = audio_phase_inver_output_data_process_len;
|
||
audio_phase_inver_hdl.entry.data_handler = audio_phase_inver_data_handler;
|
||
entries[entry_cnt++] = &(audio_phase_inver_hdl.entry);
|
||
#endif/*TCFG_DIG_PHASE_INVERTER_EN*/
|
||
|
||
#if AUDIO_EQUALLOUDNESS_CONFIG
|
||
if (loudness) {
|
||
entries[entry_cnt++] = &loudness->loudness->entry;
|
||
}
|
||
#endif
|
||
#if AUDIO_SPECTRUM_CONFIG
|
||
if (spec_hdl) {
|
||
entries[entry_cnt++] = &spec_hdl->entry;
|
||
}
|
||
#endif
|
||
|
||
#if AUDIO_VOCAL_REMOVE_EN
|
||
if (mix_vocal_remove_hdl) {
|
||
entries[entry_cnt++] = &mix_vocal_remove_hdl->entry;
|
||
}
|
||
if (vocal_remove_mix_ch_switch) {
|
||
entries[entry_cnt++] = &vocal_remove_mix_ch_switch->entry;
|
||
}
|
||
#endif
|
||
|
||
#if AUDIO_OUTPUT_AUTOMUTE
|
||
entries[entry_cnt++] = mix_out_automute_entry;
|
||
#endif
|
||
|
||
/* #if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DAC) */
|
||
#if AUDIO_OUTPUT_INCLUDE_DAC
|
||
// 创建dac通道
|
||
audio_dac_new_channel(&dac_hdl, &default_dac);
|
||
struct audio_dac_channel_attr attr;
|
||
audio_dac_channel_get_attr(&default_dac, &attr);
|
||
attr.delay_time = 50;
|
||
attr.protect_time = 5;
|
||
attr.write_mode = WRITE_MODE_BLOCK;
|
||
audio_dac_channel_set_attr(&default_dac, &attr);
|
||
entries[entry_cnt++] = &default_dac.entry;
|
||
/*entries[entry_cnt++] = &dac_hdl.entry;*/
|
||
#endif
|
||
|
||
// 创建数据流,把所有节点连接起来
|
||
mixer.stream = audio_stream_open(&mixer, audio_mixer_stream_resume);
|
||
audio_stream_add_list(mixer.stream, entries, entry_cnt);
|
||
|
||
#if (!AUDIO_OUTPUT_INCLUDE_DAC)
|
||
entry_cnt++;
|
||
#endif
|
||
|
||
|
||
#if AUDIO_OUTPUT_INCLUDE_IIS
|
||
// iis。从倒数第二个节点分流
|
||
audio_dig_vol_param iis_digvol_last_param = {
|
||
.vol_start = app_var.music_volume,
|
||
.vol_max = SYS_MAX_VOL,
|
||
.ch_total = 2,
|
||
.fade_en = 1,
|
||
.fade_points_step = 5,
|
||
.fade_gain_step = 10,
|
||
.vol_list = NULL,
|
||
};
|
||
iis_digvol_last = audio_dig_vol_open(&iis_digvol_last_param);
|
||
iis_digvol_last_entry = audio_dig_vol_entry_get(iis_digvol_last);
|
||
|
||
iis_last_entry = audio_iis_output_start(TCFG_IIS_OUTPUT_PORT, TCFG_IIS_OUTPUT_DATAPORT_SEL);
|
||
struct audio_stream_entry *iis_entries_start = entries[entry_cnt - 2];
|
||
entry_cnt = 0;
|
||
entries[entry_cnt++] = iis_entries_start;
|
||
entries[entry_cnt++] = iis_digvol_last_entry;
|
||
entries[entry_cnt++] = iis_last_entry;
|
||
for (int i = 0; i < entry_cnt - 1; i++) {
|
||
audio_stream_add_entry(entries[i], entries[i + 1]);
|
||
}
|
||
#endif
|
||
|
||
|
||
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DONGLE)
|
||
// 蓝牙dongle。从倒数第二个节点分流
|
||
/* #if 1 */
|
||
{
|
||
audio_dig_vol_param dongle_digvol_last_param = {
|
||
.vol_start = 30,
|
||
.vol_max = 30,
|
||
.ch_total = 2,
|
||
.fade_en = 1,
|
||
.fade_points_step = 5,
|
||
.fade_gain_step = 10,
|
||
.vol_list = NULL,
|
||
};
|
||
dongle_digvol_last = audio_dig_vol_open(&dongle_digvol_last_param);
|
||
dongle_digvol_last_entry = audio_dig_vol_entry_get(dongle_digvol_last);
|
||
}
|
||
|
||
audio_dongle_emitter_init();
|
||
struct audio_stream_entry *dongle_entries_start = entries[entry_cnt - 2];
|
||
entry_cnt = 0;
|
||
entries[entry_cnt++] = dongle_entries_start;
|
||
entries[entry_cnt++] = dongle_digvol_last_entry;
|
||
entries[entry_cnt++] = &dongle_emitter.mix_ch.entry;
|
||
for (int i = 0; i < entry_cnt - 1; i++) {
|
||
audio_stream_add_entry(entries[i], entries[i + 1]);
|
||
}
|
||
#endif
|
||
|
||
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
|
||
// 蓝牙发射。从倒数第二个节点分流
|
||
extern int audio_data_set_zero(struct audio_stream_entry * entry, struct audio_data_frame * data_buf);
|
||
default_dac.entry.prob_handler = audio_data_set_zero;
|
||
audio_dig_vol_param bt_digvol_last_param = {
|
||
.vol_start = app_var.music_volume,
|
||
.vol_max = SYS_MAX_VOL,
|
||
.ch_total = 2,
|
||
.fade_en = 1,
|
||
.fade_points_step = 5,
|
||
.fade_gain_step = 10,
|
||
.vol_list = NULL,
|
||
};
|
||
bt_digvol_last = audio_dig_vol_open(&bt_digvol_last_param);
|
||
bt_digvol_last_entry = audio_dig_vol_entry_get(bt_digvol_last);
|
||
audio_stream_add_entry(entries[entry_cnt - 2], bt_digvol_last_entry);
|
||
|
||
audio_sbc_emitter_init();
|
||
audio_stream_add_entry(bt_digvol_last_entry, &sbc_emitter.entry);
|
||
#endif
|
||
|
||
#if (RECORDER_MIX_EN)
|
||
// 录音
|
||
recorder_mix_audio_stream_entry_add(entries[entry_cnt - 2]);
|
||
#endif
|
||
|
||
__mixer_init_end:
|
||
// 音频音量初始化
|
||
app_audio_volume_init();
|
||
audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC);
|
||
|
||
#if AUDIO_OUTPUT_INCLUDE_DAC
|
||
/* audio_link_init(); */
|
||
/* #if TCFG_IIS_OUTPUT_EN */
|
||
/* audio_link_open(TCFG_IIS_OUTPUT_PORT, ALINK_DIR_TX); */
|
||
/* #endif */
|
||
#endif
|
||
#if TCFG_SPDIF_ENABLE
|
||
// spdif音频
|
||
spdif_init();
|
||
#endif
|
||
|
||
audio_dec_inited = 1;
|
||
#if (TCFG_MIC_EFFECT_ENABLE && TCFG_MIC_EFFECT_START_DIR)
|
||
mic_effect_start();
|
||
#endif
|
||
|
||
#if TCFG_AUDIO_CONFIG_TRACE
|
||
sys_timer_add(NULL, audio_config_trace, 3000);
|
||
#endif/*TCFG_AUDIO_CONFIG_TRACE*/
|
||
#if TCFG_EQ_ENABLE
|
||
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
|
||
audio_drc_code_movable_load();//加载代码到ram
|
||
#endif
|
||
#endif
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 音频解码初始化判断
|
||
@param
|
||
@return 1: 还没初始化
|
||
@return 0: 已经初始化
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
static u8 audio_dec_init_complete()
|
||
{
|
||
/*不支持Audio功能,返回idle*/
|
||
#if (defined TCFG_AUDIO_ENABLE && (TCFG_AUDIO_ENABLE == 0))
|
||
return 1;
|
||
#endif/*TCFG_AUDIO_ENABLE*/
|
||
|
||
if (!audio_dec_inited) {
|
||
return 0;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
REGISTER_LP_TARGET(audio_dec_init_lp_target) = {
|
||
.name = "audio_dec_init",
|
||
.is_idle = audio_dec_init_complete,
|
||
};
|
||
|
||
|
||
|
||
#if AUDIO_OUTPUT_AUTOMUTE
|
||
|
||
void audio_mix_out_automute_mute(u8 mute)
|
||
{
|
||
//printf(">>>>>>>>>>>>>>>>>>>> %s\n", mute ? ("MUTE") : ("UNMUTE"));
|
||
if (mute)
|
||
{
|
||
gpio_set_output_value(IO_PORTA_04,1);
|
||
}
|
||
else
|
||
{
|
||
gpio_set_output_value(IO_PORTA_04,0);
|
||
}
|
||
|
||
}
|
||
|
||
/* #define AUDIO_E_DET_UNMUTE (0x00) */
|
||
/* #define AUDIO_E_DET_MUTE (0x01) */
|
||
void mix_out_automute_handler(u8 event, u8 ch)
|
||
{
|
||
printf(">>>> ch:%d %s\n", ch, event ? ("MUTE") : ("UNMUTE"));
|
||
if (ch == app_audio_output_channel_get()) {
|
||
audio_mix_out_automute_mute(event);
|
||
}
|
||
}
|
||
|
||
void mix_out_automute_skip(u8 skip)
|
||
{
|
||
u8 mute = !skip;
|
||
if (mix_out_automute_hdl) {
|
||
audio_energy_detect_skip(mix_out_automute_hdl, 0xFFFF, skip);
|
||
audio_mix_out_automute_mute(mute);
|
||
}
|
||
}
|
||
|
||
void mix_out_automute_open()
|
||
{
|
||
if (mix_out_automute_hdl) {
|
||
printf("mix_out_automute is already open !\n");
|
||
return;
|
||
}
|
||
audio_energy_detect_param e_det_param = {0};
|
||
e_det_param.mute_energy = 5;
|
||
e_det_param.unmute_energy = 10;
|
||
e_det_param.mute_time_ms = 1000;
|
||
e_det_param.unmute_time_ms = 50;
|
||
e_det_param.count_cycle_ms = 10;
|
||
e_det_param.sample_rate = 44100;
|
||
e_det_param.event_handler = mix_out_automute_handler;
|
||
e_det_param.ch_total = app_audio_output_channel_get();
|
||
e_det_param.dcc = 1;
|
||
mix_out_automute_hdl = audio_energy_detect_open(&e_det_param);
|
||
mix_out_automute_entry = audio_energy_detect_entry_get(mix_out_automute_hdl);
|
||
}
|
||
|
||
void mix_out_automute_close()
|
||
{
|
||
if (mix_out_automute_hdl) {
|
||
audio_energy_detect_close(mix_out_automute_hdl);
|
||
}
|
||
}
|
||
#endif //#if AUDIO_OUTPUT_AUTOMUTE
|
||
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* 数字音量分组管理
|
||
*
|
||
****************************************************************************/
|
||
|
||
#if SYS_DIGVOL_GROUP_EN
|
||
|
||
char *music_dig_logo[] = {
|
||
|
||
"music_a2dp",
|
||
"music_file",
|
||
"music_fm",
|
||
"music_linein",
|
||
"music_pc",
|
||
"NULL"
|
||
|
||
};
|
||
|
||
|
||
void *sys_digvol_group = NULL;
|
||
|
||
int sys_digvol_group_open(void)
|
||
{
|
||
if (sys_digvol_group == NULL) {
|
||
sys_digvol_group = audio_dig_vol_group_open();
|
||
return 0;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
int sys_digvol_group_close(void)
|
||
{
|
||
if (sys_digvol_group != NULL) {
|
||
return audio_dig_vol_group_close(sys_digvol_group);
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
// 根据每个解码通道的logo来决定启动时候的数字音量等级
|
||
u16 __attribute__((weak)) get_ch_digvol_start(char *logo)
|
||
{
|
||
#if 0
|
||
if (!strcmp(logo, "music_a2dp")) {
|
||
return 100;
|
||
} else if (!strcmp(logo, "music_fm")) {
|
||
return 100;
|
||
}
|
||
#endif
|
||
return get_max_sys_vol();
|
||
}
|
||
|
||
|
||
/*******************************************************
|
||
* Function name : sys_digvol_group_ch_open
|
||
* Description : 解码通道数字音量打开且加入分组管理
|
||
* Parameter :
|
||
* @logo 解码通道的标识
|
||
* @vol_start 解码通道数字音量启动等级, 传 -1 时会调用 get_ch_digvol_start 获取
|
||
* Return : digvol audio stream entry
|
||
*******************************************************/
|
||
void *sys_digvol_group_ch_open(char *logo, int vol_start, audio_dig_vol_param *parm)
|
||
{
|
||
|
||
if (sys_digvol_group == NULL || logo == NULL) {
|
||
return NULL;
|
||
}
|
||
|
||
if (vol_start == -1) {
|
||
vol_start = get_ch_digvol_start(logo);
|
||
}
|
||
|
||
audio_dig_vol_param temp_digvol_param = {
|
||
.vol_start = vol_start,
|
||
.vol_max = get_max_sys_vol(),
|
||
.ch_total = 2,
|
||
.fade_en = 1,
|
||
.fade_points_step = 5,
|
||
.fade_gain_step = 10,
|
||
.vol_list = NULL,
|
||
};
|
||
|
||
|
||
if (parm == NULL) {
|
||
parm = &temp_digvol_param;
|
||
}
|
||
void *digvol_hdl = audio_dig_vol_open(parm);
|
||
if (digvol_hdl) {
|
||
|
||
audio_dig_vol_group_add(sys_digvol_group, digvol_hdl, logo);
|
||
|
||
return audio_dig_vol_entry_get(digvol_hdl);
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
int sys_digvol_group_ch_close(char *logo)
|
||
{
|
||
if (sys_digvol_group == NULL || logo == NULL) {
|
||
return -1;
|
||
}
|
||
void *hdl = audio_dig_vol_group_hdl_get(sys_digvol_group, logo);
|
||
|
||
if (hdl != NULL) {
|
||
void *entry = audio_dig_vol_entry_get(hdl);
|
||
if (entry != NULL) {
|
||
audio_stream_del_entry(entry);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
audio_dig_vol_close(audio_dig_vol_group_hdl_get(sys_digvol_group, logo));
|
||
audio_dig_vol_group_del(sys_digvol_group, logo);
|
||
return 0;
|
||
}
|
||
|
||
#endif // SYS_DIGVOL_GROUP_EN
|
||
|
||
|
||
#if AUDIO_VOCAL_REMOVE_EN
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 人声消除打开例子
|
||
@param ch_num:通道个数
|
||
@return 句柄
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void *vocal_remove_open(u8 ch_num)
|
||
{
|
||
vocal_remove_hdl *hdl = NULL;
|
||
vocal_remove_open_parm parm = {0};
|
||
parm.channel = ch_num;
|
||
hdl = audio_vocal_remove_open(&parm);
|
||
return hdl;
|
||
}
|
||
/*----------------------------------------------------------------------------*/
|
||
/**@brief 人声消除关闭例子
|
||
@param
|
||
@return
|
||
@note
|
||
*/
|
||
/*----------------------------------------------------------------------------*/
|
||
void vocal_remove_close()
|
||
{
|
||
if (mix_vocal_remove_hdl) {
|
||
audio_vocal_remove_close(mix_vocal_remove_hdl);
|
||
mix_vocal_remove_hdl = NULL;
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
|