4.7 Session Negotiation Model
Many changes to state of an RTCPeerConnection
will require communication with the remote side via the signaling channel, in order to have the desired effect. The app can be kept informed as to when it needs to do signaling, by listening to the negotiationneeded
event. This event is fired according to the state of the connection’s negotiation-needed flag, represented by a [[NegotiationNeeded]] internal slot.
4.7.1 Setting Negotiation-Needed
This section is non-normative.
If an operation is performed on an RTCPeerConnection
that requires signaling, the connection will be marked as needing negotiation. Examples of such operations include adding or stopping an RTCRtpTransceiver
, or adding the first RTCDataChannel
.
Internal changes within the implementation can also result in the connection being marked as needing negotiation.
Note that the exact procedures for updating the negotiation-needed flag are specified below.
4.7.2 Clearing Negotiation-Needed
This section is non-normative.
The negotiation-needed flag is cleared when a session description of type “answer
“ is set successfully, and the supplied description matches the state of the RTCRtpTransceiver
s and RTCDataChannel
s that currently exist on the RTCPeerConnection
. Specifically, this means that all non-stopped
transceivers have an associated section in the local description with matching properties, and, if any data channels have been created, a data section exists in the local description.
Note that the exact procedures for updating the negotiation-needed flag are specified below.
4.7.3 Updating the Negotiation-Needed flag
The process below occurs where referenced elsewhere in this document. It also may occur as a result of internal changes within the implementation that affect negotiation. If such changes occur, the user agent MUST update the negotiation-needed flag.
To update the negotiation-needed flag for connection, run the following steps:
If the length of connection.[[Operations]] is not
0
, then set connection.[[UpdateNegotiationNeededFlagOnEmptyChain]] totrue
, and abort these steps.Queue a task to run the following steps:
If connection.[[IsClosed]] is
true
, abort these steps.If the length of connection.[[Operations]] is not
0
, then set connection.[[UpdateNegotiationNeededFlagOnEmptyChain]] totrue
, and abort these steps.If connection’s signaling state is not “
stable
“, abort these steps.Note
The negotiation-needed flag will be updated once the state transitions to “
stable
“, as part of the steps for setting a session description.If the result of checking if negotiation is needed is
false
, clear the negotiation-needed flag by setting connection.[[NegotiationNeeded]] tofalse
, and abort these steps.If connection.[[NegotiationNeeded]] is already
true
, abort these steps.Set connection.[[NegotiationNeeded]] to
true
.Fire an event named
negotiationneeded
at connection.
Note
The task queueing prevents
negotiationneeded
from firing prematurely, in the common situation where multiple modifications to connection are being made at once.Additionally, we avoid racing with negotiation methods by only firing
negotiationneeded
when the operations chain is empty.
To check if negotiation is needed for connection, perform the following checks:
If any implementation-specific negotiation is required, as described at the start of this section, return
true
.If connection.[[LocalIceCredentialsToReplace]] is not empty, return
true
.Let description be connection.[[CurrentLocalDescription]].
If connection has created any
RTCDataChannel
s, and no m= section in description has been negotiated yet for data, returntrue
.For each transceiver in connection’s set of transceivers, perform the following checks:
If transceiver.[[Stopping]] is
true
and transceiver.[[Stopped]] isfalse
, returntrue
.If transceiver isn’t
stopped
and isn’t yet associated with an m= section in description, returntrue
.If transceiver isn’t
stopped
and is associated with an m= section in description then perform the following checks:If transceiver.[[Direction]] is “
sendrecv
“ or “sendonly
“, and the associated m= section in description either doesn’t contain a singlea=msid
line, or the number of MSIDs from thea=msid
lines in thism=
section, or the MSID values themselves, differ from what is in transceiver.sender.[[AssociatedMediaStreamIds]], returntrue
.If description is of type “
offer
“, and the direction of the associated m= section in neither connection.[[CurrentLocalDescription]] nor connection.[[CurrentRemoteDescription]] matches transceiver.[[Direction]], returntrue
. In this step, when the direction is compared with a direction found in [[CurrentRemoteDescription]], the description’s direction must be reversed to represent the peer’s point of view.If description is of type “
answer
“, and the direction of the associated m= section in the description does not match transceiver.[[Direction]] intersected with the offered direction (as described in [RFC8829] (section 5.3.1.)), returntrue
.
If transceiver is
stopped
and is associated with an m= section, but the associated m= section is not yet rejected in connection.[[CurrentLocalDescription]] or connection.[[CurrentRemoteDescription]], returntrue
.
If all the preceding checks were performed and
true
was not returned, nothing remains to be negotiated; returnfalse
.