Skip to content

Mobile: WebKit OOM crash on Load + stuck Preparing audio after reload #234

Description

@thcp

Summary

Two related bugs triggered when pressing Load in the mobile library view, reported by @goermezer in #216.

Bug 1 - WebKit tab crash (root cause)

openTrack() calls createAudioEngine(), which fetches all stems in parallel via res.arrayBuffer() then decodes each with decodeAudioData(). This holds both the compressed MP3 and the decoded PCM in memory simultaneously for all stems at once.

Rough memory for a 5-minute, 4-stem track:

  • Decoded PCM: 5 min x 4 stems x 44100 Hz x 2ch x 4 bytes = ~420 MB
  • Compressed MP3 buffers in flight: ~32 MB

Mobile browser tabs get killed at 256-512 MB on most devices. The desktop player (player.js) already has a MAX_ENGINE_DECODED_BYTES = 1.2e9 guard with a streaming fallback - the mobile engine has no equivalent.

Relevant files:

  • static/js/audioEngine.js lines 43-63 (parallel arrayBuffer() + decodeAudioData())
  • static/mobile/app.js lines 262-278 (openTrack - no memory guard before createAudioEngine)
  • static/js/player.js lines 879-891 (desktop guard, for reference)

Bug 2 - Stuck on "Preparing audio" after reload (symptom)

After WebKit kills and reloads the tab, loadLibrary() auto-selects the first track:

// static/mobile/app.js line 893
if (!state.current && state.tracks.length) state.current = state.tracks[0];

This sets a raw track card into state.current (with loading: false, error: null) but never calls openTrack(), so engineReady stays false. The preparing condition on line 428 evaluates to true indefinitely:

const preparing = !!state.current && !state.current.loading && !state.current.error && !ready;

Pressing Load manually calls openTrack() and clears the state. That is why the workaround works.

Reproduction

  1. Open StemDeck mobile on a phone browser (iOS Safari or Android Chrome)
  2. Open the Library tab, press Load on any track
  3. On longer tracks or older devices: blank white page briefly, page reloads ("This website was reloaded because of a problem" on iOS)
  4. After reload: player shows "Preparing audio..." and never progresses

Proposed fix

  • Bug 1: Add a decoded-size estimate before calling createAudioEngine() in openTrack(). If it exceeds a mobile-appropriate threshold (e.g. 150 MB), fall back to sequential decoding or <audio> element streaming.
  • Bug 2: Remove the auto-select on line 893, or only set state.current when also triggering openTrack().

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions