Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
2c14e46
refactor(host): narrow the cfg gate on frames_to_duration to its real…
ErwanLegrand Sep 19, 2026
3c95b11
fix(wasapi): check cbSize before reading the format extension
ErwanLegrand Sep 19, 2026
b66ee83
fix(wasapi): avoid overflow when converting a config to WAVEFORMATEXT…
ErwanLegrand Sep 19, 2026
0c1f0ea
fix(wasapi): derive the format pointer from the full WAVEFORMATEXTENS…
ErwanLegrand Sep 19, 2026
9df8b0f
doc(host): clarify what the stream-build timeout covers per backend
ErwanLegrand Sep 19, 2026
6a89799
fix(wasapi): bound the buffer size reported by the audio client
ErwanLegrand Sep 19, 2026
bf6da4c
fix(wasapi): reject a padding larger than the output buffer
ErwanLegrand Sep 19, 2026
5f7a437
fix(wasapi): release the render packet when the timestamp query fails
ErwanLegrand Sep 19, 2026
adebf05
fix(wasapi): handle empty and silent capture packets from GetBuffer
ErwanLegrand Sep 19, 2026
9e12d2f
fix(wasapi): release the capture packet when processing fails
ErwanLegrand Sep 19, 2026
0cb327c
fix(wasapi): bound the capture drain loop per audio event
ErwanLegrand Sep 19, 2026
dacc5d2
fix(wasapi): bound a capture packet against the reported buffer size
ErwanLegrand Sep 19, 2026
a59a1eb
doc(changelog): summarize the WASAPI hardening series
ErwanLegrand Sep 19, 2026
79ff335
test(wasapi): pin the WAVEFORMATEX conversion overflow guard and layout
ErwanLegrand Sep 19, 2026
85e1ab6
test(host): pin equilibrium byte patterns for the common formats
ErwanLegrand Sep 19, 2026
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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **WASAPI**: Output streams now start with real audio immediately instead of undefined content in the render buffer.
- **WASAPI**: A stream paused immediately after starting no longer plays silence before real audio on resume.
- **WASAPI**: Fix `I64` and `F64` incorrectly reported as supported output formats.
- **WASAPI**: Formats with a `cbSize` that doesn't cover the extension, and configurations whose
derived `WAVEFORMATEX` fields would overflow, are now rejected instead of being read out of
bounds, panicking, or wrapping.
- **WASAPI**: A buffer size or padding count beyond the stream's negotiated bounds, or a capture
packet larger than its buffer, is now rejected with a backend error instead of panicking,
over-reading, or allocating gigabytes.
- **WASAPI**: Empty capture packets are no longer delivered as a null buffer, packets the engine
marks silent now arrive as silence, and a slow data callback no longer leaves `stop()` and
`Drop` unserviced.

## [0.18.2] - 2026-08-16

Expand Down
2 changes: 2 additions & 0 deletions src/host/aaudio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! AAudio backend implementation.
//!
//! Default backend on Android.
//!
//! The stream-build `timeout` is ignored.

