From 5d51457eea713762c7846e9535b88246bcdb0896 Mon Sep 17 00:00:00 2001 From: Long Chen Date: Tue, 7 Jul 2026 11:51:55 +0800 Subject: [PATCH 1/2] fix: don't log expected publisher data channel close as unexpected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the server tears a session down (e.g. the room is deleted) it closes the publisher data channels from the remote side before the engine sets its own `closed` flag, so the close was logged at ERROR as "publisher data channel closed unexpectedly" even though it was expected. Record the terminal disconnect (server `Leave{Disconnect}`) and skip the error for the close it triggers. Genuine unexpected closes — e.g. an oversized message silently killing the channel — still log, and Resume/Reconnect are unaffected. --- livekit/src/rtc_engine/rtc_session.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index 4bb9ff54a..cf278f69c 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -413,6 +413,9 @@ struct SessionInner { dt_packet_tx: DataTrackSendQueue, closed: AtomicBool, + // Set on a terminal disconnect (server `Leave{Disconnect}`) so the publisher + // data-channel close it triggers isn't logged as unexpected + disconnecting: AtomicBool, emitter: SessionEmitter, options: EngineOptions, @@ -617,6 +620,7 @@ impl RtcSession { sub_data_track_dc: Mutex::new(None), dt_packet_tx, closed: Default::default(), + disconnecting: Default::default(), emitter, options, negotiation_debouncer: Default::default(), @@ -642,7 +646,10 @@ impl RtcSession { let Some(inner) = weak_inner.upgrade() else { return; }; - if !inner.closed.load(Ordering::Acquire) && inner.publisher_pc.is_connected() { + if !inner.closed.load(Ordering::Acquire) + && !inner.disconnecting.load(Ordering::Acquire) + && inner.publisher_pc.is_connected() + { log::error!("publisher data channel '{}' closed unexpectedly", label); } }))); @@ -1876,6 +1883,11 @@ impl SessionInner { action: proto::leave_request::Action, retry_now: bool, ) { + // A terminal disconnect (e.g. room deleted) closes the publisher data channels + // from the remote side; flag it so that close isn't logged as unexpected + if action == proto::leave_request::Action::Disconnect { + self.disconnecting.store(true, Ordering::Release); + } let _ = self.emitter.send(SessionEvent::Close { source: source.to_owned(), reason, From 1b3a19ff928860a9d0e9d98424a4285d36d62453 Mon Sep 17 00:00:00 2001 From: Long Chen Date: Tue, 7 Jul 2026 11:52:59 +0800 Subject: [PATCH 2/2] chore: add changeset --- .changeset/fix_publisher_dc_closed_unexpectedly.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/fix_publisher_dc_closed_unexpectedly.md diff --git a/.changeset/fix_publisher_dc_closed_unexpectedly.md b/.changeset/fix_publisher_dc_closed_unexpectedly.md new file mode 100644 index 000000000..a89ea815a --- /dev/null +++ b/.changeset/fix_publisher_dc_closed_unexpectedly.md @@ -0,0 +1,6 @@ +--- +livekit: patch +livekit-ffi: patch +--- + +Don't log an expected publisher data channel close as unexpected - #1224 (@longcw)