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::session::{Bitrate, Config, Session};
use librespot::mixer::softmixer::SoftMixer;
use librespot::mixer::Mixer;
use librespot::version;
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();
opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
.reqopt("n", "name", "Device name", "NAME")
@ -124,18 +126,18 @@ fn setup(args: &[String]) -> (Session, Player) {
let mixer = SoftMixer::new();
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))
});
(session, player)
(session, player, Box::new(mixer))
}
fn main() {
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();
thread::spawn(move || spirc.run());

View file

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

View file

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

View file

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

View file

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