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:
+25
-1
@@ -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 => {}
|
||||
|
||||
Reference in New Issue
Block a user