mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Fixes for PR #148
This commit is contained in:
parent
387c2598e0
commit
5974cf7f24
3 changed files with 59 additions and 111 deletions
|
@ -1,7 +1,3 @@
|
||||||
use self::softmixer::SoftMixer;
|
|
||||||
|
|
||||||
pub mod softmixer;
|
|
||||||
|
|
||||||
pub trait Mixer {
|
pub trait Mixer {
|
||||||
fn start(&self);
|
fn start(&self);
|
||||||
fn stop(&self);
|
fn stop(&self);
|
||||||
|
@ -16,8 +12,12 @@ pub trait AudioFilter {
|
||||||
fn modify_stream(&self, data: &mut [i16]);
|
fn modify_stream(&self, data: &mut [i16]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod softmixer;
|
||||||
|
use self::softmixer::SoftMixer;
|
||||||
|
|
||||||
pub fn find<T: AsRef<str>>(name: Option<T>) -> Option<Box<Mixer + Send>> {
|
pub fn find<T: AsRef<str>>(name: Option<T>) -> Option<Box<Mixer + Send>> {
|
||||||
match name {
|
match name.as_ref().map(AsRef::as_ref) {
|
||||||
_ => Some(Box::new(SoftMixer::new())),
|
None | Some("softvol") => Some(Box::new(SoftMixer::new())),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -72,8 +72,9 @@ enum PlayerCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
pub fn new<F>(session: Session, stream_editor: Option<Box<AudioFilter + Send>>, sink_builder: F) -> Player
|
pub fn new<F>(session: Session, audio_filter: Option<Box<AudioFilter + Send>>, sink_builder: F) -> Player
|
||||||
where F: FnOnce() -> Box<Sink> + Send + 'static {
|
where F: FnOnce() -> Box<Sink> + Send + 'static
|
||||||
|
{
|
||||||
let (cmd_tx, cmd_rx) = mpsc::channel();
|
let (cmd_tx, cmd_rx) = mpsc::channel();
|
||||||
|
|
||||||
let state = Arc::new(Mutex::new(PlayerState {
|
let state = Arc::new(Mutex::new(PlayerState {
|
||||||
|
@ -93,7 +94,7 @@ impl Player {
|
||||||
observers: observers.clone(),
|
observers: observers.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
thread::spawn(move || internal.run(sink_builder(), stream_editor));
|
thread::spawn(move || internal.run(sink_builder(), audio_filter));
|
||||||
|
|
||||||
Player {
|
Player {
|
||||||
commands: cmd_tx,
|
commands: cmd_tx,
|
||||||
|
@ -206,7 +207,7 @@ fn run_onstop(session: &Session) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlayerInternal {
|
impl PlayerInternal {
|
||||||
fn run(self, mut sink: Box<Sink>, stream_editor: Option<Box<AudioFilter + Send>>) {
|
fn run(self, mut sink: Box<Sink>, audio_filter: Option<Box<AudioFilter + Send>>) {
|
||||||
let mut decoder = None;
|
let mut decoder = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -341,7 +342,7 @@ impl PlayerInternal {
|
||||||
|
|
||||||
match packet {
|
match packet {
|
||||||
Some(Ok(mut packet)) => {
|
Some(Ok(mut packet)) => {
|
||||||
if let Some(ref editor) = stream_editor {
|
if let Some(ref editor) = audio_filter {
|
||||||
editor.modify_stream(&mut packet.data)
|
editor.modify_stream(&mut packet.data)
|
||||||
};
|
};
|
||||||
sink.write(&packet.data).unwrap();
|
sink.write(&packet.data).unwrap();
|
||||||
|
|
141
src/spirc.rs
141
src/spirc.rs
|
@ -44,53 +44,6 @@ struct SpircInternal {
|
||||||
devices: HashMap<String, String>,
|
devices: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct State {
|
|
||||||
pub status: PlayStatus,
|
|
||||||
pub position_ms: u32,
|
|
||||||
pub position_measured_at: i64,
|
|
||||||
pub update_time: i64,
|
|
||||||
pub volume: u16,
|
|
||||||
pub track: Option<SpotifyId>,
|
|
||||||
pub end_of_track: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
pub fn new() -> State {
|
|
||||||
let state = State {
|
|
||||||
status: PlayStatus::kPlayStatusStop,
|
|
||||||
position_ms: 0,
|
|
||||||
position_measured_at: 0,
|
|
||||||
update_time: 0,
|
|
||||||
volume: 0,
|
|
||||||
track: None,
|
|
||||||
end_of_track: false,
|
|
||||||
};
|
|
||||||
state.update_time()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_from_player(mut self, player: &Player) -> State {
|
|
||||||
let player_state = player.state();
|
|
||||||
let (position_ms, position_measured_at) = player_state.position();
|
|
||||||
self.status = player_state.status();
|
|
||||||
self.position_ms = position_ms;
|
|
||||||
self.position_measured_at = position_measured_at;
|
|
||||||
self.track = player_state.track;
|
|
||||||
self.end_of_track = player_state.end_of_track();
|
|
||||||
self.update_time()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_from_mixer(mut self, mixer: &Box<Mixer + Send>) -> State {
|
|
||||||
self.volume = mixer.volume();
|
|
||||||
self.update_time()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_time(mut self) -> State {
|
|
||||||
self.update_time = util::now_ms();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SpircManager {
|
impl SpircManager {
|
||||||
pub fn new(session: Session, player: Player, mixer: Box<Mixer + Send>) -> SpircManager {
|
pub fn new(session: Session, player: Player, mixer: Box<Mixer + Send>) -> SpircManager {
|
||||||
let ident = session.device_id().to_owned();
|
let ident = session.device_id().to_owned();
|
||||||
|
@ -340,11 +293,14 @@ impl SpircInternal {
|
||||||
cs.send();
|
cs.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spirc_state(&self, state: &State) -> protocol::spirc::State {
|
fn spirc_state(&self) -> protocol::spirc::State {
|
||||||
|
let player_state = self.player.state();
|
||||||
|
let (position_ms, position_measured_at) = player_state.position();
|
||||||
|
|
||||||
protobuf_init!(protocol::spirc::State::new(), {
|
protobuf_init!(protocol::spirc::State::new(), {
|
||||||
status: state.status,
|
status: player_state.status(),
|
||||||
position_ms: state.position_ms,
|
position_ms: position_ms,
|
||||||
position_measured_at: state.position_measured_at as u64,
|
position_measured_at: position_measured_at as u64,
|
||||||
|
|
||||||
playing_track_index: self.index,
|
playing_track_index: self.index,
|
||||||
track: self.tracks.iter().map(|track| {
|
track: self.tracks.iter().map(|track| {
|
||||||
|
@ -363,12 +319,12 @@ impl SpircInternal {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn device_state(&self, state: &State) -> protocol::spirc::DeviceState {
|
fn device_state(&self) -> protocol::spirc::DeviceState {
|
||||||
protobuf_init!(protocol::spirc::DeviceState::new(), {
|
protobuf_init!(protocol::spirc::DeviceState::new(), {
|
||||||
sw_version: version::version_string(),
|
sw_version: version::version_string(),
|
||||||
is_active: self.is_active,
|
is_active: self.is_active,
|
||||||
can_play: self.can_play,
|
can_play: self.can_play,
|
||||||
volume: state.volume as u32,
|
volume: self.mixer.volume() as u32,
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
error_code: 0,
|
error_code: 0,
|
||||||
became_active_at: if self.is_active { self.became_active_at as i64 } else { 0 },
|
became_active_at: if self.is_active { self.became_active_at as i64 } else { 0 },
|
||||||
|
@ -429,63 +385,54 @@ impl SpircInternal {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CommandSender<'a> {
|
struct CommandSender<'a> {
|
||||||
spirc_internal: &'a mut SpircInternal,
|
spirc: &'a mut SpircInternal,
|
||||||
cmd: MessageType,
|
frame: protocol::spirc::Frame,
|
||||||
recipient: Option<&'a str>,
|
|
||||||
state: Option<protocol::spirc::State>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CommandSender<'a> {
|
impl<'a> CommandSender<'a> {
|
||||||
fn new(spirc_internal: &'a mut SpircInternal, cmd: MessageType) -> CommandSender {
|
fn new(spirc: &'a mut SpircInternal, cmd: MessageType) -> CommandSender {
|
||||||
CommandSender {
|
let frame = protobuf_init!(protocol::spirc::Frame::new(), {
|
||||||
spirc_internal: spirc_internal,
|
|
||||||
cmd: cmd,
|
|
||||||
recipient: None,
|
|
||||||
state: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipient(mut self, r: &'a str) -> CommandSender {
|
|
||||||
self.recipient = Some(r);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state(mut self, s: protocol::spirc::State) -> CommandSender<'a> {
|
|
||||||
self.state = Some(s);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send(self) {
|
|
||||||
let state = State::new()
|
|
||||||
.update_from_player(&self.spirc_internal.player)
|
|
||||||
.update_from_mixer(&self.spirc_internal.mixer);
|
|
||||||
|
|
||||||
let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
|
|
||||||
version: 1,
|
version: 1,
|
||||||
ident: self.spirc_internal.ident.clone(),
|
|
||||||
protocol_version: "2.0.0",
|
protocol_version: "2.0.0",
|
||||||
seq_nr: { self.spirc_internal.seq_nr += 1; self.spirc_internal.seq_nr },
|
ident: spirc.ident.clone(),
|
||||||
typ: self.cmd,
|
seq_nr: { spirc.seq_nr += 1; spirc.seq_nr },
|
||||||
recipient: RepeatedField::from_vec(
|
typ: cmd,
|
||||||
self.recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![])
|
|
||||||
),
|
device_state: spirc.device_state(),
|
||||||
device_state: self.spirc_internal.device_state(&state),
|
state_update_id: util::now_ms(),
|
||||||
state_update_id: state.update_time
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.spirc_internal.is_active {
|
CommandSender {
|
||||||
pkt.set_state(self.spirc_internal.spirc_state(&state));
|
spirc: spirc,
|
||||||
|
frame: frame,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.spirc_internal
|
fn recipient(mut self, recipient: &'a str) -> CommandSender {
|
||||||
|
self.frame.mut_recipient().push(recipient.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state(mut self, state: protocol::spirc::State) -> CommandSender<'a> {
|
||||||
|
self.frame.set_state(state);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(mut self) {
|
||||||
|
if !self.frame.has_state() && self.spirc.is_active {
|
||||||
|
self.frame.set_state(self.spirc.spirc_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload = vec![self.frame.write_to_bytes().unwrap()];
|
||||||
|
|
||||||
|
self.spirc
|
||||||
.session
|
.session
|
||||||
.mercury(MercuryRequest {
|
.mercury(MercuryRequest {
|
||||||
method: MercuryMethod::SEND,
|
method: MercuryMethod::SEND,
|
||||||
uri: self.spirc_internal.uri(),
|
uri: self.spirc.uri(),
|
||||||
content_type: None,
|
content_type: None,
|
||||||
payload: vec![pkt.write_to_bytes().unwrap()],
|
payload: payload,
|
||||||
})
|
}).fire();
|
||||||
.fire();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue