perf(agent): E2E 排队修复——发送窗口 512KB→64KB + 拥塞反馈自动跳帧

- 实测数据:FPS 61 / RTT 7ms / E2E 618ms → 延迟全在发送侧排队:
  512KB 窗口 ÷ WiFi 实际 ~3Mbps 吞吐 ≈ 1.3s 排队上限,latest-wins 管不到已进 QUIC 的字节
- send_window 64KB:排队硬上限 ~170ms@3Mbps;突发吞吐 64KB/7ms≈72Mbps 不受限;
  连接级窗口,流 2 输入数据量极小不受影响
- 拥塞反馈跳帧:send write 耗时 >20ms(单帧预算 1.2 倍) → 置位标志 → 采集线程
  跳过当前帧(NVENC 少输入一帧,参考链连续无花屏),注入率自适应匹配网络吞吐;
  capture 日志新增 skipped 计数
- viewer 标题版本 v0.7-LowLatency
- 回环实测:NVENC 4ms/帧、skipped 0(回环无拥塞符合预期)、零错误
This commit is contained in:
dev-team committed 2026-10-23 12:48:16 +08:00
1 parent bd7ca29945
commit 168f600fe1
3 files changed
+34 -9

No files matched your search

+17 -3
View File
@@ -275,7 +275,8 @@ pub fn desktop_size() -> Result<(u32, u32)> {
/// 采集主循环:独立线程运行;连接断开(通道关闭)时退出。
/// 通道为 watch 单槽(latest-wins):发送即覆盖,网络慢时不产生积压。
pub fn run(tx: Sender<Option<Vec<u8>>>, keyreq: Arc<AtomicBool>) {
/// congestion:发送侧 write 超时置位 → 跳过当前帧(不编码不发送),注入率自适应降速。
pub fn run(tx: Sender<Option<Vec<u8>>>, keyreq: Arc<AtomicBool>, congestion: Arc<AtomicBool>) {
let start = Instant::now();
loop {
let mut dup = match Duplication::new() {
@@ -333,6 +334,7 @@ pub fn run(tx: Sender<Option<Vec<u8>>>, keyreq: Arc<AtomicBool>) {
let mut stat_frames = 0u64;
let mut stat_convert_ms = 0u64;
let mut stat_encode_ms = 0u64;
let mut stat_skipped = 0u64; // 拥塞跳帧计数
macro_rules! emit {
($payload:expr) => {{
@@ -357,6 +359,16 @@ pub fn run(tx: Sender<Option<Vec<u8>>>, keyreq: Arc<AtomicBool>) {
Ok(true) => {
// 主控端请求关键帧(解码异常恢复)
let force_key = keyreq.swap(false, Ordering::Relaxed);
// 拥塞反馈:发送侧排队深 → 跳过本帧(NVENC 少输入一帧,参考链连续;
// 解码端收到的帧序 = 编码端实际输出序,无花屏风险)
if congestion.swap(false, Ordering::Relaxed) {
stat_skipped += 1;
let el = iter_start.elapsed();
if el < min_frame {
std::thread::sleep(min_frame - el);
}
continue;
}
match &mut encoder {
EncoderKind::Nvenc(enc) => {
let enc_start = Instant::now();
@@ -412,12 +424,14 @@ pub fn run(tx: Sender<Option<Vec<u8>>>, keyreq: Arc<AtomicBool>) {
}
if stat_frames > 0 && stat_frames % 120 == 0 {
eprintln!(
"[capture] avg convert {}ms, encode {}ms/frame (last 120)",
"[capture] avg convert {}ms, encode {}ms/frame, skipped {} (last 120)",
stat_convert_ms / 120,
stat_encode_ms / 120
stat_encode_ms / 120,
stat_skipped
);
stat_convert_ms = 0;
stat_encode_ms = 0;
stat_skipped = 0;
}
// 帧间隔节流到 ~60fps
let el = iter_start.elapsed();