I'm trying to get the sound input and send output directly with less latency possible with C#.
我正在尝试获取声音输入并直接发送输出,使用c#可以减少延迟。
I'm using the library NAudio that supports ASIO for better latency.
我正在使用支持ASIO的NAudio库,以获得更好的延迟。
In particular, I use the AsioOut object for recording and another for playback initialized with a BufferedWaveProvider, which is filled in a Callback function: OnAudioAvailable, which allows me to use the ASIO buffers.
特别是,我使用AsioOut对象进行记录,使用BufferedWaveProvider初始化的另一个对象进行回放,这个对象被填充在一个回调函数:OnAudioAvailable中,它允许我使用ASIO缓冲区。
The problem is that I hear the sound with various glitches and with a bit of delay. I think the problem is in the function OnAudioAvailable where the buffer is filled with data taken as input from the sound card.
问题是我听到的声音有各种各样的小故障,而且有一点延迟。我认为问题出在OnAudioAvailable函数中,在这个函数中,缓冲区中填充了作为声卡输入的数据。
Declarations:
声明:
NAudio.Wave.AsioOut playAsio;
NAudio.Wave.AsioOut recAsio;
NAudio.Wave.BufferedWaveProvider buffer;
Play procedure:
游戏过程:
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():
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 definition:
AsioAudioAvailableEventArgs定义:
public AsioAudioAvailableEventArgs(IntPtr[] inputBuffers, int samplesPerBuffer, AsioSampleType asioSampleType);
public float[] GetAsInterleavedSamples();
Does anyone know how to fix it? Thank you all.
有人知道怎么修理吗?谢谢大家。
1 个解决方案
#1
2
You should not be using two instances of AsioOut
for the same device. I'm surprised this works at all. Just use the one, with InitRecordAndPlayback
.
您不应该为同一设备使用两个AsioOut实例。我很惊讶这竟然有效。就用这个,有InitRecordAndPlayback。
For absolute minimal latency for pass-through monitoring, in AudioAvailableEvent
, copy directly to the OutputBuffers
, and set WrittenToOutputBuffers = true
. This means you don't need a BufferedWaveProvider
.
对于传递监视的绝对最小延迟,在AudioAvailableEvent中,直接复制到OutputBuffers,并设置WrittenToOutputBuffers = true。这意味着您不需要缓冲波提供程序。
Also remember that any glitches are simply due to you not managing to process the AudioAvailable event quickly enough. When you're working with ASIO, you can be at very low latencies (e.g. sub 10ms), and can be dealing with lots of data (e.g. 96kHz sample rates, 8 channels of input and output). So you need to do a lot of moving of data in a short time window. With .NET, you have to factor in the unfortunate fact that the garbage collector could kick in at any time and cause you to miss a buffer from time to time.
还要记住,任何故障都只是由于您没有足够快地处理音频可用事件造成的。当您使用ASIO时,您可能处于非常低的延迟(例如10毫秒以下),并且可以处理大量数据(例如96kHz采样率,8个输入和输出通道)。所以你需要在短时间内做大量的数据移动。对于。net,您必须考虑到一个不幸的事实,即垃圾收集器可能在任何时候启动,并导致您不时地丢失缓冲区。
#1
2
You should not be using two instances of AsioOut
for the same device. I'm surprised this works at all. Just use the one, with InitRecordAndPlayback
.
您不应该为同一设备使用两个AsioOut实例。我很惊讶这竟然有效。就用这个,有InitRecordAndPlayback。
For absolute minimal latency for pass-through monitoring, in AudioAvailableEvent
, copy directly to the OutputBuffers
, and set WrittenToOutputBuffers = true
. This means you don't need a BufferedWaveProvider
.
对于传递监视的绝对最小延迟,在AudioAvailableEvent中,直接复制到OutputBuffers,并设置WrittenToOutputBuffers = true。这意味着您不需要缓冲波提供程序。
Also remember that any glitches are simply due to you not managing to process the AudioAvailable event quickly enough. When you're working with ASIO, you can be at very low latencies (e.g. sub 10ms), and can be dealing with lots of data (e.g. 96kHz sample rates, 8 channels of input and output). So you need to do a lot of moving of data in a short time window. With .NET, you have to factor in the unfortunate fact that the garbage collector could kick in at any time and cause you to miss a buffer from time to time.
还要记住,任何故障都只是由于您没有足够快地处理音频可用事件造成的。当您使用ASIO时,您可能处于非常低的延迟(例如10毫秒以下),并且可以处理大量数据(例如96kHz采样率,8个输入和输出通道)。所以你需要在短时间内做大量的数据移动。对于。net,您必须考虑到一个不幸的事实,即垃圾收集器可能在任何时候启动,并导致您不时地丢失缓冲区。