WebRTC系列之音频的那些事
年初因为工作需要,开始学习 WebRTC,就被其复杂的编译环境和巨大的代码量所折服,注定是一块难啃的骨头。俗话说万事开头难,坚持一个恒心,终究能学习到 WebRTC 的设计精髓。今天和大家聊聊 WebRTC 中音频的那些事。WebRTC 由语音引擎,视频引擎和网络传输三大模块组成,其中语音引擎是 WebRTC 中最具价值的技术之一,实现了音频数据的采集、前处理、编码、发送、接受、解码、混音、后处理、播放等一系列处理流程。
音频引擎主要包含:音频设备模块 ADM、音频编码器工厂、音频解码器工厂、混音器 Mixer、音频前处理 APM。
音频工作机制
想要系统的了解音频引擎,首先需要了解核心的实现类和音频数据流向,接下来我们将简单的分析一下。
音频引擎核心类图:
音频引擎 WebrtcVoiceEngine 主要包含音频设备模块 AudioDeviceModule、音频混音器 AudioMixer、音频 3A 处理器 AudioProcessing、音频管理类 AudioState、音频编码器工厂 AudioEncodeFactory、音频解码器工厂 AudioDecodeFactory、语音媒体通道包含发送和接受等。
1. 音频设备模块 AudioDeviceModule 主要负责硬件设备层,包括音频数据的采集和播放,以及硬件设备的相关操作。
2. 音频混音器 AudioMixer 主要负责音频发送数据的混音(设备采集和伴音的混音)、音频播放数据的混音(多路接受音频和伴音的混音)。
3. 音频 3A 处理器 AudioProcessing 主要负责音频采集数据的前处理,包含回声消除 AEC、自动增益控制 AGC、噪声抑制 NS。APM 分为两个流,一个近端流,一个远端流。近端(Near-end)流是指从麦克风进入的数据;远端(Far-end)流是指接收到的数据。
4. 音频管理类 AudioState 包含音频设备模块 ADM、音频前处理模块 APM、音频混音器 Mixer 以及数据流转中心 AudioTransportImpl。
5. 音频编码器工厂 AudioEncodeFactory 包含了 Opus、iSAC、G711、G722、iLBC、L16 等 codec。
6. 音频解码器工厂 AudioDecodeFactory 包含了 Opus、iSAC、G711、G722、iLBC、L16 等 codec。
音频的工作流程图:
1. 发起端通过麦克风进行声音采集
2. 发起端将采集到的声音信号输送给 APM 模块,进行回声消除 AEC,噪音抑制 NS,自动增益控制处理 AGC
3. 发起端将处理之后的数据输送给编码器进行语音压缩编码
4. 发起端将编码后的数据通过 RtpRtcp 传输模块发送,通过 Internet 网路传输到接收端
5. 接收端接受网络传输过来的音频数据,先输送给 NetEQ 模块进行抖动消除,丢包隐藏解码等操作
6. 接收端将处理过后的音频数据送入声卡设备进行播放
NetEQ模块是 Webrtc 语音引擎中的核心模块
在 NetEQ 模块中,又被大致分为 MCU 模块和 DSP 模块。MCU 主要负责做延时及抖动的计算统计,并生成对应的控制命令。而 DSP 模块负责接收并根据 MCU 的控制命令进行对应的数据包处理,并传输给下一个环节.
音频数据流向
根据上面介绍的音频工作流程图,我们将继续细化一下音频的数据流向。将会重点介绍一下数据流转中心 AudioTransportImpl 在整个环节中扮演的重要角色。
数据流转中心 AudioTransportImpl 实现了采集数据处理接口 RecordDataIsAvailbale 和播放数据处理接口 NeedMorePlayData。RecordDataIsAvailbale 负责采集音频数据的处理和将其分发到所有的发送 Streams。NeedMorePlayData 负责混音所有接收到的 Streams,然后输送给 APM 作为一路参考信号处理,最后将其重采样到请求输出的采样率。
RecordDataIsAvailbale 内部主要流程:
1. 由硬件采集过来的音频数据,直接重采样到发送采样率
2. 由音频前处理针对重采样之后的音频数据进行 3A 处理
3.VAD 处理
4. 数字增益调整采集音量
5. 音频数据回调外部进行外部前处理
6. 混音发送端所有需要发送的音频数据,包括采集的数据和伴音的数据
7. 计算音频数据的能量值
8. 将其分发到所有的发送 Streams
NeedMorePlayData 内部主要流程:
1. 混音所有接收到的 Streams 的音频数据
1.1 计算输出采样率 CalculateOutputFrequency()
1.2 从 Source 收集音频数据 GetAudioFromSources(), 选取没有 mute,且能量最大的三路进行混音
1.3 执行混音操作 FrameCombiner::Combine()
2. 特定条件下,进行噪声注入,用于采集侧作为参考信号
3. 对本地伴音进行混音操作
4. 数字增益调整播放音量
5. 音频数据回调外部进行外部前处理
6. 计算音频数据的能量值
7. 将音频重采样到请求输出的采样率
8. 将音频数据输送给 APM 作为一路参考信号处理
由上图的数据流向发现,为什么需要 FineAudioBuffer 和 AudioDeviceBuffer?因为 WebRTC 的音频流水线只支持处理 10 ms 的数据,不同的操作系统平台提供了不同的采集和播放时长的音频数据,不同的采样率也会提供不同时长的数据。例如 iOS 上,16K 采样率会提供 8ms 的音频数据 128 帧;8K 采样率会提供 16ms 的音频数据 128 帧;48K 采样率会提供 10.67ms 的音频数据 512 帧.
AudioDeviceModule 播放和采集的数据,总会通过 AudioDeviceBuffer 拿进来或者送出去 10 ms 的音频数据。对于不支持采集和播放 10 ms 音频数据的平台,在平台的 AudioDeviceModule 和 AudioDeviceBuffer 还会插入一个 FineAudioBuffer,用于将平台的音频数据格式转换为 10 ms 的 WebRTC 能处理的音频帧。在 AudioDeviceBuffer 中,还会 10s 定时统计一下当前硬件设备过来的音频数据对应的采样点个数和采样率,可以用于检测当前硬件的一个工作状态。
音频相关改动
1. 音频 Profile 的实现,支持 Voip 和 Music 2 种场景,实现了采样率、编码码率、编码模式、声道数的综合性技术策略。
iOS 实现了采集和播放线程的分离,支持双声道的播放。
2. 音频 3A 参数的兼容性下发适配方案。
3. 耳机场景的适配,蓝牙耳机和普通耳机的适配,动态 3A 切换适配。
4.Noise_Injection 噪声注入算法,作为一路参考信号,在耳机场景的回声消除中的作用特别明显。
5. 支持本地伴音文件 file 和网络伴音文件 http&https。
6.Audio Nack 的实现,提高音频的抗丢包能力,目前正在进行 In-band FEC。
7. 音频处理在单讲和双讲方面的优化。
8.iOS 在 Built-In AGC 方面的研究:
1. Built-In AGC 对于 Speech 和 Music 有效,对于 noise 和环境底噪不会产生作用。
2. 不同机型的麦克风硬件的增益不同,iPhone 7 Plus > iPhone 8 > iPhone X; 因此会在软件 AGC 和硬件 AGC 都关闭的情况下,远端听到的声音大小表现不一样。
3. iOS 除了提供的可开关的 AGC 以外,还有一个 AGC 会一直工作,对信号的 level 进行微调;猜想这个一直工作的 AGC 是 iOS 自带的 analog AGC,可能和硬件有关,且没有 API 可以开关,而可开关的 AGC 是一个 digital AGC。
4. 在大部分 iOS 机型上,外放模式“耳机再次插入后”,input 的音量会变小。当前的解决方案是在耳机再次插入后,增加一个 preGain 来把输入的音量拉回正常值。
音频问题排查
和大家分享一下音频最常见的一些现象以及原因:
更多技术干货,欢迎关注 vx 公众号 “ 网易智慧企业技术+”。系列课程提前看,精品礼物免费得,还可直接对话 CTO。
听网易 CTO 讲述前沿观察,看最有价值技术干货,学网易最新实践经验。网易智慧企业技术 +,陪你从思考者成长为技术专家。