Implement track preloading
Will preload the next track close to the end of the currently playing track. Should make playback of queued tracks a little smoother.
This commit is contained in:
@@ -1,10 +1,12 @@
|
|||||||
use crossbeam_channel::{unbounded, Receiver, Sender, TryIter};
|
use crossbeam_channel::{unbounded, Receiver, Sender, TryIter};
|
||||||
use cursive::{CbSink, Cursive};
|
use cursive::{CbSink, Cursive};
|
||||||
|
|
||||||
|
use crate::queue::QueueEvent;
|
||||||
use crate::spotify::PlayerEvent;
|
use crate::spotify::PlayerEvent;
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Player(PlayerEvent),
|
Player(PlayerEvent),
|
||||||
|
Queue(QueueEvent),
|
||||||
SessionDied,
|
SessionDied,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -328,6 +328,9 @@ fn main() {
|
|||||||
queue.next(false);
|
queue.next(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::Queue(event) => {
|
||||||
|
queue.handle_event(event);
|
||||||
|
}
|
||||||
Event::SessionDied => spotify.start_worker(None),
|
Event::SessionDied => spotify.start_worker(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/queue.rs
17
src/queue.rs
@@ -21,6 +21,11 @@ pub enum RepeatSetting {
|
|||||||
RepeatTrack,
|
RepeatTrack,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum QueueEvent {
|
||||||
|
PreloadTrackRequest,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Queue {
|
pub struct Queue {
|
||||||
pub queue: Arc<RwLock<Vec<Playable>>>,
|
pub queue: Arc<RwLock<Vec<Playable>>>,
|
||||||
random_order: RwLock<Option<Vec<usize>>>,
|
random_order: RwLock<Option<Vec<usize>>>,
|
||||||
@@ -383,6 +388,18 @@ impl Queue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_event(&self, event: QueueEvent) {
|
||||||
|
match event {
|
||||||
|
QueueEvent::PreloadTrackRequest => {
|
||||||
|
if let Some(next_index) = self.next_index() {
|
||||||
|
let track = self.queue.read().unwrap()[next_index].clone();
|
||||||
|
debug!("Preloading track {} as requested by librespot", track);
|
||||||
|
self.spotify.preload(&track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_spotify(&self) -> Spotify {
|
pub fn get_spotify(&self) -> Spotify {
|
||||||
self.spotify.clone()
|
self.spotify.clone()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -842,6 +842,10 @@ impl Spotify {
|
|||||||
self.send_worker(WorkerCommand::SetVolume(Self::log_scale(volume)));
|
self.send_worker(WorkerCommand::SetVolume(Self::log_scale(volume)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn preload(&self, track: &Playable) {
|
||||||
|
self.send_worker(WorkerCommand::Preload(track.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn shutdown(&self) {
|
pub fn shutdown(&self) {
|
||||||
self.send_worker(WorkerCommand::Shutdown);
|
self.send_worker(WorkerCommand::Shutdown);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::events::{Event, EventManager};
|
use crate::events::{Event, EventManager};
|
||||||
use crate::playable::Playable;
|
use crate::playable::Playable;
|
||||||
|
use crate::queue::QueueEvent;
|
||||||
use crate::spotify::{PlayerEvent, Spotify};
|
use crate::spotify::{PlayerEvent, Spotify};
|
||||||
use futures::channel::{mpsc, oneshot};
|
use futures::channel::{mpsc, oneshot};
|
||||||
use futures::compat::Stream01CompatExt;
|
use futures::compat::Stream01CompatExt;
|
||||||
@@ -25,6 +26,7 @@ pub(crate) enum WorkerCommand {
|
|||||||
Seek(u32),
|
Seek(u32),
|
||||||
SetVolume(u16),
|
SetVolume(u16),
|
||||||
RequestToken(oneshot::Sender<Token>),
|
RequestToken(oneshot::Sender<Token>),
|
||||||
|
Preload(Playable),
|
||||||
Shutdown,
|
Shutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +128,12 @@ impl futures::Future for Worker {
|
|||||||
self.token_task = Spotify::get_token(&self.session, sender);
|
self.token_task = Spotify::get_token(&self.session, sender);
|
||||||
progress = true;
|
progress = true;
|
||||||
}
|
}
|
||||||
|
WorkerCommand::Preload(playable) => {
|
||||||
|
if let Ok(id) = SpotifyId::from_uri(&playable.uri()) {
|
||||||
|
debug!("Preloading {:?}", id);
|
||||||
|
self.player.preload(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
WorkerCommand::Shutdown => {
|
WorkerCommand::Shutdown => {
|
||||||
self.player.stop();
|
self.player.stop();
|
||||||
self.session.shutdown();
|
self.session.shutdown();
|
||||||
@@ -173,6 +181,10 @@ impl futures::Future for Worker {
|
|||||||
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
|
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
|
||||||
progress = true;
|
progress = true;
|
||||||
}
|
}
|
||||||
|
LibrespotPlayerEvent::TimeToPreloadNextTrack { .. } => {
|
||||||
|
self.events
|
||||||
|
.send(Event::Queue(QueueEvent::PreloadTrackRequest));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user