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