Bug: tx.send() 失败被静默忽略,编码器继续无效工作 (avhw.rs) #6

Closed
opened 2026-06-04 20:58:52 +08:00 by dailz · 1 comment
Owner

位置

src/avhw.rs:875

严重性

🟡

问题描述

tx.send() 返回 Result<(), SendError<T>>,当接收端(WebRTC 客户端)断开连接时 channel 会被关闭,send 将失败。当前用 let _ = 忽略返回值,会导致:

  1. 编码器在连接断开后继续消耗资源编码帧
  2. 没有任何日志或错误上报,发送端对断连完全无感知

建议修复

记录 warning 并 break 退出 drain 循环,避免无效编码:

Some(FrameOutput::Channel(ref tx)) => {
    // SAFETY: avcodec_receive_packet just succeeded
    let data: &[u8] = unsafe { /* ... */ };
    if tx.send(data.to_vec()).is_err() {
        tracing::warn!("WebRTC channel send failed (receiver disconnected)");
        break;
    }
}
## 位置 `src/avhw.rs:875` ## 严重性 🟡 中 ## 问题描述 `tx.send()` 返回 `Result<(), SendError<T>>`,当接收端(WebRTC 客户端)断开连接时 channel 会被关闭,`send` 将失败。当前用 `let _ =` 忽略返回值,会导致: 1. 编码器在连接断开后继续消耗资源编码帧 2. 没有任何日志或错误上报,发送端对断连完全无感知 ## 建议修复 记录 warning 并 break 退出 drain 循环,避免无效编码: ```rust Some(FrameOutput::Channel(ref tx)) => { // SAFETY: avcodec_receive_packet just succeeded let data: &[u8] = unsafe { /* ... */ }; if tx.send(data.to_vec()).is_err() { tracing::warn!("WebRTC channel send failed (receiver disconnected)"); break; } } ```
dailz closed this issue 2026-06-06 15:12:56 +08:00
Author
Owner

修复方案

第一层:channel 断开检测(SendError)

drain_encoder() 中将 let _ = tx.send(data.to_vec()) 替换为:

if let Err(e) = tx.send(data.to_vec()) {
    tracing::warn!("WebRTC channel send failed (receiver dropped): {} bytes lost", e.0.len());
    self.webrtc_disconnected = true;
    break;
}

设置 webrtc_disconnected 终态标志,encode_filtered_frame() 在标志为 true 时跳过编码,避免反复 drain 做无用功。

第二层:WebRTC 客户端断连感知(AtomicBool)

经 Oracle 审核发现:WebRTC 客户端断连时 receiver 不会被 drop(它存活在 State 生命周期内),tx.send() 永远不会返回 SendError。

因此新增 Arc<AtomicBool> webrtc_paused 共享于 State ↔ SwEncState:

  • poll_webrtc() 中同步 wrtc.is_connected()webrtc_paused
  • encode_filtered_frame() 检查 webrtc_paused,断连时跳过编码
  • 重连时自动恢复编码
  • 初始值 true(首个客户端连接前暂停编码)

断连时丢弃陈旧帧

poll_webrtc()rx.try_recv()!connectedcontinue 丢弃队列中的陈旧帧,不再传给 write_h264_frame()

改动文件

  • src/avhw.rs:SwEncState 新增两个标志 + encode_filtered_frame 双重早返回 + drain_encoder 错误处理
  • src/state.rs:State 新增 webrtc_paused + poll_webrtc 同步标志 + 传 clone 给 new_webrtc
  • src/state_portal.rs:与 state.rs 对称的改动

Commit: 226768c

## 修复方案 ### 第一层:channel 断开检测(SendError) `drain_encoder()` 中将 `let _ = tx.send(data.to_vec())` 替换为: ```rust if let Err(e) = tx.send(data.to_vec()) { tracing::warn!("WebRTC channel send failed (receiver dropped): {} bytes lost", e.0.len()); self.webrtc_disconnected = true; break; } ``` 设置 `webrtc_disconnected` 终态标志,`encode_filtered_frame()` 在标志为 true 时跳过编码,避免反复 drain 做无用功。 ### 第二层:WebRTC 客户端断连感知(AtomicBool) 经 Oracle 审核发现:WebRTC 客户端断连时 receiver 不会被 drop(它存活在 State 生命周期内),`tx.send()` 永远不会返回 SendError。 因此新增 `Arc<AtomicBool> webrtc_paused` 共享于 State ↔ SwEncState: - `poll_webrtc()` 中同步 `wrtc.is_connected()` → `webrtc_paused` - `encode_filtered_frame()` 检查 `webrtc_paused`,断连时跳过编码 - 重连时自动恢复编码 - 初始值 `true`(首个客户端连接前暂停编码) ### 断连时丢弃陈旧帧 `poll_webrtc()` 中 `rx.try_recv()` 在 `!connected` 时 `continue` 丢弃队列中的陈旧帧,不再传给 `write_h264_frame()`。 ### 改动文件 - `src/avhw.rs`:SwEncState 新增两个标志 + encode_filtered_frame 双重早返回 + drain_encoder 错误处理 - `src/state.rs`:State 新增 webrtc_paused + poll_webrtc 同步标志 + 传 clone 给 new_webrtc - `src/state_portal.rs`:与 state.rs 对称的改动 Commit: 226768c
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dailz/wl-webrtc#6