c# - NAudio 缓冲区已满异常
c# - NAudio buffer full exception
我试着做一个软电话。它通过声音,但 5 秒后我得到 "Buffer Full" 异常。
这是我的发送代码:
public class Media
{
static WaveInEvent s_WaveIn = new WaveInEvent();
Action<byte[]> waveHandler;
public void Capture(Action<byte[]> toRtp)
{
s_WaveIn = new WaveInEvent();
s_WaveIn.WaveFormat = new WaveFormat(8000, 1);//44100, 2);
waveHandler = toRtp;
s_WaveIn.DataAvailable += new EventHandler<WaveInEventArgs>(SendCaptureSamples);
s_WaveIn.StartRecording();
}
void SendCaptureSamples(object sender, WaveInEventArgs e)
{
waveHandler(e.Buffer);
}
public void Stop()
{
s_WaveIn.StopRecording();
}
}
ToRtp 是
private void ToRtp(byte[] buffer)
{
myRTP.SequenceNumber++;
Sender.SendResponse(myRTP.MakePacket(alaw.Encode(buffer,0,buffer.Length)), RTPClient, rtpPort);//ToRTPData(buffer, 8000, 1), myUdpClient);
}
接收:
class Client
{
WaveFormat pcmFormat = new WaveFormat(8000, 16, 1);
WaveFormat alawFormat = WaveFormat.CreateALawFormat(8000, 1);
WaveOut waveOut;
BufferedWaveProvider waveProvider;
ALawChatCodec alaw = new ALawChatCodec();
public Client(IHandlerFactory handlerFactory, IPAddress hostAddress, int portNumber)
{
waveOut = new WaveOut();
waveProvider = new BufferedWaveProvider(pcmFormat);
waveOut.Init(waveProvider);
waveOut.Play();
}
private void HandleIncomingRTPRequest(IAsyncResult ar)
{
IPEndPoint temp = new IPEndPoint(IPAddress.Parse(asteriskip), rtpPort);
byte[] received = RTPClient.EndReceive(ar, ref temp);
byte[] decoded = alaw.Decode(received, 12, received.Length - 12);
waveProvider.AddSamples(decoded, 0, decoded.Length);//Exception occures here
}
}
我看过类似的问题,大家都建议不要使用WaveInProvider,但是在那些问题中他们不需要流声音,他们只是保存它。为什么我得到这个异常,如果是因为 WaveInProvider,我如何在没有它的情况下进行流式传输?
编辑。问题是我没有通过 SIP 发送正确的 ACK 请求,我在收到对初始 INVITE 请求的 OK 响应后发送它。结果,Asterisk 向我发送了另一个 OK 响应,当我收到 INVITE 请求的 OK 时,我开始流式传输声音,所以有多个流式线程。
缓冲区已满异常意味着您将数据写入缓冲区的速度比读取数据的速度快。如果您正在播放实时流式传输的音频,这会很奇怪。您确定发送音频的内容没有超出您的预期吗?
为了减少偶尔出现的缓冲区已满异常,您始终可以在 BufferedWaveProvider 变满时清除它。但如果它经常发生,则意味着您接收传入音频的速度比播放它的速度快。
作为替代方案,如果您无法找出缓冲区问题的根源,您可以在 BufferedWaveProvider
实例上设置 DiscardOnBufferOverflow = true
。这有点像 hack,因为您可能会丢弃样本,但如果您不需要完美的精度,这是一种快速而肮脏的解决方法。
我试着做一个软电话。它通过声音,但 5 秒后我得到 "Buffer Full" 异常。
这是我的发送代码:
public class Media
{
static WaveInEvent s_WaveIn = new WaveInEvent();
Action<byte[]> waveHandler;
public void Capture(Action<byte[]> toRtp)
{
s_WaveIn = new WaveInEvent();
s_WaveIn.WaveFormat = new WaveFormat(8000, 1);//44100, 2);
waveHandler = toRtp;
s_WaveIn.DataAvailable += new EventHandler<WaveInEventArgs>(SendCaptureSamples);
s_WaveIn.StartRecording();
}
void SendCaptureSamples(object sender, WaveInEventArgs e)
{
waveHandler(e.Buffer);
}
public void Stop()
{
s_WaveIn.StopRecording();
}
}
ToRtp 是
private void ToRtp(byte[] buffer)
{
myRTP.SequenceNumber++;
Sender.SendResponse(myRTP.MakePacket(alaw.Encode(buffer,0,buffer.Length)), RTPClient, rtpPort);//ToRTPData(buffer, 8000, 1), myUdpClient);
}
接收:
class Client
{
WaveFormat pcmFormat = new WaveFormat(8000, 16, 1);
WaveFormat alawFormat = WaveFormat.CreateALawFormat(8000, 1);
WaveOut waveOut;
BufferedWaveProvider waveProvider;
ALawChatCodec alaw = new ALawChatCodec();
public Client(IHandlerFactory handlerFactory, IPAddress hostAddress, int portNumber)
{
waveOut = new WaveOut();
waveProvider = new BufferedWaveProvider(pcmFormat);
waveOut.Init(waveProvider);
waveOut.Play();
}
private void HandleIncomingRTPRequest(IAsyncResult ar)
{
IPEndPoint temp = new IPEndPoint(IPAddress.Parse(asteriskip), rtpPort);
byte[] received = RTPClient.EndReceive(ar, ref temp);
byte[] decoded = alaw.Decode(received, 12, received.Length - 12);
waveProvider.AddSamples(decoded, 0, decoded.Length);//Exception occures here
}
}
我看过类似的问题,大家都建议不要使用WaveInProvider,但是在那些问题中他们不需要流声音,他们只是保存它。为什么我得到这个异常,如果是因为 WaveInProvider,我如何在没有它的情况下进行流式传输?
编辑。问题是我没有通过 SIP 发送正确的 ACK 请求,我在收到对初始 INVITE 请求的 OK 响应后发送它。结果,Asterisk 向我发送了另一个 OK 响应,当我收到 INVITE 请求的 OK 时,我开始流式传输声音,所以有多个流式线程。
缓冲区已满异常意味着您将数据写入缓冲区的速度比读取数据的速度快。如果您正在播放实时流式传输的音频,这会很奇怪。您确定发送音频的内容没有超出您的预期吗?
为了减少偶尔出现的缓冲区已满异常,您始终可以在 BufferedWaveProvider 变满时清除它。但如果它经常发生,则意味着您接收传入音频的速度比播放它的速度快。
作为替代方案,如果您无法找出缓冲区问题的根源,您可以在 BufferedWaveProvider
实例上设置 DiscardOnBufferOverflow = true
。这有点像 hack,因为您可能会丢弃样本,但如果您不需要完美的精度,这是一种快速而肮脏的解决方法。