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

1987 lines
61 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
****************************************************************
* 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