2025-08-23 11:46:47 +02:00

155 lines
4.7 KiB
Rust

use std::{ffi::OsStr, sync::Arc};
use rc_u8_reader::ArcU8Reader;
use rodio::{decoder::DecoderError, Decoder, OutputStream, Sink, Source};
use crate::{
data::{song::Song, SongId},
server::{Action, Command},
};
use super::PlayerBackend;
pub struct PlayerBackendRodio<T> {
#[allow(unused)]
output_stream: OutputStream,
sink: Sink,
stopped: bool,
current: Option<(SongId, Arc<Vec<u8>>, Option<u128>, T)>,
next: Option<(SongId, Arc<Vec<u8>>, Option<MyDecoder>, T)>,
command_sender: Option<std::sync::mpsc::Sender<(Command, Option<u64>)>>,
}
impl<T> PlayerBackendRodio<T> {
pub fn new(
command_sender: std::sync::mpsc::Sender<(Command, Option<u64>)>,
) -> Result<Self, Box<dyn std::error::Error>> {
Self::new_with_optional_command_sending(Some(command_sender))
}
pub fn new_without_command_sending() -> Result<Self, Box<dyn std::error::Error>> {
Self::new_with_optional_command_sending(None)
}
pub fn new_with_optional_command_sending(
command_sender: Option<std::sync::mpsc::Sender<(Command, Option<u64>)>>,
) -> Result<Self, Box<dyn std::error::Error>> {
let output_stream =
rodio::OutputStreamBuilder::from_default_device()?.open_stream_or_fallback()?;
let sink = Sink::connect_new(&output_stream.mixer());
Ok(Self {
output_stream,
sink,
stopped: true,
current: None,
next: None,
command_sender,
})
}
}
impl<T> PlayerBackend<T> for PlayerBackendRodio<T> {
fn load_next_song(
&mut self,
id: SongId,
_song: &Song,
_filename: &OsStr,
bytes: Arc<Vec<u8>>,
_load_duration: bool,
custom_data: T,
) {
let decoder = decoder_from_bytes(Arc::clone(&bytes));
if let Err(e) = &decoder {
if let Some(s) = &self.command_sender {
s.send((
Action::ErrorInfo(
format!("Couldn't decode song #{id}!"),
format!("Error: '{e}'"),
)
.cmd(0xFFu8),
None,
))
.unwrap();
}
}
self.next = Some((id, bytes, decoder.ok(), custom_data));
}
fn pause(&mut self) {
self.sink.pause();
}
fn stop(&mut self) {
if !self.stopped {
self.sink.clear();
if let Some((_, bytes, _, _)) = &self.current {
if let Ok(decoder) = decoder_from_bytes(Arc::clone(bytes)) {
self.sink.append(decoder);
}
}
}
}
fn resume(&mut self) {
self.stopped = false;
self.sink.play();
}
fn next(&mut self, play: bool, load_duration: bool) {
self.stopped = false;
self.sink.clear();
self.current = self
.next
.take()
.map(|(id, bytes, mut decoder, custom_data)| {
let duration = if let Some(decoder) = decoder.take() {
let duration = if load_duration {
dbg!(decoder.total_duration().map(|v| v.as_millis()))
} else {
None
};
self.sink.append(decoder);
if play {
self.sink.play();
}
duration
} else {
None
};
(id, bytes, duration, custom_data)
});
}
fn clear(&mut self) {
self.sink.clear();
}
fn playing(&self) -> bool {
!(self.sink.is_paused() || self.sink.empty())
}
fn current_song(&self) -> Option<(SongId, bool, &T)> {
self.current.as_ref().map(|(id, _, _, t)| (*id, true, t))
}
fn next_song(&self) -> Option<(SongId, bool, &T)> {
self.next.as_ref().map(|(id, _, _, t)| (*id, true, t))
}
fn gen_data_mut(&mut self) -> (Option<&mut T>, Option<&mut T>) {
(
self.current.as_mut().map(|(_, _, _, t)| t),
self.next.as_mut().map(|(_, _, _, t)| t),
)
}
fn song_finished_polling(&self) -> bool {
true
}
fn song_finished(&self) -> bool {
self.current.is_some() && self.sink.empty()
}
fn current_song_duration(&self) -> Option<u64> {
self.current
.as_ref()
.and_then(|(_, _, dur, _)| dur.map(|v| v as _))
}
fn current_song_playback_position(&self) -> Option<u64> {
None
}
}
type MyDecoder = Decoder<ArcU8Reader<Vec<u8>>>;
fn decoder_from_bytes(bytes: Arc<Vec<u8>>) -> Result<MyDecoder, DecoderError> {
Decoder::new(ArcU8Reader::new(Arc::clone(&bytes))).map(|decoder| decoder)
}