Skip to the content.

合并音频时的静音写入

AudioProcessor 在每个输入音频后写入一段静音,WAV 和 MP3 路径原本各有一个写入方法。两者都会先按整段静音的长度创建零数组,再调用一次写入器。默认格式为 44.1 kHz、16 bit、双声道,1 秒静音就会创建 176,400 字节数组;处理 100 段会创建 100 个这样的临时数组。输出最终仍要保存或编码,问题在于这份额外的工作内存随时长增长。

现在两个路径共用 WriteSilence:每次独立计算总字节数,用类私有的 4 KB 零数组反复写入,最后一次只写剩余字节。WAV 仍写给 WaveFileWriter;MP3 仍把 PCM 零字节交给 LameMP3FileWriter 编码。保留原来的浮点乘法、按样本截断和每个输入之后都写静音的时序。共享数组只作为写入器的输入,不交给音频读取器或调用方,也不共享输出流的游标。

测量

在 Windows x64、.NET 10.0.12、Release 下,用同一份临时探针比较修改前后的生产方法:预先建立 WaveFileWriter 和容量为 18 MB 的 MemoryStream,预热一次,然后连续写入 100 段各 1 秒的默认格式静音。探针通过反射调用内部方法以保持两次测量入口一致;GC.GetAllocatedBytesForCurrentThread 的数字包含探针调用开销,不包含输出流初始化及预留容量。

100 段静音 修改前 修改后
该线程分配 17,657,728 B 9,456 B

修改后的回归测试还用不保存输出的记录流直接调用方法。预热后写 100 段,测得工作路径分配为 0 B,输出总长度为 17,640,000 B。这些是局部写入路径的数据,不代表完整音频合并的总分配或吞吐量。

行为和取舍

分块会增加 Write 调用次数,因此没有依据上述分配数据推断耗时也会下降。测试覆盖零时长、极短与分数秒、整块及尾块、不同位深和声道、长静音、并发输出、WAV 中的静音位置、MP3 编码结果、写入失败及不可表示的长度。字节数计算改用 checked,超出 int 可表示范围时在写入前抛出异常,避免溢出后少写。

4 KB 数组在类生命周期内常驻。后续若完整音频合并的测量显示分块调用影响吞吐,可在保持有界工作内存的前提下比较其他块大小;当前没有这项端到端数据。