webrtc的音频混音源码都在modules\audio_mixer目录下,最核心的文件为frame_combiner.h/frame_combiner.cc,该文件的类为class FrameCombiner。
FrameCombiner是 WebRTC 音频混音器(Audio Mixer)模块中的核心组件,负责将多个输入的音频帧(AudioFrame)**混合(Mix/Sum)**成一个单一的输出音频帧。
它的主要任务是执行实际的样本级加法运算,并处理防止音频削波(Clipping)的限幅(Limiting)逻辑。总之FrameCombiner 是 WebRTC 音频会议的数学引擎。它高效地将多路音频信号叠加在一起,并通过智能限幅技术保证输出音质的完整性,是实现多人实时语音通话不可或缺的基础组件
一、核心职责
-
音频混合:接收来自不同参与者(Remote Streams)的音频数据,将它们对应的采样点相加。例如,如果有两个说话者,输出样本 。
-
防削波处理:当多个音频信号相加时,振幅可能会超过最大允许值(对于 float 类型通常是 +/- 1.0,对于 int16 是 +/- 32767)。FrameCombiner 使用 Limiter 来平滑地降低增益,避免产生刺耳的数字失真。
-
缓冲区管理:维护一个固定的浮点数缓冲区 (mixing_buffer_) 用于中间计算,避免频繁的内存分配。
二、关键成员
2.1 mixing_buffer (std::unique_ptr<MixingBuffer>):
• 这是一个二维数组:通道数样本数。
• kMaximumNumberOfChannels = 8: 支持最多 8 个通道(通常用于环绕声或特殊配置,标准通话为 1 或 2)。
• kMaximumChannelSize = 480: 对应 48kHz 采样率下 10ms 的样本数 ()。
• 使用 float 类型进行累加,因为浮点数具有更大的动态范围,可以在混合过程中暂时容纳超过整型范围的数值,最后再转换或限幅。
2.2 limiter (Limiter):
• 音频限幅器实例。
• 如果混合后的信号峰值过高,Limiter 会动态调整增益,使输出信号保持在合法范围内,同时尽量保持音质自然(避免剧烈的音量跳动)。
2.3 use_limiter (bool):
构造函数传入的标志位,决定是否启用限幅功能。在某些低延迟或特定测试场景下可能会禁用。
2.4 data_dumper:
用于调试和日志记录,可以将混合前后的音频数据dump到文件进行分析。
三、核心混音函数
cpp
void Combine(const std::vector<AudioFrame*>& mix_list,
size_t number_of_channels,
int sample_rate,
size_t number_of_streams,
AudioFrame* audio_frame_for_mixing);
这是执行混合操作的核心函数。
3.1 参数说明:
• mix_list: 输入音频帧的指针列表。每个 AudioFrame 代表一个远程参与者的音频数据。
• number_of_channels: 输出音频的通道数(如 1 为单声道,2 为立体声)。输入帧会被重采样或混音到此通道数。
• sample_rate: 采样率(如 48000 Hz)。所有输入帧必须与此采样率一致(或在进入此函数前已重采样)。
• number_of_streams: 活跃流的数量。用于判断是否需要应用限幅(例如,只有一个流时通常不需要限幅,除非它本身就过载)。
• audio_frame_for_mixing: 输出参数。混合后的结果将写入这个 AudioFrame 对象。
3.2 内部工作流程(逻辑推断):
-
初始化缓冲区: 将 mixing_buffer_ 清零。
-
累加样本:
• 遍历 mix_list 中的每一个 AudioFrame。
• 将每个帧的样本数据(通常从 int16 转换为 float)累加到 mixing_buffer_ 对应的通道和样本位置上。
• 如果是多声道输入,可能需要进行下混(Downmix)到目标 number_of_channels。
- 应用限幅 (Limiter):
• 如果 use_limiter_ 为 true 且 number_of_streams > 1(或信号过大),调用 limiter_.Process()。
• Limiter 会分析 mixing_buffer_ 中的峰值,并应用增益衰减,确保最终输出不会削波。
- 写入输出:
• 将处理后的 mixing_buffer_ 中的数据转换回 int16_t(WebRTC AudioFrame 的标准格式)。
• 填充 audio_frame_for_mixing 的字段(samples_per_channel_, num_channels, sample_rate_hz_, data 等)。
- 统计日志: 调用 LogMixingStats 记录混合状态(如是否发生了削波,限幅器的增益调整量等)。
四、为什么需要单独的 FrameCombiner?
• 性能优化: 音频混合是 CPU 密集型操作(每 10ms 处理数千次浮点加法)。使用预分配的 mixing_buffer_ 避免了每次混合都 new/delete 数组。
• 模块化: 将"混合算法"与"混音器调度逻辑"(决定谁该被混合、静音处理等)分离。AudioMixerImpl 负责调度,FrameCombiner 负责数学运算。
• 音质保护: 简单的相加会导致严重的削波失真。集成 Limiter 确保了在多人大声说话时,输出音频依然清晰且不破音。