Skip to content

Conversation

@royalmustard
Copy link

This PR add support for using a custom codec registry with the symphonia backend.

This allows easily add support for additional codecs, many of which are already supported by third party addons for symphonia (e.g. opus).

To use a custom registry, a (global) codec registry must be instantiated and all desired codecs must be registered in it.
Then, this registry can be given to a DecoderBuilder via the with_codec_registry function.
If no custom registry is given to the builder, the decoder will use symphonia's default registry, as before.

@yara-blue
Copy link
Member

Wonderful idea :)

What do you think of adding these behind a cargo feature and doing the with_codec_registry bit ourselves (as in not exposing that to the user)?

@royalmustard
Copy link
Author

as in adding a third_party_codecs feature, which then uses a different registry? If you insist on it we could do it, however this would move the task of curating and selecting the third party crates to the rodio maintainers. Additionally, this would limit the users in case they want to use a codec which is not in the third party codecs "officially" supported by rodio at that time.

@roderickvd
Copy link
Member

I tend to agree that the power in this feature would be precisely to expose it to users.
To that extent it'd be worthwhile to have an example added that shows how to use it.

@roderickvd
Copy link
Member

I like it. Can you find a public-domain music.opus that you can include as asset?

Something as hybrid with what @dvdsk suggested, because Opus support is a requested feature, could we also offer a opus feature that sets this up with Symphonia automatically?

I expect Opus support to be come merged in to Symphonia eventually, but not soon.

@UnknownSuperficialNight
Copy link
Contributor

This is great, before as a get around for opus decoding I made a custom FFmpeg Source to use FFmpeg to decode opus

Although this is not as a great as a first party solution, It's still great compared to using FFmpeg would be cool to see in rodio.

I expect Opus support to be come merged in to Symphonia eventually, but not soon.

Yep, only the initial work has really started here pdeljanov/Symphonia#398

and Tracking of opus as a whole started here 5 years ago pdeljanov/Symphonia#8

@aschey
Copy link
Contributor

aschey commented Oct 28, 2025

Before merging this, you might want to update symphonia-adapter-libopus to 0.2 at least. I made an important change for gapless playback.

@roderickvd
Copy link
Member

@royalmustard would you take a stab at getting the CI to pass?

@yara-blue
Copy link
Member

only a cargo fmt left and CI should pass 🥳

@yara-blue yara-blue self-requested a review January 9, 2026 11:52
@Android789515
Copy link

Testing that fork, I still experiencing an error with some WebM files encoded as Opus. The test file assets/music.opus works fine.

https://github.com/royalmustard/rodio.git Branch: symphonia-registry-workaround

A file like this is not working.
Rush-Limelight.webm

Code
use std::{fs::File, sync::Arc};

use rodio::decoder::DecoderBuilder;
use symphonia::{core::codecs::CodecRegistry, default::register_enabled_codecs};
use symphonia_adapter_libopus::OpusDecoder;

fn main() {
    let stream = rodio::DeviceSinkBuilder::open_default_sink()
        .unwrap();

    let sink = rodio::Player::connect_new(
        stream.mixer()
    );
    
    let mut codec_registry = CodecRegistry::new();

    codec_registry.register_all::<OpusDecoder>();

    register_enabled_codecs(&mut codec_registry);

    let codec_registry = Arc::new(codec_registry);

    let file = File::open("/home/untitled1/Music/Rush-Limelight.webm")
        .unwrap();

    let source = DecoderBuilder::new()
        .with_codec_registry(codec_registry)
        .with_data(file)
        .build()
        .unwrap();

    sink.append(source);

    sink.sleep_until_end();
}

Cargo.toml

[package]
name = "test-audio"
version = "0.1.0"
edition = "2024"

[dependencies]
rodio = { git = "https://github.com/royalmustard/rodio.git", branch = "symphonia-registry-workaround", features = ["symphonia", "symphonia-all", "playback"]}
symphonia = "0.5.5"
symphonia-adapter-libopus = "0.2.5"

