spirc: Keep track of player status

This commit is contained in:
Paul Lietar 2015-07-02 13:54:34 +02:00
parent df11960946
commit c1ce87dbbd

View file

@ -48,6 +48,7 @@ use util::version::version_string;
use player::Player;
use mercury::{MercuryRequest, MercuryMethod};
use librespot_protocol as protocol;
use librespot_protocol::spirc::PlayStatus;
fn main() {
let mut args = std::env::args().skip(1);
@ -83,6 +84,8 @@ fn main() {
can_play: true,
is_active: false,
became_active_at: 0,
state: PlayerState::new()
}.run();
/*
@ -118,6 +121,88 @@ fn print_track(cache: &mut MetadataCache, track_id: SpotifyId) {
}
}
struct PlayerState {
status: PlayStatus,
context_uri: String,
index: u32,
queue: Vec<SpotifyId>,
repeat: bool,
shuffle: bool,
position_ms: u32,
position_measured_at: i64,
last_command_ident: String,
last_command_msgid: u32,
}
impl PlayerState {
fn new() -> PlayerState {
PlayerState {
status: PlayStatus::kPlayStatusPause,
context_uri: String::new(),
index: 0,
queue: Vec::new(),
repeat: false,
shuffle: false,
position_ms: 0,
position_measured_at: 0,
last_command_ident: String::new(),
last_command_msgid: 0
}
}
fn import(&mut self, state: &protocol::spirc::State) {
//println!("{:?}", state);
self.status = state.get_status();
self.context_uri = state.get_context_uri().to_string();
self.index = state.get_playing_track_index();
self.queue = state.get_track().iter().filter(|t| {
t.has_gid()
}).map(|t| {
SpotifyId::from_raw(t.get_gid())
}).collect();
self.repeat = state.get_repeat();
self.shuffle = state.get_shuffle();
self.position_ms = state.get_position_ms();
self.position_measured_at = SpircManager::now();
}
fn export(&self) -> protocol::spirc::State {
protobuf_init!(protocol::spirc::State::new(), {
status: self.status,
context_uri: self.context_uri.to_string(),
playing_track_index: self.index,
track: self.queue.iter().map(|t| {
protobuf_init!(protocol::spirc::TrackRef::new(), {
gid: t.to_raw().to_vec()
})
}).collect(),
shuffle: self.shuffle,
repeat: self.repeat,
position_ms: self.position_ms,
position_measured_at: self.position_measured_at as u64,
playing_from_fallback: true,
last_command_ident: self.last_command_ident.clone(),
last_command_msgid: self.last_command_msgid
})
}
}
struct SpircManager {
session: Session,
username: String,
@ -132,6 +217,8 @@ struct SpircManager {
can_play: bool,
is_active: bool,
became_active_at: i64,
state: PlayerState
}
impl SpircManager {
@ -140,7 +227,7 @@ impl SpircManager {
self.session.mercury.send(MercuryRequest{
method: MercuryMethod::SUB,
uri: format!("hm://remote/user/{}/v23", self.username).to_string(),
uri: format!("hm://remote/user/{}/v23", self.username),
content_type: None,
callback: Some(tx),
payload: Vec::new()
@ -148,23 +235,22 @@ impl SpircManager {
self.notify(None);
for pkt in rx.iter() {
let frame : protocol::spirc::Frame =
protobuf::parse_from_bytes(pkt.payload.front().unwrap()).unwrap();
println!("{:?} {} {} {}",
let rx = rx.into_iter().map(|pkt| {
protobuf::parse_from_bytes::<protocol::spirc::Frame>(pkt.payload.front().unwrap()).unwrap()
});
for frame in rx {
println!("{:?} {} {} {} {}",
frame.get_typ(),
frame.get_device_state().get_name(),
frame.get_ident(),
frame.get_device_state().get_became_active_at());
if frame.get_ident() == self.ident ||
(frame.get_recipient().len() > 0 &&
!frame.get_recipient().contains(&self.ident)) {
continue;
}
self.handle(frame);
frame.get_seq_nr(),
frame.get_state_update_id());
if frame.get_ident() != self.ident &&
(frame.get_recipient().len() == 0 ||
frame.get_recipient().contains(&self.ident)) {
self.handle(frame);
}
}
}
@ -175,37 +261,79 @@ impl SpircManager {
}
protocol::spirc::MessageType::kMessageTypeLoad => {
self.is_active = true;
self.became_active_at = {
let ts = time::now_utc().to_timespec();
ts.sec * 1000 + ts.nsec as i64 / 1000000
};
println!("{:?} {}", frame, self.became_active_at);
self.notify(None)
self.became_active_at = SpircManager::now();
self.state.import(frame.get_state());
self.state.last_command_ident = frame.get_ident().to_string();
self.state.last_command_msgid = frame.get_seq_nr();
self.state_update_id = SpircManager::now();
self.notify(None);
}
protocol::spirc::MessageType::kMessageTypePlay => {
self.state.status = PlayStatus::kPlayStatusPlay;
self.state.position_measured_at = SpircManager::now();
self.state.last_command_ident = frame.get_ident().to_string();
self.state.last_command_msgid = frame.get_seq_nr();
self.state_update_id = SpircManager::now();
self.notify(None);
}
protocol::spirc::MessageType::kMessageTypePause => {
self.state.status = PlayStatus::kPlayStatusPause;
self.state.position_measured_at = SpircManager::now();
self.state.last_command_ident = frame.get_ident().to_string();
self.state.last_command_msgid = frame.get_seq_nr();
self.state_update_id = SpircManager::now();
self.notify(None);
}
protocol::spirc::MessageType::kMessageTypeSeek => {
self.state.position_ms = frame.get_position();
self.state.position_measured_at = SpircManager::now();
self.state.last_command_ident = frame.get_ident().to_string();
self.state.last_command_msgid = frame.get_seq_nr();
self.state_update_id = SpircManager::now();
self.notify(None);
}
protocol::spirc::MessageType::kMessageTypeNotify => {
if frame.get_device_state().get_is_active() {
//println!("{:?}", frame.get_state());
}
}
_ => ()
}
}
fn notify(&mut self, recipient: Option<&str>) {
let device_state = self.device_state();
let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
version: 1,
ident: self.ident.clone(),
protocol_version: "2.0.0".to_string(),
seq_nr: { self.seq_nr += 1; self.seq_nr },
typ: protocol::spirc::MessageType::kMessageTypeNotify,
device_state: self.device_state(),
recipient: protobuf::RepeatedField::from_vec(
recipient.map(|r| vec![r.to_string()] ).unwrap_or(vec![])
),
state_update_id: self.state_update_id
});
if self.is_active {
pkt.set_state(self.state.export());
}
self.session.mercury.send(MercuryRequest{
method: MercuryMethod::SEND,
uri: format!("hm://remote/user/{}", self.username).to_string(),
uri: format!("hm://remote/user/{}", self.username),
content_type: None,
callback: None,
payload: vec![
protobuf_init!(protocol::spirc::Frame::new(), {
version: 1,
ident: self.ident.clone(),
protocol_version: "2.0.0".to_string(),
seq_nr: { self.seq_nr += 1; self.seq_nr },
typ: protocol::spirc::MessageType::kMessageTypeNotify,
device_state: device_state,
recipient: protobuf::RepeatedField::from_vec(
recipient.map(|r| vec![r.to_string()] ).unwrap_or(vec![])
)
}).write_to_bytes().unwrap()
]
payload: vec![ pkt.write_to_bytes().unwrap() ]
}).unwrap();
}
@ -268,5 +396,10 @@ impl SpircManager {
],
})
}
fn now() -> i64 {
let ts = time::now_utc().to_timespec();
ts.sec * 1000 + ts.nsec as i64 / 1000000
}
}