2022-07-05 22:31:08 +08:00
|
|
|
use super::*;
|
2023-07-19 13:11:24 +08:00
|
|
|
use scrap::codec::Quality;
|
2022-07-05 22:31:08 +08:00
|
|
|
use std::time::Duration;
|
2023-07-18 12:39:27 +08:00
|
|
|
pub const FPS: u32 = 30;
|
|
|
|
pub const MIN_FPS: u32 = 1;
|
|
|
|
pub const MAX_FPS: u32 = 120;
|
2022-07-05 22:31:08 +08:00
|
|
|
trait Percent {
|
|
|
|
fn as_percent(&self) -> u32;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Percent for ImageQuality {
|
|
|
|
fn as_percent(&self) -> u32 {
|
|
|
|
match self {
|
|
|
|
ImageQuality::NotSet => 0,
|
|
|
|
ImageQuality::Low => 50,
|
|
|
|
ImageQuality::Balanced => 66,
|
|
|
|
ImageQuality::Best => 100,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
#[derive(Default, Debug, Copy, Clone)]
|
|
|
|
struct Delay {
|
|
|
|
state: DelayState,
|
|
|
|
staging_state: DelayState,
|
|
|
|
delay: u32,
|
|
|
|
counter: u32,
|
|
|
|
slower_than_old_state: Option<bool>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default, Debug, Copy, Clone)]
|
2023-07-18 12:39:27 +08:00
|
|
|
struct UserData {
|
|
|
|
full_speed_fps: Option<u32>,
|
2023-07-25 15:46:29 +08:00
|
|
|
auto_adjust_fps: Option<u32>,
|
2023-07-18 12:39:27 +08:00
|
|
|
custom_fps: Option<u32>,
|
2023-07-19 13:11:24 +08:00
|
|
|
quality: Option<(i64, Quality)>, // (time, quality)
|
|
|
|
delay: Option<Delay>,
|
|
|
|
response_delayed: bool,
|
2023-07-18 12:39:27 +08:00
|
|
|
}
|
|
|
|
|
2022-07-05 22:31:08 +08:00
|
|
|
pub struct VideoQoS {
|
2023-07-18 12:39:27 +08:00
|
|
|
fps: u32,
|
2023-07-19 13:11:24 +08:00
|
|
|
quality: Quality,
|
2023-07-18 12:39:27 +08:00
|
|
|
users: HashMap<i32, UserData>,
|
2023-07-19 13:11:24 +08:00
|
|
|
bitrate_store: u32,
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
2022-07-05 22:31:08 +08:00
|
|
|
enum DelayState {
|
|
|
|
Normal = 0,
|
|
|
|
LowDelay = 200,
|
|
|
|
HighDelay = 500,
|
|
|
|
Broken = 1000,
|
|
|
|
}
|
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
impl Default for DelayState {
|
|
|
|
fn default() -> Self {
|
|
|
|
DelayState::Normal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-05 22:31:08 +08:00
|
|
|
impl DelayState {
|
|
|
|
fn from_delay(delay: u32) -> Self {
|
|
|
|
if delay > DelayState::Broken as u32 {
|
|
|
|
DelayState::Broken
|
|
|
|
} else if delay > DelayState::HighDelay as u32 {
|
|
|
|
DelayState::HighDelay
|
|
|
|
} else if delay > DelayState::LowDelay as u32 {
|
|
|
|
DelayState::LowDelay
|
|
|
|
} else {
|
|
|
|
DelayState::Normal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for VideoQoS {
|
|
|
|
fn default() -> Self {
|
|
|
|
VideoQoS {
|
|
|
|
fps: FPS,
|
2023-07-19 13:11:24 +08:00
|
|
|
quality: Default::default(),
|
2023-07-18 12:39:27 +08:00
|
|
|
users: Default::default(),
|
2023-07-19 13:11:24 +08:00
|
|
|
bitrate_store: 0,
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
|
|
pub enum RefreshType {
|
|
|
|
SetImageQuality,
|
|
|
|
}
|
2022-07-05 22:31:08 +08:00
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
impl VideoQoS {
|
2023-07-18 12:39:27 +08:00
|
|
|
pub fn spf(&self) -> Duration {
|
2023-07-25 15:46:29 +08:00
|
|
|
Duration::from_secs_f32(1. / (self.fps() as f32))
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
pub fn fps(&self) -> u32 {
|
2023-07-25 15:46:29 +08:00
|
|
|
if self.fps >= MIN_FPS && self.fps <= MAX_FPS {
|
|
|
|
self.fps
|
|
|
|
} else {
|
|
|
|
FPS
|
|
|
|
}
|
2022-10-19 10:19:49 +08:00
|
|
|
}
|
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
pub fn store_bitrate(&mut self, bitrate: u32) {
|
|
|
|
self.bitrate_store = bitrate;
|
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
pub fn bitrate(&self) -> u32 {
|
2023-07-19 13:11:24 +08:00
|
|
|
self.bitrate_store
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
pub fn quality(&self) -> Quality {
|
|
|
|
self.quality
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
pub fn abr_enabled() -> bool {
|
|
|
|
"N" != Config::get_option("enable-abr")
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
pub fn refresh(&mut self, typ: Option<RefreshType>) {
|
2023-07-18 12:39:27 +08:00
|
|
|
// fps
|
|
|
|
let user_fps = |u: &UserData| {
|
|
|
|
// full_speed_fps
|
|
|
|
let mut fps = u.full_speed_fps.unwrap_or_default() * 9 / 10;
|
2023-07-25 15:46:29 +08:00
|
|
|
// auto adjust fps
|
|
|
|
if let Some(auto_adjust_fps) = u.auto_adjust_fps {
|
|
|
|
if fps == 0 || auto_adjust_fps < fps {
|
|
|
|
fps = auto_adjust_fps;
|
|
|
|
}
|
|
|
|
}
|
2023-07-18 12:39:27 +08:00
|
|
|
// custom_fps
|
|
|
|
if let Some(custom_fps) = u.custom_fps {
|
|
|
|
if fps == 0 || custom_fps < fps {
|
|
|
|
fps = custom_fps;
|
|
|
|
}
|
2022-10-19 10:19:49 +08:00
|
|
|
}
|
2023-07-18 12:39:27 +08:00
|
|
|
// delay
|
|
|
|
if let Some(delay) = u.delay {
|
2023-07-19 13:11:24 +08:00
|
|
|
fps = match delay.state {
|
2023-07-18 12:39:27 +08:00
|
|
|
DelayState::Normal => fps,
|
2023-07-25 15:46:29 +08:00
|
|
|
DelayState::LowDelay => fps * 3 / 4,
|
2023-07-18 12:39:27 +08:00
|
|
|
DelayState::HighDelay => fps / 2,
|
|
|
|
DelayState::Broken => fps / 4,
|
|
|
|
}
|
|
|
|
}
|
2023-07-19 13:11:24 +08:00
|
|
|
// delay response
|
|
|
|
if u.response_delayed {
|
|
|
|
if fps > MIN_FPS + 2 {
|
|
|
|
fps = MIN_FPS + 2;
|
|
|
|
}
|
|
|
|
}
|
2023-07-18 12:39:27 +08:00
|
|
|
return fps;
|
|
|
|
};
|
|
|
|
let mut fps = self
|
|
|
|
.users
|
|
|
|
.iter()
|
|
|
|
.map(|(_, u)| user_fps(u))
|
|
|
|
.filter(|u| *u >= MIN_FPS)
|
|
|
|
.min()
|
|
|
|
.unwrap_or(FPS);
|
|
|
|
if fps > MAX_FPS {
|
|
|
|
fps = MAX_FPS;
|
2022-10-19 10:19:49 +08:00
|
|
|
}
|
2023-07-19 13:11:24 +08:00
|
|
|
self.fps = fps;
|
2022-07-05 22:31:08 +08:00
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
// quality
|
|
|
|
// latest image quality
|
2023-07-19 13:11:24 +08:00
|
|
|
let latest_quality = self
|
2023-07-18 12:39:27 +08:00
|
|
|
.users
|
|
|
|
.iter()
|
2023-07-19 13:11:24 +08:00
|
|
|
.map(|(_, u)| u.quality)
|
|
|
|
.filter(|q| *q != None)
|
|
|
|
.max_by(|a, b| a.unwrap_or_default().0.cmp(&b.unwrap_or_default().0))
|
|
|
|
.unwrap_or_default()
|
|
|
|
.unwrap_or_default()
|
|
|
|
.1;
|
|
|
|
let mut quality = latest_quality;
|
|
|
|
|
|
|
|
// network delay
|
|
|
|
if Self::abr_enabled() && typ != Some(RefreshType::SetImageQuality) {
|
|
|
|
// max delay
|
|
|
|
let delay = self
|
|
|
|
.users
|
|
|
|
.iter()
|
|
|
|
.map(|u| u.1.delay)
|
|
|
|
.filter(|d| d.is_some())
|
|
|
|
.max_by(|a, b| {
|
|
|
|
(a.unwrap_or_default().state as u32).cmp(&(b.unwrap_or_default().state as u32))
|
|
|
|
});
|
|
|
|
let delay = delay.unwrap_or_default().unwrap_or_default().state;
|
|
|
|
if delay != DelayState::Normal {
|
|
|
|
match self.quality {
|
|
|
|
Quality::Best => {
|
2023-07-25 15:46:29 +08:00
|
|
|
quality = if delay == DelayState::Broken {
|
|
|
|
Quality::Low
|
|
|
|
} else {
|
|
|
|
Quality::Balanced
|
|
|
|
};
|
2023-07-19 13:11:24 +08:00
|
|
|
}
|
|
|
|
Quality::Balanced => {
|
|
|
|
quality = Quality::Low;
|
|
|
|
}
|
|
|
|
Quality::Low => {
|
|
|
|
quality = Quality::Low;
|
|
|
|
}
|
|
|
|
Quality::Custom(b) => match delay {
|
|
|
|
DelayState::LowDelay => {
|
|
|
|
quality =
|
|
|
|
Quality::Custom(if b >= 150 { 100 } else { std::cmp::min(50, b) });
|
|
|
|
}
|
|
|
|
DelayState::HighDelay => {
|
|
|
|
quality =
|
|
|
|
Quality::Custom(if b >= 100 { 50 } else { std::cmp::min(25, b) });
|
|
|
|
}
|
|
|
|
DelayState::Broken => {
|
|
|
|
quality =
|
|
|
|
Quality::Custom(if b >= 50 { 25 } else { std::cmp::min(10, b) });
|
|
|
|
}
|
|
|
|
DelayState::Normal => {}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
match self.quality {
|
|
|
|
Quality::Low => {
|
|
|
|
if latest_quality == Quality::Best {
|
|
|
|
quality = Quality::Balanced;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Quality::Custom(current_b) => {
|
|
|
|
if let Quality::Custom(latest_b) = latest_quality {
|
|
|
|
if current_b < latest_b / 2 {
|
|
|
|
quality = Quality::Custom(latest_b / 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
2023-07-18 12:39:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-19 13:11:24 +08:00
|
|
|
self.quality = quality;
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
pub fn user_custom_fps(&mut self, id: i32, fps: u32) {
|
|
|
|
if fps < MIN_FPS {
|
|
|
|
return;
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
2023-07-18 12:39:27 +08:00
|
|
|
if let Some(user) = self.users.get_mut(&id) {
|
|
|
|
user.custom_fps = Some(fps);
|
|
|
|
} else {
|
|
|
|
self.users.insert(
|
|
|
|
id,
|
|
|
|
UserData {
|
|
|
|
custom_fps: Some(fps),
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2023-07-19 13:11:24 +08:00
|
|
|
self.refresh(None);
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
pub fn user_full_speed_fps(&mut self, id: i32, full_speed_fps: u32) {
|
|
|
|
if let Some(user) = self.users.get_mut(&id) {
|
|
|
|
user.full_speed_fps = Some(full_speed_fps);
|
|
|
|
} else {
|
|
|
|
self.users.insert(
|
|
|
|
id,
|
|
|
|
UserData {
|
|
|
|
full_speed_fps: Some(full_speed_fps),
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2023-07-19 13:11:24 +08:00
|
|
|
self.refresh(None);
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-25 15:46:29 +08:00
|
|
|
pub fn user_auto_adjust_fps(&mut self, id: i32, fps: u32) {
|
|
|
|
if let Some(user) = self.users.get_mut(&id) {
|
|
|
|
user.auto_adjust_fps = Some(fps);
|
|
|
|
} else {
|
|
|
|
self.users.insert(
|
|
|
|
id,
|
|
|
|
UserData {
|
|
|
|
auto_adjust_fps: Some(fps),
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
self.refresh(None);
|
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
pub fn user_image_quality(&mut self, id: i32, image_quality: i32) {
|
2023-07-19 13:11:24 +08:00
|
|
|
// https://github.com/rustdesk/rustdesk/blob/d716e2b40c38737f1aa3f16de0dec67394a6ac68/src/server/video_service.rs#L493
|
|
|
|
let convert_quality = |q: i32| {
|
2023-07-18 12:39:27 +08:00
|
|
|
if q == ImageQuality::Balanced.value() {
|
2023-07-19 13:11:24 +08:00
|
|
|
Quality::Balanced
|
2023-07-18 12:39:27 +08:00
|
|
|
} else if q == ImageQuality::Low.value() {
|
2023-07-19 13:11:24 +08:00
|
|
|
Quality::Low
|
2023-07-18 12:39:27 +08:00
|
|
|
} else if q == ImageQuality::Best.value() {
|
2023-07-19 13:11:24 +08:00
|
|
|
Quality::Best
|
2023-07-18 12:39:27 +08:00
|
|
|
} else {
|
2023-07-12 04:33:53 +08:00
|
|
|
let mut b = (q >> 8 & 0xFFF) * 2;
|
|
|
|
b = std::cmp::max(b, 20);
|
|
|
|
b = std::cmp::min(b, 8000);
|
2023-07-19 13:11:24 +08:00
|
|
|
Quality::Custom(b as u32)
|
2023-07-18 12:39:27 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
let quality = Some((hbb_common::get_time(), convert_quality(image_quality)));
|
2023-07-18 12:39:27 +08:00
|
|
|
if let Some(user) = self.users.get_mut(&id) {
|
|
|
|
user.quality = quality;
|
|
|
|
} else {
|
|
|
|
self.users.insert(
|
|
|
|
id,
|
|
|
|
UserData {
|
|
|
|
quality,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2023-07-19 13:11:24 +08:00
|
|
|
self.refresh(Some(RefreshType::SetImageQuality));
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
|
2023-07-18 12:39:27 +08:00
|
|
|
pub fn user_network_delay(&mut self, id: i32, delay: u32) {
|
|
|
|
let state = DelayState::from_delay(delay);
|
2023-07-19 13:11:24 +08:00
|
|
|
let debounce = 3;
|
2023-07-18 12:39:27 +08:00
|
|
|
if let Some(user) = self.users.get_mut(&id) {
|
2023-07-19 13:11:24 +08:00
|
|
|
if let Some(d) = &mut user.delay {
|
|
|
|
d.delay = (delay + d.delay) / 2;
|
|
|
|
let new_state = DelayState::from_delay(d.delay);
|
|
|
|
let slower_than_old_state = new_state as i32 - d.staging_state as i32;
|
|
|
|
let slower_than_old_state = if slower_than_old_state > 0 {
|
|
|
|
Some(true)
|
|
|
|
} else if slower_than_old_state < 0 {
|
|
|
|
Some(false)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
if d.slower_than_old_state == slower_than_old_state {
|
|
|
|
let old_counter = d.counter;
|
|
|
|
d.counter += delay / 1000 + 1;
|
|
|
|
if old_counter < debounce && d.counter >= debounce {
|
|
|
|
d.counter = 0;
|
|
|
|
d.state = d.staging_state;
|
|
|
|
d.staging_state = new_state;
|
|
|
|
}
|
|
|
|
if d.counter % debounce == 0 {
|
|
|
|
self.refresh(None);
|
|
|
|
}
|
2023-07-18 12:39:27 +08:00
|
|
|
} else {
|
2023-07-19 13:11:24 +08:00
|
|
|
d.counter = 0;
|
|
|
|
d.staging_state = new_state;
|
|
|
|
d.slower_than_old_state = slower_than_old_state;
|
2023-07-18 12:39:27 +08:00
|
|
|
}
|
|
|
|
} else {
|
2023-07-19 13:11:24 +08:00
|
|
|
user.delay = Some(Delay {
|
|
|
|
state: DelayState::Normal,
|
|
|
|
staging_state: state,
|
|
|
|
delay,
|
|
|
|
counter: 0,
|
|
|
|
slower_than_old_state: None,
|
|
|
|
});
|
2023-07-18 12:39:27 +08:00
|
|
|
}
|
2022-07-05 22:31:08 +08:00
|
|
|
} else {
|
2023-07-18 12:39:27 +08:00
|
|
|
self.users.insert(
|
|
|
|
id,
|
|
|
|
UserData {
|
2023-07-19 13:11:24 +08:00
|
|
|
delay: Some(Delay {
|
|
|
|
state: DelayState::Normal,
|
|
|
|
staging_state: state,
|
|
|
|
delay,
|
|
|
|
counter: 0,
|
|
|
|
slower_than_old_state: None,
|
|
|
|
}),
|
2023-07-18 12:39:27 +08:00
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
);
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
2023-07-19 13:11:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn user_delay_response_elapsed(&mut self, id: i32, elapsed: u128) {
|
|
|
|
if let Some(user) = self.users.get_mut(&id) {
|
|
|
|
let old = user.response_delayed;
|
|
|
|
user.response_delayed = elapsed > 3000;
|
|
|
|
if old != user.response_delayed {
|
|
|
|
self.refresh(None);
|
|
|
|
}
|
2023-07-18 12:39:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn on_connection_close(&mut self, id: i32) {
|
|
|
|
self.users.remove(&id);
|
2023-07-19 13:11:24 +08:00
|
|
|
self.refresh(None);
|
2022-07-05 22:31:08 +08:00
|
|
|
}
|
|
|
|
}
|