Skip to content

Commit 87ae99f

Browse files
gabrielste1nclaude
andcommitted
fix: inline AudioWorklet as blob URL to fix ASAR module loading failure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 932bca5 commit 87ae99f

File tree

1 file changed

+51
-4
lines changed

1 file changed

+51
-4
lines changed

src/helpers/audioManager.js

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,51 @@ class AudioManager {
5757
this.cachedMicDeviceId = null;
5858
this.persistentAudioContext = null;
5959
this.workletModuleLoaded = false;
60+
this.workletBlobUrl = null;
61+
}
62+
63+
getWorkletBlobUrl() {
64+
if (this.workletBlobUrl) return this.workletBlobUrl;
65+
const code = `
66+
const BUFFER_SIZE = 800;
67+
class PCMStreamingProcessor extends AudioWorkletProcessor {
68+
constructor() {
69+
super();
70+
this._buffer = new Int16Array(BUFFER_SIZE);
71+
this._offset = 0;
72+
this._stopped = false;
73+
this.port.onmessage = (event) => {
74+
if (event.data === "stop") {
75+
if (this._offset > 0) {
76+
const partial = this._buffer.slice(0, this._offset);
77+
this.port.postMessage(partial.buffer, [partial.buffer]);
78+
this._buffer = new Int16Array(BUFFER_SIZE);
79+
this._offset = 0;
80+
}
81+
this._stopped = true;
82+
}
83+
};
84+
}
85+
process(inputs) {
86+
if (this._stopped) return false;
87+
const input = inputs[0]?.[0];
88+
if (!input) return true;
89+
for (let i = 0; i < input.length; i++) {
90+
const s = Math.max(-1, Math.min(1, input[i]));
91+
this._buffer[this._offset++] = s < 0 ? s * 0x8000 : s * 0x7fff;
92+
if (this._offset >= BUFFER_SIZE) {
93+
this.port.postMessage(this._buffer.buffer, [this._buffer.buffer]);
94+
this._buffer = new Int16Array(BUFFER_SIZE);
95+
this._offset = 0;
96+
}
97+
}
98+
return true;
99+
}
100+
}
101+
registerProcessor("pcm-streaming-processor", PCMStreamingProcessor);
102+
`;
103+
this.workletBlobUrl = URL.createObjectURL(new Blob([code], { type: "application/javascript" }));
104+
return this.workletBlobUrl;
60105
}
61106

62107
getCustomDictionaryPrompt() {
@@ -1643,8 +1688,7 @@ class AudioManager {
16431688
try {
16441689
const audioContext = await this.getOrCreateAudioContext();
16451690
if (!this.workletModuleLoaded) {
1646-
const workletUrl = new URL("./pcm-streaming-processor.js", document.baseURI).href;
1647-
await audioContext.audioWorklet.addModule(workletUrl);
1691+
await audioContext.audioWorklet.addModule(this.getWorkletBlobUrl());
16481692
this.workletModuleLoaded = true;
16491693
logger.debug("AudioWorklet module pre-loaded during warmup", {}, "streaming");
16501694
}
@@ -1770,8 +1814,7 @@ class AudioManager {
17701814
this.streamingStream = stream;
17711815

17721816
if (!this.workletModuleLoaded) {
1773-
const workletUrl = new URL("./pcm-streaming-processor.js", document.baseURI).href;
1774-
await audioContext.audioWorklet.addModule(workletUrl);
1817+
await audioContext.audioWorklet.addModule(this.getWorkletBlobUrl());
17751818
this.workletModuleLoaded = true;
17761819
}
17771820

@@ -2100,6 +2143,10 @@ class AudioManager {
21002143
this.persistentAudioContext.close().catch(() => {});
21012144
this.persistentAudioContext = null;
21022145
this.workletModuleLoaded = false;
2146+
if (this.workletBlobUrl) {
2147+
URL.revokeObjectURL(this.workletBlobUrl);
2148+
this.workletBlobUrl = null;
2149+
}
21032150
}
21042151
try {
21052152
window.electronAPI?.assemblyAiStreamingStop?.();

0 commit comments

Comments
 (0)