Skip to content

Symphonia custom registry support#806

Open
royalmustard wants to merge 13 commits intoRustAudio:masterfrom
royalmustard:symphonia-registry-workaround
Open

Symphonia custom registry support#806
royalmustard wants to merge 13 commits intoRustAudio:masterfrom
royalmustard:symphonia-registry-workaround

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?

Cargo.lock Outdated

[[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.

@aschey
Copy link
Contributor

aschey commented Feb 14, 2026

I see this is failing on the MSRV checks. I'd be willing to bump the MSRV for symphonia-adapter-libopus down if that's a hard blocker here. Personally, I feel stable-4 is an acceptable MSRV for a project like this, but it wouldn't be difficult to remove the code that requires 1.89.

@yara-blue
Copy link
Member

I'm happy to increase the MSRV @roderickvd you?

@roderickvd
Copy link
Member

1.89 is just 6 months old and I think two releases behind stable? I'd favor allowing older toolchains if that doesn't cost too much. cpals MSRV is 1.82 on most platforms now. But when it's too much of a hassle then it's OK for me too.

@aschey
Copy link
Contributor

aschey commented Feb 15, 2026

1.89 is 4 releases behind stable. Current is 1.93.

@yara-blue
Copy link
Member

yara-blue commented Feb 15, 2026

I'd favor allowing older toolchains if that doesn't cost too much.

At the risk of starting a larger debate :) could you explain why? I can see the reason for not being on the latest rustc (mitigates supply chain attacks) but 6 months is a long time. Is there a reason want the latest rodio but not a recent rustc? I personally really like being on a recent rustc as I tend to use the latest goodies coming out :)

edit: if we can figure this out/debate it out quickly then I'd propose we make a policy directly.

@roderickvd
Copy link
Member

No fancy reason. Just that backwards compatibility is a nice thing to have and I don’t want users to force updating their toolchains when it’s easy to circumvent.

6 months is fine for me, I’d rather spend my time on other things than MSRV debates. Don’t take that as any form of passive aggressiveness to you guys, it’s not. Literally that I see it in every crate I’m involved in 🙄 so ready to get it over with 😄

@yara-blue
Copy link
Member

yara-blue commented Feb 15, 2026

I personally think 6 months is super long but I am highly biassed and aware of that :)

MSRV = stable-4 it is then 🎉

No debate needed 🥳

edit: done 2b7439a

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

Comments