如何使用AsioOut使用NAudio录制和播放

时间:2014-03-18 20:10:46

标签: c# audio-recording playback naudio asio

我正在尝试获取声音输入直接发送输出,同时减少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();

有谁知道如何修复它? 谢谢大家。

1 个答案:

答案 0 :(得分:3)

您不应该为同一设备使用AsioOut的两个实例。我很惊讶这个工作。只需使用InitRecordAndPlayback

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

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