librespot/src/player.rs

341 lines
11 KiB
Rust
Raw Normal View History

use eventual::{self, Async};
2015-06-23 14:38:29 +00:00
use portaudio;
use std::borrow::Cow;
use std::sync::{mpsc, Mutex, Arc, MutexGuard};
use std::thread;
2015-09-01 11:20:37 +00:00
use vorbis;
2015-06-23 14:38:29 +00:00
2016-01-02 02:30:24 +00:00
use metadata::{FileFormat, Track, TrackRef};
use session::{Bitrate, Session};
2015-06-23 14:38:29 +00:00
use audio_decrypt::AudioDecrypt;
use util::{self, SpotifyId, Subfile};
2016-01-20 14:11:49 +00:00
use spirc::PlayStatus;
2015-06-23 14:38:29 +00:00
pub type PlayerObserver = Box<Fn(&PlayerState) + Send>;
2015-09-01 11:20:37 +00:00
pub struct Player {
state: Arc<Mutex<PlayerState>>,
observers: Arc<Mutex<Vec<PlayerObserver>>>,
2015-07-09 20:08:14 +00:00
commands: mpsc::Sender<PlayerCommand>,
}
2015-06-23 14:38:29 +00:00
#[derive(Clone)]
pub struct PlayerState {
2015-07-09 20:08:14 +00:00
status: PlayStatus,
position_ms: u32,
position_measured_at: i64,
update_time: i64,
2016-01-20 13:55:36 +00:00
volume: u16,
2016-01-02 15:19:39 +00:00
end_of_track: bool,
}
2015-06-23 14:38:29 +00:00
2015-09-01 11:20:37 +00:00
struct PlayerInternal {
state: Arc<Mutex<PlayerState>>,
observers: Arc<Mutex<Vec<PlayerObserver>>>,
2015-09-01 11:20:37 +00:00
session: Session,
commands: mpsc::Receiver<PlayerCommand>,
}
#[derive(Debug)]
2015-07-09 20:08:14 +00:00
enum PlayerCommand {
Load(SpotifyId, bool, u32),
Play,
Pause,
2016-01-20 13:55:36 +00:00
Volume(u16),
2015-07-09 20:08:14 +00:00
Stop,
2016-01-02 15:19:39 +00:00
Seek(u32),
}
2015-09-01 11:20:37 +00:00
impl Player {
2016-01-01 23:16:12 +00:00
pub fn new(session: Session) -> Player {
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: 0xFFFF,
end_of_track: false,
}));
let observers = Arc::new(Mutex::new(Vec::new()));
let internal = PlayerInternal {
2016-01-01 23:16:12 +00:00
session: session,
commands: cmd_rx,
2016-01-02 15:19:39 +00:00
state: state.clone(),
observers: observers.clone(),
};
2016-01-02 15:19:39 +00:00
thread::spawn(move || internal.run());
2015-09-01 11:20:37 +00:00
Player {
commands: cmd_tx,
state: state,
observers: observers,
}
}
2015-07-09 20:08:14 +00:00
fn command(&self, cmd: PlayerCommand) {
self.commands.send(cmd).unwrap();
}
2016-01-20 14:11:49 +00:00
pub fn load(&self, track: SpotifyId, start_playing: bool, position_ms: u32) {
self.command(PlayerCommand::Load(track, start_playing, position_ms));
}
pub fn play(&self) {
self.command(PlayerCommand::Play)
}
pub fn pause(&self) {
self.command(PlayerCommand::Pause)
}
pub fn stop(&self) {
self.command(PlayerCommand::Stop)
}
pub fn seek(&self, position_ms: u32) {
self.command(PlayerCommand::Seek(position_ms));
}
pub fn state(&self) -> PlayerState {
self.state.lock().unwrap().clone()
2016-01-20 14:11:49 +00:00
}
pub fn volume(&self, vol: u16) {
self.command(PlayerCommand::Volume(vol));
}
pub fn add_observer(&self, observer: PlayerObserver) {
self.observers.lock().unwrap().push(observer);
2016-01-20 14:11:49 +00:00
}
}
2015-06-23 14:38:29 +00:00
fn apply_volume(volume: u16, data: &[i16]) -> Cow<[i16]> {
// Fast path when volume is 100%
if volume == 0xFFFF {
Cow::Borrowed(data)
} else {
Cow::Owned(data.iter()
.map(|&x| {
(x as i32
* volume as i32
/ 0xFFFF) as i16
})
.collect())
}
}
2015-09-01 11:20:37 +00:00
impl PlayerInternal {
fn run(self) {
2015-06-23 14:38:29 +00:00
portaudio::initialize().unwrap();
2015-12-18 18:01:25 +00:00
let stream = portaudio::stream::Stream::<i16, i16>::open_default(
2015-07-09 21:04:19 +00:00
0, 2, 44100.0,
2015-06-23 14:38:29 +00:00
portaudio::stream::FRAMES_PER_BUFFER_UNSPECIFIED,
None
2015-07-09 21:04:19 +00:00
).unwrap();
let mut decoder = None;
loop {
let playing = self.state.lock().unwrap().status == PlayStatus::kPlayStatusPlay;
2016-01-01 23:16:12 +00:00
let cmd = if playing {
self.commands.try_recv().ok()
} else {
Some(self.commands.recv().unwrap())
};
match cmd {
Some(PlayerCommand::Load(track_id, play, position)) => {
2015-07-09 21:04:19 +00:00
self.update(|state| {
if state.status == PlayStatus::kPlayStatusPlay {
stream.stop().unwrap();
}
state.end_of_track = false;
state.status = PlayStatus::kPlayStatusPause;
2015-07-09 21:04:19 +00:00
state.position_ms = position;
state.position_measured_at = util::now_ms();
2016-01-02 15:48:44 +00:00
true
2015-07-09 21:04:19 +00:00
});
drop(decoder);
let mut track = self.session.metadata::<Track>(track_id).await().unwrap();
if !track.available {
2016-01-02 15:19:39 +00:00
let alternatives = track.alternatives
.iter()
.map(|alt_id| {
self.session.metadata::<Track>(*alt_id)
})
.collect::<Vec<TrackRef>>();
track = eventual::sequence(alternatives.into_iter())
.iter()
.find(|alt| alt.available)
.unwrap();
}
2015-09-01 11:20:37 +00:00
let format = match self.session.config().bitrate {
2016-01-02 02:30:24 +00:00
Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96,
Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160,
Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320,
};
let (file_id, _) = track.files.into_iter().find(|&(_, f)| f == format).unwrap();
let key = self.session.audio_key(track.id, file_id).await().unwrap();
decoder = Some(
vorbis::Decoder::new(
Subfile::new(
AudioDecrypt::new(key,
2015-07-03 00:23:49 +00:00
self.session.audio_file(file_id)), 0xa7)).unwrap());
decoder.as_mut().unwrap().time_seek(position as f64 / 1000f64).unwrap();
2015-07-09 21:04:19 +00:00
self.update(|state| {
state.status = if play {
stream.start().unwrap();
PlayStatus::kPlayStatusPlay
} else {
PlayStatus::kPlayStatusPause
};
state.position_ms = position;
state.position_measured_at = util::now_ms();
2016-01-02 15:48:44 +00:00
true
2015-07-09 21:04:19 +00:00
});
println!("Load Done");
}
Some(PlayerCommand::Seek(ms)) => {
decoder.as_mut().unwrap().time_seek(ms as f64 / 1000f64).unwrap();
2015-07-09 21:04:19 +00:00
self.update(|state| {
2016-01-02 15:19:39 +00:00
state.position_ms =
(decoder.as_mut().unwrap().time_tell().unwrap() * 1000f64) as u32;
2015-07-09 21:04:19 +00:00
state.position_measured_at = util::now_ms();
2016-01-02 15:48:44 +00:00
true
2015-07-09 21:04:19 +00:00
});
2016-01-02 15:19:39 +00:00
}
Some(PlayerCommand::Play) => {
2015-07-09 21:04:19 +00:00
self.update(|state| {
state.status = PlayStatus::kPlayStatusPlay;
state.position_ms =
(decoder.as_mut().unwrap().time_tell().unwrap() * 1000f64) as u32;
state.position_measured_at = util::now_ms();
2016-01-02 15:48:44 +00:00
true
2015-07-09 21:04:19 +00:00
});
stream.start().unwrap();
2016-01-02 15:19:39 +00:00
}
Some(PlayerCommand::Pause) => {
2015-07-09 21:04:19 +00:00
self.update(|state| {
state.status = PlayStatus::kPlayStatusPause;
state.update_time = util::now_ms();
state.position_ms =
(decoder.as_mut().unwrap().time_tell().unwrap() * 1000f64) as u32;
state.position_measured_at = util::now_ms();
2016-01-02 15:48:44 +00:00
true
2015-07-09 21:04:19 +00:00
});
stream.stop().unwrap();
2016-01-02 15:19:39 +00:00
}
2016-01-20 13:55:36 +00:00
Some(PlayerCommand::Volume(vol)) => {
self.update(|state| {
state.volume = vol;
true
});
}
Some(PlayerCommand::Stop) => {
2015-07-09 21:04:19 +00:00
self.update(|state| {
if state.status == PlayStatus::kPlayStatusPlay {
state.status = PlayStatus::kPlayStatusPause;
}
state.position_ms = 0;
state.position_measured_at = util::now_ms();
2016-01-02 15:48:44 +00:00
true
2015-07-09 21:04:19 +00:00
});
2015-07-09 21:04:19 +00:00
stream.stop().unwrap();
decoder = None;
2016-01-02 15:19:39 +00:00
}
None => (),
}
if self.state.lock().unwrap().status == PlayStatus::kPlayStatusPlay {
2015-07-09 21:32:40 +00:00
match decoder.as_mut().unwrap().packets().next() {
Some(Ok(packet)) => {
let buffer = apply_volume(self.state.lock().unwrap().volume,
&packet.data);
2016-01-20 13:55:36 +00:00
match stream.write(&buffer) {
Ok(_) => (),
2016-01-02 15:19:39 +00:00
Err(portaudio::PaError::OutputUnderflowed) => eprintln!("Underflow"),
Err(e) => panic!("PA Error {}", e),
};
2016-01-02 15:19:39 +00:00
}
2015-07-09 21:32:40 +00:00
Some(Err(vorbis::VorbisError::Hole)) => (),
Some(Err(e)) => panic!("Vorbis error {:?}", e),
None => {
self.update(|state| {
state.status = PlayStatus::kPlayStatusStop;
state.end_of_track = true;
2016-01-02 15:48:44 +00:00
true
2015-07-09 21:32:40 +00:00
});
stream.stop().unwrap();
decoder = None;
}
}
2015-06-23 14:38:29 +00:00
}
}
drop(stream);
portaudio::terminate().unwrap();
}
2015-07-09 21:04:19 +00:00
fn update<F>(&self, f: F)
2016-01-02 15:19:39 +00:00
where F: FnOnce(&mut MutexGuard<PlayerState>) -> bool
{
let mut guard = self.state.lock().unwrap();
2015-07-09 21:04:19 +00:00
let update = f(&mut guard);
let observers = self.observers.lock().unwrap();
2015-07-09 21:04:19 +00:00
if update {
guard.update_time = util::now_ms();
let state = guard.clone();
drop(guard);
for observer in observers.iter() {
observer(&state);
}
2015-07-09 21:04:19 +00:00
}
}
2015-06-23 14:38:29 +00:00
}
2016-01-20 14:11:49 +00:00
impl PlayerState {
pub fn status(&self) -> PlayStatus {
2016-01-02 15:48:44 +00:00
self.status
2015-07-09 20:08:14 +00:00
}
2016-01-20 14:11:49 +00:00
pub fn position(&self) -> (u32, i64) {
2016-01-02 15:48:44 +00:00
(self.position_ms, self.position_measured_at)
2015-07-09 20:08:14 +00:00
}
2016-01-20 13:55:36 +00:00
2016-01-20 14:11:49 +00:00
pub fn volume(&self) -> u16 {
2016-01-20 13:55:36 +00:00
self.volume
}
2015-07-09 20:08:14 +00:00
2016-01-20 14:11:49 +00:00
pub fn update_time(&self) -> i64 {
2016-01-02 15:48:44 +00:00
self.update_time
2015-07-09 20:08:14 +00:00
}
2016-01-20 14:11:49 +00:00
pub fn end_of_track(&self) -> bool {
2016-01-02 15:48:44 +00:00
self.end_of_track
}
2015-07-09 20:08:14 +00:00
}