回声待处理

This commit is contained in:
朱潮 2025-09-20 22:25:25 +08:00
parent d385333e0f
commit 0ab8e49ba5

View File

@ -100,7 +100,8 @@ class EnergyBasedRecorder:
# 状态变量
self.audio = None
self.stream = None
self.input_stream = None # 输入流(录音)
self.output_stream = None # 输出流(播放)
self.running = False
self.recording = False
self.recorded_frames = []
@ -484,19 +485,14 @@ class EnergyBasedRecorder:
# 如果强制重置,先完全释放资源
if force_reset:
self._force_close_audio_stream()
if self.audio:
try:
self.audio.terminate()
except:
pass
self.audio = None
# 不终止整个PyAudio实例只重置输入流
# 创建新的PyAudio实例
# 创建新的PyAudio实例如果不存在
if not self.audio:
self.audio = pyaudio.PyAudio()
# 创建音频输入流
self.stream = self.audio.open(
self.input_stream = self.audio.open(
format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
@ -510,8 +506,8 @@ class EnergyBasedRecorder:
self.audio_device_healthy = False
def _force_close_audio_stream(self):
"""强制关闭音频流,避免阻塞"""
if self.stream:
"""强制关闭音频输入流,避免阻塞"""
if self.input_stream:
try:
# 尝试优雅关闭,设置超时
import signal
@ -524,23 +520,23 @@ class EnergyBasedRecorder:
signal.alarm(5)
try:
self.stream.stop_stream()
self.stream.close()
self.input_stream.stop_stream()
self.input_stream.close()
finally:
signal.alarm(0) # 取消超时
except TimeoutError:
print("⚠️ 音频流关闭超时,强制终止")
self.stream = None
print("⚠️ 音频输入流关闭超时,强制终止")
self.input_stream = None
except Exception as e:
print(f"⚠️ 优雅关闭音频流失败: {e}")
print(f"⚠️ 优雅关闭音频输入流失败: {e}")
try:
# 强制关闭
self.stream = None
self.input_stream = None
except:
pass
finally:
self.stream = None
self.input_stream = None
self.audio_device_healthy = False # 标记设备需要重置
def calculate_energy(self, audio_data):
@ -1192,10 +1188,23 @@ class EnergyBasedRecorder:
# 等待音频播放完成后再重新开启音频输入
print("⏳ 等待音频播放完成...")
while not self.audio_playback_queue.empty() or self.currently_playing:
queue_size = self.audio_playback_queue.qsize()
playing_status = "播放中" if self.currently_playing else "等待播放"
print(f"\r🔊 {playing_status}... 队列: {queue_size}", end='', flush=True)
# 检查多个队列的状态
tts_queue_size = self.tts_task_queue.qsize()
playback_queue_size = self.audio_playback_queue.qsize()
while tts_queue_size > 0 or playback_queue_size > 0 or self.currently_playing:
tts_queue_size = self.tts_task_queue.qsize()
playback_queue_size = self.audio_playback_queue.qsize()
if tts_queue_size > 0:
status = f"🎵 TTS生成中... TTS队列: {tts_queue_size} 播放队列: {playback_queue_size}"
elif self.currently_playing:
status = f"🔊 正在播放... 播放队列: {playback_queue_size}"
else:
status = f"⏳ 等待播放... 播放队列: {playback_queue_size}"
print(f"\r{status}", end='', flush=True)
time.sleep(0.1)
# 额外等待1秒确保音频设备完全停止
@ -1245,7 +1254,7 @@ class EnergyBasedRecorder:
def run(self):
"""运行录音系统"""
if not self.stream:
if not self.input_stream:
print("❌ 音频设备未初始化")
return
@ -1275,42 +1284,50 @@ class EnergyBasedRecorder:
try:
while self.running:
# 检查音频流是否可用
if self.stream is None:
if self.input_stream is None:
print("\n❌ 音频流已断开,尝试重新连接...")
self._setup_audio(force_reset=True)
if self.stream is None:
if self.input_stream is None:
print("❌ 音频流重连失败,等待...")
time.sleep(1)
continue
# 读取音频数据
try:
data = self.stream.read(self.CHUNK_SIZE, exception_on_overflow=False)
data = self.input_stream.read(self.CHUNK_SIZE, exception_on_overflow=False)
except Exception as e:
print(f"\n❌ 读取音频数据失败: {e}")
self.stream = None
self.input_stream = None
continue
if len(data) == 0:
continue
# 检查设备健康状态和播放冷却期 - 防止回声
# 检查设备健康状态、TTS状态和播放冷却期 - 防止回声
current_time = time.time()
time_since_last_play = current_time - self.last_playback_time
in_cooldown = time_since_last_play < self.playback_cooldown_period
# 如果设备不健康、正在播放、播放队列不为空、或在冷却期内,完全跳过音频处理
if not self.audio_device_healthy or self.is_playing or self.currently_playing or not self.audio_playback_queue.empty() or in_cooldown:
# 检查TTS和播放队列状态
tts_active = not self.tts_task_queue.empty()
playback_active = not self.audio_playback_queue.empty() or self.currently_playing
# 如果设备不健康、正在播放、TTS生成中、播放队列不为空、或在冷却期内完全跳过音频处理
if not self.audio_device_healthy or self.is_playing or tts_active or playback_active or in_cooldown:
# 显示播放状态
tts_queue_size = self.tts_task_queue.qsize()
queue_size = self.audio_playback_queue.qsize()
if not self.audio_device_healthy:
status = f"🔧 设备重置中... 队列: {queue_size}"
status = f"🔧 设备重置中... TTS: {tts_queue_size} 播放: {queue_size}"
elif tts_active:
status = f"🎵 TTS生成中... TTS: {tts_queue_size} 播放: {queue_size}"
elif in_cooldown:
cooldown_time = self.playback_cooldown_period - time_since_last_play
status = f"🔊 播放冷却中... {cooldown_time:.1f}s 队列: {queue_size}"
status = f"🔊 播放冷却中... {cooldown_time:.1f}s TTS: {tts_queue_size} 播放: {queue_size}"
else:
playing_status = "播放中" if self.currently_playing else "等待播放"
status = f"🔊 {playing_status}... 队列: {queue_size}"
status = f"🔊 {playing_status}... TTS: {tts_queue_size} 播放: {queue_size}"
print(f"\r{status}", end='', flush=True)
time.sleep(0.1) # 播放时增加延迟减少CPU使用
continue
@ -1427,9 +1444,9 @@ class EnergyBasedRecorder:
self.audio_playback_queue.put(None) # 发送结束信号
self.playback_worker_thread.join(timeout=3.0)
if self.stream:
self.stream.stop_stream()
self.stream.close()
if self.input_stream:
self.input_stream.stop_stream()
self.input_stream.close()
if self.audio:
self.audio.terminate()