A multiplayer VR framework w/voice chat

voice chat implemented, need to test

phaz.uk 74dfcdaf f0419fc3

verified
+43
Cargo.lock
··· 315 315 ] 316 316 317 317 [[package]] 318 + name = "audiopus_sys" 319 + version = "0.2.2" 320 + source = "registry+https://github.com/rust-lang/crates.io-index" 321 + checksum = "62314a1546a2064e033665d658e88c620a62904be945f8147e6b16c3db9f8651" 322 + dependencies = [ 323 + "cmake", 324 + "log", 325 + "pkg-config", 326 + ] 327 + 328 + [[package]] 318 329 name = "autocfg" 319 330 version = "1.5.0" 320 331 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1743 1754 ] 1744 1755 1745 1756 [[package]] 1757 + name = "cmake" 1758 + version = "0.1.57" 1759 + source = "registry+https://github.com/rust-lang/crates.io-index" 1760 + checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" 1761 + dependencies = [ 1762 + "cc", 1763 + ] 1764 + 1765 + [[package]] 1746 1766 name = "codespan-reporting" 1747 1767 version = "0.12.0" 1748 1768 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2290 2310 "anyhow", 2291 2311 "bevy", 2292 2312 "cpal 0.16.0", 2313 + "felix-net", 2293 2314 "hound", 2294 2315 "kira", 2316 + "opus", 2295 2317 ] 2296 2318 2297 2319 [[package]] ··· 2323 2345 "bevy_math", 2324 2346 "dotenvy", 2325 2347 "felix-net", 2348 + "kanal", 2326 2349 "nanoid", 2327 2350 ] 2328 2351 ··· 2897 2920 dependencies = [ 2898 2921 "once_cell", 2899 2922 "wasm-bindgen", 2923 + ] 2924 + 2925 + [[package]] 2926 + name = "kanal" 2927 + version = "0.1.1" 2928 + source = "registry+https://github.com/rust-lang/crates.io-index" 2929 + checksum = "9e3953adf0cd667798b396c2fa13552d6d9b3269d7dd1154c4c416442d1ff574" 2930 + dependencies = [ 2931 + "futures-core", 2932 + "lock_api", 2900 2933 ] 2901 2934 2902 2935 [[package]] ··· 3665 3698 version = "1.21.3" 3666 3699 source = "registry+https://github.com/rust-lang/crates.io-index" 3667 3700 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 3701 + 3702 + [[package]] 3703 + name = "opus" 3704 + version = "0.3.0" 3705 + source = "registry+https://github.com/rust-lang/crates.io-index" 3706 + checksum = "6526409b274a7e98e55ff59d96aafd38e6cd34d46b7dbbc32ce126dffcd75e8e" 3707 + dependencies = [ 3708 + "audiopus_sys", 3709 + "libc", 3710 + ] 3668 3711 3669 3712 [[package]] 3670 3713 name = "orbclient"
+2
audio/Cargo.toml
··· 9 9 hound = "3.5.1" 10 10 kira = "0.11.0" 11 11 cpal = "0.16.0" 12 + opus = "0.3.0" 13 + felix-net = { path = '../net' }
+10 -11
audio/src/lib.rs
··· 4 4 5 5 use crate::source::FelixAudioSource; 6 6 7 + pub const SAMPLE_RATE: usize = 48_000; 8 + pub const BUFFER_SIZE: usize = 512; 9 + 10 + const MONO_20MS: usize = SAMPLE_RATE * 20 / 1000; 11 + 7 12 pub mod source; 8 13 pub mod utils; 14 + pub mod voice; 9 15 10 - fn update_listener_transform( 16 + fn update_audio_system( 11 17 mut audio_system: Query<&mut FelixAudioComponent>, 12 - listener: Query<(&FelixAudioListener, &Transform)> 18 + listener: Query<(&FelixAudioListener, &Transform)>, 19 + sources: Query<(&mut FelixAudioSource, &Transform)>, 13 20 ){ 14 21 let mut audio_system = audio_system.single_mut().expect("Cannot find FelixAudioComponent, has audio system been initialised?"); 15 22 let ( _, listener_transform ) = listener.single().expect("Cannot find FelixAudioListener."); 16 23 17 24 audio_system.main_listener.set_position(listener_transform.translation, Tween::default()); 18 25 audio_system.main_listener.set_orientation(listener_transform.rotation, Tween::default()); 19 - } 20 - 21 - fn update_audio_sources( 22 - mut audio_system: Query<&mut FelixAudioComponent>, 23 - sources: Query<(&mut FelixAudioSource, &Transform)>, 24 - ){ 25 - let mut audio_system = audio_system.single_mut().expect("Cannot find FelixAudioComponent, has audio system been initialised?"); 26 26 27 27 for ( mut source, transform ) in sources{ 28 28 if source.needs_init(){ ··· 65 65 commands.spawn(handle); 66 66 }); 67 67 68 - app.add_systems(Update, update_listener_transform); 69 - app.add_systems(Update, update_audio_sources); 68 + app.add_systems(Update, update_audio_system); 70 69 } 71 70 }
+34
audio/src/voice/decoder.rs
··· 1 + use std::{collections::VecDeque, sync::{Arc, Mutex, mpsc::{Sender, channel}}, thread}; 2 + 3 + use opus::{Channels, Decoder}; 4 + 5 + use crate::{MONO_20MS, SAMPLE_RATE}; 6 + 7 + pub struct VoiceChatDecoder{ 8 + stream_in: Sender<Vec<u8>> 9 + } 10 + 11 + impl VoiceChatDecoder{ 12 + pub fn new( queue: Arc<Mutex<VecDeque<f32>>> ) -> Self{ 13 + let mut decoder = Decoder::new(SAMPLE_RATE as u32, Channels::Mono).unwrap(); 14 + let ( stream_in, stream_out ) = channel(); 15 + 16 + thread::spawn(move || { 17 + let mut buffer = [0.0; MONO_20MS]; 18 + 19 + loop { 20 + let packet: Vec<u8> = stream_out.recv().unwrap(); 21 + decoder.decode_float(&packet, &mut buffer, false).unwrap(); 22 + 23 + let mut voice = queue.lock().unwrap(); 24 + for sample in buffer{ voice.push_back(sample); } 25 + } 26 + }); 27 + 28 + Self { stream_in } 29 + } 30 + 31 + pub fn decode( &self, packet: Vec<u8> ){ 32 + self.stream_in.send(packet).unwrap(); 33 + } 34 + }
+90
audio/src/voice/microphone.rs
··· 1 + use std::{env, net::{ToSocketAddrs, UdpSocket}, sync::{Arc, Mutex}}; 2 + 3 + use bevy::ecs::component::Component; 4 + use cpal::{BufferSize, SampleRate, Stream, StreamConfig, traits::{DeviceTrait, HostTrait, StreamTrait}}; 5 + use felix_net::{packet::Packet, packets::player_voice_packet::PlayerVoicePacket}; 6 + use opus::{Application, Channels, Encoder}; 7 + 8 + use crate::{BUFFER_SIZE, MONO_20MS, SAMPLE_RATE}; 9 + 10 + #[derive(Component)] 11 + pub struct VoiceChatMicrophone{ 12 + stream: Option<Stream>, 13 + udp: Option<UdpSocket>, 14 + muted: Arc<Mutex<bool>> 15 + } 16 + 17 + impl VoiceChatMicrophone{ 18 + pub fn new( socket: UdpSocket ) -> Self{ 19 + Self { 20 + stream: None, 21 + udp: Some(socket), 22 + muted: Arc::new(Mutex::new(false)) 23 + } 24 + } 25 + 26 + pub fn muted( &mut self, muted: bool ){ 27 + *self.muted.lock().unwrap() = muted; 28 + } 29 + 30 + pub fn start_stream( &mut self ) -> anyhow::Result<()>{ 31 + if let Some(stream) = &mut self.stream{ stream.pause().unwrap() } 32 + 33 + let mut encoder = Encoder::new(SAMPLE_RATE as u32, Channels::Mono, Application::Voip)?; 34 + 35 + let host = cpal::default_host(); 36 + let mic = host.default_input_device().unwrap(); 37 + 38 + let mut output = [0; 512]; 39 + 40 + let mut buffer_indx = 0; 41 + let mut buffer = [0; MONO_20MS]; 42 + 43 + let muted = self.muted.clone(); 44 + let udp = self.udp.take().unwrap(); 45 + 46 + let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap(); 47 + 48 + let stream = mic.build_input_stream( 49 + &StreamConfig { 50 + channels: 1, 51 + buffer_size: BufferSize::Fixed(BUFFER_SIZE as u32), 52 + sample_rate: SampleRate(SAMPLE_RATE as u32) 53 + }, 54 + move | data: &[ i16 ], _ | { 55 + let muted = *muted.lock().unwrap(); 56 + 57 + if muted{ 58 + buffer_indx = 0; 59 + } else{ 60 + for i in 0..data.len(){ 61 + buffer[buffer_indx] = data[i]; 62 + buffer_indx += 1; 63 + 64 + if buffer_indx >= MONO_20MS{ 65 + buffer_indx = 0; 66 + 67 + let len = encoder.encode(&buffer, &mut output).unwrap(); 68 + let buf_to_send = output[0..len].to_vec(); 69 + 70 + let packet = PlayerVoicePacket { 71 + id: "".into(), // NOTE: I know this kinda seems stupid but it's easier for me to get the player id on the server so imma just make the server fill this in. 72 + packet: buf_to_send 73 + }; 74 + 75 + let packet: Vec<u8> = packet.to_buf().into(); 76 + udp.send_to(&packet, addr).unwrap(); 77 + } 78 + } 79 + } 80 + }, 81 + | err | panic!("{err}"), 82 + None 83 + ).unwrap(); 84 + 85 + stream.play().unwrap(); 86 + self.stream = Some(stream); 87 + 88 + Ok(()) 89 + } 90 + }
+13
audio/src/voice/mod.rs
··· 1 + use std::net::UdpSocket; 2 + 3 + use crate::voice::microphone::VoiceChatMicrophone; 4 + 5 + pub mod decoder; 6 + pub mod microphone; 7 + 8 + pub fn init_microphone( socket: UdpSocket ) -> anyhow::Result<VoiceChatMicrophone>{ 9 + let mut handle = VoiceChatMicrophone::new(socket); 10 + handle.start_stream()?; 11 + 12 + Ok(handle) 13 + }
client/out.wav

