本文主要介绍WebRTC的APM。spa
如今主要介绍一下audio_processing.h。.net
首先插入了几个类,这些都是audio_processing的核心模块。debug
class
AudioFrame;
class
EchoCancellation;
class
EchoControlMobile;
class
GainControl;
class
HighPassFilter;
class
LevelEstimator;
class
NoiseSuppression;
class
VoiceDetection;
AudioFrame:主要记录了通道基本信息,数据,VAD标志时间戳,采样频率,信道数等。orm
EchoCancellation:回声消除模块(AEC),在使用外置扬声器的时候应该使用,有些使用耳麦通信的状况也会存在回声(由于麦克风与扬声器有空间或者电的弱耦合),若是影响了通话也应该开启。
blog
EchoControlMobile:回声抑制模块(AES),这个模块和回声消除模块功能类似,可是实现方法不同。运算量远远小于回声消除模块。很是适合移动平台使用。可是对语音损伤大。
get
GainControl:增益控制模块(AGC),这个模块使用了语音的特征对系统硬件音量和输出的信号大小进行调节。硬件上能够控制输入音量。软件上只能调节原来信号的幅度,若是对原来就已经破音的信号,或者原本输入就比较小的信号就无能为力了。it
HighPassFilter:高通滤波器,抑制不须要的低频信号。能够根据须要修改参数选择相应的截止频率。对于某些有工频干扰的设备须要使用高通滤波器。io
LevelEstimator:估计信号的能量值。event
NoiseSuppression:噪声抑制模块(NS/SE),该模块通常应用在有环境噪声的状况,或者是麦克风采集到的数据有明显噪声的状况。table
VoiceDetection:语音激活检测模块(VAD),该模块用于检测语音是否出现。用于编解码以及后续相关处理。
APM分为两个流,一个近端流,一个远端流。近端(Near-end)流是指从麦克风进入的数据;远端(Far-end)流是指接收到的数据。如今分别介绍一下,这部分代码在audio_processing_impl.cc里。
far_end流代码:
int AudioProcessingImpl::AnalyzeReverseStreamLocked() {
AudioBuffer* ra = render_audio_.get(); // For brevity.
if (rev_proc_format_.rate() == kSampleRate32kHz) {
for (int i = 0; i < rev_proc_format_.num_channels(); i++) {
// Split into low and high band.
WebRtcSpl_AnalysisQMF(ra->data(i),
ra->samples_per_channel(),
ra->low_pass_split_data(i),
ra->high_pass_split_data(i),
ra->filter_states(i)->analysis_filter_state1,
ra->filter_states(i)->analysis_filter_state2);
}
}
RETURN_ON_ERR(echo_cancellation_->ProcessRenderAudio(ra));
RETURN_ON_ERR(echo_control_mobile_->ProcessRenderAudio(ra));
RETURN_ON_ERR(gain_control_->ProcessRenderAudio(ra));
return kNoError;
}
上述代码能够看出far-end得到数据后主要有4个步骤的处理。
一、判断是不是32k信号,采起相应的分频策略;
二、AEC流程,记录AEC中的far-end及其相关运算;
三、AES流程,记录AES中的far-end及其相关运算;
四、AGC流程,计算far-end及其相关特征。
near-end流代码:
int AudioProcessingImpl::ProcessStreamLocked() {
#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
if (debug_file_->Open()) {
audioproc::Stream* msg = event_msg_->mutable_stream();
msg->set_delay(stream_delay_ms_);
msg->set_drift(echo_cancellation_->stream_drift_samples());
msg->set_level(gain_control_->stream_analog_level());
msg->set_keypress(key_pressed_);
}
#endif
AudioBuffer* ca = capture_audio_.get(); // For brevity.
bool data_processed = is_data_processed();
if (analysis_needed(data_processed)) {
for (int i = 0; i < fwd_proc_format_.num_channels(); i++) {
// Split into a low and high band.
WebRtcSpl_AnalysisQMF(ca->data(i),
ca->samples_per_channel(),
ca->low_pass_split_data(i),
ca->high_pass_split_data(i),
ca->filter_states(i)->analysis_filter_state1,
ca->filter_states(i)->analysis_filter_state2);
}
}
RETURN_ON_ERR(high_pass_filter_->ProcessCaptureAudio(ca));
RETURN_ON_ERR(gain_control_->AnalyzeCaptureAudio(ca));
RETURN_ON_ERR(echo_cancellation_->ProcessCaptureAudio(ca));
if (echo_control_mobile_->is_enabled() && noise_suppression_->is_enabled()) {
ca->CopyLowPassToReference();
}
RETURN_ON_ERR(noise_suppression_->ProcessCaptureAudio(ca));
RETURN_ON_ERR(echo_control_
mobile_->ProcessCaptureAudio(ca));
RETURN_ON_ERR(voice_detection_->ProcessCaptureAudio(ca));
RETURN_ON_ERR(gain_control_->ProcessCaptureAudio(ca));
if (synthesis_needed(data_processed)) {
for (int i = 0; i < fwd_proc_format_.num_channels(); i++) {
// Recombine low and high bands.
WebRtcSpl_SynthesisQMF(ca->low_pass_split_data(i),
ca->high_pass_split_data(i),
ca->samples_per_split_channel(),
ca->data(i),
ca->filter_states(i)->synthesis_filter_state1,
ca->filter_states(i)->synthesis_filter_state2);
}
}
// The level estimator operates on the recombined data.
RETURN_ON_ERR(level_estimator_->ProcessStream(ca));
was_stream_delay_set_ = false;
return kNoError;
}
其中包括七个步骤:一、分频;二、高通滤波;三、硬件音量控制;四、AEC;五、NS;六、AES;七、VAD;八、AGC;九、综合。
可见near-end的处理全面,流程清晰。能够根据实际须要打开不一样的模块,适应不一样场景的须要,对于通常通信系统来讲具备正面的改善效果。可是在实际工做中也发现了一些流程上隐患。另外就是该结构的各个模块处理相对独立耦合低,原本应该是一个优良的特性,然而在复杂状况的信号处理难以到达目标效果。因为低耦合形成的运算量浪费更加是没法避免的。