本文主要介紹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的處理全面,流程清晰。能夠根據實際須要打開不一樣的模塊,適應不一樣場景的須要,對於通常通信系統來講具備正面的改善效果。可是在實際工做中也發現了一些流程上隱患。另外就是該結構的各個模塊處理相對獨立耦合低,原本應該是一個優良的特性,然而在複雜狀況的信號處理難以到達目標效果。因爲低耦合形成的運算量浪費更加是沒法避免的。