NAudio没有读取包含wav数据的MemoryStream

时间:2018-02-27 01:07:33

标签: c# .net wav naudio memorystream

我正在尝试使用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);

2 个答案:

答案 0 :(得分:2)

WaveFileWriter(不幸的是)设计的方式是始终处理它在处理WaveFileWriter时写入的流。它本可以接受一些标志来控制这种行为,但事实并非如此。因此,如果您以后需要使用该流,则需要过早地处置WaveFileWriter,或者克隆该已关闭的内存流。如果您选择不处理编写器 - 您需要将内存流回退到位置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调用)。

答案 1 :(得分:1)

在此方案中无需使用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();