使用哪个线程进行音频解码?
在处理音频播放时,我习惯以下模式:
- 一个磁盘(或网络)线程从磁盘(或网络)读取数据并填充环形缓冲区;
- 一个音频线程从环形缓冲区读取数据,可能执行 DSP,然后写入至音频硬件 (拉或推 API)
这工作正常,并且在处理 WAV 文件时没有问题。
现在,如果源数据以压缩格式(如 Vorbis 或 MP3)编码,则解码需要一些时间。
在磁盘/网络线程中执行解码似乎很常见。
但这不是错误的设计吗?当磁盘或网络访问阻塞时,一些 CPU 时间可用于解码,但如果解码发生在同一线程中,则会被浪费。
在我看来,如果网络变慢,那么如果解码顺序发生,缓冲区欠载的风险就会更高。
那么,解码不应该在音频线程中进行吗?
在我的上下文中,我宁愿避免添加专用的解码线程。它是针对移动平台的,而 SMP 目前还很少见。但请告诉您专用的解码线程是否真的对您有意义。
When working with audio playback I am used to the following pattern:
- one disk (or network) thread which reads data from disk (or the network) and fills a ringbuffer
- one audio thread which reads data from the ringbuffer, possibly performs DSP, and writes to audio hardware
(pull or push API)
This works fine, and there's no issue when working with, say, a WAV file.
Now, if the source data is encoded in a compressed format, like Vorbis or MP3, decoding takes some time.
And it seems like it's quite common to perform decoding in the disk/network thread.
But isn't this wrong design? While disk or network access blocks, some CPU time is available for decoding, but is wasted if decoding happens in the same thread.
It seems to me that if the networks becomes slow, then risks of buffer underruns are higher if decoding happens sequentially.
So, shouldn't decoding be performed in the audio thread?
In my context, I would prefer to avoid adding a dedicated decoding thread. It's for mobile platforms and SMP is pretty rare right now. But please tell if a dedicated decoding thread really makes sense to you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
音频线程可用于流畅地播放音频比网络线程保持完美大小的缓冲区更重要。如果您只使用两个线程,那么解码应该在网络线程上完成。如果您要在播放线程上进行解码,那么您可能需要将更多音频推送到硬件,但线程正忙于解码。如果您维护已解码音频的缓冲区,那就更好了。
理想情况下,您将使用三个线程。一种用于读取网络,一种用于解码,一种用于播放。在我们处理音频/视频捕获、记录和流媒体的应用程序中,每个流有八个线程(自从我们最近添加了新功能以来,最近从六个线程增加到了)。每个线程拥有自己的功能要容易得多,然后它可以根据传入/传出缓冲区的性能适当地衡量其性能。这也有利于分析和优化。
It's more important for the audio thread to be available for playing audio smoothly than for the network thread to maintain a perfect size buffer. If you're only using two threads, then the decoding should be done on the network thread. If you were to decode on the playing thread then it's possible the time could come that you need to push more audio out to the hardware but the thread is busy decoding. It's better if you maintain a buffer of already decoded audio.
Ideally you would use three threads. One for reading the network, one for decoding, and one for playing. In our application that handles audio/video capture, recording, and streaming we have eight threads per stream (recently increased from six threads since we added new functionality recently). It's much easier for each thread to have it's own functionality and then it can appropriately measure its performance against those of it's incoming/outgoing buffers. This also benefits profiling and optimization.
如果您的设备只有一个 CPU,则所有线程都共享它。操作系统线程交换通常非常高效(您不会因交换而损失任何有意义的 CPU 能力)。因此,如果可以简化逻辑,您应该创建更多线程。
就您而言,有一条管道。管道的每个阶段使用不同的线程是一个很好的模式。正如您所注意到的,替代方案涉及复杂的逻辑、同步、事件、中断或其他任何内容。有时根本没有好的选择。
因此,我的建议是 - 创建一个专用的音频解码线程。
如果您拥有多个 CPU,您甚至可以通过为每个管道步骤使用一个线程来获得更高的效率。
If your device has a single CPU, all threads are sharing it. OS Thread swapping is usually very efficient (you won't lose any meaningfull CPU power for the swapping). Therefore, you should create more threads if it will simplify your logic.
In your case, there is a pipeline. Different thread for each stage of the pipeline is a good pattern. The alternative, as you notice, involves complex logic, synchronizations, events, interrupts, or whatever. Sometimes there is no good alternatives at all.
Hence, my suggestion - create a dedicated thread for the audio decoding.
If you'll have more than a single CPU, you'll even gain more efficiency by using one thread for each pipeline step.