fix(avhw): handle tx.send() failure and pause encoding on WebRTC disconnect (closes #6)

- Replace 'let _ = tx.send()' with proper error handling: log warning,
  set webrtc_disconnected flag, and break drain loop on SendError
- Add Arc<AtomicBool> webrtc_paused shared between State/StatePortal
  and SwEncState, synced from wrtc.is_connected() in poll_webrtc()
- Skip encoding in encode_filtered_frame() when paused or disconnected
- Drain and discard stale channel frames on disconnect
- Resume encoding automatically on WebRTC reconnection
This commit is contained in:
dailz
2026-06-06 15:12:49 +08:00
parent fd170b66d9
commit 226768c3e3
3 changed files with 163 additions and 47 deletions
+25 -1
View File
@@ -3,6 +3,8 @@ use std::mem;
use std::os::fd::{AsRawFd, RawFd};
use std::os::raw::c_void;
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::ptr;
use anyhow::{bail, Result};
@@ -611,6 +613,8 @@ pub struct SwEncState {
yuv_frame: *mut ffi::AVFrame,
starting_timestamp: Option<i64>,
frames_written: bool,
webrtc_disconnected: bool,
webrtc_paused: Option<Arc<AtomicBool>>,
}
unsafe impl Send for SwEncState {}
@@ -660,6 +664,8 @@ impl SwEncState {
yuv_frame,
starting_timestamp: None,
frames_written: false,
webrtc_disconnected: false,
webrtc_paused: None,
})
}
@@ -674,6 +680,7 @@ impl SwEncState {
bitrate: u64,
gop_size: u32,
tx: crossbeam_channel::Sender<Vec<u8>>,
webrtc_paused: Arc<AtomicBool>,
) -> Result<Self> {
tracing::info!(
"SwEncState::new_webrtc: GPU downscale {width}x{height} BGRA -> {enc_width}x{enc_height} NV12, software H.264 -> WebRTC"
@@ -705,6 +712,8 @@ impl SwEncState {
yuv_frame,
starting_timestamp: None,
frames_written: false,
webrtc_disconnected: false,
webrtc_paused: Some(webrtc_paused),
})
}
@@ -774,6 +783,14 @@ impl SwEncState {
}
fn encode_filtered_frame(&mut self, filtered: &ff::frame::Video) -> Result<()> {
if self.webrtc_disconnected {
return Ok(());
}
if let Some(ref paused) = self.webrtc_paused {
if paused.load(Ordering::Relaxed) {
return Ok(());
}
}
let mut sw_nv12 = unsafe { ffi::av_frame_alloc() };
if sw_nv12.is_null() {
bail!("av_frame_alloc failed for NV12 transfer frame");
@@ -876,7 +893,14 @@ impl SwEncState {
let data: &[u8] = unsafe {
std::slice::from_raw_parts(raw.data, raw.size as usize)
};
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;
}
}
}
None => {}