Python语音聊天机器人音频路由问题:如何避免识别自身播放音频?
问题描述
我开发了一个具备音频播放与录制功能的Python语音交互聊天机器人,通过线程同时运行播放与录制代码:
import os import soundfile as sf import sounddevice as sd import speech_recognition as sr def play_audio(file_name): audio_path = os.path.join(path, file_name) data, fs = sf.read(audio_path) sd.play(data, fs) sd.wait() def rec_audio(): recog = sr.Recognizer() with sr.Microphone() as source: print("Listening... From Site Rec..") audio = recog.listen(source) data = "" try: data = recog.recognize_google(audio) print("User: " + data) except sr.UnknownValueError: print("Machine coudn't process..") play_audio("voice break.mp3") except sr.RequestError as ex: print("Google side" + str(ex)) play_audio("RequestError.mp3") return data
目前机器人会将自身的音频输出识别为输入,需要解决:
- 如何阻止这种自识别情况
- 是否有应用间音频路由工具可用
- 怎么设置让机器人仅识别麦克风输入,排除自身播放音频
解决方案
一、代码层面优化(无需额外工具)
1. 播放时暂停录制线程
多线程场景下,直接在播放前暂停录制逻辑,播放完成后恢复,用threading.Event做信号控制:
import threading # 全局事件控制录制启停 recording_active = threading.Event() recording_active.set() # 默认允许录制 def rec_audio(): recog = sr.Recognizer() with sr.Microphone() as source: while True: recording_active.wait() # 等待允许录制的信号 print("Listening... From Site Rec..") audio = recog.listen(source) data = "" try: data = recog.recognize_google(audio) print("User: " + data) except sr.UnknownValueError: print("Machine coudn't process..") play_audio("voice break.mp3") except sr.RequestError as ex: print("Google side" + str(ex)) play_audio("RequestError.mp3") return data def play_audio(file_name): recording_active.clear() # 播放前暂停录制 audio_path = os.path.join(path, file_name) data, fs = sf.read(audio_path) sd.play(data, fs) sd.wait() recording_active.set() # 播放完成恢复录制
2. 用语音活动检测(VAD)过滤无效音频
借助webrtcvad库过滤掉低音量或非人声的播放音频,先安装库:pip install webrtcvad,修改录制逻辑:
import webrtcvad def rec_audio(): recog = sr.Recognizer() vad = webrtcvad.Vad(3) # 3为最严格检测模式,可根据需求调1-3 with sr.Microphone() as source: print("Listening... From Site Rec..") audio = recog.listen(source) # 转换音频格式适配VAD要求(16kHz采样率、16位宽度) raw_audio = audio.get_raw_data(convert_rate=16000, convert_width=2) frame_duration = 30 # VAD要求的帧时长,固定30ms frame_size = int(16000 * frame_duration / 1000) * 2 # 每帧字节数 frames = [raw_audio[i:i+frame_size] for i in range(0, len(raw_audio), frame_size)] # 检测是否包含有效人声 has_valid_speech = any(vad.is_speech(frame, 16000) for frame in frames) if not has_valid_speech: return "" # 无有效人声直接返回空 data = "" try: data = recog.recognize_google(audio) print("User: " + data) except sr.UnknownValueError: print("Machine coudn't process..") play_audio("voice break.mp3") except sr.RequestError as ex: print("Google side" + str(ex)) play_audio("RequestError.mp3") return data
二、系统级音频路由工具
如果不想修改代码,可通过系统工具隔离输入输出:
- Windows:使用VoiceMeeter,将机器人播放输出设置到虚拟音频设备,录制时指定物理麦克风:
- 安装VoiceMeeter后,在系统声音设置中将默认播放设备设为VoiceMeeter虚拟输出;
- 在VoiceMeeter界面,把物理麦克风设为输入,实际扬声器设为输出;
- 代码中指定麦克风设备:
sr.Microphone(device_index=你的麦克风索引),可用sr.Microphone.list_microphone_names()查看所有设备索引。
- macOS:使用BlackHole或Soundflower创建虚拟音频设备,将机器人播放路由到虚拟设备,录制时选择物理麦克风即可。
- Linux:使用pavucontrol(PulseAudio音量控制),在「录制」选项卡中,将机器人的录制来源强制设置为物理麦克风,而非「Monitor of 扬声器」。
三、硬件层面隔离
最省心的方式是用带监听屏蔽功能的麦克风,或者用耳机播放机器人音频,避免扬声器声音回传到麦克风。
内容的提问来源于stack exchange,提问作者SmokeSyd
相关产品推荐
相关产品推荐

