diff --git a/alvr/client_core/src/c_api.rs b/alvr/client_core/src/c_api.rs index 7488b4bfe9..78599008d3 100644 --- a/alvr/client_core/src/c_api.rs +++ b/alvr/client_core/src/c_api.rs @@ -25,6 +25,7 @@ use std::{ static CLIENT_CORE_CONTEXT: OptLazy = alvr_common::lazy_mut_none(); static HUD_MESSAGE: Lazy> = Lazy::new(|| Mutex::new("".into())); static SETTINGS: Lazy> = Lazy::new(|| Mutex::new("".into())); +static SERVER_VERSION: Lazy> = Lazy::new(|| Mutex::new("".into())); #[allow(clippy::type_complexity)] static NAL_QUEUE: Lazy)>>> = Lazy::new(|| Mutex::new(VecDeque::new())); @@ -310,17 +311,17 @@ pub extern "C" fn alvr_poll_event(out_event: *mut AlvrEvent) -> bool { AlvrEvent::HudMessageUpdated } - ClientCoreEvent::StreamingStarted { - settings, - negotiated_config, - } => { - *SETTINGS.lock() = serde_json::to_string(&settings).unwrap(); + ClientCoreEvent::StreamingStarted(stream_config) => { + *SETTINGS.lock() = serde_json::to_string(&stream_config.settings).unwrap(); + *SERVER_VERSION.lock() = stream_config.server_version.to_string(); AlvrEvent::StreamingStarted { - view_width: negotiated_config.view_resolution.x, - view_height: negotiated_config.view_resolution.y, - refresh_rate_hint: negotiated_config.refresh_rate_hint, - enable_foveated_encoding: negotiated_config.enable_foveated_encoding, + view_width: stream_config.negotiated_config.view_resolution.x, + view_height: stream_config.negotiated_config.view_resolution.y, + refresh_rate_hint: stream_config.negotiated_config.refresh_rate_hint, + enable_foveated_encoding: stream_config + .negotiated_config + .enable_foveated_encoding, } } ClientCoreEvent::StreamingStopped => AlvrEvent::StreamingStopped, @@ -378,6 +379,12 @@ pub extern "C" fn alvr_get_settings_json(buffer: *mut c_char) -> u64 { string_to_c_str(buffer, &SETTINGS.lock()) } +/// Will be updated after receiving StreamingStarted event +#[no_mangle] +pub extern "C" fn alvr_get_server_version(buffer: *mut c_char) -> u64 { + string_to_c_str(buffer, &SERVER_VERSION.lock()) +} + /// Call only with external decoder /// Returns the number of bytes of the next nal, or 0 if there are no nals ready. /// If out_nal or out_timestamp_ns is null, no nal is dequeued. Use to get the nal allocation size. diff --git a/alvr/client_core/src/connection.rs b/alvr/client_core/src/connection.rs index 2ec2b3b108..6baa13dff3 100644 --- a/alvr/client_core/src/connection.rs +++ b/alvr/client_core/src/connection.rs @@ -190,16 +190,15 @@ fn connection_pipeline( proto_control_socket.recv::(HANDSHAKE_ACTION_TIMEOUT)?; dbg_connection!("connection_pipeline: stream config received"); - let (settings, negotiated_config) = - alvr_packets::decode_stream_config(&config_packet).to_con()?; + let stream_config = alvr_packets::decode_stream_config(&config_packet).to_con()?; ctx.uses_multimodal_protocol - .set(negotiated_config.use_multimodal_protocol); + .set(stream_config.negotiated_config.use_multimodal_protocol); - let streaming_start_event = ClientCoreEvent::StreamingStarted { - settings: Box::new(settings.clone()), - negotiated_config: negotiated_config.clone(), - }; + let streaming_start_event = ClientCoreEvent::StreamingStarted(Box::new(stream_config.clone())); + + let settings = stream_config.settings; + let negotiated_config = stream_config.negotiated_config; *ctx.statistics_manager.lock() = Some(StatisticsManager::new( settings.connection.statistics_history_size, diff --git a/alvr/client_core/src/lib.rs b/alvr/client_core/src/lib.rs index 7eb2844d5d..23a8dffce9 100644 --- a/alvr/client_core/src/lib.rs +++ b/alvr/client_core/src/lib.rs @@ -27,10 +27,10 @@ use alvr_common::{ HEAD_ID, }; use alvr_packets::{ - BatteryInfo, ButtonEntry, ClientControlPacket, FaceData, NegotiatedStreamingConfig, - ReservedClientControlPacket, Tracking, ViewParams, ViewsConfig, + BatteryInfo, ButtonEntry, ClientControlPacket, FaceData, ReservedClientControlPacket, + StreamConfig, Tracking, ViewParams, ViewsConfig, }; -use alvr_session::{CodecType, Settings}; +use alvr_session::CodecType; use connection::ConnectionContext; use serde::{Deserialize, Serialize}; use std::{ @@ -56,10 +56,7 @@ pub fn platform() -> Platform { #[derive(Serialize, Deserialize)] pub enum ClientCoreEvent { UpdateHudMessage(String), - StreamingStarted { - settings: Box, - negotiated_config: NegotiatedStreamingConfig, - }, + StreamingStarted(Box), StreamingStopped, Haptics { device_id: u64, diff --git a/alvr/client_mock/src/main.rs b/alvr/client_mock/src/main.rs index 3d0cf62cb6..05c6d93a1d 100644 --- a/alvr/client_mock/src/main.rs +++ b/alvr/client_mock/src/main.rs @@ -264,12 +264,10 @@ fn client_thread( ClientCoreEvent::UpdateHudMessage(message) => { window_output.hud_message = message; } - ClientCoreEvent::StreamingStarted { - negotiated_config, .. - } => { - window_output.fps = negotiated_config.refresh_rate_hint; + ClientCoreEvent::StreamingStarted(config) => { + window_output.fps = config.negotiated_config.refresh_rate_hint; window_output.connected = true; - window_output.resolution = negotiated_config.view_resolution; + window_output.resolution = config.negotiated_config.view_resolution; let context = Arc::clone(&client_core_context); let streaming = Arc::clone(&streaming); @@ -278,7 +276,7 @@ fn client_thread( tracking_thread( context, streaming, - negotiated_config.refresh_rate_hint, + config.negotiated_config.refresh_rate_hint, input, ) })); diff --git a/alvr/client_openxr/src/lib.rs b/alvr/client_openxr/src/lib.rs index 0723b61424..1aa7ed87e8 100644 --- a/alvr/client_openxr/src/lib.rs +++ b/alvr/client_openxr/src/lib.rs @@ -5,7 +5,7 @@ mod interaction; mod lobby; mod stream; -use crate::stream::StreamConfig; +use crate::stream::ParsedStreamConfig; use alvr_client_core::{ graphics::GraphicsContext, ClientCapabilities, ClientCoreContext, ClientCoreEvent, Platform, }; @@ -201,7 +201,7 @@ pub fn entry_point() { let graphics_context = Rc::new(GraphicsContext::new_gl()); let mut last_lobby_message = String::new(); - let mut stream_config = None::; + let mut parsed_stream_config = None::; 'session_loop: loop { let xr_system = xr_instance @@ -263,14 +263,14 @@ pub fn entry_point() { let interaction_context = Arc::new(interaction::initialize_interaction( &xr_context, platform, - stream_config + parsed_stream_config .as_ref() .map(|c| c.prefers_multimodal_input) .unwrap_or(false), - stream_config + parsed_stream_config .as_ref() .and_then(|c| c.face_sources_config.clone()), - stream_config + parsed_stream_config .as_ref() .and_then(|c| c.body_sources_config.clone()), )); @@ -356,22 +356,19 @@ pub fn entry_point() { last_lobby_message.clone_from(&message); lobby.update_hud_message(&message); } - ClientCoreEvent::StreamingStarted { - settings, - negotiated_config, - } => { - let new_config = StreamConfig::new(&settings, negotiated_config); + ClientCoreEvent::StreamingStarted(config) => { + let new_config = ParsedStreamConfig::new(&*config); // combined_eye_gaze is a setting that needs to be enabled at session // creation. Since HTC headsets don't support session reinitialization, skip // all elements that need it, that is face and eye tracking. - if stream_config.as_ref() != Some(&new_config) + if parsed_stream_config.as_ref() != Some(&new_config) && !matches!( platform, Platform::Focus3 | Platform::XRElite | Platform::ViveUnknown ) { - stream_config = Some(new_config); + parsed_stream_config = Some(new_config); xr_session.request_exit().ok(); } else { @@ -384,7 +381,7 @@ pub fn entry_point() { &new_config, )); - stream_config = Some(new_config); + parsed_stream_config = Some(new_config); } } ClientCoreEvent::StreamingStopped => { diff --git a/alvr/client_openxr/src/stream.rs b/alvr/client_openxr/src/stream.rs index 23966c2a9b..86da7e362b 100644 --- a/alvr/client_openxr/src/stream.rs +++ b/alvr/client_openxr/src/stream.rs @@ -13,10 +13,10 @@ use alvr_common::{ glam::{UVec2, Vec2}, Pose, RelaxedAtomic, HAND_LEFT_ID, HAND_RIGHT_ID, }; -use alvr_packets::{FaceData, NegotiatedStreamingConfig, ViewParams}; +use alvr_packets::{FaceData, StreamConfig, ViewParams}; use alvr_session::{ BodyTrackingSourcesConfig, ClientsideFoveationConfig, ClientsideFoveationMode, EncoderConfig, - FaceTrackingSourcesConfig, FoveatedEncodingConfig, Settings, + FaceTrackingSourcesConfig, FoveatedEncodingConfig, }; use openxr as xr; use std::{ @@ -30,7 +30,7 @@ use std::{ const MAX_PREDICTION: Duration = Duration::from_millis(70); #[derive(PartialEq)] -pub struct StreamConfig { +pub struct ParsedStreamConfig { pub view_resolution: UVec2, pub refresh_rate_hint: f32, pub foveated_encoding_config: Option, @@ -41,28 +41,37 @@ pub struct StreamConfig { pub prefers_multimodal_input: bool, } -impl StreamConfig { - pub fn new(settings: &Settings, negotiated_config: NegotiatedStreamingConfig) -> StreamConfig { - StreamConfig { - view_resolution: negotiated_config.view_resolution, - refresh_rate_hint: negotiated_config.refresh_rate_hint, - foveated_encoding_config: negotiated_config +impl ParsedStreamConfig { + pub fn new(config: &StreamConfig) -> ParsedStreamConfig { + ParsedStreamConfig { + view_resolution: config.negotiated_config.view_resolution, + refresh_rate_hint: config.negotiated_config.refresh_rate_hint, + foveated_encoding_config: config + .negotiated_config .enable_foveated_encoding - .then(|| settings.video.foveated_encoding.as_option().cloned()) + .then(|| config.settings.video.foveated_encoding.as_option().cloned()) .flatten(), - clientside_foveation_config: settings.video.clientside_foveation.as_option().cloned(), - encoder_config: settings.video.encoder_config.clone(), - face_sources_config: settings + clientside_foveation_config: config + .settings + .video + .clientside_foveation + .as_option() + .cloned(), + encoder_config: config.settings.video.encoder_config.clone(), + face_sources_config: config + .settings .headset .face_tracking .as_option() .map(|c| c.sources.clone()), - body_sources_config: settings + body_sources_config: config + .settings .headset .body_tracking .as_option() .map(|c| c.sources.clone()), - prefers_multimodal_input: settings + prefers_multimodal_input: config + .settings .headset .controllers .as_option() @@ -93,7 +102,7 @@ impl StreamContext { gfx_ctx: Rc, interaction_ctx: Arc, platform: Platform, - config: &StreamConfig, + config: &ParsedStreamConfig, ) -> StreamContext { if xr_ctx.instance.exts().fb_display_refresh_rate.is_some() { xr_ctx diff --git a/alvr/packets/src/lib.rs b/alvr/packets/src/lib.rs index 9d2d0c911a..131698af9e 100644 --- a/alvr/packets/src/lib.rs +++ b/alvr/packets/src/lib.rs @@ -1,6 +1,7 @@ use alvr_common::{ anyhow::Result, glam::{UVec2, Vec2}, + semver::Version, ConnectionState, DeviceMotion, Fov, LogEntry, LogSeverity, Pose, ToAny, }; use alvr_session::{CodecType, SessionConfig, Settings}; @@ -136,9 +137,14 @@ pub fn encode_stream_config( }) } -pub fn decode_stream_config( - packet: &StreamConfigPacket, -) -> Result<(Settings, NegotiatedStreamingConfig)> { +#[derive(Serialize, Deserialize, Clone)] +pub struct StreamConfig { + pub server_version: Version, + pub settings: Settings, + pub negotiated_config: NegotiatedStreamingConfig, +} + +pub fn decode_stream_config(packet: &StreamConfigPacket) -> Result { let mut session_config = SessionConfig::default(); session_config.merge_from_json(&json::from_str(&packet.session)?)?; let settings = session_config.to_settings(); @@ -155,16 +161,17 @@ pub fn decode_stream_config( let use_multimodal_protocol = json::from_value(negotiated_json["use_multimodal_protocol"].clone()).unwrap_or(false); - Ok(( + Ok(StreamConfig { + server_version: session_config.server_version, settings, - NegotiatedStreamingConfig { + negotiated_config: NegotiatedStreamingConfig { view_resolution, refresh_rate_hint, game_audio_sample_rate, enable_foveated_encoding, use_multimodal_protocol, }, - )) + }) } #[derive(Serialize, Deserialize, Clone)] diff --git a/alvr/session/src/settings.rs b/alvr/session/src/settings.rs index ae48c91f20..41b231c7e8 100644 --- a/alvr/session/src/settings.rs +++ b/alvr/session/src/settings.rs @@ -1011,7 +1011,7 @@ Tilted: the world gets tilted when long pressing the oculus button. This is usef pub body_tracking: Switch, } -#[derive(SettingsSchema, Serialize, Deserialize, Clone)] +#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)] #[schema(gui = "button_group")] pub enum SocketProtocol { #[schema(strings(display_name = "UDP"))] @@ -1028,7 +1028,7 @@ pub struct DiscoveryConfig { pub auto_trust_clients: bool, } -#[derive(SettingsSchema, Serialize, Deserialize, Clone)] +#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)] pub enum SocketBufferSize { Default, Maximum, @@ -1099,7 +1099,7 @@ This could happen on TCP. A IDR frame is requested in this case."# pub dscp: Option, } -#[derive(SettingsSchema, Serialize, Deserialize, Clone)] +#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)] #[repr(u8)] #[schema(gui = "button_group")] pub enum DropProbability { @@ -1108,7 +1108,7 @@ pub enum DropProbability { High = 0x11, } -#[derive(SettingsSchema, Serialize, Deserialize, Clone)] +#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)] pub enum DscpTos { BestEffort,