116 lines
2.5 KiB
Rust
116 lines
2.5 KiB
Rust
use std::{
|
|
fs,
|
|
io::{BufReader, Cursor},
|
|
path::Path,
|
|
time::Duration,
|
|
};
|
|
|
|
use rodio::{Decoder, Sink};
|
|
|
|
use crate::{database::tracks::Track, proto::player::PlayerStatus};
|
|
|
|
pub struct AudioPlayer {
|
|
sink: Sink,
|
|
currently_playing: Option<Track>,
|
|
}
|
|
|
|
impl AudioPlayer {
|
|
pub fn new(sink: Sink) -> Self {
|
|
sink.set_volume(0.5);
|
|
|
|
Self {
|
|
sink,
|
|
currently_playing: None,
|
|
}
|
|
}
|
|
|
|
pub fn play_track<P>(&mut self, track: Track, path: P) -> Result<(), Box<dyn std::error::Error>>
|
|
where
|
|
P: AsRef<Path>,
|
|
{
|
|
self.sink.clear();
|
|
|
|
let file = BufReader::new(Cursor::new(fs::read(path)?));
|
|
|
|
let source = Decoder::new(file)?;
|
|
|
|
self.currently_playing = Some(track);
|
|
self.sink.append(source);
|
|
|
|
self.sink.play();
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn resume(&self) {
|
|
self.sink.play();
|
|
}
|
|
|
|
pub fn pause(&self) {
|
|
self.sink.pause();
|
|
}
|
|
|
|
/// Toggles the player's pause state and returns the new value
|
|
pub fn toggle_pause(&self) -> bool {
|
|
if self.is_paused() {
|
|
self.resume();
|
|
false
|
|
} else {
|
|
self.pause();
|
|
true
|
|
}
|
|
}
|
|
|
|
pub fn volume(&self) -> f32 {
|
|
self.sink.volume()
|
|
}
|
|
|
|
pub fn set_volume(&self, value: f32) {
|
|
self.sink.set_volume(value);
|
|
}
|
|
|
|
pub fn position(&self) -> u128 {
|
|
self.sink.get_pos().as_millis()
|
|
}
|
|
|
|
pub fn set_position(&self, position: u64) {
|
|
let _ = self.sink.try_seek(Duration::from_millis(position));
|
|
}
|
|
|
|
pub fn is_paused(&self) -> bool {
|
|
self.sink.is_paused()
|
|
}
|
|
|
|
pub fn currently_playing(&self) -> Option<Track> {
|
|
self.currently_playing.clone()
|
|
}
|
|
|
|
pub fn get_snapshot(&self) -> StatusSnapshot {
|
|
StatusSnapshot {
|
|
volume: self.volume(),
|
|
position: self.position(),
|
|
is_paused: self.is_paused(),
|
|
currently_playing: self.currently_playing(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct StatusSnapshot {
|
|
pub volume: f32,
|
|
pub position: u128,
|
|
pub is_paused: bool,
|
|
pub currently_playing: Option<Track>,
|
|
}
|
|
|
|
impl Into<PlayerStatus> for StatusSnapshot {
|
|
fn into(self) -> PlayerStatus {
|
|
PlayerStatus {
|
|
volume: self.volume,
|
|
is_paused: self.is_paused,
|
|
progress: self.position as u64,
|
|
currently_playing: self.currently_playing.clone().map(|t| t.into()),
|
|
}
|
|
}
|
|
}
|