基于 RTC 场景下要解决的声音的问题,WebRTC 有一个大体如下图所示的音频处理流水线:
WebRTC 的音频处理流水线,不是一次性建立起来的,而是分阶段分步骤建立的。整体而言,可以认为这个流水线分两个阶段建立,或者可以认为这个流水线分为两部分:一部分可称为静态流水线,另一部分可称为动态流水线,或者也可以称为前端和后端。静态流水线,在某个时间点建立一次,随后在整个 WebRTC 通信过程中基本保持不变;动态流水线则在通信过程中,可能出现较为频繁的变动,如本地打开或禁用录制启动发送或停止发送音频数据,远端发送者加入或退出频道等,都会改变动态流水线。
如此,WebRTC 的音频处理流水线大致如下图所示:
WebRTC 音频的静态流水线,建立之后,其相关节点状态由 AudioState
维护和管理。WebRTC 音频的静态流水线,主要包括 AudioDeviceModule
,AudioProcessing
,和 AudioMixer
等,其中 AudioDeviceModule
用于采集和播放音频数据,AudioProcessing
主要用于对录制的音频数据做初始处理,如回声消除,降噪等,AudioMixer
主要用于对远端发送过来的音频数据做混音。
WebRTC 音频的静态流水线在 WebRtcVoiceEngine
初始化时建立:
WebRTC 音频静态流水线的几个节点,由外部创建好注入进来,并通过 AudioState
创建的 AudioTransport
连接起来:WebRtcVoiceEngine::Init()
根据需要创建 AudioDeviceModule
,然后创建 AudioState
,AudioState
用注入的 AudioMixer
和 AudioProcessing
创建 AudioTransport
,WebRtcVoiceEngine::Init()
随后将 AudioState
创建的 AudioTransport
作为 AudioCallback 注册给 AudioDeviceModule
。WebRTC 音频静态流水线在 WebRtcVoiceEngine::Init()
中建立。动态流水线和静态流水线在 AudioState
和 AudioTransport
处交汇。
AudioTransport
AudioDeviceModule
在录到音频数据时,将音频数据送给 AudioTransport
,在播放音频时,也向 AudioTransport
拿要播放的音频数据。AudioTransport
是录制的音频数据和播放的音频数据的交汇点。
AudioTransport
接口的定义 (位于 webrtc/src/modules/audio_device/include/audio_device_defines.h
) 如下:
WebRTC 中的 AudioTransport
接口实现 AudioTransportImpl
定义 (位于 webrtc/src/audio/audio_transport_impl.h
) 如下:
AudioTransportImpl
实现的 AudioTransport
接口的要求的操作:将录制的音频数据送出去,及获取播放的音频数据。
AudioTransportImpl
对象创建时保存注入的 AudioMixer
和 AudioProcessing
对象指针:
播放
AudioDeviceModule
可以通过 AudioTransportImpl
的 NeedMorePlayData()
和 PullRenderData()
获取用于播放的音频数据:
NeedMorePlayData()
执行如下操作:
- 通过
AudioMixer
对远端的音频流做混音。AudioTransportImpl
没有直接与AudioReceiveStream
建立连接,但AudioMixer
的 source 实际上是AudioReceiveStream
。 - 把混音后的音频数据送进
AudioProcessing
。主要用于回声消除。 - 对混音后的音频数据重采样。如我们前面看到的
AudioMixerImpl
的实现,它的混音输出采样率有它自己的决定逻辑,可能与AudioDeviceModule
设备需要的不一致,这里需要按照设备的需要,将混音后的数据重采样到设备需要的采样率。 - 返回重采样的数据。
PullRenderData()
的操作与 NeedMorePlayData()
仅有的区别在于,没有上面的第 2 步。如注释中所说,在某些情况下,混音之后的数据无需送进 AudioProcessing
。此外,PullRenderData()
要求调用者只能请求单通道的音频数据,NeedMorePlayData()
的调用者则可以请求单通道或立体声的。
重采样和混音的更多细节,这里不再赘述。
录制
AudioDeviceModule
可以通过 AudioTransport
的 RecordedDataIsAvailable()
把录制的数据送出去:
AudioTransportImpl
的 RecordedDataIsAvailable()
拿到录音得到的音频数据,对音频数据执行如下操作:
- 重采样。
AudioDeviceModule
送进来的音频数据的采样率是设备采集的原始采样率,这里需要把采集的音频数据转换为适合 WebRTC 的音频处理模块如降噪和回声消除等模块及编码器处理的采样率。 - 对音频数据做回声消除,降噪等处理。
- 把音频数据送出去,给注入的
AudioSendStream
。
AudioState
AudioState
既是 WebRTC 音频流水线节点的容器,也可用于对这些节点做一些管理和控制,以及将不同节点粘起来构成流水线。AudioState
接口的定义 (位于 webrtc/src/call/audio_state.h
) 如下:
作为音频处理流水线的容器,AudioState
接口主要包含了 AudioMixer
、AudioProcessing
和 AudioDeviceModule
。AudioState
对象的创建主要通过静态工厂方法完成。
WebRTC 提供了 AudioState
接口的实现,该实现的定义 (位于 webrtc/src/audio/audio_state.h
) 如下:
如上面看到的,AudioState
对象在 WebRtcVoiceEngine::Init()
创建。AudioState
的 Create()
函数定义 (位于 webrtc/src/audio/audio_state.cpp
) 如下:
WebRTC 中实际在用的 AudioState
对象为 webrtc::internal::AudioState
的对象。
AudioState
完成的工作主要为:
- 音频流水线的节点的 Getter
- 管理音频静态流水线和动态流水线的连接,也就是添加和移除
AudioSendStream
和AudioReceiveStream
:把AudioSendStream
注入给AudioTransportImpl
或从中移除,把AudioReceiveStream
添加到AudioMixer
或从中移除。这些接口主要由webrtc::Call
使用。 - 控制播放和录制的启动和停止。
webrtc::internal::AudioState
的具体实现 (位于 webrtc/src/audio/audio_state.cpp
) 如下:
总结一下:
WebRtcVoiceEngine::Init()
建立了 WebRTC 音频处理的静态流水线。AudioTransport
将音频处理静态流水线的各个节点粘起来。webrtc::Call
使用AudioState
将音频处理流水线的静态部分和动态部分连接起来。