Error

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/test-audio`

thread 'main' (783291) panicked at src/main.rs:30:10:
called `Result::unwrap()` on an `Err` value: UnrecognizedFormat
stack backtrace:
   0:     0x5d496a2fa262 - std::backtrace_rs::backtrace::libunwind::trace::hd57362190422746d
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/../../backtrace/src/backtrace/libunwind.rs:117:9
   1:     0x5d496a2fa262 - std::backtrace_rs::backtrace::trace_unsynchronized::he61be86f5e8dfc7b
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/../../backtrace/src/backtrace/mod.rs:66:14
   2:     0x5d496a2fa262 - std::sys::backtrace::_print_fmt::hd233ea33e70c29e2
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/sys/backtrace.rs:66:9
   3:     0x5d496a2fa262 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h718e2d17a1928e63
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/sys/backtrace.rs:39:26
   4:     0x5d496a30c09f - core::fmt::rt::Argument::fmt::hdeda3281325c4830
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/fmt/rt.rs:173:76
   5:     0x5d496a30c09f - core::fmt::write::h1d2246b072ea91eb
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/fmt/mod.rs:1469:25
   6:     0x5d496a2d5e13 - std::io::default_write_fmt::h4ebfe695aebd90ac
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/io/mod.rs:639:11
   7:     0x5d496a2d5e13 - std::io::Write::write_fmt::haf55272405c09d9b
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/io/mod.rs:1954:13
   8:     0x5d496a2dbf62 - std::sys::backtrace::BacktraceLock::print::h61c3bd81a9458a03
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/sys/backtrace.rs:42:9
   9:     0x5d496a2de72f - std::panicking::default_hook::{{closure}}::haf1ffb5d1e33a97f
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:301:27
  10:     0x5d496a2de589 - std::panicking::default_hook::hc32245deb6eaa988
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:328:9
  11:     0x5d496a2ded05 - std::panicking::panic_with_hook::h43adc00fd0e494cb
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:834:13
  12:     0x5d496a2deb9a - std::panicking::panic_handler::{{closure}}::h44391079756da3e7
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:707:13
  13:     0x5d496a2dc0a9 - std::sys::backtrace::__rust_end_short_backtrace::h934e1568393e5b8f
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/sys/backtrace.rs:174:18
  14:     0x5d496a2ca61d - __rustc[d9b87f19e823c0ef]::rust_begin_unwind
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:698:5
  15:     0x5d496a314260 - core::panicking::panic_fmt::h62031895f6e012da
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/panicking.rs:80:14
  16:     0x5d496a3134f6 - core::result::unwrap_failed::h8e46864fd8bf13c6
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/result.rs:1862:5
  17:     0x5d4969f2c1b3 - core::result::Result<T,E>::unwrap::h4c730a9bc2daeec8
                               at /home/untitled1/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:1233:23
  18:     0x5d4969f2c1b3 - test_audio::main::h70e3df494ae24595
                               at /home/untitled1/rust-lernin/test-audio/src/main.rs:30:10
  19:     0x5d4969f1f9eb - core::ops::function::FnOnce::call_once::h12da3e6c08188d87
                               at /home/untitled1/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
  20:     0x5d4969f2b8be - std::sys::backtrace::__rust_begin_short_backtrace::h1878ffb2a49d359e
                               at /home/untitled1/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs:158:18
  21:     0x5d4969f21451 - std::rt::lang_start::{{closure}}::hcc72c97f6a8ba3f9
                               at /home/untitled1/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:206:18
  22:     0x5d496a2d72a0 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hef272b0bbce060cb
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/ops/function.rs:287:21
  23:     0x5d496a2d72a0 - std::panicking::catch_unwind::do_call::hb8c4cc43eed9a08c
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:590:40
  24:     0x5d496a2d72a0 - std::panicking::catch_unwind::h2729a121c7344441
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:553:19
  25:     0x5d496a2d72a0 - std::panic::catch_unwind::h8930b2483deb2063
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panic.rs:359:14
  26:     0x5d496a2d72a0 - std::rt::lang_start_internal::{{closure}}::hada379c5dd834c6b
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/rt.rs:175:24
  27:     0x5d496a2d72a0 - std::panicking::catch_unwind::do_call::hc3ea95eb90ebfdc8
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:590:40
  28:     0x5d496a2d72a0 - std::panicking::catch_unwind::h0b97aa6eb277c112
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:553:19
  29:     0x5d496a2d72a0 - std::panic::catch_unwind::h2db34aa2a1d62ae5
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panic.rs:359:14
  30:     0x5d496a2d72a0 - std::rt::lang_start_internal::h00c7908c7c2f92b8
                               at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/rt.rs:171:5
  31:     0x5d4969f21437 - std::rt::lang_start::h4dcfa4be966cce05
                               at /home/untitled1/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:205:5
  32:     0x5d4969f2c2fe - main
  33:     0x75f0ae627635 - <unknown>
  34:     0x75f0ae6276e9 - __libc_start_main
  35:     0x5d4969f1ec85 - _start
  36:                0x0 - <unknown>

@roderickvd
Copy link
Member

Testing that fork, I still experiencing an error with some WebM files encoded as Opus. The test file assets/music.opus works fine.

@Android789515 was the symphonia-mkv feature also enabled? You'll need that to demux the WebM format.

Copy link
Member

@roderickvd roderickvd left a comment

Choose a reason for hiding this comment

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

Sorry for keeping this around for so long. Here's a few points to make its way to getting merged.


let codec_registry_arc = Arc::new(codec_registry);

let file = std::fs::File::open("../assets/music.opus")?;
Copy link
Member

Choose a reason for hiding this comment

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

Does this work? Shouldn't it just be "assets/music.opus"?

lewton = ["dep:lewton"] # Ogg Vorbis

# Third party codec example
libopus = ["dep:symphonia-adapter-libopus"]
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: please add a newline after.

Should we call this symphonic-opus instead?


[[package]]
name = "symphonia-adapter-libopus"
version = "0.1.2"
Copy link
Member

Choose a reason for hiding this comment

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

This seems out of sync with what's specified in Cargo.toml. Please regenerate the lockfile.

fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Default => write!(f, "Default"),
Self::Custom(_) => write!(f, "Custom"),
Copy link
Member

Choose a reason for hiding this comment

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

Could it put out more? It seems that symphonia-adapter-libopus does implement Debug also.

@roderickvd
Copy link
Member

roderickvd commented Jan 15, 2026

Also if you could add a changelog entry?

Finally, if you add #[cfg_attr(docsrs, doc(cfg(feature = "foo")))] then the new methods will also show up docs.rs.

@Android789515
Copy link

Testing that fork, I still experiencing an error with some WebM files encoded as Opus. The test file assets/music.opus works fine.

@Android789515 was the symphonia-mkv feature also enabled? You'll need that to demux the WebM format.

I went ahead and added the symphonia-mkv feature in my Cargo.toml but I still get the error.

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.

6 participants