Can't enable a Timer in a Speech Recognized handler

P

Peter Oliphant

Note that although this involves SAPI, it is more a question about Timers
and event handlers.

I wrote a Speech Recognize handler (SAPI), and put some code in it to enable
a Timer. It would not do it. If I bring this same code outside this event
handler, it works just fine.

Is this normal?
 
D

David Lowndes

Note that although this involves SAPI, it is more a question about Timers
and event handlers.

I wrote a Speech Recognize handler (SAPI), and put some code in it to enable
a Timer. It would not do it. If I bring this same code outside this event
handler, it works just fine.

And the code you've used it what?

You need to tell us a bit more!

Dave
 
B

Ben Voigt [C++ MVP]

Peter Oliphant said:
Note that although this involves SAPI, it is more a question about Timers
and event handlers.

I wrote a Speech Recognize handler (SAPI), and put some code in it to
enable a Timer. It would not do it. If I bring this same code outside this
event handler, it works just fine.

Is this normal?

Which "Timer"? .NET has at least three different classes named Timer.
 
P

Peter Oliphant

I wish this newsgroup had an ability to at least attach a text file with
code. My code to demonstrate this situation is too long, and this newsgroup
tends to reformat the text in a bad way if the line is too long.

But, I'll try to explain it a bit more. Assume in the following that 'timer'
is set up with an interval and event handler:

System::Windows::Forms::Timer^ timer = gcnew Timer() ;

void Handler( Object^, SpeechRecognizedEventArgs^ e )
{
timer->Enable ; // problem!
}

That is, if I try to launch a timer inside the 'recognized speech' handler
it doesn't enable the timer. I believe it also locks out the timer from then
on (timer no longer responds to any commands). If this code is placed
outside of the handler, it launches the timer just fine.

FYI, using MS VS VC++ 2008 Express (Beta 2) with .NET Framework 3.5 on a
Vista machine. (SAPI 5.3 ala Vista). Managed (/cli) code generation.

I have a workaround, but it's not wonderful. I create an external 'master'
timer that polls whether other timers should be turned on via their
individual flags, and then set the flag of the timer to be launched in the
above handler instead. The disadvantage of course is that this adds an
unpredictable additonal lag (since it can make the request by setting the
timer flag at any point in the master timer's interval), although it is
short by human terms.

I tried moving this to the Recognition Completed handler of the speech
recognizer thinking perhaps it was the extensive recognition processing that
caused the problem. But that handler won't launch a timer either.

Hope that helps in the info department. This could be a problem or a
feature. If a problem, it could be part of SAPI or VC++.It could be a bug in
my code, but I've seen this happen two different ways (or NOT happeneing, if
you will), so this is not likely. I'm wondering if it is just disallowed in
general to launch a System Timer from an (any?) event handler. Can a Timer
handler launch another Timer, for instance?

Don't hesitate to ask if you want some specific questions asked...

Thanks!

[==Peter==]
 
D

David Lowndes

But, I'll try to explain it a bit more. Assume in the following that 'timer'
is set up with an interval and event handler:

System::Windows::Forms::Timer^ timer = gcnew Timer() ;

void Handler( Object^, SpeechRecognizedEventArgs^ e )
{
timer->Enable ; // problem!

Is that actually:
timer->Enabled = true;
?
That is, if I try to launch a timer inside the 'recognized speech' handler
it doesn't enable the timer.

Is there any sign of an exception being raised in the output window?
If this code is placed
outside of the handler, it launches the timer just fine.

So are you saying that if you just call timer->Enabled = true; for
that same timer object from elsewhere in your code (with no other
changes), it's OK? I'm stumped in that case. I don't know enough about
the timer implementation to offer an explanation of that behaviour.

Dave
 
W

William DePalo [MVP VC++]

Peter Oliphant said:
Hope that helps in the info department. This could be a problem or a
feature. If a problem, it could be part of SAPI or VC++.It could be a bug
in my code, but I've seen this happen two different ways (or NOT
happeneing, > if you will), so this is not likely. I'm wondering if it is
just disallowed in general to launch a System Timer from an (any?) event
handler. Can a Timer handler launch another Timer, for instance?

I'd bet a few cents that the "bug" is not in SAPI. Of course, I could be
wrong.

