mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 20:33:51 +08:00
fix: 优化
This commit is contained in:
@@ -3,7 +3,7 @@ import json
|
|||||||
import random
|
import random
|
||||||
import asyncio
|
import asyncio
|
||||||
from core.utils.dialogue import Message
|
from core.utils.dialogue import Message
|
||||||
from core.utils.util import audio_to_data_stream
|
from core.utils.util import audio_to_data
|
||||||
from core.providers.tts.dto.dto import SentenceType
|
from core.providers.tts.dto.dto import SentenceType
|
||||||
from core.utils.wakeup_word import WakeupWordsConfig
|
from core.utils.wakeup_word import WakeupWordsConfig
|
||||||
from core.handle.sendAudioHandle import sendAudioMessage, send_stt_message
|
from core.handle.sendAudioHandle import sendAudioMessage, send_stt_message
|
||||||
@@ -91,12 +91,7 @@ async def checkWakeupWords(conn, text):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# 获取音频数据
|
# 获取音频数据
|
||||||
opus_packets = []
|
opus_packets = audio_to_data(response.get("file_path"))
|
||||||
def handle_audio_frame(frame_data):
|
|
||||||
opus_packets.append(frame_data)
|
|
||||||
|
|
||||||
audio_to_data_stream(response.get("file_path"), is_opus=True, callback=handle_audio_frame)
|
|
||||||
|
|
||||||
# 播放唤醒词回复
|
# 播放唤醒词回复
|
||||||
conn.client_abort = False
|
conn.client_abort = False
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import json
|
|||||||
import time
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
from core.utils import textUtils
|
from core.utils import textUtils
|
||||||
from core.utils.util import audio_to_data_stream
|
from core.utils.util import audio_to_data
|
||||||
from core.providers.tts.dto.dto import SentenceType
|
from core.providers.tts.dto.dto import SentenceType
|
||||||
|
|
||||||
TAG = __name__
|
TAG = __name__
|
||||||
@@ -120,12 +120,7 @@ async def send_tts_message(conn, state, text=None):
|
|||||||
stop_tts_notify_voice = conn.config.get(
|
stop_tts_notify_voice = conn.config.get(
|
||||||
"stop_tts_notify_voice", "config/assets/tts_notify.mp3"
|
"stop_tts_notify_voice", "config/assets/tts_notify.mp3"
|
||||||
)
|
)
|
||||||
# 获取音频数据
|
audios = audio_to_data(stop_tts_notify_voice, is_opus=True)
|
||||||
audios = []
|
|
||||||
def handle_audio_frame(frame_data):
|
|
||||||
audios.append(frame_data)
|
|
||||||
|
|
||||||
audio_to_data_stream(stop_tts_notify_voice, is_opus=True, callback=handle_audio_frame)
|
|
||||||
await sendAudio(conn, audios)
|
await sendAudio(conn, audios)
|
||||||
# 清除服务端讲话状态
|
# 清除服务端讲话状态
|
||||||
conn.clearSpeakStatus()
|
conn.clearSpeakStatus()
|
||||||
|
|||||||
@@ -230,6 +230,56 @@ def audio_to_data_stream(audio_file_path, is_opus=True, callback: Callable[[Any]
|
|||||||
raw_data = audio.raw_data
|
raw_data = audio.raw_data
|
||||||
pcm_to_data_stream(raw_data, is_opus, callback)
|
pcm_to_data_stream(raw_data, is_opus, callback)
|
||||||
|
|
||||||
|
def audio_to_data(audio_file_path: str, is_opus: bool = True) -> list[bytes]:
|
||||||
|
"""
|
||||||
|
将音频文件转换为Opus/PCM编码的帧列表
|
||||||
|
Args:
|
||||||
|
audio_file_path: 音频文件路径
|
||||||
|
is_opus: 是否进行Opus编码
|
||||||
|
"""
|
||||||
|
# 获取文件后缀名
|
||||||
|
file_type = os.path.splitext(audio_file_path)[1]
|
||||||
|
if file_type:
|
||||||
|
file_type = file_type.lstrip(".")
|
||||||
|
# 读取音频文件,-nostdin 参数:不要从标准输入读取数据,否则FFmpeg会阻塞
|
||||||
|
audio = AudioSegment.from_file(
|
||||||
|
audio_file_path, format=file_type, parameters=["-nostdin"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# 转换为单声道/16kHz采样率/16位小端编码(确保与编码器匹配)
|
||||||
|
audio = audio.set_channels(1).set_frame_rate(16000).set_sample_width(2)
|
||||||
|
|
||||||
|
# 获取原始PCM数据(16位小端)
|
||||||
|
raw_data = audio.raw_data
|
||||||
|
|
||||||
|
# 初始化Opus编码器
|
||||||
|
encoder = opuslib_next.Encoder(16000, 1, opuslib_next.APPLICATION_AUDIO)
|
||||||
|
|
||||||
|
# 编码参数
|
||||||
|
frame_duration = 60 # 60ms per frame
|
||||||
|
frame_size = int(16000 * frame_duration / 1000) # 960 samples/frame
|
||||||
|
|
||||||
|
datas = []
|
||||||
|
# 按帧处理所有音频数据(包括最后一帧可能补零)
|
||||||
|
for i in range(0, len(raw_data), frame_size * 2): # 16bit=2bytes/sample
|
||||||
|
# 获取当前帧的二进制数据
|
||||||
|
chunk = raw_data[i : i + frame_size * 2]
|
||||||
|
|
||||||
|
# 如果最后一帧不足,补零
|
||||||
|
if len(chunk) < frame_size * 2:
|
||||||
|
chunk += b"\x00" * (frame_size * 2 - len(chunk))
|
||||||
|
|
||||||
|
if is_opus:
|
||||||
|
# 转换为numpy数组处理
|
||||||
|
np_frame = np.frombuffer(chunk, dtype=np.int16)
|
||||||
|
# 编码Opus数据
|
||||||
|
frame_data = encoder.encode(np_frame.tobytes(), frame_size)
|
||||||
|
else:
|
||||||
|
frame_data = chunk if isinstance(chunk, bytes) else bytes(chunk)
|
||||||
|
|
||||||
|
datas.append(frame_data)
|
||||||
|
|
||||||
|
return datas
|
||||||
|
|
||||||
def audio_bytes_to_data_stream(audio_bytes, file_type, is_opus, callback: Callable[[Any], Any]) -> None:
|
def audio_bytes_to_data_stream(audio_bytes, file_type, is_opus, callback: Callable[[Any], Any]) -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user