A proposal for a solution to "parallel forking"

A use case that isn't (well?) supported by the WebRTC 1.0 spec is what
we sometimes call "parallel forking", which basically means that a
local endpoint sends signalling information to many remote endpoints
and then can receive back signalling and then send and receive media
to/from *more than one endpoint*.    A solution was previously
discussed in the WebRTC WG as "cloning", but seemed too complicated
for the 1.0 API to be practical.

An example of how this would be useful is setting up data channels
with multiple peers without having to allocate separate ICE parameters
and candidates for each peer.  You could, with parallel forking, send
up one set of local ICE parameters to a server which could be used by
all remote peers to connect to the local peer.

The good news is that the ORTC components we already have
(IceTransport, DtlsTransport, RtpSender, RtpReceiver, SctpTransport)
give a JS app just about everything it needs for this use case.  A JS
app can create multiples of DtlsTransport, RtpSender, RtpReceiver, and
SctpTransport for each endpoint it wants to talk to.

The bad news is that we're missing one piece: the ability to have
several IceTransports that share the same ICE local parameters and
local candidates.   If we could just do that, then we would have
everything we need to support parallel forking.  I think there are
basically two ways we could allow for this in the ORTC API:

1.  Add some kind of IceTransport.fork() method which gives you a copy
of the IceTransport object which can then have different remote
parameters and remote candidates, but the same local parameters and
local candidates.   Something like this:

var iceOptions = ...;
var iceParent = new RTCIceTransport(RTCIceRole.controlling, iceOptions);
sendInitiate(iceParent.getLocalParameters(), function(response) {
  // We may get N responses
  var ice = iceParent.fork();
  var ice.setRemoteParameters(repsonse.iceParameters);
  ice.start();
  // ... setup DTLS, RTP, SCTP, etc.
});
iceParent.onlocalcandidate = sendLocalCandidate;
iceParent.start();


While I like the apparent simplicity of this approach, it does run
into a lot of weird questions, like: what if I change something on the
parent; does that effect the children?  Is it best to keep a parent
laying around that's only used for forking?  What if I need to change
the ICE role?  Questions like that would probably plague us for a long
time.



2.   Add a new object which is explicitly shared between different
IceTransports.  It acts as the "ice parent" in the previous example,
and if you want more than one IceTransport with the same local
parameters and candidates, you make one of these new parent objects
and then explicitly share it between IceTransports.   Something like
this:

var iceOptions = ...;
var iceListener = new RTCIceListener(iceOptions);
sendInitiate(iceListener.getLocalParameters(), function(response) {
  // We may get N responses
  var ice = new RTCIceTransport(RTCIceRole.controlling, iceListener);
  var ice.setRemoteParameters(repsonse.iceParameters);
  ice.start();
  // ... setup DTLS, RTP, SCTP, etc.
});

iceListener.oncandidate = sendLocalCandidate;
iceListener.start();


This has the advantage that it's much more clear and explicit is going
on and there aren't all those tricky edge cases about a parent/child
relationship between IceTransports.   I think we'll be happier
long-term with something like this.  This is just like the purpose and
design of the RTCSocket object that was in ORTC previously, but fits
in with our new IceTransport model.


So, I propose we add something like the following object, which will
give us the last remaining piece to support  parallel forking:


[Constructor(optional RTCIceListenerOptions options)]
interface RTCIceListener {
  readonly attribute RTCIceListenerOptions options;

  RTCIceParameters getLocalParameters();
  readonly attribute sequence<RTCIceCandidate> localCandidates;

  void start();
  void stop();

  attribute EventHandler? onlocalcandidate;
  attribute EventHandler? ongatherfailure;
}

I much the prefer the second solution, and I think it would be a great
way to support parallel forking and is an example of something that
the ORTC model can easily support that was too complex to be practical
in the 1.0 API.

Received on Saturday, 1 February 2014 00:12:06 UTC