gpt4 book ai didi

c# - 语音聊天,延迟增加(缓冲区) - 可以解决吗?

转载 作者:太空宇宙 更新时间:2023-11-03 13:37:38 30 4
gpt4 key购买 nike

好吧,我正在制作一个语音聊天软件。我为此使用了 NAudio,这是一个优秀的库。

但是我遇到了一个问题。当发生某些事情时,缓冲区会上升。我猜这是来自示例,当操作系统加载某些内容并且语音聊天应用程序被“搁置”一秒钟时。在此期间,它会添加缓冲区中的数据,使当前数据延迟。

并且由于接收器始终以相同的速度播放,所以它总是会延迟。

现在我有一个“解决方案”,就是在达到一定长度时清除缓冲区。尽管这根本不理想,而且与其说是解决方案,不如说是一种技巧。

现在到代码部分。首先我初始化我使用的东西。

        private NAudio.Wave.WaveInEvent SendStream = new WaveInEvent();
private NAudio.Wave.AsioOut Aut;
private NAudio.Wave.WaveFormat waveformat = new WaveFormat(48000, 16, 2);
private WasapiLoopbackCapture Waloop = new WasapiLoopbackCapture();
private NAudio.Wave.BufferedWaveProvider waveProvider;

waveProvider = new NAudio.Wave.BufferedWaveProvider(waveformat);
waveProvider.DiscardOnBufferOverflow = true;
SendStream.WaveFormat = waveformat;

waveformat 只是为了让我不必一直重写它。使用 DiscardOnBufferOverflow 所以如果我在缓冲区上设置一定的长度,例如 20ms。它会丢弃上面的任何东西,否则它会返回一个异常。但是我认为如果我不设置长度它不会做任何事情,默认情况下它可能是无限的。

除此之外,SendStream 是一个 WaveInEvent,这意味着当我使用 DataAvailable 时它将在 BackgroundThread 上运行。 Waloop 几乎相同,只是它是一个环回。waveprovider用于接收部分播放音频。Waveformat 是,好吧 waveformat,设置它很重要,并且都一样,至少在我的应用程序中是这样。

这里是接收部分。如您所见,它将数据放入一个字节数组中,然后播放它。没什么奇怪的。

   byte[] byteData = udpClient.Receive(ref remoteEP);
waveProvider.AddSamples(byteData, 0, byteData.Length);

