Files
99_7018_lmx/cpu/br28/audio_hearing/audio_hearing_aid.c

1987 lines
61 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
/*
****************************************************************
* Audio Hearing-Aid
* File : audio_hearing_aid.c
* By :
* Notes : DHA = Digital Hearing-Aid
* Usage :
****************************************************************
*/
#include "generic/typedef.h"
#include "board_config.h"
#include "media/includes.h"
#include "audio_config.h"
#include "sound_device.h"
#include "audio_hearing_aid.h"
#include "howling_api.h"
#include "audio_codec_clock.h"
#include "application/eq_config.h"
#include "application/audio_drc.h"
#include "audio_dec_eff.h"
#include "audio_enc.h"
#include "audio_llns.h"
#include "audio_dvol.h"
#include "circular_buf.h"
#include "audio_gain_process.h"
#include "bt_tws.h"
#include "audio_noise_gate.h"
#include "amplitude_statistic.h"
#include "audio_hearing_aid_lp.h"
#include "media/audio_howling.h"
#if TCFG_AUTO_SHUT_DOWN_TIME
#include "bt_edr_fun.h"
#endif /*TCFG_AUTO_SHUT_DOWN_TIME*/
#if TCFG_AUDIO_HEARING_AID_ENABLE
extern struct audio_dac_hdl dac_hdl;
extern struct audio_adc_hdl adc_hdl;
#define HEARING_AID_TASK_NAME "HearingAid"
//*********************************************************************************//
// 数字信号处理配置(Digital Hearing_Aid[DHA] Process Config) //
//*********************************************************************************//
/*mic声音淡入使能*/
#define DHA_FADEIN_ENABLE 1
/*均衡器*/
#define DHA_EQ_ENABLE 1
/*均衡器2*/
#define DHA_EQ2_ENABLE 0
/*动态范围控制*/
#define DHA_DRC_ENABLE 1
/*[啸叫抑制-移频法]Howling Suppress - FreqShift*/
#define DHA_HS_FS_ENABLE 1
/*[啸叫抑制-陷波法]Howling Suppress - Notch*/
#define DHA_HS_NOTCH_ENABLE 1
/*噪声抑制Noise Suppress*/
#define DHA_NS_ENABLE 0
/*变采样模块:如果输入输出采样率一致,条件编译自动关闭使能*/
#define DHA_SRC_ENABLE 1
/*音量控制模块*/
#define DHA_VOLUME_ENABLE 1
/*Noise-Gate噪声门限控制*/
#define DHA_NOISE_GATE_ENABLE 0
//*********************************************************************************//
// 数据结构定义 //
//*********************************************************************************//
typedef struct {
u16 mic_ch_sel;
u16 sample_rate;
u16 adc_irq_points;
u16 adc_buf_num;
u16 dac_delay;
u16 mic_gain;
} hearing_adda_param_t;
/*Microphone采样率和采样点数配置*/
#if DHA_NS_ENABLE
#define HEARING_AID_CLK (160 * 1000000L)
#define DHA_MIC_SAMPLE_RATE TCFG_AUDIO_DHA_MIC_SAMPLE_RATE
#define DHA_MIC_SAMPLE_POINT (DHA_MIC_SAMPLE_RATE / 200)
#else
#define HEARING_AID_CLK (160 * 1000000L)
#define DHA_MIC_SAMPLE_RATE TCFG_AUDIO_DHA_MIC_SAMPLE_RATE
#define DHA_MIC_SAMPLE_POINT 64
#endif/*DHA_NS_ENABLE*/
#if (DHA_MIC_SAMPLE_RATE == TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE)
/*输入输出采样率一致条件编译自动关闭SRC使能*/
#undef DHA_SRC_ENABLE
#define DHA_SRC_ENABLE 0
#endif/*DHA_MIC_SAMPLE_RATE*/
static const hearing_adda_param_t hearing_adda_param = {
.mic_ch_sel = TCFG_AD2DA_LOW_LATENCY_MIC_CHANNEL,
.mic_gain = 12,
.sample_rate = DHA_MIC_SAMPLE_RATE,//采样率
.adc_irq_points = DHA_MIC_SAMPLE_POINT,//一次处理数据的数据单元, 单位点 4对齐(要配合mic起中断点数修改)
.adc_buf_num = 3,
#if (TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE == 44100)
.dac_delay = (DHA_MIC_SAMPLE_POINT *TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE / DHA_MIC_SAMPLE_RATE) /
(TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE / 1000) + 5,//dac硬件混响延时 单位ms 要大于 point_unit*2
#else
.dac_delay = (DHA_MIC_SAMPLE_POINT *TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE / DHA_MIC_SAMPLE_RATE) /
(TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE / 1000) + 3,//dac硬件混响延时 单位ms 要大于 point_unit*2
#endif
};
//*********************************************************************************//
// mic能量检测处理配置 //
//*********************************************************************************//
typedef struct {
struct audio_dac_channel dac_ch;
struct adc_mic_ch mic_ch;
struct audio_adc_output_hdl adc_output;
s16 *adc_dma_buf;
OS_SEM sem;
#if DHA_MIC_DATA_CBUF_ENABLE
s16 *run_buf;
u8 *data_buf;
cbuffer_t mic_cbuf;
#else
s16 *mic_data_addr;
s32 mic_data_len;
#endif /*DHA_MIC_DATA_CBUF_ENABLE*/
u8 task_release;
u8 task_exit;
volatile u8 task_busy;
u16 fade_in_gain;
#if DHA_HS_FS_ENABLE
HOWLING_API_STRUCT *hs_fs;
HOWLING_API_STRUCT *hs_fs_1;
#endif /*DHA_HS_FS_ENABLE*/
#if DHA_HS_NOTCH_ENABLE
HOWLING_API_STRUCT *hs_notch;
HOWLING_API_STRUCT *hs_notch_1;
#endif /*DHA_HS_NOTCH_ENABLE*/
#if (DHA_EQ_ENABLE || DHA_DRC_ENABLE)
struct dec_eq_drc *hearing_eq_drc;
#endif /*(DHA_EQ_ENABLE || DHA_DRC_ENABLE)*/
#if (DHA_EQ2_ENABLE)
struct audio_eq *hearing_eq2;
#endif /*(DHA_EQ2_ENABLE)*/
#if DHA_NS_ENABLE
void *llns;
void *llns_1;
#endif /*DHA_NS_ENABLE*/
#if DHA_SRC_ENABLE
#if DHA_SRC_USE_HW_ENABLE
struct audio_src_handle *hw_src;
#else
s16 src_out_data[480];
#endif/*DHA_SRC_USE_HW_ENABLE*/
#endif /*DHA_SRC_ENABLE*/
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
s16 mono_to_dual[(DHA_MIC_SAMPLE_POINT * TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE / DHA_MIC_SAMPLE_RATE) * 2 + 8];
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
/*双声道处理双变单,单变双使用*/
s16 *tmp_buf;
s16 *tmp_buf_1;
u8 channel;
} hearing_aid_t;
static hearing_aid_t *hearing_hdl = NULL;
static u32 start_ts = 0;
static u32 end_ts = 0;
enum {
DHA_STATE_CLOSE,
DHA_STATE_OPEN,
DHA_STATE_SUSPEND,
};
typedef struct {
volatile u8 state; /*辅听状态*/
volatile u8 fitting_state; /*验配状态*/
u8 fitting; /*听力验配模式标识*/
u8 volume;
u16 timer;
} hearing_aid_schedule_t;
hearing_aid_schedule_t dha_schedule = {0};
/*保留EQ段做自定义滤波使用*/
#define DHA_REV0_FREQ 100
#define DHA_REV1_FREQ 16000
#define MIC_EQ_SECTION 8
static struct eq_seg_info audio_mic_eq_tab[MIC_EQ_SECTION] = {
{0, EQ_IIR_TYPE_BAND_PASS, DHA_CH0_FREQ, 0, 1.0f},
{1, EQ_IIR_TYPE_BAND_PASS, DHA_CH1_FREQ, 0, 1.0f},
{2, EQ_IIR_TYPE_BAND_PASS, DHA_CH2_FREQ, 0, 1.4f},
{3, EQ_IIR_TYPE_BAND_PASS, DHA_CH3_FREQ, 0, 1.4f},
{4, EQ_IIR_TYPE_BAND_PASS, DHA_CH4_FREQ, 0, 1.4f},
{5, EQ_IIR_TYPE_BAND_PASS, DHA_CH5_FREQ, 0, 2.0f},
{6, EQ_IIR_TYPE_HIGH_PASS, DHA_REV0_FREQ, 0, 1.0f},
{7, EQ_IIR_TYPE_LOW_PASS, DHA_REV1_FREQ, 0, 0.7f},
};
/*听力验配频点列表*/
static u16 sine_freq[] = {
DHA_CH0_FREQ,
DHA_CH1_FREQ,
DHA_CH2_FREQ,
DHA_CH3_FREQ,
DHA_CH4_FREQ,
DHA_CH5_FREQ
};
static u8 sine_idx = 2;
static u16 dac_digital_vol = 0;
int audio_dac_set_digital_vol(struct audio_dac_hdl *dac, u16 vol);
u16 audio_dac_get_digital_vol(void)
{
u16 vol = 0;
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_MONO_L)
vol = JL_AUDIO->DAC_VL0 & 0x0000ffff;
#else
vol = (JL_AUDIO->DAC_VL0 >> 16) & 0x0000ffff;
#endif
return vol;
}
extern void put_float(double fv);
/*
*********************************************************************
* Audio Hearing-aid Fitting
* Description: Hearing Level Fitting
* Arguments : NULL
* Return : NULL
* Note(s) :
*********************************************************************
*/
dha_fitting_adjust_t dha_fitting_result[DHA_FITTING_CHANNEL_MAX];
int fitting_param_write(u8 LR, void *buf);
extern u32 hearing_aid_rcsp_response(u8 *data, u16 data_len);
extern u32 hearing_aid_rcsp_notify(u8 *data, u16 data_len);
static int hearing_aid_eq_filter_updata(float *EQGain);
int hearing_aid_fitting_parse(u8 *data, u16 len)
{
u8 tmp[4];
u8 cmd = data[0];
u16 data_len = (data[2] << 8) | data[1];
printf("cmd %x, data_len %d\n", cmd, data_len);
switch (cmd) {
case DHA_FITTING_CMD_INFO:
break;
case DHA_FITTING_CMD_ADJUST:
printf("DHA_FITTING_CMD_ADJUST\n");
dha_fitting_adjust_t adjust;
if (data_len > sizeof(dha_fitting_adjust_t)) {
/*数据长度错误*/
printf("data_len err !!!");
return 0;
}
memcpy(&adjust, &data[3], data_len);
hearing_aid_fitting_start(adjust.sine);
if (adjust.sine) {//开始验配,需要波单频音
audio_dac_set_digital_vol(&dac_hdl, (u16)(16384 * adjust.gain / 100));
printf("dval : %d\n", (u16)(16384 * adjust.gain / 100));
#if TCFG_USER_TWS_ENABLE
enum audio_channel channel = tws_api_get_local_channel() == 'R' ? AUDIO_CH_R : AUDIO_CH_L;
if ((channel == AUDIO_CH_L) && (adjust.channel == 0)) { //当前是左耳,并且数据是设置左耳时
for (int i = 0; i < DHA_FITTING_CHANNEL_MAX; i++) {
if (audio_mic_eq_tab[i].freq == adjust.freq) {
/* audio_mic_eq_tab[i].gain = adjust.gain; */
sine_idx = i;
printf("L idx %d, freq %d, gain %d\n", sine_idx, audio_mic_eq_tab[i].freq, (int)adjust.gain);
break;
}
}
} else if ((channel == AUDIO_CH_R) && (adjust.channel == 1)) { //当前是右耳,并且数据是设置右耳时
for (int i = 0; i < DHA_FITTING_CHANNEL_MAX; i++) {
if (audio_mic_eq_tab[i].freq == adjust.freq) {
/* audio_mic_eq_tab[i].gain = adjust.gain; */
sine_idx = i;
printf("R idx %d, freq %d, gain %d\n", sine_idx, audio_mic_eq_tab[i].freq, (int)adjust.gain);
break;
}
}
}
#else
//没有TWS时,不判断左右耳直接设置单频音
for (int i = 0; i < DHA_FITTING_CHANNEL_MAX; i++) {
if (audio_mic_eq_tab[i].freq == adjust.freq) {
/* audio_mic_eq_tab[i].gain = adjust.gain; */
sine_idx = i;
printf("L idx %d, freq %d, gain %d\n", sine_idx, audio_mic_eq_tab[i].freq, (int)adjust.gain);
break;
}
}
#endif /*TCFG_USER_TWS_ENABLE*/
}
/*回复辅听状态信息*/
get_hearing_aid_state_cmd_info(tmp);
hearing_aid_rcsp_response(tmp, 4);
break;
case DHA_FITTING_CMD_UPDATE:
printf("DHA_FITTING_CMD_UPDATE\n");
float EQGain[12];
if (data_len > sizeof(EQGain)) {
/*数据长度错误*/
printf("data_len err !!!");
return 0;
}
/*回复辅听状态信息*/
get_hearing_aid_state_cmd_info(tmp);
hearing_aid_rcsp_response(tmp, 4);
/*退出验配状态*/
dha_schedule.fitting = 0;
dha_schedule.fitting_state = 0;
u8 LR = data[3]; //左右耳数据标志
memcpy(EQGain, &data[4], data_len);
/*更新验配数据到辅听*/
hearing_aid_eq_filter_updata(EQGain);
/*保存验配数据到vm*/
fitting_param_write(LR, EQGain);
for (int i = 0; i < data_len / 4; i++) {
put_float(EQGain[i]);
}
/*恢复允许播歌*/
if (get_hearing_aid_fitting_state() == 0) {
extern void a2dp_tws_dec_resume(void);
a2dp_tws_dec_resume();
}
break;
}
return 0;
}
/*获取辅听左右耳状态信息*/
int get_hearing_aid_state_cmd_info(u8 *data)
{
dha_fitting_state_t dha_fitting_state;
#if TCFG_USER_TWS_ENABLE
if (get_bt_tws_connect_status()) { //对耳已经配对
dha_fitting_state.state_left = dha_schedule.state == DHA_STATE_OPEN ? 1 : 0;
dha_fitting_state.state_right = dha_schedule.state == DHA_STATE_OPEN ? 1 : 0;
} else { /*tws 单只耳时*/
enum audio_channel channel = tws_api_get_local_channel() == 'R' ? AUDIO_CH_R : AUDIO_CH_L;
if (channel == AUDIO_CH_L) { //当前是左耳
dha_fitting_state.state_left = dha_schedule.state == DHA_STATE_OPEN ? 1 : 0;
dha_fitting_state.state_right = 0;
} else if (channel == AUDIO_CH_R) { //当前是右耳
dha_fitting_state.state_left = 0;
dha_fitting_state.state_right = dha_schedule.state == DHA_STATE_OPEN ? 1 : 0;
}
}
#else /*没有开tws单只耳当作左耳*/
dha_fitting_state.state_left = dha_schedule.state == DHA_STATE_OPEN ? 1 : 0;
dha_fitting_state.state_right = 0;
#endif /*TCFG_USER_TWS_ENABLE*/
data[0] = DHA_FITTING_CMD_STATE;
data[1] = sizeof(dha_fitting_state);
data[2] = 0;
data[3] = ((u8 *)&dha_fitting_state)[0];
put_buf(data, 4);
return 0;
}
/*获取辅听验配状态*/
u8 get_hearing_aid_fitting_state(void)
{
return dha_schedule.fitting || dha_schedule.fitting_state ? 1 : 0;
}
/*获取验配信息*/
int get_hearing_aid_fitting_info(u8 *data)
{
hearing_aid_t *hdl = (hearing_aid_t *)hearing_hdl;
if (data && hearing_hdl) {
dha_fitting_info_t dha_info = {
.version = DHA_FITTING_VERSION,
.ch_num = DHA_FITTING_CHANNEL_MAX,
.ch_freq[0] = DHA_CH0_FREQ,
.ch_freq[1] = DHA_CH1_FREQ,
.ch_freq[2] = DHA_CH2_FREQ,
.ch_freq[3] = DHA_CH3_FREQ,
.ch_freq[4] = DHA_CH4_FREQ,
.ch_freq[5] = DHA_CH5_FREQ,
};
memcpy(data, &dha_info, sizeof(dha_info));
return sizeof(dha_info);
} else {
return 0;
}
}
/*判断是否播放单频音
* en:
* BIT(0) = 1 BIT(0) = 0
* BIT(1) = 1 BIT(1) = 0
* */
int hearing_aid_fitting_start(u8 en)
{
hearing_aid_t *hdl = (hearing_aid_t *)hearing_hdl;
printf("fitting en: %d", en);
if (hdl) {
#if TCFG_USER_TWS_ENABLE
if (en) { //需要播单频音
enum audio_channel channel = tws_api_get_local_channel() == 'R' ? AUDIO_CH_R : AUDIO_CH_L;
if (channel == AUDIO_CH_L) { //当前是左耳
//判断是否设置左耳
if (en & BIT(0)) { //设置左耳时左耳播放单频音
dha_schedule.fitting = 1;
} else { //设置右耳时左耳静音
dha_schedule.fitting = 2;
}
} else if (channel == AUDIO_CH_R) { //当前是右耳
//判断是否设置右耳
if (en & BIT(1)) { //设置右耳时右耳播放单频音
dha_schedule.fitting = 1;
} else { //设置左耳时右耳静音
dha_schedule.fitting = 2;
}
}
} else { //关闭单频音
dha_schedule.fitting = en;
}
#else
//没有TWS时
dha_schedule.fitting = en ? 1 : 0;
#endif /*TCFG_USER_TWS_ENABLE*/
if (dha_schedule.fitting == 0) {
audio_dac_set_digital_vol(&dac_hdl, dac_digital_vol);
}
dha_schedule.fitting_state = dha_schedule.fitting;
printf("dha_schedule.fitting : %d", dha_schedule.fitting);
return dha_schedule.fitting;
}
return -1;
}
u8 set_hearing_aid_fitting_state(u8 state)
{
dha_schedule.fitting_state = state;
return dha_schedule.fitting_state;
}
/*同步关闭辅听验配*/
void audio_dha_fitting_sync_close(void)
{
#if TCFG_USER_TWS_ENABLE
if (get_tws_sibling_connect_state()) {
if (tws_api_get_role() == TWS_ROLE_MASTER) {
printf("[tws_master]fitting close");
bt_tws_play_tone_at_same_time(SYNC_TONE_DHA_FITTING_CLOSE, 400);
}
} else {
hearing_aid_fitting_start(0);
}
#else
hearing_aid_fitting_start(0);
#endif/*TCFG_USER_TWS_ENABLE*/
set_hearing_aid_fitting_state(0);
}
/*
*
* LR: 0 1 2
* buf:
*/
int fitting_param_write(u8 LR, void *buf)
{
float EQGain[DHA_FITTING_CHANNEL_MAX * 2];
int ret = 0;
ret = syscfg_read(CFG_DHA_FITTING_ID, EQGain, DHA_FITTING_CHANNEL_MAX * 2 * 4);
if (ret != DHA_FITTING_CHANNEL_MAX * 2 * 4) {
printf("vm fitting param empty\n");
}
if (LR == 0) { /*写左耳数据*/
memcpy(EQGain, (u8 *)buf, DHA_FITTING_CHANNEL_MAX * 4);
} else if (LR == 1) { /*写右耳数据*/
memcpy(EQGain + DHA_FITTING_CHANNEL_MAX, (u8 *)buf, DHA_FITTING_CHANNEL_MAX * 4);
} else if (LR == 2) { /*写对耳数据*/
memcpy(EQGain, (u8 *)buf, DHA_FITTING_CHANNEL_MAX * 2 * 4);
}
syscfg_write(CFG_DHA_FITTING_ID, EQGain, sizeof(EQGain));
return 0;
}
/*读取当前耳机(左耳/右耳)验配参数*/
int fitting_param_read(void *buf)
{
float EQGain[DHA_FITTING_CHANNEL_MAX * 2];
int ret = 0;
ret = syscfg_read(CFG_DHA_FITTING_ID, EQGain, DHA_FITTING_CHANNEL_MAX * 2 * 4);
if (ret != DHA_FITTING_CHANNEL_MAX * 2 * 4) {
printf("vm fitting param read err\n");
return 0;
}
/*判断是否清除过数据,全是0xFF表示是清除过数据*/
u8 *data = (u8 *)EQGain;
u8 cnt = 0;
for (u8 i = 0; i < 4; i++) {
if (data[i] == 0xFF) {
cnt++;
}
}
if (cnt >= 4) {
return 0;
}
#if TCFG_USER_TWS_ENABLE
if (get_bt_tws_connect_status()) { //对耳已经配对
enum audio_channel channel = tws_api_get_local_channel() == 'R' ? AUDIO_CH_R : AUDIO_CH_L;
if (channel == AUDIO_CH_L) { //当前是左耳,使用第一组数据
memcpy((u8 *)buf, EQGain, DHA_FITTING_CHANNEL_MAX * 4);
} else if (channel == AUDIO_CH_R) { //当前是右耳,使用第二组数据
memcpy((u8 *)buf, EQGain + DHA_FITTING_CHANNEL_MAX, DHA_FITTING_CHANNEL_MAX * 4);
}
} else
#endif /*TCFG_USER_TWS_ENABLE*/
{
//没有配对时,使用第一组数据
memcpy((u8 *)buf, EQGain, DHA_FITTING_CHANNEL_MAX * 4);
}
return ret >> 1;
}
/*清除验配参数
* LR: 0 1 2
*/
int clear_fitting_patam(u8 LR)
{
float EQGain[DHA_FITTING_CHANNEL_MAX * 2];
int ret = 0;
ret = syscfg_read(CFG_DHA_FITTING_ID, EQGain, DHA_FITTING_CHANNEL_MAX * 2 * 4);
if (ret != DHA_FITTING_CHANNEL_MAX * 2 * 4) {
printf("vm fitting param empty\n");
}
if (LR == 0) { /*清楚左耳参数*/
memset(EQGain, 0xFF, DHA_FITTING_CHANNEL_MAX * 4);
} else if (LR == 1) { /*清楚右耳参数*/
memset(EQGain + DHA_FITTING_CHANNEL_MAX, 0xFF, DHA_FITTING_CHANNEL_MAX * 4);
} else if (LR == 2) { /*清楚对耳参数*/
memset(EQGain, 0xFF, DHA_FITTING_CHANNEL_MAX * 2 * 4);
}
syscfg_write(CFG_DHA_FITTING_ID, EQGain, sizeof(EQGain));
return 0;
}
#if DHA_SRC_ENABLE
#include "Resample_api.h"
static RS_STUCT_API *sw_src_api = NULL;
static u8 *sw_src_buf = NULL;
int hearing_output(hearing_aid_t *hdl, s16 *data, u16 len);
static int hearing_aid_hw_src_output_handler(void *priv, s16 *data, int len);
static int hearing_src_init(hearing_aid_t *hdl, u8 nch, u16 insample, u16 outsample)
{
printf("hearing_src_init,insr:%d,outsr:%d\n", insample, outsample);
#if DHA_SRC_USE_HW_ENABLE
if (insample != TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE) {
printf("hw src in %d, out %d\n", insample, TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE);
hdl->hw_src = zalloc(sizeof(struct audio_src_handle));
if (hdl->hw_src) {
u8 channel = nch;
audio_hw_src_open(hdl->hw_src, channel, AUDIO_RESAMPLE_SYNC_OUTPUT);
audio_hw_src_set_rate(hdl->hw_src, insample, TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE);
audio_src_set_output_handler(hdl->hw_src, hdl, (void (*)(void *, void *, int))hearing_output);
printf("audio hw src open succ %x", hdl->hw_src);
} else {
printf("hdl->hw_src malloc fail !!!\n");
}
}
#else
if (insample != outsample) {
sw_src_api = get_rs16_context();
/* sw_src_api = get_rsfast_context(); */
printf("sw_src_api:0x%x\n", sw_src_api);
ASSERT(sw_src_api);
u32 sw_src_need_buf = sw_src_api->need_buf();
printf("sw_src_buf:%d\n", sw_src_need_buf);
sw_src_buf = zalloc(sw_src_need_buf);
ASSERT(sw_src_buf);
RS_PARA_STRUCT rs_para_obj;
rs_para_obj.nch = nch;
rs_para_obj.new_insample = insample;
rs_para_obj.new_outsample = outsample;
printf("sw src,in = %d,out = %d\n", rs_para_obj.new_insample, rs_para_obj.new_outsample);
sw_src_api->open(sw_src_buf, &rs_para_obj);
}
return 0;
#endif/*DHA_SRC_USE_HW_ENABLE*/
}
static int hearing_src_run(hearing_aid_t *hdl, s16 *indata, s16 *outdata, u16 len)
{
#if DHA_SRC_USE_HW_ENABLE
if (hdl->hw_src) {
return audio_src_resample_write(hdl->hw_src, indata, len);
}
#else
int outlen = len;
if (sw_src_api && sw_src_buf) {
outlen = sw_src_api->run(sw_src_buf, indata, len >> 1, outdata);
/* ASSERT(outlen <= (sizeof(outdata) >> 1)); */
outlen = outlen << 1;
/* printf("%d\n",outlen); */
} else {
memcpy(outdata, indata, len);
}
return outlen;
#endif/*DHA_SRC_USE_HW_ENABLE*/
}
static void hearing_src_exit(hearing_aid_t *hdl)
{
#if DHA_SRC_USE_HW_ENABLE
printf("[HW]hearing_src_exit\n");
if (hdl->hw_src) {
audio_hw_src_stop(hdl->hw_src);
audio_hw_src_close(hdl->hw_src);
free(hdl->hw_src);
hdl->hw_src = NULL;
}
#else
printf("[SW]hearing_src_exit\n");
if (sw_src_buf) {
free(sw_src_buf);
sw_src_buf = NULL;
sw_src_api = NULL;
}
#endif/*DHA_SRC_USE_HW_ENABLE*/
}
#endif /*DHA_SRC_ENABLE*/
#if DHA_SRC_ENABLE
static void hearing_volume_run(s16 *data, int len);
static int hearing_aid_hw_src_output_handler(void *priv, s16 *data, int len)
{
hearing_aid_t *hdl = (hearing_aid_t *)hearing_hdl;
if (!hdl) {
return 0;
}
s16 *mic_data = data;
int data_len = len;
int wlen = 0;
#if DHA_VOLUME_ENABLE
hearing_volume_run(mic_data, data_len);
#endif/*DHA_VOLUME_ENABLE*/
#if DHA_RUN_TIME_TRACE_ENABLE
end_ts = jiffies_msec();
printf("run_time:%d - %d = %d\n", end_ts, start_ts, (end_ts - start_ts));
#endif/*DHA_RUN_TIME_TRACE_ENABLE*/
DHA_IO_DEBUG_0();
// 写入DAC
wlen = sound_pcm_dev_write(&hdl->dac_ch, data, len);
hdl->task_busy = 0;
return len;
}
#endif /*DHA_SRC_ENABLE*/
#if DHA_NS_ENABLE
/*
* 16k 32k
* 16k采样率时,80(5ms)
* 32k采样率时 160(5ms)
*/
static const u16 llns_frame_size[2][2] = {
{16000, 160},//80点
{32000, 320},//160点
/* {44100, 440},//220点 */
/* {48000, 480},//240点 */
};
typedef struct {
char *private_buf;
char *share_buf;
s16 inbuf[160];
s16 in_pool[320];
cbuffer_t in_cbuf;
int frame_size;
void *llns;
} llns_hdl_t;
/* static llns_hdl_t *llns_hdl = NULL; */
static int llns_exit(void *hdl);
static void *llns_init(int sr, float gainfloor, float suppress_level)
{
llns_hdl_t *llns_hdl = zalloc(sizeof(llns_hdl_t));
if (llns_hdl == NULL) {
printf("llns_hdl zalloc err !!!!\n");
return -1;
}
cbuf_init(&llns_hdl->in_cbuf, llns_hdl->in_pool, sizeof(llns_hdl->in_pool));
printf("%s %d", __func__, __LINE__);
int private_heap_size, share_heap_size;
audio_llns_heap_query(&share_heap_size, &private_heap_size, sr);
printf("private_heap_size:%d,share_heap_size:%d\n", private_heap_size, share_heap_size);
llns_hdl->private_buf = (char *)zalloc(private_heap_size);
llns_hdl->share_buf = (char *)zalloc(share_heap_size);
/*判断是否支持的采样率*/
llns_hdl->frame_size = 0;
for (int i = 0; i < ARRAY_SIZE(llns_frame_size); i++) {
//printf("llns_frame_size[%d] = %d",i,llns_frame_size[i][0]);
if (llns_frame_size[i][0] == sr) {
//printf("llns sr math:%d\n",sr);
llns_hdl->frame_size = llns_frame_size[i][1];
}
}
if (llns_hdl->frame_size == 0) {
printf("samplerate only support 16k or 32k !!!\n");
return -1;
}
printf("sr: %d, gainfloor: %d/100\n", sr, (int)(gainfloor * 100));
llns_hdl->llns = audio_llns_init(llns_hdl->private_buf, private_heap_size, llns_hdl->share_buf, share_heap_size, sr, gainfloor, suppress_level);
ASSERT(llns_hdl->llns);
printf("llns init ok\n");
return llns_hdl;
}
static int llns_run(void *hdl, s16 *data, int len)
{
llns_hdl_t *llns_hdl = (llns_hdl_t *)hdl;
int llns_outsize = 0, llns_outsize1 = 0;
if (llns_hdl) {
if (len != llns_hdl->frame_size) {
putchar('B');
}
cbuf_write(&llns_hdl->in_cbuf, data, len);
if (cbuf_read(&llns_hdl->in_cbuf, llns_hdl->inbuf, llns_hdl->frame_size) == llns_hdl->frame_size) {
llns_outsize = audio_llns_run(llns_hdl->llns, llns_hdl->inbuf, llns_hdl->frame_size, data);
//llns_outsize = len >> 1;
}
}
return llns_outsize << 1;
}
static int llns_exit(void *hdl)
{
llns_hdl_t *llns_hdl = (llns_hdl_t *)hdl;
if (llns_hdl) {
audio_llns_close(llns_hdl->llns);
llns_hdl->llns = NULL;
if (llns_hdl->private_buf) {
free(llns_hdl->private_buf);
llns_hdl->private_buf = NULL;
}
if (llns_hdl->share_buf) {
free(llns_hdl->share_buf);
llns_hdl->share_buf = NULL;
}
free(llns_hdl);
llns_hdl = NULL;
}
return 0;
}
#endif /*DHA_NS_ENABLE*/
#if (DHA_EQ_ENABLE || DHA_DRC_ENABLE)
static int hearing_aid_eq_get_filter_info(void *eq, int sr, struct audio_eq_filter_info *info)
{
struct audio_eq *eq_hdl = (struct audio_eq *)eq;
if (!eq_hdl) {
return -1;
}
local_irq_disable();
u8 nsection = ARRAY_SIZE(audio_mic_eq_tab);
if (!eq_hdl->eq_coeff_tab) {
eq_hdl->eq_coeff_tab = zalloc(sizeof(int) * 5 * nsection);
}
for (int i = 0; i < nsection; i++) {
eq_seg_design(&audio_mic_eq_tab[i], sr, &eq_hdl->eq_coeff_tab[5 * i]);
}
local_irq_enable();
info->L_coeff = info->R_coeff = (void *)eq_hdl->eq_coeff_tab;
info->L_gain = info->R_gain = 0;
info->nsection = nsection;
return 0;
}
/*限幅器drc*/
static float Gain_dB = 1;
static struct drc_ch mic_drc_p = {0};
static int hearing_aid_drc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
{
float th = -10.0f;//单位:dB 范围:-60dB~0dB,限幅器阈值
Gain_dB = 7.0f; /*drc压制后要放大的dB数*/
Gain_dB = powf(10.0f, Gain_dB / 20.0f);
int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
mic_drc_p.nband = 1;
mic_drc_p.type = 1; //1:限幅器
mic_drc_p._p.limiter[0].attacktime = 5;
mic_drc_p._p.limiter[0].releasetime = 500;
mic_drc_p._p.limiter[0].threshold[0] = threshold;
mic_drc_p._p.limiter[0].threshold[1] = 32768;
info->R_pch = info->pch = &mic_drc_p;
return 0;
}
#define FITTING_EQ_THR 30
static int hearing_aid_eq_filter_updata(float *EQGain)
{
hearing_aid_t *hdl = (hearing_aid_t *)hearing_hdl;
if (hdl == NULL) {
return -1;
}
float max = 100 - FITTING_EQ_THR;
for (int i = 0; i < DHA_FITTING_CHANNEL_MAX; i++) {
if (EQGain[i] > FITTING_EQ_THR) {
audio_mic_eq_tab[i].gain = (EQGain[i] - FITTING_EQ_THR) * 12.0f / max;
} else {
audio_mic_eq_tab[i].gain = 0;
}
put_float(audio_mic_eq_tab[i].gain);
}
struct dec_eq_drc *eq_drc = hdl->hearing_eq_drc;
struct audio_eq *eq = eq_drc->eq;
if (eq_drc == NULL || eq == NULL) {
return -1;
}
eq->updata = 1;
return 0;
}
void *hearing_eq_drc_open(u32 sample_rate, u8 ch_num)
{
#if TCFG_EQ_ENABLE
struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
/* struct audio_eq_drc *eff = zalloc(sizeof(struct audio_eq_drc)); */
struct audio_eq_param eq_param = {0};
/* eff->priv = priv; */
/* eff->out_cb = eq_output_cb; */
eq_param.channels = ch_num;
eq_param.online_en = 1;
eq_param.mode_en = 0;
eq_param.remain_en = 0;
eq_param.no_wait = 0;
eq_param.out_32bit = 0;
#if TCFG_AUDIO_DHA_FITTING_ENABLE
eq_param.max_nsection = MIC_EQ_SECTION;
eq_param.cb = hearing_aid_eq_get_filter_info;
#else
eq_param.max_nsection = EQ_SECTION_MAX;
eq_param.cb = eq_get_filter_info;
#endif /*TCFG_AUDIO_DHA_FITTING_ENABLE*/
eq_param.eq_name = hearing_aid_mode;
eq_param.sr = sample_rate;
/* eq_param.priv = eff; */
/* eq_param.output = eq_output; */
eff->eq = audio_dec_eq_open(&eq_param);
#if (TCFG_DRC_ENABLE && DHA_DRC_ENABLE)
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = ch_num;
drc_param.online_en = 1;
drc_param.remain_en = 0;
drc_param.out_32bit = 0;
#if DHA_USE_WDRC_ENABLE
drc_param.cb = drc_get_filter_info;
#else
drc_param.cb = hearing_aid_drc_get_filter_info;
#endif /*DHA_USE_WDRC_ENABLE*/
drc_param.drc_name = hearing_aid_mode;
eff->drc = audio_dec_drc_open(&drc_param);
eff->async = 0;
#endif //TCFG_DRC_ENABLE
return eff;
#else
return NULL;
#endif//TCFG_EQ_ENABLE
}
void hearing_eq_drc_run(struct dec_eq_drc *eq_drc, void *data, u32 len)
{
struct dec_eq_drc *eff_hdl = (struct dec_eq_drc *)eq_drc;
#if DHA_EQ_ENABLE
if (eff_hdl->eq) {
audio_eq_run(eff_hdl->eq, data, len);
}
#endif/*DHA_EQ_ENABLE*/
#if DHA_DRC_ENABLE
if (eff_hdl->drc) {
audio_drc_run(eff_hdl->drc, data, len);
#if (DHA_USE_WDRC_ENABLE == 0)
GainProcess_16Bit(data, data, Gain_dB, 1, 1, 1, len >> 1);
#endif /*DHA_USE_WDRC_ENABLE == 0*/
}
#endif/*DHA_DRC_ENABLE*/
}
void hearing_eq_drc_close(struct dec_eq_drc *eq_drc)
{
#if TCFG_EQ_ENABLE
struct dec_eq_drc *eff_hdl = (struct dec_eq_drc *)eq_drc;
/* struct audio_eq_drc *eff_hdl = (struct audio_eq_drc *)eq_drc; */
if (eff_hdl->eq) {
audio_dec_eq_close(eff_hdl->eq);
eff_hdl->eq = NULL;
}
if (eff_hdl->drc) {
audio_dec_drc_close(eff_hdl->drc);
eff_hdl->drc = NULL;
}
free(eff_hdl);
#endif
return;
}
#endif /*(DHA_EQ_ENABLE || DHA_DRC_ENABLE)*/
#if (TCFG_EQ_ENABLE && DHA_EQ2_ENABLE)
void *hearing_eq2_open(u32 sample_rate, u8 ch_num)
{
struct audio_eq *eq;
struct audio_eq_param eq_param = {0};
/* eff->priv = priv; */
/* eff->out_cb = eq_output_cb; */
eq_param.channels = ch_num;
eq_param.online_en = 1;
eq_param.mode_en = 0;
eq_param.remain_en = 0;
eq_param.no_wait = 0;
eq_param.out_32bit = 0;
eq_param.max_nsection = EQ_SECTION_MAX;
eq_param.cb = eq_get_filter_info;
eq_param.eq_name = hearing_aid_mode2;
eq_param.sr = sample_rate;
/* eq_param.priv = eff; */
/* eq_param.output = eq_output; */
eq = audio_dec_eq_open(&eq_param);
return eq;
}
void hearing_eq2_run(struct audio_eq *eq, void *data, u32 len)
{
if (eq) {
audio_eq_run(eq, data, len);
}
}
void hearing_eq2_close(struct audio_eq *eq)
{
if (eq) {
audio_dec_eq_close(eq);
eq = NULL;
}
}
#endif /*TCFG_EQ_ENABLE && DHA_EQ2_ENABLE*/
/*
*********************************************************************
* Audio Hearing-aid Fade In
* Description:
* Arguments : data
* points
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
#define HEARING_AID_FADEIN_SHIFT (14)
#define HEARING_AID_FADEIN_GAIN_MAX (1 << HEARING_AID_FADEIN_SHIFT)
static void hearing_fade_in_run(s16 *data, u16 points)
{
if (hearing_hdl->fade_in_gain < HEARING_AID_FADEIN_GAIN_MAX) {
s32 tmp_data;
for (int i = 0; i < points; i++) {
tmp_data = data[i];
data[i] = (tmp_data * hearing_hdl->fade_in_gain) >> HEARING_AID_FADEIN_SHIFT;
if (++hearing_hdl->fade_in_gain >= HEARING_AID_FADEIN_GAIN_MAX) {
return;
}
}
}
}
#if DHA_VOLUME_ENABLE
/*
*********************************************************************
* Audio Hearing-aid Volume
* Description:
* Arguments : data
* points
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
/*数字音量*/
static void hearing_volume_run(s16 *data, int len)
{
#if 0
static u16 vol_dbg = 0;
if (vol_dbg++ > 500) {
vol_dbg = 0;
printf("[DHA]Volume:%d\n", audio_digital_vol_get(HEARING_DVOL));
}
#endif
audio_digital_vol_run(HEARING_DVOL, data, len);
}
/*设置音量*/
static void hearing_volume_set(u8 volume)
{
dha_schedule.volume = volume;
audio_digital_vol_set(HEARING_DVOL, volume);
}
/*获取当前音量大小*/
static int hearing_volume_get(void)
{
return audio_digital_vol_get(HEARING_DVOL);
}
/*打开数字音量*/
static void hearing_volume_open(u8 volume)
{
dha_schedule.volume = (volume > HEARING_DVOL_MAX) ? HEARING_DVOL_MAX : volume;
audio_digital_vol_open(HEARING_DVOL, dha_schedule.volume, HEARING_DVOL_MAX, HEARING_DVOL_FS, -1);
}
/*关闭数字音量*/
static void hearing_volume_close(void)
{
audio_digital_vol_close(HEARING_DVOL);
}
#endif /*DHA_VOLUME_ENABLE*/
/*
*********************************************************************
* Audio Hearing-aid TDE
* Description: Time Delay Estimation
* Arguments : NULL
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
typedef struct {
u16 tick;
u16 delay_points_max;
u16 delay_time_max;
} hearing_aid_tde_t;
hearing_aid_tde_t dha_dte;
void hearing_tde_run(void)
{
if (dha_dte.tick ++ > 2000) {
dha_dte.tick = 0;
extern int audio_dac_data_len();
u16 time_unit = DHA_MIC_SAMPLE_RATE / 1000;
u16 delay_points = audio_dac_data_len();
u16 delay_time = (delay_points + (time_unit >> 1)) / time_unit;
delay_time = delay_time + ((DHA_MIC_SAMPLE_POINT * 1000) / DHA_MIC_SAMPLE_RATE);
if (delay_points > dha_dte.delay_points_max) {
dha_dte.delay_points_max = delay_points;
}
if (delay_time > dha_dte.delay_time_max) {
dha_dte.delay_time_max = delay_time;
}
printf("[DHA]delay_est:%d(points),%d(ms)\n", delay_points, delay_time);
//printf("[DHA]delay_est_max:%d(points),%d(ms)\n",dha_dte.delay_points_max,dha_dte.delay_time_max);
}
}
/*
*********************************************************************
* Audio Hearing-aid Mic Raw Data Handle
* Description:
* Arguments : NULL
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
static void hearing_mic_output_handler(void *priv, s16 *data, int len)
{
hearing_aid_t *hdl = (hearing_aid_t *)priv;
DHA_IO_INTERVAL();
if (hdl == NULL) {
return;
}
len = len * hdl->channel;
#if DHA_MIC_DATA_CBUF_ENABLE
int wlen = cbuf_write(&hdl->mic_cbuf, data, len);
if (wlen != len) {
/* putchar('f'); */
printf("hearing aid mic cbuf full !!!\n");
/* audio_codec_clock_check(); */
}
#else
hdl->mic_data_addr = data;
hdl->mic_data_len = len;
/*判断上一次数据是否已经处理完了*/
if (hdl->task_busy) {
putchar('&');
/* audio_codec_clock_check(); */
/* printf("hearing aid need to increase sys_clock"); */
}
#endif /*DHA_MIC_DATA_CBUF_ENABLE*/
os_sem_set(&hdl->sem, 0);
os_sem_post(&hdl->sem);
}
static int hearing_aid_mic_en(u8 en, hearing_adda_param_t *param)
{
hearing_aid_t *hdl = (hearing_aid_t *)hearing_hdl;
if (hdl == NULL) {
printf("hearing_aid_mic_en error! hdl == NULL");
return -1;;
}
if (en) {
printf("dha mic en, ch %d, sr %d, gain %d", param->mic_ch_sel, param->sample_rate, param->mic_gain);
u16 mic_ch = param->mic_ch_sel;
u16 mic0_gain = param->mic_gain;
u16 mic1_gain = param->mic_gain;
u16 mic2_gain = param->mic_gain;
u16 mic3_gain = param->mic_gain;
audio_mic_pwr_ctl(MIC_PWR_ON);
if (mic_ch & AUDIO_ADC_MIC_0) {
audio_adc_mic_open(&hdl->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic_set_gain(&hdl->mic_ch, mic0_gain);
}
if (mic_ch & AUDIO_ADC_MIC_1) {
audio_adc_mic1_open(&hdl->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic1_set_gain(&hdl->mic_ch, mic1_gain);
}
if (mic_ch & AUDIO_ADC_MIC_2) {
audio_adc_mic2_open(&hdl->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic2_set_gain(&hdl->mic_ch, mic2_gain);
}
if (mic_ch & AUDIO_ADC_MIC_3) {
audio_adc_mic3_open(&hdl->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic3_set_gain(&hdl->mic_ch, mic3_gain);
}
audio_adc_mic_set_sample_rate(&hdl->mic_ch, param->sample_rate);
printf("adc_dma_buf: %x, size: %d", hdl->adc_dma_buf, param->adc_irq_points * 2 * param->adc_buf_num * hdl->channel);
audio_adc_mic_set_buffs(&hdl->mic_ch, hdl->adc_dma_buf,
param->adc_irq_points * 2, param->adc_buf_num);
hdl->adc_output.handler = hearing_mic_output_handler;
hdl->adc_output.priv = hdl;
audio_adc_add_output_handler(&adc_hdl, &hdl->adc_output);
audio_adc_mic_start(&hdl->mic_ch);
} else {
audio_adc_mic_close(&hdl->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &hdl->adc_output);
audio_mic_pwr_ctl(MIC_PWR_OFF);
}
return 0;
}
/*
*********************************************************************
* Audio Hearing-aid Output
* Description:
* Arguments : NULL
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
int hearing_output(hearing_aid_t *hdl, s16 *data, u16 len)
{
s16 *mic_data = data;
u16 data_len = len;
int wlen = 0;
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
if (hdl->channel == 1) {
/*单变双*/
for (u16 i = 0; i < (len >> 1); i++) {
hdl->mono_to_dual[2 * i] = mic_data[i];
hdl->mono_to_dual[2 * i + 1] = mic_data[i];
}
mic_data = hdl->mono_to_dual;
data_len = len + data_len;
}
#else /*单声道*/
if (hdl->channel == 2) {
/*双变单*/
for (u16 i = 0; i < (len >> 2); i++) {
/*左右声道混合成单声道会变成杂音*/
mic_data[i] = mic_data[2 * i];
/* mic_data[i] = mic_data[2 * i + 1]; */
/* mic_data[i] = ((int)mic_data[2 * i] + (int)mic_data[2 * i + 1]) / 2; */
}
data_len = len / 2;
}
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
// 写入DAC
//putchar('o');
int offset = 0;
int cnt = 0;
do {
wlen = sound_pcm_dev_write(&hdl->dac_ch, mic_data + (offset >> 1), data_len - offset);
offset = offset + wlen;
cnt ++;
} while ((offset != data_len) && (cnt < 1000));
if (offset != data_len) {
/* putchar('D'); */
printf("dac write err :%d %d\n", data_len, offset);
}
return len;
}
/*
*********************************************************************
* Audio Hearing-aid Task
* Description:
* Arguments : NULL
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
static LOUDNESS_M_STRUCT dha_in_loudness;
static LOUDNESS_M_STRUCT dha_out_loudness;
static void audio_hearing_aid_task(void *p)
{
int err = 0;
int wlen = 0;
s16 *mic_data = NULL;
int data_len = 0;
hearing_aid_t *hdl = (hearing_aid_t *)p;
while (1) {
err = os_sem_pend(&hdl->sem, 0);
if (err || hdl->task_release) {
break;
}
#if DHA_RUN_TIME_TRACE_ENABLE
start_ts = jiffies_msec();
#endif/*DHA_RUN_TIME_TRACE_ENABLE*/
DHA_IO_DEBUG_1();
hdl->task_busy = 1;
#if DHA_MIC_DATA_CBUF_ENABLE
mic_data = hdl->run_buf;
data_len = cbuf_read(&hdl->mic_cbuf, mic_data, DHA_MIC_SAMPLE_POINT * sizeof(short) * hdl->channel);
#else
mic_data = hdl->mic_data_addr;
data_len = hdl->mic_data_len;
#endif /*DHA_MIC_DATA_CBUF_ENABLE*/
int clk = clk_get("sys");
if (clk < HEARING_AID_CLK) {
clk_set("sys", HEARING_AID_CLK);
}
#if ((defined TCFG_AUDIO_DHA_LOW_POWER_ENABLE) && TCFG_AUDIO_DHA_LOW_POWER_ENABLE)
audio_hearing_aid_lp_detect(NULL, mic_data, data_len);
#endif /*TCFG_AUDIO_DHA_LOW_POWER_ENABLE*/
#if DHA_IN_LOUDNESS_TRACE_ENABLE
loudness_meter_short(&dha_in_loudness, mic_data, data_len >> 1);
#endif /*DHA_IN_LOUDNESS_TRACE_ENABLE*/
//数据导出
#if DHA_DATA_EXPORT_ENABLE
aec_uart_fill(0, mic_data, data_len);
#endif /*DHA_DATA_EXPORT_ENABLE*/
#if TCFG_AUDIO_DHA_FITTING_ENABLE
if (dha_schedule.fitting) {
if (dha_schedule.fitting == 1) {
/*生成听力验配对应的频点声音*/
extern void sin_pcm_fill(int fc, int fs, void *buf, u32 len);
sin_pcm_fill(sine_freq[sine_idx], DHA_MIC_SAMPLE_RATE, mic_data, data_len);
} else if (dha_schedule.fitting == 2) {
memset(mic_data, 0, data_len);
}
} else
#endif /*TCFG_AUDIO_DHA_FITTING_ENABLE*/
{
// 算法处理
if (hdl->channel == 1) {
#if DHA_HS_FS_ENABLE
if (hdl->hs_fs) {
run_howling(hdl->hs_fs, mic_data, mic_data, data_len >> 1);
}
#endif/*DHA_HS_FS_ENABLE*/
#if DHA_HS_NOTCH_ENABLE
if (hdl->hs_notch) {
run_howling(hdl->hs_notch, mic_data, mic_data, data_len >> 1);
}
#endif/*DHA_HS_NOTCH_ENABLE*/
} else {
/*双变单*/
for (int i = 0; i < data_len / 4; i++) {
hdl->tmp_buf[i] = mic_data[2 * i];
hdl->tmp_buf_1[i] = mic_data[2 * i + 1];
}
#if DHA_HS_FS_ENABLE
if (hdl->hs_fs && hdl->hs_fs_1) {
run_howling(hdl->hs_fs, hdl->tmp_buf, hdl->tmp_buf, data_len >> 2);
run_howling(hdl->hs_fs_1, hdl->tmp_buf_1, hdl->tmp_buf_1, data_len >> 2);
}
#endif/*DHA_HS_FS_ENABLE*/
#if DHA_HS_NOTCH_ENABLE
if (hdl->hs_notch && hdl->hs_notch_1) {
run_howling(hdl->hs_notch, hdl->tmp_buf, hdl->tmp_buf, data_len >> 2);
run_howling(hdl->hs_notch_1, hdl->tmp_buf_1, hdl->tmp_buf_1, data_len >> 2);
}
#endif/*DHA_HS_NOTCH_ENABLE*/
/*单变双*/
for (int i = 0; i < data_len / 4; i++) {
mic_data[2 * i] = hdl->tmp_buf[i];
mic_data[2 * i + 1] = hdl->tmp_buf_1[i];
}
}
#if (DHA_EQ_ENABLE || DHA_DRC_ENABLE)
if (hdl->hearing_eq_drc) {
hearing_eq_drc_run(hdl->hearing_eq_drc, mic_data, data_len);
}
#endif/*DHA_EQ_ENABLE || DHA_DRC_ENABLE*/
#if (TCFG_EQ_ENABLE && DHA_EQ2_ENABLE)
if (hdl->hearing_eq2) {
hearing_eq2_run(hdl->hearing_eq2, mic_data, data_len);
}
#endif /*TCFG_EQ_ENABLE && DHA_EQ2_ENABLE*/
#if DHA_NOISE_GATE_ENABLE
audio_noise_gate_run(mic_data, mic_data, data_len);
#endif/*DHA_NOISE_GATE_ENABLE*/
#if DHA_NS_ENABLE
if (hdl->channel == 1) {
if (hdl->llns) {
data_len = llns_run(hdl->llns, mic_data, data_len);
}
} else {
/*双变单*/
for (int i = 0; i < data_len / 4; i++) {
hdl->tmp_buf[i] = mic_data[2 * i];
hdl->tmp_buf_1[i] = mic_data[2 * i + 1];
}
if (hdl->llns) {
llns_run(hdl->llns, hdl->tmp_buf, data_len / 2);
}
if (hdl->llns_1) {
llns_run(hdl->llns_1, hdl->tmp_buf_1, data_len / 2);
}
/*单变双*/
for (int i = 0; i < data_len / 4; i++) {
mic_data[2 * i] = hdl->tmp_buf[i];
mic_data[2 * i + 1] = hdl->tmp_buf_1[i];
}
}
#endif /*DHA_NS_ENABLE*/
#if DHA_FADEIN_ENABLE
hearing_fade_in_run(mic_data, (data_len >> 1));
#endif/*DHA_FADEIN_ENABLE*/
}
#if DHA_VOLUME_ENABLE
hearing_volume_run(mic_data, data_len);
#endif/*DHA_VOLUME_ENABLE*/
//数据导出
#if DHA_DATA_EXPORT_ENABLE
aec_uart_fill(1, mic_data, data_len);
aec_uart_write();
#endif /*DHA_DATA_EXPORT_ENABLE*/
#if DHA_OUT_LOUDNESS_TRACE_ENABLE
loudness_meter_short(&dha_out_loudness, mic_data, data_len >> 1);
#endif /*DHA_OUT_LOUDNESS_TRACE_ENABLE*/
#if DHA_SRC_ENABLE
#if DHA_SRC_USE_HW_ENABLE
hearing_src_run(hdl, mic_data, NULL, data_len);
continue;
#else
data_len = hearing_src_run(hdl, mic_data, hdl->src_out_data, data_len);
if (data_len) {
mic_data = hdl->src_out_data;
}
#endif/*DHA_SRC_USE_HW_ENABLE*/
#endif /*DHA_SRC_ENABLE*/
//result output
hearing_output(hdl, mic_data, data_len);
#if DHA_TDE_ENABLE
hearing_tde_run();
#endif/*DHA_TDE_ENABLE*/
#if DHA_RUN_TIME_TRACE_ENABLE
end_ts = jiffies_msec();
printf("run_time:%d - %d = %d\n", end_ts, start_ts, (end_ts - start_ts));
#endif/*DHA_RUN_TIME_TRACE_ENABLE*/
DHA_IO_DEBUG_0();
hdl->task_busy = 0;
}
hdl->task_exit = 1;
while (1) {
os_time_dly(100);
}
}
/*
*********************************************************************
* Audio Hearing-aid Open
* Description:
* Arguments : NULL
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
int audio_hearing_aid_open(void)
{
printf("audi_hearing_aid_open\n");
int err = 0;
hearing_adda_param_t *param = &hearing_adda_param;
hearing_aid_t *hdl = hearing_hdl;
if (hdl != NULL) {
printf("hdl != NULL!");
return err;
}
#if TCFG_AUDIO_DHA_AND_MUSIC_MUTEX
/*播歌互斥时播歌不开辅听*/
extern u8 bt_media_is_running(void);
if (bt_media_is_running()) {
dha_schedule.state = DHA_STATE_SUSPEND;
return 0;
}
#endif /*TCFG_AUDIO_DHA_AND_MUSIC_MUTEX*/
#if TCFG_AUDIO_DHA_AND_CALL_MUTEX
/*通话互斥时通话不开辅听*/
extern u8 bt_phone_dec_is_running();
if (bt_phone_dec_is_running()) {
dha_schedule.state = DHA_STATE_SUSPEND;
return 0;
}
#endif /*TCFG_AUDIO_DHA_AND_CALL_MUTEX*/
#if TCFG_AUDIO_DHA_AND_TONE_MUTEX
/*提示音互斥时播提示音不开辅听*/
extern int tone_get_status();
extern int sine_get_status();
if (tone_get_status() || sine_get_status()) {
dha_schedule.state = DHA_STATE_SUSPEND;
return 0;
}
#endif /*TCFG_AUDIO_DHA_AND_TONE_MUTEX*/
#if TCFG_AUTO_SHUT_DOWN_TIME
sys_auto_shut_down_disable();
#endif/*TCFG_AUTO_SHUT_DOWN_TIME*/
mem_stats();
hdl = zalloc(sizeof(hearing_aid_t));
if (hdl == NULL) {
printf("hdl malloc error!");
goto __err;
}
hearing_hdl = hdl;
hdl->channel = 0;
u8 mic_ch = hearing_adda_param.mic_ch_sel;
if (mic_ch & AUDIO_ADC_MIC_0) {
hdl->channel++;
}
if (mic_ch & AUDIO_ADC_MIC_1) {
hdl->channel++;
}
if (mic_ch & AUDIO_ADC_MIC_2) {
hdl->channel++;
}
if (mic_ch & AUDIO_ADC_MIC_3) {
hdl->channel++;
}
printf(" hdl channel %d", hdl->channel);
u32 adc_dma_size = param->adc_irq_points * param->adc_buf_num * sizeof(short) * hdl->channel;
if (adc_dma_size == 0) {
printf("adc_dma_size == NULL!");
goto __err;
}
hdl->adc_dma_buf = zalloc(adc_dma_size);
if (hdl->adc_dma_buf == NULL) {
printf("hdl->adc_dma_buf malloc error!");
goto __err;
}
#if DHA_MIC_DATA_CBUF_ENABLE
hdl->run_buf = zalloc(DHA_MIC_SAMPLE_POINT * sizeof(short) * hdl->channel);
hdl->data_buf = zalloc(DHA_MIC_SAMPLE_POINT * sizeof(short) * hdl->channel * 3);
cbuf_init(&hdl->mic_cbuf, hdl->data_buf, DHA_MIC_SAMPLE_POINT * sizeof(short) * hdl->channel * 3);
#endif /*DHA_MIC_DATA_CBUF_ENABLE*/
if (hdl->channel == 2) {
hdl->tmp_buf = zalloc(DHA_MIC_SAMPLE_POINT * sizeof(short));
hdl->tmp_buf_1 = zalloc(DHA_MIC_SAMPLE_POINT * sizeof(short));
}
clk_set("sys", HEARING_AID_CLK);
/* audio_codec_clock_set(HEARING_AID_MODE, AUDIO_CODING_PCM, 0); */
#if TCFG_AUDIO_DHA_FITTING_ENABLE
/*读取验配参数*/
float EQGain[DHA_FITTING_CHANNEL_MAX];
err = fitting_param_read(EQGain);
if (err == DHA_FITTING_CHANNEL_MAX * 4) {
put_buf(EQGain, DHA_FITTING_CHANNEL_MAX * 4);
/*更新验配数据到辅听*/
hearing_aid_eq_filter_updata(EQGain);
} else {
printf("default fitting param !!!\n");
}
#endif /*TCFG_AUDIO_DHA_FITTING_ENABLE*/
#if DHA_IN_LOUDNESS_TRACE_ENABLE
loudness_meter_init(&dha_in_loudness, param->sample_rate, 50, 0);
#endif /*DHA_IN_LOUDNESS_TRACE_ENABLE*/
#if DHA_OUT_LOUDNESS_TRACE_ENABLE
loudness_meter_init(&dha_out_loudness, param->sample_rate, 50, 1);
#endif /*DHA_IN_LOUDNESS_TRACE_ENABLE*/
//memcpy(&hdl->param, param, sizeof(struct __ad2da_low_latency_param));
os_sem_create(&hdl->sem, 0);
err = task_create(audio_hearing_aid_task, (void *)hdl, HEARING_AID_TASK_NAME);
if (err != OS_NO_ERR) {
printf("task create error!");
goto __err;
}
dha_schedule.fitting = 0;
dha_schedule.fitting_state = 0;
//mem_stats();
#if ((defined TCFG_AUDIO_DHA_LOW_POWER_ENABLE) && TCFG_AUDIO_DHA_LOW_POWER_ENABLE)
audio_hearing_aid_lp_open(1, audio_hearing_aid_open, audio_hearing_aid_close);
#endif /*TCFG_AUDIO_DHA_LOW_POWER_ENABLE*/
//数据导出
#if DHA_DATA_EXPORT_ENABLE
aec_uart_open(2, param->adc_irq_points * 2);
#endif /*DHA_DATA_EXPORT_ENABLE*/
// 算法初始化
#if DHA_HS_FS_ENABLE
///啸叫抑制初始化
hdl->hs_fs = open_howling(NULL, param->sample_rate, 0, 1);//mode 1:移频
printf("open_howling %x\n\n\n", hdl->hs_fs);
if (hdl->channel == 2) {
hdl->hs_fs_1 = open_howling(NULL, param->sample_rate, 0, 1);//mode 1:移频
printf("open_howling_1 %x\n\n\n", hdl->hs_fs_1);
}
//mem_stats();
#endif/*DHA_HS_FS_ENABLE*/
#if DHA_HS_NOTCH_ENABLE
HOWLING_PARM_SET howling_param_default = {
.threshold = 25,
.sample_rate = param->sample_rate,
.channel = 1,
.fade_time = 10,
.notch_Q = 2.0f,
.notch_gain = -20.0f,
};
hdl->hs_notch = open_howling(&howling_param_default, param->sample_rate, 0, 0);//mode 0:陷波
printf("open_notch howling %x\n\n\n", hdl->hs_notch);
if (hdl->channel == 2) {
hdl->hs_notch_1 = open_howling(&howling_param_default, param->sample_rate, 0, 0);//mode 0:陷波
printf("open_notch howling_1 %x\n\n\n", hdl->hs_notch_1);
}
//mem_stats();
#endif/*DHA_HS_NOTCH_ENABLE*/
#if DHA_NOISE_GATE_ENABLE
/*限幅器上限*/
#define LIMITER_THR -3000 /*-12000 = -12dB,放大1000倍,(-10000参考)*/
/*小于CONST_NOISE_GATE的当成噪声处理,防止清0近端声音*/
#define LIMITER_NOISE_GATE -40000 /*-12000 = -12dB,放大1000倍,(-30000参考)*/
/*低于噪声门限阈值的增益 */
#define LIMITER_NOISE_GAIN ((int) (0.2 * (1 << 30))) /*(0~1)*2^30*/
audio_noise_gate_open(param->sample_rate, LIMITER_THR, LIMITER_NOISE_GATE, LIMITER_NOISE_GAIN);
#endif/*DHA_NOISE_GATE_ENABLE*/
#if (DHA_EQ_ENABLE || DHA_DRC_ENABLE)
hdl->hearing_eq_drc = hearing_eq_drc_open(param->sample_rate, hdl->channel);
printf("hearing_eq_drc open %x\n\n\n", hdl->hearing_eq_drc);
//mem_stats();
#endif/*DHA_EQ_ENABLE || DHA_DRC_ENABLE*/
#if (TCFG_EQ_ENABLE && DHA_EQ2_ENABLE)
hdl->hearing_eq2 = hearing_eq2_open(param->sample_rate, hdl->channel);
printf("hearing_eq2 open %x\n\n\n", hdl->hearing_eq2);
#endif /*TCFG_EQ_ENABLE && DHA_EQ2_ENABLE*/
#if DHA_NS_ENABLE
hdl->llns = llns_init(param->sample_rate, 0.05f, 1.0f);
if (hdl->channel == 2) {
hdl->llns_1 = llns_init(param->sample_rate, 0.05f, 1.0f);
}
//mem_stats();
#endif /*DHA_NS_ENABLE*/
#if DHA_SRC_ENABLE
hearing_src_init(hdl, hdl->channel, param->sample_rate, TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE);
//mem_stats();
#endif /*DHA_SRC_ENABLE*/
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, get_max_sys_vol(), 1);
#if DHA_VOLUME_ENABLE
hearing_volume_open(HEARING_DVOL_MAX);
#endif /*DHA_VOLUME_ENABLE*/
// DAC 初始化
audio_dac_new_channel(&dac_hdl, &hdl->dac_ch);
struct audio_dac_channel_attr attr;
attr.delay_time = param->dac_delay;
attr.protect_time = 8;
attr.write_mode = WRITE_MODE_FORCE;
audio_dac_channel_set_attr(&hdl->dac_ch, &attr);
sound_pcm_dev_start(&hdl->dac_ch, TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
#if DHA_DAC_OUTPUT_ENHANCE_ENABLE
//DAC输出音量增强使能
app_audio_dac_vol_mode_set(1);
#endif /*DHA_DAC_OUTPUT_ENHANCE_ENABLE*/
dac_digital_vol = audio_dac_get_digital_vol();
printf("dac_digital_vol : %d\n", dac_digital_vol);
#if DHA_TDE_ENABLE
memset(&dha_dte, 0, sizeof(dha_dte));
#endif/*DHA_TDE_ENABLE*/
/* hearing_volume_set(14); */
DHA_IO_DEBUG_INIT();
// ADC 初始化
hearing_aid_mic_en(1, param);
dha_schedule.state = DHA_STATE_OPEN;
printf("audio_hearing_aid_open success!");
mem_stats();
return 0;
__err:
if (hdl) {
if (hdl->adc_dma_buf) {
free(hdl->adc_dma_buf);
}
free(hdl);
}
hearing_hdl = NULL;
#if TCFG_AUTO_SHUT_DOWN_TIME
sys_auto_shut_down_enable();
#endif/*TCFG_AUTO_SHUT_DOWN_TIME*/
printf("audio_hearing_aid_open error!");
return -1;
}
void audio_hearing_aid_sync_open(void)
{
#if TCFG_USER_TWS_ENABLE
if (get_tws_sibling_connect_state()) {
if (tws_api_get_role() == TWS_ROLE_MASTER) {
printf("[tws_master]dha open");
bt_tws_play_tone_at_same_time(SYNC_TONE_HEARING_AID_OPEN, 400);
}
} else {
audio_hearing_aid_open();
}
#else
audio_hearing_aid_open();
#endif/*TCFG_USER_TWS_ENABLE*/
}
/*
*********************************************************************
* Audio Hearing-aid Close
* Description:
* Arguments : NULL
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
int audio_hearing_aid_close(void)
{
int err = 0;
hearing_aid_t *hdl = (hearing_aid_t *)hearing_hdl;
printf("[DHA]audio_hearing_aid_close\n");
if (hdl == NULL) {
if (dha_schedule.state == DHA_STATE_SUSPEND) {
printf("[DHA]hearing-aid suspend now\n");
dha_schedule.state = DHA_STATE_CLOSE;
return 0;
}
printf("audio_hearing_aid_close error! hdl == NULL");
return -1;
}
// ADC 关闭
hearing_aid_mic_en(0, NULL);
hdl->task_release = 1;
os_sem_set(&hdl->sem, 0);
os_sem_post(&hdl->sem);
while (hdl->task_exit == 0) {
os_time_dly(1);
}
err = task_kill(HEARING_AID_TASK_NAME);
os_sem_del(&hdl->sem, 0);
// DAC 关闭
sound_pcm_dev_stop(&hdl->dac_ch);
#if DHA_DAC_OUTPUT_ENHANCE_ENABLE
app_audio_dac_vol_mode_set(0);
#endif /*DHA_DAC_OUTPUT_ENHANCE_ENABLE*/
#if DHA_HS_FS_ENABLE
if (hdl->hs_fs) {
printf("close_howling\n\n\n");
close_howling(hdl->hs_fs);
}
if (hdl->hs_fs_1) {
printf("close_howling_1\n\n\n");
close_howling(hdl->hs_fs_1);
}
#endif/*DHA_HS_FS_ENABLE*/
#if DHA_HS_NOTCH_ENABLE
if (hdl->hs_notch) {
printf("close_howling\n\n\n");
close_howling(hdl->hs_notch);
}
if (hdl->hs_notch_1) {
printf("close_howling\n\n\n");
close_howling(hdl->hs_notch_1);
}
#endif/*DHA_HS_NOTCH_ENABLE*/
#if DHA_NOISE_GATE_ENABLE
audio_noise_gate_close();
#endif/*DHA_NOISE_GATE_ENABLE*/
#if (DHA_EQ_ENABLE || DHA_DRC_ENABLE)
if (hdl->hearing_eq_drc) {
hearing_eq_drc_close(hdl->hearing_eq_drc);
}
#endif/*DHA_EQ_ENABLE || DHA_DRC_ENABLE*/
#if (TCFG_EQ_ENABLE && DHA_EQ2_ENABLE)
if (hdl->hearing_eq2) {
hearing_eq2_close(hdl->hearing_eq2);
}
#endif /*TCFG_EQ_ENABLE && DHA_EQ2_ENABLE*/
#if DHA_NS_ENABLE
if (hdl->llns) {
llns_exit(hdl->llns);
hdl->llns = NULL;
if (hdl->llns_1) {
llns_exit(hdl->llns_1);
hdl->llns_1 = NULL;
}
}
#endif /*DHA_NS_ENABLE*/
#if DHA_SRC_ENABLE
hearing_src_exit(hdl);
#endif /*DHA_SRC_ENABLE*/
#if DHA_VOLUME_ENABLE
hearing_volume_close();
#endif /*DHA_VOLUME_ENABLE*/
//数据导出
#if DHA_DATA_EXPORT_ENABLE
aec_uart_close();
#endif /*DHA_DATA_EXPORT_ENABLE*/
#if DHA_MIC_DATA_CBUF_ENABLE
if (hdl->run_buf) {
free(hdl->run_buf);
hdl->run_buf = NULL;
}
if (hdl->data_buf) {
free(hdl->data_buf);
hdl->data_buf = NULL;
}
#endif /*DHA_MIC_DATA_CBUF_ENABLE*/
if (hdl->adc_dma_buf) {
free(hdl->adc_dma_buf);
hdl->adc_dma_buf = NULL;
}
if (hdl->tmp_buf) {
free(hdl->tmp_buf);
hdl->tmp_buf = NULL;
}
if (hdl->tmp_buf_1) {
free(hdl->tmp_buf_1);
hdl->tmp_buf_1 = NULL;
}
free(hdl);
hearing_hdl = NULL;
/* audio_codec_clock_del(HEARING_AID_MODE); */
// 算法关闭
dha_schedule.state = DHA_STATE_CLOSE;
#if TCFG_AUDIO_DHA_FITTING_ENABLE
/*验配过程关闭辅听主动告诉app*/
extern u8 get_rcsp_connect_status(void);
if (get_rcsp_connect_status()) {
/*主动推送辅听状态信息*/
u8 tmp[4];
get_hearing_aid_state_cmd_info(tmp);
hearing_aid_rcsp_notify(tmp, 4);
}
#endif /*TCFG_AUDIO_DHA_FITTING_ENABLE*/
dha_schedule.fitting = 0;
dha_schedule.fitting_state = 0;
#if TCFG_AUTO_SHUT_DOWN_TIME
sys_auto_shut_down_enable();
#endif/*TCFG_AUTO_SHUT_DOWN_TIME*/
printf("audio_hearing_aid_close success!\n");
return 0;
}
char *dha_state_str[] = {
"close",
"open",
"suspend",
"error",
};
/*TWS配对后状态同步*/
u8 get_hearing_aid_state(void)
{
return dha_schedule.state;
}
static void hearing_aid_state_sync_deal(void *param)
{
printf("[DHA]sync open,cur_state = %s\n", dha_state_str[dha_schedule.state]);
if (dha_schedule.timer) {
sys_timer_del(dha_schedule.timer);
dha_schedule.timer = 0;
}
if (dha_schedule.state == DHA_STATE_OPEN) {
audio_hearing_aid_open();
}
}
void hearing_aid_state_sync(u8 state)
{
if (dha_schedule.state != state) {
dha_schedule.state = state;
printf("[DHA]open, cur_state= %s,timer:0x%x\n", dha_state_str[dha_schedule.state], dha_schedule.timer);
if ((dha_schedule.state == DHA_STATE_OPEN) && (dha_schedule.timer == 0)) {
dha_schedule.timer = sys_timer_add(NULL, hearing_aid_state_sync_deal, 1500);
}
}
}
/*
*********************************************************************
* Audio Hearing-aid Demo
* Description:
* Arguments : NULL
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
void audio_hearing_aid_demo(void)
{
hearing_aid_t *hdl = (hearing_aid_t *)hearing_hdl;
printf("audio_hearing_aid_demo,toggle = %x\n", hdl);
if (hdl == NULL) {
audio_hearing_aid_sync_open();
} else {
/*验配过程中不允许按键关闭辅听*/
if (get_hearing_aid_fitting_state()) {
return;
}
audio_hearing_aid_close();
}
}
/*
*********************************************************************
* Audio Hearing-aid Schedule
* Description: suspend or resume
* Arguments : NULL
* Return : NULL
* Note(s) : NULL
*********************************************************************
*/
void audio_hearing_aid_suspend(void)
{
#if DHA_AND_MEDIA_MUTEX_ENABLE
printf("[DHA]suspend,cur_state = %s\n", dha_state_str[dha_schedule.state]);
if (dha_schedule.timer) {
printf("[DHA]schedule timer delete\n");
sys_timer_del(dha_schedule.timer);
dha_schedule.timer = 0;
}
if (hearing_hdl) {
audio_hearing_aid_close();
dha_schedule.state = DHA_STATE_SUSPEND;
}
#endif/*DHA_AND_MEDIA_MUTEX_ENABLE*/
}
static void hearing_aid_schedule(void *priv)
{
printf("[DHA]schedule,cur_state = %s\n", dha_state_str[dha_schedule.state]);
sys_timer_del(dha_schedule.timer);
dha_schedule.timer = 0;
if (dha_schedule.state == DHA_STATE_SUSPEND) {
audio_hearing_aid_sync_open();
}
}
void audio_hearing_aid_resume(void)
{
#if DHA_AND_MEDIA_MUTEX_ENABLE
printf("[DHA]resume, cur_state= %s,timer:0x%x\n", dha_state_str[dha_schedule.state], dha_schedule.timer);
if ((dha_schedule.state == DHA_STATE_SUSPEND) && (dha_schedule.timer == 0)) {
dha_schedule.timer = sys_timer_add(NULL, hearing_aid_schedule, 2500);
}
#endif/*DHA_AND_MEDIA_MUTEX_ENABLE*/
}
static u8 hearing_aid_idle_query()
{
#if ((defined TCFG_AUDIO_DHA_LOW_POWER_ENABLE) && TCFG_AUDIO_DHA_LOW_POWER_ENABLE)
if (audio_hearing_aid_lp_flag()) {
return 1; //进入低功耗
} else {
return 0; //不能进
}
#else
return hearing_hdl ? 0 : 1;
#endif /*TCFG_AUDIO_DHA_LOW_POWER_ENABLE*/
}
REGISTER_LP_TARGET(hearing_aid_lp_target) = {
.name = "hearing_aid",
.is_idle = hearing_aid_idle_query,
};
#endif //TCFG_AUDIO_HEARING_AID_ENABLE