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:
29
src/state.rs
29
src/state.rs
@@ -3,6 +3,8 @@ use std::mem;
|
||||
use std::os::fd::{AsFd, OwnedFd};
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use anyhow::Result;
|
||||
@@ -223,6 +225,7 @@ pub struct State<S: CaptureSource> {
|
||||
pub webrtc_tx: Option<crossbeam_channel::Sender<Vec<u8>>>,
|
||||
webrtc_rx: Option<crossbeam_channel::Receiver<Vec<u8>>>,
|
||||
webrtc_frames_sent: u64,
|
||||
webrtc_paused: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -273,12 +276,14 @@ impl<S: CaptureSource> State<S> {
|
||||
let fps = args.fps;
|
||||
let drm_device = args.drm_device.as_ref().map(PathBuf::from);
|
||||
|
||||
let (webrtc, webrtc_tx, webrtc_rx) = if args.port > 0 {
|
||||
let (webrtc, webrtc_tx, webrtc_rx, webrtc_paused) = if args.port > 0 {
|
||||
let (tx, rx) = crossbeam_channel::bounded(32);
|
||||
let wrtc = WebRtcState::new(args.port, args.fps)?;
|
||||
(Some(wrtc), Some(tx), Some(rx))
|
||||
// paused=true until first WebRTC client connects
|
||||
let paused = Arc::new(AtomicBool::new(true));
|
||||
(Some(wrtc), Some(tx), Some(rx), Some(paused))
|
||||
} else {
|
||||
(None, None, None)
|
||||
(None, None, None, None)
|
||||
};
|
||||
|
||||
let mut state = Self {
|
||||
@@ -309,6 +314,7 @@ impl<S: CaptureSource> State<S> {
|
||||
webrtc_tx,
|
||||
webrtc_rx,
|
||||
webrtc_frames_sent: 0,
|
||||
webrtc_paused,
|
||||
};
|
||||
|
||||
// registry_queue_init consumes registry events internally during its
|
||||
@@ -641,9 +647,25 @@ impl<S: CaptureSource> State<S> {
|
||||
wrtc.handle_signaling()?;
|
||||
wrtc.poll_and_feed()?;
|
||||
|
||||
let connected = wrtc.is_connected();
|
||||
|
||||
if let Some(ref paused) = self.webrtc_paused {
|
||||
let was_paused = paused.load(Ordering::Relaxed);
|
||||
let now_paused = !connected;
|
||||
if was_paused && !now_paused {
|
||||
tracing::info!("WebRTC client connected, resuming encoding");
|
||||
} else if !was_paused && now_paused {
|
||||
tracing::warn!("WebRTC client disconnected, pausing encoding");
|
||||
}
|
||||
paused.store(now_paused, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
if let Some(ref rx) = self.webrtc_rx {
|
||||
let mut count = 0u32;
|
||||
while let Ok(data) = rx.try_recv() {
|
||||
if !connected {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
if let Err(e) = wrtc.write_h264_frame(&data, self.webrtc_frames_sent, self.args.fps) {
|
||||
tracing::debug!("WebRTC write frame error: {e}");
|
||||
@@ -703,6 +725,7 @@ impl<S: CaptureSource> State<S> {
|
||||
bitrate,
|
||||
actual_gop_size,
|
||||
tx.clone(),
|
||||
self.webrtc_paused.as_ref().expect("webrtc_paused must exist when webrtc_tx exists").clone(),
|
||||
) {
|
||||
Ok(enc) => StreamingEncoder::WebRtc(enc),
|
||||
Err(e) => {
|
||||
|
||||
Reference in New Issue
Block a user