精华内容
下载资源
问答
  • webrtc aec3

    2019-08-14 16:47:46
    基于最新webrtc人工抽离出来的aec demo。 与平台抽离,可直接在Linux下编译。 mkdir build cd build cmake ../src; make -j; only aec: ./bin/demo <mic_signal.pcm> <ref_signal.pcm> <aec_output.pcm> aec + aes ...
  • webrtcAEC代码解读.zip

    2019-11-09 20:47:34
    webrtcAEC代码解读,希望能帮助大家。webrtcAEC代码解读,希望能帮助大家。webrtcAEC代码解读,希望能帮助大家。
  • webrtc::EchoCanceller3Config m_config; std::unique_ptr m_remover; std::unique_ptr m_render_buffer; int m_ch; int m_sample_rate; int m_framelength; }; CEchoRemover::CEchoRemover(int ch, int sample_...

     

    class  CEchoRemover :
    	public CObj
    {
    public:
    	
    	_CPP_UTIL_CLASSNAME(CEchoRemover);
    	_CPP_UTIL_QUERYOBJ(CObj);
    
    	static CEchoRemover * CreateObj(int ch ,int sample_rate,int framelength)
    	{
    		CEchoRemover *pObj = new CEchoRemover(ch, sample_rate, framelength);
    		if (pObj == NULL)
    		{
    			return NULL;
    		}
    
    		pObj->__Dynamic();
    		return pObj;
    	}
    	CEchoRemover(int ch, int sample_rate, int framelength);
    	CObjPtr<CObjNetIOBuffer> Process(CObjNetIOBuffer *mic, CObjNetIOBuffer *ref);
    
    	bool operator != (const  CEchoRemover &_this) const;
    	bool operator == (const  CEchoRemover &_this) const;
    public:
    	absl::optional<webrtc::DelayEstimate> m_delay_estimate;
    	std::vector<std::vector<std::vector<float>>> m_micData;
    	std::vector<std::vector<std::vector<float>>> m_refData;
    	webrtc::EchoPathVariability m_echo_path_variability;
    
    	webrtc::EchoCanceller3Config m_config;
    	std::unique_ptr<webrtc::EchoRemover> m_remover;
    	std::unique_ptr<webrtc::RenderDelayBuffer> m_render_buffer;
    
    	int m_ch;
    	int m_sample_rate;
    	int m_framelength;
    };
    CEchoRemover::CEchoRemover(int ch, int sample_rate, int framelength)
    	:m_micData(ch, std::vector<std::vector<float>>(sample_rate/16000,
    		std::vector<float>(framelength, 0.f)))
    	, m_refData(ch, std::vector<std::vector<float>>(sample_rate / 16000,
    		std::vector<float>(framelength, 0.f)))
    	, m_echo_path_variability(false, webrtc::EchoPathVariability::DelayAdjustment::kNone, false)
    {
    	m_ch = ch;
    	m_sample_rate = sample_rate;
    	m_framelength = framelength;
    	m_remover  = std::unique_ptr<webrtc::EchoRemover>(webrtc::EchoRemover::Create(m_config, sample_rate, 1, 1));
    	m_render_buffer = std::unique_ptr<webrtc::RenderDelayBuffer>(webrtc::RenderDelayBuffer::Create(m_config, sample_rate / 16000, 1));
    }
    CObjPtr<CObjNetIOBuffer> CEchoRemover::Process(CObjNetIOBuffer *mic, CObjNetIOBuffer *ref)
    {
    	CObjPtr<CObjNetIOBuffer> out;
    	if (ref == NULL)
    	{
    		return CObjPtr<CObjNetIOBuffer>(mic);
    	}
    	short int *mic_buf = (short int *)mic->m_pBuf;
    	short int *ref_buf = (short int *)ref->m_pBuf;
    
    
    	for (size_t i = 0; i < m_framelength; ++i) 
    	{
    		m_micData[0][0][i] = mic_buf[i];
    		m_refData[0][0][i] = ref_buf[i];
    	}
    
    	m_render_buffer->Insert(m_refData);
    	m_render_buffer->PrepareCaptureProcessing();
    
    	m_remover->ProcessCapture(m_echo_path_variability, false, m_delay_estimate,
    		m_render_buffer->GetRenderBuffer(), &m_micData, &m_refData);
    
    	out.Attach(CObjNetIOBufferSharedMemory::CreateObj(NULL, (m_framelength + 4) * 2 ));
    	mic_buf = (short int *)out->m_pBuf;
    	for (size_t i = 0; i < m_framelength; ++i) {
    		mic_buf[i] = m_micData[0][0][i];
    	}
    	out->m_nDataLen = m_framelength * 2;
    
    	return out;
    }
    bool CEchoRemover::operator != (const  CEchoRemover &_this) const
    {
    	return ((m_ch != _this.m_ch) || (m_sample_rate != _this.m_sample_rate) || (m_framelength != _this.m_framelength));
    }
    bool CEchoRemover::operator == (const  CEchoRemover &_this) const
    {
    	return ((m_ch == _this.m_ch) && (m_sample_rate == _this.m_sample_rate) && (m_framelength == _this.m_framelength));
    }

    企鹅讨论群:777901741

    展开全文
  • WebRTC_AEC_流程图

    2019-03-07 05:00:17
    博文“深入理解WebRTCAEC”的配图,由于不能单纯上传图片,我放到了word里面,请放大查看 博文“深入理解WebRTCAEC”的配图,由于不能单纯上传图片,我放到了word里面,请放大查看
  • 深入浅出 WebRTC AEC(声学回声消除)

    千次阅读 2020-12-10 16:32:06
    自 2011 年 WebRTC 开源以来,无论是其技术架构,还是其中丰富的算法模块都是值得我们细细品味,音频方面熟知的 3A 算法(AGC: Automatic gain control; ANS: Adaptive noise suppression; AEC:

    前言:近年来,音视频会议产品提升着工作协同的效率,在线教育产品突破着传统教育形式的种种限制,娱乐互动直播产品丰富着生活社交的多样性,背后都离不开音视频通信技术的优化与创新,其中音频信息内容传递的流畅性、完整性、可懂度直接决定着用户之间的沟通质量。自 2011 年 WebRTC 开源以来,无论是其技术架构,还是其中丰富的算法模块都是值得我们细细品味,音频方面熟知的 3A 算法(AGC: Automatic gain control; ANS: Adaptive noise suppression; AEC: Acoustic echo cancellation)就是其中闪闪发光的明珠。本文章将结合实例全面解析 WebRTC AEC 的基本框架和基本原理,一起探索回声消除的基本原理,技术难点以及优化方向。

    作者:珞神,阿里云高级开发工程师,负责阿里云 RTC 音频研发

    回声的形成

    WebRTC 架构中上下行音频信号处理流程如图 1,音频 3A 主要集中在上行的发送端对发送信号依次进行回声消除、降噪以及音量均衡(这里只讨论 AEC 的处理流程,如果是 AECM 的处理流程 ANS 会前置),AGC 会作为压限器作用在接收端对即将播放的音频信号进行限幅。

    图 1 WebRTC 中音频信号上下行处理流程框图

    那么回声是怎么形成的呢?

    如图 2 所示,A、B 两人在通信的过程中,我们有如下定义:

    • x(n): 远端参考信号,即 A 端订阅的 B 端音频流,通常作为参考信号;
    • y(n): 回声信号,即扬声器播放信号 x(n) 后,被麦克风采集到的信号,此时经过房间混响以及麦克风采集的信号 y(n) 已经不能等同于信号 x(n) 了, 我们记线性叠加的部分为 y’(n), 非线性叠加的部分为 y’’(n), y(n) = y’(n) + y’’(n);
    • s(n): 麦克风采集的近端说话人的语音信号,即我们真正想提取并发送到远端的信号;
    • v(n):环境噪音,这部分信号会在 ANS 中被削弱;
    • d(n): 近端信号,即麦克风采集之后,3A 之前的原始信号,可以表示为:d(n) = s(n) + y(n) + v(n);
    • s’(n): 3A 之后的音频信号,即准备经过编码发送到对端的信号。

    WebRTC 音频引擎能够拿到的已知信号只有近端信号 d(n) 和远端参考信号 x(n)。

    图 2 回声信号生成模型

    如果信号经过 A 端音频引擎得到 s’(n) 信号中依然残留信号 y(n),那么 B 端就能听到自己回声或残留的尾音(回声抑制不彻底留下的残留)。AEC 效果评估在实际情况中可以粗略分为如下几种情况(专业人员可根据应用场景、设备以及单双讲进一步细分):

    file

    回声消除的本质

    在解析 WebRTC AEC 架构之前,我们需要了解回声消除的本质是什么。音视频通话过程中,声音是传达信息的主要途径,因此从复杂的录音信号中,通过信号处理的手段使得我们要传递的信息:高保真、低延时、清晰可懂是一直以来追求的目标。在我看来,回声消除,噪声抑制和声源分离同属于语音增强的范畴,如果把噪声理解为广义的噪声三者之间的关系如下图:

    图 3 语音增强与回声消除的关系

    噪声抑制需要准确估计出噪声信号,其中平稳噪声可以通过语音检测判别有话端与无话端的状态来动态更新噪声信号,进而参与降噪,常用的手段是基于谱减法(即在原始信号的基础上减去估计出来的噪声所占的成分)的一系列改进方法,其效果依赖于对噪声信号估计的准确性。对于非平稳噪声,目前用的较多的就是基于递归神经网络的深度学习方法,很多 Windows 设备上都内置了基于多麦克风阵列的降噪的算法。效果上,为了保证音质,噪声抑制允许噪声残留,只要比原始信号信噪比高,噪且听觉上失真无感知即可。

    单声道的声源分离技术起源于传说中的鸡尾酒会效应,是指人的一种听力选择能力,在这种情况下,注意力集中在某一个人的谈话之中而忽略背景中其他的对话或噪音。该效应揭示了人类听觉系统中令人惊奇的能力,即我们可以在噪声中谈话。科学家们一直在致力于用技术手段从单声道录音中分离出各种成分,一直以来的难点,随着机器学习技术的应用,使得该技术慢慢变成了可能,但是较高的计算复杂度等原因,距离 RTC 这种低延时系统中的商用还是有一些距离。

    噪声抑制与声源分离都是单源输入,只需要近端采集信号即可,傲娇的回声消除需要同时输入近端信号与远端参考信号。有同学会问已知了远端参考信号,为什么不能用噪声抑制方法处理呢,直接从频域减掉远端信号的频谱不就可以了吗?

    file

    上图中第一行为近端信号 s(n),已经混合了近端人声和扬声器播放出来的远端信号,黄色框中已经标出对齐之后的远端信号,其语音表达的内容一致,但是频谱和幅度(明显经过扬声器放大之后声音能量很高)均不一致,意思就是:参考的远端信号与扬声器播放出来的远端信号已经是“貌合神离”了,与降噪的方法相结合也是不错的思路,但是直接套用降噪的方法显然会造成回声残留与双讲部分严重的抑制。接下来,我们来看看 WebRTC 科学家是怎么做的吧。

    信号处理流程

    WebRTC AEC 算法包含了延时调整策略,线性回声估计,非线性回声抑制 3 个部分。回声消除本质上更像是音源分离,我们期望从混合的近端信号中消除不需要的远端信号,保留近端人声发送到远端,但是 WebRTC 工程师们更倾向于将两个人交流的过程理解为一问一答的交替说话,存在远近端同时连续说话的情况并不多(即保单讲轻双讲)。

    因此只需要区分远近端说话区域就可以通过一些手段消除绝大多数远端回声,至于双讲恢复能力 WebRTC AEC 算法提供了 {kAecNlpConservative, kAecNlpModerate, kAecNlpAggressive} 3 个模式,由低到高依次代表不同的抑制程度,远近端信号处理流程如图 4:

    图 4 WebRTC AEC 算法结构框图

    NLMS 自适应算法(上图中橙色部分)的运用旨在尽可能地消除信号 d(n) 中的线性部分回声,而残留的非线性回声信号会在非线性滤波(上图中紫色部分)部分中被消除,这两个模块是 Webrtc AEC 的核心模块。模块前后依赖,现实场景中远端信号 x(n) 由扬声器播放出来在被麦克风采集的过程中,同时包含了回声 y(n) 与近端信号 x(n) 的线性叠加和非线性叠加:需要消除线性回声的目的是为了增大近端信号 X(ω) 与滤波结果 E(ω) 之间的差异,计算相干性时差异就越大(近端信号接近 1,而远端信号部分越接近 0),更容易通过门限直接区分近端帧与远端帧。非线性滤波部分中只需要根据检测的帧类型,调节抑制系数,滤波消除回声即可。下面我们结合实例分析这套架构中的线性部分与非线性分。

    线性滤波

    线性回声 y’(n) 可以理解为是远端参考信号 x(n) 经过房间冲击响应之后的结果,线性滤波的本质也就是在估计一组滤波器使得 y’(n) 尽可能的等于 x(n),通过统计滤波器组的最大幅值位置 index 找到与之对齐远端信号帧,该帧数据会参与相干性计算等后续模块。

    需要注意的是,如果 index 在滤波器阶数两端疯狂试探,只能说明当前给到线性部分的远近端延时较小或过大,此时滤波器效果是不稳定的,需要借助固定延时调整或大延时调整使 index 处于一个比较理想的位置。线性部分算法是可以看作是一个固定步长的 NLMS 算法,具体细节大家可以结合源码走读,本节重点讲解线型滤波在整个框架中的作用。

    从个人理解来看,线性部分的目的就是最大程度的消除线性回声,为远近端帧判别的时候,最大程度地保证了信号之间的相干值( 0~1 之间,值越大相干性越大)的可靠性。

    我们记消除线性回声之后的信号为估计的回声信号 e(n),e(n) = s(n) + y’’(n) + v(n),其中 y’’(n) 为非线性回声信号,记 y’(n) 为线性回声,y(n) = y’(n) + y’’(n)。相干性的计算 (Matlab代码):

    % WebRtcAec_UpdateCoherenceSpectra →_→ UpdateCoherenceSpectra
    Sd = Sd * ptrGCoh(1) + abs(wined_fft_near) .* abs(wined_fft_near)*ptrGCoh(2);
    Se = Se * ptrGCoh(1) + abs(wined_fft_echo) .* abs(wined_fft_echo)*ptrGCoh(2);
    Sx = Sx * ptrGCoh(1) + max(abs(wined_fft_far) .* abs(wined_fft_far),ones(N+1,1)*MinFarendPSD)*ptrGCoh(2);
    Sde = Sde * ptrGCoh(1) + (wined_fft_near .* conj(wined_fft_echo)) *ptrGCoh(2);
    Sxd = Sxd * ptrGCoh(1) + (wined_fft_near .* conj(wined_fft_far)) *ptrGCoh(2);     
    
    % WebRtcAec_ComputeCoherence →_→ ComputeCoherence
    cohde = (abs(Sde).*abs(Sde))./(Sd.*Se + 1.0e-10);
    cohdx = (abs(Sxd).*abs(Sxd))./(Sx.*Sd + 1.0e-10);
    

    两个实验

    (1)计算近端信号 d(n) 与远端参考信号 x(n) 的相关性 cohdx,理论上远端回声信号的相干性应该更接近 0(为了方便后续对比,WebRTC 做了反向处理: 1 - cohdx),如图 5(a),第一行为计算近端信号 d(n),第二行为远端参考信号 x(n),第三行为二者相干性曲线: 1 - cohdx,会发现回声部分相干值有明显起伏,最大值有0.7,近端部分整体接近 1.0,但是有持续波动,如果想通过一条固定的门限去区分远近端帧,会存在不同程度的误判,反映到听感上就是回声(远端判断成近端)或丢字(近端判断为远端)。

     (a) 近端信号与远端参考信号的相干性

     (b) 近端信号与估计的回声信号的相干性

    图 5 信号的相干性

    (2)计算近端信号 d(n) 与估计的回声信号 e(n) 的相干性,如图 5(b),第二行为估计的回声信号 e(n),第三行为二者相干性 cohde,很明显近端的部分几乎全部逼近 1.0,WebRTC 用比较严格的门限(>=0.98)即可将区分绝大部分近端帧,且误判的概率比较小,WebRTC 工程师设置如此严格的门限想必是宁可牺牲一部分双讲效果,也不愿意接受回声残留。

    从图 5 可以体会到,线性滤波之后可以进一步凸显远端参考信号 x(n) 与估计的回声信号 e(n) 的差异,从而提高远近端帧状态的判决的可靠性。

    存在的问题与改进

    理想情况下,远端信号从扬声器播放出来没有非线性失真,那么 e(n) = s(n) + v(n),但实际情况下 e(n)与d(n) 很像,只是远端区域有一些幅度上的变化,说明 WebRTC AEC 线性部分在这个 case 中表现不佳,如图 6(a) 从频谱看低频段明显削弱,但中高频部分几乎没变。而利用变步长的双滤波器结构的结果会非常明显,如图 6(b) 所示无论是时域波形和频谱与近端信号 x(n) 都有很大差异,目前 aec3 和 speex 中都采用这种结构,可见 WebRTC AEC 中线性部分还有很大的优化空间。

    (a) WebRTC AEC 线性部分输出

     (b) 改进的线性部分输出

    图 6 近端信号与估计的回声信号的对比

    如何衡量改进的线性部分效果?

    这里我们对比了现有的固定步长的 NLMS 和变步长的 NLMS,近端信号 d(n) 为加混响的远端参考信号 x(n) + 近端语音信号 s(n)。理论上 NLMS 在处理这种纯线性叠加的信号时,可以不用非线性部分出马,直接干掉远端回声信号。图 7(a) 第一行为近端信号 d(n),第二列为远端参考信号 x(n),线性部分输出结果,黄色框中为远端信号。WebRTC AEC 中采用固定步长的 NLMS 算法收敛较慢,有些许回声残留。但是变步长的 NLMS 收敛较快,回声抑制相对好一些,如图 7(b)。

    (a)固定步长的 NLMS

    (b) 变步长的 NLMS

    图 7 两种 NLMS 算法的效果对比

    线性滤波器参数设置

    #define FRAME_LEN 80
    #define PART_LEN 64
    enum { kExtendedNumPartitions = 32 };
    static const int kNormalNumPartitions = 12;
    

    FRAME_LEN 为每次传给音频 3A 模块的数据的长度,默认为 80 个采样点,由于 WebRTC AEC 采用了 128 点 FFT,内部拼帧逻辑会取出 PART_LEN = 64 个样本点与前一帧剩余数据连接成128点做 FFT,剩余的 16 点遗留到下一次,因此实际每次处理 PART_LEN 个样本点(4ms 数据)。

    默认滤波器阶数仅为 kNormalNumPartitions = 12 个,能够覆盖的数据范围为 kNormalNumPartitions * 4ms = 48ms,如果打开扩展滤波器模式(设置 extended_filter_enabled为true),覆盖数据范围为 kNormalNumPartitions * 4ms = 132ms。随着芯片处理能力的提升,默认会打开这个扩展滤波器模式,甚至扩展为更高的阶数,以此来应对市面上绝大多数的移动设备。另外,线性滤波器虽然不具备调整延时的能力,但可以通过估计的 index 衡量当前信号的延时状态,范围为 [0, kNormalNumPartitions],如果 index 处于作用域两端,说明真实延时过小或过大,会影响线性回声估计的效果,严重的会带来回声,此时需要结合固定延时与大延时检测来修正。

    非线性滤波

    非线性部分一共做了两件事,就是想尽千方百计干掉远端信号。

    (1) 根据线性部分提供的估计的回声信号,计算信号间的相干性,判别远近端帧状态。

    (2) 调整抑制系数,计算非线性滤波参数。

    非线性滤波抑制系数为 hNl,大致表征着估计的回声信号 e(n) 中,期望的近端成分与残留的非线性回声信号 y’’(n) 在不同频带上的能量比,hNl 是与相干值是一致的,范围是 [0,1.0],通过图 5(b) 可以看出需要消除的远端部分幅度值也普遍在 0.5 左右,如果直接使用 hNl 滤波会导致大量的回声残留。

    因此 WebRTC 工程师对 hNl 做了如下尺度变换,over_drive 与 nlp_mode 相关,代表不同的抑制激进程度,drive_curve 是一条单调递增的凸曲线,范围 [1.0, 2.0]。由于中高频的尾音在听感上比较明显,所以他们设计了这样的抑制曲线来抑制高频尾音。我们记尺度变换的 α = over_drive_scaling * drive_curve,如果设置 nlp_mode = kAecNlpAggressive,α 大约会在 30 左右。

    % matlab代码如下:
    over_drive = min_override(nlp_mode+1);
    if (over_drive < over_drive_scaling)
      over_drive_scaling = 0.99*over_drive_scaling + 0.01*over_drive;  % default 0.99 0.01
    else
      over_drive_scaling = 0.9*over_drive_scaling + 0.1*over_drive; % default 0.9 0.1
    end
    
    % WebRtcAec_Overdrive →_→ Overdrive
    hNl(index) = weight_curve(index).*hNlFb + (1-weight_curve(index)).* hNl(index);
    hNl = hNl.^(over_drive_scaling * drive_curve);
    
    % WebRtcAec_Suppress →_→ Suppress
    wined_fft_echo = wined_fft_echo .*hNl;
    wined_fft_echo = conj(wined_fft_echo);
    

    如果当前帧为近端帧(即 echo_state = false),假设第 k 个频带 hNl(k) = 0.99994 ,hNl(k) = hNl(k)^α = 0.99994 ^ 30 = 0.9982,即使滤波后的损失听感上几乎无感知。如图 8(a),hNl 经过 α 调制之后,幅值依然很接近 1.0。

    如果当前帧为远端帧(即 echo_state = true),假设第 k 个频带 hNl(k) = 0.6676 ,hNl(k) = hNl(k)^α = 0.6676 ^ 30 = 5.4386e-06,滤波后远端能量小到基本听不到了。如图 8(b),hNl 经过 α 调制之后,基本接近 0。

    (a)近端帧对应的抑制系数

    (b)远端帧对应的抑制系数

    图 8 远近端信号抑制系数在调制前后的变化

    经过如上对比,为了保证经过调制之后近端期望信号失真最小,远端回声可以被抑制到不可听,WebRTC AEC 才在远近端帧状态判断的的模块中设置了如此严格的门限。

    另外,调整系数 α 过于严格的情况下会带来双讲的抑制,如图 9 第 1 行,近端说话人声音明显丢失,通过调整 α 后得以恢复,如第 2 行所示。因此如果在 WebRTC AEC 现有策略上优化 α 估计,可以缓解双讲抑制严重的问题。

    图 9 双讲效果

    延时调整策略

    回声消除的效果与远近端数据延时强相关,调整不当会带来算法不可用的风险。在远近端数据进入线性部分之前,一定要保证延时在设计的滤波器阶数范围内,不然延时过大超出了线性滤波器估计的范围或调整过当导致远近端非因果都会造成无法收敛的回声。先科普两个问题:

    (1)为什么会存在延时?

    首先近端信号 d(n) 中的回声是扬声器播放远端参考 x(n),又被麦克风采集到的形成的,也就意味着在近端数据还未采集进来之前,远端数据缓冲区中已经躺着 N 帧 x(n)了,这个天然的延时可以约等于音频信号从准备渲染到被麦克风采集到的时间,不同设备这个延时是不等的。苹果设备延时较小,基本在 120ms 左右,Android 设备普遍在 200ms 左右,低端机型上会有 300ms 左右甚至以上。

    (2)远近端非因果为什么会导致回声?

    从(1)中可以认为,正常情况下当前帧近端信号为了找到与之对齐的远端信号,必须在远端缓冲区沿着写指针向前查找。如果此时设备采集丢数据,远端数据会迅速消耗,导致新来的近端帧在向前查找时,已经找不到与之对齐的远端参考帧了,会导致后续各模块工作异常。如图 10(a) 表示正常延时情况,(b) 表示非因果。

    (a)远近端正常延时

    (b)远近端非因果

    图10 正常远近端延时与非因果

    WebRTC AEC 中的延时调整策略关键而且复杂,涉及到固定延时调整,大延时检测,以及线性滤波器延时估计。三者的关系如下:

    ① 固定延时调整只会发生在开始 AEC 算法开始处理之前,而且仅调整一次。如会议盒子等固定的硬件设备延时基本是固定的,可以通过直接减去固定的延时的方法缩小延时估计范围,使之快速来到滤波器覆盖的延时范围之内。
    下面结合代码来看看固定延时的调整过程:

    int32_t WebRtcAec_Process(void* aecInst,
    const float* const* nearend,
    size_t num_bands,
    float* const* out,
    size_t nrOfSamples,
    int16_t reported_delay_ms,
    int32_t skew);
    

    WebRtcAec_Process 接口如上,参数 reported_delay_ms 为当前设备需要调整延时的目标值。如某 Android 设备固定延时为 400ms 左右,400ms 已经超出滤波器覆盖的延时范围,至少需要调整 300ms 延时,才能满足回声消除没有回声的要求。固定延时调整在 WebRTC AEC 算法开始之初仅作用一次:

    if (self->startup_phase) {
        int startup_size_ms = reported_delay_ms < kFixedDelayMs ? kFixedDelayMs : reported_delay_ms;
        int target_delay = startup_size_ms * self->rate_factor * 8;
        int overhead_elements = (WebRtcAec_system_delay_aliyun(self->aec) - target_delay) / PART_LEN;
        printf("[audio] target_delay = %d, startup_size_ms = %d, self->rate_factor = %d, sysdelay = %d, overhead_elements = %d\n", target_delay, startup_size_ms, self->rate_factor, WebRtcAec_system_delay(self->aec), overhead_elements);
        WebRtcAec_AdjustFarendBufferSizeAndSystemDelay_aliyun(self->aec,  overhead_elements);
    self->startup_phase = 0;
      }
    

    为什么 target_delay 是这么计算?

    int target_delay = startup_size_ms * self->rate_factor * 8;
    startup_size_ms 其实就是设置下去的 reported_delay_ms,这一步将计算时间毫秒转化为样本点数。16000hz 采样中,10ms 表示 160 个样本点,因此 target_delay 实际就是需要调整的目标样本点数(aecpc->rate_factor = aecpc->splitSampFreq / 8000 = 2)。

    我们用 330ms 延时的数据测试:
    如果设置默认延时为 240ms,overhead_elements 第一次被调整了 -60 个 block,负值表示向前查找,正好为 60 * 4 = 240ms,之后线性滤波器固定 index = 24,表示 24 * 4 = 96ms 延时,二者之和约等于 330ms。日志打印如下:

    file

    ② 大延时检测是基于远近端数据相似性在远端大缓存中查找最相似的帧的过程,其算法原理有点类似音频指纹中特征匹配的思想。大延时调整的能力是对固定延时调整与线型滤波器能力的补充,使用它的时候需要比较慎重,需要控制调整的频率,以及控制造成非因果的风险。

    WebRTC AEC 算法中开辟了可存储 250 个 block 大缓冲区,每个 block 的长度 PART_LEN = 64 个样本点,能够保存最新的 1s 的数据,这也是理论上的大延时能够估计的范围,绝对够用了。

    static const size_t kBufferSizeBlocks = 250;
    buffer_ = WebRtc_CreateBuffer(kBufferSizeBlocks, sizeof(float) * PART_LEN);
    aec->delay_agnostic_enabled = 1;
    

    我们用 610ms 延时的数据测试(启用大延时调整需要设置 delay_agnostic_enabled = 1):
    我们还是设置默认延时为 240ms,刚开始还是调整了 -60 个 block,随后大延时调整接入之后有调整了 -88 个 block,一共调整(60 + 88) * 4 = 592ms,之后线性滤波器固定 index = 4,表示最后剩余延时剩余 16ms,符合预期。

    file

    file

    ③ 线性滤波器延时估计是固定延时调整和大延时调整之后,滤波器对当前远近端延时的最直接反馈。前两者调整不当会造成延时过小甚至非因果,或延时过大超出滤波器覆盖能力,导致无法收敛的回声。因此前两者在调整的过程中需要结合滤波器的能力,确保剩余延时在滤波器能够覆盖的范围之内,即使延时小范围抖动,线性部分也能自适应调整。

    总结与优化方向

    WebRTC AEC 存在的问题:

    (1)线性部分收敛时间较慢,固定步长的 NLMS 算法对线性部分回声的估计欠佳;
    (2)线性部分滤波器阶数默认为 32 阶,默认覆盖延时 132ms,对移动端延时较大设备支持不是很好,大延时检测部分介入较慢,且存在误调导致非因果回声的风险;
    (3)基于相干性的帧状态依赖严格的固定门限,存在一定程度的误判,如果再去指导非线性部分抑制系数的调节,会带来比较严重的双讲抑制。

    优化的方向:
    (1)算法上可以通过学习 speex 和 AEC3 的线性部分,改善当前线性滤波效果;
    (2)算法上可以优化延时调整策略,工程上可以新增参数配置下发等工程手段解决一些设备的延时问题;
    (3)另外,有一些新的思路也是值得我们尝试的,如开头提到的,既然回声也可以是视为噪声,那么能否用降噪的思路做回声消除呢,答案是可以的。

    「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

    展开全文
  • webrtc中的AEC算法的matlab解释和转码,我在别人的基础上完善了一下。注意附带的两个pcm数据是浮点+大端
  • speex aecwebrtc 回声消除的比较优化

    千次阅读 2019-02-13 15:22:52
    当前开源回声消除算法主要有speex 以及webrtcaec算法。 两个开源aec 算法的基本原理都是基于自适应滤波nlms。 两者的主要区别: speex 使用的是mdf 双滤波结构。通过前滤波与本次滤波的结果来调整滤波器系数的...

    当前开源回声消除算法主要有speex 以及webrtc 的aec算法。

    两个开源aec 算法的基本原理都是基于自适应滤波nlms。

    两者的主要区别:

    speex 使用的是mdf 双滤波结构。通过前滤波与本次滤波的结果来调整滤波器系数的更新,

    滤波器长度设计的很长,同时对信号做了预加重以及去直流处理。

    webrtc aec :模块相对比较复杂,包含了延时估计,nlms以及nlp(非线性压缩),舒适噪声四个模块,

    其中延时估计模块采用自相关技术,nlms 模块开源算法只用了12block,nlp 部分使用的是互相干技术。

    可能的优化方向:

    speex aec  现在大部分是用在嵌入式,硬件对延时模块没有需求,而mdf 结构的效果比webrtc nlms 的效果

    好很多,收敛更快(webrtc 自适应滤波部分没有dtd检测,系数一直更新,只有一个简单的发散条件),

    speex 优化可以增加nlp 模块,来消除抑制残留回声。

    webrtc aec 现在大部分是在软件层使用:

    可能的优化方向:

    1、由于线程的波动,必须考虑延时估计,不同的设备,不同的信号延时估计的准确性。

    2、自适应滤波器系数一直更新,能不能有更好的方法来控制,有没有更好的方法,滤波器长度调整效果怎么样?

    3、nlp 部分能不能采用多频带系数代替单一系数,针对自适应滤波部分的问题,能不能做到一定的补救?

    4、自适应部分采用子带处理效果会不会比nlp 分子带更好!

    关于音频算法,欢迎大家加音频算法讨论群qq:153268894 (作者 zeark)

     

     

    展开全文
  • WEBRTC AEC3算法原理

    千次阅读 多人点赞 2020-07-07 10:26:24
    AEC3的延迟估计算法与AEC的非线性处理的延迟估计算法思想一致,因为回声能量是呈指数衰减,所以计算滤波器能量最大块作为延迟估计值,但是比AEC的延迟估计算法复杂的多 AEC3延迟估计模块由步长为0.7的5个时域NLMS...

    延迟估计算法

    原理

    AEC3的延迟估计算法与AEC的非线性处理的延迟估计算法思想一致,因为回声能量是呈指数衰减,所以计算滤波器能量最大块作为延迟估计值,但是比AEC的延迟估计算法复杂的多
    AEC3延迟估计模块由步长为0.7的5个时域NLMS自适应滤波器组成,每个NLMS滤波器默认32块,每块16个sample共 512点,5个滤波器之间互相重叠8块,这里的重叠指的是输入的信号在时间上重叠
    滤波器的输入信号是经过分频后的0~16kHz低频段信号然后经过4倍下采样相当于采样率为4000Hz的信号,5个nlms滤波器可以估计32*16*5 - 8*16*4 =2048个samples,也就是说该延迟估计算法最多能估计2048/4000 = 512ms的延迟

    流程

    1、滤波器更新

    滤波器更新算法:NLMS更新公式
    滤波器更新条件:

    1. 近端语音帧没有超过32000或-32000
    2. 远端能量大于一定阈值
    2、计算每个滤波器的延时值

    延时值:将每个滤波器系数能量最大块作为延时值
    延时值可信度:

    1. 延时值落在滤波器>2且<10范围内
    2. 误差能量小于近端能量的0.2倍
    3. 滤波器是否更新
    3、从5个滤波器中挑出最佳延时值估计

    挑选方法:滤波器更新且可信度为真,且accuracy最大作为延时值估计
    accuracy:近端能量-误差能量

    4、延时值过滤

    使用大小为250的历史窗口统计历史延时值,统计历史窗口中出现次数最多的延时值,当出现次数大于20次认为这是一个质量较高的估计值,反之认为是较差的估计值

    5、时钟漂移检测

    质量好的延时值会用来做时钟漂移检测,时钟漂移检测使用大小为3的历史窗口判断时钟漂移是否产生,窗口内的值时前3个历史时刻延时估计值:
    判断标准:d1,d2,d3分别时历史窗口历史值与当前时刻延时值之差
    增量漂移:d1==-1且d2==-2 或d1==-2且d2==-1 d3==-3确认产生反之可能产生

    const bool probable_drift_up =
          (d1 == -1 && d2 == -2) || (d1 == -2 && d2 == -1);
    const bool drift_up = probable_drift_up && d3 == -3;
    

    减量漂移:d1==1且d2==2 或 d1==2且d2==1 d3==3确认产生反之可能产生

    const bool probable_drift_down = (d1 == 1 && d2 == 2) || (d1 == 2 && d2 == 1);
    const bool drift_down = probable_drift_down && d3 == 3;
    

    目前aec3只做了时钟漂移检测,没有做相应处理

    6、对齐远端数据

    质量好的延时值和质量差的延时值都会用来进行远端对齐

    另外,当上一次延时值和当前延时值的质量都是高的情况下会有一个迟滞量,即延迟增量小于某一阈值时认为延时相较于上一次没有改变

    7、处理回声路径变化(延迟改变,增益改变,时钟漂移)
    • 主辅滤波器处理声路径变化
    • 将非线性增益设置为初始状态

    自适应回声消除

    原理

    线性回声消除使用主辅滤波器结构,总体来说,主滤波器可以看作是一个精简版的频域分块的kalman滤波器,只不过精简了系数误差协方差的计算,计算的是滤波器抽头系数误差协方差的平均,而不是计算每块滤波器抽头系数的误差协方差,回声路径跟踪能力和双工效果比PBFDAF效果要好一些,但比起kalman滤波器又差了点,相当于在计算量上和效果上做了权衡。辅滤波器是PBFDAF,会一直更新,能快速对回声路径进行追踪,当辅滤波器发散时主滤波器系数拷贝至辅滤波器。因此这样的双滤波器结构既能够有效消除线性回声,有着不错的双工效果,又能够快速的跟踪回声路径的变化。
    一般来说,滤波器的抽头长度应该设计的足够长,以完全逼近回声路径,但是为了快速的收敛以及降低计算量,AEC3自适应滤波器抽头长度设计的较短,只有12块,所以AEC3的自适应滤波器主要是消除早期的回声,后期的混响回声是通过混响模型进行估计然后用NLP进行消除。

    流程

    1、分析远端信号中的窄带信号

    窄带信号检测算法:

    • 远端信号中某个频率点的幅度大于左右频点幅度的3倍,则认为是弱窄带频率分量
    • 远端信号中某个频率点的幅度大于左右频点的100倍,则认为该频率点是强窄带分量

    自适应滤波器对窄带信号处理:

    • 连续5个block远端信号都含有弱窄带频率分量后,滤波器在该频率点的左右2个频率点的系数都不会更新
    • 连续10个block远端信号都含有弱窄带频率分量后,滤波器系数全部都不更新
    • 如果远端信号含有强窄带频率分量,则非线性处理的高频部分抑制系数限制为0.001

    那为什么要对这种窄带信号做处理呢?
    因为窄带信号会导致自适应滤波器朝着错误的方向收敛,最终导致滤波器发散和回声泄漏。
    假设远端信号为正弦信号,自适应滤波器不会朝着真实的回声路径去收敛,而是朝着单一频率方向收敛,最终导致自适应滤波器的效果像一个陷波器,基于LMS算法的滤波器如NLMS,FDAF等都有这个问题,如下图所示。
    如果NLMS滤波器输入为正弦激励的话,自适应滤波器的脉冲响应也为正弦形式,这与实际的回声路径不一样

    2、主滤波器更新

    更新方式1:通过计算主滤波器系数的失调增益调整滤波器系数

        mis = mis + 0.1*( e2/y2 - mis)
        scale = 2 / sqrt(mis)
        H(t)=H(t) * scale
    

    通过公式可以看出:如果误差信号一直大于某个阈值会导致失调量持续增加,当mis大于10时,计算失调增益scale来调整滤波器系数
    总体来说该算法会一直限制主滤波器误差输出在与近端能量有关的一定范围内,即滤波器不会发散

    更新方式2:通过系数更新公式更新滤波器系数

        Erl(t) = sum{H(n) * H(n)}
        mu(t) = H_error(t) / (0.5 * H_error(t) * X2(t) + N * E2(t)) —— (X2(t) > noise_gate)
        mu(t) = 0  —— (X2(t) <= noise_gate)      
        H_error(t) = H_error(t) - 0.5 * mu(t) * X2(t) * H_error(t)
        G(t) = mu(t) * E(t)
        factor = 0.00005f —— (E2_shadow>=E2_main)
        factor = 0.05f —— (E2_shadow<E2_main)
        H_error(t+1) = H_error(t) + factor * Erl(t)
        H(t+1)=H(t)+G(t) * conj(X(t))
    

    注意:这个公式是我在代码中的注释,并不规范,只是记录了aec3滤波器的思想
    通过与kalman滤波器仔细对比可以发现,其实这个滤波器是kalman滤波器的精简版,其更新公式与kalman滤波器是一样的,只不过精简了系数误差协方差的计算,计算的是滤波器抽头系数误差协方差的平均,而不是计算每块滤波器抽头系数的误差协方差,把mu(t)带入到 G(t) = mu(t)*E(t)中,会发现G(t)就是kalman滤波器增益K的计算公式,H_error(t)的计算也与kalman滤波器的系数协方差更新公式一样,N*E2(t)是测量噪声,factor*Erl(t)是过程噪声

    另外还可以看出:

    • 当远端信号能量小于预设的噪音门限值时,mu=0,代表不更新滤波器
    • 当主滤波器误差小于辅滤波器误差时,主滤波器收敛较好,factor=0.00005,设置了比较小的过程噪声,当主滤波器误差大于辅滤波器误差时,主滤波器收敛较差,factor=0.05,设置了比较大的过程噪声,这也是保证滤波器不会发散的一个手段
    3、辅滤波器更新
    • 当主滤波器误差连续超过5个block小于辅滤波器误差时,认为辅滤波器发散,将主滤波器系数拷贝至辅滤波器,更新辅滤波器
    • 按PBFDAF公式更新辅滤波器
    4、选择线性回声消除结果

    选择线性回声消除结果使用主滤波器误差还是使用辅滤波器误差,然后进行平滑过渡
    假如配置了使用辅助滤波器的输出,则满足以下情况使用辅滤波器误差输出:

    • 当近端信号大于一定阈值且辅滤波器误差输出能量小于0.9倍主滤波器误差输出能量
    • 主滤波器输出信号能量大于一定阈值或者辅滤波器输出能量大于一定阈值,即辅助滤波器检测到的回声大于一定量

    假如没有配置使用辅助滤波器的输出,则满足以下情况使用辅助滤波器误差输出

    • 辅滤波器误差能量小于主滤波器误差能量且近端信号能量小于主滤波器误差能量

    非线性回声消除

    原理

    AEC3的非线性回声消除原理主要思想是通过估计残余回声以及噪声,设计一个滤波器,以达到去除残余回声的目的,这实际上与降噪算法非常类似。

    流程

    1、AEC状态更新和参数计算

    1、根据主辅滤波器的误差与近端信号分析滤波器收敛与发散状态

    • 当主滤波器误差小于近端信号的一半且近端信号低于收敛阈值时,认为主滤波器收敛
    • 当辅滤波器误差小于近端信号的0.05倍且近端信号低于收敛阈值时,认为辅滤波器收敛
    • 当两个滤波器中较小误差大于1.5倍的近端信号且近端信号大于某阈值时,认为两个滤波器都发散

    2、根据主滤波器的时域响应分析主滤波器的属性,主要分析如下参数:

    • 寻找滤波器响应峰值
    • 计算峰值的延迟filter_delays_blocks_
    • 计算峰值的增益,即回声路径最大增益值
    • 计算第二峰值分析滤波器响应是否随时间变化一致
    • any_filter_consistent: 主滤波器时域响应是否随时间变化一致
    • max_echo_path_gain: 最大回声路径增益值

    3、计算相对于滤波器开始的直接路径延迟
    4、更新远近端语音活动统计
    5、根据回声混响模型,计算远端信号加上混响后的功率
    6、检测回声是否过饱和:通过最大回声增益值和远端信号最大值来判断

    7、更新erle和erl:根据erle的估计计算线性滤波器的好坏,以及通过erle计算残余回声

    • ERL : echo return loss = Y2 / X2 近端功率/远端功率 高表示回声强,低表示回声弱
    • ERLE : echo return loss enhancement = Y2 / E2 近端功率/误差功率 衡量AEC的性能,计算残余回声
    • RERL : Residual Echo Return Loss = ERL + ERLE

    8、更新AEC工作状态标志,在AEC由初始状态转为正常工作状态erle估计器会重置

    • 通过远端语音是否活动和近端语音是否过饱和判断AEC的状态,初始状态或正常工作状态
    • 从初始状态进入正常工作状态会将线性滤波和非线性处理模块的状态都从初始状态转换为正常工作状态

    9、transparent_mode检测:检测滤波器是否工作正常

    • 总的来说就是滤波器工作情况良好的情况下 transparent_mode = false
    • 在滤波器工作不合理且近端语音未过饱和超过6秒 transparent_mode = true
    • 在transparent_mode = true 时,滤波器性能很差,在非线性处理时会使用不同函数计算残余回声

    10、计算滤波器工作性能,来决定是否使用线性滤波的结果作为非线性处理的输入,以及使用不同的非线性抑制函数
    在滤波器工作良好时,使用线性滤波结果计算残余回声,工作良好判定需同时满足以下条件:

    • 初始化后滤波器更新次数超过0.4秒
    • 观测到任一滤波器收敛 或 延时估计模块估计出了延时
    • 非transparent mode
      在滤波器工作较差时,非线性处理的输入为近端信号,并且使用不同的函数计算残余回声

    11、估计后期回声混响模型

    2、计算频谱

    加窗、FFT,计算频谱
    计算近端信号、误差信号、线性回声信号频谱

    3、估计残余回声

    滤波器工作良好情况下:

    1. 如果回声过饱和,则R2=Y2,即认为误差输入中都是残余回声
    2. 如果回声未过饱和,则R2 = S2_linear / ERLE + Reverb

    滤波器工作较差情况下:

    1. 如果回声过饱和,则R2=Y2,即认为误差输入中都是残余回声
    2. 如果回声未过饱和,则R2 = X2 * 0.0001 + Reverb

    这里Reverb就是根据估计出的混响模型计算出来的自适应滤波器未消除的后期混响回声

    4、估计舒适噪声

    更新公式:

    N2 = Y2_smoothed < N2 ? (0.9*Y2_smoothed + 0.1*N2)* 1.0002f : N2*1.0002f
    

    缓慢更新N2噪声能量,当近端语音能量小于噪音能量时,噪音能量快速降低至近端能量水平,当近端语音能量大于噪音能量时,噪音能量N2缓慢增加

    5、近端语音活动检测

    如果近端(误差)能量显著大于残余回声能量和舒适噪声能量,且连续超过12个block时则认为产生了近端语音,最短保持时间设置为50个block

    6、选择计算非线性增益的输入参数

    根据近端功率谱、线性回声估计功率谱、残余回声估计功率谱、舒适噪声功率谱计算非线性增益值

    • 如果使用线性滤波的结果作为非线性处理的输入,则非线性处理的近端功率谱使用线性滤波的误差输出,回声功率谱使用线性滤波估计的线性回声功率谱
    • 如果不使用线性滤波的结果作为非线性处理的输入,则非线性处理的近端功率谱使用近端功率谱,回声功率谱使用估计的残余回声功率谱
    7、计算非线性增益值

    低频段非线性增益值核心计算函数GainToNoAudibleEcho代码如下:

    const auto& p = dominant_nearend_detector_->IsNearendState() ? nearend_params_
                                                                   : normal_params_;
    for (size_t k = 0; k < gain->size(); ++k) {
        float enr = echo[k] / (nearend[k] + 1.f);  // Echo-to-nearend ratio.
        float emr = echo[k] / (masker[k] + 1.f);   // Echo-to-masker (noise) ratio.
        float g = 1.0f;
        if (enr > p.enr_transparent_[k] && emr > p.emr_transparent_[k]) {
            g = (p.enr_suppress_[k] - enr) /
                 (p.enr_suppress_[k] - p.enr_transparent_[k]);
            g = std::max(g, p.emr_transparent_[k] / emr);
        }
        (*gain)[k] = g;
    }
    

    enr为残余回声功率和误差功率比值,emr为残余回声功率和噪声功率比值
    可以看出来:只有在enr和emr大于一定阈值的情况下才会计算增益,低于这个阈值增益为1,相当于不做处理,这是为了减小抑制效果,提升近端语音“透明度”,即双工效果。

    8、对误差信号进行非线性抑制
    1. 使用非线性增益与误差信号频谱相乘
    2. 加上舒适噪声
    3. IFFT
    4. 重叠相加获得去窗后的时域平滑的信号

    与AEC对比

    1. AEC3的延迟估计算法与AEC非线性处理延迟估计算法类似,但AEC就简单的多,虽然AEC也有延迟估计算法,但实际测试还是有不少机器会出现回声消除效果不好甚至无法消除的情况,但用AEC3就不会出现完全无法消除的情况,我们使用了大量机型测试,AEC3都能够保证算法能正常工作,回声能正常消除,我认为这得益于AEC3的延迟估计算法。
    2. AEC的自适应滤波为了快速对回声路径跟踪,采用了大的固定步长的滤波器,在双工的情况下滤波器会发散,发散后只是简单的重置滤波器,而AEC3的使用双滤波器结构,而且对滤波器发散进行了处理,对比AEC的单个滤波器要强不少
    3. AEC没有初始状态控制,在AEC刚开始工作时,算法还在学习阶段,这时候回声消除处理的不好,容易产生残留回声,AEC3在回声路径变化或者初始化时,会增大非线性抑制,以确保不会产生回声

    总结

    暂时只是对webrtc aec3的算法粗略的了解了一下,可以发现aec3算法对工程化做了大量的处理,例如延迟估计算法、处理回声路径变化、初始状态设置、线性回声消除以及非线性回声消除,其中的每一部分内还有更多复杂的细节及逻辑,因此不难看出Google推出aec3就是为了针对总类繁多的webrtc设备终端一站式解决适配问题。
    有任何疑问,欢迎加微信交流:xu19315519614
    最后附上我单独提取测试的AEC3代码: https://github.com/ewan-xu/AEC3

    问题记录

    1. AEC3的线性滤波器只有在远端信号达到一定阈值才会更新滤波器,这样可以防止远端的噪音信号干扰滤波器导致滤波器错误的跟踪回声路径,但也带来一个缺点,那就是在初始化时,如果远端的语音信号非常小,一直低于阈值,那么AEC3会认为是噪声,导致滤波器一直不收敛,因而回声无法消除的情况
    2. AEC3算法舒适噪声估计和AEC一样,通过近端信号能量产生舒适噪声,但是都会产生一个问题,那就是当近端持续一直很大时(比如播放音乐),这时候产生的噪声就会非常大,在实际的通话中,会造成正向激励的环路,导致即使两边都没有通话,但是噪音会持续增大的情况
    3. AEC3算法对于音乐的回声消除效果较差,因为对于音乐,有许多的乐器会产生这种类似于窄带信号的频率分量,在这种情况下AEC3的自适应滤波器基本上是不更新的,这也导致了自适应滤波器没法快速跟踪回声路径,导致回声消除效果较差
    4. AEC3延时估计的参考信号是经过下采样至频率只有0~2000Hz的信号,对于人声来说没问题,但对于音乐或者某些信号2000Hz以下没有频率分量,这时候AEC3的延时估计算法就失效了
    5. AEC3的非线性抑制算法为了提升双工效果,即近端语音“透明度”,在对每个子频带计算增益值时,enr和emr小于一定值就不进行抑制,即抑制系数设置为1,这样导致了AEC3在双工时会有残留的回声,而且残留的回声听感不平滑
    展开全文
  • webrtc aec3效果对比aec与aecm(webrtc M64 20180115版本)

    万次阅读 热门讨论 2018-01-16 10:12:21
    1、webrtc回声消除算法aec3也出来有几个月了,下面看下最新版的aec3效果,使用读文件仿真,例子为webrtc中的audioproc_f.exe,aec3aec,aecm均使用默认参数,没有改动。在cmd中使能aec3参数audioproc_f -i D:\Git\...
  • webrtc源码中的声音处理部分报告agc,anc,aec等,可以编译过去需要c++
  • webrtc AEC(回声消除模块)的完整编译工程。(vs2010) 含源码,以及静态编译成的库文件。 可以自行修改工程配置,编译成dll。 最后使用头文件 echo_cancellation_.h 即可。
  • WebRTC 回声抵消(AEC)模块 ,可单独编译,相关头文件都已经整理。
  • linux下,测试可用,包括源码,makefile文件,编译出的so文件libwebrtc_audio.so,移植后的头文件webrtc_api.h,测试用例WebRtcAudioTest.c(包括AGC,AEC,NS的使用方法)及编译出的可执行文件webrtc_aec,还有一些...
  • webrtc-based-android-aec.rar

    2020-07-07 14:23:25
    在日常的音频采集中经常会混入扬声器播放的声音,有些硬件会支持回声消除,有些则需要自己处理,本文件是Android端使用WebRTC的回声消除模块,去除录入音频的远端音频的示例
  • WebRTC AEC

    千次阅读 2019-03-01 11:08:02
    AEC算法主要模块: 1.回声时延估计(用于自适应滤波器部分延时估计对齐) 2.NLMS滤波器(归一化最小均方自适应算法),即PBFDAF(分段块频域自适应滤波算法)。 3.NLP是非线性滤波,取掉残余回声。 4.CNG舒适噪声产生 ...
  • 整体过程同webRTC降噪(NS)、自动增益控制(AGC)模块的编译与测试一样,只是在aec_rdft.c文件中可能会报错,局部变量ip跟全局变量冲突的问题,可以将局部变量重新命名一下,就可以通过编译了。修改后的代码如下/* ...
  • webRTC AEC 滤波器的自适应

    千次阅读 2018-07-17 13:56:44
    权值更新就是使用SSE指令集加速完成NLMS算法的频域计算,具体实现细节见代码注释。 static void FilterAdaptationSSE2(AecCore* aec, float* fft, float ef[2][PART_LEN1]) { in...
  • webrtc aec 用法2

    2021-01-07 22:58:13
    CEchoCanceller3::CEchoCanceller3(int ch, int sample_rate, int framelen) { m_ch = ch; m_sample_rate = sample_rate; m_bytes_per_frame = framelen; m_aec_config.filter.export_linear_aec_output = true;...
  • WebRTC AEC算法

    千次阅读 2019-07-26 11:24:39
    AEC和AECM:AECM适用于...LMS自适应算法:https://blog.csdn.net/heda3/article/details/82860463 AEC算法主要在aec_ProcessBlock函数中完成:下图是该函数流程图: 参考: https://www.docin.com/p-1404248898.html ...
  • WebRtc/Speex AEC matlab代码分析

    千次阅读 2017-12-01 11:57:51
    自适应回声消除算法 ...本文基于开源算法阐述AEC的原理和实现,基于WebRTC和speex两种算法,文末会附上两种算法的matlab实现。 回声消除原理 回声消除的基本原理是使用一个自适应滤波器对未知的回声信道:
  • 基于webRTCaec,这里aec是完全从webRTC里面剥离出来的
  • WebRtc中的AEC算法

    万次阅读 2016-09-06 16:49:23
    WebRtc中的AEC算法属于分段快频域自适应滤波算法,Partioned block frequeney domain adaptive filter(PBFDAF)。 判断远端和近端是否说话的情况,又称为双端检测,需要监测以下四种情况: 1. 仅远端说话, 此时...
  • webrtc剥离出来的audio模块的测试程序,包括,aec resample etc

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 920
精华内容 368
关键字:

aec3webrtc