【问题标题】:Speech Recognition Engine Not Firing Event in Windows ServiceWindows 服务中的语音识别引擎未触发事件
【发布时间】:2012-04-30 01:53:11
【问题描述】:

所以我有一个使用 system.speech 识别引擎实现语音识别的 Windows 服务。当我启动服务时,我的语音识别代码运行良好,但没有发生语音识别火灾的事件。奇怪的是,如果我运行完全相同的代码,但在控制台或 WPF 应用程序中,语音识别的事件触发就可以正常工作。
我已经在我的服务进程中附加了一个调试器来检查幕后发生的事情。似乎语音识别引擎正确加载了语法,将其模式设置为连续收听,并正确设置了语音识别事件。没有抛出异常,所以我不太确定这里出了什么问题。有什么想法吗?

【问题讨论】:

    标签: c# windows-services speech-recognition


    【解决方案1】:

    SpeechRecognition 应该在单独的线程上运行,并且来自 SpeechRecognitionEngine 的 OOTB,应该是这样的:

    static ManualResetEvent _completed = null;
    static void Main(string[] args)
    {
         _completed = new ManualResetEvent(false);
         SpeechRecognitionEngine _recognizer = new SpeechRecognitionEngine();
         _recognizer.RequestRecognizerUpdate(); // request for recognizer update
         _recognizer.LoadGrammar(new Grammar(new GrammarBuilder("test")) Name = { "testGrammar" }); // load a grammar
         _recognizer.RequestRecognizerUpdate(); // request for recognizer update
         _recognizer.LoadGrammar(new Grammar(new GrammarBuilder("exit")) Name = { "exitGrammar" }); // load a "exit" grammar
         _recognizer.SpeechRecognized += _recognizer_SpeechRecognized; 
         _recognizer.SetInputToDefaultAudioDevice(); // set the input of the speech recognizer to the default audio device
         _recognizer.RecognizeAsync(RecognizeMode.Multiple); // recognize speech asynchronous
         _completed.WaitOne(); // wait until speech recognition is completed
         _recognizer.Dispose(); // dispose the speech recognition engine
    } 
    void _recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
    {
         if (e.Result.Text == "test") // e.Result.Text contains the recognized text
         {
             Console.WriteLine("The test was successful!");
         } 
         else if (e.Result.Text == "exit")
         {
             _completed.Set();
         }
    }
    

    当我使用 SpeechRecognition 而不是 SpeechRecognitionEngine 时也遇到了类似的问题。 以上是一个很好的用法示例+它在另一个线程中监听事件。 ps:我从一篇很棒的文章中得到了参考: Speech recognition, speech to text, text to speech, and speech synthesis in C#有 有趣:)

    【讨论】:

    • 如果您使用RequestRecognizerUpdate,我认为您应该使用RecognizerUpdateReached 事件处理程序来调用LoadGrammar,而且您会在该事件处理程序中一起执行所有LoadGrammar 调用。但是,如果识别器尚未启动,则首先不需要调用 RequestRecognizerUpdate(可以将其删除)
    • 顺便说一句,我在 SpeechLib (SpeechLib.codeplex.com) 上提出的一种模式是在 zoomicon.wordpress.com/2015/12/07/… 末尾提到的,在语音识别已经开始时加载语法的大量试验和错误之后/跨度>
    • @Robocide 赞成!我正在做类似的事情-排队多个语音识别作业,这对我有帮助(使用ManualResetEventWaitOne()。我试图弄清楚如何将现有的_recognizer配置为队列中的下一个任务MSDN声明“不建议在事件处理程序中调用 Dispose()”。希望它对某人有所帮助!
    【解决方案2】:

    您是在使用麦克风还是在处理 WAV 文件?如果您尝试使用默认音频设备,我不确定音频管道将如何在服务中工作。如果您尝试从音频文件或流转换,请确保您使用的是 InProc 识别器。

    如果您正在创建服务器应用程序,您可能应该考虑使用 Microsoft.Speech API 和服务器识别器。请参阅 What is the difference between System.Speech.Recognition and Microsoft.Speech.Recognition? 和 Microsoft Speech Platform SDK - http://www.microsoft.com/en-us/download/details.aspx?id=27226

    如果您尝试在没有您的应用在前台的情况下进行持续识别,我相信共享识别器可能能够满足您的需求。 Windows 7 和 Vista 中附带的 Microsoft 桌面识别器可以在两种模式下工作:inproc 或 shared。共享识别器在使用语音命令控制任何打开的应用程序的桌面上很有用。在 System.Speech 中,您可以使用 SpeechRecognizer 访问共享桌面识别器或使用 SpeechRecognitionEngine 为您的应用程序提供专用的 inproc 识别器。即使您的应用不在前台,您也可以使用共享识别器为您的应用提供持续识别。

    有一篇很好的文章,几年前在http://msdn.microsoft.com/en-us/magazine/cc163663.aspx 上发表过。这可能是迄今为止我找到的最好的介绍性文章。它说:

    ...识别引擎可以在另一个名为的进程中实例化 SAPISVR.EXE。这提供了一个共享的识别引擎,可以 由多个应用程序同时使用。这个设计有一个数字 的好处。首先,识别器通常需要更多 运行时资源比合成器,共享识别器是一种 减少开销的有效方法。二、共享识别器是 Windows Vista 的内置语音功能也使用。 因此,使用共享识别器的应用程序可以从 系统的麦克风和反馈 UI。没有额外的代码 编写,并且没有新的 UI 供用户学习。SAPI 5.3 的新功能

    【讨论】:

    • 我正在使用麦克风,而不是创建服务器应用程序。
    • 我不知道您是否可以在服务中使用默认音频设备。你的用例是什么?如果您尝试在没有您的应用在前台的情况下进行持续识别,我相信共享识别器可能能够满足您的需求。
    • 是的,我的应用基本上需要在后台持续监听语音。共享识别器到底是什么意思?
    • 我更新了我的答案,加入了一些希望对您有所帮助的信息。
    • 我不知道,但服务与设备交互是一件棘手的事情,通常应该避免。见msdn.microsoft.com/en-us/library/ms683502(VS.85).aspxsupport.microsoft.com/kb/327618us.generation-nt.com/answer/…
    【解决方案3】:

    您是否尝试过将服务设置为允许与桌面交互?

    我相信此设置涵盖了与麦克风等用户接口设备的交互。

    【讨论】:

    • 我认为这可能是问题,但它没有解决它:(
    【解决方案4】:

    如果@Robocide 答案对您不起作用,就像我的情况一样,您所要做的就是在 Main 方法中将 SpeechRecognitionEngine 声明为字段而不是局部变量。

    例子:

        private SpeechRecognitionEngine _recognizer = null; //make the speeach recognition engine a private field
         static void Main(string[] args)
        {
              _recognizer = new SpeechRecognitionEngine();
             _recognizer.RequestRecognizerUpdate(); // request for recognizer update
             _recognizer.LoadGrammar(new Grammar(new GrammarBuilder("test")) Name = { "testGrammar" }); // load a grammar
             _recognizer.RequestRecognizerUpdate(); // request for recognizer update
             _recognizer.LoadGrammar(new Grammar(new GrammarBuilder("exit")) Name = { "exitGrammar" }); // load a "exit" grammar
             _recognizer.SpeechRecognized += _recognizer_SpeechRecognized; 
             _recognizer.SetInputToDefaultAudioDevice(); // set the input of the speech recognizer to the default audio device
             _recognizer.RecognizeAsync(RecognizeMode.Multiple); // recognize speech asynchronous
             _recognizer.Dispose(); // dispose the speech recognition engine
        } 
    
    void _recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
    {
         if (e.Result.Text == "test") // e.Result.Text contains the recognized text
         {
             Console.WriteLine("The test was successful!");
         } 
    }
    

    如果您注意到,我删除了 ManualResetEvent,因为如果语音未被识别,它不允许某些进程运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多