简体   繁体   English

如何使用 NAudio 从 UDP 数据包播放音频 stream?

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

I'm receiving data locally from Voicemeeter, which uses VBAN protocol to send A stream of bytes.我从 Voicemeeter 本地接收数据,它使用 VBAN 协议发送字节的 stream。

I'm trying to use NAudio to decode the bytes and play to audio using WaveOutEvent.我正在尝试使用 NAudio 解码字节并使用 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.我的实现与 NAudioDemo 中的 The NetworkChatDemo 几乎相同,查看此链接以了解有关 NAudio 的更多信息,它是一个很棒的音频库,非常感谢 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.首先,我无法将 BufferDuration 设置为无限值,因为它是实时的 stream。
  • Second, I don't hear anything, but noise.其次,我什么都听不到,只有噪音。

How to set the BufferDuration to be infinite?如何将 BufferDuration 设置为无限?
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.更新:我能够通过将 bufferPorivider 的 DiscardOnBufferOverflow 的值设置为 true 来解决第一个问题。

About the noise issue, I've reached to the solution from this question , Mark Heath mentioned关于噪音问题,我已经从这个问题中找到了解决方案,Mark Heath 提到

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:所以,在将样本添加到 BufferProvider 时,我将 offset 的值更改为等于 28,这会导致异常:

  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?如何解决此异常?

I've resolved the exception by using the Skip function to trim the first 28 bytes from the received packets:我已经通过使用 Skip function 从收到的数据包中修剪前 28 个字节来解决异常:

 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.另外,我已经回答了我的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM