From f829001e882bc4dbdf0999c791a87e15442c08c0 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Sun, 4 Aug 2024 08:33:20 +0100 Subject: [PATCH] Add Seeked signal to Mpris interface The Mpris2 spec includes a `Seeked` signal which should be fired when the track position changes in an unexpected way i.e. when the user seeks to a different part of the track. This PR implements this signal on seek events and also when a new track begins. The latter is not strictly required but has been observed in other players (e.g. VLC). Closes #1492 --- src/mpris.rs | 11 +++++++++++ src/queue.rs | 4 ++++ src/spotify.rs | 13 +++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/mpris.rs b/src/mpris.rs index 4a66ac4d..48571633 100644 --- a/src/mpris.rs +++ b/src/mpris.rs @@ -6,6 +6,7 @@ use std::time::Duration; use tokio::sync::mpsc; use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::StreamExt; +use zbus::object_server::SignalContext; use zbus::zvariant::{ObjectPath, Value}; use zbus::{interface, ConnectionBuilder}; @@ -314,6 +315,9 @@ impl MprisPlayer { self.queue.get_current().is_some() } + #[zbus(signal)] + async fn seeked(context: &SignalContext<'_>, position: &i64) -> Result<(), zbus::Error>; + fn next(&self) { self.queue.next(true) } @@ -468,6 +472,8 @@ pub enum MprisCommand { NotifyPlaybackUpdate, /// Notify about volume updates. NotifyVolumeUpdate, + /// Notify about seek changes, + NotifySeekedUpdate(i64), } /// An MPRIS server that internally manager a thread which can be sent commands. This is internally @@ -533,6 +539,11 @@ impl MprisManager { info!("sending MPRIS volume update signal"); player_iface.volume_changed(ctx).await?; } + Some(MprisCommand::NotifySeekedUpdate(pos)) => { + // let pos = player_iface.position(); + info!("sending MPRIS seeked signal"); + MprisPlayer::seeked(ctx, &pos).await?; + } None => break, } } diff --git a/src/queue.rs b/src/queue.rs index dce7b131..0907e5ce 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -332,6 +332,10 @@ impl Queue { move || send_notification(&summary_txt, &body_txt, cover_url) }); } + + // Send a Seeked signal at start of new track + #[cfg(feature = "mpris")] + self.spotify.notify_seeked(0); } if reshuffle && self.get_shuffle() { diff --git a/src/spotify.rs b/src/spotify.rs index 36d754e1..a55c529d 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -394,6 +394,8 @@ impl Spotify { /// Seek in the currently played [Playable] played by the [Player]. pub fn seek(&self, position_ms: u32) { self.send_worker(WorkerCommand::Seek(position_ms)); + #[cfg(feature = "mpris")] + self.notify_seeked(position_ms); } /// Seek relatively to the current playback position of the [Player]. @@ -408,6 +410,17 @@ impl Spotify { self.cfg.state().volume } + /// Send a Seeked signal on Mpris interface + #[cfg(feature = "mpris")] + pub fn notify_seeked(&self, position: u32) { + if let Some(mpris_manager) = self.mpris.lock().unwrap().as_ref() { + info!("Seeked event"); + // Mpris spec requires microseconds + let new_position = position * 1000; + mpris_manager.send(MprisCommand::NotifySeekedUpdate(new_position.into())); + } + } + /// Set the current volume of the [Player]. If `notify` is true, also notify MPRIS clients about /// the update. pub fn set_volume(&self, volume: u16, notify: bool) {