WebRTC语音处理

CSND已永久停更,最新版唯一来源点击下面链接跳转:

语音增强和语音识别网页书

跨平台WebRTC

WebRTC是google开源的一个免插件实时视频通信技术,其分为web开发和native开发;目前支持chrome,firefox,android,ios,opera,edge。是一个真正意义上的跨平台免插件实时视频通信技术。视频应用一般是基于web层次的开发。本文主要是webRTC的native层语音处理的代码架构和对一个native层语音算法测试程序的梳理。

native层的一些语音算法可以用于语音识别前处理。

native层的安装编译

http://blog.csdn.net/shichaog/article/details/50246155,为了得到测试程序,需要先安装并编译native层代码(源码量比较大,可能下载较慢)

如果想只使用native层的语音处理算法(aec,aecm,agc,ns,vad等),那么可以选择安装下面的代码库,有几点要说明一下:

  • .该代码库是基于Linux系统的,考虑安卓,请绕过
  • 该代码里默认没有带audioproc处理例子,需要自己写测试程序,可以使用cmake,并且参考audioproc的源程序。
  • 这个代码和最新的webRTC并不是同步的,晚上半年是很正常的。

git://anongit.freedesktop.org/pulseaudio/webrtc-audio-processing

native层语音算法测试程序

首先audio算法相关的代码在modules/audio_processing目录下,该目录的所有文件如下:

WebRTC语音处理_第1张图片

完成上述连接中的步骤后,即可找到一个可执行的测试文件audioproc,该而进行文件可以完成上述相关算法的测试。该文件的位置是:

 

webrtc-checkout/src/out/Debug$ ./audioproc


使用help选项该文件的输出如下:

 

 

gsc@gsc-250:~/webrtc-checkout/src/out/Debug$ ./audioproc --help
Usage: process_test [options] [-pb PROTOBUF_FILE]
  [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]
process_test is a test application for AudioProcessing.

When a protobuf debug file is available, specify it with -pb. Alternately,
when -ir or -i is used, the specified files will be processed directly in
a simulation mode. Otherwise the full set of legacy test files is expected
to be present in the working directory. OUT_FILE should be specified
without extension to support both raw and wav output.

Options
General configuration (only used for the simulation mode):
  -fs SAMPLE_RATE_HZ
  -ch CHANNELS_IN CHANNELS_OUT
  -rch REVERSE_CHANNELS

Component configuration:
All components are disabled by default. Each block below begins with a
flag to enable the component with default settings. The subsequent flags
in the block are used to provide configuration settings.

  -aec     Echo cancellation
  --drift_compensation
  --no_drift_compensation
  --no_echo_metrics
  --no_delay_logging
  --aec_suppression_level LEVEL  [0 - 2]
  --extended_filter
  --no_reported_delay

  -aecm    Echo control mobile
  --aecm_echo_path_in_file FILE
  --aecm_echo_path_out_file FILE
  --no_comfort_noise
  --routing_mode MODE  [0 - 4]

  -agc     Gain control
  --analog
  --adaptive_digital
  --fixed_digital
  --target_level LEVEL
  --compression_gain GAIN
  --limiter
  --no_limiter

  -hpf     High pass filter

  -ns      Noise suppression
  --ns_low
  --ns_moderate
  --ns_high
  --ns_very_high
  --ns_prob_file FILE

  -vad     Voice activity detection
  --vad_out_file FILE

  -expns   Experimental noise suppression

 Level metrics (enabled by default)
  --no_level_metrics

Modifiers:
  --noasm            Disable SSE optimization.
  --add_delay DELAY  Add DELAY ms to input value.
  --delay DELAY      Override input delay with DELAY ms.
  --perf             Measure performance.
  --quiet            Suppress text output.
  --no_progress      Suppress progress.
  --raw_output       Raw output instead of WAV file.
  --debug_file FILE  Dump a debug recording.

 

语音算法编译关系

在这个目录下有一个BUILD.gn文件,这个文件,指定了编译的规则和目标以及生成目标的源文件,这里可以看一下audioproc是如何生成的,并且该目录下还有哪些其它的可以使用的测试程序。该文件的一些目标罗列如下:

 