I don't know that it is your problem, but every time that I've seen people
report "problems" in the SAPI groups with "events" not firing it has to do
with the fact that the host application does not pump messages. Underlying
SAPI is all that COM gunk which persists in using window messages as an IPC
mechanism in the 21st century which I think (I should point out that I'm on
the lunatic fringe*) should have gone out with 16 bit Windows.

That said, I don't know what the speech classes in the .Net framework do.
Mine wrap native C++/Win32 code. ;-)

Regards,
Will
www.ivrforbeginners.com

* In my own native SAPI applications I use a Win32 synchronization object -
an event handle - to signal the completion of operations so that I don't
have to punp messages. It's a lot more work.
 
P

Peter Oliphant

Is that actually:
timer->Enabled = true;

yup, typo. Not lifted from my code since it's too big, so I just did that
from memory. :)
Is there any sign of an exception being raised in the output window?

Nope, it just does nothing. However, future attempts to use the timer no
longer work from anywhere.
So are you saying that if you just call timer->Enabled = true; for
that same timer object from elsewhere in your code (with no other
changes), it's OK? I'm stumped in that case. I don't know enough about
the timer implementation to offer an explanation of that behaviour

Yup. One possibility is this is just not allowed. An event is probably
similar to an 'interrupt', and some things can be dangerous if launched from
them. That's my guess.

I might try to write a truly reduced version of this behavior and post the
results to make sure it's not ME... :)

[==Peter==]
 
P

Peter Oliphant

I'd bet a few cents that the "bug" is not in SAPI. Of course, I could be

I've programmed long enough that I have the exact same instincts. I first
and foremost assume it's a problem either with a bug/typo in my code or a
misconception on my part (usually due to incomplete information on the
subject).

But this seems pretty cut and dried. I took the code that the event executes
(which I saw it get to ala a breakpoint experiment), took it outside the
event, and it worked perfectly. Inside, it doesn't launch the timer and the
timer no longer works. And no errors are ever reported in build or
execution.

It just might be a restrictions to what can be done in an event (since it is
like an interrupt). But it seems kind of weird that a Timer can't be
launched from event handlers (maybe any event handler, anyone have a
counter-example?). The only thing that makes me wonder about this is that no
errors are ever reported and it hangs the timer instead of doing absolutely
nothing. If this was intended behavior (on non-behavior if you will), I
would think it would do one or not the other.

Tonight I might build a tiny project that demonstrates this behavior, and
I''ll report back if this is true or if I'm an idiot (of course those are
not mutually exclusive possibilities...lol)...

[==Peter==]
 
P

Peter Oliphant

OK, I've duplicated the problem in a little bit of code. I've put it below,
you must excuse any line-wrap.

If you want to see, create a console project.Place the code I have below the
Project.CPP file (the one with main()).

Be sure to add System.Speech as a reference, and set it up tp target .NET
Framework 3.5. This code will also likely only work on a Windows VISTA
machine (SAPI 5.3).

Describing the code:

In a 'globals' class it creates a Timer and a SpeechRecognitionEngine (that
recognizes 'yes' or 'no'). Say 'yes' or 'no' into the microphone, and he
Engine's Completed handler writes 'enable timer' to the console and enables
the timer. The Timer should after that write 'tick!' to the display 4 times
a second after that.

What happens is that you will see the 'enable timer' message, proving the
Completed handler fired and enabled Timer, but the 'Tick's never show up
indicating the Timer never fires!

Thus, whether a restriction or a bug, a Timer can't be enabled successfully
in any Speech Recognition event handler (this happens with all of them, I'm
just demonstrting Completed here).

Here is the code:

//------------------------

#include "stdafx.h"

#using <mscorlib.dll>
#using <System.DLL>
#using <System.Windows.Forms.DLL>

using namespace System::Windows::Forms ;
using namespace System ;
using namespace System::Speech::Recognition ;

typedef EventHandler<RecognizeCompletedEventArgs^> Speech_Completed_Handler
;
typedef System::Windows::Forms::Timer System_Timer ;

