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

1842 lines
50 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_syncts.h"
#include "application/eq_config.h"
#include "application/audio_energy_detect.h"
#include "application/audio_surround.h"
#include "app_config.h"
#include "audio_config.h"
#include "aec_user.h"
#include "audio_enc.h"
#include "app_main.h"
#include "btstack/avctp_user.h"
#include "btstack/a2dp_media_codec.h"
#include "tone_player.h"
/* #include "audio_demo/audio_demo.h" */
#include "media/audio_vbass.h"
#include "audio_plc.h"
#include "audio_dec_eff.h"
#include "audio_codec_clock.h"
#if TCFG_AUDIO_HEARING_AID_ENABLE
#include "audio_hearing_aid.h"
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
#if TCFG_USER_TWS_ENABLE
#include "bt_tws.h"
#endif/*TCFG_USER_TWS_ENABLE*/
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
#include "audio_dvol.h"
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
#if TCFG_APP_FM_EMITTER_EN
#include "fm_emitter/fm_emitter_manage.h"
#endif/*TCFG_APP_FM_EMITTER_EN*/
#if TCFG_AUDIO_ANC_ENABLE
#include "audio_anc.h"
#endif/*TCFG_AUDIO_ANC_ENABLE*/
#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
#include "phone_message/phone_message.h"
#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
#if TCFG_SMART_VOICE_ENABLE
#include "smart_voice/smart_voice.h"
#include "media/jl_kws.h"
#if TCFG_CALL_KWS_SWITCH_ENABLE
#include "btstack/avctp_user.h"
#endif
#endif
#include "media/audio_gain_process.h"
#ifdef SUPPORT_MS_EXTENSIONS
/* #pragma bss_seg(".audio_decoder_bss") */
/* #pragma data_seg(".audio_decoder_data") */
#pragma const_seg(".audio_decoder_const")
#pragma code_seg(".audio_decoder_code")
#endif/*SUPPORT_MS_EXTENSIONS*/
#include "sound_device.h"
#if TCFG_ESCO_DL_NS_ENABLE
#include "audio_ns.h"
#define DL_NS_MODE 0
#define DL_NS_NOISELEVEL 100.0f
#define DL_NS_AGGRESSFACTOR 1.0f
#define DL_NS_MINSUPPRESS 0.09f
#endif/*TCFG_ESCO_DL_NS_ENABLE*/
#if TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE
#include "audio_NoiseGate.h"
static u8 *esco_dl_noisegate_buf = NULL;
#endif/*TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE*/
#if ((defined TCFG_DIAFX_ENABLE) && TCFG_DIAFX_ENABLE)
#include "diafx.h"
#endif
#if (TCFG_AUDIO_OUTPUT_IIS)
#include "audio_iis.h"
#endif
#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
#include "icsd_adt_app.h"
#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
#define AUDIO_CODEC_SUPPORT_SYNC 1
#define ESCO_DRC_EN 0 //通话下行增加限幅器处理,默认关闭,need en TCFG_DRC_ENABLE
#if (!TCFG_DRC_ENABLE || !TCFG_PHONE_EQ_ENABLE)
#undef ESCO_DRC_EN 0
#define ESCO_DRC_EN 0
#endif
#if TCFG_AUDIO_ANC_ENABLE && TCFG_DRC_ENABLE
#define MIX_OUT_DRC_EN 0/*mixout后增加一级限幅处理,默认关闭,need en TCFG_DRC_ENABLE*/
#else
#define MIX_OUT_DRC_EN 0/*mixout后增加一级限幅处理,默认关闭,need en TCFG_DRC_ENABLE*/
#endif/*TCFG_AUDIO_ANC_ENABLE && TCFG_DRC_ENABLE*/
#if AUDIO_OUT_EFFECT_ENABLE
int audio_out_effect_open(void *priv, u16 sample_rate);
void audio_out_effect_close(void);
int audio_out_effect_stream_clear();
struct dec_eq_drc *audio_out_effect = NULL;
#endif /*AUDIO_OUT_EFFECT_ENABLE*/
static u8 audio_out_effect_dis = 0;
static u8 mix_out_remain = 0;
struct tone_dec_hdl {
struct audio_decoder decoder;
void (*handler)(void *, int argc, int *argv);
void *priv;
};
#if AUDIO_SURROUND_CONFIG
static u8 a2dp_surround_eff; //音效模式记录
void a2dp_surround_set(u8 eff)
{
a2dp_surround_eff = eff;
}
#endif
struct esco_dec_hdl {
struct audio_decoder decoder;
struct audio_res_wait wait;
struct audio_mixer_ch mix_ch;
u32 coding_type;
u8 *frame;
u8 frame_len;
u8 offset;
u8 data_len;
u8 tws_mute_en;
u8 start;
u8 enc_start;
u8 frame_time;
u8 preempt;
u8 channels;
u8 ul_stream_open;
u16 slience_frames;
u16 sample_rate;
void *syncts;
#if AUDIO_CODEC_SUPPORT_SYNC
void *ts_handle;
u8 ts_start;
u8 sync_step;
#endif
u32 mix_ch_event_params[3];
u8 esco_len;
u16 remain;
int data[15];/*ALIGNED(4)*/
#if TCFG_EQ_ENABLE&&TCFG_PHONE_EQ_ENABLE
struct dec_eq_drc *eq_drc;
#endif//TCFG_PHONE_EQ_ENABLE
#if TCFG_ESCO_DL_NS_ENABLE
void *dl_ns;
s16 dl_ns_out[NS_OUT_POINTS_MAX];
u16 dl_ns_offset;
u16 dl_ns_remain;
#endif/*TCFG_ESCO_DL_NS_ENABLE*/
#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
struct audio_drc *limiter;
#endif
u32 hash;
s16 fade_trigger;
s16 fade_volume;
s16 fade_step;
#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
u8 icsd_adt_state;
#endif
};
#if AUDIO_OUTPUT_AUTOMUTE
void *mix_out_automute_hdl = NULL;
extern void mix_out_automute_open();
extern void mix_out_automute_close();
#endif //#if AUDIO_OUTPUT_AUTOMUTE
#define AUDIO_DAC_DELAY_TIME 30
#define DIGITAL_OdB_VOLUME 16384
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)||(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_MONO_LR_DIFF)
#define MIX_POINTS_NUM 256
#else
#define MIX_POINTS_NUM 256
#endif
s16 mix_buff[MIX_POINTS_NUM];
/* #define MAX_SRC_NUMBER 3 */
/* s16 audio_src_hw_filt[24 * 2 * MAX_SRC_NUMBER]; */
static u16 dac_idle_delay_max = 10000;
static u16 dac_idle_delay_cnt = 10000;
static struct tone_dec_hdl *tone_dec = NULL;
struct audio_decoder_task decode_task;
extern struct audio_dac_hdl dac_hdl;
struct audio_mixer mixer;
extern struct dac_platform_data dac_data;
extern struct audio_adc_hdl adc_hdl;
struct esco_dec_hdl *esco_dec = NULL;
int lmp_private_get_esco_remain_buffer_size();
int lmp_private_get_esco_data_len();
void *lmp_private_get_esco_packet(int *len, u32 *hash);
void lmp_private_free_esco_packet(void *packet);
extern int lmp_private_esco_suspend_resume(int flag);
extern void user_sat16(s32 *in, s16 *out, u32 npoint);
void *esco_play_sync_open(u8 channel, u16 sample_rate, u16 output_rate);
//void audio_adc_init(void);
void *audio_adc_open(void *param, const char *source);
int audio_adc_sample_start(void *adc);
void set_source_sample_rate(u32 sample_rate);
u8 bt_audio_is_running(void);
void audio_resume_all_decoder(void)
{
audio_decoder_resume_all(&decode_task);
}
void audio_src_isr_deal(void)
{
audio_resume_all_decoder();
}
__attribute__((weak))
u8 get_sniff_out_status()
{
return 0;
}
__attribute__((weak))
void clear_sniff_out_status()
{
}
u8 is_dac_power_off()
{
#if 1
return 1;
#else
//开机播完提示音再初始化蓝牙
if (a2dp_dec || esco_dec || get_call_status() != BT_CALL_HANGUP || !tone_get_status()) {
return 1;
}
return 0;
#endif
}
#include "a2dp_dec.c" //这里将A2DP解码代码分解到另外文件
#define AUDIO_DECODE_TASK_WAKEUP_TIME 4 //ms
#if AUDIO_DECODE_TASK_WAKEUP_TIME
#include "timer.h"
static void audio_decoder_wakeup_timer(void *priv)
{
//putchar('k');
audio_decoder_resume_all(&decode_task);
}
int audio_decoder_task_add_probe(struct audio_decoder_task *task)
{
local_irq_disable();
if (task->wakeup_timer == 0) {
task->wakeup_timer = usr_timer_add(NULL, audio_decoder_wakeup_timer, AUDIO_DECODE_TASK_WAKEUP_TIME, 1);
log_i("audio_decoder_task_add_probe:%d\n", task->wakeup_timer);
}
local_irq_enable();
return 0;
}
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;
}
local_irq_disable();
if (task->wakeup_timer) {
log_i("audio_decoder_task_del_probe:%d\n", task->wakeup_timer);
usr_timer_del(task->wakeup_timer);
task->wakeup_timer = 0;
}
local_irq_enable();
return 0;
}
int audio_decoder_wakeup_modify(int msecs)
{
if (decode_task.wakeup_timer) {
usr_timer_modify(decode_task.wakeup_timer, msecs);
}
return 0;
}
/*
* DA输出源启动后可使用DAC irq做唤醒省去hi_timer
*/
int audio_decoder_wakeup_select(u8 source)
{
if (source == 0) {
/*唤醒源为hi_timer*/
local_irq_disable();
if (!decode_task.wakeup_timer) {
decode_task.wakeup_timer = usr_timer_add(NULL, audio_decoder_wakeup_timer, AUDIO_DECODE_TASK_WAKEUP_TIME, 1);
}
local_irq_enable();
} else if (source == 1) {
/*唤醒源为输出目标中断*/
if (!sound_pcm_dev_is_running()) {
return audio_decoder_wakeup_select(0);
}
int err = sound_pcm_trigger_resume(a2dp_low_latency ? 2 : AUDIO_DECODE_TASK_WAKEUP_TIME,
NULL, audio_decoder_wakeup_timer);
if (err) {
return audio_decoder_wakeup_select(0);
}
local_irq_disable();
if (decode_task.wakeup_timer) {
usr_timer_del(decode_task.wakeup_timer);
decode_task.wakeup_timer = 0;
}
local_irq_enable();
}
return 0;
}
#endif/*AUDIO_DECODE_TASK_WAKEUP_TIME*/
static u8 bt_dec_idle_query()
{
if (a2dp_dec || esco_dec) {
return 0;
}
return 1;
}
REGISTER_LP_TARGET(bt_dec_lp_target) = {
.name = "bt_dec",
.is_idle = bt_dec_idle_query,
};
___interrupt
static void audio_irq_handler()
{
if (JL_AUDIO->DAC_CON & BIT(7)) {
JL_AUDIO->DAC_CON |= BIT(6);
if (JL_AUDIO->DAC_CON & BIT(5)) {
audio_decoder_resume_all(&decode_task);
audio_dac_irq_handler(&dac_hdl);
}
}
if (JL_AUDIO->ADC_CON & BIT(7)) {
JL_AUDIO->ADC_CON |= BIT(6);
if ((JL_AUDIO->ADC_CON & BIT(5)) && (JL_AUDIO->ADC_CON & BIT(4))) {
audio_adc_irq_handler(&adc_hdl);
}
}
}
#if AUDIO_OUTPUT_AUTOMUTE
void audio_mix_out_automute_mute(u8 mute)
{
printf(">>>>>>>>>>>>>>>>>>>> %s\n", mute ? ("MUTE") : ("UNMUTE"));
}
/* #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 (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_MUSIC_MUTEX)
if (ch == sound_pcm_dev_channel_mapping(ch)) {
printf("[DHA]>>>>>>>>>>>>>>>>>>>> %s\n", event ? ("MUTE") : ("UNMUTE"));
if (a2dp_dec) {
if (event) {
audio_hearing_aid_resume();
} else {
audio_hearing_aid_suspend();
}
}
}
#else
sound_pcm_dev_channel_mute(BIT(ch), event);
if (ch == sound_pcm_dev_channel_mapping(ch)) {
audio_mix_out_automute_mute(event);
}
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
}
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);
mix_out_automute_handler(mute, sound_pcm_dev_channel_mapping(0));
}
}
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 = sound_pcm_dev_channel_mapping(0);
e_det_param.dcc = 1;
mix_out_automute_hdl = audio_energy_detect_open(&e_det_param);
}
void mix_out_automute_close()
{
if (mix_out_automute_hdl) {
audio_energy_detect_close(mix_out_automute_hdl);
}
}
#endif //#if AUDIO_OUTPUT_AUTOMUTE
static void mixer_event_handler(struct audio_mixer *mixer, int event)
{
switch (event) {
case MIXER_EVENT_CH_OPEN:
if ((audio_mixer_get_ch_num(mixer) == 1) || (audio_mixer_get_start_ch_num(mixer) == 1)) {
#if AUDIO_OUTPUT_AUTOMUTE
audio_energy_detect_sample_rate_update(mix_out_automute_hdl, audio_mixer_get_sample_rate(mixer));
#endif //#if AUDIO_OUTPUT_AUTOMUTE
#if TCFG_APP_FM_EMITTER_EN
#else
#if TCFG_AUDIO_ANC_ENABLE
audio_anc_mix_process(1);
#endif/*TCFG_AUDIO_ANC_ENABLE*/
sound_pcm_dev_start(NULL, audio_mixer_get_sample_rate(mixer), app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
#endif
#if AUDIO_OUT_EFFECT_ENABLE
if (!audio_out_effect_dis) {
audio_out_effect_open(mixer, audio_mixer_get_sample_rate(mixer));
}
#endif
mix_out_remain = 0;
#if MIX_OUT_DRC_EN
mix_out_drc_close();
mix_out_drc_open(audio_mixer_get_sample_rate(mixer));
#endif//MIX_OUT_DRC_EN
}
break;
case MIXER_EVENT_CH_CLOSE:
if (audio_mixer_get_ch_num(mixer) == 0) {
#if AUDIO_OUT_EFFECT_ENABLE
audio_out_effect_close();
#endif
#if MIX_OUT_DRC_EN
mix_out_drc_close();
#endif//MIX_OUT_DRC_EN
#if TCFG_APP_FM_EMITTER_EN
#else
sound_pcm_dev_stop(NULL);
#if TCFG_AUDIO_ANC_ENABLE
audio_anc_mix_process(0);
#endif/*TCFG_AUDIO_ANC_ENABLE*/
#endif
}
break;
}
}
static int mix_probe_handler(struct audio_mixer *mixer)
{
return 0;
}
static int mix_output_handler(struct audio_mixer *mixer, s16 *data, u16 len)
{
int rlen = len;
int wlen = 0;
if (!mix_out_remain) {
#if MIX_OUT_DRC_EN
mix_out_drc_run(data, len);
#endif//MIX_OUT_DRC_EN
#if ((defined TCFG_DIAFX_ENABLE) && TCFG_DIAFX_ENABLE)
jl_platform_diafx_run(data, len >> 1);
#endif
}
/* audio_aec_refbuf(data, len); */
#if AUDIO_OUTPUT_AUTOMUTE
audio_energy_detect_run(mix_out_automute_hdl, data, len);
#endif //#if AUDIO_OUTPUT_AUTOMUTE
#if TCFG_APP_FM_EMITTER_EN
fm_emitter_cbuf_write((u8 *)data, len);
#else
wlen = sound_pcm_dev_write(NULL, data, len);
/*printf("0x%x, %d, %d\n", (u32)data, len, wlen);*/
/*
if (wlen == len) {
audio_decoder_resume_all(&decode_task);
}
*/
#endif/*TCFG_APP_FM_EMITTER_EN*/
if (wlen >= len) {
mix_out_remain = 0;
} else {
mix_out_remain = 1;
}
return wlen;
}
#if AUDIO_OUT_EFFECT_ENABLE
static int mix_output_effect_handler(struct audio_mixer *mixer, s16 *data, u16 len)
{
if (!audio_out_effect) {
return mix_output_handler(mixer, data, len);
}
if (audio_out_effect && audio_out_effect->async) {
return eq_drc_run(audio_out_effect, data, len);
}
if (!audio_out_effect->remain) {
if (audio_out_effect && !audio_out_effect->async) {
eq_drc_run(audio_out_effect, data, len);
}
}
int wlen = mix_output_handler(mixer, data, len);
if (wlen == len) {
audio_out_effect->remain = 0;
} else {
audio_out_effect->remain = 1;
}
return wlen;
}
#endif//AUDIO_OUT_EFFECT_ENABLE
static const struct audio_mix_handler mix_handler = {
.mix_probe = mix_probe_handler,
#if AUDIO_OUT_EFFECT_ENABLE
.mix_output = mix_output_effect_handler,
#else
.mix_output = mix_output_handler,
#endif//AUDIO_OUT_EFFECT_ENABLE
};
static const u8 msbc_mute_data[] = {
0xAD, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76,
0xDB, 0x6D, 0xDD, 0xB6, 0xDB, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6D, 0xDD,
0xB6, 0xDB, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6D, 0xDD, 0xB6, 0xDB, 0x77,
0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6C, 0x00,
};
static int headcheck(u8 *buf)
{
int sync_word = buf[0] | ((buf[1] & 0x0f) << 8);
return (sync_word == 0x801) && (buf[2] == 0xAD);
}
static int esco_dump_rts_info(struct rt_stream_info *pkt)
{
u32 hash = 0xffffffff;
int read_len = 0;
pkt->baddr = lmp_private_get_esco_packet(&read_len, &hash);
pkt->seqn = hash;
/* printf("hash0=%d,%d ",hash,pkt->baddr ); */
if (pkt->baddr && read_len) {
pkt->remain_len = lmp_private_get_esco_remain_buffer_size();
pkt->data_len = lmp_private_get_esco_data_len();
return 0;
}
if (read_len == -EINVAL) {
//puts("----esco close\n");
return -EINVAL;
}
if (read_len < 0) {
return -ENOMEM;
}
return ENOMEM;
}
static int esco_dec_get_frame(struct audio_decoder *decoder, u8 **frame)
{
int len = 0;
u32 hash = 0;
struct esco_dec_hdl *dec = container_of(decoder, struct esco_dec_hdl, decoder);
__again:
if (dec->frame) {
int len = dec->frame_len - dec->offset;
if (len > dec->esco_len - dec->data_len) {
len = dec->esco_len - dec->data_len;
}
/*memcpy((u8 *)dec->data + dec->data_len, msbc_mute_data, sizeof(msbc_mute_data));*/
memcpy((u8 *)dec->data + dec->data_len, dec->frame + dec->offset, len);
dec->offset += len;
dec->data_len += len;
if (dec->offset == dec->frame_len) {
lmp_private_free_esco_packet(dec->frame);
dec->frame = NULL;
}
}
if (dec->data_len < dec->esco_len) {
dec->frame = lmp_private_get_esco_packet(&len, &hash);
/* printf("hash1=%d,%d ",hash,dec->frame ); */
if (len <= 0) {
printf("rlen=%d ", len);
return -EIO;
}
#if AUDIO_CODEC_SUPPORT_SYNC
u32 timestamp;
if (dec->ts_handle) {
timestamp = esco_audio_timestamp_update(dec->ts_handle, hash);
if (dec->syncts && (((hash - dec->hash) & 0x7ffffff) == dec->frame_time)) {
audio_syncts_next_pts(dec->syncts, timestamp);
}
dec->hash = hash;
if (!dec->ts_start) {
dec->ts_start = 1;
dec->mix_ch_event_params[2] = timestamp;
}
}
#endif
#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
phone_message_enc_write(dec->frame + 2, len - 2);
#endif
dec->offset = 0;
dec->frame_len = len;
goto __again;
}
*frame = (u8 *)dec->data;
return dec->esco_len;
}
static void esco_dec_put_frame(struct audio_decoder *decoder, u8 *frame)
{
struct esco_dec_hdl *dec = container_of(decoder, struct esco_dec_hdl, decoder);
dec->data_len = 0;
/*lmp_private_free_esco_packet((void *)frame);*/
}
static const struct audio_dec_input esco_input = {
.coding_type = AUDIO_CODING_MSBC,
.data_type = AUDIO_INPUT_FRAME,
.ops = {
.frame = {
.fget = esco_dec_get_frame,
.fput = esco_dec_put_frame,
}
}
};
u32 lmp_private_clear_sco_packet(u8 clear_num);
static void esco_dec_clear_all_packet(struct esco_dec_hdl *dec)
{
lmp_private_clear_sco_packet(0xff);
}
static int esco_dec_probe_handler(struct audio_decoder *decoder)
{
struct esco_dec_hdl *dec = container_of(decoder, struct esco_dec_hdl, decoder);
int err = 0;
int find_packet = 0;
struct rt_stream_info rts_info = {0};
err = esco_dump_rts_info(&rts_info);
if (err == -EINVAL) {
return err;
}
if (err || !dec->enc_start) {
audio_decoder_suspend(decoder, 0);
return -EAGAIN;
}
#if TCFG_USER_TWS_ENABLE
if (tws_network_audio_was_started()) {
/*清除从机声音加入标志*/
dec->slience_frames = 20;
tws_network_local_audio_start();
}
#endif
if (dec->preempt) {
dec->preempt = 0;
dec->slience_frames = 20;
}
return err;
}
#define MONO_TO_DUAL_POINTS 30
//////////////////////////////////////////////////////////////////////////////
static inline void audio_pcm_mono_to_dual(s16 *dual_pcm, s16 *mono_pcm, int points)
{
//printf("<%d,%x>",points,mono_pcm);
s16 *mono = mono_pcm;
int i = 0;
u8 j = 0;
for (i = 0; i < points; i++, mono++) {
*dual_pcm++ = *mono;
*dual_pcm++ = *mono;
}
}
/*level:0~15*/
static const u16 esco_dvol_tab[] = {
0, //0
111,//1
161,//2
234,//3
338,//4
490,//5
708,//6
1024,//7
1481,//8
2142,//9
3098,//10
4479,//11
6477,//12
9366,//13
14955,//14
16384 //15
};
/*
*********************************************************************
* ESCO Decode mix filter
* Description: ESCO语音解码输出接入mix滤镜
* Arguments : data - 音频数据len - 音频byte长度
* Return : 输出到后级的数据长度
* Note(s) : 音频后级PCM设备为单声道直接写入mixerPCM设备为双声道
* 这里通过1 to 2ch的处理将数据写入mixer并返回消耗的原始
* 数据长度。
*********************************************************************
*/
static s16 two_ch_data[MONO_TO_DUAL_POINTS * 2];
static s16 dual_offset_points = 0;
static s16 dual_total_points = 0;
static int esco_decoder_mix_filter(struct esco_dec_hdl *dec, s16 *data, int len)
{
int wlen = 0;
s16 point_num = 0;
u8 mono_to_dual = 0;
s16 *mono_data = (s16 *)data;
u16 remain_points = (len >> 1);
/*
*如果dac输出是双声道因为esco解码出来时单声道
*所以这里要根据dac通道确定是否做单变双
*/
mono_to_dual = sound_pcm_dev_channel_mapping(1) == 2 ? 1 : 0;
if (mono_to_dual) {
do {
if (dual_offset_points < dual_total_points) {
int tmp_len = audio_mixer_ch_write(&dec->mix_ch, &two_ch_data[dual_offset_points], (dual_total_points - dual_offset_points) << 1);
dual_offset_points += tmp_len >> 1;
if (tmp_len < ((dual_total_points - dual_offset_points) << 1)) {
break;
}
if (dual_offset_points < dual_total_points) {
continue;
}
}
point_num = MONO_TO_DUAL_POINTS;
if (point_num >= remain_points) {
point_num = remain_points;
}
audio_pcm_mono_to_dual(two_ch_data, mono_data, point_num);
dual_offset_points = 0;
dual_total_points = point_num << 1;
int tmp_len = audio_mixer_ch_write(&dec->mix_ch, &two_ch_data[dual_offset_points], (dual_total_points - dual_offset_points) << 1);
dual_offset_points += tmp_len >> 1;
wlen += dual_total_points << 1;
remain_points -= (dual_total_points >> 1);
mono_data += point_num;
if (tmp_len < (dual_total_points - dual_offset_points) << 1) {
break;
}
} while (remain_points);
} else {
wlen = audio_mixer_ch_write(&dec->mix_ch, data, len);
}
wlen = mono_to_dual ? (wlen >> 1) : wlen;
return wlen;
}
/*
*********************************************************************
* ESCO Decode DL_NS filter
* Description: ESCO语音解码输出下行降噪滤镜
* Arguments : data - 音频数据len - 音频byte长度
* Return : 输出到后级的数据长度
* Note(s) : 下行降噪通话接通前为直通接通后进行NS RUN处理。
*********************************************************************
*/
static int esco_decoder_dl_ns_filter(struct esco_dec_hdl *dec, s16 *data, int len)
{
#if TCFG_ESCO_DL_NS_ENABLE
int wlen = 0;
int ret_len = len;
if (dec->dl_ns_remain) {
wlen = esco_decoder_mix_filter(dec, dec->dl_ns_out + (dec->dl_ns_offset / 2), dec->dl_ns_remain);
dec->dl_ns_offset += wlen;
dec->dl_ns_remain -= wlen;
if (dec->dl_ns_remain) {
return 0;
}
}
if (get_call_status() == BT_CALL_ACTIVE) {
/*接通的时候再开始做降噪*/
int ns_out = audio_ns_run(dec->dl_ns, data, dec->dl_ns_out, len);
//输入消耗完毕,没有输出
if (ns_out == 0) {
return len;
}
len = ns_out;
} else {
memcpy(dec->dl_ns_out, data, len);
}
wlen = esco_decoder_mix_filter(dec, dec->dl_ns_out, len);
dec->dl_ns_offset = wlen;
dec->dl_ns_remain = len - wlen;
return ret_len;
#else
return 0;
#endif/*TCFG_ESCO_DL_NS_ENABLE*/
}
/*
*********************************************************************
* ESCO output after syncts
* Description: esco同步滤镜后的数据流滤镜
* Arguments : data - 音频数据len - 音频byte长度
* Return : 输出到后级的数据长度
* Note(s) : 音频同步后使用。
*********************************************************************
*/
static int esco_output_after_syncts_filter(void *priv, s16 *data, int len)
{
struct esco_dec_hdl *dec = (struct esco_dec_hdl *)priv;
int wlen = 0;
/*
*如果dac输出是双声道因为esco解码出来时单声道
*所以这里要根据dac通道确定是否做单变双
*/
#if TCFG_ESCO_DL_NS_ENABLE
wlen = esco_decoder_dl_ns_filter(dec, data, len);
#else
wlen = esco_decoder_mix_filter(dec, data, len);
#endif
return wlen;
}
/*
*slience_frames结束前增加淡入处理防止声音突变听到一下的不适感
* */
static void esco_fade_in(struct esco_dec_hdl *dec, s16 *data, int len)
{
if (dec->fade_trigger) {
int tmp = 0;
s16 *p = data;
u16 frames = (len >> 1) / dec->channels;
for (int i = 0; i < frames; i++) {
for (int j = 0; j < dec->channels; j++) {
tmp = *p;
*p++ = dec->fade_volume * tmp / DIGITAL_OdB_VOLUME;
}
dec->fade_volume += dec->fade_step;
if (dec->fade_volume > DIGITAL_OdB_VOLUME) {
dec->fade_volume = DIGITAL_OdB_VOLUME;
break;
}
}
if (dec->fade_volume == DIGITAL_OdB_VOLUME) {
dec->fade_trigger = 0;
}
}
}
/*
*********************************************************************
* ESCO Decode Output
* Description: 蓝牙通话解码输出
* Arguments : *priv 数据包错误表示(1 == error)
* Return : 输出到后级的数据长度
* Note(s) : dec->remain不等于0表示解码输出的数据后级没有消耗完
* 也就是说,只有(dec->remain == 0)的情况,才是新解码
* 出来的数据,才是需要做后处理的数据,否则直接输出到
* 后级即可。
*********************************************************************
*/
static int esco_dec_output_handler(struct audio_decoder *decoder, s16 *buf, int size, void *priv)
{
int wlen = 0;
int ret_len = size;
int len = size;
short *data = buf;
struct esco_dec_hdl *dec = container_of(decoder, struct esco_dec_hdl, decoder);
/*非上次残留数据,进行后处理*/
if (!dec->remain) {
#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
phone_message_call_api_esco_out_data(data, len);
#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
if (priv) {
audio_plc_run(data, len, *(u8 *)priv);
}
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_run(CALL_DVOL, data, len);
u16 dvol_val = esco_dvol_tab[app_var.aec_dac_gain];
for (u16 i = 0; i < len / 2; i++) {
s32 tmp_data = data[i];
if (tmp_data < 0) {
tmp_data = -tmp_data;
tmp_data = (tmp_data * dvol_val) >> 14;
tmp_data = -tmp_data;
} else {
tmp_data = (tmp_data * dvol_val) >> 14;
}
data[i] = tmp_data;
}
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
#if TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE
/*来电去电铃声不做处理*/
if ((get_call_status() == BT_CALL_ACTIVE) && esco_dl_noisegate_buf) {
audio_noise_gate_run(esco_dl_noisegate_buf, data, data, len / 2);
}
#endif/*TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE*/
#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
if (dec->limiter) {
esco_limiter_run(dec->limiter, data, len);
}
#endif
#if TCFG_EQ_ENABLE&&TCFG_PHONE_EQ_ENABLE
eq_drc_run(dec->eq_drc, data, len);
#endif//TCFG_PHONE_EQ_ENABLE
if (dec->slience_frames) {
if (dec->slience_frames == 1) {
int fade_time = 6;
int sample_rate = dec->decoder.fmt.sample_rate;
dec->fade_step = DIGITAL_OdB_VOLUME / ((fade_time * sample_rate) / 1000);
dec->fade_trigger = 1;
dec->fade_volume = 0;
} else {
dec->fade_trigger = 0;
dec->fade_volume = 0;
memset(data, 0x0, len);
}
dec->slience_frames--;
}
esco_fade_in(dec, data, len);
}
#if AUDIO_CODEC_SUPPORT_SYNC
if (dec->syncts) {
wlen = audio_syncts_frame_filter(dec->syncts, data, len);
if (wlen < len) {
audio_syncts_trigger_resume(dec->syncts, (void *)decoder, audio_filter_resume_decoder);
}
goto ret_handle;
}
#endif
wlen = esco_output_after_syncts_filter(dec, data, len);
ret_handle:
dec->remain = wlen == len ? 0 : 1;
return wlen;
}
static int esco_dec_post_handler(struct audio_decoder *decoder)
{
return 0;
}
static const struct audio_dec_handler esco_dec_handler = {
.dec_probe = esco_dec_probe_handler,
.dec_output = esco_dec_output_handler,
.dec_post = esco_dec_post_handler,
};
void esco_dec_release()
{
#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
if (get_icsd_adt_mode()) {
audio_icsd_adt_open(0);
}
#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
audio_decoder_task_del_wait(&decode_task, &esco_dec->wait);
free(esco_dec);
esco_dec = NULL;
}
void esco_dec_close();
static void esco_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
puts("AUDIO_DEC_EVENT_END\n");
esco_dec_close();
break;
}
}
u32 source_sr;
void set_source_sample_rate(u32 sample_rate)
{
source_sr = sample_rate;
}
u16 get_source_sample_rate()
{
if (bt_audio_is_running()) {
return source_sr;
}
return 0;
}
int esco_dec_dac_gain_set(u8 gain)
{
app_var.aec_dac_gain = gain;
if (esco_dec) {
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW)
app_audio_set_max_volume(APP_AUDIO_STATE_CALL, gain);
app_audio_set_volume(APP_AUDIO_STATE_CALL, app_audio_get_volume(APP_AUDIO_STATE_CALL), 1);
#else
sound_pcm_dev_set_analog_gain(gain);
#endif/*SYS_VOL_TYPE*/
}
return 0;
}
#define ESCO_SIRI_WAKEUP() (app_var.siri_stu == 1 || app_var.siri_stu == 2)
static int esco_decoder_syncts_setup(struct esco_dec_hdl *dec)
{
int err = 0;
#if AUDIO_CODEC_SUPPORT_SYNC
#define ESCO_DELAY_TIME 60
#define ESCO_RECOGNTION_TIME 220
int delay_time = ESCO_DELAY_TIME;
if (get_sniff_out_status()) {
clear_sniff_out_status();
if (ESCO_SIRI_WAKEUP()) {
/*fix : Siri出sniff蓝牙数据到音频通路延迟过长容易引入同步的问题*/
delay_time = ESCO_RECOGNTION_TIME;
}
}
struct audio_syncts_params params = {0};
int sample_rate = dec->decoder.fmt.sample_rate;
params.nch = dec->decoder.fmt.channel;
params.pcm_device = sound_pcm_sync_device_select();//PCM_INSIDE_DAC;
params.rout_sample_rate = sound_pcm_match_sample_rate(sample_rate);
params.network = AUDIO_NETWORK_BT2_1;
params.rin_sample_rate = sample_rate;
params.priv = dec;
params.factor = TIME_US_FACTOR;
params.output = (int (*)(void *, void *, int))esco_output_after_syncts_filter;
bt_audio_sync_nettime_select(0);//0 - 主机1 - tws, 2 - BLE
u8 frame_clkn = dec->esco_len >= 60 ? 12 : 6;
dec->ts_handle = esco_audio_timestamp_create(frame_clkn, delay_time, TIME_US_FACTOR);
dec->frame_time = frame_clkn;
audio_syncts_open(&dec->syncts, &params);
if (!err) {
dec->mix_ch_event_params[0] = (u32)&dec->mix_ch;
dec->mix_ch_event_params[1] = (u32)dec->syncts;
audio_mixer_ch_set_event_handler(&dec->mix_ch, (void *)dec->mix_ch_event_params, audio_mix_ch_event_handler);
}
dec->ts_start = 0;
#endif
return err;
}
static void esco_decoder_syncts_free(struct esco_dec_hdl *dec)
{
#if AUDIO_CODEC_SUPPORT_SYNC
if (dec->ts_handle) {
esco_audio_timestamp_close(dec->ts_handle);
dec->ts_handle = NULL;
}
if (dec->syncts) {
audio_syncts_close(dec->syncts);
dec->syncts = NULL;
}
#endif
}
int esco_ul_stream_open(u32 sample_rate, u16 esco_len, u32 codec_type)
{
int err = 0;
printf("esco_ul_open,sr = %d,len = %d,type = %x\n", sample_rate, esco_len, codec_type);
if (esco_dec->start == 0) {
printf("esco_ul_stream close ing,return\n");
return 0;
}
if (esco_dec->ul_stream_open) {
printf("esco_ul_stream_open now,return\n");
return 0;
}
esco_dec->ul_stream_open = 1;
err = audio_aec_init(sample_rate);
if (err) {
printf("audio_aec_init failed:%d", err);
//goto __err3;
}
err = esco_enc_open(codec_type, esco_len);
if (err) {
printf("audio_enc_open failed:%d", err);
//goto __err3;
}
return err;
}
int esco_ul_stream_close(void)
{
printf("esco_ul_stream_close\n");
if (esco_dec->ul_stream_open == 0) {
printf("esco_ul_stream_closed,return\n");
return 0;
}
audio_aec_close();
esco_enc_close();
esco_dec->ul_stream_open = 0;
return 0;
}
int esco_ul_stream_switch(u8 en)
{
if (esco_dec == NULL) {
printf("esco_ul_stream_close now,return\n");
return 0;
}
if (en) {
return esco_ul_stream_open(esco_dec->sample_rate, esco_dec->esco_len, esco_dec->coding_type);
} else {
return esco_ul_stream_close();
}
}
int esco_enc_reset(void)
{
if (esco_dec == NULL) {
printf("esco_ul_stream_close now,return\n");
return 0;
}
esco_enc_close();
esco_enc_open(esco_dec->coding_type, esco_dec->esco_len);
return 0;
}
int esco_dec_start()
{
int err;
struct audio_fmt f;
enum audio_channel channel;
struct esco_dec_hdl *dec = esco_dec;
u16 mix_buf_len_fix = 240;
if (!esco_dec) {
return -EINVAL;
}
#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
/*通话前关闭adt*/
esco_dec->icsd_adt_state = audio_icsd_adt_is_running();
if (esco_dec->icsd_adt_state) {
audio_icsd_adt_close(0);
}
#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
err = audio_decoder_open(&dec->decoder, &esco_input, &decode_task);
if (err) {
goto __err1;
}
audio_decoder_set_handler(&dec->decoder, &esco_dec_handler);
audio_decoder_set_event_handler(&dec->decoder, esco_dec_event_handler, 0);
if (dec->coding_type == AUDIO_CODING_MSBC) {
f.coding_type = AUDIO_CODING_MSBC;
f.sample_rate = 16000;
f.channel = 1;
} else if (dec->coding_type == AUDIO_CODING_CVSD) {
f.coding_type = AUDIO_CODING_CVSD;
f.sample_rate = 8000;
f.channel = 1;
mix_buf_len_fix = 120;
}
dec->sample_rate = f.sample_rate;
set_source_sample_rate(f.sample_rate);
err = audio_decoder_set_fmt(&dec->decoder, &f);
if (err) {
goto __err2;
}
dec->channels = f.channel;
/*
*虽然mix有直通的处理但是如果混合第二种声音进来的时候就会按照mix_buff
*的大小来混合输出该buff太大回导致dac没有连续的数据播放
*/
/*audio_mixer_set_output_buf(&mixer, mix_buff, sizeof(mix_buff) / 8);*/
audio_mixer_set_output_buf(&mixer, mix_buff, mix_buf_len_fix);
audio_mixer_ch_open(&dec->mix_ch, &mixer);
audio_mixer_ch_set_sample_rate(&dec->mix_ch, sound_pcm_match_sample_rate(f.sample_rate));
audio_mixer_ch_set_resume_handler(&dec->mix_ch, (void *)&dec->decoder, (void (*)(void *))audio_decoder_resume);
#if TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE
esco_dl_noisegate_buf = audio_noise_gate_open(300, 5, ESCO_NOISEGATE_THR, ESCO_NOISEGATE_GAIN, 16000, 1);
#endif/*TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE*/
#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
dec->limiter = esco_limiter_open(f.sample_rate, f.channel);
#endif/*TCFG_AUDIO_ESCO_LIMITER_ENABLE*/
#if TCFG_EQ_ENABLE&&TCFG_PHONE_EQ_ENABLE
u8 drc_en = 0;
#if TCFG_DRC_ENABLE&&ESCO_DRC_EN
drc_en = 1;
#endif//ESCO_DRC_EN
dec->eq_drc = esco_eq_drc_setup(&dec->mix_ch, (eq_output_cb)audio_mixer_ch_write, f.sample_rate, f.channel, 0, drc_en);
#endif//TCFG_PHONE_EQ_ENABLE
app_audio_state_switch(APP_AUDIO_STATE_CALL, BT_CALL_VOL_LEAVE_MAX);
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_open(CALL_DVOL, app_audio_get_volume(APP_AUDIO_STATE_CALL), CALL_DVOL_MAX, CALL_DVOL_FS, -1);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
printf("max_vol:%d,call_vol:%d", app_var.aec_dac_gain, app_audio_get_volume(APP_AUDIO_STATE_CALL));
app_audio_set_volume(APP_AUDIO_STATE_CALL, app_var.call_volume, 1);
#if AUDIO_CODEC_SUPPORT_SYNC
esco_decoder_syncts_setup(dec);
#endif/*AUDIO_CODEC_SUPPORT_SYNC*/
/*plc调用需要考虑到代码overlay或者压缩操作*/
audio_plc_open(f.sample_rate);
sound_pcm_dev_set_delay_time(30, 50);
lmp_private_esco_suspend_resume(2);
err = audio_decoder_start(&dec->decoder);
if (err) {
goto __err3;
}
sound_pcm_dev_try_power_on();
audio_out_effect_dis = 1;//通话模式关闭高低音
dec->start = 1;
dec->remain = 0;
#if TCFG_ESCO_DL_NS_ENABLE
dec->dl_ns = audio_ns_open(f.sample_rate, DL_NS_MODE, DL_NS_NOISELEVEL, DL_NS_AGGRESSFACTOR, DL_NS_MINSUPPRESS);
dec->dl_ns_remain = 0;
#endif/*TCFG_ESCO_DL_NS_ENABLE*/
err = esco_ul_stream_open(f.sample_rate, dec->esco_len, dec->coding_type);
#if (TCFG_AUDIO_OUTPUT_IIS)
audio_aec_ref_src_open(TCFG_IIS_SR, f.sample_rate);
#endif
clk_set_sys_lock(96 * (1000000L), 0);
audio_codec_clock_set(AUDIO_ESCO_MODE, dec->coding_type, dec->wait.preemption);
/* #if TCFG_DRC_ENABLE&&ESCO_DRC_EN */
/* #endif//ESCO_DRC_EN */
dec->enc_start = 1; //该函数所在任务优先级低可能未open编码就开始解码加入enc开始的标志防止解码过快输出
printf("esco_dec_start ok\n");
return 0;
__err3:
audio_mixer_ch_close(&dec->mix_ch);
__err2:
audio_decoder_close(&dec->decoder);
__err1:
esco_dec_release();
return err;
}
static int __esco_dec_res_close(void)
{
if (!esco_dec->start) {
return 0;
}
esco_dec->start = 0;
esco_dec->enc_start = 0;
esco_dec->preempt = 1;
esco_ul_stream_close();
/* audio_aec_close(); */
/* esco_enc_close(); */
#if TCFG_AUDIO_CVP_DUT_ENABLE
cvp_dut_mode_set(CVP_DUT_MODE_ALGORITHM); //通话结束 CVP_DUT恢复成算法模式
#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
app_audio_state_exit(APP_AUDIO_STATE_CALL);
audio_decoder_close(&esco_dec->decoder);
audio_mixer_ch_close(&esco_dec->mix_ch);
sound_pcm_dev_set_delay_time(20, AUDIO_DAC_DELAY_TIME);
#if AUDIO_CODEC_SUPPORT_SYNC
esco_decoder_syncts_free(esco_dec);
esco_dec->sync_step = 0;
#endif
#if TCFG_EQ_ENABLE&&TCFG_PHONE_EQ_ENABLE
if (esco_dec->eq_drc) {
esco_eq_drc_free(esco_dec->eq_drc);
esco_dec->eq_drc = NULL;
}
#endif//TCFG_PHONE_EQ_ENABLE
audio_out_effect_dis = 0;
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_close(CALL_DVOL);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
#if TCFG_ESCO_DL_NS_ENABLE
audio_ns_close(esco_dec->dl_ns);
#endif/*TCFG_ESCO_DL_NS_ENABLE*/
audio_plc_close();
#if TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE
audio_noise_gate_close(esco_dl_noisegate_buf);
#endif/*TCFG_AUDIO_ESCO_DL_NOISEGATE_ENABLE*/
#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
if (esco_dec->limiter) {
esco_limiter_close(esco_dec->limiter);
esco_dec->limiter = NULL;
}
#endif
audio_codec_clock_del(AUDIO_ESCO_MODE);
dual_offset_points = 0;
dual_total_points = 0;
return 0;
}
static int esco_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
printf("esco_wait_res_handler:%d", event);
if (event == AUDIO_RES_GET) {
err = esco_dec_start();
} else if (event == AUDIO_RES_PUT) {
err = __esco_dec_res_close();
lmp_private_esco_suspend_resume(1);
}
return err;
}
static void esco_smart_voice_detect_handler(void)
{
#if TCFG_SMART_VOICE_ENABLE
#if TCFG_CALL_KWS_SWITCH_ENABLE
if (ESCO_SIRI_WAKEUP() || (get_call_status() != BT_CALL_INCOMING)) {
audio_smart_voice_detect_close();
}
#else
audio_smart_voice_detect_close();
#endif
#endif
}
/*
*********************************************************************
* SCO/ESCO Decode Open
* Description: 打开蓝牙通话解码
* Arguments : param 蓝牙协议栈传递上来的编解码信息
* Return : 0 成功 其他 失败
* Note(s) : None.
*********************************************************************
*/
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;
printf("esco_dec_open, type=%d,len=%d\n", codec_type, esco_len);
#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_CALL_MUTEX)
audio_hearing_aid_suspend();
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
esco_smart_voice_detect_handler();
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
esco_dec = dec;
dec->esco_len = esco_len;
if (codec_type == 3) {
dec->coding_type = AUDIO_CODING_MSBC;
} else if (codec_type == 2) {
dec->coding_type = AUDIO_CODING_CVSD;
} else {
printf("Unknow ESCO codec type:%d\n", codec_type);
}
dec->tws_mute_en = mute;
dec->wait.priority = 2;
dec->wait.preemption = 1;
dec->wait.handler = esco_wait_res_handler;
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
if (esco_dec && esco_dec->start == 0) {
dec->preempt = 1;
lmp_private_esco_suspend_resume(1);
}
#if AUDIO_OUTPUT_AUTOMUTE
mix_out_automute_skip(1);
#endif
return err;
}
/*
*********************************************************************
* SCO/ESCO Decode Close
* Description: 关闭蓝牙通话解码
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void esco_dec_close(void)
{
if (!esco_dec) {
return;
}
__esco_dec_res_close();
esco_dec_release();
#if (TCFG_AUDIO_OUTPUT_IIS)
audio_aec_ref_src_close();
#endif
#if AUDIO_OUTPUT_AUTOMUTE
mix_out_automute_skip(0);
#endif
#if (defined(TCFG_PHONE_MESSAGE_ENABLE) && (TCFG_PHONE_MESSAGE_ENABLE))
phone_message_call_api_stop();
#endif/*TCFG_PHONE_MESSAGE_ENABLE*/
audio_mixer_set_output_buf(&mixer, mix_buff, sizeof(mix_buff));
#if TCFG_SMART_VOICE_ENABLE
audio_smart_voice_detect_open(JL_KWS_COMMAND_KEYWORD);
#endif
#if (TCFG_AUDIO_HEARING_AID_ENABLE && TCFG_AUDIO_DHA_AND_CALL_MUTEX)
audio_hearing_aid_resume();
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
printf("esco_dec_close succ\n");
}
//////////////////////////////////////////////////////////////////////////////
u8 bt_audio_is_running(void)
{
return (a2dp_dec || esco_dec);
}
u8 bt_media_is_running(void)
{
return a2dp_dec != NULL;
}
u8 bt_phone_dec_is_running()
{
return esco_dec != NULL;
}
__attribute__((weak))
void mic_trim_run(void)
{
printf("==========weak fun for tmp\n");
}
extern u32 read_capless_DTB(void);
static u8 audio_dec_inited = 0;
/*音频配置实时跟踪可以用来查看ADC/DAC增益或者其他寄存器配置*/
static void audio_config_trace(void *priv)
{
printf(">>Audio_Config_Trace:\n");
audio_gain_dump();
//audio_adda_dump();
}
//////////////////////////////////////////////////////////////////////////////
int audio_dec_init()
{
int err;
printf("audio_dec_init\n");
tone_play_init();
#if TCFG_KEY_TONE_EN
// 按键音初始化
audio_key_tone_init();
#endif
err = audio_decoder_task_create(&decode_task, "audio_dec");
#if TCFG_AUDIO_ANC_ENABLE
/* audio_dac_anc_set(&dac_hdl, 1); */
/* dac_data.max_ana_vol = anc_dac_gain_get(ANC_DAC_CH_L); //获取ANC设置的模拟增益 */
#endif/*TCFG_AUDIO_ANC_ENABLE*/
request_irq(IRQ_AUDIO_IDX, 2, audio_irq_handler, 0);
/*硬件SRC模块滤波器buffer设置可根据最大使用数量设置整体buffer*/
/* audio_src_base_filt_init(audio_src_hw_filt, sizeof(audio_src_hw_filt)); */
sound_pcm_driver_init();
sound_pcm_dev_set_delay_time(20, AUDIO_DAC_DELAY_TIME);
audio_mixer_open(&mixer);
audio_mixer_set_handler(&mixer, &mix_handler);
audio_mixer_set_event_handler(&mixer, mixer_event_handler);
#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
audio_mixer_set_mode(&mixer, 4, BIT24_MODE);
#endif
audio_mixer_set_output_buf(&mixer, mix_buff, sizeof(mix_buff));
#if AUDIO_OUTPUT_AUTOMUTE
mix_out_automute_open();
#endif //#if AUDIO_OUTPUT_AUTOMUTE
#if TCFG_AUDIO_CONFIG_TRACE
sys_timer_add(NULL, audio_config_trace, 3000);
#endif/*TCFG_AUDIO_CONFIG_TRACE*/
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
spk_eq_read_from_vm();
#endif
#if ((defined TCFG_DIAFX_ENABLE) && TCFG_DIAFX_ENABLE)
diafx_init_mode(0);
diafx_enabled(1);
#endif
audio_dec_inited = 1;
#if TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
/*需要再dac trim后调用*/
/*同时开ANC和免摘功能时配置ADC固定打开的adc数字通道数*/
extern struct adc_platform_data adc_data;
adc_data.anc_adt_en = 1;
u8 esco_mic_num = audio_adc_file_get_esco_mic_num();
u8 adt_mic_num = get_icsd_adt_mic_num();
adc_data.anc_adt_mic_ch_num = esco_mic_num > adt_mic_num ? esco_mic_num : adt_mic_num;
#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
return err;
}
static u8 audio_dec_init_complete()
{
if (!audio_dec_inited) {
return 0;
}
return 1;
}
extern void audio_adc_mic_demo_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac);
extern void dac_analog_power_control(u8 en);
void audio_fast_mode_test()
{
sound_pcm_dev_start(NULL, 44100, app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
audio_adc_mic_demo_open(AUDIO_ADC_MIC_0, 10, 16000, 1);
}
REGISTER_LP_TARGET(audio_dec_init_lp_target) = {
.name = "audio_dec_init",
.is_idle = audio_dec_init_complete,
};
#if AUDIO_OUT_EFFECT_ENABLE
int audio_out_effect_stream_clear()
{
if (!audio_out_effect) {
return 0;
}
if (audio_out_effect->eq && audio_out_effect->async) {
audio_eq_async_data_clear(audio_out_effect->eq);
}
return 0;
}
void audio_out_effect_close(void)
{
if (!audio_out_effect) {
return ;
}
audio_out_eq_drc_free(audio_out_effect);
audio_out_effect = NULL;
}
int audio_out_effect_open(void *priv, u16 sample_rate)
{
audio_out_effect_close();
u8 ch_num;
#if TCFG_APP_FM_EMITTER_EN
ch_num = 2;
#else
ch_num = sound_pcm_dev_channel_mapping(0);
#endif//TCFG_APP_FM_EMITTER_EN
u8 drc_en = 0;//
u8 async = 0;
if (drc_en) {
async = 1;
}
audio_out_effect = audio_out_eq_drc_setup(priv, (eq_output_cb)mix_output_handler, sample_rate, ch_num, async, drc_en);
return 0;
}
int audio_out_eq_spec_set_gain(u8 idx, int gain)
{
if (!audio_out_effect) {
return -1;
}
audio_out_eq_set_gain(audio_out_effect, idx, gain);
return 0;
}
#endif//AUDIO_OUT_EFFECT_ENABLE
/*----------------------------------------------------------------------------*/
/**@brief 获取输出默认采样率
@param
@return 0: 采样率可变
@return 非0: 固定采样率
@note
*/
/*----------------------------------------------------------------------------*/
u32 audio_output_nor_rate(void)
{
#if TCFG_AUDIO_OUTPUT_IIS
return TCFG_IIS_SR;
#endif /*TCFG_AUDIO_OUTPUT_IIS*/
#if AUDIO_OUTPUT_INCLUDE_DAC
#if (TCFG_MIC_EFFECT_ENABLE)
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;
}
int audio_dac_sample_rate_select(struct audio_dac_hdl *dac, u32 sample_rate, u8 high)
{
u32 sample_rate_tbl[] = {8000, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000
};
int rate_num = ARRAY_SIZE(sample_rate_tbl);
int i = 0;
for (i = 0; i < rate_num; i++) {
if (sample_rate == sample_rate_tbl[i]) {
return sample_rate;
}
if (sample_rate < sample_rate_tbl[i]) {
if (high) {
return sample_rate_tbl[i];
} else {
return sample_rate_tbl[i > 0 ? (i - 1) : 0];
}
}
}
return sample_rate_tbl[rate_num - 1];
}
/*******************************************************
* Function name : app_audio_output_samplerate_select
* Description : 将输入采样率与输出采样率进行匹配对比
* Parameter :
* @sample_rate 输入采样率
* @high: 0 - 低一级采样率1 - 高一级采样率
* Return : 匹配后的采样率
********************* -HB ******************************/
int app_audio_output_samplerate_select(u32 sample_rate, u8 high)
{
return audio_dac_sample_rate_select(&dac_hdl, sample_rate, high);
}
/*----------------------------------------------------------------------------*/
/**@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 (TCFG_REVERB_ENABLE || TCFG_MIC_EFFECT_ENABLE)
if (input_rate > 48000) {
return 48000;
}
#endif
return app_audio_output_samplerate_select(input_rate, 1);
}
#if TCFG_USER_TWS_ENABLE
#if AUDIO_SURROUND_CONFIG
#define TWS_FUNC_ID_A2DP_EFF \
((int)(('A' + '2' + 'D' + 'P') << (2 * 8)) | \
(int)(('E' + 'F' + 'F') << (1 * 8)) | \
(int)(('S' + 'Y' + 'N' + 'C') << (0 * 8)))
/*
*发环绕左右耳效果同步
* */
void audio_surround_voice_ctrl()
{
int state = tws_api_get_tws_state();
if (state & TWS_STA_SIBLING_CONNECTED) {
if (a2dp_dec && a2dp_dec->sur && a2dp_dec->sur->surround) {
if (!a2dp_dec->sur->surround_eff) {
a2dp_dec->sur->surround_eff = 1;
} else {
a2dp_dec->sur->surround_eff = 0;
}
int a2dp_eff = a2dp_dec->sur->surround_eff;
tws_api_send_data_to_sibling((u8 *)&a2dp_eff, sizeof(int), TWS_FUNC_ID_A2DP_EFF);
}
}
}
/*
*左右耳环绕效果同步回调
* */
static void tws_a2dp_eff_align(void *data, u16 len, bool rx)
{
if (a2dp_dec && a2dp_dec->sur && a2dp_dec->sur->surround) {
int a2dp_eff;
memcpy(&a2dp_eff, data, sizeof(int));
a2dp_dec->sur->surround_eff = a2dp_eff;
a2dp_surround_set(a2dp_eff);
audio_surround_voice(a2dp_dec->sur, a2dp_dec->sur->surround_eff);
}
}
REGISTER_TWS_FUNC_STUB(a2dp_align_eff) = {
.func_id = TWS_FUNC_ID_A2DP_EFF,
.func = tws_a2dp_eff_align,
};
#endif//AUDIO_SURROUND_CONFIG
#endif /* TCFG_USER_TWS_ENABLE */