This is a binary file and will not be displayed.

+18 -4
client/src/components/network_interface.rs
··· 1 1 use std::collections::HashMap; 2 2 3 3 use bevy::prelude::*; 4 + use felix_audio::{SAMPLE_RATE, source::{FelixAudioSource, stream_source::StreamAudioSource}}; 4 5 use felix_net::{packet::PacketTypes, packets::update_server_position::UpdateServerPositions}; 5 6 6 7 use crate::{debug_camera::DebugCamera, net::{NetClientCommand, connection::Connection}, remote_player::RemotePlayer}; 7 8 8 9 pub fn fixed_update( 9 10 mut query: Query<(&mut DebugCamera, &mut Transform)>, 11 + 10 12 mut networking: Query<&mut Connection>, 11 13 12 14 mut commands: Commands, ··· 24 26 }; 25 27 26 28 net_manager.try_send_unreliable(update_pos_packet).unwrap(); 27 - 28 29 29 30 if let Ok(ev) = net_manager.recv_event(){ 30 31 match ev{ ··· 37 38 NetClientCommand::RecvPacket(packet) => { 38 39 match packet{ 39 40 PacketTypes::PlayerJoinPacket(packet) => { 40 - join_players(vec![packet.id], &mut commands, &mut meshes, &mut materials); 41 + join_players(vec![packet.id], &mut commands, &mut meshes, &mut materials, &mut net_manager); 41 42 } 42 43 PacketTypes::PlayerListPacket(packet) => { 43 - join_players(packet.ids, &mut commands, &mut meshes, &mut materials); 44 + join_players(packet.ids, &mut commands, &mut meshes, &mut materials, &mut net_manager); 44 45 } 45 46 PacketTypes::PlayerLeavePacket(packet) => { 46 47 leave_player(packet.id, &mut commands, players); ··· 71 72 commands: &mut Commands, 72 73 meshes: &mut ResMut<Assets<Mesh>>, 73 74 materials: &mut ResMut<Assets<StandardMaterial>>, 75 + 76 + net_manager: &mut Connection 74 77 ){ 75 78 for id in players{ 79 + let listener = net_manager.start_listening_for_player_voice(&id); 80 + 76 81 commands.spawn(( 77 82 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), 78 83 MeshMaterial3d(materials.add(Color::WHITE)), 79 84 Transform::from_xyz(0.0, 0.0, 0.0), 80 - RemotePlayer { id, ..Default::default() } 85 + RemotePlayer { id, ..Default::default() }, 86 + FelixAudioSource::from(StreamAudioSource::new(SAMPLE_RATE, move | len | { 87 + let mut buf = vec![0.0; len]; 88 + let mut lock = listener.lock().unwrap(); 89 + 90 + for i in 0..buf.len(){ 91 + buf[i] = lock.pop_front().unwrap(); } 92 + 93 + buf 94 + })) 81 95 )); 82 96 } 83 97 }
+5 -2
client/src/main.rs
··· 1 1 use bevy::{DefaultPlugins, app::{App, FixedUpdate, Startup, Update}, ecs::system::Commands}; 2 - use felix_audio::FelixAudio; 2 + use felix_audio::{FelixAudio, voice}; 3 3 4 4 use crate::{components::{debug_camera, network_interface, remote_player}, setup::setup}; 5 5 ··· 17 17 )) 18 18 .add_systems(Startup, setup) 19 19 .add_systems(Startup, move | mut commands: Commands |{ 20 - commands.spawn(net::handle_net().expect("Network Module Failed.")); 20 + let ( comp, voice ) = net::handle_net().expect("Network Module Failed."); 21 + 22 + commands.spawn(comp); 23 + commands.spawn(voice::init_microphone(voice).expect("Failed to start microphone.")); 21 24 }) 22 25 .add_systems(Update, debug_camera::update) 23 26 .add_systems(Update, remote_player::update)
+21 -3
client/src/net/connection.rs
··· 1 - use std::{io::{Read, Write}, net::{SocketAddr, TcpStream, UdpSocket}, thread}; 1 + use std::{collections::{HashMap, VecDeque}, io::{Read, Write}, net::{SocketAddr, TcpStream, UdpSocket}, sync::{Arc, Mutex, RwLock}, thread}; 2 2 use bevy::ecs::component::Component; 3 + use felix_audio::voice::decoder::VoiceChatDecoder; 3 4 use tokio::sync::broadcast::{self, Receiver, Sender}; 4 5 5 6 use felix_net::{buffer::Buffer, packet::{self, Packet, PacketTypes}, packets::{link_udp::LinkUDP, notify_connection_info::NotifyConnectionInfo}}; 6 7 7 8 use crate::net::NetClientCommand; 8 9 9 - 10 - #[derive(Component, Debug)] 10 + #[derive(Component)] 11 11 pub struct Connection{ 12 12 tcp: TcpStream, 13 13 ··· 16 16 17 17 net_recv: Receiver<NetClientCommand>, 18 18 19 + voice_queues: Arc<RwLock<HashMap<String, VoiceChatDecoder>>>, 19 20 pub id: String 20 21 } 21 22 ··· 31 32 32 33 net_recv: event_recv, 33 34 35 + voice_queues: Arc::new(RwLock::new(HashMap::new())), 34 36 id: "".to_owned() 35 37 }; 36 38 ··· 50 52 let cmd_1 = cmd.clone(); 51 53 52 54 let srv_addr = self.udp_server_address.clone(); 55 + let voice_queues = self.voice_queues.clone(); 53 56 54 57 thread::spawn(move || { // UDP RECV THREAD 55 58 let mut buf = [0; 1024]; ··· 86 89 87 90 udp.send_to(&packet, "127.0.0.1:2603").unwrap(); 88 91 }, 92 + PacketTypes::PlayerVoicePacket(packet) => { 93 + let voices = voice_queues.read().unwrap(); 94 + if let Some(decoder) = voices.get(&packet.id){ 95 + decoder.decode(packet.packet); } 96 + }, 89 97 _ => { 90 98 cmd.send(NetClientCommand::RecvPacket(packet)).unwrap(); 91 99 } ··· 97 105 }); 98 106 99 107 Ok(()) 108 + } 109 + 110 + pub fn start_listening_for_player_voice( &mut self, id: &String ) -> Arc<Mutex<VecDeque<f32>>>{ 111 + let voice_queue = Arc::new(Mutex::new(VecDeque::new())); 112 + let decoder = VoiceChatDecoder::new(voice_queue.clone()); 113 + 114 + let mut voices = self.voice_queues.write().unwrap(); 115 + voices.insert(id.clone(), decoder); 116 + 117 + voice_queue 100 118 } 101 119 102 120 pub fn recv_event(&mut self) -> anyhow::Result<NetClientCommand>{
+3 -3
client/src/net/mod.rs
··· 14 14 RecvPacket(PacketTypes) 15 15 } 16 16 17 - pub fn handle_net() -> anyhow::Result<Connection>{ 17 + pub fn handle_net() -> anyhow::Result<( Connection, UdpSocket )>{ 18 18 let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap(); 19 19 20 20 let tcp = TcpStream::connect(addr)?; 21 21 let udp = UdpSocket::bind("0.0.0.0:0")?; 22 22 23 - let conn = Connection::new(tcp, udp, addr); 24 - Ok(conn) 23 + let conn = Connection::new(tcp, udp.try_clone().unwrap(), addr); 24 + Ok((conn, udp)) 25 25 }
+1 -10
client/src/setup.rs
··· 1 1 use bevy::prelude::*; 2 - use felix_audio::{FelixAudioListener, source::{FelixAudioSource, stream_source::StreamAudioSource}, utils::wav}; 2 + use felix_audio::FelixAudioListener; 3 3 4 4 use crate::debug_camera; 5 5 ··· 8 8 mut meshes: ResMut<Assets<Mesh>>, 9 9 mut materials: ResMut<Assets<StandardMaterial>> 10 10 ){ 11 - let samples = wav::load_wav_file("out.wav"); 12 - let mut samples_index = 0; 13 - 14 11 commands.spawn(( 15 12 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), 16 13 MeshMaterial3d(materials.add(Color::WHITE)), 17 14 Transform::from_xyz(5.0, 0.0, 0.0), 18 - FelixAudioSource::from(StreamAudioSource::new(48_000, move | length | { 19 - let mono = &samples[samples_index..(samples_index + length)]; 20 - samples_index += length; 21 - 22 - mono.to_vec() 23 - })) 24 15 )); 25 16 26 17 commands.spawn((
+6 -2
net/src/packet.rs
··· 1 1 use crate::{ 2 2 buffer::Buffer, 3 3 packets::{ 4 - link_udp::LinkUDP, notify_connection_info::NotifyConnectionInfo, null::Null, player_join_packet::PlayerJoinPacket, player_leave_packet::PlayerLeavePacket, player_list_packet::PlayerListPacket, update_clients_positions::UpdateClientsPositions, update_server_position::UpdateServerPositions 4 + link_udp::LinkUDP, notify_connection_info::NotifyConnectionInfo, null::Null, player_join_packet::PlayerJoinPacket, player_leave_packet::PlayerLeavePacket, player_list_packet::PlayerListPacket, player_voice_packet::PlayerVoicePacket, update_clients_positions::UpdateClientsPositions, update_server_position::UpdateServerPositions 5 5 } 6 6 }; 7 7 ··· 16 16 PlayerJoinPacket(PlayerJoinPacket), 17 17 PlayerListPacket(PlayerListPacket), 18 18 PlayerLeavePacket(PlayerLeavePacket), 19 + 20 + PlayerVoicePacket(PlayerVoicePacket), 19 21 20 22 Null(Null) 21 23 } 22 24 23 25 pub trait Packet{ 24 26 fn from_buf(buf: &mut Buffer) -> Self; 25 - fn to_buf(&self) -> Buffer; 27 + fn to_buf(self) -> Buffer; 26 28 } 27 29 28 30 pub fn parse(buf: &mut Buffer) -> PacketTypes{ ··· 38 40 3 => PacketTypes::PlayerJoinPacket(PlayerJoinPacket::from_buf(buf)), 39 41 4 => PacketTypes::PlayerListPacket(PlayerListPacket::from_buf(buf)), 40 42 5 => PacketTypes::PlayerLeavePacket(PlayerLeavePacket::from_buf(buf)), 43 + 44 + 7 => PacketTypes::PlayerVoicePacket(PlayerVoicePacket::from_buf(buf)), 41 45 42 46 _ => PacketTypes::Null(Null::from_buf(buf)) 43 47 }
+2
net/src/packets/mod.rs
··· 8 8 pub mod player_list_packet; 9 9 pub mod player_leave_packet; 10 10 11 + pub mod player_voice_packet; 12 + 11 13 pub mod null;
+1 -1
net/src/packets/notify_connection_info.rs
··· 6 6 } 7 7 8 8 impl Packet for NotifyConnectionInfo{ 9 - fn to_buf(&self) -> Buffer { 9 + fn to_buf(self) -> Buffer { 10 10 let mut buf = Buffer::empty(); 11 11 buf.set_u16(0); 12 12 buf.set_str(self.id.clone());
+1 -1
net/src/packets/null.rs
··· 4 4 pub struct Null; 5 5 6 6 impl Packet for Null{ 7 - fn to_buf(&self) -> Buffer { 7 + fn to_buf(self) -> Buffer { 8 8 Buffer::empty() 9 9 } 10 10
+1 -1
net/src/packets/player_join_packet.rs
··· 6 6 } 7 7 8 8 impl Packet for PlayerJoinPacket{ 9 - fn to_buf(&self) -> Buffer { 9 + fn to_buf(self) -> Buffer { 10 10 let mut buf = Buffer::empty(); 11 11 buf.set_u16(3); 12 12 buf.set_str(self.id.clone());
+1 -1
net/src/packets/player_leave_packet.rs
··· 6 6 } 7 7 8 8 impl Packet for PlayerLeavePacket{ 9 - fn to_buf(&self) -> Buffer { 9 + fn to_buf(self) -> Buffer { 10 10 let mut buf = Buffer::empty(); 11 11 buf.set_u16(5); 12 12 buf.set_str(self.id.clone());
+1 -1
net/src/packets/player_list_packet.rs
··· 6 6 } 7 7 8 8 impl Packet for PlayerListPacket{ 9 - fn to_buf(&self) -> Buffer { 9 + fn to_buf(self) -> Buffer { 10 10 let mut buf = Buffer::empty(); 11 11 buf.set_u16(4); 12 12 buf.set_u32(self.ids.len() as u32);
+30
net/src/packets/player_voice_packet.rs
··· 1 + use crate::{buffer::Buffer, packet::Packet}; 2 + 3 + #[derive(Debug, Clone)] 4 + pub struct PlayerVoicePacket{ 5 + pub id: String, 6 + pub packet: Vec<u8> 7 + } 8 + 9 + impl Packet for PlayerVoicePacket{ 10 + fn to_buf(self) -> Buffer { 11 + let mut buf = Buffer::empty(); 12 + buf.set_u16(7); 13 + 14 + buf.set_str(self.id); 15 + 16 + buf.set_u32(self.packet.len() as u32); 17 + buf.set_u8s(&self.packet); 18 + 19 + buf 20 + } 21 + 22 + fn from_buf(buf: &mut Buffer) -> Self { 23 + let id = buf.get_str(); 24 + 25 + let length = buf.get_u32(); 26 + let packet = buf.get_u8s(length as usize).to_vec(); 27 + 28 + Self { id, packet } 29 + } 30 + }
+1 -1
net/src/packets/update_clients_positions.rs
··· 8 8 } 9 9 10 10 impl Packet for UpdateClientsPositions{ 11 - fn to_buf(&self) -> Buffer { 11 + fn to_buf(self) -> Buffer { 12 12 let mut buf = Buffer::empty(); 13 13 buf.set_u16(6); 14 14 buf.set_u32(self.players.len() as u32);
+1 -1
net/src/packets/update_server_position.rs
··· 9 9 } 10 10 11 11 impl Packet for UpdateServerPositions{ 12 - fn to_buf(&self) -> Buffer { 12 + fn to_buf(self) -> Buffer { 13 13 let mut buf = Buffer::empty(); 14 14 buf.set_u16(2); 15 15
+1
server/Cargo.toml
··· 8 8 bevy_math = "0.17.3" 9 9 dotenvy = "0.15.7" 10 10 felix-net = { path = '../net' } 11 + kanal = "0.1.1" 11 12 nanoid = "0.4.0"
+6 -1
server/src/net/connection.rs
··· 1 - use std::{io::{Read, Write}, net::{SocketAddr, TcpStream}, sync::mpsc::Sender, thread}; 1 + use std::{io::{Read, Write}, net::{SocketAddr, TcpStream}, thread}; 2 2 3 3 use bevy_math::{Quat, Vec3}; 4 4 use felix_net::{buffer::Buffer, packet::{self, Packet, PacketTypes}, packets::notify_connection_info::NotifyConnectionInfo}; 5 + use kanal::Sender; 5 6 use nanoid::nanoid; 6 7 7 8 use crate::net::NetServerCommand; ··· 72 73 PacketTypes::UpdateServerPositions(packet) => { 73 74 self.position = packet.position; 74 75 self.rotation = packet.rotation; 76 + }, 77 + PacketTypes::PlayerVoicePacket(mut voice) => { 78 + voice.id = self.id.clone(); // NOTE: See "audio/src/voice/microphone.rs:71" 79 + self.main_thread_sender.send(NetServerCommand::BroadcastVoice(voice)).unwrap(); 75 80 }, 76 81 _ => {} 77 82 }
+10 -4
server/src/net/mod.rs
··· 1 - use std::{collections::HashMap, env, net::{SocketAddr, TcpListener, TcpStream, UdpSocket}, sync::mpsc::channel, thread, time::Duration}; 1 + use std::{collections::HashMap, env, net::{SocketAddr, TcpListener, TcpStream, UdpSocket}, thread, time::Duration}; 2 2 3 - use felix_net::{buffer::Buffer, packet::{self, PacketTypes}, packets::{player_join_packet::PlayerJoinPacket, player_leave_packet::PlayerLeavePacket, player_list_packet::PlayerListPacket, update_clients_positions::UpdateClientsPositions}}; 3 + use felix_net::{buffer::Buffer, packet::{self, PacketTypes}, packets::{player_join_packet::PlayerJoinPacket, player_leave_packet::PlayerLeavePacket, player_list_packet::PlayerListPacket, player_voice_packet::PlayerVoicePacket, update_clients_positions::UpdateClientsPositions}}; 4 4 5 5 use crate::net::connection::Connection; 6 6 7 7 mod connection; 8 8 9 - #[derive(Debug)] 10 9 pub enum NetServerCommand{ 11 10 CreateConnection(TcpStream), 12 11 LinkUDP(String, SocketAddr), ··· 14 13 SendOverUDP(Vec<u8>, SocketAddr), 15 14 RecvOverUDP(SocketAddr, PacketTypes), 16 15 RecvOverTCP(String, PacketTypes), 16 + BroadcastVoice(PlayerVoicePacket), 17 17 BroadcastPlayerPositions 18 18 } 19 19 ··· 25 25 let udp_listener = UdpSocket::bind(format!("0.0.0.0:{}", port))?; 26 26 let udp_listener_1 = udp_listener.try_clone()?; 27 27 28 - let ( sender, recv ) = channel(); 28 + let ( sender, recv ) = kanal::unbounded(); 29 29 let sender_1 = sender.clone(); 30 30 let sender_2 = sender.clone(); 31 31 let sender_3 = sender.clone(); ··· 130 130 131 131 for (_, conn) in &mut connections{ 132 132 conn.try_send_unreliable(packet.clone())?; } 133 + }, 134 + NetServerCommand::BroadcastVoice(packet) => { 135 + for ( remote_id, conn ) in &mut connections{ 136 + if remote_id == &packet.id { continue; } 137 + conn.try_send_unreliable(packet.clone())?; 138 + } 133 139 } 134 140 } 135 141 }