fix:重写 audio_to_opus_data_stream 方法,让音频文件处理使用独立编码器,避免与 TTS 流编码器冲突。

This commit is contained in:
hrz
2026-03-01 12:59:45 +08:00
parent acf45ae8ad
commit a4583e273a
4 changed files with 74 additions and 3 deletions
@@ -6,6 +6,7 @@ import queue
import asyncio import asyncio
import traceback import traceback
import websockets import websockets
from typing import Callable, Any
from asyncio import Task from asyncio import Task
from config.logger import setup_logging from config.logger import setup_logging
from core.utils import opus_encoder_utils from core.utils import opus_encoder_utils
@@ -383,6 +384,24 @@ class TTSProvider(TTSProviderBase):
finally: finally:
self._monitor_task = None self._monitor_task = None
def audio_to_opus_data_stream(
self, audio_file_path, callback: Callable[[Any], Any] = None
):
"""重写父类方法:使用独立的临时编码器处理音频文件,避免与TTS流式编码器并发冲突。
双流式TTS中,monitor任务在event loop线程接收TTS音频并使用self.opus_encoder编码,
同时tts_text_priority_thread处理音乐文件也使用self.opus_encoder
共享的encoder.buffer非线程安全,并发访问会导致SILK resampler断言失败。
"""
from core.utils.util import audio_to_data_stream
return audio_to_data_stream(
audio_file_path,
is_opus=True,
callback=callback,
sample_rate=self.conn.sample_rate,
opus_encoder=None,
)
def to_tts(self, text: str) -> list: def to_tts(self, text: str) -> list:
"""非流式生成音频数据,用于生成音频及测试场景""" """非流式生成音频数据,用于生成音频及测试场景"""
try: try:
@@ -8,6 +8,7 @@ import time
import queue import queue
import asyncio import asyncio
import traceback import traceback
from typing import Callable, Any
from asyncio import Task from asyncio import Task
import websockets import websockets
import os import os
@@ -463,6 +464,24 @@ class TTSProvider(TTSProviderBase):
finally: finally:
self._monitor_task = None self._monitor_task = None
def audio_to_opus_data_stream(
self, audio_file_path, callback: Callable[[Any], Any] = None
):
"""重写父类方法:使用独立的临时编码器处理音频文件,避免与TTS流式编码器并发冲突。
双流式TTS中,monitor任务在event loop线程接收TTS音频并使用self.opus_encoder编码,
同时tts_text_priority_thread处理音乐文件也使用self.opus_encoder
共享的encoder.buffer非线程安全,并发访问会导致SILK resampler断言失败。
"""
from core.utils.util import audio_to_data_stream
return audio_to_data_stream(
audio_file_path,
is_opus=True,
callback=callback,
sample_rate=self.conn.sample_rate,
opus_encoder=None,
)
def to_tts(self, text: str) -> list: def to_tts(self, text: str) -> list:
"""非流式TTS处理,用于测试及保存音频文件的场景""" """非流式TTS处理,用于测试及保存音频文件的场景"""
try: try:
@@ -683,6 +683,20 @@ class TTSProvider(TTSProviderBase):
) )
) )
def audio_to_opus_data_stream(
self, audio_file_path, callback: Callable[[Any], Any] = None
):
"""重写父类方法:使用独立的临时编码器处理音频文件,避免与TTS流式编码器并发冲突。
双流式TTS中,monitor任务在event loop线程接收TTS音频并使用self.opus_encoder编码,
同时tts_text_priority_thread处理音乐文件也使用self.opus_encoder
共享的encoder.buffer非线程安全,并发访问会导致SILK resampler断言失败。
"""
from core.utils.util import audio_to_data_stream
return audio_to_data_stream(
audio_file_path, is_opus=True, callback=callback,
sample_rate=self.conn.sample_rate, opus_encoder=None
)
def wav_to_opus_data_audio_raw_stream(self, raw_data_var, is_end=False, callback: Callable[[Any], Any]=None): def wav_to_opus_data_audio_raw_stream(self, raw_data_var, is_end=False, callback: Callable[[Any], Any]=None):
return self.opus_encoder.encode_pcm_to_opus_stream(raw_data_var, is_end, callback=callback) return self.opus_encoder.encode_pcm_to_opus_stream(raw_data_var, is_end, callback=callback)
@@ -9,6 +9,7 @@ import hashlib
import asyncio import asyncio
import traceback import traceback
import websockets import websockets
from typing import Callable, Any
from asyncio import Task from asyncio import Task
from config.logger import setup_logging from config.logger import setup_logging
from core.utils import opus_encoder_utils from core.utils import opus_encoder_utils
@@ -472,9 +473,27 @@ class TTSProvider(TTSProviderBase):
return audio_data return audio_data
except Exception as e: except Exception as e:
logger.bind(tag=TAG).error(f"生成音频数据失败: {str(e)}") logger.bind(tag=TAG).error(f"生成音频数据失败: {str(e)}")
return [] return []
def _build_base_request(self, status,text=" "): def audio_to_opus_data_stream(
self, audio_file_path, callback: Callable[[Any], Any] = None
):
"""重写父类方法:使用独立的临时编码器处理音频文件,避免与TTS流式编码器并发冲突。
双流式TTS中,monitor任务在event loop线程接收TTS音频并使用self.opus_encoder编码,
同时tts_text_priority_thread处理音乐文件也使用self.opus_encoder
共享的encoder.buffer非线程安全,并发访问会导致SILK resampler断言失败。
"""
from core.utils.util import audio_to_data_stream
return audio_to_data_stream(
audio_file_path,
is_opus=True,
callback=callback,
sample_rate=self.conn.sample_rate,
opus_encoder=None,
)
def _build_base_request(self, status, text=" "):
"""构建基础请求结构""" """构建基础请求结构"""
return { return {
"header": { "header": {