Listen for speech continuously while your program does other work
Background listening allows your application to continuously monitor audio input while performing other tasks. This is perfect for voice-controlled applications, voice assistants, or any program that needs to respond to voice commands without blocking.
Here’s a complete script demonstrating background listening:
background_listening.py
import timeimport speech_recognition as sr# This is called from the background threaddef callback(recognizer, audio): # Received audio data, now recognize it try: text = recognizer.recognize_google(audio) print("Google Speech Recognition thinks you said " + text) except sr.UnknownValueError: print("Google Speech Recognition could not understand audio") except sr.RequestError as e: print("Could not request results from Google Speech Recognition service; {0}".format(e))# Create recognizer and microphone instancesr = sr.Recognizer()m = sr.Microphone()# Calibrate once before startingwith m as source: r.adjust_for_ambient_noise(source) # we only need to calibrate once# Start listening in the background# Note: we don't have to do this inside a `with` statementstop_listening = r.listen_in_background(m, callback)# `stop_listening` is now a function that, when called, stops background listening# Do some unrelated computations for 5 secondsfor _ in range(50): time.sleep(0.1) # we're still listening even though the main thread is doing other things# Calling this function requests that the background listener stop listeningstop_listening(wait_for_stop=False)# Do some more unrelated thingswhile True: time.sleep(0.1) # we're not listening anymore, even though the background thread might still be running for a second or two
def callback(recognizer, audio): try: text = recognizer.recognize_google(audio).lower() if "hello" in text: print("Hello to you too!") elif "stop" in text: print("Stopping...") stop_listening() elif "weather" in text: print("Fetching weather...") except sr.UnknownValueError: pass
Logging to file:
def callback(recognizer, audio): try: text = recognizer.recognize_google(audio) with open("transcript.txt", "a") as f: from datetime import datetime timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") f.write(f"[{timestamp}] {text}\n") except sr.UnknownValueError: pass
The wait_for_stop parameter controls whether to wait for the background thread to finish:
# Don't wait - return immediatelystop_listening(wait_for_stop=False)# Wait for the background thread to fully stopstop_listening(wait_for_stop=True)
Use wait_for_stop=False if you want to continue your program immediately. Use wait_for_stop=True if you need to ensure the listener has fully stopped before proceeding.
def callback(recognizer, audio): # Try Google first try: text = recognizer.recognize_google(audio) print(f"Google: {text}") return except (sr.UnknownValueError, sr.RequestError): pass # Fall back to Sphinx (offline) try: text = recognizer.recognize_sphinx(audio) print(f"Sphinx: {text}") except sr.UnknownValueError: print("Neither engine could understand audio")
The callback function runs in a background thread. Be careful with:
Shared state (use locks if needed)
UI updates (most UI frameworks require updates on the main thread)
Long-running operations (keep callbacks fast)
If you need to update UI or do heavy processing:
import queueimport threadingrecognition_queue = queue.Queue()def callback(recognizer, audio): """Quick callback - just queue the audio""" recognition_queue.put(audio)def process_audio(): """Process audio in a separate thread""" r = sr.Recognizer() while True: audio = recognition_queue.get() if audio is None: # Sentinel value to stop break try: text = r.recognize_google(audio) # Do heavy processing or UI updates here print(f"Processed: {text}") except sr.UnknownValueError: pass# Start processing threadprocessor = threading.Thread(target=process_audio, daemon=True)processor.start()# Start listeningr = sr.Recognizer()m = sr.Microphone()with m as source: r.adjust_for_ambient_noise(source)stop_listening = r.listen_in_background(m, callback)
# Increase the energy thresholdr.energy_threshold = 4000# Or adjust for ambient noise with a longer durationwith m as source: r.adjust_for_ambient_noise(source, duration=2)