update:优化测试web工具

This commit is contained in:
hrz
2025-03-31 21:04:11 +08:00
parent 6bd7ad9413
commit e11a37ffec
3 changed files with 486 additions and 411 deletions
@@ -19,6 +19,7 @@ import xiaozhi.common.page.TokenDTO;
import xiaozhi.common.user.UserDetail; import xiaozhi.common.user.UserDetail;
import xiaozhi.common.utils.Result; import xiaozhi.common.utils.Result;
import xiaozhi.common.validator.AssertUtils; import xiaozhi.common.validator.AssertUtils;
import xiaozhi.common.validator.ValidatorUtils;
import xiaozhi.modules.security.dto.LoginDTO; import xiaozhi.modules.security.dto.LoginDTO;
import xiaozhi.modules.security.password.PasswordUtils; import xiaozhi.modules.security.password.PasswordUtils;
import xiaozhi.modules.security.service.CaptchaService; import xiaozhi.modules.security.service.CaptchaService;
@@ -104,6 +105,8 @@ public class LoginController {
@PutMapping("/change-password") @PutMapping("/change-password")
@Operation(summary = "修改用户密码") @Operation(summary = "修改用户密码")
public Result<?> changePassword(@RequestBody PasswordDTO passwordDTO) { public Result<?> changePassword(@RequestBody PasswordDTO passwordDTO) {
// 判断非空
ValidatorUtils.validateEntity(passwordDTO);
Long userId = SecurityUser.getUserId(); Long userId = SecurityUser.getUserId();
sysUserTokenService.changePassword(userId, passwordDTO); sysUserTokenService.changePassword(userId, passwordDTO);
return new Result<>(); return new Result<>();
@@ -90,7 +90,6 @@ public class Oauth2Filter extends AuthenticatingFilter {
String json = JsonUtils.toJsonString(r); String json = JsonUtils.toJsonString(r);
httpResponse.getWriter().print(json); httpResponse.getWriter().print(json);
} catch (IOException e1) { } catch (IOException e1) {
logger.error("onLoginFailure:登录失败! msg:{}", e1.getMessage(), e1);
} }
return false; return false;
+234 -161
View File
@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN"> <html lang="zh-CN">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,36 +12,45 @@
padding: 20px; padding: 20px;
background-color: #f5f5f5; background-color: #f5f5f5;
} }
.container { .container {
max-width: 800px; max-width: 800px;
margin: 0 auto; margin: 0 auto;
background-color: white; background-color: white;
border-radius: 10px; border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 20px; padding: 10px 20px 10px 20px;
} }
h1 { h1 {
color: #333; color: #333;
text-align: center; text-align: center;
margin-bottom: 30px; margin-bottom: 30px;
} }
.section { .section {
margin-bottom: 20px; margin-bottom: 20px;
padding: 15px; padding: 15px;
border-radius: 8px; border-radius: 8px;
background-color: #f9f9f9; background-color: #f9f9f9;
} }
.section h2 { .section h2 {
margin-top: 0; margin-top: 0;
color: #444; color: #444;
font-size: 18px; font-size: 18px;
display: flex;
align-items: center;
gap: 10px;
} }
.control-panel { .control-panel {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 10px; gap: 10px;
margin-bottom: 20px; margin-top: 10px;
} }
button { button {
padding: 8px 15px; padding: 8px 15px;
border: none; border: none;
@@ -50,36 +60,43 @@
cursor: pointer; cursor: pointer;
transition: background-color 0.2s; transition: background-color 0.2s;
} }
button:hover { button:hover {
background-color: #3367d6; background-color: #3367d6;
} }
button:disabled { button:disabled {
background-color: #cccccc; background-color: #cccccc;
cursor: not-allowed; cursor: not-allowed;
} }
#serverUrl { #serverUrl {
flex-grow: 1; flex-grow: 1;
padding: 8px; padding: 8px;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 5px; border-radius: 5px;
} }
.message-input { .message-input {
display: flex; display: flex;
gap: 10px; gap: 10px;
margin-bottom: 20px; margin-bottom: 20px;
} }
#messageInput { #messageInput {
flex-grow: 1; flex-grow: 1;
padding: 8px; padding: 8px;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 5px; border-radius: 5px;
} }
#nfcCardId { #nfcCardId {
flex-grow: 1; flex-grow: 1;
padding: 8px; padding: 8px;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 5px; border-radius: 5px;
} }
.conversation { .conversation {
max-height: 300px; max-height: 300px;
overflow-y: auto; overflow-y: auto;
@@ -87,36 +104,45 @@
border-radius: 5px; border-radius: 5px;
padding: 10px; padding: 10px;
background-color: white; background-color: white;
flex: 1;
margin-right: 10px;
} }
.message { .message {
margin-bottom: 10px; margin-bottom: 10px;
padding: 8px 12px; padding: 8px 12px;
border-radius: 8px; border-radius: 8px;
max-width: 80%; max-width: 80%;
} }
.user { .user {
background-color: #e2f2ff; background-color: #e2f2ff;
margin-left: auto; margin-left: auto;
margin-right: 10px; margin-right: 10px;
text-align: right; text-align: right;
} }
.server { .server {
background-color: #f0f0f0; background-color: #f0f0f0;
margin-right: auto; margin-right: auto;
margin-left: 10px; margin-left: 10px;
} }
.status { .status {
color: #666; color: #666;
font-style: italic; font-style: italic;
text-align: center; font-size: 14px;
margin-bottom: 10px; margin: 0;
padding: 0;
} }
.audio-controls { .audio-controls {
display: flex; display: flex;
justify-content: center; justify-content: center;
gap: 10px; gap: 10px;
margin-top: 20px; margin-top: 20px;
} }
.audio-visualizer { .audio-visualizer {
height: 60px; height: 60px;
width: 100%; width: 100%;
@@ -125,45 +151,72 @@
border-radius: 5px; border-radius: 5px;
background-color: #fafafa; background-color: #fafafa;
} }
.record-button { .record-button {
background-color: #db4437; background-color: #db4437;
} }
.record-button:hover { .record-button:hover {
background-color: #c53929; background-color: #c53929;
} }
.record-button.recording { .record-button.recording {
animation: pulse 1.5s infinite; animation: pulse 1.5s infinite;
} }
@keyframes pulse { @keyframes pulse {
0% { background-color: #db4437; } 0% {
50% { background-color: #ff6659; } background-color: #db4437;
100% { background-color: #db4437; } }
50% {
background-color: #ff6659;
}
100% {
background-color: #db4437;
}
} }
#logContainer { #logContainer {
margin-top: 20px; margin-top: 0;
padding: 10px; padding: 10px;
background-color: #f0f0f0; background-color: #f0f0f0;
border-radius: 5px; border-radius: 5px;
font-family: monospace; font-family: monospace;
height: 150px; height: 300px;
overflow-y: auto; overflow-y: auto;
flex: 1;
margin-left: 10px;
} }
.log-entry { .log-entry {
margin: 5px 0; margin: 5px 0;
font-size: 12px; font-size: 12px;
} }
.log-info { color: #333; }
.log-error { color: #db4437; } .log-info {
.log-success { color: #0f9d58; } color: #333;
.info-box { }
background-color: #e8f4ff;
border-left: 4px solid #4285f4; .log-error {
width: auto; color: #db4437;
display: none; }
margin: 10px 0;
padding: 10px; .log-success {
font-size: 14px; color: #0f9d58;
line-height: 1.5; }
@keyframes fadeIn {
from {
opacity: 0;
transform: translate(-50%, -60%);
}
to {
opacity: 1;
transform: translate(-50%, -50%);
}
} }
.script-status { .script-status {
@@ -174,9 +227,17 @@
margin-right: 5px; margin-right: 5px;
} }
.script-loaded { background-color: #0f9d58; } .script-loaded {
.script-loading { background-color: #f4b400; } background-color: #0f9d58;
.script-error { background-color: #db4437; } }
.script-loading {
background-color: #f4b400;
}
.script-error {
background-color: #db4437;
}
.script-list { .script-list {
margin: 10px 0; margin: 10px 0;
@@ -187,14 +248,6 @@
font-size: 11px; font-size: 11px;
} }
/* 状态消息样式 */
#scriptStatus {
padding: 10px 15px;
border-radius: 5px;
margin-bottom: 15px;
font-weight: bold;
}
#scriptStatus.success { #scriptStatus.success {
background-color: #e6f4ea; background-color: #e6f4ea;
color: #0f9d58; color: #0f9d58;
@@ -212,57 +265,106 @@
color: #f4b400; color: #f4b400;
border-left: 4px solid #f4b400; border-left: 4px solid #f4b400;
} }
/* 标签页样式 */
.tabs {
display: flex;
margin-bottom: 20px;
border-bottom: 2px solid #e0e0e0;
}
.tab {
padding: 10px 20px;
cursor: pointer;
border: none;
background: none;
font-size: 16px;
color: #666;
position: relative;
transition: all 0.3s ease;
}
.tab:hover {
color: #4285f4;
}
.tab.active {
color: #4285f4;
font-weight: bold;
}
.tab.active::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 100%;
height: 2px;
background-color: #4285f4;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.flex-container {
display: flex;
gap: 20px;
margin-top: 10px;
}
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1>小智服务器测试页面</h1> <h1>小智服务器测试页面</h1>
<div id="scriptStatus" class="info-box"></div> <div id="scriptStatus" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);">
正在加载Opus库...</div>
<div class="section"> <div class="section">
<h2>WebSocket连接</h2> <h2>WebSocket连接 <span id="connectionStatus" class="status">未连接</span></h2>
<div class="control-panel"> <div class="control-panel">
<input type="text" id="serverUrl" value="ws://localhost:8000" placeholder="WebSocket服务器地址"> <input type="text" id="serverUrl" value="ws://127.0.0.1:8000/xiaozhi/v1/" placeholder="WebSocket服务器地址">
<button id="connectButton">连接</button> <button id="connectButton">连接</button>
<button id="disconnectButton" disabled>断开</button>
<button id="authTestButton">测试认证</button> <button id="authTestButton">测试认证</button>
</div> </div>
<div id="connectionStatus" class="status">未连接</div>
</div> </div>
<div class="section"> <div class="section">
<h2>文本消息</h2> <h2>消息发送</h2>
<div class="message-input"> <div class="tabs">
<input type="text" id="messageInput" placeholder="输入消息..." disabled> <button class="tab active" data-tab="text">文本消息</button>
<button id="sendTextButton" disabled>发送</button> <button class="tab" data-tab="voice">语音消息</button>
</div> </div>
</div>
<div class="section"> <div class="tab-content active" id="textTab">
<h2>NFC卡片模拟</h2> <div class="message-input">
<div class="message-input"> <input type="text" id="messageInput" placeholder="输入消息..." disabled>
<input type="text" id="nfcCardId" placeholder="输入NFC卡片ID..." value="ABCD1234EFGH5678" disabled> <button id="sendTextButton" disabled>发送</button>
<button id="sendNfcButton" disabled>模拟NFC卡片</button> </div>
</div> </div>
</div>
<div class="section"> <div class="tab-content" id="voiceTab">
<h2>语音消息</h2> <div class="audio-controls">
<div class="audio-controls"> <button id="recordButton" class="record-button" disabled>开始录音</button>
<button id="recordButton" class="record-button" disabled>开始录音</button> </div>
<button id="stopButton" disabled>停止录音并发送</button> <canvas id="audioVisualizer" class="audio-visualizer"></canvas>
</div> </div>
<canvas id="audioVisualizer" class="audio-visualizer"></canvas>
</div> </div>
<div class="section"> <div class="section">
<h2>会话记录</h2> <h2>会话记录</h2>
<div id="conversation" class="conversation"></div> <div class="flex-container">
</div> <div id="conversation" class="conversation"></div>
<div id="logContainer">
<div id="logContainer"> <div class="log-entry log-info">准备就绪,请连接服务器开始测试...</div>
<div class="log-entry log-info">准备就绪,请连接服务器开始测试...</div> </div>
</div>
</div> </div>
</div> </div>
@@ -283,48 +385,42 @@
// 检查Opus库是否已加载 // 检查Opus库是否已加载
function checkOpusLoaded() { function checkOpusLoaded() {
// setTimeout(() => { try {
try { // 检查Module是否存在(本地库导出的全局变量)
// 检查Module是否存在(本地库导出的全局变量) if (typeof Module === 'undefined') {
if (typeof Module === 'undefined') { throw new Error('Opus库未加载,Module对象不存在');
throw new Error('Opus库未加载,Module对象不存在');
}
// 尝试先使用Module.instancelibopus.js最后一行导出方式)
if (typeof Module.instance !== 'undefined' && typeof Module.instance._opus_decoder_get_size === 'function') {
// 使用Module.instance对象替换全局Module对象
window.ModuleInstance = Module.instance;
log('Opus库加载成功(使用Module.instance', 'success');
updateScriptStatus('Opus库加载成功', 'success');
// 3秒后隐藏状态
setTimeout(() => {
const statusElement = document.getElementById('scriptStatus');
if (statusElement) statusElement.style.display = 'none';
}, 3000);
return;
}
// 如果没有Module.instance,检查全局Module函数
if (typeof Module._opus_decoder_get_size === 'function') {
window.ModuleInstance = Module;
log('Opus库加载成功(使用全局Module', 'success');
updateScriptStatus('Opus库加载成功', 'success');
// 3秒后隐藏状态
setTimeout(() => {
const statusElement = document.getElementById('scriptStatus');
if (statusElement) statusElement.style.display = 'none';
}, 3000);
return;
}
throw new Error('Opus解码函数未找到,可能Module结构不正确');
} catch (err) {
log(`Opus库加载失败,请检查libopus.js文件是否存在且正确: ${err.message}`, 'error');
updateScriptStatus('Opus库加载失败,请检查libopus.js文件是否存在且正确', 'error');
} }
// }, 1000); // 延迟1秒检查,确保脚本有时间加载
// 尝试先使用Module.instancelibopus.js最后一行导出方式)
if (typeof Module.instance !== 'undefined' && typeof Module.instance._opus_decoder_get_size === 'function') {
// 使用Module.instance对象替换全局Module对象
window.ModuleInstance = Module.instance;
log('Opus库加载成功(使用Module.instance', 'success');
updateScriptStatus('Opus库加载成功', 'success');
// 3秒后隐藏状态
const statusElement = document.getElementById('scriptStatus');
if (statusElement) statusElement.style.display = 'none';
return;
}
// 如果没有Module.instance,检查全局Module函数
if (typeof Module._opus_decoder_get_size === 'function') {
window.ModuleInstance = Module;
log('Opus库加载成功(使用全局Module', 'success');
updateScriptStatus('Opus库加载成功', 'success');
// 3秒后隐藏状态
const statusElement = document.getElementById('scriptStatus');
if (statusElement) statusElement.style.display = 'none';
return;
}
throw new Error('Opus解码函数未找到,可能Module结构不正确');
} catch (err) {
log(`Opus库加载失败,请检查libopus.js文件是否存在且正确: ${err.message}`, 'error');
updateScriptStatus('Opus库加载失败,请检查libopus.js文件是否存在且正确', 'error');
}
} }
// 更新脚本状态显示 // 更新脚本状态显示
@@ -358,13 +454,10 @@
// DOM元素 // DOM元素
const connectButton = document.getElementById('connectButton'); const connectButton = document.getElementById('connectButton');
const disconnectButton = document.getElementById('disconnectButton');
const serverUrlInput = document.getElementById('serverUrl'); const serverUrlInput = document.getElementById('serverUrl');
const connectionStatus = document.getElementById('connectionStatus'); const connectionStatus = document.getElementById('connectionStatus');
const messageInput = document.getElementById('messageInput'); const messageInput = document.getElementById('messageInput');
const sendTextButton = document.getElementById('sendTextButton'); const sendTextButton = document.getElementById('sendTextButton');
const nfcCardIdInput = document.getElementById('nfcCardId');
const sendNfcButton = document.getElementById('sendNfcButton');
const recordButton = document.getElementById('recordButton'); const recordButton = document.getElementById('recordButton');
const stopButton = document.getElementById('stopButton'); const stopButton = document.getElementById('stopButton');
const conversationDiv = document.getElementById('conversation'); const conversationDiv = document.getElementById('conversation');
@@ -433,7 +526,6 @@
conversationDiv.scrollTop = conversationDiv.scrollHeight; conversationDiv.scrollTop = conversationDiv.scrollHeight;
} }
// 播放Opus音频数据 // 播放Opus音频数据
function playOpusData(opusBuffers) { function playOpusData(opusBuffers) {
if (!opusBuffers || opusBuffers.length === 0) { if (!opusBuffers || opusBuffers.length === 0) {
@@ -482,7 +574,7 @@
module: window.ModuleInstance, // 保存模块实例的引用 module: window.ModuleInstance, // 保存模块实例的引用
// 使用ModuleInstance提供的函数来解码 // 使用ModuleInstance提供的函数来解码
decode_float: function(opusData) { decode_float: function (opusData) {
try { try {
const mod = this.module; // 简写引用 const mod = this.module; // 简写引用
@@ -527,7 +619,7 @@
// 从内存中复制PCM数据 // 从内存中复制PCM数据
const pcmData = new Float32Array(samplesDecoded); const pcmData = new Float32Array(samplesDecoded);
for (let i = 0; i < samplesDecoded; i++) { for (let i = 0; i < samplesDecoded; i++) {
pcmData[i] = mod.HEAPF32[pcmPtr/4 + i]; pcmData[i] = mod.HEAPF32[pcmPtr / 4 + i];
} }
// 释放内存 // 释放内存
@@ -562,7 +654,7 @@
const opusBuffer = opusBuffers[i]; const opusBuffer = opusBuffers[i];
// 确保这是Uint8Array // 确保这是Uint8Array
const opusArray = opusBuffer instanceof Uint8Array ? const opusArray = opusBuffer instanceof Uint8Array ?
opusBuffer : new Uint8Array(opusBuffer); opusBuffer : new Uint8Array(opusBuffer);
// 解码Opus帧为PCM数据 // 解码Opus帧为PCM数据
const decoded = opusDecoder.decode_float(opusArray); const decoded = opusDecoder.decode_float(opusArray);
@@ -571,7 +663,7 @@
successCount++; successCount++;
} }
} catch (error) { } catch (error) {
log(`Opus帧 #${i+1} 解码错误: ${error.message}`, 'error'); log(`Opus帧 #${i + 1} 解码错误: ${error.message}`, 'error');
} }
} }
@@ -616,7 +708,7 @@
}; };
source.start(); source.start();
log(`开始播放PCM音频,时长: ${(combinedPCM.length/16000).toFixed(2)}`, 'debug'); log(`开始播放PCM音频,时长: ${(combinedPCM.length / 16000).toFixed(2)}`, 'debug');
} catch (error) { } catch (error) {
log(`播放Opus音频错误: ${error.message},尝试使用简单播放`, 'error'); log(`播放Opus音频错误: ${error.message},尝试使用简单播放`, 'error');
@@ -911,12 +1003,10 @@
// 连接成功后发送hello消息 // 连接成功后发送hello消息
await sendHelloMessage(); await sendHelloMessage();
connectButton.disabled = true; connectButton.textContent = '断开';
disconnectButton.disabled = false; connectButton.onclick = disconnectFromServer;
messageInput.disabled = false; messageInput.disabled = false;
sendTextButton.disabled = false; sendTextButton.disabled = false;
nfcCardIdInput.disabled = false;
sendNfcButton.disabled = false;
const audioInitialized = await initAudio(); const audioInitialized = await initAudio();
if (audioInitialized) { if (audioInitialized) {
@@ -929,14 +1019,12 @@
connectionStatus.textContent = '已断开'; connectionStatus.textContent = '已断开';
connectionStatus.style.color = 'red'; connectionStatus.style.color = 'red';
connectButton.disabled = false; connectButton.textContent = '连接';
disconnectButton.disabled = true; connectButton.onclick = connectToServer;
messageInput.disabled = true; messageInput.disabled = true;
sendTextButton.disabled = true; sendTextButton.disabled = true;
recordButton.disabled = true; recordButton.disabled = true;
stopButton.disabled = true; stopButton.disabled = true;
nfcCardIdInput.disabled = true;
sendNfcButton.disabled = true;
}; };
websocket.onerror = (error) => { websocket.onerror = (error) => {
@@ -945,7 +1033,7 @@
connectionStatus.style.color = 'red'; connectionStatus.style.color = 'red';
}; };
websocket.onmessage = function(event) { websocket.onmessage = function (event) {
try { try {
// 检查是否为文本消息 // 检查是否为文本消息
if (typeof event.data === 'string') { if (typeof event.data === 'string') {
@@ -989,14 +1077,6 @@
if (message.text && message.text !== '😊') { if (message.text && message.text !== '😊') {
addMessage(message.text); addMessage(message.text);
} }
} else if (message.type === 'nfc_card_response') {
// NFC卡片响应
log(`NFC卡片响应: ${message.status}`, message.status === 'success' ? 'success' : 'error');
if (message.content) {
addMessage(`[NFC卡片内容] ${message.content}`);
} else if (message.message) {
addMessage(`[NFC卡片错误] ${message.message}`);
}
} else { } else {
// 未知消息类型 // 未知消息类型
log(`未知消息类型: ${message.type}`, 'info'); log(`未知消息类型: ${message.type}`, 'info');
@@ -1104,41 +1184,37 @@
} }
} }
// 发送NFC卡片消息
function sendNfcCardMessage() {
const cardId = nfcCardIdInput.value.trim();
if (cardId === '' || !websocket || websocket.readyState !== WebSocket.OPEN) return;
try {
// 构造NFC卡片消息
const nfcMessage = {
type: 'nfc_card_detected',
card_id: cardId
};
websocket.send(JSON.stringify(nfcMessage));
log(`发送NFC卡片消息, 卡片ID: ${cardId}`, 'info');
addMessage(`[NFC卡片] ${cardId}`, true);
} catch (error) {
log(`发送NFC卡片消息错误: ${error.message}`, 'error');
}
}
// 初始化事件监听器 // 初始化事件监听器
function initEventListeners() { function initEventListeners() {
connectButton.addEventListener('click', connectToServer); connectButton.addEventListener('click', connectToServer);
disconnectButton.addEventListener('click', disconnectFromServer);
document.getElementById('authTestButton').addEventListener('click', testAuthentication); document.getElementById('authTestButton').addEventListener('click', testAuthentication);
// 标签页切换
const tabs = document.querySelectorAll('.tab');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
// 移除所有标签页的active类
tabs.forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
// 添加当前标签页的active类
tab.classList.add('active');
document.getElementById(`${tab.dataset.tab}Tab`).classList.add('active');
});
});
sendTextButton.addEventListener('click', sendTextMessage); sendTextButton.addEventListener('click', sendTextMessage);
messageInput.addEventListener('keypress', (e) => { messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendTextMessage(); if (e.key === 'Enter') sendTextMessage();
}); });
sendNfcButton.addEventListener('click', sendNfcCardMessage); recordButton.addEventListener('click', () => {
if (isRecording) {
recordButton.addEventListener('click', startRecording); stopRecording();
stopButton.addEventListener('click', stopRecording); } else {
startRecording();
}
});
window.addEventListener('resize', initVisualizer); window.addEventListener('resize', initVisualizer);
} }
@@ -1253,8 +1329,6 @@
return window.btoa(binary); return window.btoa(binary);
} }
// 使用libopus创建一个Opus编码器 // 使用libopus创建一个Opus编码器
let opusEncoder = null; let opusEncoder = null;
function initOpusEncoder() { function initOpusEncoder() {
@@ -1283,7 +1357,7 @@
module: mod, module: mod,
// 初始化编码器 // 初始化编码器
init: function() { init: function () {
try { try {
// 获取编码器大小 // 获取编码器大小
const encoderSize = mod._opus_encoder_get_size(this.channels); const encoderSize = mod._opus_encoder_get_size(this.channels);
@@ -1329,7 +1403,7 @@
}, },
// 编码PCM数据为Opus // 编码PCM数据为Opus
encode: function(pcmData) { encode: function (pcmData) {
if (!this.encoderPtr) { if (!this.encoderPtr) {
if (!this.init()) { if (!this.init()) {
return null; return null;
@@ -1381,7 +1455,7 @@
}, },
// 销毁编码器 // 销毁编码器
destroy: function() { destroy: function () {
if (this.encoderPtr) { if (this.encoderPtr) {
this.module._free(this.encoderPtr); this.module._free(this.encoderPtr);
this.encoderPtr = null; this.encoderPtr = null;
@@ -1733,15 +1807,14 @@
let recordingSeconds = 0; let recordingSeconds = 0;
const recordingTimer = setInterval(() => { const recordingTimer = setInterval(() => {
recordingSeconds += 0.1; recordingSeconds += 0.1;
recordButton.textContent = `录音中... ${recordingSeconds.toFixed(1)}`; recordButton.textContent = `停止录音 ${recordingSeconds.toFixed(1)}`;
}, 100); }, 100);
// 保存计时器,以便在停止时清除 // 保存计时器,以便在停止时清除
window.recordingTimer = recordingTimer; window.recordingTimer = recordingTimer;
recordButton.classList.add('recording'); recordButton.classList.add('recording');
recordButton.disabled = true; recordButton.disabled = false;
stopButton.disabled = false;
log('开始PCM直接录音', 'success'); log('开始PCM直接录音', 'success');
return true; return true;
@@ -1813,7 +1886,6 @@
recordButton.textContent = '开始录音'; recordButton.textContent = '开始录音';
recordButton.classList.remove('recording'); recordButton.classList.remove('recording');
recordButton.disabled = false; recordButton.disabled = false;
stopButton.disabled = true;
log('停止PCM直接录音', 'success'); log('停止PCM直接录音', 'success');
return true; return true;
@@ -1858,4 +1930,5 @@
initApp(); initApp();
</script> </script>
</body> </body>
</html> </html>