Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/platforms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,34 @@ jobs:
env:
RUSTUP_TOOLCHAIN: nightly

# WebAssembly - Emscripten (WebAudio host)
wasm-emscripten:
runs-on: ubuntu-latest
env:
TARGET: wasm32-unknown-emscripten
steps:
- uses: actions/checkout@v5

- name: Install Rust MSRV (${{ env.MSRV_WASM }})
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.MSRV_WASM }}
targets: ${{ env.TARGET }}

- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
key: wasm-emscripten

- name: Check examples (default features)
run: cargo +${{ env.MSRV_WASM }} check --examples --workspace --verbose --target ${{ env.TARGET }}

- name: Check examples (wasm-bindgen feature)
run: cargo +${{ env.MSRV_WASM }} check --examples --features wasm-bindgen --workspace --verbose --target ${{ env.TARGET }}

- name: Check all features
run: cargo +${{ env.MSRV_WASM }} check --workspace --all-features --verbose --target ${{ env.TARGET }}

# WebAssembly - WASI Preview 1
wasm-wasip1:
runs-on: ubuntu-latest
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ jobs:
features: --features wasm-bindgen
os: ubuntu-latest

# WASM - Emscripten (WebAudio host)
- target: wasm32-unknown-emscripten
name: WASM-emscripten
features: --features wasm-bindgen
os: ubuntu-latest

# WASM - WASI
- target: wasm32-wasip1
name: WASI
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **ALSA**: Update `alsa` dependency to 0.12.
- **Linux**: `realtime` can now promote threads without requiring `realtime-dbus`.
- **PipeWire**: Set `node.rate` property so that `default.clock.allowed-rates` PipeWire config works.
- **WebAudio**: the WebAudio host now works on `wasm32-unknown-emscripten` via [wasm-bindgen/Emscripten integration](https://github.com/wasm-bindgen/wasm-bindgen/issues/5237).

### Deprecated

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ objc2-avf-audio = { version = "0.3", default-features = false, features = [
"AVAudioSessionTypes",
] }

[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
[target.'cfg(all(target_arch = "wasm32", any(target_os = "emscripten", target_os = "unknown")))'.dependencies]
wasm-bindgen = { version = "0.2", optional = true }
wasm-bindgen-futures = { version = "0.4", optional = true }
futures-channel = { version = "0.3", optional = true }
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ The minimum Rust version (MSRV) and minimum operating system / runtime version b
| PipeWire | Linux, BSD | 1.85 | PipeWire 0.3.53 |
| PulseAudio | Linux, BSD | 1.88 | — |
| WASAPI / ASIO | Windows | 1.85 | Windows 8 |
| WASM (`wasm32-unknown`) | WebAssembly | 1.85 | — |
| WASM (`wasm32-unknown-unknown`) | WebAssembly | 1.85 | — |
| WASM (`wasm32-unknown-emscripten`) | WebAssembly | 1.85 | Emscripten 6.0.3, wasm-bindgen 0.2.127 |
| WASM (`wasm32-wasip1`) | WebAssembly | 1.85 | — |
| WASM (`audioworklet`) | WebAssembly | nightly | — |

Expand All @@ -70,7 +71,7 @@ The `audioworklet` backend additionally requires `-Zbuild-std` with atomics supp
| `pulseaudio` | Linux, BSD | PulseAudio sound server backend. Requires `libpulse-dev` (Debian/Ubuntu) or `pulseaudio-libs-devel` (Fedora). |
| `realtime` | Android, Linux, Windows | Raises the audio callback thread to real-time or high-priority scheduling for lower latency. On Linux, requires `CAP_SYS_NICE`, root, or an `rtprio` limit granted via `limits.conf` or systemd, unless `realtime-dbus` is also enabled. |
| `realtime-dbus` | Linux | Uses `rtkit` via D-Bus for RT scheduling on Linux desktop systems. Implies `realtime` on all platforms. Requires `libdbus-1-dev` on Linux. |
| `wasm-bindgen` | WebAssembly (`wasm32-unknown-unknown`) | Web Audio API backend for browser-based audio; required for any WebAssembly audio support. See the `webaudio` example. |
| `wasm-bindgen` | WebAssembly (`wasm32-unknown-emscripten`, `wasm32-unknown-unknown`) | Web Audio API backend for browser-based audio; required for any WebAssembly audio support. See the `webaudio` example. |

See the [beep example](examples/beep.rs) for selecting the backend at runtime.

Expand Down
20 changes: 13 additions & 7 deletions src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub(crate) mod wasapi;

#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
pub(crate) mod webaudio;
Expand All @@ -96,7 +96,7 @@ pub(crate) mod custom;
target_os = "android",
all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
),
)))]
Expand Down Expand Up @@ -246,7 +246,13 @@ pub(crate) use error_emit::try_emit_error;
target_os = "netbsd",
target_os = "windows",
target_vendor = "apple",
feature = "audioworklet",
all(
target_arch = "wasm32",
target_os = "unknown",
feature = "wasm-bindgen",
feature = "audioworklet",
target_feature = "atomics"
),
))]
#[inline]
pub(crate) fn frames_to_duration(
Expand Down Expand Up @@ -333,7 +339,7 @@ where
/// <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#exceptions>
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
pub(crate) fn get_user_media_error(js_err: &wasm_bindgen::JsValue) -> crate::Error {
Expand Down Expand Up @@ -366,7 +372,7 @@ pub(crate) fn get_user_media_error(js_err: &wasm_bindgen::JsValue) -> crate::Err
/// <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
pub(crate) async fn request_microphone() -> Result<web_sys::MediaStream, wasm_bindgen::JsValue> {
Expand All @@ -387,7 +393,7 @@ pub(crate) async fn request_microphone() -> Result<web_sys::MediaStream, wasm_bi
/// microphone is actually present without asking for permission first via getUserMedia().
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
pub(crate) fn is_get_user_media_available() -> bool {
Expand All @@ -398,7 +404,7 @@ pub(crate) fn is_get_user_media_available() -> bool {
/// browser's capture indicator. Dropping a WebAudio graph alone does not do this.
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
pub(crate) fn stop_tracks(media_stream: &web_sys::MediaStream) {
Expand Down
14 changes: 7 additions & 7 deletions src/host/webaudio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ impl DeviceTrait for Device {
#[cfg(target_feature = "atomics")]
let current_time_bits_cb = current_time_bits.clone();

let on_audio_process = Closure::wrap(Box::new(move |event: AudioProcessingEvent| {
let on_audio_process_fn = Box::new(move |event: AudioProcessingEvent| {
let now = ctx_cb.current_time();
#[cfg(target_feature = "atomics")]
current_time_bits_cb.store(now.to_bits(), Ordering::Relaxed);
Expand Down Expand Up @@ -456,8 +456,8 @@ impl DeviceTrait for Device {
),
),
}
})
as Box<dyn FnMut(AudioProcessingEvent)>);
});
let on_audio_process = Closure::wrap(on_audio_process_fn);

processor.set_onaudioprocess(Some(on_audio_process.as_ref().unchecked_ref()));

Expand Down Expand Up @@ -876,7 +876,7 @@ impl DeviceTrait for Device {

// Keep track of when the next buffer worth of samples should be played.
*time_handle.write().unwrap() = time_at_start_of_buffer + buffer_time_step_secs;
}) as Box<dyn FnMut()>));
})));

