I can get the proper results by using python's built in Queue class:
import pyttsx
from Queue import Queue
from threading import Thread
q = Queue()
def say_loop():
engine = pyttsx.init()
while True:
engine.say(q.get())
engine.runAndWait()
q.task_done()
def another_method():
t = Thread(target=say_loop)
t.daemon = True
t.start()
for i in range(0, 3):
q.put('Sally sells seashells by the seashore.')
print "end of another method..."
def third_method():
q.put('Something Something Something')
if __name__=="__main__":
another_method()
third_method()
q.join() # ends the loop when queue is empty
Above is a simple example I whipped up. It uses the 'queue/consumer' model to allow separate functions/classes to access the same queue, then a worker that will execute anytime the queue has items. Should be pretty easy to adapt to your needs.
Further reading about Queues: https://docs.python.org/2/library/queue.html
There appears to be an interface for this in the docs you linked to, but it seemed like you were already on the separate thread track so this seemed closer to what you wanted.
And here's the modified version of your code:
import pyttsx
from Queue import Queue
import threading
class VoiceAssistant(threading.Thread):
def __init__(self):
super(VoiceAssistant, self).__init__()
self.engine = pyttsx.init()
self.q = Queue()
self.daemon = True
def add_say(self, msg):
self.q.put(msg)
def run(self):
while True:
self.engine.say(self.q.get())
self.engine.runAndWait()
self.q.task_done()
if __name__ == '__main__':
va = VoiceAssistant()
va.start()
for i in range(0, 3):
va.add_say('Sally sells seashells by the seashore.')
print "now we want to exit..."
va.q.join() # ends the loop when queue is empty