丢包隐藏(PLC)技术

概述

丢包隐藏(Packet Loss Concealment, PLC)是在接收端对丢失的音频包进行补偿的技术。与 FEC(前向纠错)和 NACK(重传)不同,PLC 不需要任何额外的网络传输——它完全在接收端本地完成,利用已收到的音频信息来"猜测"丢失的内容。

PLC 是实时通信中的最后一道防线:当 FEC 和 NACK 都无法恢复丢失的包时,PLC 负责生成替代音频,避免播放中断。

        flowchart LR
  A[丢包发生] --> B{FEC 能恢复?}
  B -->|是| C[FEC 解码恢复]
  B -->|否| D{NACK 来得及?}
  D -->|是| E[重传恢复]
  D -->|否| F[PLC 生成替代音频]

  style F fill:#f96,stroke:#333
    

PLC 技术分类

类型

原理

质量

代表

静音插入

丢包处用静音填充

差(明显中断)

最简单的实现

重复帧

重复最后一个正常帧

一般(有重复感)

早期 VoIP

基于波形

利用基音周期外推

G.711 Appendix I

基于模型

利用编码器参数外推

很好

G.729 PLC, Opus SILK

基于深度学习

神经网络预测

优秀

WaveNetPLC, LPCNet

静音插入

最简单的 PLC——丢包时插入静音或零值:

正常: |~~~~∿~~~~|~~~~∿~~~~|          |~~~~∿~~~~|
丢包:                      |  静音  |
                            ↑ 听感:明显的"咔嗒"中断

缺点:即使 1% 的丢包率也会严重影响通话质量。唯一的优点是零复杂度。

重复帧

重复最后一个正常帧:

正常: |~~~~∿~~~~|~~~~∿~~~~|          |~~~~∿~~~~|
丢包:                      |~~~~∿~~~~|
                            ↑ 重复上一帧

比静音好,但连续丢包时会产生"机器人"般的重复感。通常加上逐渐衰减来改善。

基于波形的 PLC

利用语音信号的准周期性(基音周期),从已收到的波形中外推丢失的部分。

G.711 Appendix I 算法

这是最经典的波形 PLC 算法:

步骤:
1. 保存最近 48.75ms 的语音历史(390 samples @ 8kHz)
2. 丢包时,在历史缓冲中搜索基音周期
   - 用自相关函数找到最强的周期性
   - 搜索范围:40-120 samples(200-1000 Hz)
3. 用基音周期长度的波形片段重复填充丢失帧
4. 在拼接点做重叠相加(OLA)平滑
5. 连续丢包时逐渐衰减(每帧衰减约 10%)
/* 简化的基音周期搜索 */
int find_pitch(int16_t *history, int hist_len) {
    float best_corr = -1.0;
    int best_lag = 40;

    for (int lag = 40; lag <= 120; lag++) {
        float corr = 0, energy1 = 0, energy2 = 0;
        for (int i = 0; i < 80; i++) {
            int idx1 = hist_len - 80 + i;
            int idx2 = idx1 - lag;
            corr += history[idx1] * history[idx2];
            energy1 += history[idx1] * history[idx1];
            energy2 += history[idx2] * history[idx2];
        }
        float norm_corr = corr / sqrt(energy1 * energy2 + 1e-10);
        if (norm_corr > best_corr) {
            best_corr = norm_corr;
            best_lag = lag;
        }
    }
    return best_lag;
}

基于模型的 PLC

编解码器内置的 PLC 利用编码器的参数模型来生成替代帧,质量通常比波形 PLC 更好。

Opus SILK 模式 PLC

Opus 的 SILK 模式(语音)内置了高质量 PLC:

  1. LP 系数外推:使用最后一帧的 LP 系数(频谱包络)

  2. 基音外推:使用最后一帧的基音周期和增益

  3. 激励信号:用随机噪声 + 基音周期的混合作为激励

  4. 能量衰减:每丢一帧,增益衰减约 2dB

  5. 抖动注入:对基音周期加入微小随机偏移,避免机械感

丢包帧生成:
  LP 滤波器系数 = 上一帧的 LP 系数(略向平坦方向收缩)
  基音延迟 = 上一帧的基音延迟 + 随机偏移(±1 sample)
  激励 = 基音周期重复 × 衰减增益 + 随机噪声 × 噪声增益
  输出 = LP 合成滤波器(激励)

Opus CELT 模式 PLC

Opus 的 CELT 模式(音乐/全带宽)使用不同的 PLC 策略:

  1. 保存最后一帧的 MDCT 频谱

  2. 丢包时,对频谱进行随机相位旋转

  3. 逆 MDCT 变换回时域

  4. 与前一帧做重叠相加

  5. 能量逐渐衰减

这种频域 PLC 对音乐信号效果更好,因为音乐的频谱结构比时域波形更稳定。

G.729 PLC

G.729 的内置 PLC:

  1. 使用最后一帧的 LP 系数和基音参数

  2. 自适应码本(基音预测)继续运行

  3. 固定码本用随机激励替代

  4. 增益逐帧衰减

  5. 连续丢包 > 6 帧后退化为舒适噪声

基于深度学习的 PLC

近年来,深度学习 PLC 取得了显著进展:

LPCNet PLC

Mozilla 的 LPCNet 将传统 LPC 分析与神经网络结合:

  1. 从历史帧提取 LPC 特征

  2. 神经网络预测丢失帧的 LPC 特征

  3. 用 LPCNet 声码器合成波形

  4. 质量接近原始信号

IETF DRED

Deep REDundancy (DRED) 是 Opus 的新扩展(正在标准化):

  • 编码器用神经网络将最近几帧压缩为极低码率的冗余数据

  • 冗余数据嵌入当前帧的 padding 中

  • 丢包时,解码器用冗余数据 + 神经网络恢复丢失帧

  • 可恢复长达数百毫秒的连续丢包

PLC 质量评估

评估 PLC 效果的方法:

方法

说明

工具

PESQ/POLQA

与原始信号对比的客观评分

ITU-T P.862/P.863

PLCMOS

微软开源的 PLC 专用 MOS 预测

pip install plcmos

主观测试

人工听音评分

ITU-T P.800 方法

频谱分析

观察 PLC 帧的频谱连续性

Audacity, MATLAB

不同丢包率下的 PLC 效果参考(Opus SILK @ 16 kbps):

丢包率

无 PLC (MOS)

有 PLC (MOS)

说明

0%

4.0

4.0

基准

5%

2.5

3.6

PLC 效果显著

10%

1.8

3.2

仍可接受

20%

1.2

2.5

质量明显下降

30%

1.0

1.8

勉强可用

小结

PLC 是实时通信音频质量的最后保障。从简单的帧重复到基于深度学习的预测,PLC 技术在不断进化。

对于 WebRTC 开发者,好消息是 Opus 和 NetEQ 已经内置了高质量的 PLC,通常不需要自己实现。但理解 PLC 的原理有助于:

  1. 选择合适的编解码器(Opus 的 PLC 远优于 G.711)

  2. 调优 FEC/NACK 策略(PLC 是最后手段,应优先用 FEC/NACK)

  3. 排查音频质量问题("机器音"可能是 PLC 过度触发)