diff --git a/src/app_service.rs b/src/app_service.rs index fac4fc6..d2c417e 100644 --- a/src/app_service.rs +++ b/src/app_service.rs @@ -1,26 +1,28 @@ +use std::sync::Arc; + use crate::{ network_dispatcher::NetworkDispatcher, network_handler::NetworkHandler, sound_engine::SoundEngine, }; pub struct AppService { - sound_engine: SoundEngine, network_handler: NetworkHandler, network_dispatcher: NetworkDispatcher, } impl AppService { pub fn new() -> Self { + let sound_engine = Arc::new(SoundEngine::new()); Self { - sound_engine: SoundEngine::new(), - network_handler: NetworkHandler::new(), + 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()); + .dispatch_sound("localhost:3000".to_owned(), 1, "sound".to_owned()) + .unwrap(); } pub fn listen(&self) { diff --git a/src/audios/augh.m4a b/src/audios/augh.m4a new file mode 100644 index 0000000..98f2b48 Binary files /dev/null and b/src/audios/augh.m4a differ diff --git a/src/network_dispatcher.rs b/src/network_dispatcher.rs index 914aeaf..b00b2be 100644 --- a/src/network_dispatcher.rs +++ b/src/network_dispatcher.rs @@ -9,13 +9,13 @@ impl NetworkDispatcher { Self {} } - pub fn dispatch_sound(&self, addr: String, timestamp: u64, sound_source: String) { + 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); + sock.write_all(&buf) } } diff --git a/src/network_handler.rs b/src/network_handler.rs index 57e521c..35fb005 100644 --- a/src/network_handler.rs +++ b/src/network_handler.rs @@ -1,23 +1,55 @@ -use std::{io::Read, net::{TcpListener, TcpStream}}; +use std::{ + io::Read, + net::{TcpListener, TcpStream}, + sync::Arc, + thread::sleep, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; -use crate::protocol::{Message, PlaySound}; +use crate::{ + protocol::{Message, PlaySound}, + sound_engine::SoundEngine, +}; -pub struct NetworkHandler {} +pub struct NetworkHandler { + sound_engine: Arc, +} impl NetworkHandler { - pub fn new() -> Self { - Self {} + 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"); + 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) => { - let PlaySound { sound_source, timestamp } = play_sound; - println!("Playing sound: {:?} at {:?}", sound_source, timestamp); + self.handle_scheduled_sound(play_sound); } } } diff --git a/src/protocol.rs b/src/protocol.rs index 644bdfb..8d65dc6 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -7,6 +7,6 @@ pub enum Message { #[derive(Serialize, Deserialize, Debug)] pub struct PlaySound { - pub timestamp: u64, + pub timestamp: u128, pub sound_source: String, } diff --git a/src/sound_engine.rs b/src/sound_engine.rs index 58c4fe2..5d6673a 100644 --- a/src/sound_engine.rs +++ b/src/sound_engine.rs @@ -1,11 +1,23 @@ -pub struct SoundEngine {} +use std::{fs::File, io::BufReader}; + +use rodio::{Decoder, OutputStream, OutputStreamHandle, Source}; + +pub struct SoundEngine { + stream_handle: OutputStreamHandle, +} impl SoundEngine { pub fn new() -> Self { - Self {} + let (_stream, stream_handle) = OutputStream::try_default().unwrap(); + Self { stream_handle } } - pub fn play_sound(&self) { - println!("Playing sound"); + 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(); } }