player: Add seek_at command for precise seeking

This commit is contained in:
Paul Lietar 2016-04-24 14:48:15 +01:00
parent 8c0a37357d
commit f50fca02ae

View file

@ -10,7 +10,7 @@ use audio_backend::Sink;
use metadata::{FileFormat, Track, TrackRef}; use metadata::{FileFormat, Track, TrackRef};
use session::{Bitrate, Session}; use session::{Bitrate, Session};
use util::{self, SpotifyId, Subfile}; use util::{self, SpotifyId, Subfile};
use spirc::PlayStatus; pub use spirc::PlayStatus;
#[cfg(not(feature = "with-tremor"))] #[cfg(not(feature = "with-tremor"))]
fn vorbis_time_seek_ms<R>(decoder: &mut vorbis::Decoder<R>, ms: i64) -> Result<(), vorbis::VorbisError> where R: Read + Seek { fn vorbis_time_seek_ms<R>(decoder: &mut vorbis::Decoder<R>, ms: i64) -> Result<(), vorbis::VorbisError> where R: Read + Seek {
@ -34,6 +34,7 @@ fn vorbis_time_tell_ms<R>(decoder: &mut vorbis::Decoder<R>) -> Result<i64, vorbi
pub type PlayerObserver = Box<Fn(&PlayerState) + Send>; pub type PlayerObserver = Box<Fn(&PlayerState) + Send>;
#[derive(Clone)]
pub struct Player { pub struct Player {
state: Arc<Mutex<PlayerState>>, state: Arc<Mutex<PlayerState>>,
observers: Arc<Mutex<Vec<PlayerObserver>>>, observers: Arc<Mutex<Vec<PlayerObserver>>>,
@ -43,13 +44,14 @@ pub struct Player {
#[derive(Clone)] #[derive(Clone)]
pub struct PlayerState { pub struct PlayerState {
status: PlayStatus, pub status: PlayStatus,
position_ms: u32, pub position_ms: u32,
position_measured_at: i64, pub position_measured_at: i64,
update_time: i64, pub update_time: i64,
volume: u16, pub volume: u16,
pub track: Option<SpotifyId>,
end_of_track: bool, pub end_of_track: bool,
} }
struct PlayerInternal { struct PlayerInternal {
@ -68,6 +70,7 @@ enum PlayerCommand {
Volume(u16), Volume(u16),
Stop, Stop,
Seek(u32), Seek(u32),
SeekAt(u32, i64),
} }
impl Player { impl Player {
@ -81,6 +84,7 @@ impl Player {
position_measured_at: 0, position_measured_at: 0,
update_time: util::now_ms(), update_time: util::now_ms(),
volume: 0xFFFF, volume: 0xFFFF,
track: None,
end_of_track: false, end_of_track: false,
})); }));
@ -126,6 +130,10 @@ impl Player {
self.command(PlayerCommand::Seek(position_ms)); 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 { pub fn state(&self) -> PlayerState {
self.state.lock().unwrap().clone() self.state.lock().unwrap().clone()
} }
@ -176,6 +184,7 @@ impl PlayerInternal {
state.status = PlayStatus::kPlayStatusPause; state.status = PlayStatus::kPlayStatusPause;
state.position_ms = position; state.position_ms = position;
state.position_measured_at = util::now_ms(); state.position_measured_at = util::now_ms();
state.track = Some(track_id);
true true
}); });
drop(decoder); drop(decoder);
@ -235,6 +244,20 @@ impl PlayerInternal {
true 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) => { Some(PlayerCommand::Play) => {
self.update(|state| { self.update(|state| {
state.status = PlayStatus::kPlayStatusPlay; state.status = PlayStatus::kPlayStatusPlay;
@ -249,7 +272,7 @@ impl PlayerInternal {
self.update(|state| { self.update(|state| {
state.status = PlayStatus::kPlayStatusPause; state.status = PlayStatus::kPlayStatusPause;
state.update_time = util::now_ms(); 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(); state.position_measured_at = util::now_ms();
true true
}); });
@ -286,6 +309,13 @@ impl PlayerInternal {
let buffer = apply_volume(self.state.lock().unwrap().volume, let buffer = apply_volume(self.state.lock().unwrap().volume,
&packet.data); &packet.data);
sink.write(&buffer).unwrap(); 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(vorbis::VorbisError::Hole)) => (),
Some(Err(e)) => panic!("Vorbis error {:?}", e), Some(Err(e)) => panic!("Vorbis error {:?}", e),