PeerConnection: complete W3C §4.3 method/accessor surface#47
Merged
Conversation
Part of the PeerConnection W3C surface gap. The ICE agent already tracks iceNew / iceGathering / iceGatheringComplete internally; expose it as the W3C `iceGatheringState`. - `IceGatheringState` enum (newState/gathering/complete — `newState` dodges the `new` keyword, mirroring `IceConnectionState.iceNew`). - `iceGatheringState` getter + `onIceGatheringStateChange` stream, derived from the ICE agent's combined state in _onIceStateChange. - `getConfiguration()` returning the connection's configuration. Remaining PeerConnection items (restartIce, removeTrack, setConfiguration, current/pendingLocalDescription, onNegotiationNeeded, onIceCandidateError, connectionState `new`) stay in BACKLOG — restartIce is the highest-value next one. Tested: gathering state transitions new → gathering → complete with the event firing (loopback), and getConfiguration round-trips. analyze clean; 667 unit + 22 e2e pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds ICE restart on top of the iceGatheringState/getConfiguration change.
- ICE agent `restart(localParams, {hosts, clearRemote})`: discards local
candidates, pairs, pending checks, the selected pair, and consent
tracking, then re-gathers under the new credentials over the same
sockets. `clearRemote` distinguishes the initiator (drops the peer's
stale credentials, awaits new ones) from the answerer (keeps the peer's
freshly-applied credentials).
- `restartIce()` regenerates the local ICE ufrag/pwd (now mutable) and
flags a pending restart; the next `setLocalDescription` routes through
`_ice.restart` instead of `startGathering`.
- `setRemoteDescription` auto-restarts the answerer when it sees a changed
ufrag/pwd in an *offer* (RFC 8445 §9), regenerating its own credentials
so the answer carries them.
- DTLS handshake is now started once (`_dtlsHandshakeStarted` guard): an
ICE restart re-reaches `iceConnected`, but DTLS/SCTP/SRTP persist over
the new pair and must not be re-handshaked.
Tested: a loopback test establishes a data channel, exchanges a message,
restarts ICE (asserting both peers get new ufrags), renegotiates, and
confirms data flows again over the freshly-validated pair. analyze clean;
668 unit + 22 e2e pass (Chrome/Firefox handshake unaffected by the DTLS
guard).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Finish the remaining PeerConnection spec members on top of the already-shipped
iceGatheringState/getConfiguration/restartIce work:
- removeTrack(): detach the track and downgrade the transceiver direction
(sendrecv→recvonly, sendonly→inactive); fires negotiationneeded.
- setConfiguration(): configuration is now a mutable holder; bundlePolicy /
rtcpMuxPolicy changes are rejected (W3C InvalidModificationError).
- current/pending {local,remote}Description: derived from the last-set
description + signaling state (no parallel bookkeeping fields).
- onNegotiationNeeded: microtask-coalesced flag, cleared on local apply.
- onIceCandidateError: STUN gather timeout (701) or server error code,
surfaced from the ICE machine via an onCandidateError callback.
- connectionState now starts in newState (the spec `new`).
Tests: PC-level spec methods, removeTrack SDP reflection, onNegotiationNeeded
re-fire, onIceCandidateError (ICE-machine + PC). dart analyze clean; full unit
+ e2e suites green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Completes the W3C
RTCPeerConnectionAPI surface (BACKLOG #5). Three commits on this branch:iceGatheringState+onIceGatheringStateChange+getConfiguration()restartIce()(ICE-agent restart + answerer auto-restart on a changed-ufrag offer; DTLS/SCTP persist)What's new in the final batch
removeTrack(sender)sendrecv→recvonly,sendonly→inactive); keeps the transceiver/receiver; firesnegotiationneeded. No-op for a foreign/already-detached sender.setConfiguration(config)configurationis now a mutable holder. RejectsbundlePolicy/rtcpMuxPolicychanges (W3CInvalidModificationError) and rejects when closed.current{Local,Remote}Description/pending{Local,Remote}DescriptionsignalingState— a side is pending while it owns the in-flight offer/pranswer, current otherwise.onNegotiationNeededonIceCandidateErrorIceCandidateError(url/address/port/errorCode/errorText). STUN gather timeout → 701; server error response → its STUN error code. Plumbed via anonCandidateErrorcallback on the ICE state machine, mirroringonLocalCandidate.connectionStatenewState(the specnew;newis a Dart keyword, so the value mirrorsIceConnectionState.iceNew).Tests
test/peer_connection/pc_spec_methods_test.dart(new) — connectionStatenew, setConfiguration (replace/reject/closed), current/pending split (pre-negotiation, mid-negotiation, post-handshake), onNegotiationNeeded (fire/coalesce/re-fire), onIceCandidateError end-to-end via PeerConnection (unroutable STUN → 701).test/peer_connection/transceiver_test.dart— removeTrack (detach+downgrade, sendonly→inactive, foreign no-op, SDP reflection).test/ice/ice_test.dart—onCandidateErrorat the ICE-machine layer (timeout 701, STUN error response).Verification
dart analyze→ No issues founddart test(full unit suite) → all greendart test test/e2e/→ 22 passed (browser interop)🤖 Generated with Claude Code