SpeechSynthesizer.SpeakAsync method not immediately speaking - c#

I am trying to use the SpeakAsync() method to speak some text. However, it doesn't start speaking anything until I call Speak(). I don't want to call Speak(). If I remove the Speak() method from this code nothing gets called at all:
using (SpeechSynthesizer synth = new SpeechSynthesizer())
{
synth.SelectVoice("ScanSoft Emily_Dri20_22kHz");
synth.Rate = 10;
synth.Volume = 100;
synth.SpeakAsync("oh, i'm a lumberjack and i'm okay! I sleep all night and I work all day!");
synth.SpeakAsync("If he was dying he wouldn't bother writing ah! He'd just say it!");
synth.Speak("i don't want to go on the cart.");
synth.SpeakAsync("We don't have a lord. We're an anarcho-syndicalist commune.");
synth.SpeakAsync("If you do not show us the grail, we shall take your castle by force!");
synth.Speak("what do you mean, an african swallow or a european swallow?");
UPDATE:
It appears other people are having this problem but no solution has been found yet:
other people having this problem

It's because Speak is a blocking call which keeps the program running. Since you're running this as a console application add Console.ReadKey(); at the end of your code to ensure that the application remains running until the user presses a key.
Otherwise, the main thread will exit because SpeakAsync returns immediately so your program is flying through all those lines and then exiting which is why you don't hear anything.
Update based on comments -
The using block is disposing the SpeechSynthesizer almost immediately which is why nothing can be heard. You can either place Console.ReadKey(); just before the closing brace of the using block or remove the using block and dispose of it manually later on.

Related

Reading StandardInput stops code execution without breaking application

Im using Stockfish game engine to power Human Vs Computer games.
Here is first part of the code:
Process _proc= new Process();
_proc.StartInfo = new ProcessStartInfo(path);
_proc.StartInfo.RedirectStandardInput = true;
_proc.StartInfo.RedirectStandardOutput = true;
_proc.StartInfo.UseShellExecute = false;
_proc.StartInfo.CreateNoWindow = true;
_proc.Start();
_proc.StandardInput.WriteLine("uci");
_proc.StandardInput.WriteLine("ucinewgame");
At this point everything is ok, but when I try to read StandardOutput something weird happens.
string result = _proc.StandardOutput.ReadToEnd();
Stockfish.exe program pops-up my application is running but code after that line is not executing. When I press pause, it points at this line:
If I use:
while (!_proc.StandardOutput.EndOfStream)
{
result += _proc.StandardOutput.ReadLine();
}
Same thing happens only at while statement. result has its full value there, all the text is written into it.
Is there any way to overcome this without async reading?
Side problem:
Since this is all part of singleton class that is used over whole ASP.NET application, i dont feel like using async reading since Im not sure how can I protect (with locking) multiple threads writing into it. Also, I dont know how to stop current thread since the processing of command can last up to 10 sec.
I don't feel like using Thread.Sleep() to constantly check for end of reading output, not elegant.
Considering side problem, how could i avoid multithread problems if async is only solution?
My threading knowledge is weak, so please have that in mind when giving thread related answers. Thank you.
The call to StandardOutput.ReadToEnd will block until this process ends. Is the goal here to read, process, and respond to various text commands from the process you spawn as you receive them?
You must approach this via asynchronous reading.
For example, you could setup a listener to Process.OutputDataReceived. Then call Process.BeginOutputReadLine to start reading. Your code will continue execution. Meanwhile, the .NET Framework will handle incoming text messages on a separate thread.

App.Current.Shutdown not letting DataSet.WriteXml complete results in corrupt config file

Environment - C#, .NET 4.0, WPF, VS2010
I have an app that uses a keyboard hook to detect when a combination of four keys is pressed. When this occurs it calls Configuration.Save(), which has a call to myConfigDataSet.WriteXml(myConfigFile). And then on the next line it calls App.Current.Shutdown().
About half the time it works as expected. But many times it would insert XML content right into the middle of a previously existing configuration file, resulting in corrupt data.
I was able to fix the above issue by using...
if(File.Exists(myConfigFile)) { File.Delete(myConfigFile) }
...on the line just above the call to myConfigDataSet.WriteXml(myConfigFile)
But now many times it just writes a 0KB size file. I am pretty sure that all of my problems are being caused by App.Current.Shutdown() not waiting for the call to myConfigDataSet.WriteXml(myConfigFile) to finish.
Shouldn't this call block execution until the file has been written to disk? ...apparently not!!!
As a workaround I've already tried inserting Thread.Sleep(1000) to create a 1 second delay just before App.Current.Shutdown. But now sometimes the app errors out with a "StackOverFlow" exception...!!!
What would you guys recommend as a fix or workaround for this? What am I doing wrong?
You can't stop a App.Current.Shutdown
Instead, use Application.Current.MainWindow.Close().
In this case, you can intercept in the Close event, process what you need to process, and then you could call App.Current.Shutdown
You can try to put the call to myConfigDataSet.WriteXml(myConfigFile) in a try/finally block. The finally block is executed completely even when the thread is aborted (see here). Not sure if it works with App.Current.Shutdown though.
So instead of:
myConfigDataSet.WriteXml(myConfigFile)
Do the following:
try {
// Empty...
} finally {
myConfigDataSet.WriteXml(myConfigFile)
}

Different LinqPad tabs acquires the same mutex?

I'm testing some threading code, and using LinqPad I noticed that I'm able to acquire the same named Mutex from two different LinqPad tabs. After diagnosing for I while I realized that it only happens in LinqPad and not in regular code.
Any help why it happens? AFAIK LinqPad uses different App Domains to execute each tab but I'm not sure how that should change anything since I'm using a named mutex.
Here's the code:
var mutexName = #"Global\TestMutex".Dump();
var createdNew = false;
var mtx = new Mutex(true, mutexName, out createdNew);
(createdNew ? "I own the mutex" : "I don't own the mutex").Dump();
mtx.WaitOne(); // Not really necessary
"I aquired the mutex".Dump();
string.Format("PID: {0} ThreadID: {1} AppDomainID: {2}",
Process.GetCurrentProcess().Id,
AppDomain.GetCurrentThreadId(),
AppDomain.CurrentDomain.Id).Dump();
Util.ReadLine();
Paste this code into two LinqPad tabs and it will consistently reproduce the issue, sometimes you'd have to stop and start the second tab though.
Your Mutex is being collected by the GC, so that the first program closes it before the second one starts.
Add GC.KeepAlive(mtx) after the ReadLine to force the Mutex to survive until then.

Alternative to Console.ReadLine() to keep the Console visible

Isn't there a better looking statement (or way) to keep the console from disappearing than the hackish Console.ReadLine() call. Something that's more expressive of the purpose of, more orthogonal to, keeping the Console visible ?
If you are still developing application you can run via Ctrl + F5 (Without debugging)
otherwise you can use Console.ReadKey() (same but there is no more option)
You can do:
Console.ReadKey();
Console.ReadLine() is not really hackish, your pausing the screen to wait for input. The input can either be a single key, or a string.
Update
One nice thing about the ReadKey() method is that it "waits, that is, blocks on the thread issuing the ReadKey method, until a character or function key is pressed." MSDN
This is different than ReadLine which takes in a string. Arguably, cleaner.
It depends on the context. If you're talking about running a command line, debugging through your code, and then being able to view the results on the console you have two options:
If you run with the debugger attached (f5), you must use Console.ReadLine
If you run without the debugger attached (ctrl + f5), it will stay open ... but then you obviously can't debug through.
I'm not sure why that's the default behavior, but there it is :-)
I usually use one of these:
Console.ReadKey(true); //You might want to put this in an infinite loop
new AutoResetEvent(false).WaitOne();
In VS You can also run (Ctrl + F5) the program (in distinction to running in debug) and it will add a system pause after it finishes executing.
I'd say that WaitOne, and just running (& not debugging) the program are your non-hackish options.
If you do want to debug, perhaps set a breakpoint at the last }.
Depends on what I am doing. If I am doing multi-threaded work and want my Console application to remain alive until all other work is done, I usually do something like this. (Similar to MasterMastic)
using System;
using System.Threading;
namespace Test_Console
{
class Program
{
static EventWaitHandle EWHandle;
static void Main(string[] args)
{
EWHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
Thread WorkThread = new Thread(new ThreadStart(DoStuff));
EWHandle.WaitOne();
}
static void DoStuff()
{
Console.WriteLine("Do what you want here");
EWHandle.Set();
}
}
}
Of course, there's always just using the regular breakpoints and the other debugging tools if that's what you're going for.