use std::{
fmt,
Expand Down
3 changes: 3 additions & 0 deletions src/host/alsa/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! ALSA backend implementation.
//!
//! Default backend on Linux and BSD systems.
//!
//! The stream-build `timeout` is not a setup bound: it becomes the `poll()` timeout of the
//! stream's run loop, so it applies for the life of the stream, and `None` polls forever.

extern crate alsa;
#[cfg(feature = "realtime")]
Expand Down
2 changes: 2 additions & 0 deletions src/host/asio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//!
//! ASIO is available on Windows with the `asio` feature.
//! See the project README for setup instructions.
//!
//! The stream-build `timeout` is ignored.

extern crate asio_sys as sys;

Expand Down
2 changes: 2 additions & 0 deletions src/host/audioworklet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//!
//! Available on WebAssembly with the `audioworklet` feature. Requires atomics support.
//! See the `audioworklet` example for setup instructions.
//!
//! The stream-build `timeout` is ignored.

use std::{
cell::RefCell,
Expand Down
3 changes: 3 additions & 0 deletions src/host/coreaudio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! CoreAudio backend implementation.
//!
//! Default backend on macOS, iOS, and tvOS.
//!
//! On macOS the stream-build `timeout` bounds the device rate change made during setup, with a
//! one-second default; on iOS it is ignored.

use objc2_core_audio_types::{
AudioStreamBasicDescription, kAudioFormatFlagIsFloat, kAudioFormatFlagIsPacked,
Expand Down
49 changes: 49 additions & 0 deletions src/host/equilibrium.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,52 @@ pub fn fill_equilibrium(buffer: &mut [u8], sample_format: SampleFormat) {
}
}
}

#[test]
fn test_fill_equilibrium_byte_patterns() {
let mut buf = vec![0u8; 8].into_boxed_slice();

// Unsigned 8-bit silence is 0x80, the midpoint of the range.
fill_equilibrium(&mut buf[..], SampleFormat::U8);
assert_eq!(buf[0], 0x80);
assert_eq!(buf[5], 0x80);

// Signed and float formats rest at zero.
fill_equilibrium(&mut buf[..], SampleFormat::I16);
assert_eq!(buf[0], 0);
assert_eq!(buf[5], 0);
fill_equilibrium(&mut buf[..], SampleFormat::I24);
assert_eq!(buf[0], 0);
assert_eq!(buf[5], 0);
fill_equilibrium(&mut buf[..], SampleFormat::F32);
assert_eq!(buf[0], 0);
assert_eq!(buf[5], 0);

// DSD silence is the 0x69 pattern.
fill_equilibrium(&mut buf[..], SampleFormat::DsdU8);
assert_eq!(buf[0], 0x69);
assert_eq!(buf[5], 0x69);

// Multi-byte unsigned formats take the typed path, the only one that casts the buffer to a
// wider pointer: check the value written and that `chunks_exact` accounts for every byte.
fill_equilibrium(&mut buf[..], SampleFormat::U16);
assert!(
buf.chunks_exact(2)
.all(|c| u16::from_ne_bytes(c.try_into().unwrap()) == 0x8000)
);
fill_equilibrium(&mut buf[..], SampleFormat::U24);
assert!(
buf.chunks_exact(4)
.all(|c| i32::from_ne_bytes(c.try_into().unwrap()) == 0x0080_0000)
);
fill_equilibrium(&mut buf[..], SampleFormat::U32);
assert!(
buf.chunks_exact(4)
.all(|c| u32::from_ne_bytes(c.try_into().unwrap()) == 0x8000_0000)
);
fill_equilibrium(&mut buf[..], SampleFormat::U64);
assert!(
buf.chunks_exact(8)
.all(|c| u64::from_ne_bytes(c.try_into().unwrap()) == 0x8000_0000_0000_0000)
);
}
1 change: 1 addition & 0 deletions src/host/jack/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! JACK backend implementation.
//!
//! Available on all platforms with the `jack` feature. Requires JACK server and client libraries.
//! The stream-build `timeout` bounds the whole build, including opening the JACK client.

extern crate jack;

Expand Down
2 changes: 1 addition & 1 deletion src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ pub(crate) use error_emit::try_emit_error;
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "windows",
target_vendor = "apple",
all(windows, any(feature = "asio", feature = "jack")),
all(
target_arch = "wasm32",
target_os = "unknown",
Expand Down
6 changes: 6 additions & 0 deletions src/host/pipewire/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
//! PipeWire backend implementation.
//!
//! Default backend on Linux when PipeWire is available.
//!
//! The stream-build `timeout` bounds stream initialization, waiting two seconds when given `None`.

use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
Expand Down
6 changes: 6 additions & 0 deletions src/host/pulseaudio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
//! PulseAudio backend implementation.
//!
//! Default backend on Linux and BSD systems when PipeWire is unavailable.
//!
//! The stream-build `timeout` bounds stream creation.

use std::{
ffi::CString,
fmt,
Expand Down
Loading
Loading