Question

I have a Windows Phone 8 app that uses the SpeechRecognizer class (not SpeechRecognizerUI) to do speech recognition. How do I cancel a session that is in progress? I don't see a cancel or stop method in the SpeechRecognizer class.

UPDATE: I want to give context to mparkuk's answer based on this MSDN thread:

SpeechRecognizer.Settings.InitialSilenceTimeout not working right

The way to cancel a speech recognition operation is to maintain a reference to the IAsyncOperation returned by the recognizer's IAsyncOperation call instead of "discarding it" by directly awaiting the RecoAsync() call to get the recognition result. I am including the code below in case the thread get's lost over time. The gist of cancelling a speech recognition session is to call the IAsyncOperation.Cancel() method.

    private const int SpeechInputTimeoutMSEC = 10000;

    private SpeechRecognizer CreateRecognizerAndLoadGrammarAsync(string fileName, Uri grammarUri, out Task grammarLoadTask)
    {
        // Create the recognizer and start loading grammars
        SpeechRecognizer reco = new SpeechRecognizer();
        // @@BUGBUG: Set the silence detection to twice the configured time - we cancel it from the thread
        reco.Settings.InitialSilenceTimeout = TimeSpan.FromMilliseconds(2 * SpeechInputTimeoutMSEC);
        reco.AudioCaptureStateChanged += recognizer_AudioCaptureStateChanged;
        reco.Grammars.AddGrammarFromUri(fileName, grammarUri);

        // Start pre-loading grammars to minimize reco delays:
        reco.PreloadGrammarsAsync();
        return reco;
    }

    /// <summary>
    /// Recognize async
    /// </summary>
    public async void RecognizeAsync()
    {
        try
        {
            // Start recognition asynchronously
            this.currentRecoOperation = this.recognizer.RecognizeAsync();

            // @@BUGBUG: Add protection code and handle speech timeout programmatically
            this.SpeechBugWorkaround_RunHangProtectionCode(this.currentRecoOperation);

            // Wait for the reco to complete (or get cancelled)
            SpeechRecognitionResult result = await this.currentRecoOperation;
            this.currentRecoOperation = null;

    // Get the results
    results = GetResults(result);
            this.CompleteRecognition(results, speechError);
        }
        catch (Exception ex)
        {
    // error
            this.CompleteRecognition(null, ex);
        }

        // Restore the recognizer for next operation if necessary
        this.ReinitializeRecogizerIfNecessary();
    }

    private void SpeechBugWorkaround_RunHangProtectionCode(IAsyncOperation<SpeechRecognitionResult> speechRecoOp)
    {
        ThreadPool.QueueUserWorkItem(delegate(object s)
        {
            try
            {
                bool cancelled = false;
                if (false == this.capturingEvent.WaitOne(3000) && speechRecoOp.Status == AsyncStatus.Started)
                {
                    cancelled = true;
                    speechRecoOp.Cancel();
                }

                // If after 10 seconds we are still running - cancel the operation.
                if (!cancelled)
                {
                    Thread.Sleep(SpeechInputTimeoutMSEC);
                    if (speechRecoOp.Status == AsyncStatus.Started)
                    {
                        speechRecoOp.Cancel();
                    }
                }
            }
            catch (Exception) { /* TODO: Add exception handling code */}
        }, null);
    }

    private void ReinitializeRecogizerIfNecessary()
    {
        lock (this.sync)
        {
            // If the audio capture event was not raised, the recognizer hang -> re-initialize it.
            if (false == this.capturingEvent.WaitOne(0))
            {
                this.recognizer = null;
                this.CreateRecognizerAndLoadGrammarAsync(...);
            }
        }
    }

    /// <summary>
    /// Handles audio capture events so we can tell the UI thread we are listening...
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    private void recognizer_AudioCaptureStateChanged(SpeechRecognizer sender, SpeechRecognizerAudioCaptureStateChangedEventArgs args)
    {
        if (args.State == SpeechRecognizerAudioCaptureState.Capturing)
        {
            this.capturingEvent.Set(); 
        }
    }

------------------------------------- FROM THE MSDN THREAD -------------------

Credit: Mark Chamberlain Sr. Escalation Engineer | Microsoft Developer Support | Windows Phone 8

Regarding a cancellation mechanism, here is some suggested code from the developer.

The IAsyncOperation returned by RecognizeAsync has a Cancel function.

You have to:

1) Set the initial silence timeout to a large value (e.g.: twice the desired speech input timeout, in my case 10 seconds) reco.Settings.InitialSilenceTimeout = TimeSpan.FromMilliseconds(2 * SpeechInputTimeoutMSEC);

2) Store this.currentRecoOperation = this.recognizer.RecognizeAsync();

3) Kick off a worker thread to cancel the operation after 10 seconds if necessary. I didn’t want to take any chances so I also added code to re-initialize everything if a hang is detected. This is done by looking at whether the audio capture state changed to Capturing within a few seconds of starting the recognition.

Was it helpful?
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top