ref class globals
{
public:
static globals()
{
Timer = gcnew System::Windows::Forms::Timer() ;
Timer->Tick += gcnew EventHandler(&globals::Tick_Handler ) ;
Timer->Interval = 100 ;
Engine = gcnew SpeechRecognitionEngine() ;
Engine->SetInputToDefaultAudioDevice() ;
Engine->RecognizeCompleted += gcnew Speech_Completed_Handler(
&globals::Completed_Handler ) ;
Choices^ choices = gcnew Choices ;
choices->Add( "yes" ) ;
choices->Add("no" ) ;
Grammar^ grammar = gcnew Grammar(choices) ;
Engine->LoadGrammar(grammar) ;
}

static void Completed_Handler(Object^,RecognizeCompletedEventArgs^)
{
Console::WriteLine( "enable timer" ) ;
Timer->Enabled = true ;
}

static void Tick_Handler( System::Object^,EventArgs^ )
{
Console::WriteLine( "tick!" ) ;
}

static SpeechRecognitionEngine^ Engine ;
static System::Windows::Forms::Timer^ Timer ;
} ;

int main(array<System::String ^> ^args)
{
Console::WriteLine("Speak!");
globals::Engine->RecognizeAsync() ;
Form^ form = gcnew Form() ;
Application::Run( form ) ;
return 0;
}

//------------------------

[==Peter==]
 
P

Peter Oliphant

I've noticed something, so here's some more info on the behavior. This
message comes up in the Ouput window instead of the Timer firing:

"Loaded 'C:\Windows\System32\msxml3.dl"
"First-chance exception at 0x7611b09e in PAO_Recognition_Quirk.exe:
0x0000071A: The remote procedure call was cancelled."

[PAO_Recognition_Quirk.exe is the exacutable file's name for the project]

which I believe this is somehow telling me that my Timer is no-workie... :)

[==Peter==]

Peter Oliphant said:
OK, I've duplicated the problem in a little bit of code. I've put it
below, you must excuse any line-wrap.

If you want to see, create a console project.Place the code I have below
the Project.CPP file (the one with main()).

Be sure to add System.Speech as a reference, and set it up tp target .NET
Framework 3.5. This code will also likely only work on a Windows VISTA
machine (SAPI 5.3).

Describing the code:

In a 'globals' class it creates a Timer and a SpeechRecognitionEngine
(that recognizes 'yes' or 'no'). Say 'yes' or 'no' into the microphone,
and he Engine's Completed handler writes 'enable timer' to the console and
enables the timer. The Timer should after that write 'tick!' to the
display 4 times a second after that.

What happens is that you will see the 'enable timer' message, proving the
Completed handler fired and enabled Timer, but the 'Tick's never show up
indicating the Timer never fires!

