1

I'm trying to get the sound input and send output directly with less latency possible with C#.

I'm using the library NAudio that supports ASIO for better latency.

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.

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.

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():

//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:

public AsioAudioAvailableEventArgs(IntPtr[] inputBuffers, int samplesPerBuffer, AsioSampleType asioSampleType);
public float[] GetAsInterleavedSamples();

Does anyone know how to fix it? Thank you all.

4

1 回答 1

3

您不应该AsioOut对同一设备使用两个实例。我很惊讶这完全有效。只需使用一个,with InitRecordAndPlayback

对于直通监控的绝对最小延迟,在 中AudioAvailableEvent,直接复制到OutputBuffers,并设置WrittenToOutputBuffers = true。这意味着您不需要BufferedWaveProvider.

还要记住,任何故障都只是由于您没有足够快地处理 AudioAvailable 事件。当您使用 ASIO 时,您可以处于非常低的延迟(例如低于 10 毫秒),并且可以处理大量数据(例如 96kHz 采样率,8 个输入和输出通道)。所以你需要在很短的时间窗口内做大量的数据移动。使用 .NET,您必须考虑一个不幸的事实,即垃圾收集器可能随时启动并导致您不时错过缓冲区。

于 2014-03-19T10:08:17.260 回答