2015-12-28 16:47:53 +00:00
|
|
|
use eventual::{self, Async};
|
2015-06-23 14:38:29 +00:00
|
|
|
use portaudio;
|
2015-07-09 20:08:14 +00:00
|
|
|
use std::sync::{mpsc, Mutex, Arc, Condvar, MutexGuard};
|
2015-07-02 19:42:49 +00:00
|
|
|
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;
|
2015-07-02 19:42:49 +00:00
|
|
|
use util::{self, SpotifyId, Subfile};
|
2015-07-09 20:08:14 +00:00
|
|
|
use spirc::{SpircState, SpircDelegate, PlayStatus};
|
2015-06-23 14:38:29 +00:00
|
|
|
|
2015-09-01 11:20:37 +00:00
|
|
|
pub struct Player {
|
2015-07-09 20:08:14 +00:00
|
|
|
state: Arc<(Mutex<PlayerState>, Condvar)>,
|
|
|
|
|
|
|
|
commands: mpsc::Sender<PlayerCommand>,
|
2015-07-02 19:42:49 +00:00
|
|
|
}
|
2015-06-23 14:38:29 +00:00
|
|
|
|
2015-07-02 19:42:49 +00:00
|
|
|
pub struct PlayerState {
|
2015-07-09 20:08:14 +00:00
|
|
|
status: PlayStatus,
|
|
|
|
position_ms: u32,
|
|
|
|
position_measured_at: i64,
|
2015-07-09 22:09:40 +00:00
|
|
|
update_time: i64,
|
|
|
|
|
2016-01-02 15:19:39 +00:00
|
|
|
end_of_track: bool,
|
2015-07-02 19:42:49 +00:00
|
|
|
}
|
2015-06-23 14:38:29 +00:00
|
|
|
|
2015-09-01 11:20:37 +00:00
|
|
|
struct PlayerInternal {
|
2015-07-02 19:42:49 +00:00
|
|
|
state: Arc<(Mutex<PlayerState>, Condvar)>,
|
2015-09-01 11:20:37 +00:00
|
|
|
session: Session,
|
2015-07-02 19:42:49 +00:00
|
|
|
commands: mpsc::Receiver<PlayerCommand>,
|
|
|
|
}
|
|
|
|
|
2015-07-09 20:08:14 +00:00
|
|
|
enum PlayerCommand {
|
|
|
|
Load(SpotifyId, bool, u32),
|
|
|
|
Play,
|
|
|
|
Pause,
|
|
|
|
Stop,
|
2016-01-02 15:19:39 +00:00
|
|
|
Seek(u32),
|
2015-07-02 19:42:49 +00:00
|
|
|
}
|
|
|
|
|
2015-09-01 11:20:37 +00:00
|
|
|
impl Player {
|
2016-01-01 23:16:12 +00:00
|
|
|
pub fn new(session: Session) -> Player {
|
2015-07-02 19:42:49 +00:00
|
|
|
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(),
|
2015-07-09 22:09:40 +00:00
|
|
|
end_of_track: false,
|
2016-01-02 15:19:39 +00:00
|
|
|
}),
|
|
|
|
Condvar::new()));
|
2015-07-02 19:42:49 +00:00
|
|
|
|
|
|
|
let internal = PlayerInternal {
|
2016-01-01 23:16:12 +00:00
|
|
|
session: session,
|
2015-07-02 19:42:49 +00:00
|
|
|
commands: cmd_rx,
|
2016-01-02 15:19:39 +00:00
|
|
|
state: state.clone(),
|
2015-07-02 19:42:49 +00:00
|
|
|
};
|
|
|
|
|
2016-01-02 15:19:39 +00:00
|
|
|
thread::spawn(move || internal.run());
|
2015-09-01 11:20:37 +00:00
|
|
|
|
2015-07-02 19:42:49 +00:00
|
|
|
Player {
|
|
|
|
commands: cmd_tx,
|
|
|
|
state: state,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-09 20:08:14 +00:00
|
|
|
fn command(&self, cmd: PlayerCommand) {
|
2015-07-02 19:42:49 +00:00
|
|
|
self.commands.send(cmd).unwrap();
|
|
|
|
}
|
|
|
|
}
|
2015-06-23 14:38:29 +00:00
|
|
|
|
2015-09-01 11:20:37 +00:00
|
|
|
impl PlayerInternal {
|
2015-07-02 19:42:49 +00:00
|
|
|
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();
|
2015-07-02 19:42:49 +00:00
|
|
|
|
|
|
|
let mut decoder = None;
|
|
|
|
|
|
|
|
loop {
|
2016-01-01 23:16:12 +00:00
|
|
|
let playing = self.state.0.lock().unwrap().status == PlayStatus::kPlayStatusPlay;
|
|
|
|
let cmd = if playing {
|
2015-12-28 17:45:13 +00:00
|
|
|
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();
|
|
|
|
}
|
2015-07-09 22:09:40 +00:00
|
|
|
state.end_of_track = false;
|
2016-01-01 23:16:12 +00:00
|
|
|
state.status = if play {
|
|
|
|
PlayStatus::kPlayStatusPlay
|
|
|
|
} else {
|
|
|
|
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
|
|
|
});
|
2015-12-28 16:47:53 +00:00
|
|
|
drop(decoder);
|
2015-07-02 19:42:49 +00:00
|
|
|
|
2015-12-28 16:47:53 +00:00
|
|
|
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-12-28 16:47:53 +00:00
|
|
|
}
|
2015-09-01 11:20:37 +00:00
|
|
|
|
2016-01-02 02:30:24 +00:00
|
|
|
let format = match self.session.0.config.bitrate {
|
|
|
|
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();
|
2015-12-28 15:53:54 +00:00
|
|
|
|
|
|
|
let key = self.session.audio_key(track.id, file_id).await().unwrap();
|
2015-07-02 19:42:49 +00:00
|
|
|
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());
|
2015-07-02 19:42:49 +00:00
|
|
|
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
|
|
|
});
|
2015-07-02 19:42:49 +00:00
|
|
|
println!("Load Done");
|
|
|
|
}
|
2015-12-28 17:45:13 +00:00
|
|
|
Some(PlayerCommand::Seek(ms)) => {
|
2015-07-02 19:42:49 +00:00
|
|
|
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
|
|
|
}
|
2015-12-28 17:45:13 +00:00
|
|
|
Some(PlayerCommand::Play) => {
|
2015-07-09 21:04:19 +00:00
|
|
|
self.update(|state| {
|
|
|
|
state.status = PlayStatus::kPlayStatusPlay;
|
2016-01-02 15:48:44 +00:00
|
|
|
true
|
2015-07-09 21:04:19 +00:00
|
|
|
});
|
2015-07-02 19:42:49 +00:00
|
|
|
|
|
|
|
stream.start().unwrap();
|
2016-01-02 15:19:39 +00:00
|
|
|
}
|
2015-12-28 17:45:13 +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();
|
2016-01-02 15:48:44 +00:00
|
|
|
true
|
2015-07-09 21:04:19 +00:00
|
|
|
});
|
2015-07-02 19:42:49 +00:00
|
|
|
|
|
|
|
stream.stop().unwrap();
|
2016-01-02 15:19:39 +00:00
|
|
|
}
|
2015-12-28 17:45:13 +00:00
|
|
|
Some(PlayerCommand::Stop) => {
|
2015-07-09 21:04:19 +00:00
|
|
|
self.update(|state| {
|
|
|
|
if state.status == PlayStatus::kPlayStatusPlay {
|
|
|
|
state.status = PlayStatus::kPlayStatusPause;
|
|
|
|
}
|
2016-01-02 15:48:44 +00:00
|
|
|
true
|
2015-07-09 21:04:19 +00:00
|
|
|
});
|
2015-07-02 19:42:49 +00:00
|
|
|
|
2015-07-09 21:04:19 +00:00
|
|
|
stream.stop().unwrap();
|
2015-07-02 19:42:49 +00:00
|
|
|
decoder = None;
|
2016-01-02 15:19:39 +00:00
|
|
|
}
|
2015-12-28 17:45:13 +00:00
|
|
|
None => (),
|
2015-07-02 19:42:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if self.state.0.lock().unwrap().status == PlayStatus::kPlayStatusPlay {
|
2015-07-09 21:32:40 +00:00
|
|
|
match decoder.as_mut().unwrap().packets().next() {
|
|
|
|
Some(Ok(packet)) => {
|
2015-07-02 19:42:49 +00:00
|
|
|
match stream.write(&packet.data) {
|
|
|
|
Ok(_) => (),
|
2016-01-02 15:19:39 +00:00
|
|
|
Err(portaudio::PaError::OutputUnderflowed) => eprintln!("Underflow"),
|
|
|
|
Err(e) => panic!("PA Error {}", e),
|
2015-07-02 19:42:49 +00:00
|
|
|
};
|
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;
|
2015-07-09 22:09:40 +00:00
|
|
|
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-07-02 19:42:49 +00:00
|
|
|
}
|
|
|
|
|
2015-07-09 21:04:19 +00:00
|
|
|
self.update(|state| {
|
|
|
|
let now = util::now_ms();
|
|
|
|
|
|
|
|
if now - state.position_measured_at > 5000 {
|
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 = now;
|
2016-01-02 15:48:44 +00:00
|
|
|
|
|
|
|
true
|
2015-07-09 21:04:19 +00:00
|
|
|
} else {
|
2016-01-02 15:48:44 +00:00
|
|
|
false
|
2015-07-09 21:04:19 +00:00
|
|
|
}
|
|
|
|
});
|
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
|
|
|
|
{
|
2015-07-09 21:04:19 +00:00
|
|
|
let mut guard = self.state.0.lock().unwrap();
|
|
|
|
let update = f(&mut guard);
|
|
|
|
if update {
|
|
|
|
guard.update_time = util::now_ms();
|
|
|
|
self.state.1.notify_all();
|
|
|
|
}
|
|
|
|
}
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
|
2015-09-01 11:20:37 +00:00
|
|
|
impl SpircDelegate for Player {
|
2015-07-09 20:08:14 +00:00
|
|
|
type State = PlayerState;
|
|
|
|
|
2016-01-02 15:19:39 +00:00
|
|
|
fn load(&self, track: SpotifyId, start_playing: bool, position_ms: u32) {
|
2015-07-09 20:08:14 +00:00
|
|
|
self.command(PlayerCommand::Load(track, start_playing, position_ms));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn play(&self) {
|
|
|
|
self.command(PlayerCommand::Play)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pause(&self) {
|
|
|
|
self.command(PlayerCommand::Pause)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn stop(&self) {
|
|
|
|
self.command(PlayerCommand::Stop)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn seek(&self, position_ms: u32) {
|
|
|
|
self.command(PlayerCommand::Seek(position_ms));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn state(&self) -> MutexGuard<Self::State> {
|
|
|
|
self.state.0.lock().unwrap()
|
|
|
|
}
|
|
|
|
|
2015-07-09 21:04:19 +00:00
|
|
|
fn updates(&self) -> mpsc::Receiver<i64> {
|
|
|
|
let state = self.state.clone();
|
|
|
|
let (update_tx, update_rx) = mpsc::channel();
|
|
|
|
|
|
|
|
thread::spawn(move || {
|
|
|
|
let mut guard = state.0.lock().unwrap();
|
|
|
|
let mut last_update;
|
|
|
|
loop {
|
|
|
|
last_update = guard.update_time;
|
|
|
|
update_tx.send(guard.update_time).unwrap();
|
|
|
|
|
|
|
|
while last_update >= guard.update_time {
|
|
|
|
guard = state.1.wait(guard).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-01-02 15:48:44 +00:00
|
|
|
update_rx
|
2015-07-09 20:08:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SpircState for PlayerState {
|
|
|
|
fn status(&self) -> PlayStatus {
|
2016-01-02 15:48:44 +00:00
|
|
|
self.status
|
2015-07-09 20:08:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
fn update_time(&self) -> i64 {
|
2016-01-02 15:48:44 +00:00
|
|
|
self.update_time
|
2015-07-09 20:08:14 +00:00
|
|
|
}
|
2015-07-09 22:09:40 +00:00
|
|
|
|
|
|
|
fn end_of_track(&self) -> bool {
|
2016-01-02 15:48:44 +00:00
|
|
|
self.end_of_track
|
2015-07-09 22:09:40 +00:00
|
|
|
}
|
2015-07-09 20:08:14 +00:00
|
|
|
}
|