Implement chunking

This commit is contained in:
Silvio Braendle 2025-01-13 15:32:22 +01:00
parent 29c4cacbbb
commit 3b61210761
No known key found for this signature in database
GPG key ID: 553A5A37BA69D8AE
5 changed files with 60 additions and 34 deletions

View file

@ -1,6 +1,5 @@
use crate::protocol::Message; use crate::protocol::Message;
use crate::sound_scheduler::SoundScheduler; use crate::sound_scheduler::SoundScheduler;
use std::io::Read;
use std::net::{TcpListener, TcpStream}; use std::net::{TcpListener, TcpStream};
use std::thread; use std::thread;
@ -9,17 +8,22 @@ pub struct ClientHandler;
impl ClientHandler { impl ClientHandler {
fn handle_client(mut stream: TcpStream) { fn handle_client(mut stream: TcpStream) {
println!("Handling client: {:?}", stream); println!("Handling client: {:?}", stream);
let mut buf: Vec<u8> = Vec::new(); loop {
stream match bincode::deserialize_from::<&mut TcpStream, Message>(&mut stream) {
.read_to_end(buf.as_mut()) Ok(message) => {
.expect("Could not read from stream");
let message = bincode::deserialize::<Message>(&buf).expect("Could not deserialize message");
match message { match message {
Message::PlaySound(play_sound) => { Message::PlaySound(play_sound) => {
SoundScheduler::handle_scheduled_sound(play_sound); SoundScheduler::handle_scheduled_sound(play_sound);
} }
} }
} }
Err(e) => {
eprintln!("Error deserializing message: {}", e);
break;
}
}
}
}
pub fn listen() { pub fn listen() {
let listener = TcpListener::bind("0.0.0.0:3000").expect("Could not bind to address"); let listener = TcpListener::bind("0.0.0.0:3000").expect("Could not bind to address");

View file

@ -1,41 +1,60 @@
use std::io::{BufReader, Read}; use std::io::BufReader;
use std::net::TcpStream; use std::net::TcpStream;
use std::time::SystemTime; use std::time::{Duration, SystemTime};
use std::{fs::File, io::Write}; use std::{fs::File, io::Write};
use rodio::{Decoder, Source};
use crate::protocol::{Message, PlaySound}; use crate::protocol::{Message, PlaySound};
pub struct Dispatcher; pub struct Dispatcher;
impl Dispatcher { impl Dispatcher {
fn load_sound(path: String) -> Vec<u8> { fn load_sound(path: String) -> Decoder<BufReader<File>> {
let file = BufReader::new(File::open(path).unwrap()); let file = BufReader::new(File::open(path).unwrap());
let data: Vec<u8> = file.bytes().map(|byte| byte.unwrap()).collect(); Decoder::new(file).unwrap()
data
} }
pub fn handle_dispatch_sample(addrs: Vec<String>, sound_path: String) { pub fn handle_dispatch_sample(addrs: Vec<String>, sound_path: String) {
let now = SystemTime::now() let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap();
.as_micros();
let timestamp = now + 10000000; let source = Dispatcher::load_sound(sound_path).buffered();
let sound_data = Dispatcher::load_sound(sound_path);
let msg = Message::PlaySound(PlaySound { let channels = source.channels();
timestamp: timestamp, let sample_rate = source.sample_rate();
sound_data: sound_data, let duration = source.total_duration().unwrap();
}); let chunk_len = Duration::from_secs(1);
let mut offset = Duration::from_secs(0);
for addr in addrs { for addr in addrs {
if addr.is_empty() { if addr.is_empty() {
continue; continue;
}
} else {
let mut sock = TcpStream::connect(addr).expect("Failed to connect"); let mut sock = TcpStream::connect(addr).expect("Failed to connect");
while offset < duration {
let sound_data = source
.clone()
.skip_duration(offset)
.take_duration(chunk_len)
.collect::<Vec<i16>>();
offset += chunk_len;
let msg = Message::PlaySound(PlaySound {
timestamp: (now + offset).as_micros(),
channels: channels,
sample_rate: sample_rate,
sound_data: sound_data,
});
let buf = bincode::serialize(&msg).expect("Failed to serialize"); let buf = bincode::serialize(&msg).expect("Failed to serialize");
sock.write_all(&buf).unwrap(); sock.write_all(&buf).unwrap();
} }
}
}
} }
} }

View file

@ -8,5 +8,7 @@ pub enum Message {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct PlaySound { pub struct PlaySound {
pub timestamp: u128, pub timestamp: u128,
pub sound_data: Vec<u8>, pub channels: u16,
pub sample_rate: u32,
pub sound_data: Vec<i16>,
} }

View file

@ -1,12 +1,11 @@
use rodio::{Decoder, OutputStream, Sink}; use rodio::{buffer::SamplesBuffer, OutputStream, Sink};
use std::io::Cursor;
pub struct SoundPlayer; pub struct SoundPlayer;
impl SoundPlayer { impl SoundPlayer {
pub fn play_sound(sound_data: Vec<u8>) { pub fn play_sound(channels: u16, sample_rate: u32, sound_data: Vec<i16>) {
let data = Cursor::new(sound_data); // let data = Cursor::new(sound_data);
let source = Decoder::new(data).unwrap(); let source = SamplesBuffer::new(channels, sample_rate, sound_data);
let (_stream, stream_handle) = OutputStream::try_default().unwrap(); let (_stream, stream_handle) = OutputStream::try_default().unwrap();
let sink = Sink::try_new(&stream_handle).unwrap(); let sink = Sink::try_new(&stream_handle).unwrap();

View file

@ -9,6 +9,8 @@ impl SoundScheduler {
pub fn handle_scheduled_sound(play_msg: PlaySound) { pub fn handle_scheduled_sound(play_msg: PlaySound) {
thread::spawn(move || { thread::spawn(move || {
let PlaySound { let PlaySound {
channels,
sample_rate,
sound_data, sound_data,
timestamp, timestamp,
} = play_msg; } = play_msg;
@ -28,7 +30,7 @@ impl SoundScheduler {
} }
sleep(Duration::from_micros(wait as u64)); sleep(Duration::from_micros(wait as u64));
println!("Playing sound..."); println!("Playing sound...");
SoundPlayer::play_sound(sound_data); SoundPlayer::play_sound(channels, sample_rate, sound_data);
}); });
} }
} }