mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Add a SpircDelegate abstraction.
This commit is contained in:
parent
cdd939e88e
commit
1264394838
4 changed files with 117 additions and 49 deletions
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
74
src/spirc.rs
74
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,
|
||||
|
|
Loading…
Reference in a new issue