rustdesk/src/client/helper.rs

138 lines
4.0 KiB
Rust
Raw Normal View History

2022-05-19 21:45:25 +08:00
use std::{
sync::{Arc, Mutex},
time::Instant,
};
2022-08-04 17:24:02 +08:00
use hbb_common::{
log,
2023-02-06 11:42:25 +08:00
message_proto::{video_frame, VideoFrame, Message, VoiceCallRequest, VoiceCallResponse}, get_time,
2022-08-04 17:24:02 +08:00
};
2022-05-19 21:45:25 +08:00
const MAX_LATENCY: i64 = 500;
const MIN_LATENCY: i64 = 100;
2022-05-28 03:56:42 +08:00
/// Latency controller for syncing audio with the video stream.
/// Only sync the audio to video, not the other way around.
2022-05-19 21:45:25 +08:00
#[derive(Debug)]
pub struct LatencyController {
last_video_remote_ts: i64, // generated on remote device
2022-05-19 21:45:25 +08:00
update_time: Instant,
allow_audio: bool,
2023-01-30 11:32:46 +08:00
audio_only: bool
2022-05-19 21:45:25 +08:00
}
impl Default for LatencyController {
fn default() -> Self {
Self {
last_video_remote_ts: Default::default(),
update_time: Instant::now(),
allow_audio: Default::default(),
2023-01-30 11:51:03 +08:00
audio_only: false
2022-05-19 21:45:25 +08:00
}
}
}
impl LatencyController {
2022-05-28 03:56:42 +08:00
/// Create a new latency controller.
2022-05-19 21:45:25 +08:00
pub fn new() -> Arc<Mutex<LatencyController>> {
Arc::new(Mutex::new(LatencyController::default()))
}
2023-01-30 11:32:46 +08:00
/// Set whether this [LatencyController] should be working in audio only mode.
pub fn set_audio_only(&mut self, only: bool) {
self.audio_only = only;
}
2022-05-28 03:56:42 +08:00
/// Update the latency controller with the latest video timestamp.
2022-05-19 21:45:25 +08:00
pub fn update_video(&mut self, timestamp: i64) {
self.last_video_remote_ts = timestamp;
self.update_time = Instant::now();
}
2022-05-28 03:56:42 +08:00
/// Check if the audio should be played based on the current latency.
2022-05-19 21:45:25 +08:00
pub fn check_audio(&mut self, timestamp: i64) -> bool {
2022-05-28 03:56:42 +08:00
// Compute audio latency.
2022-05-20 00:22:43 +08:00
let expected = self.update_time.elapsed().as_millis() as i64 + self.last_video_remote_ts;
2023-01-30 11:51:03 +08:00
let latency = if self.audio_only {
expected
} else {
expected - timestamp
};
2022-05-28 03:56:42 +08:00
// Set MAX and MIN, avoid fixing too frequently.
2022-05-19 21:45:25 +08:00
if self.allow_audio {
if latency.abs() > MAX_LATENCY {
log::debug!("LATENCY > {}ms cut off, latency:{}", MAX_LATENCY, latency);
self.allow_audio = false;
}
} else {
if latency.abs() < MIN_LATENCY {
log::debug!("LATENCY < {}ms resume, latency:{}", MIN_LATENCY, latency);
self.allow_audio = true;
}
}
2023-01-30 11:51:03 +08:00
// No video frame here, which means the update time is not up to date.
2023-01-30 11:32:46 +08:00
// We manually update the time here.
2023-01-30 11:51:03 +08:00
self.update_time = Instant::now();
2022-05-19 21:45:25 +08:00
self.allow_audio
}
}
2022-07-05 22:17:34 +08:00
#[derive(PartialEq, Debug, Clone)]
pub enum CodecFormat {
VP9,
H264,
H265,
Unknown,
}
impl From<&VideoFrame> for CodecFormat {
fn from(it: &VideoFrame) -> Self {
match it.union {
Some(video_frame::Union::Vp9s(_)) => CodecFormat::VP9,
Some(video_frame::Union::H264s(_)) => CodecFormat::H264,
Some(video_frame::Union::H265s(_)) => CodecFormat::H265,
2022-07-05 22:17:34 +08:00
_ => CodecFormat::Unknown,
}
}
}
impl ToString for CodecFormat {
fn to_string(&self) -> String {
match self {
CodecFormat::VP9 => "VP9".into(),
CodecFormat::H264 => "H264".into(),
CodecFormat::H265 => "H265".into(),
CodecFormat::Unknown => "Unknow".into(),
}
}
}
2022-08-04 17:24:02 +08:00
#[derive(Debug, Default)]
pub struct QualityStatus {
pub speed: Option<String>,
pub fps: Option<i32>,
pub delay: Option<i32>,
pub target_bitrate: Option<i32>,
pub codec_format: Option<CodecFormat>,
}
2023-02-06 11:42:25 +08:00
#[inline]
pub fn new_voice_call_request(is_connect: bool) -> Message {
let mut req = VoiceCallRequest::new();
req.is_connect = is_connect;
req.req_timestamp = get_time();
let mut msg = Message::new();
msg.set_voice_call_request(req);
msg
}
#[inline]
pub fn new_voice_call_response(request_timestamp: i64, accepted: bool) -> Message {
let mut resp = VoiceCallResponse::new();
resp.accepted = accepted;
resp.req_timestamp = request_timestamp;
resp.ack_timestamp = get_time();
let mut msg = Message::new();
msg.set_voice_call_response(resp);
msg
}