mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Remove mixer from Player and add it to SpircManager
This commit is contained in:
parent
347bf05dbe
commit
59398b3cee
5 changed files with 48 additions and 80 deletions
12
src/main.rs
12
src/main.rs
|
@ -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());
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
73
src/spirc.rs
73
src/spirc.rs
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue