流式音频播放延迟(约 200 毫秒)

发布于 2024-12-23 06:51:45 字数 1874 浏览 1 评论 0原文

我有一个播放流式音频数据的应用程序(如聊天客户端)。该工作流程涉及三个简单的步骤:

  1. 首先发送文件头信息(采样率、每个样本的位数和通道数)。
  2. 音频波形输出设备根据上述参数进行初始化。
  3. 音频(pcm)数据被发送并在上述设备上播放。

数据接收代码是本机的(C 代码)。它读取套接字上的数据。然后它调用托管 C# 代码,该代码使用 Naudio 库来初始化设备并播放音频。

现在的问题是,我发现音频播放有一些延迟。我已经检测了其余的代码(特别是:在套接字上传输数据并将其传递回托管代码),这似乎没问题。整个传输过程大约需要 600 微秒,但是在我将缓冲区分配给 Naudio 后,它似乎在一段时间后(大约 200-250 毫秒)开始播放。

这是我处理音频播放部分的 C# 类:

class foo
{
    static  IWavePlayer     s_WaveOut;
    static  WaveFormat      s_WaveOutFormat;
    static  BufferedWaveProvider    s_WaveProvider;
    static  byte[]          s_Samples       = new byte[10000];

    // called from native code to init deivce with specified sample rate and num of channels
    private static void DeviceInit(int rate, int bits, int channels)
    {
        s_WaveOut   = new WaveOut(WaveCallbackInfo.FunctionCallback());
        s_WaveOutFormat = new WaveFormat(rate, bits, channels);
        s_WaveProvider  = new BufferedWaveProvider(s_WaveOutFormat);

        s_WaveProvider.DiscardOnBufferOverflow      = true;
        s_WaveProvider.BufferLength         = 5 * 1024 * 1024;

        s_WaveOut.Init(s_WaveProvider);
        s_WaveOut.Play();
    }

    // called from native 'C' code upon receiving audio packates
    private unsafe static void PlayDataCallback(
        IntPtr buff,
        Int32 size) 
    {
        Marshal.Copy(buff, s_Samples, 0, size);
        s_WaveProvider.AddSamples(s_Samples, 0, size);
    }
}

任何人都知道可能导致延迟的原因,或者我是否以某种错误的方式使用它(Naudio)。

我尝试使用相同的 Naudio 库来播放 wav 文件,这似乎工作完美,只有当我自己初始化设备后添加样本时,问题才会出现。

[更新] 如果我将 s_WaveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()); 更改为 s_WaveOut = new DirectSound();,性能好多了。如果在此之后,我修改 Naudio 源以将播放线程优先级设置为“最高”(默认为“正常”),则性能会进一步提高,但正如预期的那样,该进程开始消耗大量资源。

谢谢你,

维克拉姆

I have an application which plays the streamed audio data (like a chat client). The workflow involves three simple steps:

  1. The file header info (sample rate, bits per sample and num of channels) is sent first.
  2. Audio waveout device is initialized based on the above parameters.
  3. Audio (pcm) data is sent and is played on the above device.

The data receiving code is native (C code). and it reads data on a socket. Then it calls the managed C# code, which uses Naudio library to initialize device and play audio.

Now the problem is that, I am seeing some delay in audio playback. I have already instrumented the rest of my code (specifically: transferring data on socket and passing it back to managed code) and that seems to be okay. The whole transfer process is taking around 600 micro seconds, but after I assign the buffer to Naudio, it seems to start playing it after some time (around 200-250 milliseconds).

Here is my C# class that handles the audio playing part:

class foo
{
    static  IWavePlayer     s_WaveOut;
    static  WaveFormat      s_WaveOutFormat;
    static  BufferedWaveProvider    s_WaveProvider;
    static  byte[]          s_Samples       = new byte[10000];

    // called from native code to init deivce with specified sample rate and num of channels
    private static void DeviceInit(int rate, int bits, int channels)
    {
        s_WaveOut   = new WaveOut(WaveCallbackInfo.FunctionCallback());
        s_WaveOutFormat = new WaveFormat(rate, bits, channels);
        s_WaveProvider  = new BufferedWaveProvider(s_WaveOutFormat);

        s_WaveProvider.DiscardOnBufferOverflow      = true;
        s_WaveProvider.BufferLength         = 5 * 1024 * 1024;

        s_WaveOut.Init(s_WaveProvider);
        s_WaveOut.Play();
    }

    // called from native 'C' code upon receiving audio packates
    private unsafe static void PlayDataCallback(
        IntPtr buff,
        Int32 size) 
    {
        Marshal.Copy(buff, s_Samples, 0, size);
        s_WaveProvider.AddSamples(s_Samples, 0, size);
    }
}

Anyone has any idea on what might be causing the delay or am I using it (Naudio) in some wrong way.

I tried the same Naudio library to play a wav file and that seems to work perfect, the problem is coming only when I am adding samples after initialing the device myself.

[update] If I change s_WaveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()); to s_WaveOut = new DirectSound();, the performance is much better. If after this, I modify the Naudio source to set playback thread priority to Highest (default is Normal), the performace improves further, but as expected, the process starts consuming high resources.

Thank you,

Vikram

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

土豪我们做朋友吧 2024-12-30 06:51:45

我还使用 NAudio 开发音频流应用程序。我们还存在延迟问题。达到300毫秒。

捕获每秒发生 10 次(每 100 毫秒一次)。

使用 Vikram.exe 的建议来使用 DirectSoundOut 而不是 WaveOut 有一点帮助。延迟减少了 50 或 100 毫秒,但前提是我将所需延迟设置为 50 毫秒。

new DirectSoundOut(guid, 50);

另一项技巧已将延迟降低了 100 或 200 毫秒。我们检查是否有声音正在播放,如果有则跳过新帧。

if (s_WaveProvider.BufferedDuration <= 100)
    s_WaveProvider.AddSamples(s_Samples, 0, size);

在声音流畅度方面还有一些工作要做,但现在基本上已经没有延迟了。

I also develop audio streaming application using NAudio. We also have latency issue. It reaches 300 ms.

The capture happens 10 times per second (once a 100 ms).

Using the advice of Vikram.exe to use DirectSoundOut instead of WaveOut helped a bit. The latency decreased by 50 or 100 ms, but only if I set Desired Latency to 50 ms.

new DirectSoundOut(guid, 50);

One more trick has lowered the latency by 100 or 200 ms. We check if there is a sound being played and skip new frames if it is.

if (s_WaveProvider.BufferedDuration <= 100)
    s_WaveProvider.AddSamples(s_Samples, 0, size);

There is still some work to be done in regards of sound smoothness, but generally we have no latency now.

得不到的就毁灭 2024-12-30 06:51:45

音频播放总是会产生延迟。对于 WaveOut,您可以指定缓冲区的数量和总体所需的延迟。您还可以为其他驱动程序模型指定缓冲区大小。对于大多数播放场景,两个 100 毫秒的缓冲区是理想的选择,因为它具有合理的响应能力,并且除非在极端负载下,否则不会卡顿。但是,如果需要,您可以降低,但要冒无法及时填充下一个缓冲区的风险。不要期望使用 NAudio 在 DAW 中获得那么低的延迟(例如 5 毫秒),它没有经过高度优化,并且由于垃圾收集器的原因,.NET 框架无论如何都不是特别适合此类应用程序。

以下是设置 WaveOut 输出延迟的示例:

var waveOut = new WaveOut();
waveout.DesiredLatency = 50; // 50ms latency

There is always latency introduced with audio playback. For WaveOut, you can specify the number of buffers and the overall desired latency. You can also specify buffer sizes for the other driver models too. For most playback scenarios, two buffers of 100ms each is ideal as it is reasonably responsive and will not stutter except under extreme load. However, you can go lower if you need to, but run the risk of it not being able to fill the next buffer in time. Don't expect as low latencies as you could get in a DAW (e.g. 5ms) with NAudio, it is not so highly optimised, and the .NET framework is not particularly well suited for this kind of application anyway due to the garbage collector.

Here's an example of setting the output latency for WaveOut:

var waveOut = new WaveOut();
waveout.DesiredLatency = 50; // 50ms latency
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文