mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-26 00:53:54 +08:00
update:优化代码
This commit is contained in:
@@ -154,6 +154,9 @@ class ConnectionHandler:
|
||||
# {"mcp":true} 表示启用MCP功能
|
||||
self.features = None
|
||||
|
||||
# 标记连接是否来自MQTT
|
||||
self.conn_from_mqtt_gateway = False
|
||||
|
||||
# 初始化提示词管理器
|
||||
self.prompt_manager = PromptManager(config, self.logger)
|
||||
|
||||
@@ -198,6 +201,13 @@ class ConnectionHandler:
|
||||
self.websocket = ws
|
||||
self.device_id = self.headers.get("device-id", None)
|
||||
|
||||
# 检查是否来自MQTT连接
|
||||
request_path = ws.request.path
|
||||
self.conn_from_mqtt_gateway = request_path.endswith("?from=mqtt")
|
||||
self.logger.bind(tag=TAG).info(
|
||||
f"WebSocket URL路径: '{request_path}', 来自MQTT连接: {self.conn_from_mqtt_gateway}"
|
||||
)
|
||||
|
||||
# 初始化活动时间戳
|
||||
self.last_activity_time = time.time() * 1000
|
||||
|
||||
@@ -277,57 +287,64 @@ class ConnectionHandler:
|
||||
if isinstance(message, str):
|
||||
await handleTextMessage(self, message)
|
||||
elif isinstance(message, bytes):
|
||||
if self.vad is None:
|
||||
if self.vad is None or self.asr is None:
|
||||
return
|
||||
if self.asr is None:
|
||||
return
|
||||
|
||||
# 检查是否需要处理头部(只有当websocket URL以"?from=mqtt"为结尾时才处理头部)
|
||||
request_path = self.websocket.request.path
|
||||
need_header_processing = request_path.endswith("?from=mqtt")
|
||||
|
||||
# 调试日志:首次连接时记录配置
|
||||
if not hasattr(self, '_logged_mqtt_config'):
|
||||
self.logger.bind(tag=TAG).info(f"WebSocket URL路径: '{request_path}', 头部处理: {need_header_processing}")
|
||||
self._logged_mqtt_config = True
|
||||
|
||||
if need_header_processing and len(message) >= 16:
|
||||
try:
|
||||
timestamp = int.from_bytes(message[8:12], 'big')
|
||||
audio_length = int.from_bytes(message[12:16], 'big')
|
||||
|
||||
|
||||
# 提取音频数据
|
||||
if audio_length > 0 and len(message) >= 16 + audio_length:
|
||||
audio_data = message[16:16 + audio_length]
|
||||
|
||||
# 基于时间戳进行简单排序
|
||||
self._process_websocket_audio(audio_data, timestamp)
|
||||
return
|
||||
elif len(message) > 16:
|
||||
# 去掉16字节头部
|
||||
audio_data = message[16:]
|
||||
self.asr_audio_queue.put(audio_data)
|
||||
return
|
||||
except Exception as e:
|
||||
self.logger.bind(tag=TAG).error(f"解析WebSocket音频包失败: {e}")
|
||||
|
||||
# 处理来自MQTT网关的音频包
|
||||
if self.conn_from_mqtt_gateway and len(message) >= 16:
|
||||
handled = await self._process_mqtt_audio_message(message)
|
||||
if handled:
|
||||
return
|
||||
|
||||
# 不需要头部处理或没有头部时,直接处理原始消息
|
||||
self.asr_audio_queue.put(message)
|
||||
|
||||
async def _process_mqtt_audio_message(self, message):
|
||||
"""
|
||||
处理来自MQTT网关的音频消息,解析16字节头部并提取音频数据
|
||||
|
||||
Args:
|
||||
message: 包含头部的音频消息
|
||||
|
||||
Returns:
|
||||
bool: 是否成功处理了消息
|
||||
"""
|
||||
try:
|
||||
# 提取头部信息
|
||||
timestamp = int.from_bytes(message[8:12], "big")
|
||||
audio_length = int.from_bytes(message[12:16], "big")
|
||||
|
||||
# 提取音频数据
|
||||
if audio_length > 0 and len(message) >= 16 + audio_length:
|
||||
# 有指定长度,提取精确的音频数据
|
||||
audio_data = message[16 : 16 + audio_length]
|
||||
# 基于时间戳进行排序处理
|
||||
self._process_websocket_audio(audio_data, timestamp)
|
||||
return True
|
||||
elif len(message) > 16:
|
||||
# 没有指定长度或长度无效,去掉头部后处理剩余数据
|
||||
audio_data = message[16:]
|
||||
self.asr_audio_queue.put(audio_data)
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.bind(tag=TAG).error(f"解析WebSocket音频包失败: {e}")
|
||||
|
||||
# 处理失败,返回False表示需要继续处理
|
||||
return False
|
||||
|
||||
def _process_websocket_audio(self, audio_data, timestamp):
|
||||
"""处理WebSocket格式的音频包"""
|
||||
# 初始化时间戳序列管理
|
||||
if not hasattr(self, 'audio_timestamp_buffer'):
|
||||
if not hasattr(self, "audio_timestamp_buffer"):
|
||||
self.audio_timestamp_buffer = {}
|
||||
self.last_processed_timestamp = 0
|
||||
self.max_timestamp_buffer_size = 20
|
||||
|
||||
|
||||
# 如果时间戳是递增的,直接处理
|
||||
if timestamp >= self.last_processed_timestamp:
|
||||
self.asr_audio_queue.put(audio_data)
|
||||
self.last_processed_timestamp = timestamp
|
||||
|
||||
|
||||
# 处理缓冲区中的后续包
|
||||
processed_any = True
|
||||
while processed_any:
|
||||
@@ -346,30 +363,6 @@ class ConnectionHandler:
|
||||
else:
|
||||
self.asr_audio_queue.put(audio_data)
|
||||
|
||||
def _process_sequenced_audio(self, audio_data, sequence, timestamp):
|
||||
"""处理有序的音频包"""
|
||||
# 初始化音频缓冲区
|
||||
if not hasattr(self, 'audio_buffer'):
|
||||
self.audio_buffer = {}
|
||||
self.expected_sequence = sequence
|
||||
self.max_buffer_size = 20 # 最大缓冲20个包
|
||||
|
||||
# 如果是下一个期望的包,直接处理
|
||||
if sequence == self.expected_sequence:
|
||||
self.asr_audio_queue.put(audio_data)
|
||||
self.expected_sequence += 1
|
||||
|
||||
# 检查缓冲区中是否有后续的连续包
|
||||
while self.expected_sequence in self.audio_buffer:
|
||||
buffered_audio = self.audio_buffer.pop(self.expected_sequence)
|
||||
self.asr_audio_queue.put(buffered_audio)
|
||||
self.expected_sequence += 1
|
||||
|
||||
elif sequence > self.expected_sequence:
|
||||
# 乱序包,暂存到缓冲区
|
||||
if len(self.audio_buffer) < self.max_buffer_size:
|
||||
self.audio_buffer[sequence] = audio_data
|
||||
|
||||
async def handle_restart(self, message):
|
||||
"""处理服务器重启请求"""
|
||||
try:
|
||||
@@ -940,7 +933,11 @@ class ConnectionHandler:
|
||||
{
|
||||
"id": function_id,
|
||||
"function": {
|
||||
"arguments": "{}" if function_arguments == "" else function_arguments,
|
||||
"arguments": (
|
||||
"{}"
|
||||
if function_arguments == ""
|
||||
else function_arguments
|
||||
),
|
||||
"name": function_name,
|
||||
},
|
||||
"type": "function",
|
||||
@@ -1009,9 +1006,9 @@ class ConnectionHandler:
|
||||
"""资源清理方法"""
|
||||
try:
|
||||
# 清理音频缓冲区
|
||||
if hasattr(self, 'audio_buffer'):
|
||||
if hasattr(self, "audio_buffer"):
|
||||
self.audio_buffer.clear()
|
||||
|
||||
|
||||
# 取消超时任务
|
||||
if self.timeout_task and not self.timeout_task.done():
|
||||
self.timeout_task.cancel()
|
||||
|
||||
Reference in New Issue
Block a user