Files
99_7018_lmx/cpu/br28/audio_dec.c

1842 lines
50 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
#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 */