0

I have two threads concurrently running, speechRecognition and speakBack. Both of these threads are run in while loops (while True: #do something). Speech recognition is constantly waiting for microphone input. Then, once it is received, it saves the text version of the verbal input to a file, which is loaded by my second thread, speakBack, and spoken through the speakers. My issue is that when the phrase is spoken through the speakers, it is picked up by the microphone and then translated and once again saved to this file to be processed, resulting in an endless loop.

How can i make the speechRecognition thread suspend itself, wait for the speakBack thread to stop outputting sound through the speakers, and then continue listening for the next verbal input? Im using the speechRecognition library and the pyttsx3 library for speech recognition and verbal ouput respectively.

carbaretta
  • 303
  • 1
  • 6

1 Answers1

1

The way to do this is to have shared state between the threads (either with global variables that the threads can store into and read from to indicate their progress, or with a mutable reference that is passed into each thread). The solution I’ll give below involves a global variable that stores a mutable reference, but you could just as easily pass the queue into both threads instead of storing it globally.

Using queues is a very standard way to pass messages between threads in python, because queues are already written in a thread-safe way that makes it so you don’t have to think about synchronization and locking. Furthermore, the blocking call to queue.get is implemented in a way that doesn’t involve repeatedly and wastefully checking a condition variable in a while loop.

Here’s how some code might look:

import queue

START_SPEAK_BACK = 0
START_SPEECH_RECOGNITION = 1
messageQueue = queue.Queue()

# thread 1
def speechRecognition():
  while True:
    # wait for input like you were doing before
    # write to file as before
    # put message on the queue for other thread to get
    messageQueue.put(START_SPEAK_BACK)
    # Calling `get` with no arguments makes the call be
    # "blocking" in the sense that it won't return until
    # there is an element on the queue to get.
    messageFromOtherThread = messageQueue.get()
    # logically, messageFromOtherThread can only ever be
    # START_SPEECH_RECOGNITION, but you could still
    # check that this is true and raise an exception if not.

# thread 2
def speakBack():
  while True:
    messageFromOtherThread = messageQueue.get()
    # likewise, this message will only be START_SPEAK_BACK
    # but you could still check.
    # Here, fill in the code that speaks through the speakers.
    # When that's done:
    messageQueue.put(START_SPEECH_RECOGNITION)

Some comments:

  1. This solution uses a single queue. It could just have easily used two queues, one for speakBack —> speechRecognition communication and the other for speechRecognition —> communication. This might make more sense if the two threads were generating messages concurrently.

  2. This solution doesn’t actually involve inspecting the contents of the messages. However, if you need to pass additional information between threads, you could very easily pass objects or data as messages (instead of just constant values)

  3. Finally, it’s not clear to me why you don’t just run all code in the same thread. It seems like there’s a very clear (serial) series of steps you want your program to follow: get audio input, write it to file, speak it back, start over. It might make more sense to write everything as a normal, serial, threadless python program.

Nick
  • 1,038
  • 9
  • 10