mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
abr
This commit is contained in:
@@ -159,6 +159,7 @@ class Header: Reactor.Component {
|
||||
<li #custom type="image-quality"><span>{svg_checkmark}</span>{translate('Custom')}</li>
|
||||
<div .separator />
|
||||
<li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Show remote cursor')}</li>
|
||||
<li #show-quality-monitor .toggle-option><span>{svg_checkmark}</span>{translate('Show quality monitor')}</li>
|
||||
{audio_enabled ? <li #disable-audio .toggle-option><span>{svg_checkmark}</span>{translate('Mute')}</li> : ""}
|
||||
{is_win && pi.platform == 'Windows' && file_enabled ? <li #enable-file-transfer .toggle-option><span>{svg_checkmark}</span>{translate('Allow file copy and paste')}</li> : ""}
|
||||
{keyboard_enabled && clipboard_enabled ? <li #disable-clipboard .toggle-option><span>{svg_checkmark}</span>{translate('Disable clipboard')}</li> : ""}
|
||||
@@ -315,7 +316,9 @@ class Header: Reactor.Component {
|
||||
handle_custom_image_quality();
|
||||
} else if (me.id == "privacy-mode") {
|
||||
togglePrivacyMode(me.id);
|
||||
} else if (me.attributes.hasClass("toggle-option")) {
|
||||
} else if (me.id == "show-quality-monitor") {
|
||||
toggleQualityMonitor(me.id);
|
||||
}else if (me.attributes.hasClass("toggle-option")) {
|
||||
handler.toggle_option(me.id);
|
||||
toggleMenuState();
|
||||
} else if (!me.attributes.hasClass("selected")) {
|
||||
@@ -332,16 +335,13 @@ class Header: Reactor.Component {
|
||||
}
|
||||
|
||||
function handle_custom_image_quality() {
|
||||
var tmp = handler.get_custom_image_quality();
|
||||
var bitrate0 = tmp[0] || 50;
|
||||
var quantizer0 = tmp.length > 1 ? tmp[1] : 100;
|
||||
var bitrate = handler.get_custom_image_quality()[0] / 2;
|
||||
msgbox("custom", "Custom Image Quality", "<div .form> \
|
||||
<div><input type=\"hslider\" style=\"width: 50%\" name=\"bitrate\" max=\"100\" min=\"10\" value=\"" + bitrate0 + "\"/ buddy=\"bitrate-buddy\"><b #bitrate-buddy>x</b>% bitrate</div> \
|
||||
<div><input type=\"hslider\" style=\"width: 50%\" name=\"quantizer\" max=\"100\" min=\"0\" value=\"" + quantizer0 + "\"/ buddy=\"quantizer-buddy\"><b #quantizer-buddy>x</b>% quantizer</div> \
|
||||
<div><input type=\"hslider\" style=\"width: 50%\" name=\"bitrate\" max=\"100\" min=\"10\" value=\"" + bitrate + "\"/ buddy=\"bitrate-buddy\"><b #bitrate-buddy>x</b>% Bitrate</div> \
|
||||
</div>", function(res=null) {
|
||||
if (!res) return;
|
||||
if (!res.bitrate) return;
|
||||
handler.save_custom_image_quality(res.bitrate, res.quantizer);
|
||||
handler.save_custom_image_quality(res.bitrate * 2);
|
||||
toggleMenuState();
|
||||
});
|
||||
}
|
||||
@@ -357,7 +357,7 @@ function toggleMenuState() {
|
||||
for (var el in $$(menu#display-options>li)) {
|
||||
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
|
||||
}
|
||||
for (var id in ["show-remote-cursor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end"]) {
|
||||
for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end"]) {
|
||||
var el = self.select('#' + id);
|
||||
if (el) {
|
||||
var value = handler.get_toggle_option(id);
|
||||
@@ -425,6 +425,17 @@ function togglePrivacyMode(privacy_id) {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleQualityMonitor(name) {
|
||||
var show = handler.get_toggle_option(name);
|
||||
if (show) {
|
||||
$(#quality-monitor).style.set{ display: "none" };
|
||||
} else {
|
||||
$(#quality-monitor).style.set{ display: "block" };
|
||||
}
|
||||
handler.toggle_option(name);
|
||||
toggleMenuState();
|
||||
}
|
||||
|
||||
handler.updateBlockInputState = function(input_blocked) {
|
||||
if (!input_blocked) {
|
||||
handler.toggle_option("block-input");
|
||||
|
||||
@@ -9,6 +9,16 @@ div#video-wrapper {
|
||||
background: #212121;
|
||||
}
|
||||
|
||||
div#quality-monitor {
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: #7571719c;
|
||||
padding: 5px;
|
||||
min-width: 150px;
|
||||
color: azure;
|
||||
border: solid azure;
|
||||
}
|
||||
|
||||
video#handler {
|
||||
behavior: native-remote video;
|
||||
size: *;
|
||||
@@ -24,7 +34,7 @@ img#cursor {
|
||||
}
|
||||
|
||||
.goup {
|
||||
transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
table#remote-folder-view {
|
||||
@@ -33,4 +43,4 @@ table#remote-folder-view {
|
||||
|
||||
table#local-folder-view {
|
||||
context-menu: selector(menu#local-folder-view);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
<html window-resizable window-frame="extended">
|
||||
<head>
|
||||
<style>
|
||||
@import url(common.css);
|
||||
@import url(remote.css);
|
||||
@import url(file_transfer.css);
|
||||
@import url(header.css);
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
|
||||
<head>
|
||||
<style>
|
||||
@import url(common.css);
|
||||
@import url(remote.css);
|
||||
@import url(file_transfer.css);
|
||||
@import url(header.css);
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
include "common.tis";
|
||||
include "msgbox.tis";
|
||||
include "remote.tis";
|
||||
@@ -15,23 +16,28 @@
|
||||
include "grid.tis";
|
||||
include "header.tis";
|
||||
</script>
|
||||
</head>
|
||||
<header>
|
||||
<div.window-icon role="window-icon"><icon /></div>
|
||||
</head>
|
||||
<header>
|
||||
<div.window-icon role="window-icon">
|
||||
<icon />
|
||||
</div>
|
||||
<caption role="window-caption" />
|
||||
<div.window-toolbar />
|
||||
<div.window-buttons />
|
||||
</header>
|
||||
<body>
|
||||
<div #video-wrapper>
|
||||
<video #handler>
|
||||
<div style="position: relative">
|
||||
<img #cursor src="in-memory:cursor" />
|
||||
</div>
|
||||
</video>
|
||||
</div>
|
||||
<div #file-transfer-wrapper>
|
||||
</div>
|
||||
<div #msgbox />
|
||||
</body>
|
||||
</html>
|
||||
</header>
|
||||
|
||||
<body>
|
||||
<div #video-wrapper>
|
||||
<video #handler>
|
||||
<div #quality-monitor style="position: absolute; display: none" />
|
||||
<div style="position: relative">
|
||||
<img #cursor src="in-memory:cursor" />
|
||||
</div>
|
||||
</video>
|
||||
</div>
|
||||
<div #file-transfer-wrapper>
|
||||
</div>
|
||||
<div #msgbox />
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@ use std::{
|
||||
collections::HashMap,
|
||||
ops::Deref,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
Arc, Mutex, RwLock,
|
||||
},
|
||||
};
|
||||
@@ -223,7 +223,7 @@ impl sciter::EventHandler for Handler {
|
||||
fn get_custom_image_quality();
|
||||
fn save_view_style(String);
|
||||
fn save_image_quality(String);
|
||||
fn save_custom_image_quality(i32, i32);
|
||||
fn save_custom_image_quality(i32);
|
||||
fn refresh_video();
|
||||
fn get_toggle_option(String);
|
||||
fn is_privacy_mode_supported();
|
||||
@@ -234,6 +234,25 @@ impl sciter::EventHandler for Handler {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct QualityStatus {
|
||||
speed: String,
|
||||
fps: i32,
|
||||
delay: i32,
|
||||
target_bitrate: i32,
|
||||
}
|
||||
|
||||
impl Default for QualityStatus {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
speed: Default::default(),
|
||||
fps: -1,
|
||||
delay: -1,
|
||||
target_bitrate: -1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
pub fn new(cmd: String, id: String, args: Vec<String>) -> Self {
|
||||
let me = Self {
|
||||
@@ -249,6 +268,18 @@ impl Handler {
|
||||
me
|
||||
}
|
||||
|
||||
fn update_quality_status(&self, status: QualityStatus) {
|
||||
self.call2(
|
||||
"updateQualityStatus",
|
||||
&make_args!(
|
||||
status.speed,
|
||||
status.fps,
|
||||
status.delay,
|
||||
status.target_bitrate
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
fn start_keyboard_hook(&self) {
|
||||
if self.is_port_forward() || self.is_file_transfer() {
|
||||
return;
|
||||
@@ -533,12 +564,12 @@ impl Handler {
|
||||
self.send(Data::Message(LoginConfigHandler::refresh()));
|
||||
}
|
||||
|
||||
fn save_custom_image_quality(&mut self, bitrate: i32, quantizer: i32) {
|
||||
fn save_custom_image_quality(&mut self, custom_image_quality: i32) {
|
||||
let msg = self
|
||||
.lc
|
||||
.write()
|
||||
.unwrap()
|
||||
.save_custom_image_quality(bitrate, quantizer);
|
||||
.save_custom_image_quality(custom_image_quality as u32);
|
||||
self.send(Data::Message(msg));
|
||||
}
|
||||
|
||||
@@ -1296,7 +1327,10 @@ async fn io_loop(handler: Handler) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
let (video_sender, audio_sender) = start_video_audio_threads(|data: &[u8]| {
|
||||
let frame_count = Arc::new(AtomicUsize::new(0));
|
||||
let frame_count_cl = frame_count.clone();
|
||||
let (video_sender, audio_sender) = start_video_audio_threads(move |data: &[u8]| {
|
||||
frame_count_cl.fetch_add(1, Ordering::Relaxed);
|
||||
VIDEO
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -1319,6 +1353,8 @@ async fn io_loop(handler: Handler) {
|
||||
first_frame: false,
|
||||
#[cfg(windows)]
|
||||
clipboard_file_context: None,
|
||||
data_count: Arc::new(AtomicUsize::new(0)),
|
||||
frame_count,
|
||||
};
|
||||
remote.io_loop(&key, &token).await;
|
||||
remote.sync_jobs_status_to_local().await;
|
||||
@@ -1369,6 +1405,8 @@ struct Remote {
|
||||
first_frame: bool,
|
||||
#[cfg(windows)]
|
||||
clipboard_file_context: Option<Box<CliprdrClientContext>>,
|
||||
data_count: Arc<AtomicUsize>,
|
||||
frame_count: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl Remote {
|
||||
@@ -1394,6 +1432,8 @@ impl Remote {
|
||||
#[cfg(windows)]
|
||||
let mut rx_clip_client = get_rx_clip_client().lock().await;
|
||||
|
||||
let mut status_timer = time::interval(Duration::new(1, 0));
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
res = peer.next() => {
|
||||
@@ -1406,6 +1446,7 @@ impl Remote {
|
||||
}
|
||||
Ok(ref bytes) => {
|
||||
last_recv_time = Instant::now();
|
||||
self.data_count.fetch_add(bytes.len(), Ordering::Relaxed);
|
||||
if !self.handle_msg_from_peer(bytes, &mut peer).await {
|
||||
break
|
||||
}
|
||||
@@ -1450,6 +1491,16 @@ impl Remote {
|
||||
self.timer = time::interval_at(Instant::now() + SEC30, SEC30);
|
||||
}
|
||||
}
|
||||
_ = status_timer.tick() => {
|
||||
let speed = self.data_count.swap(0, Ordering::Relaxed);
|
||||
let speed = format!("{:.2}kB/s", speed as f32 / 1024 as f32);
|
||||
let fps = self.frame_count.swap(0, Ordering::Relaxed) as _;
|
||||
self.handler.update_quality_status(QualityStatus {
|
||||
speed,
|
||||
fps,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
log::debug!("Exit io_loop of id={}", self.handler.id);
|
||||
@@ -2370,7 +2421,7 @@ impl Remote {
|
||||
}
|
||||
back_notification::PrivacyModeState::OffSucceeded => {
|
||||
self.handler
|
||||
.msgbox("custom-nocancel", "Privacy mode", "Out privacy mode");
|
||||
.msgbox("custom-nocancel", "Privacy mode", "Out privacy mode");
|
||||
self.update_privacy_mode(false);
|
||||
}
|
||||
back_notification::PrivacyModeState::OffByPeer => {
|
||||
@@ -2549,7 +2600,16 @@ impl Interface for Handler {
|
||||
}
|
||||
|
||||
async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream) {
|
||||
handle_test_delay(t, peer).await;
|
||||
if !t.from_client {
|
||||
self.update_quality_status(QualityStatus {
|
||||
delay: t.last_delay as _,
|
||||
target_bitrate: t.target_bitrate as _,
|
||||
..Default::default()
|
||||
});
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_test_delay(t);
|
||||
allow_err!(peer.send(&msg_out).await);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -456,6 +456,45 @@ function self.closing() {
|
||||
if (is_file_transfer || is_port_forward || size_adapted) handler.save_size(x, y, w, h);
|
||||
}
|
||||
|
||||
var qualityMonitor;
|
||||
var qualityMonitorData = [];
|
||||
|
||||
class QualityMonitor: Reactor.Component
|
||||
{
|
||||
function this() {
|
||||
qualityMonitor = this;
|
||||
if (handler.get_toggle_option("show-quality-monitor")) {
|
||||
$(#quality-monitor).style.set{ display: "block" };
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
return <div >
|
||||
<div>
|
||||
Speed: {qualityMonitorData[0]}
|
||||
</div>
|
||||
<div>
|
||||
FPS: {qualityMonitorData[1]}
|
||||
</div>
|
||||
<div>
|
||||
Delay: {qualityMonitorData[2]} ms
|
||||
</div>
|
||||
<div>
|
||||
Target Bitrate: {qualityMonitorData[3]}kb
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
$(#quality-monitor).content(<QualityMonitor />);
|
||||
handler.updateQualityStatus = function(speed, fps, delay, bitrate) {
|
||||
speed ? qualityMonitorData[0] = speed:null;
|
||||
fps > -1 ? qualityMonitorData[1] = fps:null;
|
||||
delay > -1 ? qualityMonitorData[2] = delay:null;
|
||||
bitrate > -1 ? qualityMonitorData[3] = bitrate:null;
|
||||
qualityMonitor.update();
|
||||
}
|
||||
|
||||
handler.setPermission = function(name, enabled) {
|
||||
self.timer(60ms, function() {
|
||||
if (name == "keyboard") keyboard_enabled = enabled;
|
||||
|
||||
Reference in New Issue
Block a user