Delay (approx 200 ms) in streamed audio playback

Vikram.exe picture Vikram.exe · Dec 28, 2011 · Viewed 7.1k times · Source

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

Answer

Vasyl Boroviak picture Vasyl Boroviak · Sep 21, 2012

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.