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:
1 parent
bd7ca29945
commit
168f600fe1
3 files changed
+34
-9
No files matched your search
+17
-3
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user