How are data feeds negotiated between two peers using WebRTC?
WebRTC interface RTCPeerConnection
has createDataChannel
and ondatachannel
event handler. How do they interact? How do I create a single data channel that can be used to send / receive data between two peers?
In addition, the constructor RTCDataChannelInit
has a field negotiated
that is set to by default false
and says it is in the channel declared in the frequency band. What happens if it's installed on true
?
source to share
First: to create any data channel, peers must exchange an SDP offer / response that negotiates the properties of the SCTP connection used by all data channels. This doesn't happen by default; you must call createDataChannel
before calling createOffer
for an offer to contain this SCTP information (the "m = application" section in the SDP).
If you don't, the data link state will be stuck forever <<22>.
From this point of view, there are two ways to negotiate a data channel between two peers:
In-band negotiation
This is what happens by default if the field is negotiated
not set to true
. One peer calls createDataChannel
and the other connects to ondatachannel
EventHandler
. How it works:
- Peer A calls
createDataChannel
. - The usual offer / response is executed.
- Once the SCTP connection is complete, a message is sent within range from peer A to peer B to signal the existence of a data link.
- The Peer B
ondatachannel
EventHandler
is called with a new data channel created from the in-band message. It has the same properties as the data channel created by Peer A, and these data channels can now be used to send data bi-directionally.
The advantage of this approach is that data channels can be dynamically created at any time without an application requiring additional signaling.
Out-of-band negotiation
Data channels can also be negotiated out of range. With this approach, instead of calling createDataChannel
on one side and listening ondatachannel
on the other side, the application simply calls createDataChannel
on both sides.
- Peer-to-peer call A
createDataChannel({negotiated: true, id: 0})
- Peer B also calls
createDataChannel({negotiated: true, id: 0})
. - The usual offer / response is executed.
- Once the SCTP connection is established, the channels will be instantly used (
readyState
will change toopen
). They are matched by an identifier that is the base identifier of the SCTP stream.
The advantage of this approach is that since no in-band message is required to create a data channel on Peer B, the channel will be used earlier. It also makes the application code simpler as you don't even need to worry about ondatachannel
.
So, for applications that only use a fixed number of data channels, this approach is recommended .
Note that the identifier you choose is not just an arbitrary value . It represents the base SCTP stream ID based on 0. And these IDs can only reach the number of SCTP streams negotiated with the WebRTC implementation. Thus, if you use too high an ID, your data feed will not work.
What about native apps?
If you use the native webrtc library instead of the JS API, it works the same; things just have different names.
C ++:
-
PeerConnectionObserver::OnDataChannel
-
DataChannelInit::negotiated
-
DataChannelInit::id
Java:
-
PeerConnection.Observer.onDataChannel
-
DataChannel.Init.negotiated
-
DataChannel.Init.id
Obj-C:
-
RTCPeerConnectionDelegate::didOpenDataChannel
-
RTCDataChannelConfiguration::isNegotiated
-
RTCDataChannelConfiguration::channelId
source to share