mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-11-03 16:32:22 +00:00
fix(client): invalidate auto FPS state when updating FPS limits (#16283)
* fix(client): sync FPS control and reset limits on quality changes Track the last sent FPS across manual and automatic updates. Reset the FPS limit to 30 when leaving custom image quality, while preserving lower automatic limits when already capped at 30. fix(client): reset last sent FPS state on reconnect Signed-off-by: 21pages <sunboeasy@gmail.com> fix(client): invalidate auto FPS state when updating FPS limits Clear last_auto_fps when setting custom FPS so the controller recomputes on its next tick. Restore the 30 FPS cap when switching to preset quality while preserving the saved custom FPS setting. Signed-off-by: 21pages <sunboeasy@gmail.com> fix(client): reset auto FPS state after successful login Move last_auto_fps invalidation from login send paths to handle_peer_info, covering both normal and switch-side logins. Signed-off-by: 21pages <sunboeasy@gmail.com> fix(client): scope auto FPS state to each connection Keep automatic FPS state in the connection loop and invalidate it when processing manual FPS updates or successful login. Validate queued automatic updates against the current FPS cap and record the value only after a successful send. Signed-off-by: 21pages <sunboeasy@gmail.com> * test(client): cover FPS adjustment after manual updates Signed-off-by: 21pages <sunboeasy@gmail.com> --------- Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
1 parent
21c488b6ce
commit
4d37f00af9
3 files changed
+59
-8
No files matched your search
@@ -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<Mutex<Option<usize>>>,
|
||||
pub last_auto_fps: Option<usize>,
|
||||
pub adapter_luid: Option<i64>,
|
||||
pub mark_unsupported: Vec<CodecFormat>,
|
||||
pub selected_windows_session_id: Option<u32>,
|
||||
|
||||
+57
-5
@@ -98,6 +98,7 @@ pub struct Remote<T: InvokeUiSession> {
|
||||
elevation_requested: bool,
|
||||
peer_info: ParsedPeerInfo,
|
||||
video_threads: HashMap<usize, VideoThread>,
|
||||
last_auto_fps: Option<usize>,
|
||||
chroma: Arc<RwLock<Option<Chroma>>>,
|
||||
last_record_state: bool,
|
||||
sent_close_reason: bool,
|
||||
@@ -150,6 +151,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
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<T: InvokeUiSession> Remote<T> {
|
||||
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<T: InvokeUiSession> Remote<T> {
|
||||
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<T: InvokeUiSession> Remote<T> {
|
||||
// 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<usize, i32>) {
|
||||
async fn fps_control(
|
||||
&mut self,
|
||||
direct: bool,
|
||||
real_fps_map: HashMap<usize, i32>,
|
||||
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<T: InvokeUiSession> Remote<T> {
|
||||
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::<Vec<_>>();
|
||||
let mut fps_trending = |display: usize| {
|
||||
let thread = self.video_threads.get_mut(&display)?;
|
||||
@@ -1472,9 +1484,10 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
});
|
||||
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<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
|
||||
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)]
|
||||
|
||||
@@ -497,8 +497,8 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
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));
|
||||
|
||||
Reference in new issue
Block a user