本文主要整理了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文件)
增强后的语音如下
另外在测试的过程中发现对于语音能量较小的语音文件,会出现延迟方法的现象。以及对于语音中有大小声的情况,自适应的效果也不是很明显。