From 4423cb85c2f760f69bf2388b8b5055a1514718d5 Mon Sep 17 00:00:00 2001 From: JianYu Zheng <2375294554@qq.com> Date: Fri, 15 Aug 2025 11:26:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96:=E4=BC=98=E5=8C=96=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E9=80=BB=E8=BE=91=E5=8E=BB=E9=99=A4=E5=A4=9A=E4=B8=AA?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=85=B1=E4=BA=AB=E5=B1=9E=E6=80=A7=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E9=80=BB=E8=BE=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/js/utils/BlockingQueue.js | 13 +- main/xiaozhi-server/test/test_page.html | 2966 +++++++++-------- 2 files changed, 1525 insertions(+), 1454 deletions(-) diff --git a/main/xiaozhi-server/test/js/utils/BlockingQueue.js b/main/xiaozhi-server/test/js/utils/BlockingQueue.js index d23df942..31a43872 100644 --- a/main/xiaozhi-server/test/js/utils/BlockingQueue.js +++ b/main/xiaozhi-server/test/js/utils/BlockingQueue.js @@ -7,9 +7,16 @@ export default class BlockingQueue { #emptyResolve = null; /* 生产者:把数据塞进去 */ - enqueue(item) { - this.#items.push(item); - + enqueue(item, ...restItems) { + if (restItems.length === 0) { + this.#items.push(item); + } + // 如果有额外参数,批量处理所有项 + else { + const items = [item, ...restItems].filter(i => i); + if (items.length === 0) return; + this.#items.push(...items); + } // 若有空队列闸门,一次性放行所有等待者 if (this.#emptyResolve) { this.#emptyResolve(); diff --git a/main/xiaozhi-server/test/test_page.html b/main/xiaozhi-server/test/test_page.html index 6a70e5ba..1bd8a36a 100644 --- a/main/xiaozhi-server/test/test_page.html +++ b/main/xiaozhi-server/test/test_page.html @@ -8,314 +8,336 @@ -
-

小智服务器测试页面

+
+

小智服务器测试页面

-
- 正在加载Opus库...
+
+ 正在加载Opus库... +
- -
-

- 设备配置 - + +
+

+ 设备配置 + MAC: 客户端: web_test_client - -

-
-
-
- - -
-
- - -
-
- - -
-
- - -
+ +

+
+
+
+ +
-
-
- -
-

- 连接信息 - - OTA: ota未连接 - WS: ws未连接 - -

-
- - - - -
-
- -
-
- - -
- -
-
- - +
+ +
-
- -
-
- +
+ +
- -
-
- -
-

会话记录

-
-
-
-
准备就绪,请连接服务器开始测试...
+
+ +
- - +
+

+ 连接信息 + + OTA: ota未连接 + WS: ws未连接 + +

+
+ + + + +
+
- - // DOM元素 - const connectButton = document.getElementById('connectButton'); - const serverUrlInput = document.getElementById('serverUrl'); - const connectionStatus = document.getElementById('connectionStatus'); - const messageInput = document.getElementById('messageInput'); - const sendTextButton = document.getElementById('sendTextButton'); - const recordButton = document.getElementById('recordButton'); - const stopButton = document.getElementById('stopButton'); - const conversationDiv = document.getElementById('conversation'); - const logContainer = document.getElementById('logContainer'); + + // 编码并发送剩余的数据 + encodeAndSendOpus(); + + // 发送一个空的消息作为结束标志(模拟接收到空音频数据的情况) + if (websocket && websocket.readyState === WebSocket.OPEN) { + // 使用空的Uint8Array发送最后一个空帧 + const emptyOpusFrame = new Uint8Array(0); + websocket.send(emptyOpusFrame); + + // 发送监听结束消息 + const stopMessage = { + type: 'listen', + mode: 'manual', + state: 'stop' + }; + + websocket.send(JSON.stringify(stopMessage)); + log('已发送录音停止信号', 'info'); + } + + // 重置UI + recordButton.textContent = '开始录音'; + recordButton.classList.remove('recording'); + recordButton.disabled = false; + + log('停止PCM直接录音', 'success'); + return true; + } catch (error) { + log(`直接录音停止错误: ${error.message}`, 'error'); + return false; + } + } + + async function handleBinaryMessage(data) { + try { + let arrayBuffer; + // 根据数据类型进行处理 + if (data instanceof ArrayBuffer) { + arrayBuffer = data; + log(`收到ArrayBuffer音频数据,大小: ${data.byteLength}字节`, 'debug'); + } else if (data instanceof Blob) { + // 如果是Blob类型,转换为ArrayBuffer + arrayBuffer = await data.arrayBuffer(); + log(`收到Blob音频数据,大小: ${arrayBuffer.byteLength}字节`, 'debug'); + } else { + log(`收到未知类型的二进制数据: ${typeof data}`, 'warning'); + return; + } + // 创建Uint8Array用于处理 + const opusData = new Uint8Array(arrayBuffer); + if (opusData.length > 0) { + // 将数据添加到缓冲队列 + queue.enqueue(opusData); + } else { + log('收到空音频数据帧,可能是结束标志', 'warning'); + // 如果正在播放,发送结束信号 + if (isAudioPlaying && streamingContext) { + streamingContext.endOfStream = true; + } + } + } catch (error) { + log(`处理二进制消息出错: ${error.message}`, 'error'); + } + } + + // 获取配置值 + function getConfig() { + const deviceMac = document.getElementById('deviceMac').value.trim(); + return { + deviceId: deviceMac, // 使用MAC地址作为deviceId + deviceName: document.getElementById('deviceName').value.trim(), + deviceMac: deviceMac, + clientId: document.getElementById('clientId').value.trim(), + token: document.getElementById('token').value.trim() + }; + } + + initApp(); + \ No newline at end of file