7f25c8f6bb
- main.py:uv run main.py 一键启动——读取 backend/.env、TORCH_HOME/NLTK_DATA 指向项目内缓存、certifi SSL + NO_PROXY 网络直连、默认开启 s2s,启动横幅 - vendor/:补丁后 s2s 云化栈移入项目(backend/vendor/s2s-cloud),pyproject sources 改相对路径 - .gitignore:忽略 .torch-cache / nltk_data 缓存 - AGENTS.md:进程管理铁律(AI 不启动/重启服务,由用户操作)
56 lines
1.9 KiB
HTML
56 lines
1.9 KiB
HTML
<!doctype html>
|
|
<html lang="zh">
|
|
<head><meta charset="utf-8"><title>worklet 输出测试</title></head>
|
|
<body>
|
|
<pre id="out">running...</pre>
|
|
<script>
|
|
const out = document.getElementById("out");
|
|
function log(s) { out.textContent += s + "\n"; }
|
|
|
|
(async () => {
|
|
try {
|
|
const ctx = new AudioContext();
|
|
if (ctx.state === "suspended") await ctx.resume();
|
|
log("ctx state: " + ctx.state);
|
|
await ctx.audioWorklet.addModule("worklets/audio-playback.js?v=t3");
|
|
const node = new AudioWorkletNode(ctx, "audio-playback", {
|
|
numberOfInputs: 0, numberOfOutputs: 1, outputChannelCount: [1],
|
|
});
|
|
const cap = ctx.createAnalyser();
|
|
cap.fftSize = 2048;
|
|
node.connect(cap);
|
|
cap.connect(ctx.destination); // keep the graph running
|
|
|
|
const sr = 16000, n = sr; // 1s @16k
|
|
const samples = new Float32Array(n);
|
|
for (let i = 0; i < n; i++) samples[i] = 0.5 * Math.sin(2 * Math.PI * 440 * i / sr);
|
|
const chunk = 1280;
|
|
let pushed = 0;
|
|
for (let i = 0; i < n; i += chunk) {
|
|
node.port.postMessage({ kind: "audio", samples: samples.slice(i, i + chunk) });
|
|
pushed++;
|
|
}
|
|
log("pushed chunks: " + pushed);
|
|
|
|
await new Promise(r => setTimeout(r, 2500));
|
|
const buf = new Uint8Array(cap.frequencyBinCount);
|
|
cap.getByteTimeDomainData(buf);
|
|
let sum = 0;
|
|
for (let i = 0; i < buf.length; i++) sum += Math.abs(buf[i] - 128);
|
|
const rms = sum / buf.length; // 0..127 scale
|
|
log("output RMS = " + rms.toFixed(2) + (rms > 5 ? " ✅ 有声音输出" : " ❌ 输出静音"));
|
|
// 也测一下统计回传
|
|
const stats = await new Promise(res => {
|
|
const timer = setTimeout(() => res("no-stats"), 3000);
|
|
node.port.onmessage = e => { clearTimeout(timer); res(JSON.stringify(e.data)); };
|
|
node.port.postMessage({ kind: "config", inputRate: 16000, muted: false });
|
|
});
|
|
log("stats from worklet: " + stats);
|
|
} catch (e) {
|
|
log("ERROR: " + e.message);
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|