diff --git a/alvr/client_core/src/connection.rs b/alvr/client_core/src/connection.rs index 55af7356ce..c471677c09 100644 --- a/alvr/client_core/src/connection.rs +++ b/alvr/client_core/src/connection.rs @@ -251,6 +251,7 @@ fn connection_pipeline( Duration::from_secs(1), settings.connection.stream_port, settings.connection.stream_protocol, + settings.connection.dscp, settings.connection.client_send_buffer_bytes, settings.connection.client_recv_buffer_bytes, ) diff --git a/alvr/server/src/connection.rs b/alvr/server/src/connection.rs index e60b70b0fd..d3f579a22f 100644 --- a/alvr/server/src/connection.rs +++ b/alvr/server/src/connection.rs @@ -538,6 +538,7 @@ fn connection_pipeline( client_ip, settings.connection.stream_port, settings.connection.stream_protocol, + settings.connection.dscp, settings.connection.server_send_buffer_bytes, settings.connection.server_recv_buffer_bytes, settings.connection.packet_size as _, diff --git a/alvr/session/src/settings.rs b/alvr/session/src/settings.rs index 76e2c91b48..b01c09d05f 100644 --- a/alvr/session/src/settings.rs +++ b/alvr/session/src/settings.rs @@ -942,6 +942,8 @@ TCP: Slower than UDP, but more stable. Pick this if you experience video or audi pub web_server_port: u16, pub osc_local_port: u16, + pub dscp: Option, + #[schema(strings(display_name = "Streamer send buffer size"))] pub server_send_buffer_bytes: SocketBufferSize, @@ -990,6 +992,30 @@ For now works only on Windows+Nvidia"# pub statistics_history_size: usize, } +#[derive(SettingsSchema, Serialize, Deserialize, Clone)] +#[repr(u8)] +#[schema(gui = "button_group")] +pub enum DropProbability { + Low = 0x01, + Medium = 0x10, + High = 0x11, +} + +#[derive(SettingsSchema, Serialize, Deserialize, Clone)] +pub enum DscpTos { + BestEffort, + + ClassSelector(#[schema(gui(slider(min = 1, max = 7)))] u8), + + AssuredForwarding { + #[schema(gui(slider(min = 1, max = 4)))] + class: u8, + drop_probability: DropProbability, + }, + + ExpeditedForwarding, +} + #[derive(SettingsSchema, Serialize, Deserialize, Clone)] pub struct RawEventsConfig { #[schema(flag = "real-time")] @@ -1140,7 +1166,7 @@ pub fn session_settings_default() -> SettingsDefault { ConstantMbps: 30, Adaptive: BitrateModeAdaptiveDefault { gui_collapsed: true, - saturation_multiplier: 1.0, + saturation_multiplier: 0.95, max_bitrate_mbps: SwitchDefault { enabled: false, content: 100, @@ -1512,6 +1538,19 @@ pub fn session_settings_default() -> SettingsDefault { web_server_port: 8082, stream_port: 9944, osc_local_port: 9942, + dscp: OptionalDefault { + set: false, + content: DscpTosDefault { + ClassSelector: 7, + AssuredForwarding: DscpTosAssuredForwardingDefault { + class: 4, + drop_probability: DropProbabilityDefault { + variant: DropProbabilityDefaultVariant::Low, + }, + }, + variant: DscpTosDefaultVariant::ExpeditedForwarding, + }, + }, server_send_buffer_bytes: socket_buffer.clone(), server_recv_buffer_bytes: socket_buffer.clone(), client_send_buffer_bytes: socket_buffer.clone(), diff --git a/alvr/sockets/src/backend/tcp.rs b/alvr/sockets/src/backend/tcp.rs index 5dc3017c29..d9383c8660 100644 --- a/alvr/sockets/src/backend/tcp.rs +++ b/alvr/sockets/src/backend/tcp.rs @@ -2,7 +2,7 @@ use crate::LOCAL_IP; use super::{SocketReader, SocketWriter}; use alvr_common::{anyhow::Result, con_bail, ConResult, HandleTryAgain, ToCon}; -use alvr_session::SocketBufferSize; +use alvr_session::{DscpTos, SocketBufferSize}; use std::{ io::Read, io::Write, @@ -13,12 +13,16 @@ use std::{ pub fn bind( timeout: Duration, port: u16, + dscp: Option, send_buffer_bytes: SocketBufferSize, recv_buffer_bytes: SocketBufferSize, ) -> Result { let socket = TcpListener::bind((LOCAL_IP, port))?.into(); crate::set_socket_buffers(&socket, send_buffer_bytes, recv_buffer_bytes).ok(); + + crate::set_dscp(&socket, dscp); + socket.set_read_timeout(Some(timeout))?; Ok(socket.into()) diff --git a/alvr/sockets/src/backend/udp.rs b/alvr/sockets/src/backend/udp.rs index c8928f02ec..f0071106de 100644 --- a/alvr/sockets/src/backend/udp.rs +++ b/alvr/sockets/src/backend/udp.rs @@ -2,7 +2,7 @@ use crate::LOCAL_IP; use super::{SocketReader, SocketWriter}; use alvr_common::{anyhow::Result, ConResult, HandleTryAgain}; -use alvr_session::SocketBufferSize; +use alvr_session::{DscpTos, SocketBufferSize}; use socket2::{MaybeUninitSlice, Socket}; use std::{ ffi::c_int, @@ -15,6 +15,7 @@ use std::{ // let tokio set all the internal parameters it needs from the start. pub fn bind( port: u16, + dscp: Option, send_buffer_bytes: SocketBufferSize, recv_buffer_bytes: SocketBufferSize, ) -> Result { @@ -22,6 +23,8 @@ pub fn bind( crate::set_socket_buffers(&socket, send_buffer_bytes, recv_buffer_bytes).ok(); + crate::set_dscp(&socket, dscp); + Ok(socket.into()) } diff --git a/alvr/sockets/src/control_socket.rs b/alvr/sockets/src/control_socket.rs index 9209f266a7..62c6d0852d 100644 --- a/alvr/sockets/src/control_socket.rs +++ b/alvr/sockets/src/control_socket.rs @@ -127,6 +127,7 @@ pub fn get_server_listener(timeout: Duration) -> Result { let listener = tcp::bind( timeout, CONTROL_PORT, + None, SocketBufferSize::Default, SocketBufferSize::Default, )?; diff --git a/alvr/sockets/src/lib.rs b/alvr/sockets/src/lib.rs index 2631431f38..3424317479 100644 --- a/alvr/sockets/src/lib.rs +++ b/alvr/sockets/src/lib.rs @@ -3,7 +3,8 @@ mod control_socket; mod stream_socket; use alvr_common::{anyhow::Result, info}; -use alvr_session::SocketBufferSize; +use alvr_session::{DscpTos, SocketBufferSize}; +use socket2::Socket; use std::{ net::{IpAddr, Ipv4Addr}, time::Duration, @@ -69,3 +70,20 @@ fn set_socket_buffers( Ok(()) } + +fn set_dscp(socket: &Socket, dscp: Option) { + // https://en.wikipedia.org/wiki/Differentiated_services + if let Some(dscp) = dscp { + let tos = match dscp { + DscpTos::BestEffort => 0, + DscpTos::ClassSelector(precedence) => precedence << 3, + DscpTos::AssuredForwarding { + class, + drop_probability, + } => (class << 3) | drop_probability as u8, + DscpTos::ExpeditedForwarding => 0b101110, + }; + + socket.set_tos((tos << 2) as u32).ok(); + } +} diff --git a/alvr/sockets/src/stream_socket.rs b/alvr/sockets/src/stream_socket.rs index 83e2c27129..ce882fc47d 100644 --- a/alvr/sockets/src/stream_socket.rs +++ b/alvr/sockets/src/stream_socket.rs @@ -20,7 +20,7 @@ use crate::backend::{tcp, udp, SocketReader, SocketWriter}; use alvr_common::{ anyhow::Result, debug, parking_lot::Mutex, AnyhowToCon, ConResult, HandleTryAgain, ToCon, }; -use alvr_session::{SocketBufferSize, SocketProtocol}; +use alvr_session::{DscpTos, SocketBufferSize, SocketProtocol}; use serde::{de::DeserializeOwned, Serialize}; use std::{ cmp::Ordering, @@ -271,16 +271,21 @@ impl StreamSocketBuilder { timeout: Duration, port: u16, stream_socket_config: SocketProtocol, + stream_tos_config: Option, send_buffer_bytes: SocketBufferSize, recv_buffer_bytes: SocketBufferSize, ) -> Result { Ok(match stream_socket_config { - SocketProtocol::Udp => { - StreamSocketBuilder::Udp(udp::bind(port, send_buffer_bytes, recv_buffer_bytes)?) - } + SocketProtocol::Udp => StreamSocketBuilder::Udp(udp::bind( + port, + stream_tos_config, + send_buffer_bytes, + recv_buffer_bytes, + )?), SocketProtocol::Tcp => StreamSocketBuilder::Tcp(tcp::bind( timeout, port, + stream_tos_config, send_buffer_bytes, recv_buffer_bytes, )?), @@ -327,6 +332,7 @@ impl StreamSocketBuilder { client_ip: IpAddr, port: u16, protocol: SocketProtocol, + dscp: Option, send_buffer_bytes: SocketBufferSize, recv_buffer_bytes: SocketBufferSize, max_packet_size: usize, @@ -334,7 +340,8 @@ impl StreamSocketBuilder { let (send_socket, receive_socket): (Box, Box) = match protocol { SocketProtocol::Udp => { - let socket = udp::bind(port, send_buffer_bytes, recv_buffer_bytes).to_con()?; + let socket = + udp::bind(port, dscp, send_buffer_bytes, recv_buffer_bytes).to_con()?; let (send_socket, receive_socket) = udp::connect(&socket, client_ip, port, timeout).to_con()?;