这里是发送/录音部分。

  private void Sendv2()
{
try
{
if (connect == true)
{
if (AudioDevice == "Wasapi Loopback")
{
SendStream.StopRecording();
Waloop.StartRecording();
}
else
{
Waloop.StopRecording();
SendStream.StartRecording();
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}

void Sending(object sender, NAudio.Wave.WaveInEventArgs e)
{
if (connect == true && MuteMic.Checked == false)
{
udpClient.Send(e.Buffer, e.BytesRecorded, otherPartyIP.Address.ToString(), 1500);
}

}
void SendWaloop(object sender, NAudio.Wave.WaveInEventArgs e)
{

byte[] newArray16Bit = new byte[e.BytesRecorded / 2];
short two;
float value;
for (int i = 0, j = 0; i < e.BytesRecorded; i += 4, j += 2)
{
value = (BitConverter.ToSingle(e.Buffer, i));
two = (short)(value * short.MaxValue);

newArray16Bit[j] = (byte)(two & 0xFF);
newArray16Bit[j + 1] = (byte)((two >> 8) & 0xFF);
}
if (connect == true && MuteMic.Checked == false)
{
udpClient.Send(newArray16Bit, newArray16Bit.Length, otherPartyIP.Address.ToString(), 1500);
}

}

Waloop 是一个环回,因此它通过另一个“ channel ”,但它在这里并不重要。

非常简单,当数据可用时(当它正在记录时)并且如果连接为真等,它只会发送缓冲区。

非常像接收器部分,但相反。

现在我是这样解决这个问题的:

 if (waveProvider.BufferedDuration.Milliseconds > 40)
{

waveProvider.ClearBuffer();
TimesBufferClear++;
}

因此,如果缓冲区超过 40 毫秒,我将清除缓冲区(这是在 600 毫秒间隔的计时器中)。(TimesBufferClear++; 只是为了让我可以跟踪它被清除的时间)

现在可悲的是,我不知道如何防止缓冲区增加,将其设置为强制状态(20 毫秒等)只会导致播放效果越来越差,缓冲区越高越好,因为它没有。不要真的停下来,它只是忽略了我认为的上面的部分。

这里是输入设备的创建。在我的实现中它与 ASIO 和 Wasapi 有点不同,但它的工作原理几乎相同,唯一真正的区别是我告诉 UI ASIO 是打开还是关闭,正如你在代码中看到的那样,最后我添加了SendStream(任何输入、麦克风等)和 Waloop(正在播放的环回声音)的 DataAvailable 事件。

  private void CheckAsio()
{

if (NAudio.Wave.AsioOut.isSupported())
{

Aut = new NAudio.Wave.AsioOut();
ASIO.Text += "\nSupported: " + Aut.DriverName;
ASIO.ForeColor = System.Drawing.Color.Green;
Aut.Init(waveProvider);
Aut.Play();
SendStream.NumberOfBuffers = 2;
SendStream.BufferMilliseconds = 10;
}
else
{
AsioSettings.Enabled = false;
ASIO.Text += "\n Not Supported: Wasapi used";
ASIO.ForeColor = System.Drawing.Color.DarkGray;
Wasout = new WasapiOut(AudioClientShareMode.Shared, 0);
Wasout.Init(waveProvider);
Wasout.Play();
SendStream.NumberOfBuffers = 2;
SendStream.BufferMilliseconds = 9;
}
SendStream.DataAvailable += Sending;
Waloop.DataAvailable += SendWaloop;

}

我不确定这是否可以解决。但由于我没有看到其他语音聊天程序有它,我猜一定有什么可以做的。

最佳答案

在大多数应用程序中,这种处理方式似乎是以定义的速率(以样本/秒为单位)发送数据 block ,并丢弃超过该速率的数据 block 。如果发送方资源有限且无法保持速率,则流将出现音频间隙。当传输速率被锁定为高于网络连接可以处理的速度时,或者当 CODEC 代码占用太多时间时,这种情况过去常常发生在通过拨号进行的音频通话中。

但从事物的声音来看,缓冲和跳过是症状,而不是原因。问题的根源在于您的流程因其他操作而被搁置。您可以通过以更高的进程和/或线程优先级运行来解决这个问题。优先级越高,您遇到的中断就越少,这将降低数据排队等待处理的可能性。

在 .NET 中,您可以非常简单地提高进程和/或线程的优先级。对于进程优先级:

using System.Diagnostics;

...

Process.GetCurrentProcess().PriorityClass = PriorityClass.Highest;

或者对于线程:

using System.Threading;

...

Thread.CurrentThread.Priority = ThreadPriority.Highest;

这不是一个完整的解决方案,因为操作系统在各种情况下仍会从您的应用程序中窃取时间片,但在具有大量内存的多 CPU/内核系统中,您应该能够获得相当不错的稳定记录环境。

当然没有万无一失的方法,而且总是有一台慢速计算机会把你搞得一团糟,所以你应该让系统在必要时丢弃多余的样本。跟踪您发送的数据量以及数据何时开始备份,丢弃任何超过您的最大样本数/秒的数据。这样,您的服务器(或客户端)就不会缓冲越来越多的数据,也不会越来越落后于实时。

其中一个选项是为您发送的每个数据包打上时间戳,以便客户端可以选择何时开始丢弃数据以 catch 进度。最好在这里和那里丢失几毫秒的输出,而不是越来越不同步。

关于c# - 语音聊天,延迟增加(缓冲区) - 可以解决吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18214678/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com