In WebRTC, what does one RTCPeerConnection bundle under its API, and how are its transport objects layered on each other?
answer
- one object, several transports
- ICE at the bottom
- DTLS on top of ICE
- sender and receiver per m-section
- SCTP for data, via the sctp attribute
basics
~20 sOne RTCPeerConnection bundles an ICE agent (RTCIceTransport), a DTLS transport layered on it (RTCDtlsTransport), RTP transceivers whose senders and receivers send SRTP over that DTLS transport, and, when data channels exist, an SCTP association (RTCSctpTransport) running inside DTLS.
solid answer
~40 sAn `RTCPeerConnection` is a bundle of transports behind one API. At the bottom is the **ICE agent**, exposed per transport as `RTCIceTransport`, which finds and keeps a working address pair. On it sits an `RTCDtlsTransport` (its `iceTransport` attribute points down) that authenticates the peer and keys encryption. Media runs through `RTCRtpTransceiver`s, each pairing an `RTCRtpSender` and an `RTCRtpReceiver` for one m-section; both expose `transport`, the DTLS transport their SRTP packets use. Data channels ride an `RTCSctpTransport`, reached through `pc.sctp`, whose `transport` is again a DTLS transport. With BUNDLE (RFC 8843) every m-section shares one transport, so a typical call has one ICE transport, one DTLS handshake and one SCTP association. `RTCConfiguration` shapes the bundle: `iceServers`, `iceTransportPolicy`, `bundlePolicy`, `rtcpMuxPolicy` and `certificates`.
code
pseudocode · 9 linespc = new RTCPeerConnection(config) // iceServers, bundlePolicy, certificates ...
tx = pc.addTransceiver("video") // RTCRtpTransceiver { mid, sender, receiver, direction }
chat = pc.createDataChannel("chat") // asks for an SCTP association
// after the offer and answer are applied
dtls = tx.sender.transport // RTCDtlsTransport carrying SRTP
ice = dtls.iceTransport // RTCIceTransport underneath it
sctp = pc.sctp // RTCSctpTransport for the data channels
sctp.transport // an RTCDtlsTransport; with BUNDLE, the one abovego deeper
Recall the four pieces under one RTCPeerConnection: ICE for connectivity, DTLS for security, transceivers for media, SCTP for data channels.
Walk the object graph: sender.transport to RTCDtlsTransport, its iceTransport to RTCIceTransport, and pc.sctp to RTCSctpTransport over DTLS, and say what BUNDLE collapses.
Use the layering to diagnose: which transport a symptom belongs to, why ICE can be up while DTLS fails, and why one bundled path takes all media and data down together.
Weigh bundling against compatibility: max-bundle simplifies firewalls and handshakes, while a mixed estate with non-bundling endpoints pushes toward balanced or max-compat and more transports per call.
## One object, a stack of transports Application code sees a single `RTCPeerConnection`, but the W3C WebRTC 1.0 specification models it as several cooperating objects, each mapping to a protocol from the IETF WebRTC suite. Knowing the stack explains where a call can break and which state to watch. From the bottom up: | Layer | W3C object | Protocol | Job | |---|---|---|---| | Connectivity | `RTCIceTransport` | ICE (RFC 8445) over UDP or TCP | find and keep a working address pair | | Security | `RTCDtlsTransport` | DTLS | authenticate the peer, key the encryption | | Media | `RTCRtpTransceiver` (`sender`, `receiver`) | RTP protected as SRTP | send and receive one m-section's media | | Data | `RTCSctpTransport` and its `RTCDataChannel`s | SCTP over DTLS (RFC 8261, RFC 8831) | carry application messages | ## The ICE agent and RTCIceTransport The **ICE agent** gathers candidate addresses, runs connectivity checks and selects a pair. The API exposes it per transport as an `RTCIceTransport` with its own `state` and gathering state. RFC 8835 requires a WebRTC endpoint to run full ICE, not the reduced "lite" variant, and to support STUN and TURN servers configured by the application — in the W3C API, through `iceServers`. ## RTCDtlsTransport on top of ICE Every `RTCDtlsTransport` has an `iceTransport` attribute naming the ICE transport underneath it, and the specification says that underlying transport may not be shared between multiple active DTLS transports. DTLS does two things here: - it **authenticates** the far end, by checking its certificate against the fingerprint received in the remote description; - it **keys** the media and carries the data: SRTP keys come out of the handshake, and SCTP packets travel inside DTLS records. The local certificate comes from the `certificates` member of `RTCConfiguration`, created with `RTCPeerConnection.generateCertificate()`, or, when the member is absent, a default set generated for each connection. ## Transceivers: senders and receivers Media is organised in **transceivers**. An `RTCRtpTransceiver` pairs one `RTCRtpSender` and one `RTCRtpReceiver` that share an m-section of the session description, identified by its `mid`. Its `direction` (`sendrecv`, `sendonly`, `recvonly`, `inactive`, `stopped`) says which halves are active. Transceivers are created by `addTrack()`, `addTransceiver()` or by applying a remote offer, and listed by `getTransceivers()`. Both the sender and the receiver expose `transport`: the `RTCDtlsTransport` over which their RTP and RTCP flow, protected as SRTP. It stays `null` until that DTLS transport is constructed, which happens while a session description is applied. ## The SCTP association for data `createDataChannel()` asks for an SCTP association. Once negotiated, it appears as `pc.sctp`, an `RTCSctpTransport` whose `transport` is again an `RTCDtlsTransport`; before SCTP is negotiated the attribute is `null`. The association exposes `maxMessageSize` and `maxChannels`, and every `RTCDataChannel` is a stream inside it. ## How BUNDLE collapses the stack Without bundling, each m-section could negotiate its own transport, and the stack above would repeat per m-section. **BUNDLE** (RFC 8843) lets several m-sections share a single 5-tuple. The W3C specification says that when bundling is used, multiple senders and receivers share one transport. The result for a typical call carrying audio, video and a data channel: 1. one ICE transport and one selected pair; 2. one DTLS transport, and so — as RFC 8827 puts it for the most likely case — one DTLS handshake; 3. SRTP for all media and one SCTP association for all data channels over that DTLS transport. The `bundlePolicy` configuration member controls how candidates are gathered when the far end may not support BUNDLE: `balanced` (the default) gathers per media type, `max-compat` per track, and `max-bundle` for only one track. `rtcpMuxPolicy` defaults to `require`, putting RTP and RTCP on the same transport. ## Why the layering matters in practice - **State has layers too.** ICE can be connected while DTLS fails; the peer connection's aggregate `connectionState` combines both, which is why it is the attribute a call screen should watch. - **One path for everything.** With BUNDLE, a broken ICE pair takes audio, video and data down together, and one ICE restart brings them back together. - **Encryption is not optional.** Every media and data path runs over DTLS; there is no plain transport object to choose. - **Null transports are a signal.** A `transport` or `sctp` attribute that is still `null` means negotiation has not reached that layer yet, which points at signalling, not the network. - **Certificates outlive calls only by choice.** A default certificate is made per connection; persisting one through `certificates` gives key continuity across calls. - **Configuration is per connection.** `iceServers`, `iceTransportPolicy`, `bundlePolicy`, `rtcpMuxPolicy` and `certificates` belong to `RTCConfiguration` and shape every transport the connection creates.
- In WebRTC, why is `pc.sctp` null on a connection that carries only audio and video?`RTCSctpTransport` exists only once SCTP has been negotiated, which happens when the session descriptions include an application m-section for data. A connection that never called `createDataChannel()` and never received a data m-section has no SCTP association, so the attribute stays `null`. Media flows over its transceivers' DTLS transport without it.
- In WebRTC, what changes in the transport graph when the far endpoint does not support BUNDLE?Each m-section keeps its own transport: its own ICE transport, its own DTLS transport and its own handshake, so several `RTCDtlsTransport` objects coexist. `bundlePolicy` decides how candidates are gathered for that case: `balanced` per media type, `max-compat` per track, and `max-bundle` for only one track, so a non-bundling peer then negotiates just one media track.
saying these in an interview costs you the question
- A data channel runs over its own separate connection, not the peer connection's
- Media in WebRTC runs over plain RTP unless the application enables DTLS
- Each audio and video track always gets its own ICE and DTLS handshake
- An RTCRtpTransceiver is just another name for a MediaStreamTrack
- RTCPeerConnection is a socket; there are no separate transport objects beneath it