2

我在 C++ 中有一个跨平台项目,我在其中实时混合音频。我有几个独立的轨道作为输入,我从磁盘上的单独文件中读取。然后我混合这些,应用一些处理,并用生成的音频吐出一个缓冲区。我遇到的问题是磁盘 IO 速度。对于我正在执行的当前测试,我有大约 10 个同时从磁盘读取的磁道。每个音轨都是原始 PCM、48000 HZ 16 位立体声。这意味着需要尽快读取大量数据。我已经通过 Boost 尝试了简单的 fread 调用和内存映射文件,但问题是一样的。首次打开文件时,通常会导致音频中断(可能是在文件被操作系统读入缓存时)。之后,一切运行顺利,没有出现故障。目前我在常见情况下每个文件使用一个线程,有时每个线程两个文件。通常,当我每个线程有两个文件时,就会发生流的停止/中断。请注意,我事先并不知道需要播放哪些输入文件,因为这是由用户控制的。所以我的问题是如何以这样的方式阅读这些初始块,这样我就不会陷入停滞/分手。此外,当加载新文件时,读取不一定要从头开始。所以我的问题是如何以这样的方式阅读这些初始块,这样我就不会陷入停滞/分手。此外,当加载新文件时,读取不一定要从头开始。所以我的问题是如何以这样的方式阅读这些初始块,这样我就不会陷入停滞/分手。此外,当加载新文件时,读取不一定要从头开始。

我有几个想法:

  1. 我们可以通过在启动时读取所有文件但忽略数据来将文件预取到缓存中吗?我无法将其全部存储在内存中。但是依赖操作系统读取现金的内部行为似乎很糟糕,特别是因为这是跨平台的。

  2. 我们是否可以使用 Ogg Vorbis 等格式进行压缩,将压缩数据完全加载到内存中,然后即时解码?我在想解码 10 个或更多 Vorbis 流可能太占用 CPU,但我还没有基准测试。至少通过这种方式,我们将其从 I/O 密集型任务转变为 CPU 密集型任务。

  3. 我们可以做任何其他聪明的缓冲方法来使大读取更均匀分布吗?我对如何做到这一点知之甚少。

我被困在这一点上,如果有任何可能提高吞吐量的建议,我将不胜感激。

4

2 回答 2

1

尝试使用事件处理进行文件加载。

这是您打开一堆文件描述符并让操作系统在数据可用时通知您的程序的地方。

使用“select”( http://linux.die.net/man/2/select )执行此操作的最广泛可用的 api ,但是有更好的方法(poll、epoll、kqueue)。这些并非随处可见。

有一些库可以为你抽象出来( libev 和 libevent )。

所以你这样做的方式是,一个线程打开你需要的所有文件并在它们上设置一个“观察者”。当数据可用时,观察者触发,并调用回调。

优点是您没有大量线程等待和休眠检查所有打开的文件描述符。如果这不起作用,那么很可能您已经过度饱和了硬件的 io 带宽——在这种情况下,您只需要等待。如果是这种情况,那么您需要做一些缓冲以避免口吃。

于 2013-04-12T20:57:22.607 回答
0

根据经验,您需要在单独的线程中执行文件 IO 操作以进行实时操作。当用户想要混合第二个音频文件时,您可以打开一个新线程并读取第二个音频文件的前 N ​​个字节并将读取的数据返回到主线程。这也会导致延迟,但不会中断音频流。

于 2013-04-12T18:09:37.100 回答