本文主要整理了webrtc中agc2模塊。目前為止,webrtc提供的agc總共有三個版本,最老的版本在legacy文件夾下,然后就是agc文件下的一個版本,最后一個就是位於agc2文件下的另一版本。相較於之前的版本,agc2引入了RNN做vad估計。當然其它的部分也有所改進,如噪聲估計、增益求解。webrtc的agc2模塊打算分兩次博文介紹,本篇主要介紹編譯以及agc2效果測試,下一篇博文主要介紹自己對agc2算法的理解。agc2的編譯所需文件包括:api、common_audio、rtc_base、system_wrappers、third_party以及modules模塊下的大部分文件。具體的文件可以參見我的github鏈接https://github.com/ctwgL/webrtc_agc2。上述文件准備完畢后,編寫CMakeLists.txt文件,該部分主要參考https://github.com/lyapple2008/webrtc_apm_cmake
cmake_minimum_required(VERSION 3.6)
project(webrtc_apm)
set(CMAKE_CXX_STANDARD 14)
if (WIN32)
set(CMAKE_C_FLAGS "/arch:AVX2")
else ()
set(CMAKE_C_FLAGS "-mavx2 -mfma")
endif()
add_compile_options(-march=native)
if (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
if (WIN32)
add_definitions(-DWEBRTC_WIN)
else()
add_definitions(-DWEBRTC_POSIX)
endif ()
if (UNIX)
add_definitions(-DWEBRTC_LINUX)
endif ()
add_definitions(-DWEBRTC_NS_FLOAT)
add_definitions(-DWEBRTC_APM_DEBUG_DUMP=1)
set(CURRENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# api
set(WEBRTC_API_DIR ${CURRENT_DIR}/api)
set(WEBRTC_API_INCLUDE ${CURRENT_DIR}/api)
set(WEBRTC_API_AUDIO_DIR ${CURRENT_DIR}/api/audio)
set(WEBRTC_API_TASK_QUEUE_DIR ${CURRENT_DIR}/api/task_queue)
# common_audio
set(WEBRTC_COMMON_AUDIO_DIR ${CURRENT_DIR}/common_audio)
set(WEBRTC_COMMON_AUDIO_INCLUDE ${CURRENT_DIR}/common_audio)
set(WEBRTC_COMMON_AUDIO_RESAMPLER_DIR ${CURRENT_DIR}/common_audio/resampler)
set(WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_DIR ${CURRENT_DIR}/common_audio/signal_processing)
set(WEBRTC_COMMON_AUDIO_THIRD_PARTY_OOURA_128_DIR ${CURRENT_DIR}/common_audio/third_party/ooura/fft_size_128)
set(WEBRTC_COMMON_AUDIO_THIRD_PARTY_OOURA_256_DIR ${CURRENT_DIR}/common_audio/third_party/ooura/fft_size_256)
set(WEBRTC_COMMON_AUDIO_THIRD_PARTY_SPL_DIR ${CURRENT_DIR}/common_audio/third_party/spl_sqrt_floor)
set(WEBRTC_COMMON_AUDIO_VAD_DIR ${CURRENT_DIR}/common_audio/vad)
set(WEBRTC_COMMON_AUDIO_VAD_INCLUDE ${CURRENT_DIR}/common_audio/vad/include)
# modules
set(WEBRTC_MODULES_AUDIO_CODING_ISAC_VAD_DIR ${CURRENT_DIR}/modules/audio_coding/codecs/isac/main/source)
# modules->audio_processing
set(WEBRTC_MODULES_AUDIO_PROCESSING_DIR ${CURRENT_DIR}/modules/audio_processing)
set(WEBRTC_MODULES_AUDIO_PROCESSING_INCLUDE ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/include)
set(WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/aec_dump)
set(WEBRTC_MODULES_AUDIO_PROCESSING_AEC3_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/aec3)
set(WEBRTC_MODULES_AUDIO_PROCESSING_AECM_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/aecm)
set(WEBRTC_MODULES_AUDIO_PROCESSING_AGC_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/agc)
set(WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/agc/legacy)
set(WEBRTC_MODULES_AUDIO_PROCESSING_AGC2_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/agc2)
set(WEBRTC_MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/agc2/rnn_vad)
set(WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/echo_detector)
set(WEBRTC_MODULES_AUDIO_PROCESSING_LOGGING_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/logging)
set(WEBRTC_MODULES_AUDIO_PROCESSING_NS_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/ns)
set(WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/transient)
set(WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/utility)
set(WEBRTC_MODULES_AUDIO_PROCESSING_VAD_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/vad)
# modules->third_party->fft
set(WEBRTC_MODULES_AUDIO_PROCESSING_THIRD_PARTY_FFT_DIR ${WEBRTC_MODULES_AUDIO_PROCESSING_DIR}/third_party/fft)
# rtc_base
set(WEBRTC_RTC_BASE_DIR ${CURRENT_DIR}/rtc_base)
set(WEBRTC_RTC_BASE_EXPERIMENTS_DIR ${WEBRTC_RTC_BASE_DIR}/experiments)
set(WEBRTC_RTC_BASE_MEMORY_DIR ${WEBRTC_RTC_BASE_DIR}/memory)
set(WEBRTC_RTC_BASE_STRINGS_DIR ${WEBRTC_RTC_BASE_DIR}/strings)
set(WEBRTC_RTC_BASE_SYNCHRONIZATION_DIR ${WEBRTC_RTC_BASE_DIR}/synchronization)
set(WEBRTC_RTC_BASE_SYSTEM_DIR ${WEBRTC_RTC_BASE_DIR}/system)
# system_wrappers
set(WEBRTC_SYSTEM_WRAPPERS_DIR ${CURRENT_DIR}/system_wrappers/source)
set(WEBRTC_SYSTEM_WRAPPERS_INCLUDE ${CURRENT_DIR}/system_wrappers/include)
# jsoncpp
set(WEBRTC_THIRD_PARTY_JSONCPP_INCLUDE ${CURRENT_DIR}/third_party/jsoncpp/source/include)
# pffft
set(WEBRTC_THIRD_PARTY_PFFFT_INCLUDE ${CURRENT_DIR}/third_party/pffft/src)
# rnnoise
set(WEBRTC_THIRD_PARTY_RNNNOISE_DIR ${CURRENT_DIR}/third_party/rnnoise/src)
include_directories(
${CURRENT_DIR}
${WEBRTC_API_INCLUDE}
${WEBRTC_COMMON_AUDIO_VAD_INCLUDE}
${WEBRTC_COMMON_AUDIO_INCLUDE}
${WEBRTC_MODULES_AUDIO_PROCESSING_INCLUDE}
${WEBRTC_THIRD_PARTY_JSONCPP_INCLUDE}
${WEBRTC_THIRD_PARTY_PFFFT_INCLUDE}
)
aux_source_directory(${WEBRTC_API_AUDIO_DIR} WEBRTC_API_AUDIO_DIR_SRC)
set(WEBRTC_API_TASK_QUEUE_SRC ${CURRENT_DIR}/api/task_queue/task_queue_base.cc)
if (WIN32)
set(WEBRTC_API_DEFAULT_TASK_QUEUE_SRC ${CURRENT_DIR}/api/task_queue/default_task_queue_factory_win.cc)
elseif (UNIX)
set(WEBRTC_API_DEFAULT_TASK_QUEUE_SRC ${CURRENT_DIR}/api/task_queue/default_task_queue_factory_stdlib.cc)
else ()
set(WEBRTC_API_DEFAULT_TASK_QUEUE_SRC ${CURRENT_DIR}/api/task_queue/default_task_queue_factory_gcd.cc)
endif()
aux_source_directory(${WEBRTC_COMMON_AUDIO_DIR} WEBRTC_COMMON_AUDIO_DIR_SRC)
aux_source_directory(${WEBRTC_COMMON_AUDIO_RESAMPLER_DIR} WEBRTC_COMMON_AUDIO_RESAMPLER_DIR_SRC)
aux_source_directory(${WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_DIR} WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_DIR_SRC)
aux_source_directory(${WEBRTC_COMMON_AUDIO_THIRD_PARTY_OOURA_128_DIR} WEBRTC_COMMON_AUDIO_THIRD_PARTY_OOURA_128_DIR_SRC)
aux_source_directory(${WEBRTC_COMMON_AUDIO_THIRD_PARTY_OOURA_256_DIR} WEBRTC_COMMON_AUDIO_THIRD_PARTY_OOURA_256_DIR_SRC)
aux_source_directory(${WEBRTC_COMMON_AUDIO_THIRD_PARTY_SPL_DIR} WEBRTC_COMMON_AUDIO_THIRD_PARTY_SPL_DIR_SRC)
aux_source_directory(${WEBRTC_COMMON_AUDIO_VAD_DIR} WEBRTC_COMMON_AUDIO_VAD_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_CODING_ISAC_VAD_DIR} WEBRTC_MODULES_AUDIO_CODING_ISAC_VAD_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_INCLUDE} WEBRTC_MODULES_AUDIO_PROCESSING_INCLUDE_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_AEC3_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_AEC3_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_AECM_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_AECM_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_AGC_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_AGC_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_AGC2_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_AGC2_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_AGC2_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_LOGGING_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_LOGGING_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_NS_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_NS_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_VAD_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_VAD_DIR_SRC)
aux_source_directory(${WEBRTC_MODULES_AUDIO_PROCESSING_THIRD_PARTY_FFT_DIR} WEBRTC_MODULES_AUDIO_PROCESSING_THIRD_PARTY_FFT_DIR_SRC)
aux_source_directory(${WEBRTC_RTC_BASE_DIR} WEBRTC_RTC_BASE_DIR_SRC)
aux_source_directory(${WEBRTC_RTC_BASE_EXPERIMENTS_DIR} WEBRTC_RTC_BASE_EXPERIMENTS_DIR_SRC)
aux_source_directory(${WEBRTC_RTC_BASE_MEMORY_DIR} WEBRTC_RTC_BASE_MEMORY_DIR_SRC)
aux_source_directory(${WEBRTC_RTC_BASE_STRINGS_DIR} WEBRTC_RTC_BASE_STRINGS_DIR_SRC)
aux_source_directory(${WEBRTC_RTC_BASE_SYNCHRONIZATION_DIR} WEBRTC_RTC_BASE_SYNCHRONIZATION_DIR_SRC)
aux_source_directory(${WEBRTC_RTC_BASE_SYSTEM_DIR} WEBRTC_RTC_BASE_SYSTEM_DIR_SRC)
aux_source_directory(${WEBRTC_SYSTEM_WRAPPERS_DIR} WEBRTC_SYSTEM_WRAPPERS_DIR_SRC)
aux_source_directory(${WEBRTC_THIRD_PARTY_RNNNOISE_DIR} WEBRTC_THIRD_PARTY_RNNNOISE_DIR_SRC)
add_subdirectory(${CURRENT_DIR}/third_party/abseil-cpp)
add_subdirectory(${CURRENT_DIR}/third_party/jsoncpp/source)
add_subdirectory(${CURRENT_DIR}/third_party/pffft/src)
add_library(${PROJECT_NAME} STATIC
${WEBRTC_API_AUDIO_DIR_SRC}
${WEBRTC_API_TASK_QUEUE_SRC}
${WEBRTC_API_DEFAULT_TASK_QUEUE_SRC}
${WEBRTC_COMMON_AUDIO_DIR_SRC}
${WEBRTC_COMMON_AUDIO_RESAMPLER_DIR_SRC}
${WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_DIR_SRC}
${WEBRTC_COMMON_AUDIO_THIRD_PARTY_OOURA_128_DIR_SRC}
${WEBRTC_COMMON_AUDIO_THIRD_PARTY_OOURA_256_DIR_SRC}
${WEBRTC_COMMON_AUDIO_THIRD_PARTY_SPL_DIR_SRC}
${WEBRTC_COMMON_AUDIO_VAD_DIR_SRC}
${WEBRTC_MODULES_AUDIO_CODING_ISAC_VAD_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_INCLUDE_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_AEC3_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_AECM_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_AGC_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_AGC2_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_DIR}
${WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_LOGGING_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_NS_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_VAD_DIR_SRC}
${WEBRTC_MODULES_AUDIO_PROCESSING_THIRD_PARTY_FFT_DIR_SRC}
${WEBRTC_RTC_BASE_DIR_SRC}
${WEBRTC_RTC_BASE_EXPERIMENTS_DIR_SRC}
${WEBRTC_RTC_BASE_MEMORY_DIR_SRC}
${WEBRTC_RTC_BASE_STRINGS_DIR_SRC}
${WEBRTC_RTC_BASE_SYNCHRONIZATION_DIR_SRC}
${WEBRTC_RTC_BASE_SYSTEM_DIR_SRC}
${WEBRTC_SYSTEM_WRAPPERS_DIR_SRC}
${WEBRTC_THIRD_PARTY_RNNNOISE_DIR_SRC}
)
target_link_libraries(${PROJECT_NAME} absl::strings absl::optional absl::base jsoncpp_static pffft)
另外還需准備agc2的測試demo,該demo只是基於我對webrtc代碼的理解,也有可能理解不對,因為在測試過程中,效果並沒有期望的那么好,所以分享出來這個項目希望大佬能夠指正問題
#include "modules/audio_processing/gain_control_impl.h"
#include "modules/audio_processing/gain_controller2.h"
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "modules/audio_processing/audio_buffer.h"
#include "common_audio/wav_file.h"
#include "common_audio/wav_header.h"
#include "common_audio/channel_buffer.h"
#include "common_audio/include/audio_util.h"
#include "common_audio/test_utils.h"
using namespace std;
using namespace webrtc;
const int kChunkSizeMs = 10;
const int kSampleRate16kHz = 16000;
struct Agcinput{
char* input_file;
char* output_file;
};
void agc2(struct Agcinput* agc_input){
std::unique_ptr<WavReader> in_file(new WavReader(agc_input->input_file));
int input_sample_rate_hz = in_file->sample_rate();
int input_num_channels = in_file->num_channels();
std::unique_ptr<WavWriter> out_file(new WavWriter(agc_input->output_file,input_sample_rate_hz,input_num_channels));
std::unique_ptr<ChannelBufferWavReader> buffer_reader_;
buffer_reader_.reset(new ChannelBufferWavReader(std::move(in_file)));
std::unique_ptr<ChannelBuffer<float>> in_buf_;
int kChunksPerSecond = 1000 / 10;
in_buf_.reset(new ChannelBuffer<float>(input_sample_rate_hz / kChunksPerSecond,input_num_channels));
std::unique_ptr<ChannelBufferWavWriter> buffer_writer_;
buffer_writer_.reset(new ChannelBufferWavWriter(std::move(out_file)));
std::unique_ptr<ChannelBuffer<float>> out_buf_;
out_buf_.reset(new ChannelBuffer<float>(input_sample_rate_hz / kChunksPerSecond,input_num_channels));
AudioProcessing::Config::GainController2 agc2_config;
agc2_config.enabled=true;
agc2_config.adaptive_digital.enabled=true;
agc2_config.fixed_digital.gain_db=5;
std::unique_ptr<GainController2> gainController2;
gainController2.reset(new GainController2);
gainController2->Initialize(input_sample_rate_hz);
gainController2->ApplyConfig(agc2_config);
RTC_CHECK_EQ(gainController2->Validate(agc2_config), true);
StreamConfig sc(input_sample_rate_hz,input_num_channels);
AudioBuffer ab(input_sample_rate_hz / kChunksPerSecond,input_num_channels,input_sample_rate_hz / kChunksPerSecond,input_num_channels,input_sample_rate_hz / kChunksPerSecond);
bool samples_left_process = true;
int count = 0;
while (samples_left_process){
samples_left_process = buffer_reader_->Read(in_buf_.get());
ab.CopyFrom(in_buf_->channels(), sc);
if(input_sample_rate_hz > kSampleRate16kHz){
ab.SplitIntoFrequencyBands();
}
gainController2->NotifyAnalogLevel(5);
gainController2->Process(&ab);
if(input_sample_rate_hz > kSampleRate16kHz){
ab.MergeFrequencyBands();
}
ab.CopyTo(sc, out_buf_->channels());
buffer_writer_->Write(*out_buf_);
count++;
}
}
int main(int argc, char* argv[]){
std::cout << "webrtc audio processing agc2 test" << std::endl;
char* input_file = argv[1];
char* output_file = argv[2];
Agcinput agc_handle;
agc_handle.input_file = input_file;
agc_handle.output_file = output_file;
agc2(&agc_handle);
return 0;
}
該部分的CMakeLists.txt文件如下
cmake_minimum_required(VERSION 3.6)
project(test_apm)
set(CMAKE_CXX_STANDARD 14)
set(CURRENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CURRENT_DIR}/../webrtc)
add_executable(${PROJECT_NAME}
${CURRENT_DIR}/main.cc
)
target_link_libraries(${PROJECT_NAME} webrtc_apm)
最后建立整個工程的CMakeLists.txt文件
cmake_minimum_required(VERSION 3.6)
project(webrtc_apm_cmake)
set(CURRENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(${CURRENT_DIR}/webrtc)
add_subdirectory(${CURRENT_DIR}/test_apm)
整個工程的項目列表如下

執行如下代碼
cmake .
make
即可得到可執行文件,然后在Clion中配置輸入參數得到運行結果如下。(注:該demo只適用於采樣率16k, 單通道的wav文件)

增強后的語音如下

另外在測試的過程中發現對於語音能量較小的語音文件,會出現延遲方法的現象。以及對於語音中有大小聲的情況,自適應的效果也不是很明顯。
