Skip to content

Fix web: don't spawn the deferred-pause std::thread on web (Aborted() in initEngine)#488

Merged
alnitak merged 2 commits into
alnitak:mainfrom
felixmin:fix/web-init-thread-abort
Jun 22, 2026
Merged

Fix web: don't spawn the deferred-pause std::thread on web (Aborted() in initEngine)#488
alnitak merged 2 commits into
alnitak:mainfrom
felixmin:fix/web-init-thread-abort

Conversation

@felixmin

@felixmin felixmin commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Description

On web, SoLoud.init() aborts with RuntimeError: Aborted() inside initEngine as soon as the engine initializes — a regression in 4.0.10.

4.0.10 (#486) starts a background pause-scheduler thread in Player::init() (startPauseEngineScheduler()std::thread). The web build is single-threaded (web/compile_wasm.sh passes no -pthread), so constructing std::thread calls pthread_create with no thread runtime and the module aborts on the first init(). 4.0.9 had no such thread.

This guards the thread behind __EMSCRIPTEN__:

  • startPauseEngineScheduler() / stopPauseEngineScheduler() are no-ops on web (no std::thread is constructed).
  • pauseEngine() falls back to the pre-4.0.10 immediate pause on web — the browser's AudioContext doesn't have the OS audio-session settling issue that motivates the delay on native.

Native (iOS/Android/desktop) keeps the deferred, coalesced pause unchanged.

The web artifacts (web/libflutter_soloud_plugin.{js,wasm}) are regenerated via web/compile_wasm.sh (Emscripten 6.0.0, with Opus/Ogg) and committed.

Verified in Chrome with the rebuilt artifacts by calling initEngine:

  • published 4.0.10 → Aborted(). Build with -sASSERTIONS for more info. (the crash)
  • this branch → initEngine returns 0, isInited() returns 1 — no abort

Note: the wasm here was built with emsdk 6.0.0. If you release with a different Emscripten version, regenerating with yours will keep the committed binary aligned with your toolchain — happy to update if you prefer.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

…orted in initEngine)

4.0.10 added a background pause-scheduler thread that `Player::init()` starts
unconditionally via `startPauseEngineScheduler()`. On web the wasm is built
single-threaded (compile_wasm.sh passes no -pthread), so constructing
`std::thread` calls `pthread_create` with no thread runtime and the module
aborts: `RuntimeError: Aborted()` inside initEngine — every web user crashes the
moment the engine initializes.

This guards the thread machinery with `__EMSCRIPTEN__`:
- `startPauseEngineScheduler()` / `stopPauseEngineScheduler()` become no-ops on
  web (no thread is ever constructed).
- `pauseEngine()` falls back to the pre-4.0.10 behavior on web — pause the
  device immediately when no voices remain active. The browser's AudioContext
  doesn't have the OS audio-session settling issue that motivates the delay on
  iOS/native, so the immediate pause is correct there.

Native (iOS/Android/desktop) keeps the deferred, coalesced pause unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@felixmin

Copy link
Copy Markdown
Contributor Author

Runtime verification (real browser)

I rebuilt the web wasm from this branch with Emscripten 6.0.0 and ran initEngine directly in Chrome, comparing it against the published 4.0.10 artifacts. Minimal harness: load the module factory, then Module.ccall('initEngine', 'number', ['number','number','number','number'], [-1, 44100, 2048, 2]).

Build Result
4.0.10 (published web/libflutter_soloud_plugin.*) Aborted(). Build with -sASSERTIONS for more info. — i.e. the reported crash, reproduced
This branch (rebuilt wasm) initEngine returns 0 (noError), isInited() returns 1 — no abort

So the __EMSCRIPTEN__ guard resolves the web init crash. (The patched test build was compiled without the Xiph/opus libs for speed, but that's irrelevant to this code path — the abort is solely the std::thread constructed in Player::init(), which the guard removes on web.)

Still source-only here — the committed web/libflutter_soloud_plugin.{js,wasm} should be regenerated with your pinned Emscripten toolchain so the artifact diff matches your setup. Happy to push a rebuild if you share the emsdk version you release with.

…it-thread fix

Rebuilt via web/compile_wasm.sh (Emscripten 6.0.0, with Opus/Ogg) so the
__EMSCRIPTEN__ guard is reflected in the published web artifacts. Verified in
Chrome: initEngine returns 0 / isInited() == 1 (no Aborted()).

Note: built with emsdk 6.0.0 — if you release with a different Emscripten
version, regenerate with yours so the binary diff matches your toolchain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@felixmin felixmin marked this pull request as ready for review June 21, 2026 18:55
@alnitak

alnitak commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Thank you so much! LGTM.

Happy to push a rebuild if you share the emsdk version you release with.

Thanks, I will rebuild wasm before publishing on pub.dev.

@alnitak alnitak merged commit a5303d3 into alnitak:main Jun 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants