如何中断pyttsx3语音播报与playsound音频播放?
解决音频播放与语音播报的中断问题
我完全懂你现在的困扰——playsound的阻塞播放逻辑和pyttsx3里runAndWait()的阻塞特性,直接导致没法中途中断操作。下面给你两套落地可行的方案,分别搞定歌曲播放和语音播报的中断需求:
一、替换playsound为pygame.mixer实现歌曲可中断播放
playsound本质是阻塞式运行,很难中途停止,而pygame.mixer支持非阻塞播放,还能随时调用停止方法。具体步骤如下:
- 先安装依赖库:
pip install pygame keyboard
- 示例代码:
import pygame import pyttsx3 import keyboard engine = pyttsx3.init() def play_song(song_name): pygame.mixer.init() try: pygame.mixer.music.load(song_name) pygame.mixer.music.play() # 监听按键,这里设为按'q'停止播放,你可以自定义按键 while pygame.mixer.music.get_busy(): if keyboard.is_pressed('q'): pygame.mixer.music.stop() print("歌曲已停止") break except pygame.error: engine.say("I couldn't find the song.") engine.runAndWait() finally: pygame.mixer.quit() # 模拟用户输入逻辑 user_input = input("Enter command: ") if "play" in user_input: song_name = user_input[5:] + ".mp3" play_song(song_name)
二、解决pyttsx3的语音播报中断问题
pyttsx3的engine.stop()之所以不生效,核心原因是runAndWait()会阻塞主线程,导致你根本没机会触发停止操作。解决思路是把播报任务放到子线程,让主线程专门负责监听中断信号:
方案1:基于pyttsx3的多线程实现
import pyttsx3 import threading import keyboard engine = pyttsx3.init() is_speaking = False def speak(text): global is_speaking is_speaking = True engine.say(text) engine.runAndWait() is_speaking = False def stop_speech(): global is_speaking if is_speaking: engine.stop() is_speaking = False print("语音播报已中断") # 绑定中断按键,这里设为按's'停止播报 keyboard.add_hotkey('s', stop_speech) # 测试长文本播报 speak_thread = threading.Thread( target=speak, args=("This is a long test speech. You can press 's' to stop me at any time.",) ) speak_thread.start() # 主线程可继续处理其他逻辑,这里等待播报线程结束 while speak_thread.is_alive(): pass
方案2:用gTTS+pygame替代pyttsx3
如果pyttsx3的方案还是有兼容性问题,可以用gTTS生成语音文件,再用pygame播放,这样就能和歌曲播放共用一套中断逻辑:
- 安装依赖库:
pip install gTTS pygame keyboard
- 示例代码:
from gtts import gTTS import pygame import keyboard import os def speak_and_interrupt(text): # 生成临时语音文件 tts = gTTS(text=text, lang='en') temp_file = "temp_speech.mp3" tts.save(temp_file) # 用pygame播放并监听中断 pygame.mixer.init() pygame.mixer.music.load(temp_file) pygame.mixer.music.play() while pygame.mixer.music.get_busy(): if keyboard.is_pressed('s'): pygame.mixer.music.stop() print("语音播报已中断") break pygame.mixer.quit() os.remove(temp_file) # 清理临时文件 # 测试中断功能 speak_and_interrupt("I couldn't find the song. Press 's' to stop this message right now.")
小提示
keyboard库在Windows下需要管理员权限才能正常监听按键,如果你不想用它,也可以换成pynput库,用法逻辑类似。- 多线程处理时,注意全局变量的线程安全,不过这里的
is_speaking只是简单状态标记,不会有问题。
内容的提问来源于stack exchange,提问作者gozdekurtulmus




