Skip to content
Merged
1 change: 1 addition & 0 deletions .codespellignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Exceptions, all lowercase, sorted lexicographically
caf
crate
ser
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Version History

## Unreleased

- Decoders are enabled always - the legacy cargo features mp3/ogg/flac/wav/.. are now no-op
- Added .aiff decoder support
- Fix: mp3 decoding would sometimes insert leading silent frames

## Version 1.4.0 (2026-05-18)

- Added `BaseAudioContext::render_quantum_size` (128 always for now)
Expand Down
42 changes: 22 additions & 20 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ arc-swap = "1.6"
arrayvec = "0.7"
fft-convolver = "0.3"
cpal = { version = "0.17", optional = true }
creek = "1.2"
creek = { version = "1.2", default-features = false, features = [
"decode",
"decode-all",
"encode-wav",
] }
crossbeam-channel = "0.5"
cubeb = { version = "0.15", optional = true }
dasp_sample = "0.11"
Expand All @@ -41,7 +45,10 @@ num-complex = "0.4"
realfft = "3.3"
rubato = "0.16"
smallvec = "1.11"
symphonia = { version = "0.5", default-features = false }
symphonia = { version = "0.6", default-features = false, features = [
"all",
"opt-simd",
] }
vecmath = "1.0"

[target.'cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))'.dependencies]
Expand Down Expand Up @@ -69,24 +76,19 @@ path = "benches/my_benchmark.rs"
harness = false

[features]
default = ["mp3", "ogg", "flac", "wav", "m4a", "alac", "cpal"]
mp3 = ["symphonia/mp3", "creek/decode-mp3"]
ogg = [
"symphonia/ogg",
"symphonia/vorbis",
"creek/decode-ogg",
"creek/decode-vorbis",
]
flac = ["symphonia/flac", "creek/decode-flac"]
wav = ["symphonia/wav", "symphonia/pcm", "creek/decode-wav", "creek/decode-pcm"]
aac = ["symphonia/aac", "creek/decode-aac"]
m4a = ["aac", "symphonia/isomp4", "creek/decode-isomp4"]
alac = [
"symphonia/alac",
"symphonia/isomp4",
"creek/decode-alac",
"creek/decode-isomp4",
]
default = ["cpal"]

# Legacy codec feature names kept for backwards compatibility.
# Decoding support is no longer split by file format; all supported Symphonia
# and Creek decoders are enabled unconditionally.
mp3 = []
ogg = []
flac = []
wav = []
aac = []
m4a = []
alac = []

cpal = ["dep:cpal"]
cubeb = ["dep:cubeb"]
cpal-jack = ["cpal", "cpal/jack"]
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ via `cpal`'s `wasm-bindgen` backend. Check out [an example WASM
project](https://github.com/orottier/wasm-web-audio-rs).
Warning: experimental!

## Audio decoding support

Audio decoding is powered by Symphonia. The current implementation enables all
Symphonia-supported audio formats and codecs, including AIFF, CAF, ISO/MP4,
MKV/WebM, Ogg, WAV, AAC, ADPCM, ALAC, FLAC, MP1/MP2/MP3, PCM, and Vorbis.

## Contributing

web-audio-api-rs welcomes contribution from everyone in the form of
Expand Down
44 changes: 9 additions & 35 deletions src/context/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::context::{
AudioContextRegistration, AudioContextState, AudioParamId, ConcreteBaseAudioContext,
DESTINATION_NODE_ID,
};
use crate::decoding::MediaDecoder;
use crate::decoding::decode_media_data;
use crate::events::{Event, EventHandler, EventType};
use crate::node::{AudioNode, AudioNodeOptions};
use crate::param::AudioParamDescriptor;
Expand All @@ -27,7 +27,9 @@ pub trait BaseAudioContext {

/// Decode an [`AudioBuffer`] from a given input stream.
///
/// The current implementation can decode FLAC, Opus, PCM, Vorbis, and Wav.
/// The current implementation supports Symphonia's audio formats and codecs,
/// including AIFF, CAF, ISO/MP4, MKV/WebM, Ogg, WAV, AAC, ADPCM, ALAC,
/// FLAC, MP1/MP2/MP3, PCM, and Vorbis.
///
/// In addition to the official spec, the input parameter can be any byte stream (not just an
/// array). This means you can decode audio data from a file, network stream, or in memory
Expand Down Expand Up @@ -67,26 +69,14 @@ pub trait BaseAudioContext {
&self,
input: R,
) -> Result<AudioBuffer, Box<dyn std::error::Error + Send + Sync>> {
// Set up a media decoder, consume the stream in full and construct a single buffer out of it
let mut buffer = MediaDecoder::try_new(input)?
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.reduce(|mut accum, item| {
accum.extend(&item);
accum
})
// if there are no samples decoded, return an empty buffer
.unwrap_or_else(|| AudioBuffer::from(vec![vec![]], self.sample_rate()));

// resample to desired rate (no-op if already matching)
buffer.resample(self.sample_rate());

Ok(buffer)
decode_media_data(input, self.sample_rate())
}

/// Decode an [`AudioBuffer`] from a given input stream.
///
/// The current implementation can decode FLAC, Opus, PCM, Vorbis, and Wav.
/// The current implementation supports Symphonia's audio formats and codecs,
/// including AIFF, CAF, ISO/MP4, MKV/WebM, Ogg, WAV, AAC, ADPCM, ALAC,
/// FLAC, MP1/MP2/MP3, PCM, and Vorbis.
///
/// In addition to the official spec, the input parameter can be any byte stream (not just an
/// array). This means you can decode audio data from a file, network stream, or in memory
Expand All @@ -109,23 +99,7 @@ pub trait BaseAudioContext {
+ Send
+ 'static {
let sample_rate = self.sample_rate();
async move {
// Set up a media decoder, consume the stream in full and construct a single buffer out of it
let mut buffer = MediaDecoder::try_new(input)?
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.reduce(|mut accum, item| {
accum.extend(&item);
accum
})
// if there are no samples decoded, return an empty buffer
.unwrap_or_else(|| AudioBuffer::from(vec![vec![]], sample_rate));

// resample to desired rate (no-op if already matching)
buffer.resample(sample_rate);

Ok(buffer)
}
async move { decode_media_data(input, sample_rate) }
}

/// Create an new "in-memory" `AudioBuffer` with the given number of channels,
Expand Down
Loading
Loading