on_ended_closures.push(on_ended_closure);
}
Expand Down Expand Up @@ -1082,7 +1082,7 @@ impl DeviceTrait for Device {
js_sys::Float32Array::new(&temporary_channel_array)
};

let on_audio_process = Closure::wrap(Box::new(move |event: AudioProcessingEvent| {
let on_audio_process_fn = Box::new(move |event: AudioProcessingEvent| {
let now = ctx_cb.current_time();
#[cfg(target_feature = "atomics")]
current_time_bits_cb.store(now.to_bits(), Ordering::Relaxed);
Expand Down Expand Up @@ -1219,8 +1219,8 @@ impl DeviceTrait for Device {
return;
}
}
})
as Box<dyn FnMut(AudioProcessingEvent)>);
});
let on_audio_process = Closure::wrap(on_audio_process_fn);

processor.set_onaudioprocess(Some(on_audio_process.as_ref().unchecked_ref()));

Expand Down
16 changes: 8 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,19 @@
// Extern crate declarations with `#[macro_use]` must unfortunately be at crate root.
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
extern crate js_sys;
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
extern crate wasm_bindgen;
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
extern crate web_sys;
Expand All @@ -226,7 +226,7 @@ pub use platform::{
pub use sample_format::{FromSample, I24, Sample, SampleFormat, SizedSample, U24};
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
use wasm_bindgen::prelude::*;
Expand Down Expand Up @@ -426,7 +426,7 @@ pub enum BufferSize {

#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
impl wasm_bindgen::describe::WasmDescribe for BufferSize {
Expand All @@ -437,7 +437,7 @@ impl wasm_bindgen::describe::WasmDescribe for BufferSize {

#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
impl wasm_bindgen::convert::IntoWasmAbi for BufferSize {
Expand All @@ -454,7 +454,7 @@ impl wasm_bindgen::convert::IntoWasmAbi for BufferSize {

#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
impl wasm_bindgen::convert::FromWasmAbi for BufferSize {
Expand All @@ -476,7 +476,7 @@ impl wasm_bindgen::convert::FromWasmAbi for BufferSize {
#[cfg_attr(
all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
),
wasm_bindgen
Expand Down
12 changes: 8 additions & 4 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -924,18 +924,22 @@ mod platform_impl {

#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
mod platform_impl {
#[cfg(all(feature = "audioworklet", target_feature = "atomics"))]
#[cfg(all(
target_os = "unknown",
feature = "audioworklet",
target_feature = "atomics"
))]
use crate::host::audioworklet::Host as AudioWorkletHost;
use crate::host::webaudio::Host as WebAudioHost;
use crate::traits::HostTrait as _;

impl_platform_host!(
WebAudio => WebAudioHost,
#[cfg(all(feature = "audioworklet", target_feature = "atomics"))] AudioWorklet => AudioWorkletHost,
#[cfg(all(target_os = "unknown", feature = "audioworklet", target_feature = "atomics"))] AudioWorklet => AudioWorkletHost,
#[cfg(feature = "custom")] Custom => super::CustomHost
);

Expand Down Expand Up @@ -1004,7 +1008,7 @@ mod platform_impl {
target_os = "android",
all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
),
)))]
Expand Down
4 changes: 2 additions & 2 deletions src/sample_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub use dasp_sample::U24;
pub use dasp_sample::{FromSample, Sample};
#[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
))]
use wasm_bindgen::prelude::*;
Expand All @@ -56,7 +56,7 @@ use wasm_bindgen::prelude::*;
#[cfg_attr(
all(
target_arch = "wasm32",
target_os = "unknown",
any(target_os = "emscripten", target_os = "unknown"),
feature = "wasm-bindgen"
),
wasm_bindgen
Expand Down
Loading