mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
refactor: 优化非流式音频过滤机制
fix: 修复等待中被打断队列被停止造成的死锁
This commit is contained in:
@@ -17,7 +17,11 @@ AUDIO_FRAME_DURATION = 60
|
||||
PRE_BUFFER_COUNT = 5
|
||||
|
||||
|
||||
async def sendAudioMessage(conn: "ConnectionHandler", sentenceType, audios, text):
|
||||
async def sendAudioMessage(conn: "ConnectionHandler", sentenceType, audios, text, sentence_id=None):
|
||||
# 跳过旧句子残留音频
|
||||
if sentence_id is not None and sentence_id != conn.sentence_id:
|
||||
return
|
||||
|
||||
if conn.tts.tts_audio_first_sentence:
|
||||
conn.logger.bind(tag=TAG).info(f"发送第一段语音: {text}")
|
||||
conn.tts.tts_audio_first_sentence = False
|
||||
@@ -281,12 +285,14 @@ async def send_tts_message(conn: "ConnectionHandler", state, text=None):
|
||||
await sendAudio(conn, audios)
|
||||
# 等待所有音频包发送完成
|
||||
await _wait_for_audio_completion(conn)
|
||||
# 停止音频发送循环(仅在流控器已初始化时调用)
|
||||
if hasattr(conn, "audio_rate_controller") and conn.audio_rate_controller:
|
||||
conn.audio_rate_controller.stop_sending()
|
||||
|
||||
# 检查是否是当前轮次
|
||||
if current_sentence_id != conn.sentence_id:
|
||||
return
|
||||
|
||||
# 停止音频发送循环(仅在流控器已初始化时调用)
|
||||
if hasattr(conn, "audio_rate_controller") and conn.audio_rate_controller:
|
||||
conn.audio_rate_controller.stop_sending()
|
||||
conn.clearSpeakStatus()
|
||||
|
||||
# 发送消息到客户端
|
||||
|
||||
@@ -83,7 +83,7 @@ class TTSProviderBase(ABC):
|
||||
|
||||
def handle_opus(self, opus_data: bytes):
|
||||
logger.bind(tag=TAG).debug(f"推送数据到队列里面帧数~~ {len(opus_data)}")
|
||||
self.tts_audio_queue.put((SentenceType.MIDDLE, opus_data, None))
|
||||
self.tts_audio_queue.put((SentenceType.MIDDLE, opus_data, None, getattr(self, 'current_sentence_id', None)))
|
||||
|
||||
def handle_audio_file(self, file_audio: bytes, text):
|
||||
self.before_stop_play_files.append((file_audio, text))
|
||||
@@ -97,7 +97,7 @@ class TTSProviderBase(ABC):
|
||||
try:
|
||||
audio_bytes = asyncio.run(self.text_to_speak(text, None))
|
||||
if audio_bytes:
|
||||
self.tts_audio_queue.put((SentenceType.FIRST, None, text))
|
||||
self.tts_audio_queue.put((SentenceType.FIRST, None, text, getattr(self, 'current_sentence_id', None)))
|
||||
audio_bytes_to_data_stream(
|
||||
audio_bytes,
|
||||
file_type=self.audio_file_type,
|
||||
@@ -146,7 +146,7 @@ class TTSProviderBase(ABC):
|
||||
logger.bind(tag=TAG).error(
|
||||
f"语音生成失败: {text},请检查网络或服务是否正常"
|
||||
)
|
||||
self.tts_audio_queue.put((SentenceType.FIRST, None, text))
|
||||
self.tts_audio_queue.put((SentenceType.FIRST, None, text, getattr(self, 'current_sentence_id', None)))
|
||||
self._process_audio_file_stream(tmp_file, callback=opus_handler)
|
||||
except Exception as e:
|
||||
logger.bind(tag=TAG).error(f"Failed to generate TTS file: {e}")
|
||||
@@ -327,7 +327,7 @@ class TTSProviderBase(ABC):
|
||||
logger.bind(tag=TAG).info("收到打断信息,终止TTS文本处理线程")
|
||||
continue
|
||||
if message.sentence_type == SentenceType.FIRST:
|
||||
# 初始化参数
|
||||
self.current_sentence_id = message.sentence_id
|
||||
self.tts_stop_request = False
|
||||
self.processed_chars = 0
|
||||
self.tts_text_buff = []
|
||||
@@ -348,7 +348,7 @@ class TTSProviderBase(ABC):
|
||||
if message.sentence_type == SentenceType.LAST:
|
||||
self._process_remaining_text_stream(opus_handler=self.handle_opus)
|
||||
self.tts_audio_queue.put(
|
||||
(message.sentence_type, [], message.content_detail)
|
||||
(message.sentence_type, [], message.content_detail, message.sentence_id)
|
||||
)
|
||||
|
||||
except queue.Empty:
|
||||
@@ -367,9 +367,12 @@ class TTSProviderBase(ABC):
|
||||
text = None
|
||||
try:
|
||||
try:
|
||||
sentence_type, audio_datas, text = self.tts_audio_queue.get(
|
||||
timeout=0.1
|
||||
)
|
||||
item = self.tts_audio_queue.get(timeout=0.1)
|
||||
if len(item) == 4:
|
||||
sentence_type, audio_datas, text, sentence_id = item
|
||||
else:
|
||||
sentence_type, audio_datas, text = item
|
||||
sentence_id = None
|
||||
except queue.Empty:
|
||||
if self.conn.stop_event.is_set():
|
||||
break
|
||||
@@ -404,7 +407,7 @@ class TTSProviderBase(ABC):
|
||||
|
||||
# 发送音频
|
||||
future = asyncio.run_coroutine_threadsafe(
|
||||
sendAudioMessage(self.conn, sentence_type, audio_datas, text),
|
||||
sendAudioMessage(self.conn, sentence_type, audio_datas, text, sentence_id),
|
||||
self.conn.loop,
|
||||
)
|
||||
future.result()
|
||||
@@ -493,9 +496,9 @@ class TTSProviderBase(ABC):
|
||||
|
||||
def _process_before_stop_play_files(self):
|
||||
for audio_datas, text in self.before_stop_play_files:
|
||||
self.tts_audio_queue.put((SentenceType.MIDDLE, audio_datas, text))
|
||||
self.tts_audio_queue.put((SentenceType.MIDDLE, audio_datas, text, getattr(self, 'current_sentence_id', None)))
|
||||
self.before_stop_play_files.clear()
|
||||
self.tts_audio_queue.put((SentenceType.LAST, [], None))
|
||||
self.tts_audio_queue.put((SentenceType.LAST, [], None, getattr(self, 'current_sentence_id', None)))
|
||||
|
||||
def _process_remaining_text_stream(
|
||||
self, opus_handler: Callable[[bytes], None] = None
|
||||
|
||||
Reference in New Issue
Block a user