resonator 0.1.0

This crate allows 2 devices to send live PCM audio data to each other through a server
Documentation
use std::{sync::{Arc, Mutex}, net::{TcpListener, TcpStream}, thread, io::{Read, Write}};
use crate::{config::{AUDIO_BUFFER_SIZE, BUFFER_WITH_HEADER_SIZE, HEADER_SIZE, METADATA_SIZE}, common::audiobuffer::AudioBuffer};

use super::{client::{ClientManager, Client}, metadata::Metadata};

pub struct AudioData {
    pub sender: u32,
    pub reciever: u32,
    pub buffer_size: i32,
    pub sample_rate: i32,
    pub samples: [f32; AUDIO_BUFFER_SIZE],
}

pub struct ResonatorServer {
    pub client_send_port: u16,
    pub client_receive_port: u16,
}

impl ResonatorServer {
    /**

     * Constructs a new Resonator using the specified ports
     */
    pub fn new(client_send_port: u16, client_receive_port: u16) -> ResonatorServer {
        ResonatorServer {
            client_send_port,
            client_receive_port
        }
    }

    /**

     * Begins the server, listening for incoming connections on the specified ports
     */
    pub fn begin(&self) {
        println!("Beginning socket server. Port {} will be used for sending audio data to this server, and port {} will be used for recieving outgoing audio data from this server.", self.client_send_port, self.client_receive_port);
        let client_manager: Arc<Mutex<ClientManager>> = Arc::new(Mutex::new(ClientManager::new()));

        //Handles audio data being sent from a client
        let client_send_listener: TcpListener = TcpListener::bind(format!("127.0.0.1:{}", self.client_send_port)).unwrap();

        //Handles broadcasting audio data back down to a client
        let client_receive_listener: TcpListener = TcpListener::bind(format!("127.0.0.1:{}", self.client_receive_port)).unwrap();
    
        //Spawn a new thread for handling incoming data sent from connected clients
        {
            let client_manager = client_manager.clone();
            thread::spawn(move || {
                for stream in client_send_listener.incoming() {
                    match stream {
                        Ok(tcp_stream) => {
                            let client_manager = client_manager.clone();
                            thread::spawn(move || {
                                handle_client_sent_data(tcp_stream, client_manager);
                            });
                        }
                        Err(e) => eprintln!("Error accepting connection: {}", e),
                    }
                }
            });
        }

        //Spawns a new thread for handling sending outgoing data to their respective recipients
        {
            let client_manager = client_manager.clone();
            thread::spawn(move || {
                for stream in client_receive_listener.incoming() {
                    match stream {
                        Ok(tcp_stream) => {
                            let client_manager = client_manager.clone();
                            thread::spawn(move || {
                                handle_client_will_receive_data(tcp_stream, client_manager);
                            });
                        }
                        Err(e) => eprintln!("Error accepting connection: {}", e),
                    }
                }
            });
        }
    }
}

/**

 * Loop which handles recieving incoming data sent from connected clients
 */
fn handle_client_sent_data(mut tcp_stream: TcpStream, client_manager: Arc<Mutex<ClientManager>>) {
    let mut buffer = [0; BUFFER_WITH_HEADER_SIZE]; //Stores the raw bytes of the audio buffer sent from the client
    let mut id: i32 = 0; //Stores the clients id

    loop {
        //Read the next audio buffer sent from the client if available
        match tcp_stream.read(&mut buffer) {
            Ok(size) if size == 0 => {
                println!("Client closed connection");
                break;
            }
            Ok(size) => size,
            Err(_) => {
                println!("Client error");
                break;
            }
        };

        //Copy the raw bytes into their respective buffers
        let bytes = &buffer[..];
        let header_bytes = &bytes[..HEADER_SIZE];
        let metadata_bytes = &bytes[HEADER_SIZE..(HEADER_SIZE + METADATA_SIZE)];
        let audio_bytes = &bytes[(HEADER_SIZE + METADATA_SIZE)..];

        //Parse the sender and reciever ids from the header
        let h_sender_id = i32::from_le_bytes(header_bytes[0..4].try_into().unwrap());
        let h_reciever_id = i32::from_le_bytes(header_bytes[4..8].try_into().unwrap());

        //Parse the metadata
        let m_buff_size = i32::from_le_bytes(metadata_bytes[0..4].try_into().unwrap());
        let m_sample_rate = i32::from_le_bytes(metadata_bytes[4..8].try_into().unwrap());

        //Parse the audio samples
        let samples: Vec<f32> = audio_bytes.chunks_exact(4).map(|chunk| {
            f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])
        })
        .collect();

        //Set the (sender) id to be the id specified in the header
        id = h_sender_id;

        //Lock & access the ClientManager Mutex
        let mut temp_client_manager = client_manager.lock().unwrap();
        
        //Add the client to the ClientManager if they are not already in it
        let client_added = temp_client_manager.get_by_id(h_sender_id).is_some();
        if !client_added {
            temp_client_manager.add(h_sender_id);
        }

        //Construct an AudioBuffer from the recieved byte data
        let new_buff = AudioBuffer {
            samples,
            metadata: Metadata {
                sample_rate: m_sample_rate,
                buffer_size: m_buff_size,
            }
        };

        //Add the buffer to the queue of buffers to be sent to the intended recipient
        if temp_client_manager.get_by_id(h_reciever_id).is_none() {
            temp_client_manager.add(h_reciever_id);
        }
        let temp_client: &mut Client = temp_client_manager.get_by_id(h_reciever_id).unwrap();
        temp_client.enqueue_buffer(new_buff.clone());
    }

    let mut temp_client_manager = client_manager.lock().unwrap();
    temp_client_manager.remove(id);
}

/**

 * Loop which handles sending outgoing data to their respective recipients
 */
fn handle_client_will_receive_data(mut tcp_stream: TcpStream, client_manager: Arc<Mutex<ClientManager>>) {
    let mut buffer = [0; std::mem::size_of::<i32>()]; //Stores the raw bytes of the initial data sent on connection
    let mut id: i32 = 0; //The clinets id

    loop {
        //If the client has not yet sent their id, read the next data sent from the client. Otherwise, send the next buffer to the client
        if id == 0 {
            //Read data sent from the client if available
            match tcp_stream.read(&mut buffer) {
                Ok(size) if size == 0 => {
                    println!("Client closed connection");
                    break;
                }
                Ok(size) => size,
                Err(_) => {
                    println!("Client error");
                    break;
                }
            };

            let bytes = &buffer[..];
            id = i32::from_le_bytes(bytes.try_into().unwrap());
    
            let mut temp_client_manager = client_manager.lock().unwrap();
            if temp_client_manager.get_by_id(id).is_none() {
                temp_client_manager.add(id);
            }
        } else {
            //Lock & access the ClientManager Mutex
            let mut temp_client_manager = client_manager.lock().unwrap();
            let temp_client: &mut Client = temp_client_manager.get_by_id(id).unwrap();
            
            //Check if there is a buffer ready to be sent to the client
            let next_buffer = temp_client.get_next_buffer();
            if next_buffer.is_some() {
                //Send the buffer to the client
                let next_buffer = next_buffer.unwrap().as_buffer().unwrap();
                let raw_buffer = next_buffer.raw_buffer();
                tcp_stream.write_all(raw_buffer).unwrap();
            }
        }
    }

    //On disconnect remove the client from the ClientManager
    let mut temp_client_manager = client_manager.lock().unwrap();
    temp_client_manager.remove(id);
}