diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 81500b0e..e7194d7e 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -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" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5baec629..3a19dd16 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -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" diff --git a/src-tauri/src/audio.rs b/src-tauri/src/audio.rs index c26c61f1..e049ebe6 100644 --- a/src-tauri/src/audio.rs +++ b/src-tauri/src/audio.rs @@ -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"] +/// Symphonia’s default codec set for our enabled features, plus Opus via libopus. +fn psysonic_codec_registry() -> &'static CodecRegistry { + static REGISTRY: OnceLock = OnceLock::new(); + REGISTRY.get_or_init(|| { + let mut registry = CodecRegistry::new(); + symphonia::default::register_enabled_codecs(&mut registry); + registry.register_all::(); + registry + }) +} + fn try_make_radio_decoder( params: &symphonia::core::codecs::CodecParameters, opts: &DecoderOptions, ) -> Result, 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}");