A. ALSA / 音频基础
1. ALSA 采集流程是什么?
ALSA 采集的典型流程是:
snd_pcm_open()打开采集设备,流方向选SND_PCM_STREAM_CAPTURE- 分配并初始化硬件参数对象
snd_pcm_hw_params_t - 设置访问方式,比如
SND_PCM_ACCESS_RW_INTERLEAVED - 设置采样格式,比如
SND_PCM_FORMAT_S16_LE或SND_PCM_FORMAT_S32_LE - 设置声道数和采样率
- 可选设置
period_size和buffer_size - 调用
snd_pcm_hw_params()使参数生效 - 循环调用
snd_pcm_readi()读取 PCM 帧数据 - 如果出现
-EPIPE等错误,做恢复处理,比如snd_pcm_prepare()或snd_pcm_recover() - 结束时
snd_pcm_close()
一句话总结:打开设备 → 配参数 → 连续读 PCM → 异常恢复 → 关闭设备。
2. ALSA 播放流程是什么?
播放和采集基本对称,只是方向相反:
snd_pcm_open()打开播放设备,流方向选SND_PCM_STREAM_PLAYBACK- 设置硬件参数:访问方式、采样格式、采样率、声道数、buffer/period
snd_pcm_hw_params()提交参数- 循环调用
snd_pcm_writei()向设备写 PCM 帧 - 如果返回欠载,比如
-EPIPE,做恢复 - 播放结束时调用
snd_pcm_drain()等待剩余数据播完 - 最后
snd_pcm_close()
一句话:打开设备 → 配参数 → 连续写 PCM → 处理 underrun → drain/close。
3. 什么是 sample 和 frame?
sample 是一个声道在某一时刻的一个采样值 。
frame 是某一时刻所有声道的采样值集合。
比如:
- 单声道 16bit:1 个 frame = 1 个 sample = 2 字节
- 双声道 16bit:1 个 frame = 左 1 个 sample + 右 1 个 sample = 4 字节
面试里最常见的坑是把 frame 和字节数混了。
readi/writei 的单位一般是 frame,不是字节。
4. 什么是 period_size 和 buffer_size?
buffer_size 是 ALSA 整个环形缓冲区的大小。
period_size 是缓冲区中一个周期块的大小。
可以理解成:
text
buffer = 多个 period 组成
设备通常每处理完一个 period,就触发一次唤醒或中断,应用就可以继续读/写数据。
它们的影响是:
period_size小:延迟低,但中断更频繁,CPU 压力更大buffer_size大:更稳定,不容易欠载/溢出,但延迟更大
所以它们本质上是在 延迟 和 稳定性 之间做权衡。
5. 什么是 underrun 和 overrun?
underrun
发生在播放场景。
设备播放数据太快,应用写数据太慢,导致缓冲区空了。
结果就是:
- 播放卡顿
- 爆音
snd_pcm_writei()报错,常见是-EPIPE
overrun
发生在采集场景。
设备采集数据太快,应用读数据太慢,导致缓冲区满了,新数据覆盖旧数据。
结果就是:
- 录音丢帧
- 数据断裂
snd_pcm_readi()报错
一句话:
播放供不上是 underrun,采集来不及读是 overrun。
6. PCM 和 WAV 有什么区别?
PCM 是原始音频采样数据 ,本质上就是一串采样值。
它不一定带任何描述信息。
WAV 是文件封装格式。最常见情况下它内部存的是 PCM,但额外带了头部信息,比如:
- 采样率
- 声道数
- 位深
- 数据长度
所以可以简单理解为:
text
WAV = 头信息 + PCM 数据
PCM 更像"裸数据",WAV 更像"带说明书的数据文件"。
7. WAV 文件头有哪些关键字段?
WAV 是 RIFF 结构,最重要的字段是:
RIFF:标识这是 RIFF 文件WAVE:标识这是 WAV 类型fmt:描述音频格式data:真正的音频数据块
fmt 里常见的关键参数有:
AudioFormatNumChannelsSampleRateByteRateBlockAlignBitsPerSample
data 里最关键的是:
Subchunk2Size,也就是 PCM 数据长度
面试时可以补一句:
text
ByteRate = SampleRate × Channels × BitsPerSample / 8
BlockAlign = Channels × BitsPerSample / 8
8. 采样率、位深、通道数分别影响什么?
采样率
决定单位时间采多少个点,影响时间分辨率和可还原的频率范围。
采样率越高,理论上越能还原高频细节,但数据量也越大。
位深
决定每个采样值的精度,影响动态范围和量化噪声。
位深越高,信号精度越高,动态范围越大。
通道数
决定同一时刻有几个声道数据。
单声道是 1,双声道是 2。通道数越多,数据量越大,也能表达更丰富的空间信息。
B. 音频处理 / 声学相关
9. A/C/Z 计权是什么?
A/C/Z 是三种常见的频率计权方式,用于模拟人耳或做物理测量。
- A 计权:更接近人耳对中低声压下的听觉特性,对低频衰减比较大,最常用
- C 计权:低频衰减比 A 小,适合较高声压场景
- Z 计权:基本不加权,接近平坦响应,反映原始频谱
面试时可以说:
A 更偏主观听感,C 更适合高声压评估,Z 更接近原始物理量。
10. F/S/I 时间计权是什么?
这是时间计权,用于描述声级随时间变化时的响应速度。
- F(Fast):快响应,时间常数短
- S(Slow):慢响应,时间常数长,显示更平滑
- I(Impulse):脉冲响应,针对瞬态冲击声
作用是:
让声级显示既能反映瞬时变化,也能在需要时足够平稳。
11. Leq 和 Lpeak 的区别是什么?
Leq
等效连续声级。
它表示在一段时间内,把变化的声音能量折算成一个等效的恒定声级。
本质上是时间平均能量指标,常用于噪声评价。
Lpeak
峰值声级。
表示在测量期间出现过的最大峰值,反映瞬态冲击的极值。
一句话:
- Leq 看整体平均能量
- Lpeak 看最大瞬时峰值
12. 为什么要做高通滤波?
高通滤波主要是为了去掉:
- 直流分量
- 极低频漂移
- 机械振动或电路低频干扰
这样可以避免低频异常成分影响后续的计权、声级计算或动态范围判断。
在测量型设备里,高通往往是前处理的重要一步。
13. 声级计为什么需要校准?
因为实际测量链路里会有很多误差来源:
- 麦克风灵敏度偏差
- 模拟前端增益偏差
- ADC 偏差
- 温漂、老化
- 机械结构差异
校准的目的就是把"设备输出值"和"标准声压值"对齐。
这样测出来的 dB 值才有可比性和可信度。
14. 什么是量程选择,为什么要高低量程切换?
量程选择本质上是为了同时兼顾:
- 小信号时的分辨率
- 大信号时的不失真
比如高低量程双通道设计:
- 低量程适合较小声压,精度更高
- 高量程适合较大声压,避免过载削顶
如果不做量程切换,可能出现:
- 小信号测不准
- 大信号一来就过载
所以量程切换是为了扩大可测范围。
15. 频率计权和时间计权分别解决什么问题?
- 频率计权 解决"不同频率成分该怎么评价"的问题
- 时间计权 解决"随时间变化的声级该怎么平滑或响应"的问题
前者是频域角度,后者是时间域角度。
两个计权经常组合使用,比如:
- A + Fast
- A + Slow
- C + Peak
16. 倍频程分析是做什么的?
倍频程分析是把声音频谱按标准频带划分,比如:
- 1/1 OCT
- 1/3 OCT
这样可以看到各个频带上的能量分布。
它常用于:
- 噪声频谱分析
- 设备故障定位
- 声学调试
- 环境噪声评价
比单一总声级更能看出"问题主要集中在哪个频段"。
C. 音频编解码与处理链
17. 为什么 PCM 不能直接用于网络传输?
不是"不能",而是不适合直接传。
原因有三点:
-
数据量太大
比如 48kHz、16bit、双声道 PCM,每秒就接近 192KB,更高配置会更大。
-
不带自描述和容错能力
裸 PCM 只有采样值,没有压缩、封装、纠错等机制。
-
网络实时场景更关注码率和延迟
音频编码可以在尽量保证可懂度或音质的前提下,大幅降低带宽占用。
所以工程上更常见的是先把 PCM 编成 AAC、Opus、G711 等,再传输。
18. AAC、Opus、G711 的特点分别是什么?
AAC
- 有损压缩
- 音质和压缩效率比较均衡
- 常见于音乐、视频音频
- 通用性好
Opus
- 低延迟、适合实时通信
- 对语音和音乐都兼顾得比较好
- WebRTC、会议、对讲里很常见
G711
- 结构简单,延迟低
- 码率固定 64kbps
- 压缩效率不高,但实现简单
- 传统语音通信、对讲设备里很常见
一句话:
- AAC 偏通用多媒体
- Opus 偏实时互动
- G711 偏传统语音链路
19. 什么是音频重采样?
重采样是把一种采样率的音频,转换成另一种采样率。
比如:
- 48kHz → 16kHz
- 44.1kHz → 48kHz
常见用途:
- 设备只支持某个采样率
- 算法模块要求固定采样率
- 网络协议或编码器要求固定输入格式
本质上是对信号进行重新插值和滤波,不是简单丢点或补点。
20. 为什么会出现爆音和卡顿?
爆音常见原因
- 播放 underrun
- 采样值突然跳变
- 格式解释错误,比如 16bit/32bit 对不上
- 数据截断、缓冲错位
- 音量突变或溢出削顶
卡顿常见原因
- 线程调度不及时
- 缓冲区设计不合理
- CPU 占用过高
- 网络抖动
- 编解码或 IO 阻塞
面试时最好强调:
爆音更多是数据连续性和幅值异常问题,卡顿更多是供数/取数不平衡问题。
21. AEC、ANS、AGC、VAD 分别是什么?
-
AEC :Acoustic Echo Cancellation,回声消除
解决扬声器播放的声音又被麦克风采回的问题
-
ANS :Automatic Noise Suppression,降噪
压低环境背景噪声
-
AGC :Automatic Gain Control,自动增益控制
让语音幅度保持在较合适范围
-
VAD :Voice Activity Detection,语音活动检测
判断当前有没有人在说话
22. 音频链路中这些算法一般放在哪?
典型实时通话链路中,麦克风采集后的处理顺序通常类似:
text
Mic -> AEC -> ANS -> AGC -> VAD -> 编码 -> 网络发送
但具体顺序会依产品略有不同。
- AEC 通常靠前,因为要先去掉回声
- ANS 和 AGC 常在其后
- VAD 常用于决定是否发包、节省带宽或做状态判断
D. 视频基础
23. RGB 和 YUV 的区别是什么?
RGB
直接表示红绿蓝三个颜色分量。
更适合显示和图形处理。
YUV
把亮度和色度分开:
- Y:亮度
- U/V:色度
YUV 更适合视频压缩,因为人眼对亮度更敏感、对色度没那么敏感,所以可以对色度做降采样。
一句话:
RGB 更适合显示,YUV 更适合视频采集和编码。
24. NV12、NV21、YUV420P 有什么区别?
它们都属于 4:2:0 采样格式,区别主要在色度存放方式。
YUV420P
- Y 平面单独存
- U 平面单独存
- V 平面单独存
- 三个平面分开
NV12
- Y 平面单独存
- UV 交错存放
NV21
- Y 平面单独存
- VU 交错存放
区别本质上是:
平面式还是半平面式,UV 顺序是谁在前。
25. 分辨率、帧率、码率分别表示什么?
分辨率
一帧图像有多少像素,比如 1920×1080。
影响清晰度和数据量。
帧率
每秒多少帧,比如 25fps、30fps。
影响画面流畅度。
码率
单位时间编码后产生多少比特数据,比如 2Mbps、4Mbps。
影响带宽占用和压缩质量。
一句话:
- 分辨率看"细节"
- 帧率看"流畅"
- 码率看"压缩质量和带宽"
26. I 帧、P 帧、B 帧区别是什么?
I 帧
关键帧,完整编码一帧图像,不依赖其他帧。
体积大,但可独立解码。
P 帧
前向预测帧,只记录和前面参考帧的差异。
体积比 I 帧小。
B 帧
双向预测帧,既参考前面帧,也参考后面帧。
压缩率更高,但延迟和复杂度更高。
27. 什么是 GOP?
GOP 是 Group of Pictures,图像组。
它表示一组视频帧的组织结构,比如:
text
I P P P I P P P
GOP 长度通常表示两个关键帧之间的间隔。
影响:
- 随机访问能力
- 压缩效率
- 编码延迟
- 丢包恢复能力
28. H.264 码流由什么组成?
H.264 码流本质上由一个个 NALU 组成。
常见类型包括:
- SPS
- PPS
- SEI
- IDR
- 非 IDR 图像数据
也可以从帧类型角度说:
- I 帧
- P 帧
- B 帧
面试时说:
H.264 码流是由不同类型的 NAL 单元组成的。
29. SPS 和 PPS 是什么?
SPS
Sequence Parameter Set,序列参数集。
描述整个视频序列的重要参数,比如:
- 分辨率
- profile/level
- 参考帧信息等
PPS
Picture Parameter Set,图像参数集。
描述单帧或图像相关的参数。
播放器或解码器通常需要先拿到 SPS/PPS,才能正确解码后续图像。
30. IDR 帧和 I 帧有什么区别?
I 帧是帧内编码帧,不依赖前面帧。
IDR 帧是一种特殊的 I 帧,它还意味着:
- 解码器可以从这里重新开始
- 后面的帧不会再引用 IDR 前面的旧帧
所以:
所有 IDR 帧都是 I 帧,但不是所有 I 帧都是 IDR 帧。
E. 推流与流媒体
31. RTP、RTCP、RTSP、RTMP 分别是什么?
- RTP:实时传输协议,负责真正承载音视频数据包
- RTCP:和 RTP 配套的控制协议,用于统计、同步、质量反馈
- RTSP:控制协议,用于建立、控制媒体会话,比如 play/pause/teardown
- RTMP:实时消息传输协议,常用于直播推流
一句话:
- RTP 传数据
- RTCP 做反馈
- RTSP 做控制
- RTMP 做推流
32. RTP 为什么需要序号和时间戳?
序号
用于:
- 检测丢包
- 检测乱序
- 便于接收端重排
时间戳
用于:
- 表示采样时刻
- 计算播放时间
- 做抖动缓冲
- 做音视频同步
所以 RTP 能做实时媒体传输,序号和时间戳是核心。
33. RTSP 和 RTMP 的主要区别是什么?
RTSP
- 更像"媒体会话控制协议"
- 常和 RTP/RTCP 搭配
- 常见于 IPC、NVR、监控场景
RTMP
- 更像"直播推流协议"
- 基于 TCP
- 常见于直播推流链路
一句话:
RTSP 更偏控制 + RTP 传输,RTMP 更偏直播推流。
34. 为什么直播和点播关注点不同?
直播
更关注:
- 低延迟
- 实时性
- 连续性
点播
更关注:
- 画质
- 拖动定位
- 缓冲稳定性
- 文件完整性
因为直播的数据是"边产边播",点播的数据是"完整文件已经存在"。
35. 为什么 WebRTC 延迟低?
WebRTC 为实时互动设计,低延迟的原因主要有:
- 协议栈专门为实时优化
- 通常基于 UDP
- 缓冲控制更激进
- 支持丢包恢复、抖动控制、拥塞控制
- 编解码、回声消除等都围绕低延迟场景优化
所以它适合视频会议、实时语音通话等场景。
36. 音视频同步一般依赖什么?
主要依赖:
- 时间戳
- 时钟基准
- 缓冲区管理
- 同步策略
通常是让音频和视频都挂到同一个时间轴上,再选择:
- 音频时钟为主
- 视频时钟为主
- 系统时钟为主
很多播放器里常用"音频做主时钟",因为人耳对音频异常更敏感。
37. 推流端和拉流端分别做什么?
推流端
负责:
- 采集音视频
- 编码
- 打包
- 发送到服务器或对端
拉流端
负责:
- 接收流
- 解包
- 解码
- 渲染/播放
简单说:
- 推流端负责"生产和发送"
- 拉流端负责"接收和播放"
38. 为什么会首帧慢?
首帧慢常见原因:
- 设备初始化慢
- 编码器启动慢
- 关键帧间隔太长
- 网络连接建立慢
- 缓冲区攒太多
- 解码器还没拿到 SPS/PPS/IDR
视频场景里,关键帧等待 是很常见原因。
39. 为什么会音画不同步?
常见原因:
- 音频和视频时间戳不一致
- 一路处理延迟明显更大
- 缓冲区堆积不一样
- 编码/解码耗时不同
- 网络抖动不一致
- 同步策略设计不好
一句话:
本质是音频时间轴和视频时间轴没有对齐。
F. 嵌入式工程问题
40. 你的音频缓冲区是怎么设计的?
面试回答可以这样说:
我一般会采用生产者-消费者模型 。
采集线程不断从 ALSA 读取 PCM,写入缓冲队列;处理线程从队列里按顺序取数据做算法或封装;如果还有播放/网络发送,也会进一步拆成独立消费者。
设计时重点考虑:
- 是否 FIFO
- 队列深度多大
- 满了是丢旧帧还是阻塞
- 线程安全
- 是否需要零拷贝或复用内存块
如果结合你的项目,还可以补一句:
以前代码里我用过"只拿最新块"的方式,后来发现会导致丢帧和统计失真,更合理的是严格 FIFO 消费。
41. 为什么实时音频处理中要做生产者/消费者解耦?
因为采集、处理、存盘、播放的速度通常不一致。
如果不解耦:
- 采集线程可能被文件 IO 卡住
- 算法处理慢会拖垮采集
- 一旦阻塞就容易 overrun/underrun
解耦后,每个模块只管自己的节奏,中间靠缓冲区做速率匹配,系统更稳。
42. 如果采集线程比处理线程快,会发生什么?
会发生两种结果之一:
- 缓冲区不断堆积,延迟越来越大
- 缓冲区满了之后开始丢帧或覆盖旧帧
如果设计不当,还可能出现:
- 重复处理同一帧
- 统计结果失真
- 录音文件不连续
所以采集线程比处理线程快时,必须靠:
- 合理队列深度
- 丢帧策略
- 降低处理耗时
- 分线程设计
来平衡。
43. 你项目里最大的稳定性问题是什么?
你可以结合自己的代码回答:
我项目里最大的稳定性问题,不是算法本身,而是实时链路中的缓冲区和异步写文件模型 。
比如:
- 采集线程产出快,处理线程如果只拿最新帧,会丢历史帧
- 异步录音如果共享成员缓存,会出现数据竞争
- ALSA 读块过大,会让时延和恢复都变差
这类问题在功能测试时可能不明显,但在长时间运行和高负载下容易暴露。
44. 你是怎么排查音频采集问题的?
我的排查思路一般是分层看:
-
设备层
用
arecord -l看设备是否存在,确认声卡和设备号 -
参数层
看采样率、位深、通道数是不是设备支持的
-
数据层
把采回来的 PCM 落盘,检查长度、幅值、波形是否正常
-
文件层
如果导出 WAV,就检查头部字段和 data size 是否正确
-
线程层
看有没有 overrun、有没有缓冲区堆积或丢帧
-
性能层
看 CPU 占用、阻塞点、日志时间戳
45. 如果 WAV 文件无法播放,你怎么排查?
我会先分两步:
先看文件头
检查:
- RIFF / WAVE / fmt / data 是否正确
SampleRateChannelsBitsPerSampleByteRateBlockAligndata_size
再看数据本身
确认:
- 文件里有没有真正写入 PCM
- 数据长度是否和头一致
- 字节序是否对
- 实际采样格式和头里写的是否一致
很多时候 WAV 播不了,不是 PCM 没有,而是头写错了。
46. 如果推流延迟高,你从哪些方向分析?
我一般从 5 个方向看:
-
采集端
采集是否有额外缓冲,是否帧率设置过低
-
编码端
编码器是否缓存太多,GOP 是否过大,是否开启 B 帧
-
传输端
网络抖动、重传、带宽不足
-
接收端
播放器缓冲策略是否太保守
-
协议和系统参数
比如 RTSP/RTMP 自身缓冲、队列深度、时间戳策略
一句话:
延迟通常不是单点问题,而是采集、编码、传输、播放各层缓冲叠加出来的。
47. 如果视频有花屏、绿屏、卡顿,你怎么分析?
花屏/绿屏
优先看:
- 解码前码流是否损坏
- SPS/PPS 是否正确
- 分辨率、stride、像素格式是否匹配
- YUV 数据排列有没有错
- 关键帧是否缺失
卡顿
优先看:
- 帧率是否稳定
- 编码速度是否跟得上
- 网络是否丢包/抖动
- 播放端缓冲是否异常
- CPU 是否打满
48. 如何判断是采集问题、编码问题还是传输问题?
我的方法是分段截断定位:
-
先看采集原始帧或原始 PCM 是否正常
如果原始数据就有问题,那就是采集链路问题
-
再看编码输出是否正常
比如本地保存码流或文件,拿播放器/分析工具验证
如果原始帧正常、编码后异常,那就是编码链路问题
-
再看网络传输
抓包、看 RTP 序号、丢包、乱序、时延
如果本地编码正常、网络后异常,那就是传输问题
核心思路是:
分层验证,逐段排除。
49. 多线程下为什么容易丢帧或重复处理?
因为多线程里的问题常出在:
- 生产者和消费者速度不一致
- 队列不是严格 FIFO
- 共享数据没有拷贝或没有加锁
- 事件排队导致"处理的不是当时那块数据"
- 线程间传的是指针,实际数据生命周期已经结束
所以会出现:
- 旧帧被跳过
- 最新帧被处理两次
- 录音写错帧
- 播放拿到悬空数据
这也是你做实时音视频时最容易踩的坑之一。
50. 你项目里最值得优化的一点是什么?
你可以这样答:
如果只选一个点,我觉得最值得优化的是缓冲区和异步数据流模型 。
因为它直接影响:
- 是否丢帧
- 是否重复处理
- 统计结果是否可信
- 录音文件是否连续
- 系统长时间运行是否稳定
算法精度固然重要,但实时音视频系统里,链路稳定性往往先于算法本身 。
如果缓冲区模型不稳,再好的算法也会被错误输入拖垮。
最后给你一个建议
你现在不要只"背答案",而是要把这 50 题分成三类来准备:
第一类:必须能脱口而出
- ALSA 流程
- PCM/WAV
- period/buffer
- underrun/overrun
- I/P/B、GOP、SPS/PPS
- RTP/RTSP/RTMP
- 你的项目链路
第二类:能结合项目讲
- A/C/Z
- Leq/Lpeak
- 校准
- 缓冲区设计
- WAV 导出
- 推流延迟
- 丢帧问题
第三类:知道概念和定位方法即可
- AEC/ANS/AGC/VAD
- WebRTC
- HLS
- 更深的编码细节