Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Gate UPnP FFI exports behind feature

Add an "ffi" feature to crates/upnp (default disabled) and guard the
C ABI functions with #[cfg(feature = "ffi")]. Enable the feature from
crates/cli so the rockbox-cli staticlib pulls in the UPnP FFI symbols.
This prevents the FFI code from being compiled by default.

+15 -11
+1 -1
crates/cli/Cargo.toml
··· 10 10 anyhow = "1.0.90" 11 11 rockbox-airplay = {path = "../airplay"} 12 12 rockbox-slim = {path = "../slim"} 13 - rockbox-upnp = {path = "../upnp"} 13 + rockbox-upnp = {path = "../upnp", features = ["ffi"]} 14 14 clap = "4.5.16" 15 15 owo-colors = "4.1.0" 16 16 reqwest = { workspace = true, features = ["rustls-tls", "json"] }
+4
crates/upnp/Cargo.toml
··· 9 9 [lib] 10 10 crate-type = ["rlib"] 11 11 12 + [features] 13 + default = [] 14 + ffi = [] 15 + 12 16 [dependencies] 13 17 anyhow = { workspace = true } 14 18 tokio = { workspace = true }
+10 -10
crates/upnp/src/lib.rs
··· 20 20 pub fn _link_upnp() {} 21 21 22 22 use std::collections::VecDeque; 23 + #[cfg(feature = "ffi")] 23 24 use std::ffi::CStr; 25 + #[cfg(feature = "ffi")] 24 26 use std::os::raw::{c_char, c_int}; 25 27 use std::sync::atomic::{AtomicU64, Ordering}; 26 28 use std::sync::{Arc, Condvar, Mutex, OnceLock}; ··· 238 240 239 241 // --------------------------------------------------------------------------- 240 242 // FFI exports — UPnP PCM sink (WAV streaming to UPnP/DLNA renderers) 243 + // Only compiled when the `ffi` feature is enabled (rockbox-cli staticlib). 241 244 // --------------------------------------------------------------------------- 242 245 243 - /// Set the HTTP port for the WAV PCM stream (default: 7879). 246 + #[cfg(feature = "ffi")] 244 247 #[no_mangle] 245 248 pub extern "C" fn pcm_upnp_set_http_port(port: u16) { 246 249 CONFIG.lock().unwrap().pcm_port = port; 247 250 } 248 251 249 - /// Set the AVTransport control URL of a UPnP renderer to auto-command on start. 250 - /// Pass NULL to clear. 252 + #[cfg(feature = "ffi")] 251 253 #[no_mangle] 252 254 pub extern "C" fn pcm_upnp_set_renderer_url(url: *const c_char) { 253 255 let mut cfg = CONFIG.lock().unwrap(); ··· 262 264 cfg.renderer_url = if s.is_empty() { None } else { Some(s) }; 263 265 } 264 266 265 - /// Inform the PCM sink of the current sample rate (called by set_freq). 267 + #[cfg(feature = "ffi")] 266 268 #[no_mangle] 267 269 pub extern "C" fn pcm_upnp_set_sample_rate(rate: u32) { 268 270 CONFIG.lock().unwrap().sample_rate = rate; 269 271 } 270 272 271 - /// Start the WAV PCM stream HTTP server. The HTTP server starts once; the 272 - /// renderer is notified with fresh DIDL-Lite metadata on every call (track 273 - /// change), but Play is only issued on the first call after a full stop. 273 + #[cfg(feature = "ffi")] 274 274 #[no_mangle] 275 275 pub extern "C" fn pcm_upnp_start() -> c_int { 276 276 // --- Start the HTTP broadcast server once --- ··· 333 333 0 334 334 } 335 335 336 - /// Push raw S16LE stereo PCM into the WAV broadcast buffer. 336 + #[cfg(feature = "ffi")] 337 337 #[no_mangle] 338 338 pub extern "C" fn pcm_upnp_write(data: *const u8, len: usize) -> c_int { 339 339 if data.is_null() || len == 0 { ··· 344 344 0 345 345 } 346 346 347 - /// No-op between tracks — HTTP connections stay alive. 347 + #[cfg(feature = "ffi")] 348 348 #[no_mangle] 349 349 pub extern "C" fn pcm_upnp_stop() {} 350 350 351 - /// Shut down the PCM stream server (called on daemon exit). 351 + #[cfg(feature = "ffi")] 352 352 #[no_mangle] 353 353 pub extern "C" fn pcm_upnp_close() { 354 354 let mut started = PCM_STARTED.lock().unwrap();