From 64f10b28e7ca815a83fff865f5bfcf8857d48870 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Thu, 8 May 2025 11:31:12 +0800 Subject: [PATCH] =?UTF-8?q?update:=E5=90=88=E5=B9=B6main=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xiaozhi-server/core/handle/helloHandle.py | 3 +- .../core/handle/receiveAudioHandle.py | 10 ++-- .../core/handle/sendAudioHandle.py | 2 +- .../xiaozhi-server/core/providers/tts/base.py | 51 +------------------ main/xiaozhi-server/core/utils/util.py | 20 ++++---- 5 files changed, 19 insertions(+), 67 deletions(-) diff --git a/main/xiaozhi-server/core/handle/helloHandle.py b/main/xiaozhi-server/core/handle/helloHandle.py index d40a0533..f902a64f 100644 --- a/main/xiaozhi-server/core/handle/helloHandle.py +++ b/main/xiaozhi-server/core/handle/helloHandle.py @@ -1,5 +1,4 @@ import json -from config.logger import setup_logging from core.handle.sendAudioHandle import send_stt_message from core.utils.util import remove_punctuation_and_length import shutil @@ -25,7 +24,7 @@ async def handleHelloMessage(conn, msg_json): audio_params = msg_json.get("audio_params") if audio_params: format = audio_params.get("format") - logger.bind(tag=TAG).info(f"客户端音频格式: {format}") + conn.logger.bind(tag=TAG).info(f"客户端音频格式: {format}") conn.audio_format = format conn.asr.set_audio_format(format) conn.welcome_msg["audio_params"] = audio_params diff --git a/main/xiaozhi-server/core/handle/receiveAudioHandle.py b/main/xiaozhi-server/core/handle/receiveAudioHandle.py index 383616c3..992ae96f 100644 --- a/main/xiaozhi-server/core/handle/receiveAudioHandle.py +++ b/main/xiaozhi-server/core/handle/receiveAudioHandle.py @@ -5,7 +5,7 @@ from core.handle.sendAudioHandle import send_stt_message from core.handle.intentHandler import handle_user_intent from core.utils.output_counter import check_device_output_limit from core.handle.ttsReportHandle import enqueue_tts_report -from core.providers.tts.base import audio_to_opus_data +from core.utils.util import audio_to_data TAG = __name__ @@ -111,7 +111,7 @@ async def max_out_size(conn): conn.tts_last_text_index = 0 conn.llm_finish_task = True file_path = "config/assets/max_output_size.wav" - opus_packets, _ = audio_to_opus_data(file_path) + opus_packets, _ = audio_to_data(file_path) conn.audio_play_queue.put((opus_packets, text, 0)) conn.close_after_chat = True @@ -133,7 +133,7 @@ async def check_bind_device(conn): # 播放提示音 music_path = "config/assets/bind_code.wav" - opus_packets, _ = audio_to_opus_data(music_path) + opus_packets, _ = audio_to_data(music_path) conn.audio_play_queue.put((opus_packets, text, 0)) # 逐个播放数字 @@ -141,7 +141,7 @@ async def check_bind_device(conn): try: digit = conn.bind_code[i] num_path = f"config/assets/bind_code/{digit}.wav" - num_packets, _ = audio_to_opus_data(num_path) + num_packets, _ = audio_to_data(num_path) conn.audio_play_queue.put((num_packets, None, i + 1)) except Exception as e: conn.logger.bind(tag=TAG).error(f"播放数字音频失败: {e}") @@ -153,5 +153,5 @@ async def check_bind_device(conn): conn.tts_last_text_index = 0 conn.llm_finish_task = True music_path = "config/assets/bind_not_found.wav" - opus_packets, _ = audio_to_opus_data(music_path) + opus_packets, _ = audio_to_data(music_path) conn.audio_play_queue.put((opus_packets, text, 0)) diff --git a/main/xiaozhi-server/core/handle/sendAudioHandle.py b/main/xiaozhi-server/core/handle/sendAudioHandle.py index 78fe743c..89f16426 100644 --- a/main/xiaozhi-server/core/handle/sendAudioHandle.py +++ b/main/xiaozhi-server/core/handle/sendAudioHandle.py @@ -115,7 +115,7 @@ async def send_tts_message(conn, state, text=None): stop_tts_notify_voice = conn.config.get( "stop_tts_notify_voice", "config/assets/tts_notify.mp3" ) - audios, duration = conn.tts.audio_to_opus_data(stop_tts_notify_voice) + audios, _ = conn.tts.audio_to_opus_data(stop_tts_notify_voice) await sendAudio(conn, audios) # 清除服务端讲话状态 conn.clearSpeakStatus() diff --git a/main/xiaozhi-server/core/providers/tts/base.py b/main/xiaozhi-server/core/providers/tts/base.py index 9bc693b0..f2632c02 100644 --- a/main/xiaozhi-server/core/providers/tts/base.py +++ b/main/xiaozhi-server/core/providers/tts/base.py @@ -56,56 +56,7 @@ class TTSProviderBase(ABC): def audio_to_pcm_data(self, audio_file_path): """音频文件转换为PCM编码""" return audio_to_data(audio_file_path, is_opus=False) - + def audio_to_opus_data(self, audio_file_path): """音频文件转换为Opus编码""" return audio_to_data(audio_file_path, is_opus=True) - - def audio_to_data(self, audio_file_path, is_opus=True): - # 获取文件后缀名 - 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) - - # 音频时长(秒) - duration = len(audio) / 1000.0 - - # 获取原始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, duration diff --git a/main/xiaozhi-server/core/utils/util.py b/main/xiaozhi-server/core/utils/util.py index 2ed67b19..effbf38e 100644 --- a/main/xiaozhi-server/core/utils/util.py +++ b/main/xiaozhi-server/core/utils/util.py @@ -862,8 +862,7 @@ def analyze_emotion(text): return top_emotions[0] # 如果都不在优先级列表里,返回第一个 -def audio_to_opus_data(audio_file_path): - """音频文件转换为Opus编码""" +def audio_to_data(audio_file_path, is_opus=True): # 获取文件后缀名 file_type = os.path.splitext(audio_file_path)[1] if file_type: @@ -889,7 +888,7 @@ def audio_to_opus_data(audio_file_path): frame_duration = 60 # 60ms per frame frame_size = int(16000 * frame_duration / 1000) # 960 samples/frame - opus_datas = [] + datas = [] # 按帧处理所有音频数据(包括最后一帧可能补零) for i in range(0, len(raw_data), frame_size * 2): # 16bit=2bytes/sample # 获取当前帧的二进制数据 @@ -899,14 +898,17 @@ def audio_to_opus_data(audio_file_path): if len(chunk) < frame_size * 2: chunk += b"\x00" * (frame_size * 2 - len(chunk)) - # 转换为numpy数组处理 - np_frame = np.frombuffer(chunk, dtype=np.int16) + 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) - # 编码Opus数据 - opus_data = encoder.encode(np_frame.tobytes(), frame_size) - opus_datas.append(opus_data) + datas.append(frame_data) - return opus_datas, duration + return datas, duration def check_vad_update(before_config, new_config):