Search code examples
c#backgroundworkerspeech-recognitionsapi

SpeechRecognitionEngine in BackgroundWorker


I am trying to write a C# application using Windows Forms and System.Speech to convert a WAV file to text. I've seen plenty of samples online of how to do this, but none that are very robust. I was hoping to write an application that could parse smaller pieces of a large WAV file using BackgroundWorker threads, but I keep getting the following exception in my threads' DoWork function when it calls engine.Recognize():

"No audio input is supplied to this recognizer. Use the method SetInputToDefaultAudioDevice if a microphone is connected to the system, otherwise use SetInputToWaveFile, SetInputToWaveStream or SetInputToAudioStream to perform speech recognition from pre-recorded audio"

Here is the code in my DoWork() function:

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);
}

I am launching multiple BackgroundWorker threads that run this code. If i use a single thread, I don't see this problem.


Solution

  • You can try this approach. I tested it for Console and Windows Forms application types.

    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);
        }
    }