Skip to content

Commit 4d34fa3

Browse files
committed
more ergonomic API, update MSRV
1 parent fd7b5dc commit 4d34fa3

10 files changed

Lines changed: 139 additions & 46 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
fail-fast: false
1919
matrix:
2020
os: [macos-latest, windows-latest, ubuntu-latest]
21-
toolchain: ["1.87"]
21+
toolchain: ["1.89"]
2222
include:
2323
- os: macos-latest
2424
MACOS: true

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
88
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
99

1010
## Unreleased
11+
- Added Opus support via `symphonia-adapter-libopus`.
1112

1213
## Version [0.22.1] (2026-02-22)
1314

Cargo.lock

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ repository = "https://github.com/RustAudio/rodio"
88
documentation = "https://docs.rs/rodio"
99
exclude = ["assets/**", "tests/**"]
1010
edition = "2021"
11-
rust-version = "1.87"
11+
rust-version = "1.89"
1212

1313
[features]
1414
# Default feature set provides audio playback and common format support
@@ -50,6 +50,9 @@ noise = ["rand", "rand_distr"]
5050
# Enable WebAssembly support for web browsers
5151
wasm-bindgen = ["cpal/wasm-bindgen"]
5252

53+
# Base symphonia feature (doesn't enable any codecs)
54+
symphonia = ["dep:symphonia"]
55+
5356
# To decode an audio source with Rodio, you need to enable the appropriate features for *both* the
5457
# demuxer and the decoder.
5558
#
@@ -96,15 +99,15 @@ symphonia-wav = ["symphonia/wav"]
9699
# Enable SIMD optimisations for Symphonia
97100
symphonia-simd = ["symphonia/opt-simd"]
98101

102+
# libopus adapter for Symphonia
103+
symphonia-libopus = ["symphonia", "dep:symphonia-adapter-libopus"]
104+
99105
# Alternative decoders and demuxers
100106
claxon = ["dep:claxon"] # FLAC
101107
hound = ["dep:hound"] # WAV
102108
minimp3 = ["dep:minimp3_fixed"] # MP3
103109
lewton = ["dep:lewton"] # Ogg Vorbis
104110

105-
# Third party codec example
106-
libopus = ["dep:symphonia-adapter-libopus"]
107-
108111
[package.metadata.docs.rs]
109112
all-features = true
110113
rustdoc-args = ["--cfg", "docsrs"]
@@ -129,7 +132,7 @@ atomic_float = { version = "1.1.0", optional = true }
129132
rtrb = { version = "0.3.2", optional = true }
130133
num-rational = "0.4.2"
131134

132-
symphonia-adapter-libopus = {version="0.2", optional = true}
135+
symphonia-adapter-libopus = { version = "0.2", optional = true }
133136

134137
[dev-dependencies]
135138
quickcheck = "1"
@@ -138,6 +141,7 @@ rstest_reuse = "0.7"
138141
approx = "0.5.1"
139142
divan = "0.1.14"
140143
inquire = "0.9.3"
144+
symphonia-adapter-fdk-aac = "0.1"
141145

142146
[[bench]]
143147
name = "effects"
@@ -235,6 +239,10 @@ required-features = ["playback", "vorbis"]
235239
name = "music_wav"
236240
required-features = ["playback", "wav"]
237241

242+
[[example]]
243+
name = "music_opus"
244+
required-features = ["playback", "symphonia-libopus"]
245+
238246
[[example]]
239247
name = "noise_generator"
240248
required-features = ["playback", "noise"]
@@ -261,4 +269,4 @@ required-features = ["playback", "vorbis"]
261269

262270
[[example]]
263271
name = "third_party_codec"
264-
required-features = ["playback", "symphonia", "libopus"]
272+
required-features = ["playback", "symphonia", "symphonia-isomp4"]

