本文主要介绍WebRTC的APM。

现在主要介绍一下audio_processing.h。

首先插入了几个类,这些都是audio_processing的核心模块。

class AudioFrame;  
class EchoCancellation;  
class EchoControlMobile;  
class GainControl;  
class HighPassFilter;  
class LevelEstimator;  
class NoiseSuppression;  
class VoiceDetection;  

AudioFrame:主要记录了通道基本信息,数据,VAD标志时间戳,采样频率,信道数等。

EchoCancellation:回声消除模块(AEC),在使用外置扬声器的时候应该使用,有些使用耳麦通讯的情况也会存在回声(因为麦克风与扬声器有空间或者电的弱耦合),如果影响了通话也应该开启。

EchoControlMobile:回声抑制模块(AES),这个模块和回声消除模块功能相似,但是实现方法不一样。运算量远远小于回声消除模块。非常适合移动平台使用。但是对语音损伤大。

GainControl:增益控制模块(AGC),这个模块使用了语音的特征对系统硬件音量和输出的信号大小进行调节。硬件上可以控制输入音量。软件上只能调节原来信号的幅度,如果对原来就已经破音的信号,或者本来输入就比较小的信号就无能为力了。

HighPassFilter:高通滤波器,抑制不需要的低频信号。可以根据需要修改参数选择相应的截止频率。对于某些有工频干扰的设备需要使用高通滤波器。

LevelEstimator:估计信号的能量值。

NoiseSuppression:噪声抑制模块(NS/SE),该模块一般应用在有环境噪声的情况,或者是麦克风采集到的数据有明显噪声的情况。

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个步骤的处理。

1、判断是否是32k信号,采取相应的分频策略;

2、AEC流程,记录AEC中的far-end及其相关运算;

3、AES流程,记录AES中的far-end及其相关运算;

4、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;
}

其中包括七个步骤:1、分频;2、高通滤波;3、硬件音量控制;4、AEC;5、NS;6、AES;7、VAD;8、AGC;9、综合。

可见near-end的处理全面,流程清晰。可以根据实际需要打开不同的模块,适应不同场景的需要,对于一般通讯系统来说具有正面的改善效果。但是在实际工作中也发现了一些流程上隐患。另外就是该结构的各个模块处理相对独立耦合低,本来应该是一个优良的特性,然而在复杂情况的信号处理难以到达目标效果。由于低耦合造成的运算量浪费更加是无法避免的。

WebRTC APM音频处理流程概述的更多相关文章

  1. webrtc的音频处理模块apm( audio processing)下载与编译出libwebrtc_audio_preprocessing.so

    webrtc代码在android和chromium项目中都有.但是android中的那个带有Android.mk,稍微修改下就能用ndk-build编译出libwebrtc_audio_preproc ...

  2. 单独编译使用WebRTC的音频处理模块

    块,每块个点,(12*64=768采样)即AEC-PC仅能处理48ms的单声道16kHz延迟的数据,而 - 加载编译好的NS模块动态库 接下来只需要按照 此文 的描述在 android 的JAVA代码 ...

  3. 【单独编译使用WebRTC的音频处理模块 - android】

    更新 [2015年2月15日] Bill 这段时间没有再关注 WebRTC 以及音频处理的相关信息,且我个人早已不再推荐单独编译 WebRTC 中的各个模块出来使用.实际上本文的参考价值已经很小了,甚 ...

  4. 2019 WebRtc AudioMixer混音流程

    本文简要说明最新版WebRtc AudioMixer混音流程. 本程序使用4个16KHz 单声道时长均大于10秒的Wav文件作为混音源,只合成前10秒的音频,输出也是16KHz单声道音频. 输入和输出 ...

  5. Java虚拟机JVM学习01 流程概述

    Java虚拟机JVM学习01 流程概述 Java虚拟机与程序的生命周期 一个运行时的Java虚拟机(JVM)负责运行一个Java程序. 当启动一个Java程序时,一个虚拟机实例诞生:当程序关闭退出,这 ...

  6. 异步tcp通信——APM.Core 服务端概述

    为什么使用异步 异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池.就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理.异步操作执行时,会将操作丢给 ...

  7. ETL流程概述及常用实现方法

    ETL流程概述及常用实现方法 http://blog.csdn.net/btkuangxp/article/details/48224187 目录(?)[-] 1抽取作业 1手工开发抽取作业时候的常用 ...

  8. Linux音频驱动-ALSA概述

    概述 ALSA(Advanced Linux Sound Architecture)是linux上主流的音频结构,在没有出现ALSA架构之前,一直使用的是OSS(Open Sound System)音 ...

  9. iOS音频开发系列-概述篇

    概述 iOS中对于音频的处理,苹果提供了两个库. AVFoundation AudioToolbox 在iOS系统中apple对上述的流程进行了封装并提供了不同层次的接口

随机推荐

  1. Bzoj1597 [Usaco2008 Mar]土地购买

    Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4005  Solved: 1460 Description 农夫John准备扩大他的农场,他正在考虑N ...

  2. 有关bat的一些代码

    1.if语句    @echo off     if exist E:\aa.dat dir C: >> E:\ff.txt       pause     type E:\ff.txt ...

  3. codevs 1772 歌词

    1772 歌词  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 白银 Silver       题目描述 Description 35痛过以后才知情已难寻吾爱至斯只剩飞花梦影回 ...

  4. C++ ## ... 实用

    关于...的使用...在C宏中称为Variadic Macro,也就是变参宏.比如:#define myprintf(templt,...)fprintf(stderr,templt,__VA_ARG ...

  5. win32 disk imager使用后u盘容量恢复

    XP下进入CMD命令窗体,Vista及7下右键以管理员方式运行DOS窗体 输入DISKPART,会显示计算机名,及DISKPART>命令行 在此状态下输入LIST DISK查看机器磁盘,正常Di ...

  6. mysql中event的用法详解

    一.基本概念mysql5.1版本开始引进event概念.event既“时间触发器”,与triggers的事件触发不同,event类似与linux crontab计划任务,用于时间触发.通过单独或调用存 ...

  7. linux用命令删除重复行

    文本处理时,经常要删除重复行,下面是三种方法 第一,用sort+uniq,注意,单纯uniq是不行的. sort -n test.txt | uniq 第二,用sort+awk命令,注意,单纯awk同 ...

  8. PHP控制输出不缓存头

    @header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); @header("Cache-Control: no-cache, ...

  9. ReactiveCocoa源码拆分解析(三)

    (整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载) 这一章节主要讨论信号的“冷”与“热” 在RAC的世界 ...

  10. 安卓TabHost页面

    <?xml version="1.0" encoding="UTF-8"?> <!-- TabHost组件id值不可变--> <T ...