Merge remote-tracking branch 'upstream/master'

# Conflicts:
#	Cargo.lock
#	src/server/connection.rs
This commit is contained in:
mcfans
2023-11-07 12:13:15 +08:00
166 changed files with 10361 additions and 6739 deletions

View File

@@ -1,5 +1,5 @@
use super::{input_service::*, *};
#[cfg(windows)]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
use crate::clipboard_file::*;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::common::update_clipboard;
@@ -44,12 +44,14 @@ use hbb_common::{
use scrap::android::{call_main_service_pointer_input, call_main_service_key_event};
#[cfg(target_os = "android")]
use crate::keyboard::client::map_key_to_control_key;
use serde_derive::Serialize;
use serde_json::{json, value::Value};
use sha2::{Digest, Sha256};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use std::sync::atomic::Ordering;
use std::{
num::NonZeroI64,
path::PathBuf,
sync::{atomic::AtomicI64, mpsc as std_mpsc},
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
@@ -181,6 +183,7 @@ pub struct Connection {
file: bool,
restart: bool,
recording: bool,
block_input: bool,
last_test_delay: i64,
network_delay: Option<u32>,
lock_after_session_end: bool,
@@ -194,7 +197,7 @@ pub struct Connection {
// by peer
disable_audio: bool,
// by peer
#[cfg(windows)]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
enable_file_transfer: bool,
// by peer
audio_sender: Option<MediaSender>,
@@ -225,6 +228,7 @@ pub struct Connection {
start_cm_ipc_para: Option<StartCmIpcPara>,
auto_disconnect_timer: Option<(Instant, u64)>,
authed_conn_id: Option<self::raii::AuthedConnID>,
file_remove_log_control: FileRemoveLogControl,
}
impl ConnInner {
@@ -326,13 +330,14 @@ impl Connection {
file: Connection::permission("enable-file-transfer"),
restart: Connection::permission("enable-remote-restart"),
recording: Connection::permission("enable-record-session"),
block_input: Connection::permission("enable-block-input"),
last_test_delay: 0,
network_delay: None,
lock_after_session_end: false,
show_remote_cursor: false,
ip: "".to_owned(),
disable_audio: false,
#[cfg(windows)]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
enable_file_transfer: false,
disable_clipboard: false,
disable_keyboard: false,
@@ -367,6 +372,7 @@ impl Connection {
}),
auto_disconnect_timer: None,
authed_conn_id: None,
file_remove_log_control: FileRemoveLogControl::new(id),
};
let addr = hbb_common::try_into_v4(addr);
if !conn.on_open(addr).await {
@@ -395,6 +401,9 @@ impl Connection {
if !conn.recording {
conn.send_permission(Permission::Recording, false).await;
}
if !conn.block_input {
conn.send_permission(Permission::BlockInput, false).await;
}
let mut test_delay_timer =
time::interval_at(Instant::now() + TEST_DELAY_TIMEOUT, TEST_DELAY_TIMEOUT);
let mut last_recv_time = Instant::now();
@@ -476,12 +485,15 @@ impl Connection {
} else if &name == "recording" {
conn.recording = enabled;
conn.send_permission(Permission::Recording, enabled).await;
} else if &name == "block_input" {
conn.block_input = enabled;
conn.send_permission(Permission::BlockInput, enabled).await;
}
}
ipc::Data::RawMessage(bytes) => {
allow_err!(conn.stream.send_raw(bytes).await);
}
#[cfg(windows)]
#[cfg(any(target_os="windows", target_os="linux", target_os = "macos"))]
ipc::Data::ClipboardFile(clip) => {
allow_err!(conn.stream.send(&clip_2_msg(clip)).await);
}
@@ -558,11 +570,11 @@ impl Connection {
},
_ = conn.file_timer.tick() => {
if !conn.read_jobs.is_empty() {
conn.send_to_cm(ipc::Data::FileTransferLog(fs::serialize_transfer_jobs(&conn.read_jobs)));
conn.send_to_cm(ipc::Data::FileTransferLog(("transfer".to_string(), fs::serialize_transfer_jobs(&conn.read_jobs))));
match fs::handle_read_jobs(&mut conn.read_jobs, &mut conn.stream).await {
Ok(log) => {
if !log.is_empty() {
conn.send_to_cm(ipc::Data::FileTransferLog(log));
conn.send_to_cm(ipc::Data::FileTransferLog(("transfer".to_string(), log)));
}
}
Err(err) => {
@@ -634,6 +646,7 @@ impl Connection {
break;
}
}
conn.file_remove_log_control.on_timer().drain(..).map(|x| conn.send_to_cm(x)).count();
}
_ = test_delay_timer.tick() => {
if last_recv_time.elapsed() >= SEC30 {
@@ -672,7 +685,6 @@ impl Connection {
conn.lr.my_id.clone(),
);
video_service::notify_video_frame_fetched(id, None);
scrap::codec::Encoder::update(id, scrap::codec::EncodingUpdate::Remove);
if conn.authorized {
password::update_temporary_password();
}
@@ -1034,7 +1046,7 @@ impl Connection {
pi.hostname = DEVICE_NAME.lock().unwrap().clone();
pi.platform = "Android".into();
}
#[cfg(any(target_os = "linux", target_os = "windows"))]
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
let mut platform_additions = serde_json::Map::new();
#[cfg(target_os = "linux")]
{
@@ -1064,7 +1076,18 @@ impl Connection {
}
}
#[cfg(any(target_os = "linux", target_os = "windows"))]
#[cfg(any(
target_os = "windows",
all(
any(target_os = "linux", target_os = "macos"),
feature = "unix-file-copy-paste"
)
))]
{
platform_additions.insert("has_file_clipboard".into(), json!(true));
}
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
if !platform_additions.is_empty() {
pi.platform_additions = serde_json::to_string(&platform_additions).unwrap_or("".into());
}
@@ -1164,7 +1187,7 @@ impl Connection {
sub_service = true;
}
}
Self::on_remote_authorized();
self.on_remote_authorized();
}
let mut msg_out = Message::new();
msg_out.set_login_response(res);
@@ -1203,9 +1226,10 @@ impl Connection {
}
}
fn on_remote_authorized() {
fn on_remote_authorized(&self) {
use std::sync::Once;
static ONCE: Once = Once::new();
static _ONCE: Once = Once::new();
self.update_codec_on_login();
#[cfg(any(target_os = "windows", target_os = "linux"))]
if !Config::get_option("allow-remove-wallpaper").is_empty() {
// multi connections set once
@@ -1214,7 +1238,7 @@ impl Connection {
match crate::platform::WallPaperRemover::new() {
Ok(remover) => {
*wallpaper = Some(remover);
ONCE.call_once(|| {
_ONCE.call_once(|| {
shutdown_hooks::add_shutdown_hook(shutdown_hook);
});
}
@@ -1238,7 +1262,7 @@ impl Connection {
self.audio && !self.disable_audio
}
#[cfg(windows)]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
fn file_transfer_enabled(&self) -> bool {
self.file && self.enable_file_transfer
}
@@ -1258,6 +1282,7 @@ impl Connection {
file_transfer_enabled: self.file,
restart: self.restart,
recording: self.recording,
block_input: self.block_input,
from_switch: self.from_switch,
});
}
@@ -1403,8 +1428,8 @@ impl Connection {
return Config::get_option(enable_prefix_option).is_empty();
}
fn update_codec_on_login(&self, lr: &LoginRequest) {
if let Some(o) = lr.option.as_ref() {
fn update_codec_on_login(&self) {
if let Some(o) = self.lr.clone().option.as_ref() {
if let Some(q) = o.supported_decoding.clone().take() {
scrap::codec::Encoder::update(
self.inner.id(),
@@ -1429,9 +1454,6 @@ impl Connection {
if let Some(o) = lr.option.as_ref() {
self.options_in_login = Some(o.clone());
}
if lr.union.is_none() {
self.update_codec_on_login(&lr);
}
self.video_ack_required = lr.video_ack_required;
}
@@ -1856,8 +1878,9 @@ impl Connection {
}
Some(message::Union::Cliprdr(_clip)) =>
{
#[cfg(windows)]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
if let Some(clip) = msg_2_clip(_clip) {
log::debug!("got clipfile from client peer");
self.send_to_cm(ipc::Data::ClipboardFile(clip))
}
}
@@ -1952,30 +1975,43 @@ impl Connection {
}
Some(file_action::Union::RemoveDir(d)) => {
self.send_fs(ipc::FS::RemoveDir {
path: d.path,
path: d.path.clone(),
id: d.id,
recursive: d.recursive,
});
self.file_remove_log_control.on_remove_dir(d);
}
Some(file_action::Union::RemoveFile(f)) => {
self.send_fs(ipc::FS::RemoveFile {
path: f.path,
path: f.path.clone(),
id: f.id,
file_num: f.file_num,
});
self.file_remove_log_control.on_remove_file(f);
}
Some(file_action::Union::Create(c)) => {
self.send_fs(ipc::FS::CreateDir {
path: c.path,
path: c.path.clone(),
id: c.id,
});
self.send_to_cm(ipc::Data::FileTransferLog((
"create_dir".to_string(),
serde_json::to_string(&FileActionLog {
id: c.id,
conn_id: self.inner.id(),
path: c.path,
dir: true,
})
.unwrap_or_default(),
)));
}
Some(file_action::Union::Cancel(c)) => {
self.send_fs(ipc::FS::CancelWrite { id: c.id });
if let Some(job) = fs::get_job_immutable(c.id, &self.read_jobs) {
self.send_to_cm(ipc::Data::FileTransferLog(
self.send_to_cm(ipc::Data::FileTransferLog((
"transfer".to_string(),
fs::serialize_transfer_job(job, false, true, ""),
));
)));
}
fs::remove_job(c.id, &mut self.read_jobs);
}
@@ -2215,8 +2251,9 @@ impl Connection {
}
// Send display changed message.
// For compatibility with old versions ( < 1.2.4 ).
// sciter need it in new version
// 1. For compatibility with old versions ( < 1.2.4 ).
// 2. Sciter version.
// 3. Update `SupportedResolutions`.
if let Some(msg_out) = video_service::make_display_changed_msg(self.display_idx, None) {
self.send(msg_out).await;
}
@@ -2232,7 +2269,11 @@ impl Connection {
lock.add_service(Box::new(video_service::new(display_idx)));
}
}
lock.subscribe(&old_service_name, self.inner.clone(), false);
// For versions greater than 1.2.4, a `CaptureDisplays` message will be sent immediately.
// Unnecessary capturers will be removed then.
if !crate::common::is_support_multi_ui_session(&self.lr.version) {
lock.subscribe(&old_service_name, self.inner.clone(), false);
}
lock.subscribe(&new_service_name, self.inner.clone(), true);
self.display_idx = display_idx;
}
@@ -2439,7 +2480,7 @@ impl Connection {
}
}
}
#[cfg(windows)]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
if let Ok(q) = o.enable_file_transfer.enum_value() {
if q != BoolOption::NotSet {
self.enable_file_transfer = q == BoolOption::Yes;
@@ -2544,8 +2585,8 @@ impl Connection {
}
}
}
if self.keyboard {
if let Ok(q) = o.block_input.enum_value() {
if let Ok(q) = o.block_input.enum_value() {
if self.keyboard && self.block_input {
match q {
BoolOption::Yes => {
self.tx_input.send(MessageInput::BlockOn).ok();
@@ -2555,6 +2596,17 @@ impl Connection {
}
_ => {}
}
} else {
if q != BoolOption::NotSet {
let state = if q == BoolOption::Yes {
back_notification::BlockInputState::BlkOnFailed
} else {
back_notification::BlockInputState::BlkOffFailed
};
if let Some(tx) = &self.inner.tx {
Self::send_block_input_error(tx, state, "No permission".to_string());
}
}
}
}
}
@@ -2909,6 +2961,114 @@ pub enum FileAuditType {
RemoteReceive = 1,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct FileActionLog {
id: i32,
conn_id: i32,
path: String,
dir: bool,
}
struct FileRemoveLogControl {
conn_id: i32,
instant: Instant,
removed_files: Vec<FileRemoveFile>,
removed_dirs: Vec<FileRemoveDir>,
}
impl FileRemoveLogControl {
fn new(conn_id: i32) -> Self {
FileRemoveLogControl {
conn_id,
instant: Instant::now(),
removed_files: vec![],
removed_dirs: vec![],
}
}
fn on_remove_file(&mut self, f: FileRemoveFile) -> Option<ipc::Data> {
self.instant = Instant::now();
self.removed_files.push(f.clone());
Some(ipc::Data::FileTransferLog((
"remove".to_string(),
serde_json::to_string(&FileActionLog {
id: f.id,
conn_id: self.conn_id,
path: f.path,
dir: false,
})
.unwrap_or_default(),
)))
}
fn on_remove_dir(&mut self, d: FileRemoveDir) -> Option<ipc::Data> {
self.instant = Instant::now();
let direct_child = |parent: &str, child: &str| {
PathBuf::from(child).parent().map(|x| x.to_path_buf()) == Some(PathBuf::from(parent))
};
self.removed_files
.retain(|f| !direct_child(&f.path, &d.path));
self.removed_dirs
.retain(|x| !direct_child(&d.path, &x.path));
if !self
.removed_dirs
.iter()
.any(|x| direct_child(&x.path, &d.path))
{
self.removed_dirs.push(d.clone());
}
Some(ipc::Data::FileTransferLog((
"remove".to_string(),
serde_json::to_string(&FileActionLog {
id: d.id,
conn_id: self.conn_id,
path: d.path,
dir: true,
})
.unwrap_or_default(),
)))
}
fn on_timer(&mut self) -> Vec<ipc::Data> {
if self.instant.elapsed().as_secs() < 1 {
return vec![];
}
let mut v: Vec<ipc::Data> = vec![];
self.removed_files
.drain(..)
.map(|f| {
v.push(ipc::Data::FileTransferLog((
"remove".to_string(),
serde_json::to_string(&FileActionLog {
id: f.id,
conn_id: self.conn_id,
path: f.path,
dir: false,
})
.unwrap_or_default(),
)));
})
.count();
self.removed_dirs
.drain(..)
.map(|d| {
v.push(ipc::Data::FileTransferLog((
"remove".to_string(),
serde_json::to_string(&FileActionLog {
id: d.id,
conn_id: self.conn_id,
path: d.path,
dir: true,
})
.unwrap_or_default(),
)));
})
.count();
v
}
}
#[cfg(windows)]
pub struct PortableState {
pub last_uac: bool,
@@ -3002,18 +3162,6 @@ mod raii {
fn drop(&mut self) {
let mut active_conns_lock = ALIVE_CONNS.lock().unwrap();
active_conns_lock.retain(|&c| c != self.0);
#[cfg(not(any(target_os = "android", target_os = "ios")))]
if active_conns_lock.is_empty() {
display_service::reset_resolutions();
}
#[cfg(all(windows, feature = "virtual_display_driver"))]
if active_conns_lock.is_empty() {
let _ = virtual_display_manager::reset_all();
}
#[cfg(all(windows))]
if active_conns_lock.is_empty() {
crate::privacy_win_mag::stop();
}
video_service::VIDEO_QOS
.lock()
.unwrap()
@@ -3021,17 +3169,20 @@ mod raii {
}
}
pub struct AuthedConnID(i32);
pub struct AuthedConnID(i32, AuthConnType);
impl AuthedConnID {
pub fn new(id: i32, conn_type: AuthConnType) -> Self {
AUTHED_CONNS.lock().unwrap().push((id, conn_type));
Self(id)
Self(id, conn_type)
}
}
impl Drop for AuthedConnID {
fn drop(&mut self) {
if self.1 == AuthConnType::Remote {
scrap::codec::Encoder::update(self.0, scrap::codec::EncodingUpdate::Remove);
}
let mut lock = AUTHED_CONNS.lock().unwrap();
lock.retain(|&c| c.0 != self.0);
if lock.iter().filter(|c| c.1 == AuthConnType::Remote).count() == 0 {
@@ -3039,6 +3190,12 @@ mod raii {
{
*WALLPAPER_REMOVER.lock().unwrap() = None;
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
display_service::reset_resolutions();
#[cfg(all(windows, feature = "virtual_display_driver"))]
let _ = virtual_display_manager::reset_all();
#[cfg(all(windows))]
crate::privacy_win_mag::stop();
}
}
}

View File

@@ -12,6 +12,7 @@ use scrap::Display;
pub const NAME: &'static str = "display";
#[cfg(all(windows, feature = "virtual_display_driver"))]
const DUMMY_DISPLAY_SIDE_MAX_SIZE: usize = 1024;
struct ChangedResolution {
@@ -349,7 +350,7 @@ pub fn try_get_displays() -> ResultType<Vec<Display>> {
#[cfg(all(windows, feature = "virtual_display_driver"))]
pub fn try_get_displays() -> ResultType<Vec<Display>> {
let mut displays = Display::all()?;
if no_displays(&displays) {
if crate::platform::is_installed() && no_displays(&displays) {
log::debug!("no displays, create virtual display");
if let Err(e) = virtual_display_manager::plug_in_headless() {
log::error!("plug in headless failed {}", e);

View File

@@ -8,7 +8,7 @@ use hbb_common::{
tokio::{self, sync::mpsc},
ResultType,
};
use scrap::{Capturer, Frame, TraitCapturer};
use scrap::{Capturer, Frame, TraitCapturer, TraitFrame};
use shared_memory::*;
use std::{
mem::size_of,
@@ -300,7 +300,6 @@ pub mod server {
fn run_capture(shmem: Arc<SharedMemory>) {
let mut c = None;
let mut last_current_display = usize::MAX;
let mut last_use_yuv = false;
let mut last_timeout_ms: i32 = 33;
let mut spf = Duration::from_millis(last_timeout_ms as _);
let mut first_frame_captured = false;
@@ -316,14 +315,7 @@ pub mod server {
let para = para_ptr as *const CapturerPara;
let recreate = (*para).recreate;
let current_display = (*para).current_display;
let use_yuv = (*para).use_yuv;
let use_yuv_set = (*para).use_yuv_set;
let timeout_ms = (*para).timeout_ms;
if !use_yuv_set {
c = None;
std::thread::sleep(spf);
continue;
}
if c.is_none() {
let Ok(mut displays) = display_service::try_get_displays() else {
log::error!("Failed to get displays");
@@ -338,11 +330,10 @@ pub mod server {
let display = displays.remove(current_display);
display_width = display.width();
display_height = display.height();
match Capturer::new(display, use_yuv) {
match Capturer::new(display) {
Ok(mut v) => {
c = {
last_current_display = current_display;
last_use_yuv = use_yuv;
first_frame_captured = false;
if dxgi_failed_times > MAX_DXGI_FAIL_TIME {
dxgi_failed_times = 0;
@@ -353,8 +344,6 @@ pub mod server {
CapturerPara {
recreate: false,
current_display: (*para).current_display,
use_yuv: (*para).use_yuv,
use_yuv_set: (*para).use_yuv_set,
timeout_ms: (*para).timeout_ms,
},
);
@@ -368,16 +357,11 @@ pub mod server {
}
}
} else {
if recreate
|| current_display != last_current_display
|| use_yuv != last_use_yuv
{
if recreate || current_display != last_current_display {
log::info!(
"create capturer, display:{}->{}, use_yuv:{}->{}",
"create capturer, display:{}->{}",
last_current_display,
current_display,
last_use_yuv,
use_yuv
);
c = None;
continue;
@@ -401,12 +385,12 @@ pub mod server {
utils::set_frame_info(
&shmem,
FrameInfo {
length: f.0.len(),
length: f.data().len(),
width: display_width,
height: display_height,
},
);
shmem.write(ADDR_CAPTURE_FRAME, f.0);
shmem.write(ADDR_CAPTURE_FRAME, f.data());
shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE));
utils::increase_counter(shmem.as_ptr().add(ADDR_CAPTURE_FRAME_COUNTER));
first_frame_captured = true;
@@ -651,7 +635,7 @@ pub mod client {
}
impl CapturerPortable {
pub fn new(current_display: usize, use_yuv: bool) -> Self
pub fn new(current_display: usize) -> Self
where
Self: Sized,
{
@@ -665,8 +649,6 @@ pub mod client {
CapturerPara {
recreate: true,
current_display,
use_yuv,
use_yuv_set: false,
timeout_ms: 33,
},
);
@@ -684,26 +666,6 @@ pub mod client {
}
impl TraitCapturer for CapturerPortable {
fn set_use_yuv(&mut self, use_yuv: bool) {
let mut option = SHMEM.lock().unwrap();
if let Some(shmem) = option.as_mut() {
unsafe {
let para_ptr = shmem.as_ptr().add(ADDR_CAPTURER_PARA);
let para = para_ptr as *const CapturerPara;
utils::set_para(
shmem,
CapturerPara {
recreate: (*para).recreate,
current_display: (*para).current_display,
use_yuv,
use_yuv_set: true,
timeout_ms: (*para).timeout_ms,
},
);
}
}
}
fn frame<'a>(&'a mut self, timeout: Duration) -> std::io::Result<Frame<'a>> {
let mut lock = SHMEM.lock().unwrap();
let shmem = lock.as_mut().ok_or(std::io::Error::new(
@@ -720,8 +682,6 @@ pub mod client {
CapturerPara {
recreate: (*para).recreate,
current_display: (*para).current_display,
use_yuv: (*para).use_yuv,
use_yuv_set: (*para).use_yuv_set,
timeout_ms: timeout.as_millis() as _,
},
);
@@ -744,7 +704,7 @@ pub mod client {
}
let frame_ptr = base.add(ADDR_CAPTURE_FRAME);
let data = slice::from_raw_parts(frame_ptr, (*frame_info).length);
Ok(Frame(data))
Ok(Frame::new(data, self.width, self.height))
} else {
let ptr = base.add(ADDR_CAPTURE_WOULDBLOCK);
let wouldblock = utils::ptr_to_i32(ptr);
@@ -910,7 +870,6 @@ pub mod client {
pub fn create_capturer(
current_display: usize,
display: scrap::Display,
use_yuv: bool,
portable_service_running: bool,
) -> ResultType<Box<dyn TraitCapturer>> {
if portable_service_running != RUNNING.lock().unwrap().clone() {
@@ -919,7 +878,7 @@ pub mod client {
if portable_service_running {
log::info!("Create shared memory capturer");
if current_display == *display_service::PRIMARY_DISPLAY_IDX {
return Ok(Box::new(CapturerPortable::new(current_display, use_yuv)));
return Ok(Box::new(CapturerPortable::new(current_display)));
} else {
bail!(
"Ignore capture display index: {}, the primary display index is: {}",
@@ -930,7 +889,7 @@ pub mod client {
} else {
log::debug!("Create capturer dxgi|gdi");
return Ok(Box::new(
Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?,
Capturer::new(display).with_context(|| "Failed to create capturer")?,
));
}
}
@@ -981,8 +940,6 @@ pub mod client {
pub struct CapturerPara {
recreate: bool,
current_display: usize,
use_yuv: bool,
use_yuv_set: bool,
timeout_ms: i32,
}

View File

@@ -42,9 +42,10 @@ use scrap::Capturer;
use scrap::{
aom::AomEncoderConfig,
codec::{Encoder, EncoderCfg, HwEncoderConfig, Quality},
convert_to_yuv,
record::{Recorder, RecorderContext},
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
CodecName, Display, TraitCapturer,
CodecName, Display, Frame, TraitCapturer, TraitFrame,
};
#[cfg(windows)]
use std::sync::Once;
@@ -171,7 +172,6 @@ pub fn new(idx: usize) -> GenericService {
fn create_capturer(
privacy_mode_id: i32,
display: Display,
use_yuv: bool,
_current: usize,
_portable_service_running: bool,
) -> ResultType<Box<dyn TraitCapturer>> {
@@ -182,12 +182,7 @@ fn create_capturer(
if privacy_mode_id > 0 {
#[cfg(windows)]
{
match scrap::CapturerMag::new(
display.origin(),
display.width(),
display.height(),
use_yuv,
) {
match scrap::CapturerMag::new(display.origin(), display.width(), display.height()) {
Ok(mut c1) => {
let mut ok = false;
let check_begin = Instant::now();
@@ -236,12 +231,11 @@ fn create_capturer(
return crate::portable_service::client::create_capturer(
_current,
display,
use_yuv,
_portable_service_running,
);
#[cfg(not(windows))]
return Ok(Box::new(
Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?,
Capturer::new(display).with_context(|| "Failed to create capturer")?,
));
}
};
@@ -265,7 +259,7 @@ pub fn test_create_capturer(
)
} else {
let display = displays.remove(display_idx);
match create_capturer(privacy_mode_id, display, true, display_idx, false) {
match create_capturer(privacy_mode_id, display, display_idx, false) {
Ok(_) => return "".to_owned(),
Err(e) => e,
}
@@ -320,11 +314,7 @@ impl DerefMut for CapturerInfo {
}
}
fn get_capturer(
current: usize,
use_yuv: bool,
portable_service_running: bool,
) -> ResultType<CapturerInfo> {
fn get_capturer(current: usize, portable_service_running: bool) -> ResultType<CapturerInfo> {
#[cfg(target_os = "linux")]
{
if !is_x11() {
@@ -382,7 +372,6 @@ fn get_capturer(
let capturer = create_capturer(
capturer_privacy_mode_id,
display,
use_yuv,
current,
portable_service_running,
)?;
@@ -424,7 +413,7 @@ fn run(vs: VideoService) -> ResultType<()> {
let display_idx = vs.idx;
let sp = vs.sp;
let mut c = get_capturer(display_idx, true, last_portable_service_running)?;
let mut c = get_capturer(display_idx, last_portable_service_running)?;
let mut video_qos = VIDEO_QOS.lock().unwrap();
video_qos.refresh(None);
@@ -439,11 +428,11 @@ fn run(vs: VideoService) -> ResultType<()> {
let encoder_cfg = get_encoder_config(&c, quality, last_recording);
let mut encoder;
match Encoder::new(encoder_cfg) {
let use_i444 = Encoder::use_i444(&encoder_cfg);
match Encoder::new(encoder_cfg.clone(), use_i444) {
Ok(x) => encoder = x,
Err(err) => bail!("Failed to create encoder: {}", err),
}
c.set_use_yuv(encoder.use_yuv());
VIDEO_QOS.lock().unwrap().store_bitrate(encoder.bitrate());
if sp.is_option_true(OPTION_REFRESH) {
@@ -463,6 +452,8 @@ fn run(vs: VideoService) -> ResultType<()> {
#[cfg(target_os = "linux")]
let mut would_block_count = 0u32;
let mut yuv = Vec::new();
let mut mid_data = Vec::new();
while sp.ok() {
#[cfg(windows)]
@@ -493,6 +484,9 @@ fn run(vs: VideoService) -> ResultType<()> {
if last_portable_service_running != crate::portable_service::client::running() {
bail!("SWITCH");
}
if Encoder::use_i444(&encoder_cfg) != use_i444 {
bail!("SWITCH");
}
check_privacy_mode_changed(&sp, c.privacy_mode_id)?;
#[cfg(windows)]
{
@@ -512,40 +506,23 @@ fn run(vs: VideoService) -> ResultType<()> {
frame_controller.reset();
#[cfg(any(target_os = "android", target_os = "ios"))]
let res = match c.frame(spf) {
Ok(frame) => {
let time = now - start;
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
match frame {
scrap::Frame::RAW(data) => {
if data.len() != 0 {
let send_conn_ids = handle_one_frame(
display_idx,
&sp,
data,
ms,
&mut encoder,
recorder.clone(),
)?;
frame_controller.set_send(now, send_conn_ids);
}
}
_ => {}
};
Ok(())
}
Err(err) => Err(err),
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let res = match c.frame(spf) {
Ok(frame) => {
let time = now - start;
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
let send_conn_ids =
handle_one_frame(display_idx, &sp, &frame, ms, &mut encoder, recorder.clone())?;
frame_controller.set_send(now, send_conn_ids);
if frame.data().len() != 0 {
let send_conn_ids = handle_one_frame(
display_idx,
&sp,
frame,
&mut yuv,
&mut mid_data,
ms,
&mut encoder,
recorder.clone(),
)?;
frame_controller.set_send(now, send_conn_ids);
}
#[cfg(windows)]
{
try_gdi = 0;
@@ -718,7 +695,9 @@ fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> Resu
fn handle_one_frame(
display: usize,
sp: &GenericService,
frame: &[u8],
frame: Frame,
yuv: &mut Vec<u8>,
mid_data: &mut Vec<u8>,
ms: i64,
encoder: &mut Encoder,
recorder: Arc<Mutex<Option<Recorder>>>,
@@ -732,7 +711,8 @@ fn handle_one_frame(
})?;
let mut send_conn_ids: HashSet<i32> = Default::default();
if let Ok(mut vf) = encoder.encode_to_message(frame, ms) {
convert_to_yuv(&frame, encoder.yuvfmt(), yuv, mid_data)?;
if let Ok(mut vf) = encoder.encode_to_message(yuv, ms) {
vf.display = display as _;
let mut msg = Message::new();
msg.set_video_frame(vf);

View File

@@ -76,12 +76,6 @@ impl TraitCapturer for CapturerPtr {
fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
unsafe { (*self.0).frame(timeout) }
}
fn set_use_yuv(&mut self, use_yuv: bool) {
unsafe {
(*self.0).set_use_yuv(use_yuv);
}
}
}
struct CapDisplayInfo {
@@ -192,7 +186,8 @@ pub(super) async fn check_init() -> ResultType<()> {
maxy = max_height;
let capturer = Box::into_raw(Box::new(
Capturer::new(display, true).with_context(|| "Failed to create capturer")?,
Capturer::new(display)
.with_context(|| "Failed to create capturer")?,
));
let capturer = CapturerPtr(capturer);
let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo {