How RTCPeerConnection Works in JavaScript

The RTCPeerConnection interface is the core component of the WebRTC standard used to establish, maintain, and terminate peer-to-peer audio and video communications in JavaScript. This article provides a straightforward breakdown of how RTCPeerConnection handles media acquisition, session negotiation through the offer/answer model, NAT traversal via ICE, and the continuous streaming of real-time tracks between web browsers.

1. Initializing the Connection and Adding Tracks

To manage real-time media, a JavaScript application first captures audio and video streams from local user devices using navigator.mediaDevices.getUserMedia(). Once the media is acquired, an instance of RTCPeerConnection is created, and the tracks are attached directly to the connection.

const peerConnection = new RTCPeerConnection(configuration);

const localStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
localStream.getTracks().forEach(track => {
  peerConnection.addTrack(track, localStream);
});

The configuration object typically contains a list of STUN and TURN server URLs required to navigate through firewalls and Network Address Translation (NAT).

2. Session Negotiation via the Offer/Answer Model

Peers exchange metadata about codecs, encryption, and network capabilities using the Session Description Protocol (SDP). Because RTCPeerConnection does not have a built-in messaging channel for signaling, an external mechanism like WebSockets is used to exchange this data.

  1. Creating the Offer: The initiating peer creates an SDP offer using createOffer() and applies it locally using setLocalDescription().
  2. Sending the Offer: The offer is sent to the remote peer via the signaling server.
  3. Receiving and Responding: The remote peer receives the offer, applies it using setRemoteDescription(), generates an SDP answer using createAnswer(), and sets it as its local description.
  4. Finalizing the Exchange: The initiating peer receives the answer and applies it using setRemoteDescription().

3. Network Traversal with ICE Candidates

While SDP describes the media formats, Interactive Connectivity Establishment (ICE) determines the best network path to transmit the media packets.

peerConnection.onicecandidate = (event) => {
  if (event.candidate) {
    signalingChannel.send(JSON.stringify({ candidate: event.candidate }));
  }
};

4. Receiving and Rendering Media Tracks

When the remote peer adds tracks and the connection succeeds, the track event triggers on the receiving peer’s RTCPeerConnection. This event exposes the incoming MediaStreamTrack, which can be attached to an HTML <video> or <audio> element for playback.

peerConnection.ontrack = (event) => {
  const remoteVideo = document.getElementById('remoteVideo');
  if (remoteVideo.srcObject !== event.streams[0]) {
    remoteVideo.srcObject = event.streams[0];
  }
};

5. Monitoring Connection State and Termination

RTCPeerConnection exposes connection lifecycle states through the connectionstatechange event. The states progress through connecting, connected, disconnected, failed, or closed.

To terminate a session, the application calls peerConnection.close(), which stops ICE processing, detaches media streams, and releases network sockets and hardware resources.