Browse Source

Add a SpircDelegate abstraction.

Paul Lietar 9 years ago
parent
commit
1264394838
4 changed files with 117 additions and 49 deletions
  1. 1 1
      src/lib.rs
  2. 1 1
      src/main.rs
  3. 67 21
      src/player.rs
  4. 48 26
      src/spirc.rs

+ 1 - 1
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;

+ 1 - 1
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();

+ 67 - 21
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<PlayerState>, Condvar)>,
+
+    commands: mpsc::Sender<PlayerCommand>,
+
+    #[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<PlayerCommand>,
 }
 
-pub struct Player<'s> {
-    pub state: Arc<(Mutex<PlayerState>, Condvar)>,
-
-    commands: mpsc::Sender<PlayerCommand>,
-
-    #[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> {
+        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;
+    }
+}
 

+ 48 - 26
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<SpotifyId>
 }
 
-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<Self::State>;
+    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,