我正在开发一个应用程序,它使用NAudio记录从麦克风到.wav文件的输入。我的Recorder类使用BackgroundWorker进行记录。我开始录制并继续这样做,直到10秒钟或者用户请求取消。除了一个,大多数情况下都能正常工作。在调试中,当我在中途拔掉录音设备时,事情无处可去。我预计,在工作完成事件args为e.Error(如果我抛出任何标准异常时工作正常)的情况下,问题将在BackgroundWorkedCompletedTask方法中捕获,但事实并非如此。当我选择“全部中断”时,它会将我带到行this.waveIn.StopRecording();
上的BackgroundWorkedCompletedTask方法,并且对象上的所有属性都显示为无法计算表达式,因为本机框位于调用堆栈的顶部。
我认为这与NAudio有关,使用非托管代码与设备进行交互;我希望得到的是关于如何应对这种情况的任何指导或建议。看起来try / catch块似乎不会在这里完成工作,那么我应该在哪里处理呢?在此先感谢您的帮助。
为完整起见,以下是涉及的代码的两个相关部分:
private void RecordUsingBackgroundWorker(BackgroundWorker worker)
{
var devices = this.FindDevices();
var deviceIndex = devices.IndexOf(this.requestedDevice);
var waveIn = new WaveIn(WaveCallbackInfo.FunctionCallback());
waveIn.DeviceNumber = deviceIndex;
waveIn.WaveFormat = new WaveFormat(8000, 1);
this.waveIn = waveIn;
this.waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(DataIsAvailable);
var filename = Globals.ThisAddIn.CommentFilePath;
this.waveFileWriter = new WaveFileWriter(filename, waveIn.WaveFormat);
var stopwatch = new Stopwatch();
stopwatch.Start();
this.waveIn.StartRecording();
while (stopwatch.ElapsedMilliseconds < 10000 && !worker.CancellationPending)
{
}
}
以下是工作完成时执行的代码:
private void BackgroundWorkedCompletedTask(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
}
else if (e.Error != null)
{
}
if (this.waveIn != null)
{
this.waveIn.StopRecording();
}
this.CleanUpAfterStoppedRecording();
this.IsRecording = false;
if (this.RecorderBusyRecordingChanged != null)
{
this.RecorderBusyRecordingChanged(this, new RecorderBusyEventArgs(false));
}
}
答案 0 :(得分:1)
如果对StopRecording的调用是阻塞的,一个选项就是将它包装在异步调用中并等待它完成,并超时:
public bool WaitFor(Action action, TimeSpan timeout)
{
var waitHandle = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(state =>
{
action();
waitHandle.Set();
});
return waitHandle.WaitOne(timeout);
}
你可以像这样使用它:
if (!WaitFor(this.waveIn.StopRecording, TimeSpan.FromSeconds(2)))
throw new TimeoutException("Timed out waiting for recording to stop");
请注意,这会使线程池线程在超时的操作上被阻止,因此您要么想要调用取消挂起操作的API方法(如果存在),要么继续礼貌地关闭应用程序(因为你有一个线程处于不稳定状态,你的应用程序状态可能会受到损害。)在实际的生产场景中,最好进一步改进这个方法,这样如果任务在超时后完成,你就可以得到肯定的确认句点(如果您有某种形式的取消,则可以调用。)
答案 1 :(得分:1)
Hmya,我以前见过这样的NAudio问题。它以一种使死锁很常见的方式使用mmsystem。不确定它应该受到指责,它以文档化的方式使用API。只是一种很少进行测试的方式。音频驱动程序也是一个常见的麻烦来源,恶劣的竞争对于一个优秀的软件工程师来说似乎没有多少钱。
在设备使用过程中拔出插头始终是一个问题,同时也可以在写入时将闪存驱动器从USB插槽中拉出来。或者在端口打开时拔出USB串行端口仿真器。在使用设备时拔掉设备的冲动似乎是不可抗拒的。虽然尝试了几次后他们会对它感到厌倦。
也许Larry Osterman可能会有一些意见,他在音频层上做了很多工作。他在这里发帖,你可以在他的博客上留言告诉他这个问题。除此之外,您还需要找到一种方法让NAudio作者与Microsoft支持人员一起工作。或者自己解决这个问题,提供源代码是有原因的。祝你好运。