Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threading problems with OS X #7

Open
mrmekon opened this issue Dec 8, 2011 · 1 comment
Open

Threading problems with OS X #7

mrmekon opened this issue Dec 8, 2011 · 1 comment

Comments

@mrmekon
Copy link

mrmekon commented Dec 8, 2011

PyTTSX does not seem to work in a python thread in OS X. The exact failure depends on whether PyGTK is also in use.

I am initializing a pyttsx engine:
engine = pyttsx.Engine()

And trying to speak in an infinite loop:

    while True:
        text = "Say something, say something, anything."
        engine.say(text)
        engine.runAndWait()

I have tried this with and without PyGTK, and both in its own thread and in the main python thread. I have encountered a number of different results.

A demo is available here: https://gist.github.com/1447666

In second thread, no GTK

Setup:
I do NOT import gtk or gobject. I execute the above code in a thread using Python's threading.Thread() class.

Execution result:
The text is spoken one time, and then the program hangs.

Trace results:
The queue in pyttsx's driver.py "pumps" one time, gets the text out, and speaks it. The queue never "pumps" again, so the self._engine.endLoop() function never runs. The thread hangs forever.

In second thread, with GTK

Setup:
I import gtk and gobject, run gobject.threads_init(), and run gtk.main(). The above code is run in a thread.

Execution result:
The text is spoken once, and then the program exits.

Trace result:
PyTTSX's nsss.py driver calls AppHelper.runConsoleEventLoop(). When the speech is complete, self._engine.endLoop() IS removed from the queue and executes, which calls AppHelper.stopEventLoop(). In PyObjC's AppHelper, stopEventLoop() gets None for PyObjCAppHelperRunLoopStopper.currentRunLoopStopper(), and it responds by calling NSApp()._terminate(), which kills the entire application and all threads.

In main thread, with GTK

Setup:
I import gtk and gobject. I do NOT run gtk.main(). The above code is run in the main thread, no secondary thread is started.

Execution result:
The text is spoken once, and then the program exits.

Trace results:
I did not trace this case, but I can tell it is different from the others (I have print statements all throughout my pyttsx and pyobjc modules -- this case takes a different path). Notably, it does not hang forever (endLoop() is called and the queue is empty), and it is not terminated by stopEventLoop().

@parente
Copy link
Collaborator

parente commented Aug 9, 2013

I doubt pyttsx is thread safe because the underlying libs are unlikely thread safe.

Another user found using a separate process for pyttsx avoids some bad interactions with event loops and threads. See issue #11.

You could also try scheduling calls to engine.iterate in a gtk idle callback. engine.runAndWait is definitely not what you want on the main thread because it enters an infinite loops. iterate() executes just one iteration of the loop which should allow another event loop (e.g., gtk's) to pump the pyttsx command queue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants