这是我用来录制音频文件的代码:
internal class AudioRecorder
{
public WaveIn waveSource = null;
public WaveFileWriter waveFile = null;
public string RECORDING_PATH;
public AudioRecorder(string fileName)
{
RECORDING_PATH = fileName;
}
public void Start()
{
waveSource = new WaveIn();
waveSource.WaveFormat = new WaveFormat(44100, 1);
waveSource.DeviceNumber = 0;
waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
waveFile = new WaveFileWriter(RECORDING_PATH, waveSource.WaveFormat);
System.Timers.Timer t = new System.Timers.Timer(30000);
t.Elapsed += new ElapsedEventHandler(Stop);
waveSource.StartRecording();
t.Start();
}
private void Stop(object sender, ElapsedEventArgs args)
{
waveSource.StopRecording();
}
private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
{
if (waveFile != null)
{
waveFile.Write(e.Buffer, 0, e.BytesRecorded);
waveFile.Flush();
}
}
private void waveSource_RecordingStopped(object sender, StoppedEventArgs e)
{
if (waveSource != null)
{
waveSource.Dispose();
waveSource = null;
}
if (waveFile != null)
{
waveFile.Dispose();
waveFile = null;
}
}
}
在我做的主要方法中:
AudioRecorder r = new AudioRecorder(dialog.FileName);
r.Start();
FileInfo file = new FileInfo(r.RECORDING_PATH);
// Do somehting with the recorded audio //
问题在于,当我执行r.Start()
时,线程不会阻塞并继续运行。所以我得到了一个损坏的文件错误。当我尝试像Thread.Sleep
这样的东西让线程等到录制结束时,这次AudioRecorder
代码不能正常工作(即录制永远不会完成)。
关于正确应该做什么的任何想法等待录制完成,以便我可以安全地使用录制的文件?
答案 0 :(得分:1)
如果要准确记录30秒,只要有足够的数据,就可以在DataAvailable事件处理程序中调用StopRecording。绝对不需要复杂的线程策略。我在开源.NET voice recorder application中完成了这一点。
在RecordingStopped事件中处理WaveFileWriter。
如果绝对必须有阻塞调用,则使用WaveInEvent,并按照Rene的建议等待在RecordingStopped处理程序中设置的事件。通过使用WaveInEvent,您无需使用Windows消息泵即可运行。
答案 1 :(得分:0)
使用ManualResetEvent等待调用Stop事件,为其他线程提供更改以继续。 我只添加了新位......
internal class AudioRecorder
{
private ManualResetEvent mre = new ManualResetEvent(false);
public void Start()
{
t.Start();
while (!mre.WaitOne(200))
{
// NAudio requires the windows message pump to be operational
// this works but you better raise an event
Application.DoEvents();
}
}
private void Stop(object sender, ElapsedEventArgs args)
{
// better: raise an event from here!
waveSource.StopRecording();
}
private void waveSource_RecordingStopped(object sender, EventArgs e)
{
/// ... your code here
mre.Set(); // signal thread we're done!
}
答案 2 :(得分:0)
如果不需要任何多线程代码,最好避免使用,Mark的答案就是完美地解释这一点。
但是,如果您正在编写一个Windows应用程序,并且要求记录30秒,则必须不要在等待(30秒)时阻止主线程。新的异步C#功能在这里非常方便。它将使您能够保持代码逻辑的简单性,并以非常有效的方式实现等待。
我稍微修改了您的代码,以显示在这种情况下如何使用异步功能。
这是Record方法:
public async Task RecordFixedTime(TimeSpan span)
{
waveSource = new WaveIn {WaveFormat = new WaveFormat(44100, 1), DeviceNumber = 0};
waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
waveFile = new WaveFileWriter(RECORDING_PATH, waveSource.WaveFormat);
waveSource.StartRecording();
await Task.Delay(span);
waveSource.StopRecording();
}
使用WPF app点击处理程序中的Record的示例:
private async void btnRecord_Click(object sender, RoutedEventArgs e)
{
try
{
btnRecord.IsEnabled = false;
var fileName = Path.GetTempFileName() + ".wav";
var recorder = new AudioRecorder(fileName);
await recorder.RecordFixedTime(TimeSpan.FromSeconds(5));
Process.Start(fileName);
}
finally
{
btnRecord.IsEnabled = true;
}
}
但是,你必须注意这里的时间安排。 Task.Delay不保证在确切的指定时间跨度后它将继续执行。您可能会获得比所需记录略长的记录。