From f50fca02aee409a8aa207d2bb15252ca03633f7a Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sun, 24 Apr 2016 14:48:15 +0100 Subject: [PATCH] player: Add seek_at command for precise seeking --- src/player.rs | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/player.rs b/src/player.rs index 7f381470..53ce99ba 100644 --- a/src/player.rs +++ b/src/player.rs @@ -10,7 +10,7 @@ use audio_backend::Sink; use metadata::{FileFormat, Track, TrackRef}; use session::{Bitrate, Session}; use util::{self, SpotifyId, Subfile}; -use spirc::PlayStatus; +pub use spirc::PlayStatus; #[cfg(not(feature = "with-tremor"))] fn vorbis_time_seek_ms(decoder: &mut vorbis::Decoder, ms: i64) -> Result<(), vorbis::VorbisError> where R: Read + Seek { @@ -34,6 +34,7 @@ fn vorbis_time_tell_ms(decoder: &mut vorbis::Decoder) -> Result; +#[derive(Clone)] pub struct Player { state: Arc>, observers: Arc>>, @@ -43,13 +44,14 @@ pub struct Player { #[derive(Clone)] pub struct PlayerState { - status: PlayStatus, - position_ms: u32, - position_measured_at: i64, - update_time: i64, - volume: u16, + pub status: PlayStatus, + pub position_ms: u32, + pub position_measured_at: i64, + pub update_time: i64, + pub volume: u16, + pub track: Option, - end_of_track: bool, + pub end_of_track: bool, } struct PlayerInternal { @@ -68,6 +70,7 @@ enum PlayerCommand { Volume(u16), Stop, Seek(u32), + SeekAt(u32, i64), } impl Player { @@ -81,6 +84,7 @@ impl Player { position_measured_at: 0, update_time: util::now_ms(), volume: 0xFFFF, + track: None, end_of_track: false, })); @@ -126,6 +130,10 @@ impl Player { self.command(PlayerCommand::Seek(position_ms)); } + pub fn seek_at(&self, position_ms: u32, measured_at: i64) { + self.command(PlayerCommand::SeekAt(position_ms, measured_at)); + } + pub fn state(&self) -> PlayerState { self.state.lock().unwrap().clone() } @@ -176,6 +184,7 @@ impl PlayerInternal { state.status = PlayStatus::kPlayStatusPause; state.position_ms = position; state.position_measured_at = util::now_ms(); + state.track = Some(track_id); true }); drop(decoder); @@ -235,6 +244,20 @@ impl PlayerInternal { true }); } + Some(PlayerCommand::SeekAt(position, measured_at)) => { + let position = (util::now_ms() - measured_at + position as i64) as u32; + + let before = util::now_ms(); + vorbis_time_seek_ms(decoder.as_mut().unwrap(), position as i64).unwrap(); + self.update(|state| { + state.position_ms = vorbis_time_tell_ms(decoder.as_mut().unwrap()).unwrap() as u32; + state.position_measured_at = util::now_ms(); + + println!("SEEK: {} {} {}", before, util::now_ms(), util::now_ms() - before); + + true + }); + } Some(PlayerCommand::Play) => { self.update(|state| { state.status = PlayStatus::kPlayStatusPlay; @@ -249,7 +272,7 @@ impl PlayerInternal { self.update(|state| { state.status = PlayStatus::kPlayStatusPause; state.update_time = util::now_ms(); - state.position_ms = vorbis_time_tell_ms(decoder.as_mut().unwrap()).unwrap() as u32; + state.position_ms = decoder.as_mut().map(|d| vorbis_time_tell_ms(d).unwrap()).unwrap_or(0) as u32; state.position_measured_at = util::now_ms(); true }); @@ -286,6 +309,13 @@ impl PlayerInternal { let buffer = apply_volume(self.state.lock().unwrap().volume, &packet.data); sink.write(&buffer).unwrap(); + + self.update(|state| { + state.position_ms = vorbis_time_tell_ms(decoder.as_mut().unwrap()).unwrap() as u32; + state.position_measured_at = util::now_ms(); + + false + }); } Some(Err(vorbis::VorbisError::Hole)) => (), Some(Err(e)) => panic!("Vorbis error {:?}", e),