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 player::Player;
use mercury::{MercuryRequest, MercuryMethod}; use mercury::{MercuryRequest, MercuryMethod};
use librespot_protocol as protocol; use librespot_protocol as protocol;
use librespot_protocol::spirc::PlayStatus;
fn main() { fn main() {
let mut args = std::env::args().skip(1); let mut args = std::env::args().skip(1);
@ -83,6 +84,8 @@ fn main() {
can_play: true, can_play: true,
is_active: false, is_active: false,
became_active_at: 0, became_active_at: 0,
state: PlayerState::new()
}.run(); }.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 { struct SpircManager {
session: Session, session: Session,
username: String, username: String,
@ -132,6 +217,8 @@ struct SpircManager {
can_play: bool, can_play: bool,
is_active: bool, is_active: bool,
became_active_at: i64, became_active_at: i64,
state: PlayerState
} }
impl SpircManager { impl SpircManager {
@ -140,7 +227,7 @@ impl SpircManager {
self.session.mercury.send(MercuryRequest{ self.session.mercury.send(MercuryRequest{
method: MercuryMethod::SUB, method: MercuryMethod::SUB,
uri: format!("hm://remote/user/{}/v23", self.username).to_string(), uri: format!("hm://remote/user/{}/v23", self.username),
content_type: None, content_type: None,
callback: Some(tx), callback: Some(tx),
payload: Vec::new() payload: Vec::new()
@ -148,23 +235,22 @@ impl SpircManager {
self.notify(None); self.notify(None);
for pkt in rx.iter() { let rx = rx.into_iter().map(|pkt| {
let frame : protocol::spirc::Frame = protobuf::parse_from_bytes::<protocol::spirc::Frame>(pkt.payload.front().unwrap()).unwrap()
protobuf::parse_from_bytes(pkt.payload.front().unwrap()).unwrap(); });
println!("{:?} {} {} {}", for frame in rx {
println!("{:?} {} {} {} {}",
frame.get_typ(), frame.get_typ(),
frame.get_device_state().get_name(), frame.get_device_state().get_name(),
frame.get_ident(), frame.get_ident(),
frame.get_device_state().get_became_active_at()); frame.get_seq_nr(),
frame.get_state_update_id());
if frame.get_ident() == self.ident || if frame.get_ident() != self.ident &&
(frame.get_recipient().len() > 0 && (frame.get_recipient().len() == 0 ||
!frame.get_recipient().contains(&self.ident)) { frame.get_recipient().contains(&self.ident)) {
continue; self.handle(frame);
} }
self.handle(frame);
} }
} }
@ -175,37 +261,79 @@ impl SpircManager {
} }
protocol::spirc::MessageType::kMessageTypeLoad => { protocol::spirc::MessageType::kMessageTypeLoad => {
self.is_active = true; self.is_active = true;
self.became_active_at = { self.became_active_at = SpircManager::now();
let ts = time::now_utc().to_timespec();
ts.sec * 1000 + ts.nsec as i64 / 1000000 self.state.import(frame.get_state());
};
println!("{:?} {}", frame, self.became_active_at); self.state.last_command_ident = frame.get_ident().to_string();
self.notify(None) 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>) { 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{ self.session.mercury.send(MercuryRequest{
method: MercuryMethod::SEND, method: MercuryMethod::SEND,
uri: format!("hm://remote/user/{}", self.username).to_string(), uri: format!("hm://remote/user/{}", self.username),
content_type: None, content_type: None,
callback: None, callback: None,
payload: vec![ payload: vec![ pkt.write_to_bytes().unwrap() ]
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()
]
}).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
}
} }