From decf7c2aefdb9e0cff866704bfd2572b5ffccecd Mon Sep 17 00:00:00 2001 From: Henrik Friedrichsen Date: Sun, 11 Apr 2021 15:17:10 +0200 Subject: [PATCH] Improve synchronization of playback times Take librespot timestamps instead of approximating them in ncspot. --- src/mpris.rs | 4 ++-- src/queue.rs | 2 +- src/spotify.rs | 24 +++++++++--------------- src/spotify_worker.rs | 25 ++++++++++++++++++++----- src/ui/statusbar.rs | 8 ++++---- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/mpris.rs b/src/mpris.rs index aecacc6..955465d 100644 --- a/src/mpris.rs +++ b/src/mpris.rs @@ -30,8 +30,8 @@ struct MprisState(String, Option); fn get_playbackstatus(spotify: Spotify) -> String { match spotify.get_current_status() { - PlayerEvent::Playing | PlayerEvent::FinishedTrack => "Playing", - PlayerEvent::Paused => "Paused", + PlayerEvent::Playing(_) | PlayerEvent::FinishedTrack => "Playing", + PlayerEvent::Paused(_) => "Paused", _ => "Stopped", } .to_string() diff --git a/src/queue.rs b/src/queue.rs index 31b3ff5..837679f 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -273,7 +273,7 @@ impl Queue { pub fn toggleplayback(&self) { match self.spotify.get_current_status() { - PlayerEvent::Playing | PlayerEvent::Paused => { + PlayerEvent::Playing(_) | PlayerEvent::Paused(_) => { self.spotify.toggleplayback(); } PlayerEvent::Stopped => match self.next_index() { diff --git a/src/spotify.rs b/src/spotify.rs index 78bef76..fe43f0b 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -60,8 +60,8 @@ pub const VOLUME_PERCENT: u16 = ((u16::max_value() as f64) * 1.0 / 100.0) as u16 #[derive(Clone, Debug, PartialEq)] pub enum PlayerEvent { - Playing, - Paused, + Playing(SystemTime), + Paused(Duration), Stopped, FinishedTrack, } @@ -746,12 +746,13 @@ impl Spotify { pub fn update_status(&self, new_status: PlayerEvent) { match new_status { - PlayerEvent::Paused => { - self.set_elapsed(Some(self.get_current_progress())); + PlayerEvent::Paused(position) => { + self.set_elapsed(Some(position)); self.set_since(None); } - PlayerEvent::Playing => { - self.set_since(Some(SystemTime::now())); + PlayerEvent::Playing(playback_start) => { + self.set_since(Some(playback_start)); + self.set_elapsed(None); } PlayerEvent::Stopped | PlayerEvent::FinishedTrack => { self.set_elapsed(None); @@ -778,8 +779,8 @@ impl Spotify { pub fn toggleplayback(&self) { match self.get_current_status() { - PlayerEvent::Playing => self.pause(), - PlayerEvent::Paused => self.play(), + PlayerEvent::Playing(_) => self.pause(), + PlayerEvent::Paused(_) => self.play(), _ => (), } } @@ -805,13 +806,6 @@ impl Spotify { } pub fn seek(&self, position_ms: u32) { - self.set_elapsed(Some(Duration::from_millis(position_ms.into()))); - self.set_since(if self.get_current_status() == PlayerEvent::Playing { - Some(SystemTime::now()) - } else { - None - }); - self.send_worker(WorkerCommand::Seek(position_ms)); } diff --git a/src/spotify_worker.rs b/src/spotify_worker.rs index bf4e7c3..2e3d44c 100644 --- a/src/spotify_worker.rs +++ b/src/spotify_worker.rs @@ -14,8 +14,8 @@ use librespot_core::session::Session; use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId}; use librespot_playback::mixer::Mixer; use librespot_playback::player::{Player, PlayerEvent as LibrespotPlayerEvent}; -use std::pin::Pin; use std::time::Duration; +use std::{pin::Pin, time::SystemTime}; pub(crate) enum WorkerCommand { Load(Playable, bool, u32), @@ -141,13 +141,28 @@ impl futures::Future for Worker { | LibrespotPlayerEvent::Changed { .. } => { progress = true; } - LibrespotPlayerEvent::Playing { .. } => { - self.events.send(Event::Player(PlayerEvent::Playing)); + LibrespotPlayerEvent::Playing { + play_request_id: _, + track_id: _, + position_ms, + duration_ms: _, + } => { + let position = Duration::from_millis(position_ms as u64); + let playback_start = SystemTime::now() - position; + self.events + .send(Event::Player(PlayerEvent::Playing(playback_start))); self.refresh_task = self.create_refresh(); self.active = true; } - LibrespotPlayerEvent::Paused { .. } => { - self.events.send(Event::Player(PlayerEvent::Paused)); + LibrespotPlayerEvent::Paused { + play_request_id: _, + track_id: _, + position_ms, + duration_ms: _, + } => { + let position = Duration::from_millis(position_ms as u64); + self.events + .send(Event::Player(PlayerEvent::Paused(position))); self.active = false; } LibrespotPlayerEvent::Stopped { .. } => { diff --git a/src/ui/statusbar.rs b/src/ui/statusbar.rs index 1f31fa8..037ecd3 100644 --- a/src/ui/statusbar.rs +++ b/src/ui/statusbar.rs @@ -72,14 +72,14 @@ impl View for StatusBar { let state_icon = if self.use_nerdfont { match self.spotify.get_current_status() { - PlayerEvent::Playing => "\u{f909} ", - PlayerEvent::Paused => "\u{f8e3} ", + PlayerEvent::Playing(_) => "\u{f909} ", + PlayerEvent::Paused(_) => "\u{f8e3} ", PlayerEvent::Stopped | PlayerEvent::FinishedTrack => "\u{f9da} ", } } else { match self.spotify.get_current_status() { - PlayerEvent::Playing => "▶ ", - PlayerEvent::Paused => "▮▮", + PlayerEvent::Playing(_) => "▶ ", + PlayerEvent::Paused(_) => "▮▮", PlayerEvent::Stopped | PlayerEvent::FinishedTrack => "◼ ", } }