本文主要介绍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. Google开源库-Volley的使用

    一.什么是Volley? Volley is an HTTP library that makes networking for Android apps easier and most import ...

  2. mybatis一个怪异的问题: Invalid bound statement not found

    ssm中报一下错误: invalid bound statement (not found): me.tspace.pm.dao.userdao.getuser    at org.apache.ib ...

  3. 配置linux----------------ip

    在终端中输入 vi /etc/sysconfig/network-scripts/ifcfg-eth0 =================================== DEVICE=" ...

  4. Hibernate的关联映射关系

    一:多对一 <many-to-one 1.name:当前类的属性名(关联映射的类) 2.column:属性多对应的类的对应的表的外键(连接条件) 3.class:属性所对应的类的权限定名 4.n ...

  5. ecshop 后台时间调用

    <script type="text/javascript" src="../js/calendar.php?lang={$cfg_lang}">& ...

  6. 利用pg_stat_activity进行问题排查

    pg_stat_activity是一个非常有用的视图,可以帮助排查pg的一些问题(如连接数目过多问题).pg_stat_activity每行展示的是一个“process”的相关信息,这里的“proce ...

  7. LYDSY模拟赛day2 Dash Speed

    /* 弃坑 */ #include<cstdio> #include<algorithm> using namespace std; ,M=N*; ],nxt[N<< ...

  8. iphone如何导出微信聊天记录到电脑?

    有个小美眉买了个iphone,但发现自己就是一小白,很多功能都不会用,微信倒是用得挺上手的,可以晚上聊到三四点,流量直接飙升500MB.最近她说手机太卡了,问ytkah帮她整一下.拿起她的IPhone ...

  9. PHP HTML代码反转义

    后端为了防止xss的攻击,会过滤前端用户的输入的数据,这样虽然有效的避免xss攻击,但是会带来一个问题,要么全部过滤html留下不非法的数据,要么把HTML代码转义,但是转义之后又会直接在浏览器内显示 ...

  10. Python日志logging

    logging 用于便捷记录日志且线程安全的模块 1.单文件日志 import logging logging.basicConfig(filename='log.log', format='%(as ...