Skip to content

Enable wasm-bindgen feature with target wasm32-unknown-emscripten - #1349

Open
DouglasDwyer wants to merge 5 commits into
RustAudio:masterfrom
DouglasDwyer:webaudio-reach-any-wasm-target
Open

Enable wasm-bindgen feature with target wasm32-unknown-emscripten#1349
DouglasDwyer wants to merge 5 commits into
RustAudio:masterfrom
DouglasDwyer:webaudio-reach-any-wasm-target

Conversation

@DouglasDwyer

@DouglasDwyer DouglasDwyer commented Sep 1, 2026

Copy link
Copy Markdown

Summary

The wasm-bindgen tool is finally getting support for integration with Emscripten. The feature is still quite new, but this means that most of Rust's web ecosystem can now work with the Emscripten target. I'd like to use cpal in a WASM/Emscripten project, but right now the wasm32-unknown-emscripten target is hard-coded to use the null backend. This PR eliminates the feature gate to make the wasm-bindgen feature work with wasm32-unknown-emscripten too.

This PR exposes the webaudio backend but not the audioworklet backend. That backend relies on re-instantiating the WASM module, but the way Emscripten modules get instantiated is different, so it wouldn't work without more changes.

Changes

  • Replace #[cfg(all(target_arch = "wasm32", target_os = "unknown", feature = "wasm-bindgen"))] with #[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] for the webaudio backend
  • Use Closure::wrap_aborting instead of Closure::wrap so that the code properly compiles on WASM targets with panic=unwind
  • Bump wasm-bindgen dependency to 0.2.110 in order to use Closure::wrap_aborting
  • Add an additional CI job for the Emscripten target

Testing

In my own project, I have gotten cpal audio working with a Rust/Emscripten WASM module in Chrome. This PR also adds CI checks to ensure that compilation is successful.

Related issues

#92 #413 #810

@roderickvd roderickvd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great! Not so long ago we removed the old Emscripten host that had become defunct. This seems like a light-weight manner to get Emscripten support back.

Beyond the changes requested in the review points, please also consider updating README.md with Emscripten support.

Comment thread src/host/webaudio/mod.rs Outdated
Comment thread Cargo.toml Outdated
Comment thread CHANGELOG.md Outdated
@DouglasDwyer
DouglasDwyer force-pushed the webaudio-reach-any-wasm-target branch 2 times, most recently from ccac245 to 1620436 Compare September 2, 2026 03:24
@DouglasDwyer

Copy link
Copy Markdown
Author

Thank you for your swift response! I have responded to the comments, and additionally updated the tables in the README to reflect support for the Emscripten target.

@roderickvd roderickvd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turnaround. Here's a few points, hopefully the last.

Comment thread README.md
Comment thread CHANGELOG.md Outdated
Comment thread src/platform/mod.rs
assert!(
WebAudioHost::is_available(),
"WebAudio is not available in this context; \
AudioContext requires a Window (not a Worker or Service Worker)"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...or now Emscripten...

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running on the browser's UI thread (and having access to the Window object) is still required, even with the Emscripten target. As such, I think this statement is clear and accurate - if you are running on one of Emscripten's worker threads, it won't work. We could change it to say "AudioContext requires the main UI thread" if that would be better?

@DouglasDwyer DouglasDwyer Sep 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I would mention that we could call emscripten_proxy_sync when creating Streams, which would allow them to be created from any Emscripten thread. I didn't do that yet because I wanted to keep the scope of this PR very small. Would you be open to that addition as well? If so, I can add it as part of this PR or in a separate PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, maybe you can propose it as a separate commit, then we can judge to keep it in or do it separately.

@DouglasDwyer DouglasDwyer Sep 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented this in 7f20ece and 31691df. I will test it in my project, and also test the webaudio example in this repo to make sure it still works

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following up - I have confirmed that the webaudio example in this repo (wasm32-unknown-unknown), as well as my own project (multithreaded wasm32-unknown-emscripten) work. I am able to get a beep going in Chrome.

Comment thread src/host/webaudio/mod.rs Outdated
@DouglasDwyer
DouglasDwyer force-pushed the webaudio-reach-any-wasm-target branch from 1620436 to 40c1b2b Compare September 3, 2026 01:52
Enable the WebAudio host (and its wasm-bindgen/js-sys/web-sys deps) for
`wasm32-unknown-emscripten`, gated on
`any(target_os = "emscripten", target_os = "unknown")` so nothing
wasm-bindgen-related is pulled in for `wasm32-wasip1`/`wasip2`. The
AudioWorklet host stays `wasm32-unknown-unknown`-only.

The three WebAudio JS callbacks keep using `Closure::wrap`. Dropping the
`as Box<dyn FnMut(_)>` cast keeps the closures concrete, so their captures
(all `UnwindSafe`) satisfy the `panic=unwind` bound on Emscripten without
`wrap_aborting` -- a callback panic still surfaces as a JS exception
rather than aborting the instance. Minimum `wasm-bindgen` stays at 0.2.

README: document the `wasm32-unknown-emscripten` target (Emscripten 6.0.3,
wasm-bindgen 0.2.127) and list it under the `wasm-bindgen` feature. Adds
an Emscripten CI job.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@DouglasDwyer
DouglasDwyer force-pushed the webaudio-reach-any-wasm-target branch from 40c1b2b to 3846df3 Compare September 3, 2026 01:58
@DouglasDwyer
DouglasDwyer force-pushed the webaudio-reach-any-wasm-target branch from 572e408 to 31691df Compare September 3, 2026 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants