From 072bb0e6b00d9b1ae84d5cbb2d87429c3b5c8fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E6=BD=AE?= Date: Sat, 20 Sep 2025 12:20:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BD=BB=E5=BA=95=E8=A7=A3=E5=86=B3=E5=9B=9E?= =?UTF-8?q?=E5=A3=B0=E9=97=AE=E9=A2=98=EF=BC=9A=E5=AE=9E=E7=8E=B0=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=88=86=E7=A6=BB=E6=92=AD=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 播放时完全关闭音频输入流 - 使用系统播放器(aplay)避免设备冲突 - 添加安全的播放方式play_audio_safe - 播放前后增加延迟确保设备状态切换 - 完全解决硬件串扰和声学回声问题 --- energy_based_recorder.py | 88 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/energy_based_recorder.py b/energy_based_recorder.py index 96d438f..27bf6fc 100644 --- a/energy_based_recorder.py +++ b/energy_based_recorder.py @@ -169,20 +169,31 @@ class EnergyBasedRecorder: def play_audio(self, filename): """播放音频文件""" try: - # 立即停止当前录音并清空缓冲区 + print("🔇 准备播放,完全停止音频输入") + + # 立即停止当前录音并清空所有缓冲区 if self.recording: - print("🔇 播放开始,停止当前录音") self.recording = False self.recorded_frames = [] self.recording_start_time = None self.last_sound_time = None - # 清空预录音缓冲区,避免录制播放的音频 + # 清空所有缓冲区 self.pre_record_buffer = [] + self.energy_history = [] + + # 完全关闭输入流 + if self.stream: + self.stream.stop_stream() + self.stream.close() + self.stream = None # 设置播放状态 self.is_playing = True + # 等待一小段时间确保音频设备完全停止输入 + time.sleep(0.5) + with wave.open(filename, 'rb') as wf: channels = wf.getnchannels() width = wf.getsampwidth() @@ -209,7 +220,7 @@ class EnergyBasedRecorder: ) print(f"🔊 开始播放: {filename}") - print("🚫 暂停录音处理,避免回声") + print("🚫 音频输入已完全关闭") # 分块播放音频 for chunk in frames: @@ -219,7 +230,7 @@ class EnergyBasedRecorder: playback_stream.close() print("✅ 播放完成") - print("🔄 恢复录音监听") + print("🔄 重新开启音频输入") except Exception as e: print(f"❌ 播放失败: {e}") @@ -227,8 +238,16 @@ class EnergyBasedRecorder: finally: # 恢复播放状态 self.is_playing = False - # 重置状态,准备重新监听 + + # 等待播放完全结束 + time.sleep(0.3) + + # 重新开启输入流 + self._setup_audio() + + # 重置所有状态 self.energy_history = [] + print("📡 音频输入已重新开启") def play_with_system_player(self, filename): """使用系统播放器播放音频""" @@ -236,11 +255,65 @@ class EnergyBasedRecorder: import subprocess cmd = ['aplay', filename] # Linux系统 print(f"🔊 使用系统播放器: {' '.join(cmd)}") + print("🚫 系统播放器播放中,音频输入保持关闭") subprocess.run(cmd, check=True) print("✅ 播放完成") + print("📡 音频输入已保持关闭状态") except Exception as e: print(f"❌ 系统播放器也失败: {e}") + def play_audio_safe(self, filename): + """安全的播放方式 - 使用系统播放器""" + try: + print("🔇 准备播放,完全停止音频输入") + + # 立即停止当前录音并清空所有缓冲区 + if self.recording: + self.recording = False + self.recorded_frames = [] + self.recording_start_time = None + self.last_sound_time = None + + # 清空所有缓冲区 + self.pre_record_buffer = [] + self.energy_history = [] + + # 完全关闭输入流 + if self.stream: + self.stream.stop_stream() + self.stream.close() + self.stream = None + + # 设置播放状态 + self.is_playing = True + + # 等待确保音频设备完全停止 + time.sleep(0.5) + + print(f"🔊 开始播放: {filename}") + print("🚫 使用系统播放器,音频输入已完全关闭") + + # 使用系统播放器 + self.play_with_system_player(filename) + + print("🔄 准备重新开启音频输入") + + except Exception as e: + print(f"❌ 播放失败: {e}") + finally: + # 恢复播放状态 + self.is_playing = False + + # 等待播放完全结束 + time.sleep(0.5) + + # 重新开启输入流 + self._setup_audio() + + # 重置所有状态 + self.energy_history = [] + print("📡 音频输入已重新开启") + def update_pre_record_buffer(self, audio_data): """更新预录音缓冲区""" self.pre_record_buffer.append(audio_data) @@ -284,7 +357,8 @@ class EnergyBasedRecorder: if success and filename: print("=" * 50) print("🔊 播放刚才录制的音频...") - self.play_audio(filename) + # 优先使用系统播放器避免回声 + self.play_audio_safe(filename) print("=" * 50) self.recording = False