Skip to content

Commit 2ee3845

Browse files
committed
edgeTTS fix stop race condition
1 parent 395d04b commit 2ee3845

1 file changed

Lines changed: 33 additions & 18 deletions

File tree

wiktionary_pron/scripts/tts.js

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -234,41 +234,56 @@ class StreamingTTS {
234234
}
235235

236236
stop() {
237+
// 1. Close the socket first to prevent new messages.
237238
if (this.#currentSocket) {
239+
this.#currentSocket.onclose = null; // Prevent the onclose handler from running
240+
this.#currentSocket.onerror = null; // Prevent the onerror handler
238241
this.#currentSocket.close();
239242
this.#currentSocket = null;
240243
}
241-
if (this.#mediaSource && this.#mediaSource.readyState === "open") {
242-
try {
243-
this.#mediaSource.endOfStream();
244-
} catch (e) {
245-
/* Ignore */
246-
}
247-
}
248-
this.#audioPlayer.pause();
249-
this.#audioPlayer.removeAttribute("src");
244+
245+
// 2. Clear the queue to stop any pending appends.
250246
this.#audioQueue = [];
251247
this.#isAppending = false;
248+
249+
// 3. Gracefully end the media stream.
250+
// This will handle the sourceBuffer and mediaSource correctly.
251+
this.#finalizeStream();
252+
253+
// 4. Reset the audio player.
254+
this.#audioPlayer.pause();
255+
if (this.#audioPlayer.src.startsWith("blob:")) {
256+
URL.revokeObjectURL(this.#audioPlayer.src);
257+
}
258+
this.#audioPlayer.removeAttribute("src");
252259
}
253260

254261
// --- Private Helper Methods ---
255262
#finalizeStream() {
263+
// This is the more robust version that prevents Firefox warnings and is generally safer.
264+
if (!this.#mediaSource || this.#mediaSource.readyState !== "open") {
265+
return;
266+
}
267+
256268
const end = () => {
257-
if (this.#mediaSource && this.#mediaSource.readyState === "open") {
269+
if (this.#mediaSource.readyState === "open") {
258270
try {
259271
this.#mediaSource.endOfStream();
260272
} catch (e) {
261-
console.warn("MediaSource already ended.");
273+
console.warn(
274+
"Error calling endOfStream, stream likely already closed.",
275+
e,
276+
);
262277
}
263278
}
264279
};
265-
if (this.#isAppending || this.#audioQueue.length > 0) {
266-
const interval = setInterval(() => {
267-
if (!this.#isAppending && this.#audioQueue.length === 0) {
268-
clearInterval(interval);
269-
end();
270-
}
271-
}, 50);
280+
281+
if (this.#sourceBuffer && this.#sourceBuffer.updating) {
282+
const onUpdateEnd = () => {
283+
this.#sourceBuffer.removeEventListener("updateend", onUpdateEnd);
284+
end();
285+
};
286+
this.#sourceBuffer.addEventListener("updateend", onUpdateEnd);
272287
} else {
273288
end();
274289
}

0 commit comments

Comments
 (0)