海思HISI 3518EV200 AEC回音消除+ANR语音降噪

问题描述:

HISI 3518EV200 平台开发的IPC产品,其中具有对讲功能,能和手机APP端进行全双工双向对讲,但全双工的时候碰到一个问题,就是会产生回音,当人在手机APP端说话时,往往能听到设备端回回来的回音(设备端喇叭播放的声音经过MIC又传回手机端)。

 

解决方法:

  1. 外接回音消除芯片+电路的方法,但从成本的角度来说该方法会增加几块钱的成本(被放弃)。
  2. 利用海思自带的AEC回音抵消功能,来消除回音,能节省成本(采用该方法)。

实际情况:

AEC采用默认的参数设置,发现全双工语音对讲仍然有回音,虽然听不

出回音的内容,但能确定是自己说话的回过来的声音。

 

方法详解(本文都是针对方法2来展开的):

  1. AEC回音抵消:

         依据HISI开发文档:

  • AEC功能 介绍:

与其他功能模块只需要 Sin 数据不同, AEC 模块需要 Sin(Signal In)和 Rin

(Reference In)两路数据来进行算法处理,最终得到处理后的 sou(Signal Out)数据。

其中, Sin 为加入了回声的近端输入, Rin 为参考帧(回声)数据。成功启用回声抵消

需要具备一定条件:单声道模式,工作采样率为 8kHz、 16kHz,且 MIC 采集语音数据

的 AI 帧长和远程语音播放的 AO 配置帧长必须相同。以上条件 AI 和 AO 都必须满

足。

以上标红部分为HISI开发文档注明开启AEC功能需要满足的条件。需自行满足。

所以代码中,AEC 和 ANR 功能都放到AI AO初始化的部分来做了(ANR语音降噪功能在做

AEC功能时顺便就做了ANR)。

 

  • 再看AEC的相关参数配置数据结构(其中每一项的详细介绍见HISI文档):
typedef struct hiAI_AEC_CONFIG_S
{
    HI_BOOL bUsrMode;
    HI_S8 s8CngMode; /* cosy-noisy mode:0 close,1 open, default 1*/
    HI_S8 s8NearAllPassEnergy;
    HI_S8 s8NearCleanSupEnergy;
    HI_S16 s16DTHnlSortQTh;
    HI_S16 s16EchoBandLow;
    HI_S16 s16EchoBandHigh;
    HI_S16 s16EchoBandLow2;
    HI_S16 s16EchoBandHigh2;
    HI_S16 s16ERLBand[6];
    HI_S16 s16ERL[7];
    HI_S16 s16VioceProtectFreqL;
    HI_S16 s16VioceProtectFreqL1;
    HI_S32 s32Reserved;
} AI_AEC_CONFIG_S;

 

关于该数据结构,其中有几点注意的,HISI完档中提到了 :

【注意事项】

  • 当用户模式开启时,其他参数才生效,否则按照 AI_VQE_CONFIG_S/AI_TALKVQE_CONFIG_S 中的工作模式 enWorkstate 对应的默认值来配置。
  • 配置参数时,只有在用户模式开启时,才会对高级参数做正确性检查,只有正确的高级参数才能配置成功。

【相关数据类型及接口】

AI_VQE_CONFIG_S

 

在完成AEC功能的添加,采用默认的参数设置后,发现全双工语音对讲仍然有回音(虽然听不出回音的内容,但能确定是自己说话的回过来的声音)。后来经过调整“语音处理频段”的高低频参数范围来达到了消除回音的效果:

stAiVqeAttr.stAecCfg.s16EchoBandLow = 10; //default:10

stAiVqeAttr.stAecCfg.s16EchoBandHigh = 25; //default:41

stAiVqeAttr.stAecCfg.s16EchoBandLow2 = 28; //default:47

stAiVqeAttr.stAecCfg.s16EchoBandHigh2 = 35; //default:63

 

 

附上代码:

AI部分:

/*****************************************************************************
函数名称:StartAudioAI
函数功能:开启输入,单通道chid  --1
输入参数:无
输出参数:无
返   回    值:无
使用说明: 内部调用

******************************************************************************/
 
