回声待处理
This commit is contained in:
parent
5a7e39f5b5
commit
d385333e0f
108
recorder.py
108
recorder.py
@ -150,6 +150,7 @@ class EnergyBasedRecorder:
|
|||||||
self.currently_playing = False # 当前是否正在播放
|
self.currently_playing = False # 当前是否正在播放
|
||||||
self.last_playback_time = 0 # 最后一次播放时间戳
|
self.last_playback_time = 0 # 最后一次播放时间戳
|
||||||
self.playback_cooldown_period = 1.5 # 播放冷却时间(秒)
|
self.playback_cooldown_period = 1.5 # 播放冷却时间(秒)
|
||||||
|
self.audio_device_healthy = True # 音频设备健康状态
|
||||||
|
|
||||||
# 启动工作线程
|
# 启动工作线程
|
||||||
self._start_tts_worker()
|
self._start_tts_worker()
|
||||||
@ -477,10 +478,24 @@ class EnergyBasedRecorder:
|
|||||||
print(f"❌ 加载角色配置失败: {e}")
|
print(f"❌ 加载角色配置失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _setup_audio(self):
|
def _setup_audio(self, force_reset=False):
|
||||||
"""设置音频设备"""
|
"""设置音频设备"""
|
||||||
try:
|
try:
|
||||||
self.audio = pyaudio.PyAudio()
|
# 如果强制重置,先完全释放资源
|
||||||
|
if force_reset:
|
||||||
|
self._force_close_audio_stream()
|
||||||
|
if self.audio:
|
||||||
|
try:
|
||||||
|
self.audio.terminate()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.audio = None
|
||||||
|
|
||||||
|
# 创建新的PyAudio实例
|
||||||
|
if not self.audio:
|
||||||
|
self.audio = pyaudio.PyAudio()
|
||||||
|
|
||||||
|
# 创建音频输入流
|
||||||
self.stream = self.audio.open(
|
self.stream = self.audio.open(
|
||||||
format=self.FORMAT,
|
format=self.FORMAT,
|
||||||
channels=self.CHANNELS,
|
channels=self.CHANNELS,
|
||||||
@ -489,8 +504,44 @@ class EnergyBasedRecorder:
|
|||||||
frames_per_buffer=self.CHUNK_SIZE
|
frames_per_buffer=self.CHUNK_SIZE
|
||||||
)
|
)
|
||||||
print("✅ 音频设备初始化成功")
|
print("✅ 音频设备初始化成功")
|
||||||
|
self.audio_device_healthy = True # 恢复设备健康状态
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ 音频设备初始化失败: {e}")
|
print(f"❌ 音频设备初始化失败: {e}")
|
||||||
|
self.audio_device_healthy = False
|
||||||
|
|
||||||
|
def _force_close_audio_stream(self):
|
||||||
|
"""强制关闭音频流,避免阻塞"""
|
||||||
|
if self.stream:
|
||||||
|
try:
|
||||||
|
# 尝试优雅关闭,设置超时
|
||||||
|
import signal
|
||||||
|
|
||||||
|
def timeout_handler(signum, frame):
|
||||||
|
raise TimeoutError("音频流关闭超时")
|
||||||
|
|
||||||
|
# 设置5秒超时
|
||||||
|
signal.signal(signal.SIGALRM, timeout_handler)
|
||||||
|
signal.alarm(5)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.stream.stop_stream()
|
||||||
|
self.stream.close()
|
||||||
|
finally:
|
||||||
|
signal.alarm(0) # 取消超时
|
||||||
|
|
||||||
|
except TimeoutError:
|
||||||
|
print("⚠️ 音频流关闭超时,强制终止")
|
||||||
|
self.stream = None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ 优雅关闭音频流失败: {e}")
|
||||||
|
try:
|
||||||
|
# 强制关闭
|
||||||
|
self.stream = None
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
self.stream = None
|
||||||
|
self.audio_device_healthy = False # 标记设备需要重置
|
||||||
|
|
||||||
def calculate_energy(self, audio_data):
|
def calculate_energy(self, audio_data):
|
||||||
"""计算音频能量"""
|
"""计算音频能量"""
|
||||||
@ -589,7 +640,7 @@ class EnergyBasedRecorder:
|
|||||||
def play_audio(self, filename):
|
def play_audio(self, filename):
|
||||||
"""播放音频文件"""
|
"""播放音频文件"""
|
||||||
try:
|
try:
|
||||||
print("🔇 准备播放,完全停止音频输入")
|
print("🔇 准备播放,强制停止音频输入")
|
||||||
|
|
||||||
# 立即停止当前录音并清空所有缓冲区
|
# 立即停止当前录音并清空所有缓冲区
|
||||||
if self.recording:
|
if self.recording:
|
||||||
@ -603,11 +654,8 @@ class EnergyBasedRecorder:
|
|||||||
self.energy_history = []
|
self.energy_history = []
|
||||||
self.zcr_history = []
|
self.zcr_history = []
|
||||||
|
|
||||||
# 完全关闭输入流
|
# 强制关闭输入流,避免阻塞
|
||||||
if self.stream:
|
self._force_close_audio_stream()
|
||||||
self.stream.stop_stream()
|
|
||||||
self.stream.close()
|
|
||||||
self.stream = None
|
|
||||||
|
|
||||||
# 设置播放状态
|
# 设置播放状态
|
||||||
self.is_playing = True
|
self.is_playing = True
|
||||||
@ -663,13 +711,13 @@ class EnergyBasedRecorder:
|
|||||||
# 等待播放完全结束
|
# 等待播放完全结束
|
||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
|
|
||||||
# 重新开启输入流
|
# 重新开启输入流(强制重置)
|
||||||
self._setup_audio()
|
self._setup_audio(force_reset=True)
|
||||||
|
|
||||||
# 重置所有状态
|
# 重置所有状态
|
||||||
self.energy_history = []
|
self.energy_history = []
|
||||||
self.zcr_history = []
|
self.zcr_history = []
|
||||||
print("📡 音频输入已重新开启")
|
print("📡 音频输入已重新开启(强制重置)")
|
||||||
|
|
||||||
def play_with_system_player(self, filename):
|
def play_with_system_player(self, filename):
|
||||||
"""使用系统播放器播放音频"""
|
"""使用系统播放器播放音频"""
|
||||||
@ -835,11 +883,8 @@ class EnergyBasedRecorder:
|
|||||||
self.energy_history = []
|
self.energy_history = []
|
||||||
self.zcr_history = []
|
self.zcr_history = []
|
||||||
|
|
||||||
# 关闭输入流
|
# 强制关闭输入流
|
||||||
if self.stream:
|
self._force_close_audio_stream()
|
||||||
self.stream.stop_stream()
|
|
||||||
self.stream.close()
|
|
||||||
self.stream = None
|
|
||||||
|
|
||||||
self.is_playing = True
|
self.is_playing = True
|
||||||
time.sleep(0.3) # 等待音频设备切换
|
time.sleep(0.3) # 等待音频设备切换
|
||||||
@ -987,7 +1032,7 @@ class EnergyBasedRecorder:
|
|||||||
def play_audio_safe(self, filename, reopen_input=False):
|
def play_audio_safe(self, filename, reopen_input=False):
|
||||||
"""安全的播放方式 - 使用系统播放器"""
|
"""安全的播放方式 - 使用系统播放器"""
|
||||||
try:
|
try:
|
||||||
print("🔇 准备播放,完全停止音频输入")
|
print("🔇 准备播放,强制停止音频输入")
|
||||||
|
|
||||||
# 立即停止当前录音并清空所有缓冲区
|
# 立即停止当前录音并清空所有缓冲区
|
||||||
if self.recording:
|
if self.recording:
|
||||||
@ -1001,11 +1046,8 @@ class EnergyBasedRecorder:
|
|||||||
self.energy_history = []
|
self.energy_history = []
|
||||||
self.zcr_history = []
|
self.zcr_history = []
|
||||||
|
|
||||||
# 完全关闭输入流
|
# 强制关闭输入流
|
||||||
if self.stream:
|
self._force_close_audio_stream()
|
||||||
self.stream.stop_stream()
|
|
||||||
self.stream.close()
|
|
||||||
self.stream = None
|
|
||||||
|
|
||||||
# 设置播放状态
|
# 设置播放状态
|
||||||
self.is_playing = True
|
self.is_playing = True
|
||||||
@ -1033,13 +1075,13 @@ class EnergyBasedRecorder:
|
|||||||
|
|
||||||
# 只在需要时重新开启输入流
|
# 只在需要时重新开启输入流
|
||||||
if reopen_input:
|
if reopen_input:
|
||||||
# 重新开启输入流
|
# 重新开启输入流(强制重置)
|
||||||
self._setup_audio()
|
self._setup_audio(force_reset=True)
|
||||||
|
|
||||||
# 重置所有状态
|
# 重置所有状态
|
||||||
self.energy_history = []
|
self.energy_history = []
|
||||||
self.zcr_history = []
|
self.zcr_history = []
|
||||||
print("📡 音频输入已重新开启")
|
print("📡 音频输入已重新开启(强制重置)")
|
||||||
|
|
||||||
def update_pre_record_buffer(self, audio_data):
|
def update_pre_record_buffer(self, audio_data):
|
||||||
"""更新预录音缓冲区"""
|
"""更新预录音缓冲区"""
|
||||||
@ -1162,6 +1204,10 @@ class EnergyBasedRecorder:
|
|||||||
|
|
||||||
print("🔄 音频播放完成,准备重新开启音频输入")
|
print("🔄 音频播放完成,准备重新开启音频输入")
|
||||||
|
|
||||||
|
# 强制重置音频设备,确保完全关闭
|
||||||
|
print("🔄 强制重置音频设备...")
|
||||||
|
self._force_close_audio_stream()
|
||||||
|
|
||||||
self.recording = False
|
self.recording = False
|
||||||
self.recorded_frames = []
|
self.recorded_frames = []
|
||||||
self.recording_start_time = None
|
self.recording_start_time = None
|
||||||
@ -1231,7 +1277,7 @@ class EnergyBasedRecorder:
|
|||||||
# 检查音频流是否可用
|
# 检查音频流是否可用
|
||||||
if self.stream is None:
|
if self.stream is None:
|
||||||
print("\n❌ 音频流已断开,尝试重新连接...")
|
print("\n❌ 音频流已断开,尝试重新连接...")
|
||||||
self._setup_audio()
|
self._setup_audio(force_reset=True)
|
||||||
if self.stream is None:
|
if self.stream is None:
|
||||||
print("❌ 音频流重连失败,等待...")
|
print("❌ 音频流重连失败,等待...")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
@ -1248,16 +1294,18 @@ class EnergyBasedRecorder:
|
|||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 检查播放冷却期 - 防止回声
|
# 检查设备健康状态和播放冷却期 - 防止回声
|
||||||
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
|
||||||
|
|
||||||
# 如果正在播放、播放队列不为空、或在冷却期内,完全跳过音频处理
|
# 如果设备不健康、正在播放、播放队列不为空、或在冷却期内,完全跳过音频处理
|
||||||
if self.is_playing or self.currently_playing or not self.audio_playback_queue.empty() or in_cooldown:
|
if not self.audio_device_healthy or self.is_playing or self.currently_playing or not self.audio_playback_queue.empty() or in_cooldown:
|
||||||
# 显示播放状态
|
# 显示播放状态
|
||||||
queue_size = self.audio_playback_queue.qsize()
|
queue_size = self.audio_playback_queue.qsize()
|
||||||
if in_cooldown:
|
if not self.audio_device_healthy:
|
||||||
|
status = f"🔧 设备重置中... 队列: {queue_size}"
|
||||||
|
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 队列: {queue_size}"
|
||||||
else:
|
else:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user