我正在尝试 获取声音输入并直接发送输出,使用 C# 可以减少延迟。
我正在使用支持 ASIO 的库 NAudio 以获得更好的延迟。
特别是,我使用 AsioOut 对象进行录制,另一个用于使用 BufferedWaveProvider 初始化的播放,该对象填充了一个回调函数:OnAudioAvailable,它允许我使用 ASIO 缓冲区。
问题是我听到的声音带有各种故障并且有一点延迟。我认为问题出在 OnAudioAvailable 函数中,其中缓冲区充满了从声卡输入的数据。
声明:
NAudio.Wave.AsioOut playAsio;
NAudio.Wave.AsioOut recAsio;
NAudio.Wave.BufferedWaveProvider buffer;
播放流程:
if (sourceList.SelectedItems.Count == 0) return;
int deviceNumber = sourceList.SelectedItems[0].Index;
recAsio = new NAudio.Wave.AsioOut(deviceNumber);
recAsio.InitRecordAndPlayback(null, 2, 44100); //rec channel = 1
NAudio.Wave.WaveFormat formato = new NAudio.Wave.WaveFormat();
buffer = new NAudio.Wave.BufferedWaveProvider(formato);
recAsio.AudioAvailable += new EventHandler<NAudio.Wave.AsioAudioAvailableEventArgs>(OnAudioAvailable);
//Collego l'output col buffer
playAsio = new NAudio.Wave.AsioOut(deviceNumber);
playAsio.Init(buffer);
//Registro
recAsio.Play();
//Playback
playAsio.Play();
OnAudioAvailable():
//Callback
private unsafe void OnAudioAvailable(object sender, NAudio.Wave.AsioAudioAvailableEventArgs e)
{
//Copio tutti gli elementi di InputBuffers in buf e li aggiungo in coda al buffer
byte[] buf = new byte[e.SamplesPerBuffer];
for (int i = 0; i < e.InputBuffers.Length; i++)
{
Marshal.Copy(e.InputBuffers[i], buf, 0, e.SamplesPerBuffer);
//Aggiungo in coda al buffer
buffer.AddSamples(buf, 0, buf.Length);
}
}
AsioAudioAvailableEventArgs 定义:
public AsioAudioAvailableEventArgs(IntPtr[] inputBuffers, int samplesPerBuffer, AsioSampleType asioSampleType);
public float[] GetAsInterleavedSamples();
有人知道如何解决吗? 谢谢大家。
您不应在同一设备上使用两个
AsioOut
实例。我很惊讶这竟然有效。只需使用带有 InitRecordAndPlayback
的那个即可。
为了实现直通监控的绝对最小延迟,请在
AudioAvailableEvent
中,直接复制到 OutputBuffers
,然后设置 WrittenToOutputBuffers = true
。这意味着您不需要 BufferedWaveProvider
。
还请记住,任何故障都只是由于您未能足够快地处理 AudioAvailable 事件造成的。当您使用 ASIO 时,您可以处于非常低的延迟(例如低于 10 毫秒),并且可以处理大量数据(例如 96kHz 采样率、8 个输入和输出通道)。因此,您需要在短时间内进行大量数据移动。使用 .NET,您必须考虑到一个不幸的事实,即垃圾收集器可能随时启动并导致您不时错过缓冲区。
有人解决了吗?我也在做同样的事情,但我在音频输出处听不到任何声音。
我尝试使用 Marshal.Copy
Marshal.Copy(e.InputBuffers[0], e.OutputBuffers, 0, e.InputBuffers.Length);
但是,不起作用