NAudio 未读取包含 wav 数据的 MemoryStream

NAudio is not reading MemoryStream containing wav data

我正在尝试使用 NAudio 录制 8 秒的流式音频,将其存储在 System.IO.MemoryStream 中,然后立即播放。为此,我 运行 以下代码:

using System.IO;
using NAudio.Wave;

public class AudioCapture{

    static WaveFileWriter wri;
    static bool stopped = false;

    public AudioCapture(){
        //record from loopback
        IWaveIn waveIn = new WasapiLoopbackCapture();
        waveIn.DataAvailable += waveIn_DataAvailable;
        waveIn.RecordingStopped += waveIn_RecordingStopped;

        //write loopback capture to MemoryStream
        Stream sos = new MemoryStream();
        wri = new WaveFileWriter(sos, waveIn.WaveFormat);

        //record 8 seconds of streaming audio
        waveIn.StartRecording();
        System.Threading.Thread.Sleep(8000);
        waveIn.StopRecording();

        //flush and dispose objects
        wri.Flush();
        waveIn.Dispose();
        wri.Dispose();

        //play back recorded audio
        WaveOut waveOut = new WaveOut();
        WaveFileReader waveFileReader = new WaveFileReader(sos);
        waveOut.Init(waveFileReader);
        waveOut.Play();

    }

    static void waveIn_RecordingStopped(object sender, StoppedEventArgs e){
        stopped = true;
    }

    static void waveIn_DataAvailable(object sender, WaveInEventArgs e){
        if (wri != null) wri.Write(e.Buffer, 0, e.BytesRecorded);
    }

}

我收到以下异常,告诉我无法读取流:

Activated   Event   Time    Duration    Thread
    Exception: Exception thrown: 'System.ArgumentException' in NAudio.dll 
("Stream was not readable."). Exception thrown: 'System.ArgumentException' in 
NAudio.dll ("Stream was not readable.") 17.86s      [17404] <No Name> 

我不太确定问题出在哪里,因为根据文档,WaveFileWriter 明确接受 MemoryStream。我缺少一些转换吗?任何帮助,将不胜感激。谢谢!

澄清一下:错误似乎在这一行:

WaveFileReader waveFileReader = new WaveFileReader(sos);

WaveFileWriter 的设计方式(不幸的是)在您处理 WaveFileWriter 总是 处理它写入的流。它本可以接受一些标志来控制这种行为,但它没有。因此,如果您稍后需要使用该流,则需要不要过早处理 WaveFileWriter,或者克隆该已关闭的内存流。如果你选择不处理writer - 你需要将内存流倒回到位置0,这样读取就可以从头开始(在写入位置结束后):

wri.Flush();
waveIn.Dispose();
// wri.Dispose(); < too early
sos.Seek(0, SeekOrigin.Begin);

如果您想使用克隆 - 不需要倒带:

wri.Flush();
waveIn.Dispose();
wri.Dispose();
sos = new MemoryStream(sos.ToArray());

克隆的缺点是它创建了整个字节数组的不必要副本(ToArray 调用)。

在这种情况下不需要使用 WaveFileReaderWaveFileWriter。只需将收到的音频写入 MemoryStream 即可:

static void waveIn_DataAvailable(object sender, WaveInEventArgs e){
    if (sos != null) sos.Write(e.Buffer, 0, e.BytesRecorded);
}

然后,当您完成并准备开始播放时,倒回 MemoryStream 并使用 RawSourceWaveStream:

//play back recorded audio
var waveOut = new WaveOut();
sos.Position = 0;
var waveFileReader = new RawSourceWaveStream(sos, waveIn.WaveFormat);
waveOut.Init(waveFileReader);
waveOut.Play();