Thus, whether a restriction or a bug, a Timer can't be enabled
successfully in any Speech Recognition event handler (this happens with
all of them, I'm just demonstrting Completed here).

Here is the code:

//------------------------

#include "stdafx.h"

#using <mscorlib.dll>
#using <System.DLL>
#using <System.Windows.Forms.DLL>

using namespace System::Windows::Forms ;
using namespace System ;
using namespace System::Speech::Recognition ;

typedef EventHandler<RecognizeCompletedEventArgs^>
Speech_Completed_Handler ;
typedef System::Windows::Forms::Timer System_Timer ;

ref class globals
{
public:
static globals()
{
Timer = gcnew System::Windows::Forms::Timer() ;
Timer->Tick += gcnew EventHandler(&globals::Tick_Handler ) ;
Timer->Interval = 100 ;
Engine = gcnew SpeechRecognitionEngine() ;
Engine->SetInputToDefaultAudioDevice() ;
Engine->RecognizeCompleted += gcnew Speech_Completed_Handler(
&globals::Completed_Handler ) ;
Choices^ choices = gcnew Choices ;
choices->Add( "yes" ) ;
choices->Add("no" ) ;
Grammar^ grammar = gcnew Grammar(choices) ;
Engine->LoadGrammar(grammar) ;
}

static void Completed_Handler(Object^,RecognizeCompletedEventArgs^)
{
Console::WriteLine( "enable timer" ) ;
Timer->Enabled = true ;
}

static void Tick_Handler( System::Object^,EventArgs^ )
{
Console::WriteLine( "tick!" ) ;
}

static SpeechRecognitionEngine^ Engine ;
static System::Windows::Forms::Timer^ Timer ;
} ;

int main(array<System::String ^> ^args)
{
Console::WriteLine("Speak!");
globals::Engine->RecognizeAsync() ;
Form^ form = gcnew Form() ;
Application::Run( form ) ;
return 0;
}

//------------------------

[==Peter==]

Ben Voigt said:
Which "Timer"? .NET has at least three different classes named Timer.
 
P

Peter Oliphant

"Which "Timer"? .NET has at least three different classes named Timer. "

I got to thinking. Maybe this is the problem. Maybe I'm using the wrong
flavor of Timer. I'm using the System::Windows::Form::Timer, which now that
I think of it, is an 'old' Timer class.

Is there maybe a new-and-improved managed Timer class I should look at? I
All I need is one I can enable and disable, set its interval in
milliseconds, and for it to have tick event. I guess to distinguish it I
need it's full 'namespace' and any headers required.

Thanks!

[==Peter==]


[==Peter==]
 
D

David Lowndes

I've noticed something, so here's some more info on the behavior. This
message comes up in the Ouput window instead of the Timer firing:

"Loaded 'C:\Windows\System32\msxml3.dl"
"First-chance exception at 0x7611b09e in PAO_Recognition_Quirk.exe:
0x0000071A: The remote procedure call was cancelled."

Is the SAPI callback run on a different thread perhaps?

Dave
 
P

Peter Oliphant

"> Is the SAPI callback run on a different thread perhaps?"

The code I listed is the entire program. I didn't setup anything specific
except making sure it targets .NET Framework 3.5 and making System::Speech a
reference. And this must be run on a machine using Windows Vista, but might
work on an XP machine for which SAPI has been manually installed.

So to answer your question, I don't really know, but I didn't write anything
special to run it in a separate thread if that is what is happening.

[==Peter==]
 
D

David Lowndes

"> Is the SAPI callback run on a different thread perhaps?"
So to answer your question, I don't really know

You can find out if you run it under the debugger and check what
thread is active when you hit the callback.

I was offering it as a suggestion as to the cause of the error which I
originally suspected might have been showing up in the output window.

Dave
 
P

Peter Oliphant

You can find out if you run it under the debugger and check what
thread is active when you hit the callback.

Where do I look in the GUI (during a debug session) to find this
information? How is a thread identified/distinguished (to determine 'what
thread' I need to know how a thread is represented: thread 1? thread A?
thread ???), Should I set a breakpoint in the callback and then look for it?
And I assume you mean the RecognitionCompleted callback since the Tick
callback never fires.

Can't do this till I get home tonight since my work computer isn't a Vista
machine... :)
I was offering it as a suggestion as to the cause of the error which I
originally suspected might have been showing up in the output window.

Cool. And thanks for taking the time to respond, too! :)

[==Peter==]
 
D

David Lowndes

Where do I look in the GUI (during a debug session) to find this
information? How is a thread identified/distinguished (to determine 'what
thread' I need to know how a thread is represented: thread 1? thread A?
thread ???), Should I set a breakpoint in the callback and then look for it?

Yes, that's right - use the Threads pane.
And I assume you mean the RecognitionCompleted callback since the Tick
callback never fires.

Yes - that's where I'd assume setting the Enabled property might be
throwing an exception.

Dave
 
B

Ben Voigt [C++ MVP]

Peter Oliphant said:
OK, I've duplicated the problem in a little bit of code. I've put it
below, you must excuse any line-wrap.

If you want to see, create a console project.Place the code I have below
the Project.CPP file (the one with main()).

Be sure to add System.Speech as a reference, and set it up tp target .NET
Framework 3.5. This code will also likely only work on a Windows VISTA
machine (SAPI 5.3).

Describing the code:

In a 'globals' class it creates a Timer and a SpeechRecognitionEngine
(that recognizes 'yes' or 'no'). Say 'yes' or 'no' into the microphone,
and he Engine's Completed handler writes 'enable timer' to the console and
enables the timer. The Timer should after that write 'tick!' to the
display 4 times a second after that.

What happens is that you will see the 'enable timer' message, proving the
Completed handler fired and enabled Timer, but the 'Tick's never show up
indicating the Timer never fires!

What if you enable the Timer before starting recognition? Do ticks stop
arriving when you enable the recognition engine? Could your tick handler
check a shared variable and immediately return in order to emulate disabling
the timer?
Thus, whether a restriction or a bug, a Timer can't be enabled
successfully in any Speech Recognition event handler (this happens with
all of them, I'm just demonstrting Completed here).

Here is the code:

//------------------------

#include "stdafx.h"

#using <mscorlib.dll>
#using <System.DLL>
#using <System.Windows.Forms.DLL>

using namespace System::Windows::Forms ;
using namespace System ;
using namespace System::Speech::Recognition ;

typedef EventHandler<RecognizeCompletedEventArgs^>
Speech_Completed_Handler ;
typedef System::Windows::Forms::Timer System_Timer ;

ref class globals
{
public:
static globals()
{
Timer = gcnew System::Windows::Forms::Timer() ;
Timer->Tick += gcnew EventHandler(&globals::Tick_Handler ) ;
Timer->Interval = 100 ;
Engine = gcnew SpeechRecognitionEngine() ;
Engine->SetInputToDefaultAudioDevice() ;
Engine->RecognizeCompleted += gcnew Speech_Completed_Handler(
&globals::Completed_Handler ) ;
Choices^ choices = gcnew Choices ;
choices->Add( "yes" ) ;
choices->Add("no" ) ;
Grammar^ grammar = gcnew Grammar(choices) ;
Engine->LoadGrammar(grammar) ;
}

static void Completed_Handler(Object^,RecognizeCompletedEventArgs^)
{
Console::WriteLine( "enable timer" ) ;
Timer->Enabled = true ;
}

static void Tick_Handler( System::Object^,EventArgs^ )
{
Console::WriteLine( "tick!" ) ;
}

static SpeechRecognitionEngine^ Engine ;
static System::Windows::Forms::Timer^ Timer ;
} ;

int main(array<System::String ^> ^args)
{
Console::WriteLine("Speak!");
globals::Engine->RecognizeAsync() ;
Form^ form = gcnew Form() ;
Application::Run( form ) ;
return 0;
}

//------------------------

[==Peter==]

Ben Voigt said:
Which "Timer"? .NET has at least three different classes named Timer.
 
P

Peter Oliphant

What if you enable the Timer before starting recognition? Do ticks stop
arriving when you enable the recognition engine?

The Timer runs fine unless I try to use it in the event handler. That is,
any running Timer is not effected by the recognition event handler firing,
but trying to do something with a Timer inside such a handler does.
Could your tick handler check a shared variable and immediately return in
order to emulate disabling the timer?

Indeed, this is how I do it. But of course this isn't as immediate, but so
far works for my purposes. While this is a 'work around' that works, it
still seems odd that one can't launch (i.e., enable successfully) a Timer
inside recognition handlers. If this is a bug, I'd rather not have to create
the delayed infostructure I have and enable the Timer directly. If this is a
'feature' (ala it is intended behaviour), then I'll stick with the work
around.

[==Peter==]

Ben Voigt said:
Peter Oliphant said:
OK, I've duplicated the problem in a little bit of code. I've put it
below, you must excuse any line-wrap.

If you want to see, create a console project.Place the code I have below
the Project.CPP file (the one with main()).

Be sure to add System.Speech as a reference, and set it up tp target .NET
Framework 3.5. This code will also likely only work on a Windows VISTA
machine (SAPI 5.3).

Describing the code:

In a 'globals' class it creates a Timer and a SpeechRecognitionEngine
(that recognizes 'yes' or 'no'). Say 'yes' or 'no' into the microphone,
and he Engine's Completed handler writes 'enable timer' to the console
and enables the timer. The Timer should after that write 'tick!' to the
display 4 times a second after that.

What happens is that you will see the 'enable timer' message, proving the
Completed handler fired and enabled Timer, but the 'Tick's never show up
indicating the Timer never fires!

What if you enable the Timer before starting recognition? Do ticks stop
arriving when you enable the recognition engine? Could your tick handler
check a shared variable and immediately return in order to emulate
disabling the timer?
Thus, whether a restriction or a bug, a Timer can't be enabled
successfully in any Speech Recognition event handler (this happens with
all of them, I'm just demonstrting Completed here).

Here is the code:

//------------------------

#include "stdafx.h"

#using <mscorlib.dll>
#using <System.DLL>
#using <System.Windows.Forms.DLL>

using namespace System::Windows::Forms ;
using namespace System ;
using namespace System::Speech::Recognition ;

typedef EventHandler<RecognizeCompletedEventArgs^>
Speech_Completed_Handler ;
typedef System::Windows::Forms::Timer System_Timer ;

ref class globals
{
public:
static globals()
{
Timer = gcnew System::Windows::Forms::Timer() ;
Timer->Tick += gcnew EventHandler(&globals::Tick_Handler ) ;
Timer->Interval = 100 ;
Engine = gcnew SpeechRecognitionEngine() ;
Engine->SetInputToDefaultAudioDevice() ;
Engine->RecognizeCompleted += gcnew Speech_Completed_Handler(
&globals::Completed_Handler ) ;
Choices^ choices = gcnew Choices ;
choices->Add( "yes" ) ;
choices->Add("no" ) ;
Grammar^ grammar = gcnew Grammar(choices) ;
Engine->LoadGrammar(grammar) ;
}

static void Completed_Handler(Object^,RecognizeCompletedEventArgs^)
{
Console::WriteLine( "enable timer" ) ;
Timer->Enabled = true ;
}

static void Tick_Handler( System::Object^,EventArgs^ )
{
Console::WriteLine( "tick!" ) ;
}

static SpeechRecognitionEngine^ Engine ;
static System::Windows::Forms::Timer^ Timer ;
} ;

int main(array<System::String ^> ^args)
{
Console::WriteLine("Speak!");
globals::Engine->RecognizeAsync() ;
Form^ form = gcnew Form() ;
Application::Run( form ) ;
return 0;
}

//------------------------

[==Peter==]

Ben Voigt said:
Note that although this involves SAPI, it is more a question about
Timers and event handlers.

I wrote a Speech Recognize handler (SAPI), and put some code in it to
enable a Timer. It would not do it. If I bring this same code outside
this event handler, it works just fine.

Is this normal?

Which "Timer"? .NET has at least three different classes named Timer.
 
B

Ben Voigt [C++ MVP]

Peter Oliphant said:
The Timer runs fine unless I try to use it in the event handler. That is,
any running Timer is not effected by the recognition event handler firing,
but trying to do something with a Timer inside such a handler does.


Indeed, this is how I do it. But of course this isn't as immediate, but so
far works for my purposes. While this is a 'work around' that works, it
still seems odd that one can't launch (i.e., enable successfully) a Timer
inside recognition handlers. If this is a bug, I'd rather not have to
create the delayed infostructure I have and enable the Timer directly. If
this is a 'feature' (ala it is intended behaviour), then I'll stick with
the work around.

Could you print out the value of the InvokeRequired property of your timer,
seen inside the recognition handler?
[==Peter==]
 
P

Peter Oliphant

I've been using System::Windows::Forms::Timer, which doesn't have an
'InvokeRequired' property.

I'm thinking I'm using the wrong Timer class. I'll look for others in MSDN.
Not sure how to look up different classes with the same name though. The one
I use isn't managed. I'd rather use a managed one, as long as it can have an
Interval in milliseconds, a means to turn it on and off, and a way to give
it an event handler (hopefully via delegates).

Not sure that has anything to do with it, but it could...

[==Peter==]

Ben Voigt said:
Peter Oliphant said:
The Timer runs fine unless I try to use it in the event handler. That is,
any running Timer is not effected by the recognition event handler
firing, but trying to do something with a Timer inside such a handler
does.


Indeed, this is how I do it. But of course this isn't as immediate, but
so far works for my purposes. While this is a 'work around' that works,
it still seems odd that one can't launch (i.e., enable successfully) a
Timer inside recognition handlers. If this is a bug, I'd rather not have
to create the delayed infostructure I have and enable the Timer directly.
If this is a 'feature' (ala it is intended behaviour), then I'll stick
with the work around.

Could you print out the value of the InvokeRequired property of your
timer, seen inside the recognition handler?
[==Peter==]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top