Process.CloseMainWindow() not working

I start the Windows On-Screen-Keyboard like that:
s_onScreenKeyboard = new Process();
s_onScreenKeyboard.StartInfo = new ProcessStartInfo("osk.exe");
s_onScreenKeyboard.EnableRaisingEvents = true;
s_onScreenKeyboard.Exited += new EventHandler(s_onScreenKeyboard_Exited);
s_onScreenKeyboard.Start();
This works fine, but when I try to stop it using the following code, it does not work, i.e. the OSK keeps running and the method returns false:
s_onScreenKeyboard.CloseMainWindow();
if (!s_onScreenKeyboard.HasExited)
{
if (!s_onScreenKeyboard.WaitForExit(1000))
{
s_onScreenKeyboard.Close();
//s_onScreenKeyboard.Kill();
}
}
When uncommenting s_onScreenKeyboard.Kill(); it is closed, but the problem is that osk.exe obviously uses another process called "msswchx.exe" which is not closed if I simply kill the OSK process. This way, I would end up with hundreds of these processes which is not what I want.
Another strange thing is that the CloseMainWindow() call worked at some time, but then it suddenly did not work anymore, and I do not remember what has changed.
Any ideas?
EDIT: I have found a solution myself. Please see my answer for details.
Background:
I am implementing an On-Screen-Keyboard for my application because it should work with a touchscreen. It is important that the keyboard layout matches the layout which is configured in Windows since the application will be shipped to many different countries. Therefore, instead of implementing a custom keyboard control with approx. 537 keyboard layouts (exaggerating a little here...), I wanted to utilize the Windows built-in On-Screen-Keyboard which adapts to the selected keyboard layout automatically, saving a lot of work for me.
I have found the/a solution myself:
When I successfully retrieve the MainWindowHandle after the process has been started, the call to CloseMainWindow() is also successful later on. I do not understand the reason for this, but the important thing is: it works!
BTW, for others having the same problem: The MainWindowHandle is not available immediately after starting the process. Obviously, it takes some milliseconds until the MainWindow is started which is why I use the following code to retrieve the handle:
DateTime start = DateTime.Now;
IntPtr handle = IntPtr.Zero;
while (handle == IntPtr.Zero && DateTime.Now - start <= TimeSpan.FromSeconds(2))
{
try
{
// sleep a while to allow the MainWindow to open...
System.Threading.Thread.Sleep(50);
handle = s_onScreenKeyboard.MainWindowHandle;
}
catch (Exception) { }
}
In this code I continuously get the MainWindowHandle every ~50ms as long as it is still equal to IntPtr.Zero. If the handle could not be retrieved after 2 seconds, I quit the loop to avoid an endless loop in case of error.
You need to wait untill the process finishes initialization, run
Process.WaitForInputIdle Method in order to do that.

Categories