NAudio - 通过RTP实时向外流式传输音频

时间:2015-06-25 16:07:04

标签: c# streaming audio-streaming naudio

我正在使用NAudio来满足我的音频需求,但我遇到了一个棘手的问题。我有一个可以接收RTP音频的远程设备。我想将音频文件流式传输到该设备(在u-law或类似的编码+ RTP包装之后)。但是,似乎没有一种机制来维护RTP数据包的传出时序。

例如,WaveOut播放器"管理"通过简单地响应来自底层声音/ directx层的请求来进行定时。通过这种方式,时间实际上由声音驱动程序使用" pull"方法

我正在寻找的是一个可以提供正确"拉动"在(例如)IWaveProvider(或类似)上计时,以便我可以接收每个数据包,RTP-ify,然后通过网络发送。

所以,这是核心代码:

IPEndPoint target = new IPEndPoint(addr, port);
Socket sender = new Socket( AddressFamily.InterNetwork,
                            SocketType.Dgram,
                            ProtocolType.Udp );

IWaveProvider provider = new AudioFileReader(filename);
MuLawChatCodec codec = new MuLawChatCodec();  // <-- from chat example
int alignment = provider.BlockAlign * 32;  // <-- arbitrary
byte [] buffer = new byte [alignment];

try
{
    int numbytes;
    while( (numbytes = provider.Read(buffer, 0, alignment)) != 0 )
    {
        byte [] encoded = m_Codec.Encode(buffer, 0, numbytes);
        m_Sender.SendTo(buffer, numbytes, SocketFlags.None, target);
    }
}
catch( Exception )
{
    // We just assume that any exception is an exit signal.
}

发生的事情是while循环只是抓住&#34;音频&#34;尽可能快地将其吹出UDP端口。这不适用于RTP,因为我们需要保持适当的输出时序。

作为测试,我尝试使用NotifyingSampleProvider的WaveOut,将每个L / R对馈送到编码器/ RTP-ifier /发送器,它似乎工作正常。然而,音频播放本地扬声器的副作用(通过WaveOut)对于我正在处理的应用来说是不可接受的(例如,我们可能希望同时将多个不同的文件流式传输到不同的设备)。我们也可能正在使用音频硬件(例如)同时进行软电话转换。基本上,我们并不想在此实现中实际使用本地音频硬件。

那么,是否有人知道(或编写)可以为发送方提供适当时机的组件?能够以适当的速率获取音频的东西,以便我可以提供编码器/发送器链吗?

2 个答案:

答案 0 :(得分:1)

如果有人有兴趣,我就让它上班了。我不得不添加一些组件,并将时间缩短到非常精细的水平。

添加了:

  • 现在使用 m2 <- cbind(which(m1!=0, arr.ind=TRUE), value= m1[m1!=0]) m2[order(m2[,'value']),] 。我使用它是因为它为您阅读的每个帧提供时序信息。
  • 可配置'缓冲'(缓冲帧时间,而不是实际音频)
  • 使用NAudio.Wave.Mp3FileReaderSystem.Diagnostics.Stopwatch
  • 更准确地管理时间安排

这是代码的精简(单线程)版本,没有尝试/捕获等。实际的东西使用了一个播放器线程和一些其他同步机制,让你通过杀死套接字“取消”播放。

Socket.Poll

答案 1 :(得分:0)

基本上,您需要生成一个时钟来驱动样品交付。 AudioFileReader继承自WaveStream,它通过CurrentTime(通过WaveFormat.AverageBytesPerSecond计算)提供样本的当前时间。您应该可以使用它来为音频数据包加时间戳。

此外,根据您的项目需求,您可能需要查看StreamCoder的MediaSuite.NET产品。我过去曾用它来做类似的事情,它为这类事情抽象了大部分传输层复杂性。