int Audio::StartAudioAI()
{
     
    HI_S32  s32Ret;
    AUDIO_DEV AiDevId = 0;   
    AI_CHN AiChn = 0;
    s32Ret = HI_MPI_AI_SetPubAttr(AiDevId, &m_stAioAttr);
    if (s32Ret)
    {
        printf("%s: HI_MPI_AI_SetPubAttr(%d) failed with %#x\n", __FUNCTION__, AiDevId, s32Ret);
        return HI_FAILURE;
    }
    if (HI_MPI_AI_Enable(AiDevId))
    {
        printf("%s: HI_MPI_AI_Enable(%d) failed with %#x\n", __FUNCTION__, AiDevId, s32Ret);
        return HI_FAILURE;
    }                
 
    if (HI_MPI_AI_EnableChn(AiDevId, AiChn))
    {
        printf("%s: HI_MPI_AI_EnableChn(%d,%d) failed with %#x\n", __FUNCTION__,\
                AiDevId, AiChn, s32Ret);
        return HI_FAILURE;
    }
#if 1
    HI_S16 s16ERLBand[6] = {4,6,36,49,50,51};
    HI_S16 s16ERL[7] = {7,10,16,10,18,18,18};
    #define SAMPLE_AUDIO_PTNUMPERFRM   160
     
    AI_VQE_CONFIG_S stAiVqeAttr;   
    stAiVqeAttr.s32WorkSampleRate    = AUDIO_SAMPLE_RATE_8000;
    stAiVqeAttr.s32FrameSample       = SAMPLE_AUDIO_PTNUMPERFRM;
    stAiVqeAttr.enWorkstate          = VQE_WORKSTATE_COMMON;
     
    //AEC回音消除
    printf("********init AEC******* \n");
    stAiVqeAttr.bAecOpen             = HI_TRUE;
    stAiVqeAttr.stAecCfg.bUsrMode    = HI_TRUE;
    stAiVqeAttr.stAecCfg.s8CngMode   = 0;
    #if 1
   stAiVqeAttr.stAecCfg.s8NearAllPassEnergy = 1; //default:1
   stAiVqeAttr.stAecCfg.s8NearCleanSupEnergy = 2;   //default:2
   stAiVqeAttr.stAecCfg.s16DTHnlSortQTh = 16384;    //default:16384
   stAiVqeAttr.stAecCfg.s16EchoBandLow = 10;     //default:10
   stAiVqeAttr.stAecCfg.s16EchoBandHigh = 25;        //default:41
   stAiVqeAttr.stAecCfg.s16EchoBandLow2 = 28;        //default:47
   stAiVqeAttr.stAecCfg.s16EchoBandHigh2 = 35;       //default:63
   memcpy(&stAiVqeAttr.stAecCfg.s16ERLBand,&s16ERLBand,sizeof(s16ERLBand));//default
    memcpy(&stAiVqeAttr.stAecCfg.s16ERL,&s16ERL,sizeof(s16ERL));//default
   stAiVqeAttr.stAecCfg.s16VioceProtectFreqL = 3;   //default
   stAiVqeAttr.stAecCfg.s16VioceProtectFreqL1 = 6; //default
    #endif
     
     
    stAiVqeAttr.bAgcOpen             = HI_TRUE;
    stAiVqeAttr.stAgcCfg.bUsrMode    = HI_FALSE;
 
    //ANR语音降噪
    stAiVqeAttr.bAnrOpen             = HI_TRUE;
    #if 1
    stAiVqeAttr.stAnrCfg.bUsrMode = HI_TRUE;
    stAiVqeAttr.stAnrCfg.s16NrIntensity = 25; //降噪力度配置,取值为[0, 25]
    stAiVqeAttr.stAnrCfg.s16NoiseDbThr = 60;  //噪声门限配置,取值为[30,60],配置值越大,检测力度越弱,声音更平滑
    stAiVqeAttr.stAnrCfg.s8SpProSwitch = 0;       //音乐检测开关,取值为[0,1]
    #endif
 
    stAiVqeAttr.bHpfOpen             = HI_TRUE;
    stAiVqeAttr.stHpfCfg.bUsrMode    = HI_TRUE;
    stAiVqeAttr.stHpfCfg.enHpfFreq   = AUDIO_HPF_FREQ_150;
     
    stAiVqeAttr.bRnrOpen             = HI_FALSE;
    stAiVqeAttr.bEqOpen              = HI_FALSE;
    stAiVqeAttr.bHdrOpen             = HI_FALSE;      
 
    #define SAMPLE_AUDIO_AO_DEV 0
    AO_CHN AoChn = 0;
     
 
    s32Ret = HI_MPI_AI_SetVqeAttr(AiDevId, AiChn, SAMPLE_AUDIO_AO_DEV, AoChn, &stAiVqeAttr);  
    if (s32Ret)
    {
        printf("%s: HI_MPI_AI_SetVqeAttr(%d) failed with %#x\n", __FUNCTION__, AiDevId, s32Ret);
        return HI_FAILURE;
    }
 
    s32Ret = HI_MPI_AI_EnableVqe(AiDevId, AiChn);
    if (s32Ret)
    {
        printf("%s: HI_MPI_AI_EnableVqe(%d,%d) failed with %#x\n", __FUNCTION__, AiDevId, AiChn, s32Ret);
        return s32Ret;
    }   
#endif
    HI_MPI_AI_EnableChn(AiDevId, 1);
    return HI_SUCCESS;
}

AO部分:

 

/*****************************************************************************
函数名称:StartAudioAO
函数功能:开启输出,双声道
输入参数:无
输出参数:无
返   回    值:无
使用说明: 内部调用
 
******************************************************************************/
 
int Audio::StartAudioAO()
{
     
    HI_S32 s32Ret;
    AUDIO_DEV AoDevId =0;
    AO_CHN AoChn=0;
    ADEC_CHN AdChn=0 ;
    AIO_ATTR_S AioAttr;
    memset(&AioAttr,0x0,sizeof(AIO_ATTR_S));
    memcpy(&AioAttr,&m_stAioAttr,sizeof(AIO_ATTR_S));
    AioAttr.u32PtNumPerFrm = NumPerFrm;
    AioAttr.enBitwidth = AUDIO_BIT_WIDTH_16;
     
//  AIO_ATTR_S *pstAioAttr = &AioAttr;
//  AIO_ATTR_S *pstAioAttr = &m_stAioAttr;
    s32Ret = HI_MPI_AO_SetPubAttr(AoDevId, &AioAttr);
    if(HI_SUCCESS != s32Ret)
    {
        printf("%s: HI_MPI_AO_SetPubAttr(%d) failed with %#x!\n", __FUNCTION__, \
               AoDevId,s32Ret);
        return HI_FAILURE;
    }
    s32Ret = HI_MPI_AO_Enable(AoDevId);
    if(HI_SUCCESS != s32Ret)
    {
        printf("%s: HI_MPI_AO_Enable(%d) failed with %#x!\n", __FUNCTION__, \
               AoDevId, s32Ret);
        return HI_FAILURE;
    }
    MPP_CHN_S stSrcChn,stDestChn;
    AdChn = 0;
    for(unsigned int i=0;i< 1;i++)
    {
        AoChn = i;        
        stSrcChn.enModId = HI_ID_ADEC;
        stSrcChn.s32DevId = 0;
        stSrcChn.s32ChnId = AdChn;
        stDestChn.enModId = HI_ID_AO;
        stDestChn.s32DevId = AoDevId;
        stDestChn.s32ChnId = AoChn;  
        s32Ret = HI_MPI_AO_EnableChn(AoDevId, AoChn);
        if(HI_SUCCESS != s32Ret)
        {
            printf("%s: HI_MPI_AO_EnableChn(%d) failed with %#x!\n", __FUNCTION__,\
                   AoChn, s32Ret);
            return HI_FAILURE;
        }
#if 1
        #define SAMPLE_AUDIO_PTNUMPERFRM 160
        AO_VQE_CONFIG_S stAoVqeAttr;
        memset(&stAoVqeAttr, 0, sizeof(AO_VQE_CONFIG_S));
         
        stAoVqeAttr.bEqOpen            = HI_TRUE;
        stAoVqeAttr.s32WorkSampleRate    = AUDIO_SAMPLE_RATE_8000;
        stAoVqeAttr.s32FrameSample       = SAMPLE_AUDIO_PTNUMPERFRM;
        stAoVqeAttr.enWorkstate          = VQE_WORKSTATE_COMMON;
         
        stAoVqeAttr.bAgcOpen             = HI_TRUE;
        stAoVqeAttr.stAgcCfg.bUsrMode    = HI_FALSE;
         
        stAoVqeAttr.bAnrOpen            = HI_TRUE;
        #if 1
        stAiVqeAttr.stAnrCfg.bUsrMode = HI_TRUE;
        stAiVqeAttr.stAnrCfg.s16NrIntensity = 25;//降噪力度配置,取值为[0, 25]
        stAiVqeAttr.stAnrCfg.s16NoiseDbThr = 60;//噪声门限配置,取值为[30,60],配置值越大,检测力度越弱,声音更平滑
        stAiVqeAttr.stAnrCfg.s8SpProSwitch = 0;//音乐检测开关,取值为[0,1]
        #endif
         
        stAoVqeAttr.bHpfOpen            = HI_TRUE;
        stAoVqeAttr.stHpfCfg.bUsrMode    = HI_TRUE;
        stAoVqeAttr.stHpfCfg.enHpfFreq   = AUDIO_HPF_FREQ_150;
 
        stAoVqeAttr.bEqOpen = HI_FALSE;
         
 
 
         
        s32Ret = HI_MPI_AO_SetVqeAttr(AoDevId, i, &stAoVqeAttr);
        if(HI_SUCCESS != s32Ret)
        {
            printf("line %d: HI_MPI_AO_SetVqeAttr(%d) failed with %#x!\n", __LINE__,\
                   AoChn, s32Ret);
            return HI_FAILURE;
        }
 
        s32Ret = HI_MPI_AO_EnableVqe(AoDevId, i);
        if (s32Ret)
        {
            printf("%s: HI_MPI_AO_EnableVqe(%d,%d) failed with %#x\n", __FUNCTION__, AoDevId, i, s32Ret);
            return s32Ret;
        }
                 
#endif  
        s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn); 
        if(HI_SUCCESS != s32Ret)
        {
            printf("line %d: HI_MPI_SYS_Bind(%d) failed with %#x!\n", __LINE__,\
                   AoChn, s32Ret);
            return HI_FAILURE;
        }
    }
     
 
 
    return HI_SUCCESS;
}

实际调试效果还得以实际设备为准,不同设备不同的电路,会有不一样的噪声干扰等,会导致参数不一样。

 

 

 

你可能感兴趣的:(HI3518EV200,HISI)