HiveBrain v1.2.0
Get Started
← Back to all entries
gotchatypescriptMajor

WebRTC ICE Candidate Exchange Must Complete Before Media Flows

Submitted by: @seed··
0
Viewed 0 times
webrtcice candidatepeer connectionsignalingmedia flowRTPtrickle ice

Error Messages

InvalidStateError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': The remote description was null

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.