Merge pull request #628 from fufesou/simple_rc

Fix WCHAR Path & Add Resources Integration Lib
This commit is contained in:
RustDesk
2022-06-02 22:01:01 +08:00
committed by GitHub
51 changed files with 2983 additions and 287 deletions

View File

@@ -19,19 +19,18 @@
// https://slhck.info/video/2017/03/01/rate-control.html
use super::*;
use hbb_common::tokio::{
runtime::Runtime,
sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex,
},
use hbb_common::tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex,
};
use scrap::{Capturer, Config, Display, EncodeFrame, Encoder, VideoCodecId, STRIDE_ALIGN};
use scrap::{Capturer, Config, Display, EncodeFrame, Encoder, Frame, VideoCodecId, STRIDE_ALIGN};
use std::{
collections::HashSet,
io::ErrorKind::WouldBlock,
io::{ErrorKind::WouldBlock, Result},
time::{self, Duration, Instant},
};
#[cfg(windows)]
use virtual_display;
pub const NAME: &'static str = "video";
@@ -45,16 +44,39 @@ lazy_static::lazy_static! {
let (tx, rx) = unbounded_channel();
(tx, Arc::new(TokioMutex::new(rx)))
};
static ref PRIVACY_MODE_CONN_ID: Mutex<i32> = Mutex::new(0);
static ref IS_CAPTURER_MAGNIFIER_SUPPORTED: bool = is_capturer_mag_supported();
}
fn is_capturer_mag_supported() -> bool {
#[cfg(windows)]
return scrap::CapturerMag::is_supported();
#[cfg(not(windows))]
false
}
pub fn notify_video_frame_feched(conn_id: i32, frame_tm: Option<Instant>) {
FRAME_FETCHED_NOTIFIER.0.send((conn_id, frame_tm)).unwrap()
}
pub fn set_privacy_mode_conn_id(conn_id: i32) {
*PRIVACY_MODE_CONN_ID.lock().unwrap() = conn_id
}
pub fn get_privacy_mode_conn_id() -> i32 {
*PRIVACY_MODE_CONN_ID.lock().unwrap()
}
pub fn is_privacy_mode_supported() -> bool {
#[cfg(windows)]
return *IS_CAPTURER_MAGNIFIER_SUPPORTED;
#[cfg(not(windows))]
return false;
}
struct VideoFrameController {
cur: Instant,
send_conn_ids: HashSet<i32>,
rt: Runtime,
}
impl VideoFrameController {
@@ -62,7 +84,6 @@ impl VideoFrameController {
Self {
cur: Instant::now(),
send_conn_ids: HashSet::new(),
rt: Runtime::new().unwrap(),
}
}
@@ -77,46 +98,69 @@ impl VideoFrameController {
}
}
fn blocking_wait_next(&mut self, timeout_millis: u128) {
#[tokio::main(flavor = "current_thread")]
async fn try_wait_next(&mut self, fetched_conn_ids: &mut HashSet<i32>, timeout_millis: u64) {
if self.send_conn_ids.is_empty() {
return;
}
let send_conn_ids = self.send_conn_ids.clone();
self.rt.block_on(async move {
let mut fetched_conn_ids = HashSet::new();
let begin = Instant::now();
while begin.elapsed().as_millis() < timeout_millis {
let timeout_dur =
Duration::from_millis((timeout_millis - begin.elapsed().as_millis()) as u64);
match tokio::time::timeout(
timeout_dur,
FRAME_FETCHED_NOTIFIER.1.lock().await.recv(),
)
.await
{
Err(_) => {
// break if timeout
// log::error!("blocking wait frame receiving timeout {}", timeout_millis);
break;
}
Ok(Some((id, instant))) => {
if let Some(tm) = instant {
log::trace!("Channel recv latency: {}", tm.elapsed().as_secs_f32());
}
fetched_conn_ids.insert(id);
// break if all connections have received current frame
if fetched_conn_ids.len() >= send_conn_ids.len() {
break;
}
}
Ok(None) => {
// this branch would nerver be reached
}
}
let timeout_dur = Duration::from_millis(timeout_millis as u64);
match tokio::time::timeout(timeout_dur, FRAME_FETCHED_NOTIFIER.1.lock().await.recv()).await
{
Err(_) => {
// break if timeout
// log::error!("blocking wait frame receiving timeout {}", timeout_millis);
}
});
Ok(Some((id, instant))) => {
if let Some(tm) = instant {
log::trace!("Channel recv latency: {}", tm.elapsed().as_secs_f32());
}
fetched_conn_ids.insert(id);
}
Ok(None) => {
// this branch would nerver be reached
}
}
}
}
trait TraitCapturer {
fn frame<'a>(&'a mut self, timeout_ms: u32) -> Result<Frame<'a>>;
#[cfg(windows)]
fn is_gdi(&self) -> bool;
#[cfg(windows)]
fn set_gdi(&mut self) -> bool;
}
impl TraitCapturer for Capturer {
fn frame<'a>(&'a mut self, timeout_ms: u32) -> Result<Frame<'a>> {
self.frame(timeout_ms)
}
#[cfg(windows)]
fn is_gdi(&self) -> bool {
self.is_gdi()
}
#[cfg(windows)]
fn set_gdi(&mut self) -> bool {
self.set_gdi()
}
}
#[cfg(windows)]
impl TraitCapturer for scrap::CapturerMag {
fn frame<'a>(&'a mut self, _timeout_ms: u32) -> Result<Frame<'a>> {
self.frame(_timeout_ms)
}
fn is_gdi(&self) -> bool {
false
}
fn set_gdi(&mut self) -> bool {
false
}
}
@@ -132,7 +176,7 @@ fn check_display_changed(
last_width: usize,
last_hegiht: usize,
) -> bool {
let displays = match Display::all() {
let displays = match try_get_displays() {
Ok(d) => d,
_ => return false,
};
@@ -156,7 +200,126 @@ fn check_display_changed(
return false;
}
// Capturer object is expensive, avoiding to create it frequently.
fn create_capturer(privacy_mode_id: i32, display: Display) -> ResultType<Box<dyn TraitCapturer>> {
let use_yuv = true;
#[cfg(not(windows))]
let c: Option<Box<dyn TraitCapturer>> = None;
#[cfg(windows)]
let mut c: Option<Box<dyn TraitCapturer>> = None;
if privacy_mode_id > 0 {
#[cfg(windows)]
{
use crate::ui::win_privacy::*;
match scrap::CapturerMag::new(
display.origin(),
display.width(),
display.height(),
use_yuv,
) {
Ok(mut c1) => {
let mut ok = false;
let check_begin = Instant::now();
while check_begin.elapsed().as_secs() < 5 {
match c1.exclude("", PRIVACY_WINDOW_NAME) {
Ok(false) => {
ok = false;
std::thread::sleep(std::time::Duration::from_millis(500));
}
Err(e) => {
bail!(
"Failed to exclude privacy window {} - {}, err: {}",
"",
PRIVACY_WINDOW_NAME,
e
);
}
_ => {
ok = true;
break;
}
}
}
if !ok {
bail!(
"Failed to exclude privacy window {} - {} ",
"",
PRIVACY_WINDOW_NAME
);
}
log::debug!("Create maginifier capture for {}", privacy_mode_id);
c = Some(Box::new(c1));
}
Err(e) => {
bail!(format!("Failed to create magnifier capture {}", e));
}
}
}
}
let c = match c {
Some(c1) => c1,
None => {
let c1 =
Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?;
log::debug!("Create capturer dxgi|gdi");
Box::new(c1)
}
};
Ok(c)
}
#[cfg(windows)]
fn ensure_close_virtual_device() -> ResultType<()> {
let num_displays = Display::all()?.len();
if num_displays == 0 {
// Device may sometimes be uninstalled by user in "Device Manager" Window.
// Closing device will clear the instance data.
virtual_display::close_device();
} else if num_displays > 1 {
// Try close device, if display device changed.
if virtual_display::is_device_created() {
virtual_display::close_device();
}
}
Ok(())
}
pub fn test_create_capturer(privacy_mode_id: i32, timeout_millis: u64) -> bool {
let test_begin = Instant::now();
while test_begin.elapsed().as_millis() < timeout_millis as _ {
if let Ok((_, _, display)) = get_current_display() {
if let Ok(_) = create_capturer(privacy_mode_id, display) {
return true;
}
}
std::thread::sleep(Duration::from_millis(300));
}
false
}
#[cfg(windows)]
fn check_uac_switch(privacy_mode_id: i32, captuerer_privacy_mode_id: i32) -> ResultType<()> {
if captuerer_privacy_mode_id != 0 {
if privacy_mode_id != captuerer_privacy_mode_id {
if !crate::ui::win_privacy::is_process_consent_running()? {
bail!("consent.exe is running");
}
}
if crate::ui::win_privacy::is_process_consent_running()? {
bail!("consent.exe is running");
}
}
Ok(())
}
fn run(sp: GenericService) -> ResultType<()> {
#[cfg(windows)]
ensure_close_virtual_device()?;
let fps = 30;
let wait = 1000 / fps;
let spf = time::Duration::from_secs_f32(1. / (fps as f32));
@@ -172,8 +335,27 @@ fn run(sp: GenericService) -> ResultType<()> {
num_cpus::get_physical(),
num_cpus::get(),
);
// Capturer object is expensive, avoiding to create it frequently.
let mut c = Capturer::new(display, true).with_context(|| "Failed to create capturer")?;
let privacy_mode_id = *PRIVACY_MODE_CONN_ID.lock().unwrap();
#[cfg(not(windows))]
let captuerer_privacy_mode_id = privacy_mode_id;
#[cfg(windows)]
let mut captuerer_privacy_mode_id = privacy_mode_id;
#[cfg(windows)]
if crate::ui::win_privacy::is_process_consent_running()? {
captuerer_privacy_mode_id = 0;
}
log::debug!(
"Try create capturer with captuerer privacy mode id {}",
captuerer_privacy_mode_id,
);
if privacy_mode_id != captuerer_privacy_mode_id {
log::info!("In privacy mode, but show UAC prompt window for now");
} else {
log::info!("In privacy mode, the peer side cannot watch the screen");
}
let mut c = create_capturer(captuerer_privacy_mode_id, display)?;
let q = get_image_quality();
let (bitrate, rc_min_quantizer, rc_max_quantizer, speed) = get_quality(width, height, q);
@@ -220,6 +402,9 @@ fn run(sp: GenericService) -> ResultType<()> {
#[cfg(windows)]
log::info!("gdi: {}", c.is_gdi());
while sp.ok() {
#[cfg(windows)]
check_uac_switch(privacy_mode_id, captuerer_privacy_mode_id)?;
if *SWITCH.lock().unwrap() {
bail!("SWITCH");
}
@@ -227,6 +412,7 @@ fn run(sp: GenericService) -> ResultType<()> {
*SWITCH.lock().unwrap() = true;
bail!("SWITCH");
}
check_privacy_mode_changed(&sp, privacy_mode_id)?;
if get_image_quality() != q {
bail!("SWITCH");
}
@@ -245,12 +431,13 @@ fn run(sp: GenericService) -> ResultType<()> {
bail!("SWITCH");
}
}
*LAST_ACTIVE.lock().unwrap() = now;
frame_controller.reset();
#[cfg(any(target_os = "android", target_os = "ios"))]
let res = match c.frame(wait as _) {
let res = match (*c).frame(wait as _) {
Ok(frame) => {
let time = now - start;
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
@@ -273,7 +460,7 @@ fn run(sp: GenericService) -> ResultType<()> {
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let res = match c.frame(wait as _) {
let res = match (*c).frame(wait as _) {
Ok(frame) => {
let time = now - start;
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
@@ -320,8 +507,19 @@ fn run(sp: GenericService) -> ResultType<()> {
_ => {}
}
// i love 3, 6, 8
frame_controller.blocking_wait_next(3_000);
let mut fetched_conn_ids = HashSet::new();
let timeout_millis = 3_000u64;
let wait_begin = Instant::now();
while wait_begin.elapsed().as_millis() < timeout_millis as _ {
check_privacy_mode_changed(&sp, privacy_mode_id)?;
#[cfg(windows)]
check_uac_switch(privacy_mode_id, captuerer_privacy_mode_id)?;
frame_controller.try_wait_next(&mut fetched_conn_ids, 300);
// break if all connections have received current frame
if fetched_conn_ids.len() >= frame_controller.send_conn_ids.len() {
break;
}
}
let elapsed = now.elapsed();
// may need to enable frame(timeout)
@@ -333,6 +531,21 @@ fn run(sp: GenericService) -> ResultType<()> {
Ok(())
}
#[inline]
fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> ResultType<()> {
let privacy_mode_id_2 = *PRIVACY_MODE_CONN_ID.lock().unwrap();
if privacy_mode_id != privacy_mode_id_2 {
if privacy_mode_id_2 != 0 {
let msg_out = crate::common::make_privacy_mode_msg(
back_notification::PrivacyModeState::OnByOther,
);
sp.send_to_others(msg_out, privacy_mode_id_2);
}
bail!("SWITCH");
}
Ok(())
}
#[inline]
fn create_msg(vp9s: Vec<VP9>) -> Message {
let mut msg_out = Message::new();
@@ -416,7 +629,7 @@ pub fn handle_one_frame_encoded(
}
fn get_display_num() -> usize {
if let Ok(d) = Display::all() {
if let Ok(d) = try_get_displays() {
d.len()
} else {
0
@@ -430,7 +643,7 @@ pub fn get_displays() -> ResultType<(usize, Vec<DisplayInfo>)> {
}
let mut displays = Vec::new();
let mut primary = 0;
for (i, d) in Display::all()?.iter().enumerate() {
for (i, d) in try_get_displays()?.iter().enumerate() {
if d.is_primary() {
primary = i;
}
@@ -467,7 +680,7 @@ pub fn refresh() {
}
fn get_primary() -> usize {
if let Ok(all) = Display::all() {
if let Ok(all) = try_get_displays() {
for (i, d) in all.iter().enumerate() {
if d.is_primary() {
return i;
@@ -481,9 +694,44 @@ pub fn switch_to_primary() {
switch_display(get_primary() as _);
}
#[cfg(not(windows))]
fn try_get_displays() -> ResultType<Vec<Display>> {
Ok(Display::all()?)
}
#[cfg(windows)]
fn try_get_displays() -> ResultType<Vec<Display>> {
let mut displays = Display::all()?;
if displays.len() == 0 {
log::debug!("no displays, create virtual display");
// Try plugin monitor
if !virtual_display::is_device_created() {
if let Err(e) = virtual_display::create_device() {
log::debug!("Create device failed {}", e);
}
}
if virtual_display::is_device_created() {
if let Err(e) = virtual_display::plug_in_monitor() {
log::debug!("Plug in monitor failed {}", e);
} else {
if let Err(e) = virtual_display::update_monitor_modes() {
log::debug!("Update monitor modes failed {}", e);
}
}
}
displays = Display::all()?;
} else if displays.len() > 1 {
// If more than one displays exists, close RustDeskVirtualDisplay
if virtual_display::is_device_created() {
virtual_display::close_device()
}
}
Ok(displays)
}
fn get_current_display() -> ResultType<(usize, usize, Display)> {
let mut current = *CURRENT_DISPLAY.lock().unwrap() as usize;
let mut displays = Display::all()?;
let mut displays = try_get_displays()?;
if displays.len() == 0 {
bail!("No displays");
}