From 12643948381151a27495d94f1c59a823ba2eb604 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Thu, 9 Jul 2015 21:08:14 +0100 Subject: [PATCH] Add a SpircDelegate abstraction. --- src/lib.rs | 2 +- src/main.rs | 2 +- src/player.rs | 88 +++++++++++++++++++++++++++++++++++++++------------ src/spirc.rs | 74 ++++++++++++++++++++++++++++--------------- 4 files changed, 117 insertions(+), 49 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 915227b1..4c9f2264 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ #![feature(plugin,scoped,zero_one,iter_arith,slice_position_elem,slice_bytes,bitset,arc_weak,append,future)] #![allow(deprecated)] -#![allow(unused_imports,dead_code)] +//#![allow(unused_imports,dead_code)] #![plugin(protobuf_macros)] #[macro_use] extern crate lazy_static; diff --git a/src/main.rs b/src/main.rs index ec2fea1c..638f6e8f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,7 @@ fn main() { let player = Player::new(&session); - let mut spirc_manager = SpircManager::new(&session, &player, username, name); + let mut spirc_manager = SpircManager::new(&session, player, username, name); spirc_manager.run(); poll_thread.join(); diff --git a/src/player.rs b/src/player.rs index 2cba53ea..b9c1713e 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,28 +1,28 @@ use portaudio; use vorbis; -use std::sync::{mpsc, Mutex, Arc, Condvar}; +use std::sync::{mpsc, Mutex, Arc, Condvar, MutexGuard}; use std::thread; use metadata::TrackRef; use session::Session; -use audio_file::AudioFile; use audio_decrypt::AudioDecrypt; use util::{self, SpotifyId, Subfile}; -use librespot_protocol::spirc::PlayStatus; +use spirc::{SpircState, SpircDelegate, PlayStatus}; -pub enum PlayerCommand { - Load(SpotifyId, bool, u32), - Play, - Pause, - Stop, - Seek(u32) +pub struct Player<'s> { + state: Arc<(Mutex, Condvar)>, + + commands: mpsc::Sender, + + #[allow(dead_code)] + thread: thread::JoinGuard<'s, ()>, } pub struct PlayerState { - pub status: PlayStatus, - pub position_ms: u32, - pub position_measured_at: i64, - pub update_time: i64 + status: PlayStatus, + position_ms: u32, + position_measured_at: i64, + update_time: i64 } struct PlayerInternal<'s> { @@ -32,13 +32,12 @@ struct PlayerInternal<'s> { commands: mpsc::Receiver, } -pub struct Player<'s> { - pub state: Arc<(Mutex, Condvar)>, - - commands: mpsc::Sender, - - #[allow(dead_code)] - thread: thread::JoinGuard<'s, ()>, +enum PlayerCommand { + Load(SpotifyId, bool, u32), + Play, + Pause, + Stop, + Seek(u32) } impl <'s> Player<'s> { @@ -67,7 +66,7 @@ impl <'s> Player<'s> { } } - pub fn command(&self, cmd: PlayerCommand) { + fn command(&self, cmd: PlayerCommand) { self.commands.send(cmd).unwrap(); } } @@ -183,4 +182,51 @@ impl <'s> PlayerInternal<'s> { } } +impl <'s> SpircDelegate for Player<'s> { + type State = PlayerState; + + fn load(&self, track: SpotifyId, + start_playing: bool, position_ms: u32) { + self.command(PlayerCommand::Load(track, start_playing, position_ms)); + } + + fn play(&self) { + self.command(PlayerCommand::Play) + } + + fn pause(&self) { + self.command(PlayerCommand::Pause) + } + + fn stop(&self) { + self.command(PlayerCommand::Stop) + } + + fn seek(&self, position_ms: u32) { + self.command(PlayerCommand::Seek(position_ms)); + } + + fn state(&self) -> MutexGuard { + self.state.0.lock().unwrap() + } + + fn wait_update<'a>(&'a self, guard: MutexGuard<'a, Self::State>) + -> MutexGuard<'a, Self::State> { + self.state.1.wait(guard).unwrap() + } +} + +impl SpircState for PlayerState { + fn status(&self) -> PlayStatus { + return self.status; + } + + fn position(&self) -> (u32, i64) { + return (self.position_ms, self.position_measured_at); + } + + fn update_time(&self) -> i64 { + return self.update_time; + } +} diff --git a/src/spirc.rs b/src/spirc.rs index adcfce75..c60400d3 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -1,18 +1,17 @@ - use protobuf::{self, Message}; use util; -use session::{Config, Session}; +use session::Session; use util::SpotifyId; use util::version::version_string; -use player::{Player, PlayerCommand}; use mercury::{MercuryRequest, MercuryMethod}; +use std::sync::MutexGuard; use librespot_protocol as protocol; -use librespot_protocol::spirc::PlayStatus; +pub use librespot_protocol::spirc::PlayStatus; -pub struct SpircManager<'s> { - player: &'s Player<'s>, +pub struct SpircManager<'s, D: SpircDelegate> { + delegate: D, session: &'s Session, username: String, @@ -37,11 +36,33 @@ pub struct SpircManager<'s> { track: Option } -impl <'s> SpircManager<'s> { - pub fn new(session: &'s Session, player: &'s Player<'s>, username: String, name: String) -> SpircManager<'s> { +pub trait SpircDelegate { + type State : SpircState; + + fn load(&self, track: SpotifyId, + start_playing: bool, position_ms: u32); + fn play(&self); + fn pause(&self); + fn seek(&self, position_ms: u32); + fn stop(&self); + + fn state(&self) -> MutexGuard; + fn wait_update<'a>(&'a self, guard: MutexGuard<'a, Self::State>) + -> MutexGuard<'a, Self::State>; +} + +pub trait SpircState { + fn status(&self) -> PlayStatus; + fn position(&self) -> (u32, i64); + fn update_time(&self) -> i64; +} + +impl <'s, D: SpircDelegate> SpircManager<'s, D> { + pub fn new(session: &'s Session, delegate: D, + username: String, name: String) -> SpircManager<'s, D> { SpircManager { + delegate: delegate, session: &session, - player: &player, username: username.clone(), state_update_id: 0, @@ -88,10 +109,11 @@ impl <'s> SpircManager<'s> { } } - let h = self.player.state.0.lock().unwrap(); - if h.update_time > self.state_update_id { + if { + let state = self.delegate.state(); + state.update_time() > self.state_update_id + } { self.state_update_id = util::now_ms(); - drop(h); self.notify(None); } } @@ -114,24 +136,23 @@ impl <'s> SpircManager<'s> { let index = frame.get_state().get_playing_track_index() as usize; let track = SpotifyId::from_raw(frame.get_state().get_track()[index].get_gid()); + let play = frame.get_state().get_status() == PlayStatus::kPlayStatusPlay; self.track = Some(track); - self.player.command(PlayerCommand::Load(track, - frame.get_state().get_status() == PlayStatus::kPlayStatusPlay, - frame.get_state().get_position_ms())); + self.delegate.load(track, play, frame.get_state().get_position_ms()); } protocol::spirc::MessageType::kMessageTypePlay => { - self.player.command(PlayerCommand::Play); + self.delegate.play(); } protocol::spirc::MessageType::kMessageTypePause => { - self.player.command(PlayerCommand::Pause); + self.delegate.pause(); } protocol::spirc::MessageType::kMessageTypeSeek => { - self.player.command(PlayerCommand::Seek(frame.get_position())); + self.delegate.seek(frame.get_position()); } protocol::spirc::MessageType::kMessageTypeNotify => { if self.is_active && frame.get_device_state().get_is_active() { self.is_active = false; - self.player.command(PlayerCommand::Stop); + self.delegate.stop(); } } _ => () @@ -153,7 +174,7 @@ impl <'s> SpircManager<'s> { }); if self.is_active { - pkt.set_state(self.state()); + pkt.set_state(self.spirc_state()); } self.session.mercury(MercuryRequest{ @@ -164,13 +185,14 @@ impl <'s> SpircManager<'s> { }); } - fn state(&mut self) -> protocol::spirc::State { - let state = self.player.state.0.lock().unwrap(); + fn spirc_state(&self) -> protocol::spirc::State { + let state = self.delegate.state(); + let (position_ms, position_measured_at) = state.position(); protobuf_init!(protocol::spirc::State::new(), { - status: state.status, - position_ms: state.position_ms, - position_measured_at: state.position_measured_at as u64, + status: state.status(), + position_ms: position_ms, + position_measured_at: position_measured_at as u64, playing_track_index: 0, track => [ @@ -189,7 +211,7 @@ impl <'s> SpircManager<'s> { }) } - fn device_state(&mut self) -> protocol::spirc::DeviceState { + fn device_state(&self) -> protocol::spirc::DeviceState { protobuf_init!(protocol::spirc::DeviceState::new(), { sw_version: version_string(), is_active: self.is_active,