-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
DataChannel
Here the roadmap for adding DataChannel support to mediasoup. It includes a preliminary architecture design among other considerations (below) such as implementation details.
The DataChannel design and exposed API must follow the principles of the already exiting audio/video Producer and Consumer design in mediasoup v3. So, the DataChannel design must conform to the following requirements:
-
The DataChannel message unit is a SCTP packet (in the same way, the message unit in audio/video is a RTP packet).
-
There must two new classes:
DataProducerandDataConsumer(in both mediasoup server and mediasoup-client).- A
DataProducerrepresents a data channel source (so a SCTP stream with a specificid) being injected into a mediasoup router. It's created on top of a transport that defines how the SCTP packets are carried. -
DataProducersare created using the already existing transport.produce() JavaScript API with new arguments. - A
DataConsumerrepresents a data channel source (so a SCTP stream with a specificid) being forwarded from a mediasoup router to an endpoint. It's created on top of a transport that defines how the SCTP packets are carried. -
DataConsumersare created using the already existing transport.consume() JavaScript API with new arguments.
- A
-
STCP packets can be injected into a mediasoup router on top of a WebRtcTransport (so STCP over DTLS over UDP/TCP) and also on top of a PlainRtpTransport (so SCTP over UDP).
- NOTE: We may want to rename
PlainRtpTransporttoPlainTransport.
- NOTE: We may want to rename
-
The
WebRtcTransportandPlainRtpTransportwill hold a newSctpAssociationclass instance to manage the SCTP connection itself, STCP retransmission, etc. -
When a SCTP endpoint sends a SCTP packet on a
DataProducer:- The SCTP packet reaches the mediasoup
WebRtcTransportorPlainRtpTransportwhich delivers the SCTP packet to itsSctpAssociationclass instance. - The
SctpAssociationwill determine whether this is a SCTP control packet (init, reset, new stream created, alert, etc) or a SCTP user message packet. Let's assume it's a user message packet. - The
SctpAssociationwill notify the transport about "new SCTP user message packet". - The transport reads the SCTP
idof the packet and looks for the correspondingDataProducerusing itsSctpListener(similar to theRtpListener) and passes the packet to it. - The
DataProducermay need to do something with the SCTP packet (may be not) and then notifies its transport back with the same SCTP packet. - The transport notifies it to the router (
RouterC++ class). - The router iterates the
DataConsumersassociated to the senderDataProducerand callsdataConsumer->SendSctpDataPacket(packet)on all them. - Each
DataConsumergets the packet, mangles its SCTPidfield (and may be other fields in the packet) and notifies its transport to deliver the packet. - The transport of the
DataConsumerreceives the SCTP packet and passes it to itsSctpAssociationinstance (that will manage retransmissions, etc). - The
SctpAssociationwill then notify back the SCTP user message packet to the transport, which will finally deliver the packet to the remote endpoint:- If it's a
WebRtcTransport, it will send the SCTP packet as DTLS data using the already existingDtlsTransport::SendApplicationData()method. - If it's a
PlainRtpTransportit will send the SCTP packet using raw UDP.
- If it's a
- The
DataConsumerthen restores the SCTP packet fields.
- The SCTP packet reaches the mediasoup
-
The
WebRtcTransportandPlainRtpTransportmay need a newSctpAssociationclass instance to manage the SCTP connection itself ( -
Similar to audio/video
ProducersandConsumers, it must be possible for the Node.js app running mediasoup to decide which endpoints consume (by means of aDataConsumer) from a specificDataProducer. Once aDataConsumeris created, theRouter(at C++ level) will route to it SCTP user messages from the associatedDataProducer. -
It must be possible for the Node.js app (the application that integrates mediasoup lib and uses its JS API) to inject SCTP user messages into a mediasoup router so those messages are routed to endpoints via WebRTC DataChannel. And vice-versa: the Node.js app must be able to receive SCTP user messages sent by endpoints to the mediasoup router. To do it, the Node.js app:
- must create a
PlainRtpTransportin the mediasoup router, - must call
produce()on it with appropriate arguments to create aDataProducerinstance, - must create a UDP+SCTP client that sends (and/or receives) SCTP packets (with the announced
id) to the IP:port of the previously created mediasoupPlainRtpTransport.
- must create a
-
Such a "UDP+SCTP client" could be a Node.js library/module which, for example, uses the Node.js UDP stack plus the node-sctp or @nodertc/sctp Node.js libraries.
The WebRtcTransport of mediasoup already has an (unused yet) API to send and receive DTLS application data:
(we would add the same OnDtlsApplicationData callback into the PlainRtpTransport for SCTP over UDP).
So we need to plug a C++ SCTP stack to handle SCTP packets. It would be done within a new C++ class named SctpHandler or whatever.
As per now there are three C or C++ SCTP stacks out there we can consider:
-
medooze/libdatachannels, whose API is exactly what we need (single thread, and provides an API to send and receive packets by letting the external application manage the socket, timers, the DTLS, etc). Unfortunately it's nor finished neither active.
-
sctplab/usrsctp, the "SCTP stack". Used by libwebrtc, Janus among many others. Problems:
- It's multi-thread (question). We need a single-thread stack.
- There is a Pull Request that makes it single thread, but was not merged.
- Then @lgrahl said "No need to wait, you can use usrsctp-neat which will be merged back eventually", but that did never happen.
- I also do not like the idea of integrating a library with more than 50 open issues, some of them definitively relevant as a memory leak.
- It does not provide a GYP file, so we should do it (plus PR of course).
-
And then there is rawrtc/rawrtc-data-channel, which is a layer on top of usrsctp which, somehow, hiddes its multi-thread nature. Problems:
- It depends on usrsctp, so same concerns as above apply (however my concerns could be wrong).
- It also depends on re and rew C libraries (due the usage of some helpers and utils included in them). Not a super big problem, but I don't like the idea of having mediasoup depend on a C library that implements SIP, WebSocket, DNS, HTTP, etc.
- It depends on
mesonandninjafor the building stage. This is a no-go for mediasoup. Users of mediasoup are supposed to just runnpm install mediasoupand they are done. The"postinstall": "make -C worker"inpackage.jsonbuilds the mediasoup C++ code and its C/C++ deps (included in the source) by usinggyp(which is also included in the package). All C/C++ dependencies of mediasoup include GYP files. - In other words, we should create GYP files for rawrtc-data-channel, usrsctp, re and rew libraries...
-
Another option is coding our own stack. Not desirable, but we have a clear design and whichever C/C++ SCTP stack we choose (or build) must conform to it.
- peer-to-peer-data-api: Peer-to-Peer Data API
- draft-ietf-rtcweb-transports: Transports for WebRTC
- draft-ietf-rtcweb-data-channel: WebRTC Data Channels
- draft-ietf-rtcweb-data-protocol: WebRTC Data Channel Establishment Protocol
- This is for in-band DataChannel (pair of send & recv SCTP streams with same
idover the same STCP association). We (mediasoup) may prefer to use out-of-band negotiation (so DataChannelidand other parameters are exchanged between client and server via signaling).
- This is for in-band DataChannel (pair of send & recv SCTP streams with same
- draft-ietf-mmusic-sctp-sdp: SDP Offer/Answer Procedures For SCTP over DTLS
- Q: It's not clear to me which endpoint (DTLS client? DLTS server?) sends the SCTP INIT message. Section 9.3 says "When an SCTP association is established, both SCTP endpoints MUST initiate the SCTP association (i.e. both SCTP endpoints take the 'active' role)". I don't understand it at all. Isn't the SCTP association established with the INIT chunk?
- R: The SCTP association is just determined by the SCTP ports negotiated in the SDP O/A (plus 'max-message-size', etc), so it "just" exists. Both endpoints must "initiate" it (via SCTP INIT) to setup the initial TSN and so on.
- RFC 4960: Stream Control Transmission Protocol
- RFC 3758: SCTP Partial Reliability Extension
- RFC 5061: SCTP Dynamic Address Reconfiguration
- Needed by RFC 6525.
- RFC 6525: SCTP Stream Reconfiguration
- RFC 7496: Additional Policies for the Partially Reliable SCTP Extension
- Provides limited retransmission policy (limiting the number of retransmissions).
- RFC 8260: Stream Schedulers and User Message Interleaving for SCTP
- RFC 8261: DTLS Encapsulation of SCTP Packets