C# 流式音频播放中的延迟(约200毫秒)

C# 流式音频播放中的延迟(约200毫秒),c#,optimization,instrumentation,naudio,C#,Optimization,Instrumentation,Naudio,我有一个播放流式音频数据的应用程序(如聊天客户端)。工作流程包括三个简单步骤: 首先发送文件头信息(采样率、每采样位数和通道数) 音频waveout设备根据上述参数进行初始化 音频(pcm)数据在上述设备上发送和播放 数据接收代码是本机代码(C代码)。它读取套接字上的数据。然后调用托管C#代码,该代码使用Naudio库初始化设备并播放音频 现在的问题是,我看到一些音频播放延迟。我已经对我的代码的其余部分进行了检测(特别是:在套接字上传输数据并将其传递回托管代码),这似乎还可以。整个传输过程大约需

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

  • 首先发送文件头信息(采样率、每采样位数和通道数)
  • 音频waveout设备根据上述参数进行初始化
  • 音频(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源以将播放线程优先级设置为最高(默认为正常),则性能会进一步提高,但正如预期的那样,进程开始消耗大量资源

    谢谢,


    Vikram

    音频播放总是会引入延迟。对于WaveOut,您可以指定缓冲区的数量和所需的总延迟。您还可以为其他驱动程序型号指定缓冲区大小。对于大多数播放场景,两个100毫秒的缓冲区都是理想的,因为它们响应合理,并且除非在极端负载下,否则不会结巴。然而,如果需要的话,你可以降低价格,但要冒着无法及时填满下一个缓冲区的风险。不要期望NAudio在DAW(例如5毫秒)中具有低延迟,它没有得到高度优化,而且由于垃圾收集器的存在,.NET framework并不特别适合这种应用程序

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

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

    我还使用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);
    

    if(s_WaveProvider.BufferedDuration我认为音频子系统中的缓冲增加了延迟。这可能纯粹是因为声音连续性的原因(设备必须有足够的预缓冲数据,否则它将播放明显的间隙和砰砰声)@ALex,我也这么想,但是当我播放视频文件时,没有延迟,音频和视频是同步的。另外,如果我玩游戏,不同动作的声音会立即出现。可能是我缺少一些配置吗?说网络框架不适合这种工作有点苛刻。很有可能编写一个真正的游戏-在.NET中的时间应用程序(初始化后)根本不会产生任何垃圾。问题是.NET鼓励一种方便但低效的编码方式,这与实时性能关键型应用程序不符,而且大多数.NET编码人员从不需要考虑低水平的性能(相反,C++程序员确实被迫采用这种心理,但NETTER可以保持幸福的无知:@MattDavey,我曾尝试以这样一种方式编写NAudio,即GC只需很少的工作,例如预先创建缓冲区并重新使用它们,甚至在EventArgs中也可以这样做,但是如果你的应用程序有GUI,你也可以接受GC会在某个时候启动,并且当它进行音频播放时,甚至在退出时也可能出现故障e适度延迟。啊,是的,这是一个正确的观点,Winforms尤其会产生大量垃圾。但你不应该为此责备GC:)
    waveout.DesiredLatency=50;
    代码在大多数系统上都不能正常工作。声音嘎嘎作响。有时甚至100毫秒也不够大。