rtc_static_library:编译生成静态库
rtc_executable:将会生成可执行程序,这里指示生成的可执行程序,

以下是可执行程序和其依赖的源程序关系

audioproc:test/process_test.cc

unpack_aecdump:test/unpack.cc

audioproc_f:test/aec_dump_based_simulator.cc;test/audio_processing_simulator.cc;test/audioproc_float.cc;test/wav_based_simulator.cc

transient_suppression_test:transient/transient_suppression_test.cc

nonlinear_beamformer_test:beamformer/nonlinear_beamformer_test.cc

intelligibility_proc:intelligibility/test/intelligibility_proc.cc

 

这篇文章不打算涉及具体的算法,而是梳理代码,所以这里就以process_test.cc来看看最重要的APM(audio processing module)。

 

process_test.cc(在最新的webRTC中已经没有这个文件)

 

1141 }  // namespace
1142 }  // namespace webrtc
1143 
1144 int main(int argc, char* argv[]) {
1145   webrtc::void_main(argc, argv);
1146 
1147   // Optional, but removes memory leak noise from Valgrind.
1148   google::protobuf::ShutdownProtobufLibrary();
1149   return 0;
1150 }


这个全局的main函数调用了webrtc命令空间中的void_main函数。

在这个cc文件的48行

 

48:namespace webrtc {
...
143 // void function for gtest.
144 void void_main(int argc, char* argv[]) { 
...
创建关键对象
155   std::unique_ptr apm(AudioProcessing::Create());
183   AudioProcessing::Config apm_config;
...
//aec模式使能
227     } else if (strcmp(argv[i], "-aec") == 0) {
228       ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
229       ASSERT_EQ(apm->kNoError,
230                 apm->echo_cancellation()->enable_metrics(true));
231       ASSERT_EQ(apm->kNoError,
232                 apm->echo_cancellation()->enable_delay_logging(true));
...
//这个是回声抑制系数,分为low, moderate以及high三种模式
258     } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
259       i++;
260       ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
261       int suppression_level;
262       ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
263       ASSERT_EQ(apm->kNoError,
264                 apm->echo_cancellation()->set_suppression_level(
265                     static_cast(
266                         suppression_level)));
...
458   apm->ApplyConfig(apm_config);

//对于智能语音音箱,近端信号就是说话人对其说话采集到的语音,远端信号就是智能音箱自身发出的声音
//对于VoIP,近端信号就是人对电脑说话,电脑采集到的声音,远端信号就是Voip另外一端人将的语音信号。
767           err = apm->ProcessStream(&near_frame);

//执行远端处理,这里是进行回声消除,这里还有一个延迟估计,暂时跳过
691           ASSERT_EQ(apm->kNoError,
692                     apm->ProcessReverseStream(&far_frame));


1159 }  // namespace
1160 }  // namespace webrtc

这里可以看出,就是执行这里的void_main函数,这个函数执行pb格式的文件,pb格式文件就是google的protocol buffer协议格式的文件,和pb相关的可以选择跳过。其它变量的命名是不言自明的。
我们将155行创建apm模块的方法也可以换一种更为清楚的写法:

 

 

    webrtc::AudioProcessing* apm = webrtc::AudioProcessing::Create();

上述可以看出webrtc命名空间中的AudioProcessing是一个关键的类。
 

AudioProcessing类

这个类定义于是应用程序要包括的头文件(算法实现被编译成库了),有接近三百行,不过由于这个类是沟通算法和应用程序的桥梁,还是非常重要的,所以这里就将其全展开了,但是其调用的一些算法实现方法,就不展开了。最新的webRTC中该类继承于rtc::RefCountInterface类。

这个类包括了实时语音处理的若干组件,其基于逐帧处理,主要帧(做为ProcessStream()括号中的帧参数)将会经过所有使能组件(算法)处理(实际上ProcessStream的参数就是近端信号),ProcessReverseStream()方法则是逐帧处理远端信号。这个模块通常被放在HAL或者是应用之下层(实际上它和应用没有关系,如果确实要和应用打交到,也最好通过socket或者其它通信方式时间,而不是直接嵌入应用程序代码)。

