Skip to content

Keep the in-flight read when an injected packet wins nextPacket - #1

Merged
cnderrauber merged 1 commit into
livekit:warp-3.1.5from
pblazej:blaze/sped-orphaned-read
Sep 27, 2026
Merged

cnderrauber merged 1 commit into
livekit:warp-3.1.5from
pblazej:blaze/sped-orphaned-read

Conversation

@pblazej

@pblazej pblazej commented Sep 25, 2026 •

Copy link
Copy Markdown

Problem

With SPED (DTLS-in-STUN), nextPacket starts a new nextConn read on every call and races it against inboundPacketInject. When an injected packet wins, that read keeps running, and the next packet it receives goes into a channel nobody reads, so it's lost. Each piggybacked handshake packet therefore drops one of the peer's later packets.

I found this while enabling WARP in the Swift SDK (livekit/client-sdk-swift#1138). It was tested against a local livekit-server 1.13.7 with rtc.enable_warp: true, which uses this fork at v3.1.5-warp.1.

  • For 1–12 s after connect, the client's first SCTP packets never reach the SFU's SCTP: data-channel OPENs, DATA, SACKs and their retransmissions.
  • As a result the first data message after connect is delayed by seconds, and early lossy messages are dropped.
  • The client's packets are well formed (CRC32c and verification tags check out) and arrive from the same address whose STUN the SFU is processing. SFU→client traffic is unaffected.

Fix

Keep the in-flight read on the Conn (it's owned by the single read loop) and reuse it on the next call instead of starting another.

Measurements

Swift SDK client with SPED+SNAP, local server, loopback. n=10 for first messages, n=5 for bursts.

v3.1.5-warp.1 with this fix
First reliable message after connect (dual PC) 0.4–12.6 s, 6/10 over 6 s 11–13 ms
First reliable message after connect (single PC) ~0.4 s 11–14 ms
100 lossy messages right after connect 0–100 delivered 100/100
100 reliable messages right after connect 100/100 100/100
SFU SCTP T3-rtx timeouts 17–21 0–1

The same tests against a server with WARP disabled give 11–14 ms and 100/100. Connect time (BM-CONN) is unchanged by this fix.

go test ./... passes.

Related: livekit/ice#4 fixes a second WARP issue, the ~95 ms connect penalty for clients without SPED.

An injected (DTLS-in-STUN) packet winning the select left the spawned
nextConn read running. Whatever it read next went into a channel nobody
received from, so each piggybacked handshake packet silently dropped one
later packet from the peer (SCTP DATA, SACKs and their retransmissions),
stalling data channels for seconds after a SPED handshake.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@cnderrauber cnderrauber left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thank you!

@cnderrauber
cnderrauber merged commit 645570f into livekit:warp-3.1.5 Sep 27, 2026
12 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants