webrtc-agc2

本文主要整理了webrtcagc2模块。目前为止,webrtc提供的agc总共有三个版本,最老的版本在legacy文件夹下,然后就是agc文件下的一个版本,最后一个就是位于agc2文件下的另一版本。相较于之前的版本,agc2引入了RNNvad估计。当然其它的部分也有所改进,如噪声估计、增益求解。webrtcagc2模块打算分两次博文介绍,本篇主要介绍编译以及agc2效果测试,下一篇博文主要介绍自己对agc2算法的理解。agc2的编译所需文件包括:apicommon_audiortc_basesystem_wrappersthird_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文件)

增强后的语音如下

另外在测试的过程中发现对于语音能量较小的语音文件,会出现延迟方法的现象。以及对于语音中有大小声的情况,自适应的效果也不是很明显。

原文地址:https://www.cnblogs.com/tingweichen/p/14094825.html