PCM 到扬声器:时钟、缓冲与故障证据链¶
1. 场景与格式契约¶
本页为可计算的教学案例,不是某款芯片的实测报告。设播放 48 kHz、双声道、24-bit 有效 PCM,内存使用每 sample 4 B 的容器,串行口使用两个 32-bit slot;period=240 frame,ring=4 period。
先明确有符号表示、端序、有效位对齐、交织方式,以及控制器与 Codec 的时钟提供/消费角色。容器的 32-bit 不能自动推导其有效位在高 24 位还是低 24 位;需要匹配 PCM 格式与硬件配置。
2. 五个独立预算¶
PCM 内存速率 = 48000 * 2 * 4 = 384000 B/s
I2S BCLK = 48000 * 2 * 32 = 3072000 Hz
period 时间 = 240 / 48000 = 5 ms
period 字节 = 240 * 2 * 4 = 1920 B
ring 容量 = 4 * 1920 = 7680 B = 20 ms 的 PCM
有效音频位率为 2.304 Mbit/s,但串行时钟为 3.072 MHz;DMA 的内存速率也不等于压缩 AAC/Opus 的码率。MCLK 与 BCLK 不同,能否使用 256fs 等比例取决于器件,不在本页设成通用要求。
每 period 通知一次对应理想通知频率 200 次/s,不能保证硬件 IRQ 计数严格相同:某些实现有合并、轮询或不同的通知机制。20 ms 是满 ring 的容量,不表示当前排队时延固定 20 ms。
3. 把供数 deadline 与算法块分开¶
如果某时刻待播放队列只有 480 frame,则静态供数裕量约 10 ms,尚需考虑具体硬件 FIFO 和指针语义。线程长时间未运行、解码阻塞、锁竞争或总线访问延迟都可能耗尽这段裕量。
如果算法每次输入 480 frame,单是攒齐一个块就可能引入等待;缩小 DMA period 到 120 frame 不会自动把算法块变成 120 frame。端到端预算必须分别列出网络缓冲、解码、算法成块、PCM 排队、数字滤波和声学传播,避免重复计同一段时间。
4. ALSA 状态和数据所有权¶
打开设备后进行参数协商,prepare 后预填充并启动。写入返回值以 frame 为单位,必须处理短写、-EAGAIN、XRUN 和设备断开。不能把 snd_pcm_writei() 返回值直接当字节数移动指针。
在 DMA 消费完成之前,不得覆盖该段播放数据;mmap 方式也需遵循 begin/commit 协议。XRUN 恢复后要重新确认数据和时间戳基线;不能认为一次 recover 自动补回丢掉的音频。API 语义参考 ALSA PCM interface。
播放停止时区分 drain(按约定处理剩余数据)与 drop(立即停止)。底层驱动需要停止新工作、同步 DMA 与回调,再释放 buffer;软件通知结束和 DMA 已完全静止不是同一个条件。
5. 无声与断音的分层排查¶
| 观察点 | 要确认的事实 | 不能据此直接得出的结论 |
|---|---|---|
| 解码输出 | PCM 非零、范围/声道/采样率正确 | 有 PCM 不说明已经发到总线 |
| 软件 ring | 指针随时间推进,水位有足够余量 | hw_ptr 推进不证明扬声器有声 |
| 串行口 | BCLK/WS 比例、相位、slot 和数据正确 | 逻辑波形正确不证明模拟输出正常 |
| Codec 路由 | DAI 参数、mute、DAC 与路径有效 | I2C 可访问不代表音频时钟锁定 |
| PA/输出 | 供电、使能、负载与输出波形 | 使能电平正确不代表没有削顶 |
DAPM 根据音频路径与活动流管理电源,路由图不完整可能导致所需部件未上电。对照 DAPM 文档,确认软件图与板级连接一致,而不是仅靠强制所有部件常开掩盖问题。
6. 时钟漂移不是网络抖动¶
假设生产与消费时钟相对频偏为 100 ppm,48 kHz 下水位变化约 48000*100/1000000=4.8 frame/s。若可用安全余量只有 480 frame,理想匀速漂移约 100 s 就会耗尽,期间网络平均吞吐可以完全正常。
扩大 buffer 只延后失步。长期要根据系统主时钟策略调整播放速率或 ASRC 比率,并对控制量限幅和滤波。输入瞬时到达抖动使用 jitter buffer 吸收;不能把每次包到达间隔变化都当成采样时钟偏差。
7. 可复现与安全要求¶
第一步使用软件生成音频和离线模型,不自动打开真实声卡。实板测试从低电平开始,先确认 mute/PA 顺序、耳机与扬声器负载;示波器接地方式应适合待测电路,不能将桥接 Class-D 输出任意一端短接到保护地。
记录设备/内核/驱动版本、格式、period/buffer、CPU 负载、时钟源和首次异常时间。使用同一单调时钟记录软件事件;示波器与软件时钟不同源时需明确对齐方法。报告 XRUN 次数、最长供数间隙、队列水位和输出连续性,不只写“听起来正常”。
本案例的数值由 CPU 预算测试 验证,可在仓库根目录运行 python3 -B Audio/Labs/test_audio_budget.py。这些测试证明算术与假设一致,不证明实际设备达到相同指标。