feat: 优化 AudioWorklet 加载逻辑,增加 Blob URL 兼容性和多基址回退方案
This commit is contained in:
@@ -478,11 +478,11 @@ export class S2sWsRealtimeClient extends EventTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The worklets live at the repo root, one level up from this module.
|
// AudioWorklet 加载(WebView2/打包兼容):
|
||||||
// ?v=2 busts the browser cache so the fixed (unmuted) playback worklet
|
// 1) 先直接 addModule(http 地址) —— 浏览器/常规环境快路径
|
||||||
// always loads instead of a stale muted copy.
|
// 2) 失败则 fetch 源码 → Blob URL → addModule —— 打包 WebView2 下
|
||||||
// 多基址回退:打包环境优先后端 http(tauri.localhost 无法加载 worklet 模块),
|
// tauri.localhost 自定义协议与跨域均受限,Blob 同源最稳
|
||||||
// 浏览器开发回退页面源 / 相对路径。
|
// 3) 多个候选基址(后端 http / 页面源 / 相对路径)
|
||||||
const candidates = [
|
const candidates = [
|
||||||
window.VOICE_WORKLETS_BASE,
|
window.VOICE_WORKLETS_BASE,
|
||||||
`${window.location.origin}/voice-worklets/`,
|
`${window.location.origin}/voice-worklets/`,
|
||||||
@@ -490,6 +490,27 @@ export class S2sWsRealtimeClient extends EventTarget {
|
|||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
let workletErr = null;
|
let workletErr = null;
|
||||||
let workletOk = false;
|
let workletOk = false;
|
||||||
|
|
||||||
|
const addViaBlob = async (name) => {
|
||||||
|
for (const base of candidates) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(base + name, { cache: "no-store" });
|
||||||
|
if (!res.ok) continue;
|
||||||
|
const src = await res.text();
|
||||||
|
const url = URL.createObjectURL(new Blob([src], { type: "application/javascript" }));
|
||||||
|
try {
|
||||||
|
await ctx.audioWorklet.addModule(url);
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
workletErr = err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
for (const base of candidates) {
|
for (const base of candidates) {
|
||||||
try {
|
try {
|
||||||
await ctx.audioWorklet.addModule(base + "mic-capture.js?v=3");
|
await ctx.audioWorklet.addModule(base + "mic-capture.js?v=3");
|
||||||
@@ -498,9 +519,16 @@ export class S2sWsRealtimeClient extends EventTarget {
|
|||||||
break;
|
break;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
workletErr = err;
|
workletErr = err;
|
||||||
console.warn("[ws] worklet 加载失败,尝试备用地址:", base, err);
|
console.warn("[ws] worklet 直接加载失败,改走 Blob 方案:", base, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!workletOk) {
|
||||||
|
// 回退:fetch → Blob → addModule(WebView2 打包环境最稳)
|
||||||
|
const micOk = await addViaBlob("mic-capture.js?v=3");
|
||||||
|
const playOk = await addViaBlob("audio-playback.js?v=3");
|
||||||
|
workletOk = micOk && playOk;
|
||||||
|
if (workletOk) console.info("[ws] AudioWorklet 已通过 Blob URL 加载(WebView2 兼容模式)");
|
||||||
|
}
|
||||||
if (!workletOk) throw workletErr || new Error("AudioWorklet 模块加载失败");
|
if (!workletOk) throw workletErr || new Error("AudioWorklet 模块加载失败");
|
||||||
|
|
||||||
const captureNode = new AudioWorkletNode(ctx, "mic-capture", {
|
const captureNode = new AudioWorkletNode(ctx, "mic-capture", {
|
||||||
|
|||||||
Reference in New Issue
Block a user