gotchatypescriptMajor
WebRTC ICE Candidate Exchange Must Complete Before Media Flows
Viewed 0 times
webrtcice candidatepeer connectionsignalingmedia flowRTPtrickle ice
Error Messages
Problem
WebRTC connection established (RTCPeerConnection state shows 'connected') but no audio/video arrives. Media tracks added but never render on the remote side.
Solution
Ensure ICE candidates gathered by each peer are sent to the remote peer via your signaling channel and added with addIceCandidate() before the connection can carry media. Candidates arrive asynchronously after setLocalDescription(), so you must buffer and relay each one.
const pc = new RTCPeerConnection({ iceServers });
pc.onicecandidate = ({ candidate }) => {
if (candidate) {
signalingChannel.send({ type: 'ice-candidate', candidate });
}
};
// On receiving a candidate from signaling:
signalingChannel.on('ice-candidate', async ({ candidate }) => {
try {
await pc.addIceCandidate(new RTCIceCandidate(candidate));
} catch (err) {
console.error('addIceCandidate failed', err);
}
});Why
ICE (Interactive Connectivity Establishment) is a separate negotiation layer that discovers viable network paths (direct, STUN-reflected, TURN-relayed). Without exchanging candidates the browser has no route to send RTP packets through.
Gotchas
- Candidates can arrive before setRemoteDescription() completes — buffer them and add after.
- A null candidate in onicecandidate signals ICE gathering is complete, not an error.
- Trickle ICE (sending candidates as they arrive) is much faster than waiting for all candidates.
- If the remote description is not set before addIceCandidate(), you get an InvalidStateError.
Revisions (0)
No revisions yet.