How do I play an audio stream from UDP packets using NAudio?

1

I'm receiving data locally from Voicemeeter, which uses VBAN protocol to send A stream of bytes.

I'm trying to use NAudio to decode the bytes and play to audio using WaveOutEvent. My implementation is almost the same as The NetworkChatDemo from the NAudioDemo, Checkout this link to know more about NAudio, it's a great audio library, huge thanks to Mark Heath.

My implementation:

private readonly ILogger<AudioController> _logger;
        private NetworkAudioPlayer player;
        private readonly INetworkChatCodec _codec;


        public AudioController(ILogger<AudioController> logger)
        {
            _logger = logger;
            _codec = new ALawChatCodec();
        }

        [HttpGet]
        [Route("start")]
        public IActionResult Start()
        {

            var receiver = new UdpAudioReceiver(6980);
            player = new NetworkAudioPlayer(_codec, receiver);

            return Ok("Hello");
        }

Network audio player:

private readonly INetworkChatCodec codec;
    private readonly IAudioReceiver receiver;
    private readonly IWavePlayer waveOut;
    private readonly BufferedWaveProvider waveProvider;

    public NetworkAudioPlayer(INetworkChatCodec codec, IAudioReceiver receiver)
    {
        this.codec = codec;
        this.receiver = receiver;
        receiver.OnReceived(OnDataReceived);

        waveOut = new WaveOutEvent();
        waveProvider = new BufferedWaveProvider(codec.RecordFormat);
        waveProvider.BufferDuration = TimeSpan.FromSeconds(300);
        waveOut.Init(waveProvider);
        waveOut.Play();
    }

    void OnDataReceived(byte[] compressed)
    {
        byte[] decoded = codec.Decode(compressed, 0, compressed.Length);
        waveProvider.AddSamples(decoded, 0, decoded.Length);
    }

    public void Dispose()
    {
        receiver?.Dispose();
        waveOut?.Dispose();
    }

I got two issues in this implementation:

  • First, I'm unable to set the BufferDuration to an infinite value, since it's a live stream.
  • Second, I don't hear anything, but noise.

How to set the BufferDuration to be infinite?
How to play the Audio correctly?

Update: I was able to solve the first issue, by setting the value of DiscardOnBufferOverflow of the bufferPorivider to be equal to true.

About the noise issue, I've reached to the solution from this question, Mark Heath mentioned

Also, are you sure that there is no surrounding metadata in the network packets being received? If so that needs to be stripped out or it will result in noise.

So, I've changed the value of offset when adding samples to BufferProvider to be equal to 28, which causes an exception:

  void OnDataReceived(byte[] compressed)
        {
            var l = compressed.Length;
            waveProvider.AddSamples(compressed, 28, compressed.Length);
        }

Stack trace:

    > 
> System.ArgumentException
  HResult=0x80070057
  Message=Source array was not long enough. Check the source index, length, and the array's lower bounds. (Parameter 'sourceArray')
  Source=System.Private.CoreLib
  StackTrace:
   at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
   at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length)
   at NAudio.Utils.CircularBuffer.Write(Byte[] data, Int32 offset, Int32 count)
   at NAudio.Wave.BufferedWaveProvider.AddSamples(Byte[] buffer, Int32 offset, Int32 count)
   at POC.AudioStreaming.AudioManagers.NetworkAudioPlayer.OnDataReceived(Byte[] compressed) in C:\dev\POC.AudioStreaming\POC.AudioStreaming\AudioManagers\NetworkAudioPlayer.cs:line 41
   at POC.AudioStreaming.AudioManagers.UdpAudioReceiver.ListenerThread(Object state) in C:\dev\POC.AudioStreaming\POC.AudioStreaming\AudioManagers\UdpAudioReceiver.cs:line 38
   at System.Threading.QueueUserWorkItemCallback.<>c.<.cctor>b__6_0(QueueUserWorkItemCallback quwi)
   at System.Threading.ExecutionContext.RunForThreadPoolUnsafe[TState](ExecutionContext executionContext, Action`1 callback, TState& state)
   at System.Threading.QueueUserWorkItemCallback.Execute()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

How can I resolve this exception?

c#
.net
naudio
asked on Stack Overflow May 26, 2020 by Yousef Alaqra • edited May 27, 2020 by Yousef Alaqra

1 Answer

0

I've resolved the exception by using the Skip function to trim the first 28 bytes from the received packets:

 void OnDataReceived(byte[] compressed)
    {
        byte[] buffer = compressed.Skip(28).ToArray();
        waveProvider.AddSamples(buffer, 0, buffer.Length);
    }

By solving the exception I was able to hear the audio very well. Also, I've answered my question.

answered on Stack Overflow May 27, 2020 by Yousef Alaqra

User contributions licensed under CC BY-SA 3.0