In WebRTC, how does a data channel opened in-band with DCEP differ from one created with negotiated: true and an agreed id?
answer
- who creates the remote object
- an open message and an acknowledgement
- even and odd stream ids
- the application agrees id and options
basics
~20 sIn-band, createDataChannel sends a DCEP DATA_CHANNEL_OPEN with the channel's options; the peer replies DATA_CHANNEL_ACK and its application gets a datachannel event. With negotiated: true, each application creates the channel itself on an agreed id, and no DCEP message is sent.
solid answer
~50 sA data channel is a pair of SCTP streams sharing one stream identifier. By default (`negotiated: false`) the user agent opens it in-band with DCEP (RFC 8832): it picks an unused id by DTLS role — the DTLS client uses even ids, the server odd — and sends `DATA_CHANNEL_OPEN` carrying the channel type, reliability parameter, priority, label and protocol; the peer answers `DATA_CHANNEL_ACK` and its application receives a `datachannel` event with a ready-made `RTCDataChannel`. The opener MAY send before the ACK, but only ordered messages until something arrives back. With `negotiated: true` the application passes an `id` and must make the other side call `createDataChannel` with the same `id` itself; no DCEP message is sent, no event fires, and each side may even choose different options. The catch: a message arriving on a stream with no channel yet is undefined behaviour and may be dropped.
go deeper
Recall the default: one side calls createDataChannel and the other side receives a datachannel event, with no extra signalling by the application.
Explain the DCEP handshake, the even and odd id rule by DTLS role, and what negotiated true with a shared id changes on each side.
Show when negotiated channels pay off, such as declared or asymmetric channels, and how to avoid dropped early messages and id collisions with in-band channels.
Decide whether channel layout is a protocol your clients must version together, and whether that coupling is worth more than letting DCEP announce channels.
## What opening a data channel means All data channels of one `RTCPeerConnection` share a **single SCTP association** carried in DTLS, and JSEP (RFC 9429) gives them a **single `m=application` section** in SDP. Only the **first** data channel needs an offer/answer exchange; later ones change nothing in SDP. RFC 9429 also notes that per-channel arguments such as `maxPacketLifeTime` **are not reflected in SDP**. Inside the association, RFC 8832 defines a data channel as **two SCTP streams with the same stream identifier**, one in each direction, managed together. Identifiers run from 0 to 65534; 65535 is reserved, and the W3C API throws a `TypeError` for it. So "opening a channel" means two things: both ends must agree **which stream id** the channel uses, and both must agree **how to send on it** — order, reliability, label and protocol. RFC 8831 allows either in-band negotiation or any out-of-band method, and requires applications to use the methods consistently on both endpoints. ## In-band: the Data Channel Establishment Protocol With the default `negotiated: false`, the user agent runs **DCEP** (RFC 8832), a two-way handshake sent on the channel's own stream and told apart from user data by its SCTP payload protocol identifier: 1. The opener picks an unused stream id. To avoid collisions when both peers open channels at once, **the side acting as DTLS client MUST use even ids and the DTLS server odd ids**. Any `id` the application passed is ignored. 2. It sends `DATA_CHANNEL_OPEN`, carrying the **channel type** (ordered or not, reliable or which partial-reliability policy), the **reliability parameter**, a **priority**, the **label** and the **protocol**. 3. The peer checks that the stream is unused, the id matches the opener's role and the parameters are valid, then answers `DATA_CHANNEL_ACK` on the same id. If any check fails it closes the channel and sends no ACK. 4. The peer's application receives a **`datachannel` event** carrying a new `RTCDataChannel` whose properties match the opener's. The opener **MAY send user messages before the ACK arrives**, but until it has received the ACK or any other message on that channel, it MUST send them **ordered**, even on an unordered channel. Because DCEP messages are themselves reliable and ordered, the open is never overtaken by the data it precedes. ## Out-of-band: `negotiated: true` With `negotiated: true`, the W3C API sends nothing in-band. The application: - passes an **`id`** — without one, `createDataChannel` throws a `TypeError`; - tells the other side, through its own signalling, to call `createDataChannel` with `negotiated: true` and the **same `id`**; - accepts that **no `datachannel` event fires** — each side holds the object it created. The W3C specification lists two benefits: channels can be **declared** up front by matching ids, and they can have **asymmetric properties**, because each direction is configured by its own creator. RFC 8831 notes that with DCEP, by contrast, all properties are the same in both directions. ## Side by side | Aspect | In-band (DCEP) | `negotiated: true` | |---|---|---| | Who picks the id | the user agent, even or odd by DTLS role | the application | | What is sent | `DATA_CHANNEL_OPEN`, then `DATA_CHANNEL_ACK` | nothing | | Remote object | delivered by a `datachannel` event | created by the remote application | | Options per direction | identical | may differ | | Main risk | none beyond the handshake rules | sending before the peer has created its channel | ## Pitfalls of negotiated channels - **Sending too early.** The W3C note is blunt: a message received on an SCTP stream with no associated data channel is **undefined behaviour and may be silently dropped**. It cannot happen if both endpoints create their channels before the first offer/answer exchange completes. - **Id collisions.** The application owns the id space it uses. Reusing an id that an existing channel occupies fails — the W3C API throws an `OperationError` — so keep negotiated ids apart from the ones the user agent hands out to in-band channels. - **Drift between clients.** Matching ids and options live in application code on both ends, so a version skew between clients silently breaks the pairing. - **Missing announcements.** Code that waits for a `datachannel` event will wait forever for a negotiated channel; each side must use the object it created itself.
- Why does DCEP make the DTLS client open channels on even stream ids and the DTLS server on odd ones?So that two peers opening channels at the same moment never pick the same id. Each side draws from its own half of the space, chosen by a role both already agree on. RFC 8832 makes it a MUST, and a DATA_CHANNEL_OPEN that breaks the rule is answered by closing the channel, not with an ACK. Labels need not be unique.
- Are a WebRTC data channel's ordered and reliability options carried in the SDP offer?No. JSEP (RFC 9429) puts every data channel of a peer connection in one m=application section with UDP/DTLS/SCTP, webrtc-datachannel, an sctp-port line and optionally max-message-size, and says per-channel arguments such as maxPacketLifeTime are not reflected in SDP. In-band they travel in DATA_CHANNEL_OPEN; for negotiated channels the application agrees them itself.
saying these in an interview costs you the question
- Every new data channel needs a fresh offer/answer exchange.
- With negotiated true, the browser still announces the channel to the peer.
- The id option is honoured even when negotiated is false.
- A data channel's label must be unique within the peer connection.
- A DCEP opener must wait for DATA_CHANNEL_ACK before sending any data.