Remove mixer from Player and add it to SpircManager

This commit is contained in:
Daniel Romero 2017-01-25 22:09:03 +01:00
parent 347bf05dbe
commit 59398b3cee
5 changed files with 48 additions and 80 deletions

View file

@ -19,6 +19,8 @@ use librespot::cache::{Cache, DefaultCache, NoCache};
use librespot::player::Player; use librespot::player::Player;
use librespot::session::{Bitrate, Config, Session}; use librespot::session::{Bitrate, Config, Session};
use librespot::mixer::softmixer::SoftMixer; use librespot::mixer::softmixer::SoftMixer;
use librespot::mixer::Mixer;
use librespot::version; use librespot::version;
fn usage(program: &str, opts: &getopts::Options) -> String { fn usage(program: &str, opts: &getopts::Options) -> String {
@ -60,7 +62,7 @@ fn list_backends() {
} }
} }
fn setup(args: &[String]) -> (Session, Player) { fn setup(args: &[String]) -> (Session, Player, Box<Mixer + Send>) {
let mut opts = getopts::Options::new(); let mut opts = getopts::Options::new();
opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE") opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
.reqopt("n", "name", "Device name", "NAME") .reqopt("n", "name", "Device name", "NAME")
@ -124,18 +126,18 @@ fn setup(args: &[String]) -> (Session, Player) {
let mixer = SoftMixer::new(); let mixer = SoftMixer::new();
let device_name = matches.opt_str("device"); let device_name = matches.opt_str("device");
let player = Player::new(session.clone(), Box::new(mixer), move || { let player = Player::new(session.clone(), move || {
(backend)(device_name.as_ref().map(AsRef::as_ref)) (backend)(device_name.as_ref().map(AsRef::as_ref))
}); });
(session, player) (session, player, Box::new(mixer))
} }
fn main() { fn main() {
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
let (session, player) = setup(&args); let (session, player, mixer) = setup(&args);
let spirc = SpircManager::new(session.clone(), player); let spirc = SpircManager::new(session.clone(), player, mixer);
let spirc_signal = spirc.clone(); let spirc_signal = spirc.clone();
thread::spawn(move || spirc.run()); thread::spawn(move || spirc.run());

View file

@ -6,7 +6,7 @@ pub trait Mixer {
fn init(&mut self); fn init(&mut self);
fn inuse(&mut self); fn inuse(&mut self);
fn release(&mut self); fn release(&mut self);
fn set(&mut self, volume: u16); fn set_volume(&mut self, volume: u16);
fn volume(&self) -> u16; fn volume(&self) -> u16;
fn apply_volume<'a>(&mut self, data: &'a [i16]) -> Cow<'a, [i16]> { fn apply_volume<'a>(&mut self, data: &'a [i16]) -> Cow<'a, [i16]> {
Cow::Borrowed(data) Cow::Borrowed(data)

View file

@ -23,7 +23,7 @@ impl Mixer for SoftMixer {
fn release(&mut self) { fn release(&mut self) {
} }
fn set(&mut self, volume: u16) { fn set_volume(&mut self, volume: u16) {
self.volume = volume; self.volume = volume;
} }

View file

@ -7,7 +7,6 @@ use vorbis;
use audio_decrypt::AudioDecrypt; use audio_decrypt::AudioDecrypt;
use audio_backend::Sink; use audio_backend::Sink;
use mixer::Mixer;
use metadata::{FileFormat, Track, TrackRef}; use metadata::{FileFormat, Track, TrackRef};
use session::{Bitrate, Session}; use session::{Bitrate, Session};
use util::{self, ReadSeek, SpotifyId, Subfile}; use util::{self, ReadSeek, SpotifyId, Subfile};
@ -48,8 +47,6 @@ pub struct PlayerState {
pub status: PlayStatus, pub status: PlayStatus,
pub position_ms: u32, pub position_ms: u32,
pub position_measured_at: i64, pub position_measured_at: i64,
pub update_time: i64,
pub volume: u16,
pub track: Option<SpotifyId>, pub track: Option<SpotifyId>,
pub end_of_track: bool, pub end_of_track: bool,
@ -68,24 +65,20 @@ enum PlayerCommand {
Load(SpotifyId, bool, u32), Load(SpotifyId, bool, u32),
Play, Play,
Pause, Pause,
Volume(u16),
Stop, Stop,
Seek(u32), Seek(u32),
SeekAt(u32, i64), SeekAt(u32, i64),
} }
impl Player { impl Player {
pub fn new<F, M>(session: Session, mixer: Box<M>, sink_builder: F) -> Player pub fn new<F>(session: Session, sink_builder: F) -> Player
where F: FnOnce() -> Box<Sink> + Send + 'static, where F: FnOnce() -> Box<Sink> + Send + 'static {
M: Mixer + 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 {
status: PlayStatus::kPlayStatusStop, status: PlayStatus::kPlayStatusStop,
position_ms: 0, position_ms: 0,
position_measured_at: 0, position_measured_at: 0,
update_time: util::now_ms(),
volume: mixer.volume(),
track: None, track: None,
end_of_track: false, end_of_track: false,
})); }));
@ -99,7 +92,7 @@ impl Player {
observers: observers.clone(), observers: observers.clone(),
}; };
thread::spawn(move || internal.run(sink_builder(), mixer)); thread::spawn(move || internal.run(sink_builder()));
Player { Player {
commands: cmd_tx, commands: cmd_tx,
@ -140,10 +133,6 @@ impl Player {
self.state.lock().unwrap().clone() self.state.lock().unwrap().clone()
} }
pub fn volume(&self, vol: u16) {
self.command(PlayerCommand::Volume(vol));
}
pub fn add_observer(&self, observer: PlayerObserver) { pub fn add_observer(&self, observer: PlayerObserver) {
self.observers.lock().unwrap().push(observer); self.observers.lock().unwrap().push(observer);
} }
@ -216,7 +205,7 @@ fn run_onstop(session: &Session) {
} }
impl PlayerInternal { impl PlayerInternal {
fn run(self, mut sink: Box<Sink>, mut mixer: Box<Mixer>) { fn run(self, mut sink: Box<Sink>) {
let mut decoder = None; let mut decoder = None;
loop { loop {
@ -321,7 +310,6 @@ impl PlayerInternal {
Some(PlayerCommand::Pause) => { Some(PlayerCommand::Pause) => {
self.update(|state| { self.update(|state| {
state.status = PlayStatus::kPlayStatusPause; state.status = PlayStatus::kPlayStatusPause;
state.update_time = util::now_ms();
state.position_ms = decoder.as_mut().map(|d| vorbis_time_tell_ms(d).unwrap()).unwrap_or(0) as u32; state.position_ms = decoder.as_mut().map(|d| vorbis_time_tell_ms(d).unwrap()).unwrap_or(0) as u32;
state.position_measured_at = util::now_ms(); state.position_measured_at = util::now_ms();
true true
@ -330,13 +318,6 @@ impl PlayerInternal {
sink.stop().unwrap(); sink.stop().unwrap();
run_onstop(&self.session); run_onstop(&self.session);
} }
Some(PlayerCommand::Volume(vol)) => {
mixer.set(vol);
self.update(|state| {
state.volume = mixer.volume();
true
});
}
Some(PlayerCommand::Stop) => { Some(PlayerCommand::Stop) => {
self.update(|state| { self.update(|state| {
if state.status == PlayStatus::kPlayStatusPlay { if state.status == PlayStatus::kPlayStatusPlay {
@ -359,7 +340,8 @@ impl PlayerInternal {
match packet { match packet {
Some(Ok(packet)) => { Some(Ok(packet)) => {
let buffer = mixer.apply_volume(&packet.data); //let buffer = mixer.apply_volume(&packet.data);
let buffer = Cow::Borrowed(&packet.data);
sink.write(&buffer).unwrap(); sink.write(&buffer).unwrap();
self.update(|state| { self.update(|state| {
@ -395,7 +377,6 @@ impl PlayerInternal {
let observers = self.observers.lock().unwrap(); let observers = self.observers.lock().unwrap();
if update { if update {
guard.update_time = util::now_ms();
let state = guard.clone(); let state = guard.clone();
drop(guard); drop(guard);
@ -415,14 +396,6 @@ impl PlayerState {
(self.position_ms, self.position_measured_at) (self.position_ms, self.position_measured_at)
} }
pub fn volume(&self) -> u16 {
self.volume
}
pub fn update_time(&self) -> i64 {
self.update_time
}
pub fn end_of_track(&self) -> bool { pub fn end_of_track(&self) -> bool {
self.end_of_track self.end_of_track
} }

View file

@ -6,6 +6,7 @@ use std::collections::HashMap;
use mercury::{MercuryRequest, MercuryMethod}; use mercury::{MercuryRequest, MercuryMethod};
use player::{Player, PlayerState}; use player::{Player, PlayerState};
use mixer::Mixer;
use session::Session; use session::Session;
use util; use util;
use util::SpotifyId; use util::SpotifyId;
@ -20,6 +21,7 @@ pub struct SpircManager(Arc<Mutex<SpircInternal>>);
struct SpircInternal { struct SpircInternal {
player: Player, player: Player,
session: Session, session: Session,
mixer: Box<Mixer + Send>,
seq_nr: u32, seq_nr: u32,
@ -43,14 +45,26 @@ 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 SpircManager { impl SpircManager {
pub fn new(session: Session, player: Player) -> 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();
let name = session.config().device_name.clone(); let name = session.config().device_name.clone();
SpircManager(Arc::new(Mutex::new(SpircInternal { SpircManager(Arc::new(Mutex::new(SpircInternal {
player: player, player: player,
session: session, session: session,
mixer: mixer,
seq_nr: 0, seq_nr: 0,
@ -184,7 +198,7 @@ impl SpircInternal {
let track = self.tracks[self.index as usize]; let track = self.tracks[self.index as usize];
self.player.load(track, true, 0); self.player.load(track, true, 0);
} else { } else {
self.notify_with_player_state(false, None, player_state); self.notify(false, None);
} }
} }
@ -253,7 +267,7 @@ impl SpircInternal {
} }
} }
MessageType::kMessageTypeVolume => { MessageType::kMessageTypeVolume => {
self.player.volume(frame.get_volume() as u16); self.mixer.set_volume(frame.get_volume() as u16);
} }
MessageType::kMessageTypeGoodbye => { MessageType::kMessageTypeGoodbye => {
if frame.has_ident() { if frame.has_ident() {
@ -287,30 +301,11 @@ impl SpircInternal {
cs.send(); cs.send();
} }
fn notify_with_player_state(&mut self, fn spirc_state(&self, state: &State) -> protocol::spirc::State {
hello: bool,
recipient: Option<&str>,
player_state: &PlayerState) {
let mut cs = CommandSender::new(self,
if hello {
MessageType::kMessageTypeHello
} else {
MessageType::kMessageTypeNotify
})
.player_state(player_state);
if let Some(s) = recipient {
cs = cs.recipient(&s);
}
cs.send();
}
fn spirc_state(&self, player_state: &PlayerState) -> protocol::spirc::State {
let (position_ms, position_measured_at) = player_state.position();
protobuf_init!(protocol::spirc::State::new(), { protobuf_init!(protocol::spirc::State::new(), {
status: player_state.status(), status: state.status,
position_ms: position_ms, position_ms: state.position_ms,
position_measured_at: position_measured_at as u64, position_measured_at: state.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| {
@ -329,12 +324,12 @@ impl SpircInternal {
}) })
} }
fn device_state(&self, player_state: &PlayerState) -> protocol::spirc::DeviceState { fn device_state(&self, state: &State) -> 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: player_state.volume() as u32, volume: state.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 },
@ -398,7 +393,6 @@ struct CommandSender<'a> {
spirc_internal: &'a mut SpircInternal, spirc_internal: &'a mut SpircInternal,
cmd: MessageType, cmd: MessageType,
recipient: Option<&'a str>, recipient: Option<&'a str>,
player_state: Option<&'a PlayerState>,
state: Option<protocol::spirc::State>, state: Option<protocol::spirc::State>,
} }
@ -408,7 +402,6 @@ impl<'a> CommandSender<'a> {
spirc_internal: spirc_internal, spirc_internal: spirc_internal,
cmd: cmd, cmd: cmd,
recipient: None, recipient: None,
player_state: None,
state: None, state: None,
} }
} }
@ -418,21 +411,21 @@ impl<'a> CommandSender<'a> {
self self
} }
fn player_state(mut self, s: &'a PlayerState) -> CommandSender {
self.player_state = Some(s);
self
}
fn state(mut self, s: protocol::spirc::State) -> CommandSender<'a> { fn state(mut self, s: protocol::spirc::State) -> CommandSender<'a> {
self.state = Some(s); self.state = Some(s);
self self
} }
fn send(self) { fn send(self) {
let state = self.player_state.map_or_else(|| { //TODO: get data
Cow::Owned(self.spirc_internal.player.state()) let state = Cow::Owned(State {
}, |s| { status: PlayStatus::kPlayStatusStop,
Cow::Borrowed(s) position_ms: 0,
position_measured_at: 0,
update_time: util::now_ms(),
volume: 0,
track: None,
end_of_track: false,
}); });
let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), { let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
@ -445,7 +438,7 @@ impl<'a> CommandSender<'a> {
self.recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![]) self.recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![])
), ),
device_state: self.spirc_internal.device_state(&state), device_state: self.spirc_internal.device_state(&state),
state_update_id: state.update_time() state_update_id: state.update_time
}); });
if self.spirc_internal.is_active { if self.spirc_internal.is_active {