examples/music_opus.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use std::error::Error;
2+
3+
fn main() -> Result<(), Box<dyn Error>> {
4+
let stream_handle = rodio::DeviceSinkBuilder::open_default_sink()?;
5+
let player = rodio::Player::connect_new(stream_handle.mixer());
6+
7+
let file = std::fs::File::open("assets/music.opus")?;
8+
player.append(rodio::Decoder::try_from(file)?);
9+
10+
player.sleep_until_end();
11+
12+
Ok(())
13+
}

examples/third_party_codec.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
1-
use std::{error::Error, sync::Arc};
2-
31
use rodio::decoder::DecoderBuilder;
4-
use symphonia::{core::codecs::CodecRegistry, default::register_enabled_codecs};
5-
use symphonia_adapter_libopus::OpusDecoder;
2+
use std::error::Error;
3+
use symphonia_adapter_fdk_aac::AacDecoder;
64

75
fn main() -> Result<(), Box<dyn Error>> {
86
let stream_handle = rodio::DeviceSinkBuilder::open_default_sink()?;
97
let sink = rodio::Player::connect_new(stream_handle.mixer());
108

11-
let mut codec_registry = CodecRegistry::new();
12-
codec_registry.register_all::<OpusDecoder>();
13-
register_enabled_codecs(&mut codec_registry);
14-
15-
let codec_registry_arc = Arc::new(codec_registry);
16-
17-
let file = std::fs::File::open("assets/music.opus")?;
9+
let file = std::fs::File::open("assets/music.m4a")?;
10+
let len = file.metadata()?.len();
1811
let decoder = DecoderBuilder::new()
19-
.with_codec_registry(codec_registry_arc)
2012
.with_data(file)
13+
// Note: the length must be known for Symphonia to properly detect the format for this file
14+
// This limitation will be removed in Symphonia 0.6
15+
.with_byte_len(len)
16+
.with_decoder::<AacDecoder>()
2117
.build()?;
2218
sink.append(decoder);
2319

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
inputs: inputs.utils.lib.eachDefaultSystem (
99
system: let
1010
pkgs = inputs.nixpkgs.legacyPackages.${system}.extend inputs.rust-overlay.overlays.default;
11-
rust = pkgs.rust-bin.stable."1.87.0".default.override {
11+
rust = pkgs.rust-bin.stable."1.89.0".default.override {
1212
extensions = [ "rust-src" "rust-analyzer" ];
1313
};
1414
in {

src/decoder/builder.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
use std::io::{Read, Seek};
4141

4242
#[cfg(feature = "symphonia")]
43-
use crate::decoder::symphonia::SymphoniaRegistry;
43+
use crate::decoder::symphonia::Registry;
4444

4545
#[cfg(feature = "symphonia")]
4646
use self::read_seek_source::ReadSeekSource;
@@ -49,6 +49,8 @@ use ::symphonia::core::{
4949
codecs::CodecRegistry,
5050
io::{MediaSource, MediaSourceStream},
5151
};
52+
#[cfg(feature = "symphonia")]
53+
use ::symphonia::default::register_enabled_codecs;
5254

5355
use super::*;
5456

@@ -85,7 +87,7 @@ pub struct Settings {
8587
pub(crate) is_seekable: bool,
8688

8789
#[cfg(feature = "symphonia")]
88-
pub(crate) codec_registry: SymphoniaRegistry,
90+
pub(crate) codec_registry: Registry,
8991
}
9092

9193
impl Default for Settings {
@@ -98,7 +100,13 @@ impl Default for Settings {
98100
mime_type: None,
99101
is_seekable: false,
100102
#[cfg(feature = "symphonia")]
101-
codec_registry: SymphoniaRegistry::Default,
103+
codec_registry: {
104+
let mut codec_registry = CodecRegistry::new();
105+
register_enabled_codecs(&mut codec_registry);
106+
#[cfg(feature = "symphonia-libopus")]
107+
codec_registry.register_all::<symphonia_adapter_libopus::OpusDecoder>();
108+
Registry::new(codec_registry)
109+
},
102110
}
103111
}
104112
}
@@ -242,12 +250,16 @@ impl<R: Read + Seek + Send + Sync + 'static> DecoderBuilder<R> {
242250
self
243251
}
244252

245-
/// Set a custom codec registry
253+
/// Adds a third-party decoder.
254+
/// If multiple decoders for the same codec are registered, the one registered last will take precedence.
246255
///
247-
/// See the symphonia documentation of Registry for how to add additional (third party) codecs.
256+
/// See the documentation for [CodecRegistry] for more info.
248257
#[cfg(feature = "symphonia")]
249-
pub fn with_codec_registry(mut self, codec_registry: Arc<CodecRegistry>) -> Self {
250-
self.settings.codec_registry = SymphoniaRegistry::Custom(codec_registry);
258+
pub fn with_decoder<D>(self) -> Self
259+
where
260+
D: ::symphonia::core::codecs::Decoder,
261+
{
262+
self.settings.codec_registry.write().register_all::<D>();
251263
self
252264
}
253265

src/decoder/symphonia.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use core::time::Duration;
2-
use std::{fmt::Debug, sync::Arc};
2+
use std::{
3+
fmt::{self, Debug},
4+
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
5+
};
36
use symphonia::{
47
core::{
58
audio::{AudioBufferRef, SampleBuffer, SignalSpec},
@@ -21,21 +24,25 @@ use crate::{
2124
};
2225

2326
#[derive(Clone)]
24-
/// Enum for choosing which codec registry to used with Symphonia decoders.
25-
pub enum SymphoniaRegistry {
26-
/// Use the symphonia default registry symphonia::default::get_codecs()
27-
Default,
27+
pub(crate) struct Registry(Arc<RwLock<CodecRegistry>>);
2828

29-
///Use a custom CodecRegistry
30-
Custom(Arc<CodecRegistry>),
29+
impl Debug for Registry {
30+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31+
f.write_str("Registry")
32+
}
3133
}
3234

33-
impl Debug for SymphoniaRegistry {
34-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35-
match self {
36-
Self::Default => write!(f, "Default"),
37-
Self::Custom(_) => write!(f, "Custom"),
38-
}
35+
impl Registry {
36+
pub(crate) fn new(registry: CodecRegistry) -> Self {
37+
Self(Arc::new(RwLock::new(registry)))
38+
}
39+
40+
pub(crate) fn write(&self) -> RwLockWriteGuard<'_, CodecRegistry> {
41+
self.0.write().unwrap()
42+
}
43+
44+
pub(crate) fn read(&self) -> RwLockReadGuard<'_, CodecRegistry> {
45+
self.0.read().unwrap()
3946
}
4047
}
4148

@@ -121,13 +128,12 @@ impl SymphoniaDecoder {
121128
None => return Ok(None),
122129
};
123130

124-
let mut decoder = match &settings.codec_registry {
125-
SymphoniaRegistry::Default => symphonia::default::get_codecs(),
126-
SymphoniaRegistry::Custom(cr) => cr.as_ref(),
127-
}
128-
.make(&track.codec_params, &DecoderOptions::default())?;
131+
let mut decoder = settings
132+
.codec_registry
133+
.read()
134+
.make(&track.codec_params, &DecoderOptions::default())?;
129135

130-
let total_duration = stream
136+
let total_duration = track
131137
.codec_params
132138
.time_base
133139
.zip(stream.codec_params.n_frames)

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@
118118
//! or enabling specific codecs using one of the `symphonia-{codec name}` features.
119119
//! By default, decoders for the most common file types (flac, mp3, mp4, vorbis, wav) are enabled.
120120
//!
121+
//! See the [symphonia docs](https://docs.rs/symphonia/latest/symphonia) for the complete
122+
//! list of supported formats.
123+
//!
121124
//! ### Alternative Decoders
122125
//!
123126
//! Alternative decoder libraries are available for some filetypes:

0 commit comments

Comments
 (0)