所有的组件在创建时都是disable的,在缺省设置值基础上进行调优,在使能一个组件时,才会触发内存分配和初始化。

免锁线程安全依赖于如下条件:

  • stream获取和设置在同一个ProcessStream()线程中,不允许在多个线程中操作。
  • 参数获取和设置不能够并发调用

APM只接受10ms的数据,int16是交叉数据排列方式,而float接口是非交叉排列方式。

一个使用的例子是:

 

   197 // Usage example, omitting error checking:
   198 // AudioProcessing* apm = AudioProcessing::Create(0);
   199 //
   200 // AudioProcessing::Config config;
   201 // config.level_controller.enabled = true;
   202 // apm->ApplyConfig(config)
   203 //
   204 // apm->high_pass_filter()->Enable(true);
   205 //
   206 // apm->echo_cancellation()->enable_drift_compensation(false);
   207 // apm->echo_cancellation()->Enable(true);
   208 //
   209 // apm->noise_reduction()->set_level(kHighSuppression);
   210 // apm->noise_reduction()->Enable(true);
   211 //
   212 // apm->gain_control()->set_analog_level_limits(0, 255);
   213 // apm->gain_control()->set_mode(kAdaptiveAnalog);
   214 // apm->gain_control()->Enable(true);
   215 //
   216 // apm->voice_detection()->Enable(true);
   217 //
   218 // // Start a voice call...
   219 //
   220 // // ... Render frame arrives bound for the audio HAL ...
   221 // apm->ProcessReverseStream(render_frame);
   222 //
   223 // // ... Capture frame arrives from the audio HAL ...
   224 // // Call required set_stream_ functions.
   225 // apm->set_stream_delay_ms(delay_ms);
   226 // apm->gain_control()->set_stream_analog_level(analog_level);
   227 //
   228 // apm->ProcessStream(capture_frame);
   229 //
   230 // // Call required stream_ functions.
   231 // analog_level = apm->gain_control()->stream_analog_level();
   232 // has_voice = apm->stream_has_voice();
   233 //
   234 // // Repeate render and capture processing for the duration of the call...
   235 // // Start a new call...
   236 // apm->Initialize();
   237 //
   238 // // Close the application...
   239 // delete apm;

 

其创建方法位于audio_processing_impl.cc文件:

 

AudioProcessing* AudioProcessing::Create() {
  Config config;
  return Create(config, nullptr);
}

AudioProcessing* AudioProcessing::Create(const Config& config) {
  return Create(config, nullptr);
}

AudioProcessing* AudioProcessing::Create(const Config& config,
                                         Beamformer* beamformer) {
  AudioProcessingImpl* apm = new AudioProcessingImpl(config, beamformer);
  if (apm->Initialize() != kNoError) {
    delete apm;
    apm = NULL;
  }

  return apm;
}

含有纯虚函数是无法实例化(new)的,必然会有继承类来重载这些纯虚函数,这个继承类就是AudioProcessingImpl类,AudioProcessingImpl是继承基类AudioProcessing的。如果想看具体实现,就看这个文件以及里面定义的方法。

WebRTC语音处理_第2张图片

这里面的设计思想还是很巧妙的,其它每一个算法模块分割成一个类,在这个中再实例化算法模块类,然后再调用相应类的enable方法以使能,所以会有若干的impl.cc结尾的函数,这些函数(如noise_suppresion_impl.cc)就是对核心算法的封装,封装后提供给这里APM模块实例化和使用,代码分格简洁/高效/可扩展性好。

 

 

总结如下:编译,测试
python webrtc/build/gyp_webrtc
ninja -C out/Debug 
 ./nonlinear_beamformer_test -i out2.wav -mic_positions "1.0 1.0 1.0 2.0 2.2 2.2 1.1 1.2 0" out.wav

20170630之后只能使用audio_proc_f,文件在:
webrtc/modules/audio_processing/test/audioproc_float.cc

 

你可能感兴趣的:(语音识别)