JavaScript Session Establishment Protocol (JSEP)
obsoleted by
- rfc-9429 — JavaScript Session Establishment Protocol (JSEP)
Extracted elements (29)
JSEP decouples the ICE state machine from the signaling state machine to allow transport information to be sent separately from session descriptions, enabling faster ICE and DTLS startup via Trickle ICE (RFC 8838). This accommodates both traditional SIP (combined) and Trickle ICE (separated) models without requiring signaling protocol changes.
JSEP provides createOffer/createAnswer rather than exposing a getCapabilities API because requiring applications to correctly generate session descriptions from raw capabilities would force use of a higher-level library even for simple examples, negating JSEP's goal of simplicity.
JSEP uses SDP syntax for session description internal representation despite its poor fit for JavaScript manipulation, because SDP is widely accepted and continually updated with new features. SDP is encapsulated in a SessionDescription object to allow future adoption of alternative encodings (e.g., JSON) without API changes.
The preferred JSEP pattern for answerers is to send an immediate 'sendonly' final answer with a null MediaStreamTrack rather than a pranswer. This avoids leaving the offer/answer exchange open, allowing the caller to send an updated offer and enabling bidirectional media to start promptly upon user acceptance.
Some endpoints generate legacy profile strings such as 'RTP/AVP' while supplying 'a=fingerprint' and 'a=rtcp-fb' attributes indicating SAVPF intent. JSEP implementations must accept these strings in received offers, but re-offers MUST use correct profile strings regardless of what the initial exchange used.
There is a known inconsistency between JSEP (RFC 8829) and BUNDLE (RFC 8843) regarding bundle-only m= sections. JSEP requires port zero and a=bundle-only only in initial offers; BUNDLE requires it in all offers and answers; most browsers mark no m= sections with port zero. The IETF intends to publish revised documents resolving this.
DTLS (RFC 6347) or DTLS-SRTP (RFC 5763) MUST be used as appropriate for the media type. The SDP security descriptions mechanism (RFC 4568) MUST NOT be used for SRTP keying.
ICE as specified in RFC 8445 MUST be used in all session descriptions handled by JSEP implementations. Implementations MUST properly handle remote endpoints using ICE-lite or the older RFC 5245 version of ICE.
If the MID field is present in a received IceCandidate, it MUST be used for m= section identification; otherwise the m= section index is used. Implementations MUST be prepared to receive IceCandidate objects with some fields missing.
Implementations MUST be able to accept remote descriptions that do not have the 'ice2' attribute, since most WebRTC implementations at the time of publication support the older RFC 5245 ICE version.
JSEP implementations MUST support the 'UDP/TLS/RTP/SAVPF' and 'TCP/DTLS/RTP/SAVPF' profiles for media m= sections and 'UDP/DTLS/SCTP' and 'TCP/DTLS/SCTP' for data m= sections. Implementations MUST also accept a broad set of legacy profile strings in received offers for compatibility.
Session descriptions generated by createOffer and createAnswer MUST be immediately usable by setLocalDescription. createOffer SHOULD return an offer reflecting the current state of the system so that setLocalDescription will succeed when acquiring needed resources.
The bundle and RTCP-multiplexing policies MUST NOT be changed after PeerConnection construction. The ICE candidate pool size MUST NOT be changed after a local description has been applied.
The default bundle policy MUST be 'balanced' to provide the best trade-off between performance and compatibility with legacy endpoints. The default RTP/RTCP multiplexing policy MUST be 'require'.
The default ICE candidate policy MUST be 'all'. The default candidate pool size MUST be zero, since pre-gathering consumes STUN/TURN server resources and MUST only occur upon explicit application request.
The JSEP implementation MUST allow the ICE candidate policy to be changed mid-session. During a gathering phase, the implementation MUST NOT expose disallowed candidates to the application, use them for connectivity checks, or reveal them indirectly via other ICE candidate fields such as raddr/rport.
The PeerConnection MUST be able to simultaneously support use of both the current and pending local descriptions (e.g., codecs from either description) from the time it enters have-local-offer until setRemoteDescription is called with a final answer or rollback.
When a=imageattr recv attributes are present in a remote description and the encoder resolution exceeds the maximum size, the encoder SHOULD apply downscaling without changing the picture aspect ratio. If no supplied attributes can be processed successfully, the encoding MUST NOT be transmitted.
When addIceCandidate encounters invalid field values or a processing error, the supplied IceCandidate MUST be ignored and an error MUST be returned. If both the m= section index and MID are null for a new remote candidate, this MUST be treated as an invalid condition.
RtpTransceivers have a 1:1 mapping with m= sections and contain an RtpSender and RtpReceiver. A transceiver is associated with an m= section when its MID property is non-null. Transceivers can be created explicitly by the application or implicitly when setRemoteDescription adds new m= sections.
SessionDescriptionType may be 'offer', 'pranswer', 'answer', or 'rollback'. A final 'answer' MUST result in freeing unused resources. A 'pranswer' MUST NOT result in freeing allocated resources. A 'rollback' type with empty contents rolls the state machine back to the previous stable state.
Simulcast is configured by setting multiple encodings on an RtpSender. This is expressed in SDP via an 'a=simulcast' attribute (RFC 8853) with a 'send' simulcast stream description and 'a=rid' attributes (RFC 8851) for each encoding. JSEP currently supports sending simulcast but not receiving it.
The canTrickleIceCandidates property returns null (no SDP received), true (remote supports trickle), or false (remote does not support trickle). Applications comparing against 'true' will default to Half Trickle on initial offers and Full Trickle on subsequent interactions with a Trickle ICE-compatible agent.
The ICE candidate pool allows pre-gathering of candidates before setLocalDescription is called. When gathering starts, the JSEP implementation SHOULD use pool candidates first. The pool is used only for the first offer/answer exchange and is emptied afterward; pre-gathering consumes STUN/TURN resources.
The IceCandidate object uses SDP candidate-attribute syntax from RFC 8839 Section 5.1 (without an 'a=' prefix) and contains fields for the associated ICE ufrag, m= section index (zero-based), and MID. The ufrag field identifies which session description and gathering phase the candidate belongs to, resolving ambiguities during ICE restarts.
The onicecandidate event fires when a new local candidate is discovered or when a gathering phase completes. In the completion case, the IceCandidate's candidate field MUST be null and the ufrag field MUST be specified; the m= section fields MAY be null to indicate all sections.
Applications can restrict ICE candidates to relay-only using the 'relay' policy to prevent remote peers from learning the local endpoint's IP address and thereby inferring its location. This privacy benefit comes at the cost of increased TURN server operational usage.
DTLS-SRTP is required for all media sessions; negotiation failure occurs if 'a=fingerprint' attributes are absent. The SDP security descriptions mechanism (RFC 4568) is prohibited. WebRTC security requirements are governed by RFC 8827.
The JSEP state machine defines five states: stable, have-local-offer, have-remote-offer, have-local-pranswer, and have-remote-pranswer. Transitions are triggered by setLocalDescription and setRemoteDescription calls with offer, pranswer, answer, or rollback types. A rollback returns the machine to the previous stable state.