【问题标题】:SpeechRecognitionEngine in BackgroundWorkerBackgroundWorker 中的 SpeechRecognitionEngine
【发布时间】:2012-02-24 11:43:09
【问题描述】:

我正在尝试使用 Windows 窗体和 System.Speech 编写 C# 应用程序,以将 WAV 文件转换为文本。我在网上看到了很多关于如何做到这一点的示例,但没有一个非常强大。我希望编写一个可以使用 BackgroundWorker 线程解析大型 WAV 文件的较小部分的应用程序,但是当它调用 engine.Recognize() 时,我的线程的 DoWork 函数中不断出现以下异常:

"没有向此识别器提供音频输入。如果麦克风已连接到系统,请使用方法 SetInputToDefaultAudioDevice,否则使用 SetInputToWaveFile、SetInputToWaveStream 或 SetInputToAudioStream 从预先录制的音频执行语音识别"

这是我的 DoWork() 函数中的代码:

SpeechRecognitionEngine engine = new SpeechRecognitionEngine(new    System.Globalization.CultureInfo("en-US"));
engine.SetInputToWaveFile(fname);
engine.LoadGrammar(new DictationGrammar());
engine.BabbleTimeout = TimeSpan.FromSeconds(10.0);
engine.EndSilenceTimeout = TimeSpan.FromSeconds(10.0);
engine.EndSilenceTimeoutAmbiguous = TimeSpan.FromSeconds(10.0);
engine.InitialSilenceTimeout = TimeSpan.FromSeconds(10.0);

BackgroundWorker w = (BackgroundWorker)sender;
while (true)
{    
RecognitionResult data = engine.Recognize();
if (data == null)
    break;
if (w == null) //our thread died from beneath us
    break;
if (!w.IsBusy) //our thread died from beneath us
    break;
if (w.CancellationPending) //notice to cancel
    break;
w.ReportProgress(0, data.Text);
}

我正在启动多个运行此代码的 BackgroundWorker 线程。如果我使用单线程,我看不到这个问题。

【问题讨论】:

  • 我已经很多年没有使用过 sapi 了,但是在我的脑海中,我记得它们可以作为单个进程外的 com 服务器运行,所以如果你试图让多个同时工作,这不是默认情况,您必须共享音频源和进程中的识别器。
  • 我注意到尝试从 BackgroundWorker 线程使用 SpeechRecognitionEngine 类会导致此异常。

标签: c# backgroundworker speech-recognition sapi


【解决方案1】:

您可以尝试这种方法。我针对控制台和 Windows 窗体应用程序类型对其进行了测试。

class Program {
    public static void Main() {
        var r1 = new Recognizer(@"c:\proj\test.wav");
        r1.Completed += (sender, e) => Console.WriteLine(r1.Result.Text);

        var r2 = new Recognizer(@"c:\proj\test.wav");
        r2.Completed += (sender, e) => Console.WriteLine(r2.Result.Text);

        Console.ReadLine();
    }
}

class Recognizer {
    private readonly string _fileName;
    private readonly AsyncOperation _operation;
    private volatile RecognitionResult _result;

    public Recognizer(string fileName) {
        _fileName = fileName;
        _operation = AsyncOperationManager.CreateOperation(null);            
        _result = null;

        var worker = new Action(Run);
        worker.BeginInvoke(delegate(IAsyncResult result) {
            worker.EndInvoke(result);
        }, null);            
    }

    private void Run() {
        try {
            SpeechRecognitionEngine engine = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("en-US"));
            engine.SetInputToWaveFile(_fileName);
            engine.LoadGrammar(new DictationGrammar());
            engine.BabbleTimeout = TimeSpan.FromSeconds(10.0);
            engine.EndSilenceTimeout = TimeSpan.FromSeconds(10.0);
            engine.EndSilenceTimeoutAmbiguous = TimeSpan.FromSeconds(10.0);
            engine.InitialSilenceTimeout = TimeSpan.FromSeconds(10.0);
            _result = engine.Recognize();
        }
        finally {
            _operation.PostOperationCompleted(delegate {
                RaiseCompleted();
            }, null);
        }
    }

    public RecognitionResult Result {
        get { return _result; }
    }

    public event EventHandler Completed;

    protected virtual void OnCompleted(EventArgs e) {
        if (Completed != null)
            Completed(this, e);
    }

    private void RaiseCompleted() {
        OnCompleted(EventArgs.Empty);
    }
}

【讨论】:

  • 酷,谢谢!我今天早上玩了这段代码,我认为这会起作用 - 虽然我真的不明白为什么 SpeechRecognitionEngine 不能是多线程的。我有一个问题 - Completed 事件处理程序似乎在另一个线程的上下文中运行,所以我无法更新 UI。您能否修改您的示例以调用调用 (UI) 线程上的回调?
  • 我使用了这里描述的代码并让它工作。 codeproject.com/Articles/11848/…
  • 最后一个问题 - 如果 Windows 窗体在操作过程中关闭,那么取消这些异步操作的最佳方法是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多