diff --git a/src/client.rs b/src/client.rs index a62f8717a..75c2b0422 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2872,7 +2872,6 @@ pub struct LoginConfigHandler { pub save_ab_password_to_recent: bool, // true: connected with ab password pub other_server: Option<(String, String, String)>, pub custom_fps: Arc>>, - pub last_auto_fps: Option, pub adapter_luid: Option, pub mark_unsupported: Vec, pub selected_windows_session_id: Option, diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 517628987..eeec5ad8a 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -98,6 +98,7 @@ pub struct Remote { elevation_requested: bool, peer_info: ParsedPeerInfo, video_threads: HashMap, + last_auto_fps: Option, chroma: Arc>>, last_record_state: bool, sent_close_reason: bool, @@ -150,6 +151,7 @@ impl Remote { elevation_requested: false, peer_info: Default::default(), video_threads: Default::default(), + last_auto_fps: None, chroma: Default::default(), last_record_state: false, sent_close_reason: false, @@ -382,7 +384,7 @@ impl Remote { self.video_threads.iter().for_each(|(_, v)| { *v.frame_count.write().unwrap() = 0; }); - self.fps_control(direct, fps.clone()); + self.fps_control(direct, fps.clone(), &mut peer).await; let chroma = self.chroma.read().unwrap().clone(); let chroma = match chroma { Some(Chroma::I444) => "4:4:4", @@ -787,6 +789,11 @@ impl Remote { self.initial_clipboard_pending = false; } Some(message::Union::Misc(misc)) => match misc.union { + Some(misc::Union::Option(ref option)) => { + if option.custom_fps > 0 { + self.last_auto_fps = None; + } + } Some(misc::Union::RefreshVideo(_)) => { self.video_threads.iter().for_each(|(_, v)| { *v.discard_queue.write().unwrap() = true; @@ -1386,7 +1393,12 @@ impl Remote { // Currently, this function only considers decoding speed and queue length, not network delay. // The controlled end can consider auto fps as the maximum decoding fps. #[inline] - fn fps_control(&mut self, direct: bool, real_fps_map: HashMap) { + async fn fps_control( + &mut self, + direct: bool, + real_fps_map: HashMap, + peer: &mut Stream, + ) { self.video_threads.iter_mut().for_each(|(k, v)| { let real_fps = real_fps_map.get(k).cloned().unwrap_or_default(); if real_fps == 0 { @@ -1426,7 +1438,7 @@ impl Remote { if limited_fps > custom_fps { limited_fps = custom_fps; } - let last_auto_fps = self.handler.lc.read().unwrap().last_auto_fps.clone(); + let last_auto_fps = self.last_auto_fps; let displays = self.video_threads.keys().cloned().collect::>(); let mut fps_trending = |display: usize| { let thread = self.video_threads.get_mut(&display)?; @@ -1472,9 +1484,10 @@ impl Remote { }); let mut msg = Message::new(); msg.set_misc(misc); - self.sender.send(Data::Message(msg)).ok(); + // Send inline so a queued manual FPS update is applied after this decision. + allow_err!(peer.send(&msg).await); log::info!("Set fps to {}", auto_fps); - self.handler.lc.write().unwrap().last_auto_fps = Some(auto_fps); + self.last_auto_fps = Some(auto_fps); } } // send refresh @@ -2387,6 +2400,7 @@ impl Remote { } fn set_peer_info(&mut self, pi: &PeerInfo) { + self.last_auto_fps = None; self.peer_info.platform = pi.platform.clone(); // Check features field for terminal support @@ -3019,6 +3033,44 @@ mod tests { "a clipboard after the login was held back" ); } + + #[tokio::test] + async fn manual_fps_update_allows_the_same_automatic_limit_again() { + let (mut remote, mut peer, mut far) = remote_and_peer().await; + let (video_sender, _video_receiver) = std::sync::mpsc::channel(); + remote.video_threads.insert( + 0, + VideoThread { + video_queue: Arc::new(RwLock::new(ArrayQueue::new(client::VIDEO_QUEUE_SIZE))), + video_sender, + decode_fps: Arc::new(RwLock::new(Some(23))), + frame_count: Default::default(), + discard_queue: Default::default(), + fps_control: Default::default(), + }, + ); + + for (manual_fps, expected) in [(None, 20), (Some(90), 90), (None, 20)] { + if let Some(fps) = manual_fps { + let lc = &remote.handler.lc; + let msg = lc.write().unwrap().set_custom_fps(fps, false); + remote + .handle_msg_from_ui(Data::Message(msg), &mut peer) + .await; + } else { + remote + .fps_control(true, HashMap::from([(0, 20)]), &mut peer) + .await; + } + let bytes = timeout(1000, far.next()) + .await + .expect("FPS update was not sent") + .unwrap() + .unwrap(); + let msg = Message::parse_from_bytes(&bytes).unwrap(); + assert_eq!(msg.misc().option().custom_fps, expected); + } + } } #[cfg(test)] diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index e2b6dc879..0c451f104 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -497,8 +497,8 @@ impl Session { self.send(Data::Message(msg)); } if value != "custom" { - let last_auto_fps = self.lc.read().unwrap().last_auto_fps; - if last_auto_fps.unwrap_or(usize::MAX) >= 30 { + let custom_fps = *self.lc.read().unwrap().custom_fps.lock().unwrap(); + if custom_fps.unwrap_or(30) != 30 { // non custom quality use 30 fps let msg = self.lc.write().unwrap().set_custom_fps(30, false); self.send(Data::Message(msg));