Merge pull request #183 from cucadmuh/feat/opus-support

feat(audio): Opus playback via symphonia-adapter-libopus
This commit is contained in:
Psychotoxical
2026-04-14 21:58:22 +02:00
committed by GitHub
3 changed files with 47 additions and 5 deletions
+30
View File
@@ -619,6 +619,15 @@ dependencies = [
"libloading 0.8.9",
]
[[package]]
name = "cmake"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
dependencies = [
"cc",
]
[[package]]
name = "cocoa"
version = "0.24.1"
@@ -3078,6 +3087,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "opusic-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc3280fe5b6f97ac1a35a0ac003e2fb0b92f8e4bdf2b2057e1bf9b87acca5696"
dependencies = [
"cmake",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
@@ -3581,6 +3599,7 @@ dependencies = [
"serde_json",
"souvlaki",
"symphonia",
"symphonia-adapter-libopus",
"sysinfo",
"tauri",
"tauri-build",
@@ -4740,6 +4759,17 @@ dependencies = [
"symphonia-metadata",
]
[[package]]
name = "symphonia-adapter-libopus"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d17450685dda0e87467eddf3e0f9c0b2a1707fc5c3234c111f70d46c6e4494"
dependencies = [
"log",
"opusic-sys",
"symphonia-core",
]
[[package]]
name = "symphonia-bundle-flac"
version = "0.5.5"
+2 -1
View File
@@ -7,7 +7,7 @@ license = ""
repository = ""
default-run = "psysonic"
edition = "2021"
rust-version = "1.77.2"
rust-version = "1.89"
[lib]
name = "psysonic_lib"
@@ -47,6 +47,7 @@ thread-priority = "1"
lofty = "0.22"
sysinfo = { version = "0.33", default-features = false, features = ["disk"] }
id3 = "1.16.4"
symphonia-adapter-libopus = "0.2.7"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
+15 -4
View File
@@ -1,5 +1,5 @@
use std::io::{Cursor, Read, Seek, SeekFrom};
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, OnceLock};
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering};
use std::time::{Duration, Instant};
#[cfg(unix)]
@@ -13,7 +13,7 @@ use rodio::source::UniformSourceIterator;
use serde::Serialize;
use symphonia::core::{
audio::{AudioBufferRef, SampleBuffer, SignalSpec},
codecs::{DecoderOptions, CODEC_TYPE_NULL},
codecs::{CodecRegistry, DecoderOptions, CODEC_TYPE_NULL},
formats::{FormatOptions, FormatReader, SeekMode, SeekTo},
io::{MediaSource, MediaSourceStream, MediaSourceStreamOptions},
meta::MetadataOptions,
@@ -682,11 +682,22 @@ impl Drop for RadioLiveState {
// [features]
// fdk-aac = ["dep:symphonia-adapter-fdk-aac"]
/// Symphonias default codec set for our enabled features, plus Opus via libopus.
fn psysonic_codec_registry() -> &'static CodecRegistry {
static REGISTRY: OnceLock<CodecRegistry> = OnceLock::new();
REGISTRY.get_or_init(|| {
let mut registry = CodecRegistry::new();
symphonia::default::register_enabled_codecs(&mut registry);
registry.register_all::<symphonia_adapter_libopus::OpusDecoder>();
registry
})
}
fn try_make_radio_decoder(
params: &symphonia::core::codecs::CodecParameters,
opts: &DecoderOptions,
) -> Result<Box<dyn symphonia::core::codecs::Decoder>, symphonia::core::errors::Error> {
symphonia::default::get_codecs().make(params, opts)
psysonic_codec_registry().make(params, opts)
}
// ── Async HTTP Download Task ──────────────────────────────────────────────────
@@ -980,7 +991,7 @@ impl SizedDecoder {
.zip(track.codec_params.n_frames)
.map(|(base, frames)| base.calc_time(frames));
let mut decoder = symphonia::default::get_codecs()
let mut decoder = psysonic_codec_registry()
.make(&track.codec_params, &DecoderOptions::default())
.map_err(|e| {
eprintln!("[psysonic] codec init failed: {e}");