I am writing a speech recognition program using system.speech from MS. I have been going through the online tutorials and all the great info on StackOverflow however i seem to keep running into an issue where the recognizer seems to throw an error.
Below is the code I am using (minus the grammar creation).
Grammar grammarQuestionsSingle;
Grammar grammarQuestionsShort;
Grammar grammarQuestionsLong;
Grammar grammarStatement;
//Grammar grammarDeclarationShort;
//Grammar grammarDeclarationLong;
Grammar grammarCommandsSingle;
Grammar grammarCommandsShort;
Grammar grammarCommandsLong;
SpeechRecognitionEngine recognizer = new SpeechRecognitionEngine();
CreateGrammar grammar = new CreateGrammar();
Think brain = new Think();
bool privacy, completed;
//bool timer;
public void OpenEars()
{
completed = true;
if (grammarQuestionsSingle == null || grammarQuestionsShort == null || grammarQuestionsLong == null || grammarStatement == null || grammarCommandsSingle == null || grammarCommandsShort == null || grammarCommandsLong == null)
{
grammarQuestionsSingle = grammar.createGrammarQuestionsSingle();
grammarQuestionsShort = grammar.createGrammarQuestionsShort();
grammarQuestionsLong = grammar.createGrammarQuestionsLong();
grammarStatement = grammar.createGrammarStatement();
grammarCommandsSingle = grammar.createGrammarCommandsSingle();
grammarCommandsShort = grammar.createGrammarCommandsShort();
grammarCommandsLong = grammar.createGrammarCommandsLong();
}
recognizer.RequestRecognizerUpdate();
if (!grammarQuestionsSingle.Loaded)
{
recognizer.LoadGrammar(grammarQuestionsSingle);
}
if (!grammarQuestionsShort.Loaded)
{
recognizer.LoadGrammar(grammarQuestionsShort);
}
if (!grammarQuestionsLong.Loaded)
{
recognizer.LoadGrammar(grammarQuestionsLong);
}
if (!grammarStatement.Loaded)
{
recognizer.LoadGrammar(grammarStatement);
}
if (!grammarCommandsSingle.Loaded)
{
recognizer.LoadGrammar(grammarCommandsSingle);
}
if (!grammarCommandsShort.Loaded)
{
recognizer.LoadGrammar(grammarCommandsShort);
}
if (!grammarCommandsLong.Loaded)
{
recognizer.LoadGrammar(grammarCommandsLong);
}
DictationGrammar dictationGrammar = new DictationGrammar("grammar:dictation");
dictationGrammar.Name = "DictationQuestion";
recognizer.LoadGrammar(dictationGrammar);
recognizer.RequestRecognizerUpdate();
recognizer.SetInputToDefaultAudioDevice();
Listening();
}
public void Listening()
{
while (!completed)
{
Thread.Sleep(333);
}
recognizer.SpeechRecognized += recognizer_SpeechRecognized;
recognizer.RecognizeAsync(RecognizeMode.Single);
}
private void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
completed = false;
SemanticValue sem = e.Result.Semantics;
if (!privacy)
{
if (e.Result.Grammar.Name=="CommandsSingle" && sem["keyCommandsSingle"].Value.ToString() == "go to sleep")
{
privacy = true;
brain.useMouth("ear muffs are on");
completed = true;
Listening();
}
else
{
brain.Understanding(sender, e);
completed = true;
}
}
else
{
if (e.Result.Grammar.Name == "CommandsSingle" && sem["keyCommandsSingle"].Value.ToString() == "wake up")
{
privacy = false;
brain.useMouth("I am listening again");
completed = true;
Listening();
}
}
completed = true;
Listening();
}
}
It recognizes the first phrase correctly but as soon as it completes the actions in the speechrecognized handler, it throws the exception "Cannot perform this operation while the recognizer is doing recognition.".
I have tried with the recognition being all in a single method however it has the same results. This was my most recent attempt prior to posting this question.
What am I doing wrong?
As to clarify...
The program launches into the systray and calls this class.OpenEars(). OpenEars then calls class.Listening() which has the RecognizeAsync. After speaking the first phrase and the recognizer hearing it correctly and following the handler, the second phrase when spoken ends up triggering the exception.
The problem is that you are calling RecognizeAsync from the SpeechRecognized event handler. It is throwing the exception because the previous recognition has not yet completed. The event handler is blocking it from completing. Try starting a different task/thread to call RecognizeAsync.
Related
I'm stuck with quite a nasty problem. I have an .net application to scan images with TWAIN driver (using new twaindsm.dll). I'm using the library NTwain for the communication with the scanner and the data/error handling should work like this (see code below):
Handling events of TwainSession
Init Twainsession and Enable DataSource
scanTwain(CancellationToken cancelToken)
{
var session = new TwainSession(TWIdentity.CreateFromAssembly(DataGroups.Image | DataGroups.Control, Assembly.GetEntryAssembly()));
Exception error = null;
bool cancel = false;
DataSource ds = null;
var waitHandle = new AutoResetEvent(false);
session.TransferReady += (sender, eventArgs) =>
{
//handle transfer ready
};
session.DataTransferred += (sender, eventArgs) =>
{
//handle data transfer
};
session.TransferError += (sender, eventArgs) =>
{
//handle error
cancel = true;
StopTwain();
};
session.SourceDisabled += (sender, eventArgs) =>
{
StopTwain();
};
void StopTwain()
{
waitHandle.Set();
}
void InitTwain()
{
try
{
ReturnCode rc = session.Open();
if (rc != ReturnCode.Success)
{
StopTwain();
}
ds = session.FirstOrDefault(x => x.Name == scanDevice.ID);
rc = ds.Open();
if (rc != ReturnCode.Success)
{
StopTwain();
}
//configure DS triplets for specific scanning options..
var ui = SourceEnableMode.NoUI;
rc = ds.Enable(ui, true, IntPtr.Zero)
if (rc != ReturnCode.Success)
{
StopTwain();
}
else
{
cancelToken.Register(() =>
{
cancel = true;
session.ForceStepDown(5);
});
}
}
catch (Exception ex)
{
error = ex;
StopTwain();
}
}
Invoker.Current.Invoke(InitTwain);
waitHandle.WaitOne();
if (ds != null && session.IsSourceOpen)
{
ds.Close();
}
if (session.IsDsmOpen)
{
session.Close();
}
if (error != null)
{
throw error;
}
}
Scanning images with twain works without problems. The real issue comes with the error handling. If an error on the scanning device occurs like e.g. a paperjam, no DataTransfer error event is triggered and the application is stuck in a loop because there is no message back from the scanning device.
The application itself is built with target Framework .NET 4.7.2 (with preference of 32 bit) and I'm currently using NTwain with version 3.7.1. I also tried different target frameworks and different NTwain versions (down to 3.3.9.5) in many possible combinations but that didn't work either..
As for the twaindsm.dll I'm using the provided one by Fujitsu PaperStream 3.10.
Does somebody have any ideas why the error handling just doesn't want to work?
Regards
Im trying to read receiving email from gmail and I did it.
If emails receive one by one it works perfectly.But if emails receive three or four at the same time.I miss at least two of them.
I hope describe my issue properly.
Here is my code for reading;
private void StartReceiving()
{
Task.Run(() =>
{
using (ImapClient client = new ImapClient("imap.gmail.com", 993, txtEmail.Text, txtSifre.Text, AuthMethod.Login, true))
{
if (client.Supports("IDLE") == false)
{
MessageBox.Show("server crash");
return;
}
client.NewMessage += new EventHandler<IdleMessageEventArgs>(OnNewMessage);
while (true) ;
}
});
}
static void OnNewMessage(object sender,IdleMessageEventArgs e)
{
//MessageBox.Show("mesaj geldi");
MailMessage m = e.Client.GetMessage(e.MessageUID, FetchOptions.Normal);
f.Invoke((MethodInvoker)delegate
{
f.txtGelen.AppendText("Body: " + m.Body + "\n");
});
}
What should I do ? Im kinda newbie at this,i have to read at least 4 emails at same time.
I never worked with gmail, but I had a similar problem when I was reading a TCP/IP log file, and it kept sending messages while I was processing.
The way I resolved it was to use a LIST of strings, and then process it in a background worker. Changing a string in place could be an issue in a race situation.
This is cut and pasted out of my code, and modified without checking my syntax, but it goes something like this:
private System.ComponentModel.BackgroundWorker backgroundWorkerReadMail;
private List<string> messagesToBeRead = null;
/****************************************************************
* readPassedMessage(string str)
* Puts message in queue, and calls background worker
****************************************************************/
private void readPassedMessage(string str)
{
string stringToRead = str;
if (messagesToBeRead == null) messagesToBeRead = new List<string>();
messagesToBeRead.Add(stringToRead);
if (backgroundWorkerReadMail != null && backgroundWorkerReadMail.IsBusy == false)
{
backgroundWorkerReadMail.RunWorkerAsync();
}
else if (backgroundWorkerReadMail == null)
{
// need to create it
}
}
private void backgroundWorkerReadMail_DoWork(object passedObj, DoWorkEventArgs e)
{
if (messagesToBeRead == null || messagesToBeRead.Count == 0) return;
if (backgroundWorkerReadMail.CancellationPending)
{
messagesToBeRead.Clear();
e.Cancel = true;
}
else
{
bool messagesLeftToRead = true;
while (messagesLeftToRead)
{
string curString = messagesToBeRead[0];
// < ADD CODE HERE TO DO WHATEVER YOU WANT WITH YOUR MESSAGE > //
messagesToBeRead.RemoveAt(0);
if (messagesToBeRead.Count == 0 || backgroundWorkerVoiceAssist.CancellationPending)
break;
} // while (messagesLeftToRead) end brace
}
}
I'm working on a text to speech demo, in which I'm using speech synthesizer.
My problem is when I click on play button the page is loading continuously.
It does not stop even if the speech is finished. Also in my demo pause and resume are not working.
I also tried to use spVoice interface for text to speech, but in this demo also pause and resume are not working.
Demo Using Speech synthesizer -
SpeechSynthesizer spRead;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Creating new object of SpeechSynthesizer.
spRead = new SpeechSynthesizer();
}
} // Page_Load
protected void btnPlay_Click(object sender, EventArgs e)
{
// Get the content data as per the content id
_contentData = new ContentFormData(ContentManager.GetContentData(Page.Database, ContentId, Page.IsLive));
// Get the text after trim
_speechText = WebUtility.HtmlDecode(_contentData.Content.Text1.Trim());
// If Speech Text is not null
// then check the button class, if cssclass is play change it to pause
and call speak method.
if (_speechText != null && !string.IsNullOrEmpty(_speechText))
{
// if button is play buttton
// then call play method and speech the text
if (btnPlay.CssClass == "button-play")
{
btnPlay.CssClass = btnPlay.CssClass.Replace("button-play",
"button-pause");
// creating the object of SpeechSynthesizer class
spRead = new SpeechSynthesizer();
spRead.SpeakAsync(_speechText);
spRead.SpeakCompleted += new
EventHandler<SpeakCompletedEventArgs>(spRead_SpeakCompleted);
}
// If button class is pause
// then change it to continue and call pause method.
else if (btnPlay.CssClass == "button-pause")
{
btnPlay.CssClass = btnPlay.CssClass.Replace("button-pause",
"button-continue");
if (spRead != null)
{
// Check the state of spRead, and call pause method.
if (spRead.State == SynthesizerState.Speaking)
{
spRead.Pause();
}
}
btnPlayFromStart.Enabled = true;
}
// If button class is continue
// then change it to pause and call resume method.
else if (btnPlay.CssClass == "button-continue")
{
btnPlay.CssClass = btnPlay.CssClass.Replace("button-continue",
"button-pause");
if (spRead != null)
{
// Check the state of spRead, and call resume method.
if (spRead.State == SynthesizerState.Paused)
{
spRead.Resume();
}
}
btnPlayFromStart.Enabled = false;
}
}
}
private void spRead_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
{
// If Spread is not null
// then dispose the spread after the speak is completed
// else do nothing
if (spRead != null)
{
spRead.Dispose();
}
else
{
// do nothing
}
} // spRead_SpeakCompleted
Demo Using SpVoice -
SpVoice voice;
protected void Page_Load(object sender, EventArgs e)
{
_contentData = new
ContentFormData(ContentManager.GetContentData(Page.Database, ContentId,
Page.IsLive));
_speechText = WebUtility.HtmlDecode(_contentData.Content.Text1.Trim());
} // Page_Load
protected void btnPlay_Click(object sender, EventArgs e)
{
voice = new SpVoice();
if (btnPlay.CssClass == "button-play")
{
voice.Speak(_speechText, SpeechVoiceSpeakFlags.SVSFlagsAsync);
btnPlay.CssClass = btnPlay.CssClass.Replace("button-play", "button-
pause");
}
else if (btnPlay.CssClass == "button-pause")
{
voice.Pause();
btnPlay.CssClass = btnPlay.CssClass.Replace("button-pause", "button-
continue");
}
else if (btnPlay.CssClass == "button-continue")
{
voice.Resume();
btnPlay.CssClass = btnPlay.CssClass.Replace("button-continue",
"button-play");
}
}
Solved the issue by using handeler, to stop the postback.
Stored the voice object in session and in pause and resume get the voice object from session.
I have a universal app the uses voice synthesis. Running under WP8.1, it works fine, but as soon as I try Win8.1 I start getting strange behaviour. The actual voice seems to speak once, however, on the second run (within the same app), the following code hangs:
string toSay = "hello";
System.Diagnostics.Debug.WriteLine("{0}: Speak {1}", DateTime.Now, toSay);
using (SpeechSynthesizer synth = new SpeechSynthesizer())
{
System.Diagnostics.Debug.WriteLine("{0}: After sythesizer instantiated", DateTime.Now);
var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);
System.Diagnostics.Debug.WriteLine("{0}: After voice stream", DateTime.Now);
The reason for the debug statements is that the code seems to have an uncertainty principle to it. That is, when I debug through it, the code executes and passes the SynthesizeTextToStreamAsync statement. However, when the breakpoits are removed, I only get the debug statement preceding it - never the one after.
The best I can deduce is that during the first run through something bad happens (it does claim to complete and actually speaks the first time), then it gets stuck and can't play any more. The full code looks similar to this:
string toSay = "hello";
System.Diagnostics.Debug.WriteLine("{0}: Speak {1}", DateTime.Now, toSay);
using (SpeechSynthesizer synth = new SpeechSynthesizer())
{
System.Diagnostics.Debug.WriteLine("{0}: After sythesizer instantiated", DateTime.Now);
var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);
System.Diagnostics.Debug.WriteLine("{0}: After voice stream", DateTime.Now);
MediaElement mediaElement;
mediaElement = rootControl.Children.FirstOrDefault(a => a as MediaElement != null) as MediaElement;
if (mediaElement == null)
{
mediaElement = new MediaElement();
rootControl.Children.Add(mediaElement);
}
mediaElement.SetSource(voiceStream, voiceStream.ContentType);
mediaElement.Volume = 1;
mediaElement.IsMuted = false;
var tcs = new TaskCompletionSource<bool>();
mediaElement.MediaEnded += (o, e) => { tcs.TrySetResult(true); };
mediaElement.MediaFailed += (o, e) => { tcs.TrySetResult(true); };
mediaElement.Play();
await tcs.Task;
Okay - I think I managed to get this working... although I'm unsure why.
using (SpeechSynthesizer synth = new SpeechSynthesizer())
{
var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);
MediaElement mediaElement;
mediaElement = rootControl.Children.FirstOrDefault(a => a as MediaElement != null) as MediaElement;
if (mediaElement == null)
{
mediaElement = new MediaElement();
rootControl.Children.Add(mediaElement);
}
mediaElement.SetSource(voiceStream, voiceStream.ContentType);
mediaElement.Volume = 1;
mediaElement.IsMuted = false;
var tcs = new TaskCompletionSource<bool>();
mediaElement.MediaEnded += (o, e) => { tcs.TrySetResult(true); };
mediaElement.Play();
await tcs.Task;
// Removing the control seems to free up whatever is locking
rootControl.Children.Remove(mediaElement);
}
I am not sure what program language you are using. However this may help. This is in C# so this could help lead you in the right direction.
namespace Alexis
{
public partial class frmMain : Form
{
SpeechRecognitionEngine _recognizer = new SpeechRecognitionEngine();
SpeechSynthesizer Alexis = new SpeechSynthesizer();
SpeechRecognitionEngine startlistening = new SpeechRecognitionEngine();
DateTime timenow = DateTime.Now;
}
//other coding such as InitializeComponent and others.
//
//
//
//
private void frmMain_Load(object sender, EventArgs e)
{
_recognizer.SetInputToDefaultAudioDevice();
_recognizer.LoadGrammarAsync(new Grammar(new GrammarBuilder(new Choices(File.ReadAllLines(#"Default Commands.txt")))));
_recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(Shell_SpeechRecognized);
_recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(Social_SpeechRecognized);
_recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(Web_SpeechRecognized);
_recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(Default_SpeechRecognized);
_recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(AlarmClock_SpeechRecognized);
_recognizer.LoadGrammarAsync(new Grammar(new GrammarBuilder(new Choices(AlarmAM))));
_recognizer.LoadGrammarAsync(new Grammar(new GrammarBuilder(new Choices(AlarmPM))));
_recognizer.SpeechDetected += new EventHandler<SpeechDetectedEventArgs>(_recognizer_SpeechDetected);
_recognizer.RecognizeAsync(RecognizeMode.Multiple);
startlistening.SetInputToDefaultAudioDevice();
startlistening.LoadGrammarAsync(new Grammar(new GrammarBuilder(new Choices("alexis"))));
startlistening.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(startlistening_SpeechRecognized);
//other stuff here..... Then once you have this then you can generate a method then with your code as follows
//
//
//
private void Default_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
int ranNum;
string speech = e.Result.Text;
switch (speech)
{
#region Greetings
case "hello":
case "hello alexis":
timenow = DateTime.Now;
if (timenow.Hour >= 5 && timenow.Hour < 12)
{ Alexis.SpeakAsync("Goodmorning " + Settings.Default.User); }
if (timenow.Hour >= 12 && timenow.Hour < 18)
{ Alexis.SpeakAsync("Good afternoon " + Settings.Default.User); }
if (timenow.Hour >= 18 && timenow.Hour < 24)
{ Alexis.SpeakAsync("Good evening " + Settings.Default.User); }
if (timenow.Hour < 5)
{ Alexis.SpeakAsync("Hello " + Settings.Default.User + ", it's getting late"); }
break;
case "whats my name":
case "what is my name":
Alexis.SpeakAsync(Settings.Default.User);
break;
case "stop talking":
case "quit talking":
Alexis.SpeakAsyncCancelAll();
ranNum = rnd.Next(1, 2);
if (ranNum == 2)
{ Alexis.Speak("sorry " + Settings.Default.User); }
break;
}
}
instead of using the commands in the code. I recommend that you use a text document. once you have that then you can add your own commands to it then put it in code. Also reference the System.Speech.
I hope this helps on getting you on the right track.
I have a winform application that runs in background with a BackgroundWorker that has an infinite loop that execute something every hour. My UI Form class is something like this:
public partial class frmAutoScript : Form
{
private volatile bool _isDownloading = false;
private bool IsDownloading { get { return this._isDownloading; } set { this._isDownloading = value; } }
public frmAutoScript()
{
InitializeComponent();
this.RunAutoSynchronization();
}
private void RunAutoSynchronization()
{
bool isDownloading = this.IsDownloading;
BackgroundWorker bgwDownloader = new BackgroundWorker();
bgwDownloader.WorkerReportsProgress = true;
bgwDownloader.ProgressChanged += (sndr, evnt) =>
{
if (evnt.ProgressPercentage == 2)
isDownloading = this.IsDownloading;
else
{
this.IsDownloading = evnt.ProgressPercentage == 1;
isDownloading = this.IsDownloading;
}
};
bgwDownloader.DoWork += (sndr, evnt) =>
{
while (true)
{
if (DateTime.Now.Hour == 16 &&
DateTime.Now.Minute == 0)
{
try
{
bgwDownloader.ReportProgress(2);
if (!isDownloading)
{
bgwDownloader.ReportProgress(1);
new Downloader().Download();
}
bgwDownloader.ReportProgress(0);
}
catch { }
}
System.Threading.Thread.Sleep(60000);
}
};
bgwDownloader.RunWorkerAsync();
}
}
And in that frmAutoScript, I also have a button named btnDownload that when clicked, it will download and change the value of the volatile varialbe _isDownloading. The event of the button is something like this:
private void btnDownload_Click(object sender, EventArgs e)
{
if (IsDownloading)
MessageBox.Show("A download is currently ongoing. Please wait for the download to finish.",
"Force Download", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
else
{
this.IsDownloading = true;
BackgroundWorker bgwDownloader = new BackgroundWorker();
bgwDownloader.DoWork += (sndr, evnt) =>
{
try
{
new Downloader().Download();
}
catch(Exception ex)
{
MessageBox.Show("An error occur during download. Please contact your system administrator.\n Exception: " +
ex.GetType().ToString() + "\nError Message:\n" + ex.Message + " Stack Trace:\n" + ex.StackTrace, "Download Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
};
bgwDownloader.RunWorkerCompleted += (sndr, evnt) =>
{
this.IsDownloading = false;
};
bgwDownloader.RunWorkerAsync();
}
}
But when I click the button btnDownload and the _isDownloading is set to true, and when the system time hit the 4:00 PM, the new Downloader().Download(); is executed again eventhough the _isDownloading is set to true. Why was it like this?
My code is in C#, framework 4, project is in winforms, build in Visual Studio 2010 Pro.
Your code is not testing against the volatile field - it is testing against isDownloading, which looks like a "local", but (because it is captured) is in fact a regular (non-volatile) field. So: either use some kind of memory barrier, or force that to be a volatile read. Or more simply: get rid of isDownloading completely, and check against the property.
Incidentally, the cache-defeating properties of volatile are not the intent of the keyword, but rather: a consequence. It'll work, but personally I'd suggest writing the code to work by intent rather than by consequence, perhaps using either a simple lock or something like Interlocked.