0

I am creating a DIY virtual assistant for fun and exercise in python. I run into a problem when trying to use engine.say in a thread and then use it again in my main program.

I already tried to use engine.endLoop() and other possible solutions from pyttsx docs (engine.stop(), engine.endLoop() etc) but still i didn't make it work. I have seen in some answers about asyncio. But with pip i can't install it and i am not very certain that it will solve my problem.

The Functions:

def portport():

        ser = serial.Serial('COM4',9600)
        raw_data = ser.read(9)
        msg = str(raw_data[3:8])
        print msg
        ser.close()
        return msg

def Comm_Connection():

    print("CommConns started")

    while True:
        global conn

        try:
            conn, addr = SERVER.accept()
            Live_Conns.append(conn)

            Server_Send = "Connection established successfully"
            Server_Send = pickle.dumps(Server_Send)
            Live_Conns[-1].send(Server_Send)

            temp = conn.recv(1024)
            Server_Receive = pickle.loads(temp)

            Live_Name.append(Server_Receive)

            Connections = (Live_Name[-1], "Connected")

            engine.say(Connections)
            engine.runAndWait()

        except socket.error as socketerror:
            continue
        except socket.timeout:
            continue

The "Main" program:

Server_Up = threading.Thread(target = Comm_Connection)
Server_Up.start()

while True:  
    engine = pyttsx.init()  

    time.sleep(7)
    engine.say("Goodmorning")
    engine.runAndWait() 

And the error i get:

raise RuntimeError('run loop already started')

RuntimeError: run loop already started

Jim Noulis
  • 13
  • 3
  • 6

3 Answers3

2

It looks like your while True loop is trying to start and run the pyttsx engine at the same time it's being operated inside the Comm_Connection loop.

Note that pyttsx uses its own internal engine that supports callbacks and manual iteration, so you might consider rewriting your app more along the lines of the following example modified from the docs:

engine = pyttsx3.init()
engine.say('The quick brown fox jumped over the lazy dog.', 'fox')
engine.startLoop(False)
# engine.iterate() must be called inside Server_Up.start()
Server_Up = threading.Thread(target = Comm_Connection)
Server_Up.start()
engine.endLoop()

Disclaimer: I've played around enough with this library to know that the manual iteration approach does work, but not enough to understand your particular needs, so YMMV.

nthmost
  • 151
  • 5
1

As this is a common question and I figured out a solution for this for my program. To use a private variable to judge if the loop is already started and then end it if it is using engine._inLoop -

while True:  
    engine = pyttsx.init()  

    time.sleep(7)
    engine.say("Goodmorning")
    engine.runAndWait() 

    if engine._inLoop:
        engine.endLoop()
tom
  • 11
  • 1
0

first of all install pyttsx3 with pip uninstall pyttsx pip install pyttsx3 and then try this

while True:  
    engine = pyttsx3.init()  

    time.sleep(7)
    engine.say("Goodmorning")
    engine.runAndWait() 
    engine = None

you are defining engine = pyttsx.init()in the loop every time so it will say that the loop is already started but if you define engine = None for every iteration it will work at least it did for me

Armin P
  • 1
  • 1