diff --git a/audios/augh.mp3 b/audios/augh.mp3 new file mode 100644 index 0000000..fdba77b Binary files /dev/null and b/audios/augh.mp3 differ diff --git a/src/app_service.rs b/src/app_service.rs deleted file mode 100644 index d2c417e..0000000 --- a/src/app_service.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::sync::Arc; - -use crate::{ - network_dispatcher::NetworkDispatcher, network_handler::NetworkHandler, - sound_engine::SoundEngine, -}; - -pub struct AppService { - network_handler: NetworkHandler, - network_dispatcher: NetworkDispatcher, -} - -impl AppService { - pub fn new() -> Self { - let sound_engine = Arc::new(SoundEngine::new()); - Self { - network_handler: NetworkHandler::new(sound_engine.clone()), - network_dispatcher: NetworkDispatcher::new(), - } - } - - pub fn dispatch_sample(&self) { - self.network_dispatcher - .dispatch_sound("localhost:3000".to_owned(), 1, "sound".to_owned()) - .unwrap(); - } - - pub fn listen(&self) { - self.network_handler.listen(); - } -} diff --git a/src/audios/augh.m4a b/src/audios/augh.m4a deleted file mode 100644 index 98f2b48..0000000 Binary files a/src/audios/augh.m4a and /dev/null differ diff --git a/src/client_handler.rs b/src/client_handler.rs new file mode 100644 index 0000000..e295afb --- /dev/null +++ b/src/client_handler.rs @@ -0,0 +1,37 @@ +use crate::protocol::Message; +use crate::sound_scheduler::SoundScheduler; +use std::io::Read; +use std::net::{TcpListener, TcpStream}; + +pub struct ClientHandler; + +impl ClientHandler { + fn handle_client(mut stream: TcpStream) { + println!("Handling client: {:?}", stream); + let mut buf: Vec = Vec::new(); + stream + .read_to_end(buf.as_mut()) + .expect("Could not read from stream"); + let message = bincode::deserialize::(&buf).expect("Could not deserialize message"); + match message { + Message::PlaySound(play_sound) => { + SoundScheduler::handle_scheduled_sound(play_sound); + } + } + } + + pub fn listen() { + let listener = TcpListener::bind("127.0.0.1:3000").expect("Could not bind to address"); + + for stream in listener.incoming() { + match stream { + Ok(stream) => { + ClientHandler::handle_client(stream); + } + Err(e) => { + eprintln!("Error: {}", e); + } + } + } + } +} diff --git a/src/dispatcher.rs b/src/dispatcher.rs new file mode 100644 index 0000000..d0b5317 --- /dev/null +++ b/src/dispatcher.rs @@ -0,0 +1,25 @@ +use std::io::Write; +use std::net::TcpStream; +use std::time::SystemTime; + +use crate::protocol::{Message, PlaySound}; + +pub struct Dispatcher; + +impl Dispatcher { + pub fn handle_dispatch_sample() { + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_micros(); + let timestamp = now + 10000000; + let addr = "localhost:3000".to_owned(); + let msg = Message::PlaySound(PlaySound { + timestamp: timestamp, + sound_source: "augh.mp3".to_owned(), + }); + let mut sock = TcpStream::connect(addr).expect("Failed to connect"); + let buf = bincode::serialize(&msg).expect("Failed to serialize"); + sock.write_all(&buf).unwrap(); + } +} diff --git a/src/main.rs b/src/main.rs index 416fed0..216a1e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,28 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release +use client_handler::ClientHandler; +use std::thread; +use ui_app::UIApp; + use eframe::egui; -use std::{sync::Arc, thread}; -mod app_service; -mod network_dispatcher; -mod network_handler; +mod client_handler; +mod dispatcher; mod protocol; -mod sound_engine; - -use crate::app_service::AppService; +mod sound_player; +mod sound_scheduler; +mod ui_app; fn main() -> eframe::Result { let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]), ..Default::default() }; + + thread::spawn(move || { + ClientHandler::listen(); + }); + eframe::run_native( "My egui App", options, @@ -27,31 +34,3 @@ fn main() -> eframe::Result { }), ) } - -struct UIApp { - app_service: Arc, -} - -impl Default for UIApp { - fn default() -> Self { - let app_service = Arc::new(AppService::new()); - - let app_service_listener = Arc::clone(&app_service); - thread::spawn(move || { - app_service_listener.listen(); - }); - - Self { - app_service: app_service, - } - } -} - -impl eframe::App for UIApp { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - egui::CentralPanel::default().show(ctx, |ui| { - ui.heading("My egui Application"); - ui.label("Hello"); - }); - } -} diff --git a/src/network_dispatcher.rs b/src/network_dispatcher.rs deleted file mode 100644 index b00b2be..0000000 --- a/src/network_dispatcher.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::{io::Write, net::TcpStream}; - -use crate::protocol::{Message, PlaySound}; - -pub struct NetworkDispatcher {} - -impl NetworkDispatcher { - pub fn new() -> Self { - Self {} - } - - pub fn dispatch_sound(&self, addr: String, timestamp: u128, sound_source: String) -> std::io::Result<()> { - let msg = Message::PlaySound(PlaySound { - timestamp: timestamp, - sound_source: sound_source, - }); - let mut sock = TcpStream::connect(addr).expect("Failed to connect"); - let buf = bincode::serialize(&msg).expect("Failed to serialize"); - sock.write_all(&buf) - } -} diff --git a/src/network_handler.rs b/src/network_handler.rs deleted file mode 100644 index 35fb005..0000000 --- a/src/network_handler.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::{ - io::Read, - net::{TcpListener, TcpStream}, - sync::Arc, - thread::sleep, - time::{Duration, SystemTime, UNIX_EPOCH}, -}; - -use crate::{ - protocol::{Message, PlaySound}, - sound_engine::SoundEngine, -}; - -pub struct NetworkHandler { - sound_engine: Arc, -} - -impl NetworkHandler { - pub fn new(sound_engine: Arc) -> Self { - Self { sound_engine } - } - - fn handle_scheduled_sound(&self, play_msg: PlaySound) { - let PlaySound { - sound_source, - timestamp, - } = play_msg; - println!("Scheduled sound: {:?} at {:?}", sound_source, timestamp); - let now_micros = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Could not get time") - .as_micros(); - let wait = timestamp as i128 - now_micros as i128; - if wait <= 0 { - println!("Too late to play sound"); - return; - } - sleep(Duration::from_micros(wait as u64)); - println!("Playing sound: {:?}", sound_source); - self.sound_engine.play_sound(sound_source); - } - - fn handle_client(&self, mut stream: TcpStream) { - println!("Handling client: {:?}", stream); - let mut buf: Vec = Vec::new(); - stream - .read_to_end(buf.as_mut()) - .expect("Could not read from stream"); - let message = bincode::deserialize::(&buf).expect("Could not deserialize message"); - match message { - Message::PlaySound(play_sound) => { - self.handle_scheduled_sound(play_sound); - } - } - } - - pub fn listen(&self) { - let listener = TcpListener::bind("127.0.0.1:3000").expect("Could not bind to address"); - - for stream in listener.incoming() { - match stream { - Ok(stream) => { - self.handle_client(stream); - } - Err(e) => { - eprintln!("Error: {}", e); - } - } - } - } -} diff --git a/src/sound_engine.rs b/src/sound_engine.rs deleted file mode 100644 index 5d6673a..0000000 --- a/src/sound_engine.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::{fs::File, io::BufReader}; - -use rodio::{Decoder, OutputStream, OutputStreamHandle, Source}; - -pub struct SoundEngine { - stream_handle: OutputStreamHandle, -} - -impl SoundEngine { - pub fn new() -> Self { - let (_stream, stream_handle) = OutputStream::try_default().unwrap(); - Self { stream_handle } - } - - pub fn play_sound(&self, sound_source: String) { - let path = format!("./audios/{}", sound_source); - let file = BufReader::new(File::open(path).unwrap()); - let source = Decoder::new(file).unwrap(); - self.stream_handle - .play_raw(source.convert_samples()) - .unwrap(); - } -} diff --git a/src/sound_player.rs b/src/sound_player.rs new file mode 100644 index 0000000..3f25214 --- /dev/null +++ b/src/sound_player.rs @@ -0,0 +1,17 @@ +use rodio::{Decoder, OutputStream, Sink}; +use std::{fs::File, io::BufReader}; + +pub struct SoundPlayer; + +impl SoundPlayer { + pub fn play_sound(sound_source: String) { + let path = format!("./audios/{}", sound_source); + let file = BufReader::new(File::open(path).unwrap()); + let source = Decoder::new(file).unwrap(); + + let (_stream, stream_handle) = OutputStream::try_default().unwrap(); + let sink = Sink::try_new(&stream_handle).unwrap(); + sink.append(source); + sink.sleep_until_end(); + } +} diff --git a/src/sound_scheduler.rs b/src/sound_scheduler.rs new file mode 100644 index 0000000..f09fe26 --- /dev/null +++ b/src/sound_scheduler.rs @@ -0,0 +1,28 @@ +use crate::protocol::PlaySound; +use crate::sound_player::SoundPlayer; +use std::thread::sleep; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +pub struct SoundScheduler; + +impl SoundScheduler { + pub fn handle_scheduled_sound(play_msg: PlaySound) { + let PlaySound { + sound_source, + timestamp, + } = play_msg; + println!("Scheduled sound: {:?} at {:?}", sound_source, timestamp); + let now_micros = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Could not get time") + .as_micros(); + let wait = timestamp as i128 - now_micros as i128; + if wait <= 0 { + println!("Too late to play sound"); + return; + } + sleep(Duration::from_micros(wait as u64)); + println!("Playing sound: {:?}", sound_source); + SoundPlayer::play_sound(sound_source); + } +} diff --git a/src/ui_app.rs b/src/ui_app.rs new file mode 100644 index 0000000..58b4611 --- /dev/null +++ b/src/ui_app.rs @@ -0,0 +1,23 @@ +use eframe::egui; + +use crate::dispatcher::Dispatcher; + +pub struct UIApp {} + +impl Default for UIApp { + fn default() -> Self { + Self {} + } +} + +impl eframe::App for UIApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + egui::CentralPanel::default().show(ctx, |ui| { + ui.heading("My egui Application"); + ui.label("Hello"); + if ui.button("Dispatch sample").clicked() { + Dispatcher::handle_dispatch_sample(); + } + }); + } +}