From 2cb282bd34e157e97e29b6f5d26f1d8b02248992 Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Sun, 20 Sep 2026 16:24:37 +0200 Subject: [PATCH] chore: audio engine improvements --- src/components/engine/audio/element.js | 192 ++++++++++++++++++++++--- 1 file changed, 170 insertions(+), 22 deletions(-) diff --git a/src/components/engine/audio/element.js b/src/components/engine/audio/element.js index 52f73728..6a062451 100644 --- a/src/components/engine/audio/element.js +++ b/src/components/engine/audio/element.js @@ -35,6 +35,8 @@ const IS_IOS = /iPhone|iPad|iPod/.test(navigator.userAgent) || const ROUTE_AUDIO = Symbol("routeAudio"); /** @type {unique symbol} */ const UNROUTE_AUDIO = Symbol("unrouteAudio"); +/** @type {unique symbol} */ +const CANCEL_PRELOAD = Symbol("cancelPreload"); /** * Automatic retry policy for transient media errors (network / CORS-handshake @@ -52,6 +54,16 @@ const RETRY_MAX_DELAY_MS = 30_000; */ const LOAD_WATCHDOG_MS = 3_000; +/** + * How many consecutive data-less watchdog windows a still-fetching + * (`NETWORK_LOADING`) load may wait through before the request is considered + * hung and reloaded. A server that accepts the connection but never sends a + * byte — a half-open connection after a network change or laptop sleep — keeps + * the element in `NETWORK_LOADING` indefinitely, so without this bound the load + * would wait forever. At the base window this is ~30s of patience. + */ +const LOAD_WAIT_LIMIT = 10; + //////////////////////////////////////////// // ELEMENT //////////////////////////////////////////// @@ -883,6 +895,24 @@ class AudioEngine extends BroadcastableDiffuseElement { if (item) fn(item.audio, item); } + /** + * Drops a preloaded item whose background fetch is stuck. Removing it from + * `#items` makes the render cleanup unload its