fix(webrtc): propagate poll_output error as cleanup signal to prevent zombie state (closes #14)

This commit is contained in:
dailz
2026-06-06 21:48:38 +08:00
parent e6e05fb44a
commit f3da1e4e6c

View File

@@ -246,8 +246,14 @@ impl WebRtcState {
} }
pub fn write_h264_frame(&mut self, data: &[u8], frame_number: u64, fps: u32) -> Result<()> { pub fn write_h264_frame(&mut self, data: &[u8], frame_number: u64, fps: u32) -> Result<()> {
if let Some(inner) = self.inner.as_mut() { let should_destroy = if let Some(inner) = self.inner.as_mut() {
inner.write_h264_frame(data, frame_number, fps)?; inner.write_h264_frame(data, frame_number, fps)?
} else {
false
};
if should_destroy {
tracing::warn!("WebRTC connection failed during write; clearing connection state");
self.inner = None;
} }
Ok(()) Ok(())
} }
@@ -379,7 +385,8 @@ impl WebRtcInner {
Ok(Output::Timeout(_t)) => break, Ok(Output::Timeout(_t)) => break,
Err(e) => { Err(e) => {
tracing::error!("rtc.poll_output error: {e}"); tracing::error!("rtc.poll_output error: {e}");
break; self.connected = false;
return Ok(true);
} }
} }
} }
@@ -423,23 +430,23 @@ impl WebRtcInner {
Ok(()) Ok(())
} }
fn write_h264_frame(&mut self, data: &[u8], frame_number: u64, fps: u32) -> Result<()> { fn write_h264_frame(&mut self, data: &[u8], frame_number: u64, fps: u32) -> Result<bool> {
if !self.connected { if !self.connected {
return Ok(()); return Ok(false);
} }
let mid = match self.video_mid { let mid = match self.video_mid {
Some(m) => m, Some(m) => m,
None => { None => {
tracing::warn!("write_h264: no video_mid"); tracing::warn!("write_h264: no video_mid");
return Ok(()); return Ok(false);
} }
}; };
let pt = match self.video_pt { let pt = match self.video_pt {
Some(p) => p, Some(p) => p,
None => { None => {
tracing::warn!("write_h264: no video_pt"); tracing::warn!("write_h264: no video_pt");
return Ok(()); return Ok(false);
} }
}; };
@@ -449,7 +456,7 @@ impl WebRtcInner {
"write_h264: skipping non-IDR frame ({} bytes), waiting for keyframe", "write_h264: skipping non-IDR frame ({} bytes), waiting for keyframe",
data.len() data.len()
); );
return Ok(()); return Ok(false);
} }
tracing::info!( tracing::info!(
"write_h264: got IDR keyframe ({} bytes), starting playback", "write_h264: got IDR keyframe ({} bytes), starting playback",
@@ -468,7 +475,7 @@ impl WebRtcInner {
Some(w) => w, Some(w) => w,
None => { None => {
tracing::warn!("write_h264: no writer for mid={mid}"); tracing::warn!("write_h264: no writer for mid={mid}");
return Ok(()); return Ok(false);
} }
}; };
@@ -482,9 +489,9 @@ impl WebRtcInner {
.write(pt, Instant::now(), rtp_time, data) .write(pt, Instant::now(), rtp_time, data)
.map_err(|e| anyhow::anyhow!("writer.write: {e}"))?; .map_err(|e| anyhow::anyhow!("writer.write: {e}"))?;
self.poll_rtc()?; let should_destroy = self.poll_rtc()?;
Ok(()) Ok(should_destroy)
} }
fn is_connected(&self) -> bool { fn is_connected(&self) -> bool {