use std::{
sync::{
Arc, Mutex,
atomic::{AtomicU32, Ordering},
mpsc::{Sender, TryRecvError, channel},
},
thread,
};
use lunar_lib::{database::Database, debug, error};
use selene_core::database::LibraryDb;
use crate::{
SHUTDOWN,
decoder::{DecoderEvent, DecoderHandle},
event_handler::EventHandler,
player::{Player, PlayerError, PlayerRequest, playback::DeviceConfig},
playlist::{AtomicPlaybackStatus, PlaybackStatus, Playlist},
wait,
};
impl Player {
fn new() -> Result<(Sender<PlayerRequest>, Self), PlayerError> {
let (player_tx, rx) = channel();
let event_tx = EventHandler::open(player_tx.clone())?;
let volume = Arc::new(AtomicU32::new(1.0_f32.to_bits()));
let playback_state = Arc::new(AtomicPlaybackStatus::new(PlaybackStatus::Stopped));
let playlist = Playlist::new(event_tx.clone());
let device_config = Arc::new(Mutex::new(DeviceConfig::default_config()?));
let decoder_tx = DecoderHandle::open(
player_tx.clone(),
event_tx.clone(),
device_config.clone(),
playback_state.clone(),
volume.clone(),
)?;
Ok((
player_tx,
Self {
rx,
decoder_tx,
event_tx,
playlist,
device_config,
playback_state,
volume,
},
))
}
pub fn open() -> Result<Sender<PlayerRequest>, PlayerError> {
let (player_tx, player) = Self::new()?;
thread::spawn(move || {
if let Err(err) = player.run() {
error!("Engine failed with error: {err}");
}
SHUTDOWN.store(true, Ordering::Relaxed);
});
Ok(player_tx)
}
pub fn start() -> Result<(), PlayerError> {
let (_, player) = Self::new()?;
player.run()?;
SHUTDOWN.store(true, Ordering::Relaxed);
Ok(())
}
fn run(mut self) -> Result<(), PlayerError> {
debug!("Engine thread started");
loop {
if SHUTDOWN.load(Ordering::Relaxed) {
return Ok(());
}
loop {
match self.rx.try_recv() {
Ok(PlayerRequest::Command(command)) => self.run_command(*command)?,
Ok(PlayerRequest::DecoderEvent(DecoderEvent::PreloadConsumed)) => {
let db = LibraryDb::open().unwrap();
self.playlist.pop_next(&db)?;
if let Some(peek_next) = self.playlist.peek_next(&db)? {
self.preload(peek_next)?;
}
}
Err(TryRecvError::Empty) => break,
Err(TryRecvError::Disconnected) => {
return Ok(());
}
}
}
wait();
continue;
}
}
}