add initial MPRIS support using zbus

- following the spec at https://specifications.freedesktop.org/mpris-spec/latest/

- some properties/commands are not fully supported, yet
This commit is contained in:
wisp3rwind 2024-10-01 11:36:41 +02:00
parent 80939819dd
commit de5a2969b7
4 changed files with 1226 additions and 1 deletions

3
Cargo.lock generated
View file

@ -1911,8 +1911,11 @@ dependencies = [
"sha1", "sha1",
"sysinfo", "sysinfo",
"thiserror", "thiserror",
"time",
"tokio", "tokio",
"url", "url",
"zbus",
"zvariant",
] ]
[[package]] [[package]]

View file

@ -64,7 +64,10 @@ sha1 = "0.10"
sysinfo = { version = "0.31.3", default-features = false, features = ["system"] } sysinfo = { version = "0.31.3", default-features = false, features = ["system"] }
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1.40", features = ["rt", "macros", "signal", "sync", "parking_lot", "process"] } tokio = { version = "1.40", features = ["rt", "macros", "signal", "sync", "parking_lot", "process"] }
time = { version = "0.3", features = ["formatting"] }
url = "2.2" url = "2.2"
zbus = { version = "4", default-features = false, features = ["tokio"], optional = true }
zvariant = { version = "4", default-features = false, optional = true }
[features] [features]
alsa-backend = ["librespot-playback/alsa-backend"] alsa-backend = ["librespot-playback/alsa-backend"]
@ -82,7 +85,9 @@ with-libmdns = ["librespot-discovery/with-libmdns"]
passthrough-decoder = ["librespot-playback/passthrough-decoder"] passthrough-decoder = ["librespot-playback/passthrough-decoder"]
default = ["rodio-backend", "with-libmdns"] with-mpris = ["dep:zbus", "dep:zvariant"]
default = ["rodio-backend", "with-libmdns", "with-mpris"]
[package.metadata.deb] [package.metadata.deb]
maintainer = "librespot-org" maintainer = "librespot-org"

View file

@ -40,6 +40,11 @@ use librespot::playback::mixer::alsamixer::AlsaMixer;
mod player_event_handler; mod player_event_handler;
use player_event_handler::{run_program_on_sink_events, EventHandler}; use player_event_handler::{run_program_on_sink_events, EventHandler};
#[cfg(feature = "with-mpris")]
mod mpris_event_handler;
#[cfg(feature = "with-mpris")]
use mpris_event_handler::MprisEventHandler;
fn device_id(name: &str) -> String { fn device_id(name: &str) -> String {
HEXLOWER.encode(&Sha1::digest(name.as_bytes())) HEXLOWER.encode(&Sha1::digest(name.as_bytes()))
} }
@ -1937,6 +1942,14 @@ async fn main() {
} }
} }
#[cfg(feature = "with-mpris")]
let mpris = MprisEventHandler::spawn(player.clone())
.await
.unwrap_or_else(|e| {
error!("could not initialize MPRIS: {}", e);
exit(1);
});
loop { loop {
tokio::select! { tokio::select! {
credentials = async { credentials = async {
@ -1990,6 +2003,10 @@ async fn main() {
exit(1); exit(1);
} }
}; };
#[cfg(feature = "with-mpris")]
mpris.set_spirc(spirc_.clone());
spirc = Some(spirc_); spirc = Some(spirc_);
spirc_task = Some(Box::pin(spirc_task_)); spirc_task = Some(Box::pin(spirc_task_));
@ -2035,6 +2052,9 @@ async fn main() {
let mut shutdown_tasks = tokio::task::JoinSet::new(); let mut shutdown_tasks = tokio::task::JoinSet::new();
#[cfg(feature = "with-mpris")]
shutdown_tasks.spawn(mpris.quit_and_join());
// Shutdown spirc if necessary // Shutdown spirc if necessary
if let Some(spirc) = spirc { if let Some(spirc) = spirc {
if let Err(e) = spirc.shutdown() { if let Err(e) = spirc.shutdown() {

1197
src/mpris_event_handler.rs Normal file

File diff suppressed because it is too large Load diff