# NetEq 时间伸缩 · 变速不变调

> NetEq 靠加速/减速播放来微调缓冲，但快进磁带会变尖、慢放会变低沉——怎么变速却不变调？靠 WSOLA：找相似波形、去掉或插入一个基音周期、交叉叠加。这一章讲清这个让 NetEq 悄悄调节延迟的核心技术。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/neteq-timestretch
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# NetEq 时间伸缩 · 变速不变调

[NetEq 靠加速 / 减速播放微调缓冲](https://daiw.org/manual/webrtc/neteq-buffer-delay)：[缓冲多了加速追回](https://daiw.org/manual/webrtc/neteq-operations)、[少了减速攒回](https://daiw.org/manual/webrtc/neteq-operations)。但有个难题：普通的变速会**变调**——快进像磁带倒带尖细，慢放像喝醉了低沉。NetEq 必须**变速却不变调**，才能让人察觉不到。这一章讲这个精妙的技术。

## 难题：变速为什么会变调

先理解为什么天真的变速会变调：

<Callout type="info">
  **声音的“音调”由波形的**频率**决定。如果你简单地把音频“快放”（每秒播更多样本），波形的频率就整体升高——音调变尖（花栗鼠效应）；“慢放”则频率降低，音调变闷。** 这是因为“播放速度”和“频率”被绑在了一起：快放 = 波形被横向压缩 = 频率升高 = 音调变高。所以不能简单地“少播点样本来加速”——那会毁掉音色，一听就假。

  NetEq 要的是：**把一段音频的时长改变（变短 = 加速 / 变长 = 减速），但保持音调不变**——就像你正常语速说话和略快说话，音调是一样的，只是时长不同。这在信号处理里叫**时间伸缩（time-stretching）**，是个经典难题。
</Callout>

## 解法：WSOLA，按基音周期增删

NetEq 用的技术是 **WSOLA（Waveform Similarity Overlap-Add，波形相似交叠相加）**，思路巧妙：

<Callout type="info">
  **要给语音“加速”（缩短），就找到一个[基音周期](https://daiw.org/manual/webrtc/neteq-plc)、把它**去掉一个**；要“减速”（拉长），就**插入一个**——因为语音是[准周期的](https://daiw.org/manual/webrtc/neteq-plc)，去掉 / 插入一整个基音周期，音调（周期本身）不变，只是时长变了。** 关键在“**去掉 / 插入的接缝处怎么不咔哒**”：WSOLA 用**波形相似性**找到最匹配的拼接点（让接缝两侧的波形尽量吻合），再用**交叉叠加（overlap-add）** 平滑过渡——和 [Merge 的交叉淡化](https://daiw.org/manual/webrtc/neteq-plc)异曲同工。

  举例：一段 30ms 的音频，基音周期是 5ms（200Hz 的低音）。要加速，就找一个位置去掉一个 5ms 周期，变成 25ms——播放时长短了、但每个周期还是 5ms，所以**音调没变**，只是这段话说得略快了。人耳对“略快 / 略慢”的语速极不敏感（尤其只调几毫秒），于是 NetEq 能**神不知鬼不觉地**每次[微调几毫秒](https://daiw.org/manual/webrtc/neteq-buffer-delay)，把缓冲量慢慢拉回目标。**变速不变调，是 NetEq 能“悄悄调节延迟”的技术基石。**
</Callout>

## 为什么这如此重要

WSOLA 时间伸缩，是 NetEq [自适应缓冲](https://daiw.org/manual/webrtc/neteq-buffer-delay)的**执行手段**，它的意义比看起来大：

<Callout type="info">
  **正因为能“无感地变速”，NetEq 才能把[延迟](https://daiw.org/manual/webrtc/neteq-buffer-delay)控制做得如此丝滑——它不必“要么多缓冲、要么断音”地生硬取舍，而能**持续地、微量地**伸缩播放，让缓冲量始终平滑地贴着目标。** 对比[视频抖动缓冲](https://daiw.org/manual/webrtc/video-jitter-buffer)：视频只能“整帧地”增减缓冲（要么多等一帧、要么丢一帧），粒度粗；而音频靠 WSOLA 能以**毫秒级、连续**地调节，粒度细得多。这就是为什么音频的延迟自适应比视频**平滑得多**——你几乎从不会感觉到音频在“调整缓冲”，但它一直在。

  代价是 CPU：WSOLA 要做[波形相似性搜索](https://daiw.org/manual/webrtc/neteq-timestretch)，有计算量。但音频[数据量小](https://daiw.org/manual/webrtc/audio-codecs)，这点开销值得——换来的是**流畅、低延迟、无感**的音频体验。当你视频通话时觉得“声音一直很顺”，背后正是 NetEq 在用 WSOLA [持续地](https://daiw.org/manual/webrtc/neteq-buffer-delay)、悄悄地伸缩着每一小段音频。
</Callout>

## 小结与第 7 部分 NetEq 回顾

**时间伸缩**让 NetEq **变速不变调**：天真变速会[变调（快尖慢闷）](https://daiw.org/manual/webrtc/neteq-timestretch)，NetEq 用 **WSOLA**——按[基音周期](https://daiw.org/manual/webrtc/neteq-plc)**去掉一个（加速）/ 插入一个（减速）**，音调不变、只改时长，接缝用**波形相似 + 交叉叠加**磨平。这让 NetEq 能**无感、连续、毫秒级**地[微调缓冲](https://daiw.org/manual/webrtc/neteq-buffer-delay)，比[视频抖动缓冲](https://daiw.org/manual/webrtc/video-jitter-buffer)平滑得多。

**NetEq 至此讲透**：[总览](https://daiw.org/manual/webrtc/neteq-overview)→[缓冲与延迟](https://daiw.org/manual/webrtc/neteq-buffer-delay)→[六种操作](https://daiw.org/manual/webrtc/neteq-operations)→[丢包隐藏](https://daiw.org/manual/webrtc/neteq-plc)→时间伸缩。它把抖动缓冲、丢包隐藏、时间伸缩融为一体，是实时音频接收侧的杰作。

接收侧讲完，转到发送侧的另一座高峰——**音频处理 APM**，尤其是**回声消除**。下一章总览 APM。👉 [APM 音频处理总览](https://daiw.org/manual/webrtc/apm-overview)。

## 参考资料

- [1] libwebrtc 源码.`modules/audio_coding/neteq/accelerate.cc`、`preemptive_expand.cc`、`time_stretch.cc`。
- [2] WSOLA 算法 —— Waveform Similarity Overlap-Add 时间伸缩。
- [3] 关联[NetEq 缓冲与延迟](https://daiw.org/manual/webrtc/neteq-buffer-delay)——时间伸缩的目的。
