彻底解决回声问题:实现设备分离播放
- 播放时完全关闭音频输入流 - 使用系统播放器(aplay)避免设备冲突 - 添加安全的播放方式play_audio_safe - 播放前后增加延迟确保设备状态切换 - 完全解决硬件串扰和声学回声问题
This commit is contained in:
parent
e6341b8620
commit
072bb0e6b0
@ -169,20 +169,31 @@ class EnergyBasedRecorder:
|
|||||||
def play_audio(self, filename):
|
def play_audio(self, filename):
|
||||||
"""播放音频文件"""
|
"""播放音频文件"""
|
||||||
try:
|
try:
|
||||||
# 立即停止当前录音并清空缓冲区
|
print("🔇 准备播放,完全停止音频输入")
|
||||||
|
|
||||||
|
# 立即停止当前录音并清空所有缓冲区
|
||||||
if self.recording:
|
if self.recording:
|
||||||
print("🔇 播放开始,停止当前录音")
|
|
||||||
self.recording = False
|
self.recording = False
|
||||||
self.recorded_frames = []
|
self.recorded_frames = []
|
||||||
self.recording_start_time = None
|
self.recording_start_time = None
|
||||||
self.last_sound_time = None
|
self.last_sound_time = None
|
||||||
|
|
||||||
# 清空预录音缓冲区,避免录制播放的音频
|
# 清空所有缓冲区
|
||||||
self.pre_record_buffer = []
|
self.pre_record_buffer = []
|
||||||
|
self.energy_history = []
|
||||||
|
|
||||||
|
# 完全关闭输入流
|
||||||
|
if self.stream:
|
||||||
|
self.stream.stop_stream()
|
||||||
|
self.stream.close()
|
||||||
|
self.stream = None
|
||||||
|
|
||||||
# 设置播放状态
|
# 设置播放状态
|
||||||
self.is_playing = True
|
self.is_playing = True
|
||||||
|
|
||||||
|
# 等待一小段时间确保音频设备完全停止输入
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
with wave.open(filename, 'rb') as wf:
|
with wave.open(filename, 'rb') as wf:
|
||||||
channels = wf.getnchannels()
|
channels = wf.getnchannels()
|
||||||
width = wf.getsampwidth()
|
width = wf.getsampwidth()
|
||||||
@ -209,7 +220,7 @@ class EnergyBasedRecorder:
|
|||||||
)
|
)
|
||||||
|
|
||||||
print(f"🔊 开始播放: {filename}")
|
print(f"🔊 开始播放: {filename}")
|
||||||
print("🚫 暂停录音处理,避免回声")
|
print("🚫 音频输入已完全关闭")
|
||||||
|
|
||||||
# 分块播放音频
|
# 分块播放音频
|
||||||
for chunk in frames:
|
for chunk in frames:
|
||||||
@ -219,7 +230,7 @@ class EnergyBasedRecorder:
|
|||||||
playback_stream.close()
|
playback_stream.close()
|
||||||
|
|
||||||
print("✅ 播放完成")
|
print("✅ 播放完成")
|
||||||
print("🔄 恢复录音监听")
|
print("🔄 重新开启音频输入")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ 播放失败: {e}")
|
print(f"❌ 播放失败: {e}")
|
||||||
@ -227,8 +238,16 @@ class EnergyBasedRecorder:
|
|||||||
finally:
|
finally:
|
||||||
# 恢复播放状态
|
# 恢复播放状态
|
||||||
self.is_playing = False
|
self.is_playing = False
|
||||||
# 重置状态,准备重新监听
|
|
||||||
|
# 等待播放完全结束
|
||||||
|
time.sleep(0.3)
|
||||||
|
|
||||||
|
# 重新开启输入流
|
||||||
|
self._setup_audio()
|
||||||
|
|
||||||
|
# 重置所有状态
|
||||||
self.energy_history = []
|
self.energy_history = []
|
||||||
|
print("📡 音频输入已重新开启")
|
||||||
|
|
||||||
def play_with_system_player(self, filename):
|
def play_with_system_player(self, filename):
|
||||||
"""使用系统播放器播放音频"""
|
"""使用系统播放器播放音频"""
|
||||||
@ -236,11 +255,65 @@ class EnergyBasedRecorder:
|
|||||||
import subprocess
|
import subprocess
|
||||||
cmd = ['aplay', filename] # Linux系统
|
cmd = ['aplay', filename] # Linux系统
|
||||||
print(f"🔊 使用系统播放器: {' '.join(cmd)}")
|
print(f"🔊 使用系统播放器: {' '.join(cmd)}")
|
||||||
|
print("🚫 系统播放器播放中,音频输入保持关闭")
|
||||||
subprocess.run(cmd, check=True)
|
subprocess.run(cmd, check=True)
|
||||||
print("✅ 播放完成")
|
print("✅ 播放完成")
|
||||||
|
print("📡 音频输入已保持关闭状态")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ 系统播放器也失败: {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):
|
def update_pre_record_buffer(self, audio_data):
|
||||||
"""更新预录音缓冲区"""
|
"""更新预录音缓冲区"""
|
||||||
self.pre_record_buffer.append(audio_data)
|
self.pre_record_buffer.append(audio_data)
|
||||||
@ -284,7 +357,8 @@ class EnergyBasedRecorder:
|
|||||||
if success and filename:
|
if success and filename:
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print("🔊 播放刚才录制的音频...")
|
print("🔊 播放刚才录制的音频...")
|
||||||
self.play_audio(filename)
|
# 优先使用系统播放器避免回声
|
||||||
|
self.play_audio_safe(filename)
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
|
|
||||||
self.recording = False
|
self.recording = False
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user