1. 课程导入
做音视频这行,天天跟卡顿打交道。但说实话,很多人干了三五年,还是分不清「音频卡顿」和「视频卡顿」到底有啥本质区别。
我刚开始带项目那会儿,有一次线上事故,用户反馈直播「一卡一卡的」。团队排查了两天,最后发现是音频缓冲区配置错了。嗯,从那以后,我养成了一个习惯——先问一句:到底是声音卡,还是画面卡?
1.1 音频卡顿 vs 视频卡顿:本质差异
先看一张对比表,把核心差异说清楚。
| 维度 | 音频卡顿 | 视频卡顿 |
|---|---|---|
| 感知方式 | 听觉——断断续续、杂音、变调 | 视觉——画面停滞、跳帧、模糊 |
| 容忍度 | 极低。超过 20ms 的断续就能察觉 | 较高。30fps 下丢一两帧不太明显 |
| 数据特征 | 连续流,采样点不可丢 | 离散帧,丢帧可接受(但会卡) |
| 缓冲策略 | 小缓冲区(几十 ms),低延迟优先 | 大缓冲区(几百 ms),平滑优先 |
| 修复手段 | 插值、PLC(丢包隐藏) | 丢帧、帧重复、降分辨率 |
核心结论:音频卡顿是「连续性」被破坏,视频卡顿是「完整性」被破坏。音频丢一个采样点,人耳就炸了;视频丢一帧,人眼可能没反应。
我个人习惯,排查卡顿时先看音频。为什么?因为音频卡顿的容忍窗口太窄了。你想想看,视频卡顿你还能忍个半秒,音频卡顿超过 50ms,用户就开始骂娘了。
1.2 推流卡顿的宏观表现
推流卡顿,不是单一现象。它是一连串连锁反应的外在表现。我把它拆成三个层面来讲。
1.2.1 采集端卡顿
源头就卡了,后面怎么修都没用。表现是:
- 麦克风或摄像头驱动丢数据
- 采集回调间隔不均匀(比如本该每 10ms 回调一次,结果有时 5ms,有时 30ms)
- 系统负载高,采集线程被调度延迟
避坑指南:我曾经在 Android 项目里遇到过,某些低端机麦克风采集回调会随机「跳 tick」。排查了三天,最后发现是 HAL 层驱动没做时钟补偿。解决方案是加一个 jitter buffer,把不均匀的采集数据先捋顺了再送编码器。
1.2.2 编码端卡顿
编码器跟不上输入速度,或者码率控制出问题。表现是:
- 编码队列堆积,延迟越来越高
- 编码器内部丢帧(尤其是硬件编码器,满了就扔)
- 音频编码器因为采样率不匹配,产生「变调」或「加速」
这里有个坑:很多人以为编码卡顿就是 CPU 不够。其实大部分情况是编码器配置不对。比如 H.264 的 preset 设成了 placebo,或者音频编码的 bitrate 设得比源采样率还高——编码器自己就卡死了。
1.2.3 网络传输卡顿
这是最常见的卡顿来源。表现是:
- 发送缓冲区满,数据包排队出不去
- 网络抖动导致 RTT 忽高忽低
- 丢包重传导致发送端阻塞
注意:网络卡顿和编码卡顿经常被混淆。我见过一个团队,用户反馈卡顿,他们先升级了服务器带宽,结果没用。最后发现是编码器输出码率峰值超过了网络出口带宽——不是网络不够,是编码器「吐」得太快了。
1.3 卡顿的宏观链路图
下面这张图,把推流卡顿的完整链路画出来了。每个环节都可能成为瓶颈。
1.4 音频卡顿的特殊性
音频卡顿和视频卡顿最大的区别,在于「人耳感知模型」。我简单说几个关键点。
- 时间分辨率极高:人耳能分辨 10μs 级别的时差。视频卡顿你还能用「丢帧」糊弄过去,音频卡顿你丢一个采样点(比如 48kHz 下约 20μs),人耳就能听出「啪」的一声。
- 连续性要求苛刻:音频是波形,必须连续。一旦中断,波形就断了,解码器会输出噪声或静音。视频丢一帧,解码器还能用上一帧「撑一下」。
- 延迟敏感度不同:音频端到端延迟超过 200ms,用户就感觉「对不上口型」。视频延迟 500ms 甚至 1 秒,用户可能都没察觉。
实战经验:我在做某款直播软件时,发现音频卡顿的根因往往是「缓冲区太小」。视频缓冲区可以设到 1 秒,音频缓冲区超过 100ms 就会导致明显的延迟感。所以音频缓冲区通常设在 20-50ms,但这又导致它对网络抖动特别敏感——这就是音频卡顿「难搞」的地方。
1.5 推流卡顿的「蝴蝶效应」
最后说一个宏观现象。推流卡顿很少是单一原因导致的。往往是:
- 网络抖动 → 发送端堆积 → 编码器背压 → 采集端被阻塞 → 音频采样点丢失 → 用户听到「咔咔咔」
你看,源头是网络,但最终用户感知到的是音频卡顿。如果你只盯着音频修,永远修不好。
所以我个人习惯,遇到卡顿问题,先拉一条完整链路:采集→编码→网络→解码→渲染。每个环节打上时间戳,看延迟在哪里堆积。这叫「端到端延迟瀑布图」,后面章节我会详细讲怎么画。
一句话总结:音频卡顿是「连续性」问题,视频卡顿是「完整性」问题。推流卡顿是整条链路的「木桶效应」——最弱的一环决定了用户体验。