//! The [Controller] is the input and output for the entire //! player. It manages queues, playback, library access, and //! other functions use std::path::{Path, PathBuf}; use std::sync::{Arc, RwLock}; use std::time::Duration; use crossbeam_channel::{Sender, Receiver}; // use std::sync::mpsc; use crossbeam_channel; use gstreamer::format::Default; use gstreamer::query::Uri; use std::thread::{self, sleep, spawn}; use std::error::Error; use crossbeam_channel::unbounded; use rayon::iter::Rev; use uuid::Uuid; use crate::config; use crate::music_storage::library::{Tag, URI}; use crate::music_storage::playlist::Playlist; use crate::{ music_player::Player, music_storage::library::{MusicLibrary, Song}, config::config::Config, }; struct Queue { player: Player, name: String, songs: Vec, } impl Queue { fn new() -> Result> { Ok( Queue { player: Player::new()?, name: String::new(), songs: Vec::new() } ) } fn set_tracks(&mut self, tracks: Vec) { let mut tracks = tracks; self.songs.clear(); self.songs.append(&mut tracks); } } pub struct Controller { // queues: Vec, config: Arc>, // library: MusicLibrary, controller_mail: MailMan, db_mail: MailMan, queue_mail: Vec>, } #[derive(Debug)] pub enum ControllerCmd { Default, Test } #[derive(Debug)] enum ControllerResponse { Empty, QueueMailMan(MailMan), } #[derive(Debug)] pub enum DatabaseCmd { Default, Test, SaveLibrary, GetSongs, QueryUuid(Uuid), QueryUuids(Vec), ReadFolder(String), } #[derive(Debug)] enum DatabaseResponse { Empty, Song(Song), Songs(Vec), Library(MusicLibrary), } #[derive(Debug)] enum QueueCmd { Default, Test, Play, Pause, SetSongs(Vec), // SetLocation(URI), Enqueue(URI), SetVolume(f64), } #[derive(Debug)] enum QueueResponse { Default, Test, Index(i32), } #[derive(Debug)] struct MailMan { pub tx: Sender, rx: Receiver } impl MailMan { pub fn new() -> Self { let (tx, rx) = unbounded::(); MailMan { tx, rx } } } impl MailMan { pub fn double() -> (MailMan, MailMan) { let (tx, rx) = unbounded::(); let (tx1, rx1) = unbounded::(); ( MailMan { tx, rx: rx1 }, MailMan { tx: tx1, rx } ) } pub fn send(&self, mail: T) -> Result<(), Box> { self.tx.send(mail).unwrap(); Ok(()) } pub fn recv(&self) -> Result> { let u = self.rx.recv().unwrap(); Ok(u) } } #[allow(unused_variables)] impl Controller { pub fn start(config_path: String) -> Result> { let config_path = PathBuf::from(config_path); let config = Config::read_file(config_path)?; let uuid = config.libraries.get_default()?.uuid; let config_ = Arc::new(RwLock::from(config)); let mut lib = MusicLibrary::init(config_.clone(), uuid)?; let config = config_.clone(); let (out_thread_controller, in_thread) = MailMan::double(); let monitor_thread = spawn(move || { use ControllerCmd::*; loop { let command = in_thread.recv().unwrap(); match command { Default => (), Test => { in_thread.send(ControllerResponse::Empty).unwrap(); }, } } }); let config = config_.clone(); let (out_thread_db, in_thread) = MailMan::double(); let db_monitor = spawn(move || { use DatabaseCmd::*; loop { let command = in_thread.recv().unwrap(); match command { Default => {}, Test => { in_thread.send(DatabaseResponse::Empty).unwrap(); }, GetSongs => { let songs = lib.query_tracks(&String::from(""), &(vec![Tag::Title]), &(vec![Tag::Title])).unwrap().iter().cloned().cloned().collect(); in_thread.send(DatabaseResponse::Songs(songs)).unwrap(); }, SaveLibrary => { //TODO: make this send lib ref to the function to save instead lib.save(config.read().unwrap().to_owned()).unwrap(); }, QueryUuid(uuid) => { match lib.query_uuid(&uuid) { Some(song) => in_thread.send(DatabaseResponse::Song(song.0.clone())).unwrap(), None => in_thread.send(DatabaseResponse::Empty).unwrap(), } }, QueryUuids(uuids) => { let mut vec = Vec::new(); for uuid in uuids { match lib.query_uuid(&uuid) { Some(song) => vec.push(song.0.clone()), None => unimplemented!() } } in_thread.send(DatabaseResponse::Songs(vec)).unwrap(); }, ReadFolder(folder) => { lib.scan_folder(&folder).unwrap(); in_thread.send(DatabaseResponse::Empty).unwrap(); } } } }); Ok( Controller { // queues: Vec::new(), config: config_.clone(), controller_mail: out_thread_controller, db_mail: out_thread_db, queue_mail: Vec::new(), } ) } fn lib_get_songs(&self) -> Vec { self.db_mail.send(DatabaseCmd::GetSongs); match self.db_mail.recv().unwrap() { DatabaseResponse::Songs(songs) => songs, _ => Vec::new() } } fn lib_scan_folder(&self, folder: String) -> Result<(), Box> { let mail = &self.db_mail; mail.send(DatabaseCmd::ReadFolder(folder))?; dbg!(mail.recv()?); Ok(()) } pub fn lib_save(&self) -> Result<(), Box> { self.db_mail.send(DatabaseCmd::SaveLibrary); Ok(()) } pub fn q_new(&mut self) -> Result> { let (out_thread_queue, in_thread) = MailMan::::double(); let queues_monitor = spawn(move || { use QueueCmd::*; let mut queue = Queue::new().unwrap(); loop { let command = in_thread.recv().unwrap(); match command { Default => {}, Test => { in_thread.send(QueueResponse::Test).unwrap() }, Play => { match queue.player.play() { Ok(_) => in_thread.send(QueueResponse::Default).unwrap(), Err(_) => todo!() }; }, Pause => { match queue.player.pause() { Ok(_) => in_thread.send(QueueResponse::Default).unwrap(), Err(_) => todo!() } }, SetSongs(songs) => { queue.set_tracks(songs); in_thread.send(QueueResponse::Default).unwrap(); }, Enqueue(uri) => { queue.player.enqueue_next(&uri).unwrap(); // in_thread.send(QueueResponse::Default).unwrap(); }, SetVolume(vol) => { queue.player.set_volume(vol); } } } }); self.queue_mail.push(out_thread_queue); Ok((self.queue_mail.len() - 1)) } fn q_play(&self, index: usize) -> Result<(), Box> { let mail = &self.queue_mail[index]; mail.send(QueueCmd::Play)?; dbg!(mail.recv()?); Ok(()) } fn q_pause(&self, index: usize) -> Result<(), Box> { let mail = &self.queue_mail[index]; mail.send(QueueCmd::Pause)?; dbg!(mail.recv()?); Ok(()) } pub fn q_set_volume(&self, index: usize, volume: f64) -> Result<(), Box> { let mail = &self.queue_mail[index]; mail.send(QueueCmd::SetVolume(volume))?; Ok(()) } fn q_set_songs(&self, index: usize, songs: Vec) -> Result<(), Box> { let mail = &self.queue_mail[index]; mail.send(QueueCmd::SetSongs(songs))?; dbg!(mail.recv()?); Ok(()) } fn q_enqueue(&self, index: usize, uri: URI) -> Result<(), Box> { let mail = &self.queue_mail[index]; mail.send(QueueCmd::Enqueue(uri))?; // dbg!(mail.recv()?); Ok(()) } } #[test] fn play_test() { let mut a = match Controller::start("test-config/config_test.json".to_string()) { Ok(c) => c, Err(e) => panic!("{e}") }; sleep(Duration::from_millis(500)); let i = a.q_new().unwrap(); a.q_set_volume(i, 0.04); // a.new_queue(); let songs = a.lib_get_songs(); a.q_enqueue(i, songs[2].location.clone()); // a.enqueue(1, songs[2].location.clone()); a.q_play(i).unwrap(); // a.play(1).unwrap(); sleep(Duration::from_secs(10)); a.q_pause(i); sleep(Duration::from_secs(10)); a.q_play(i); sleep(Duration::from_secs(1000)); } #[test] fn test_() { let a = match Controller::start("test-config/config_test.json".to_string()) { Ok(c) => c, Err(e) => panic!("{e}") }; a.lib_scan_folder("F:/Music/Mp3".to_string()); a.lib_save(); }