KT24-1110_65E-HA-651B/cpu/br25/audio_dec/audio_dec.c
2024-11-10 21:14:01 +08:00

1164 lines
32 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 "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