Skip to content

Send local ICE candidates off the transport event loop - #5

Merged
tbarbugli merged 1 commit into
mainfrom
fix/trickle-off-event-loop
Sep 30, 2026
Merged

tbarbugli merged 1 commit into
mainfrom
fix/trickle-off-event-loop

Conversation

@tbarbugli

Copy link
Copy Markdown
Member

Each local ICE candidate went to the SFU as a blocking IceTrickle RPC on the transport's event loop, one round trip each. The SFU's answer to SetPublisher is applied on that same loop, so it queued behind every candidate gathered while the offer was in flight: with ~10 candidates and a 120 ms round trip, the publisher applied its answer, and only then started ICE, about 1.3 s late.

  • pc/pc.go: the OnICECandidate event still goes through the event loop (so candidates still follow the offer), but only appends the candidate to a queue. A dedicated goroutine sends queued candidates one at a time, in gathering order. A failed send is enqueued back on the event loop so it is handled like any other failed event.
  • New TestSlowCandidateSendsDoNotHoldBackTheAnswer (pc/trickle_test.go, with an onICECandidate hook in pc/pc_test.go): every candidate send takes 200 ms; the answer must reach a stable signaling state immediately, and all candidates must still go out in gathering order. On main it fails with the answer applied ~1 s late ("999ms is not less than 150ms"); with the change it passes.

This is independent of WARP and the pion forks and applies to main on its own; the WARP PR includes it.

Tested: go build ./..., go vet ./..., gofumpt, go mod tidy and go test -race -count=1 ./... pass on the branch.

Measured on staging (10-run medians, join to first media, measured with the connection timing from #2):

Client Peer connection Before With this fix
Amsterdam, ~120 ms RTT to us-east1 SFU publisher 2347 ms 1269 ms
Amsterdam, ~120 ms RTT to us-east1 SFU subscriber 1268 ms 1248 ms
us-east5, ~23 ms RTT publisher 447 ms 366 ms

🤖 Generated with Claude Code

Each local candidate went to the SFU as a blocking IceTrickle RPC on the
event loop, one round trip each. The SFU's answer queued behind them, so
with ten candidates and a 120 ms round trip the publisher applied its
answer, and started ICE, 1.3 s late. Candidates now go out from their own
goroutine, still in order and still after the offer, and the answer is
applied as soon as it arrives.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@tbarbugli
tbarbugli marked this pull request as ready for review September 30, 2026 13:39
@tbarbugli
tbarbugli merged commit f458fbb into main Sep 30, 2026
3 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.

1 participant