PSA: Spec-compliant Simulcast using addTransceiver API

1,715 views
Skip to first unread message

ami...@webrtc.org

unread,
Feb 28, 2019, 5:42:17 PM2/28/19
to discuss-webrtc
Hi,

Following the intent-to-ship I'm happy to announce that spec-compliant Simulcast will be coming to chrome in M74 (assuming all approvals and due process).

Backwards Compatibility
If you are already achieving simulcast by using the legacy SDP munging technique, then rest assured, you do not have to make any changes and your scenario will not break. 
You are highly encouraged to change your code to use the new API surface. <meme>Munging the SDP? Just say "no!"</meme>

Summary
Users can now call addTransceiver on the peer connection and specify multiple send encodings to configure the platform to send multiple encoding layers of the same video source.
pc.addTransceiver('video', {
    sendEncodings: [ { "rid": "f" },
                                 { "rid": "h", "scaleResolutionDownBy": 2 },
                                 { "rid": "q", "scaleResolutionDownBy": 4 }]
  });

During negotiation, this will generate the appropriate SDP lines to signal simulcast:
a=rid:f send
a=rid:h send
a=rid:q send
a=simulcast:send f;h;q

The simulcast envelope (i.e. the number of layers and their RIDs) cannot be changed and is determined in the call to addTransceiver().
After the number of layers is determined, the RtpSenderInterface can be queried for the parameters using getParameters()
and the configuration for layers (not their number or RIDs) can change using setParameters().

Details
Simulcast must be negotiated by both parties. If the answer SDP does not contain the symmetric a=simulcast:recv line, then simulcast will not be sent. Instead the platform will fall back to only sending the first layer.

Layers can be rejected in the answer through omission. Omitted layers will not be sent and are removed from the sender's parameters.

A client indicating multiple send encoding layers without specifying RID values, will get RIDs that are generated by the platform.

Layers can be paused by setting the active attribute to false. This is different than layers being rejected because paused layers can be re-enabled in future calls to setParameters()

More details can be found in the simulcast section in the spec.

The Fine Print
PeerConnection does not support receiving simulcast. A server (Selective Forwarding Unit) must be used between PeerConnections.
Simulcast scenario is relevant for group calls where an SFU should be used, so no support is available for trying to negotiate simulcast between two peers without an SFU.

SSRCs will not be signaled in this scenario. 
RIDs are the identifiers that are used in simulcast and providing another source of identifiers without spec-compliant grammar to indicate how the two identifiers correlate introduces issues of conflicting ids.
SSRCs are used in all other unified plan scenarios for backwards compatibility until MID routing is more prevalent, however, since simulcast requires the SFU to signal RIDs, it is reasonable to assume that signaling RIDs indicates support for them.

An important difference between simulcast and the SDP munging technique is the negotiation aspect. The munging scenario does not consult the other party if simulcast should be sent and there is not way to reject it.
The new API requires that simulcast be 'accepted' during negotiation and multiple layers will not be sent if they are not acknowledged by the receiving party.


Looking forward to seeing this used in the wild and hearing community feedback,
Amit

Lorenzo Miniero

unread,
Mar 15, 2019, 2:00:45 PM3/15/19
to discuss-webrtc
I've added support for this in an experimental branch of Janus and it seems to be working fine with M74. For people interested in the code, you can find it here:

    https://github.com/meetecho/janus-gateway/pull/1547

What I've noticed during the tests, though, is that the very first packets Chrome sends for video don't contain neither mid nor rid/repaired-rid extensions: I can tell they're a retransmission packet because of the payload type, but not which m-line or layer they refer to, and so have to drop those packets.

Hope this helps,
Lorenzo

pablo

unread,
Mar 20, 2019, 8:32:40 PM3/20/19
to discuss-webrtc
The example shows how to specify the simulcast layers in the client offer.
Is it possible to specify layers in an answer assuming the SFU offer contains a=simulcast:recv?

ami...@webrtc.org

unread,
Mar 21, 2019, 12:25:49 PM3/21/19
to discuss-webrtc
The answer should contain the same rid lines (or at least lines for accepted streams):
a=rid:f send
a=rid:h send
a=rid:q send
and should contain the symmetric response accepting the simulcast streams:
a=simulcast:recv f;h;q

of course, offer and answer should negotiate rid/mid/rrid extension headers as well.
if the answer does not indicate willingness to accept simulcast, simulcast will not be used (all layers except the first will be removed).
Note that it is not supported to send simulcast to a peer connection, so the SFU is mandated in this scenario and a peer connection should not receive a=simulcast:send (which indicates that the other party is sending simulcast).

ami...@webrtc.org

unread,
Mar 21, 2019, 1:59:55 PM3/21/19
to discuss-webrtc
And if the SFU is creating the offer, then it should specify the streams it wants to receive:
a=rid:f send
a=rid:h send
a=rid:q send
a=simulcast:recv f;h;q

The accepting PeerConnection should respond with the symmetric
a=rid:f send
a=rid:h send
a=rid:q send
a=simulcast:send f;h;q

The application should set the parameters on the transceiver before calling SetLocalDescription().
I believe you also need to set the direction to SendReceive (or SendOnly) to enable the transceiver to send video.

Hope this is what you are looking for.

pablo platt

unread,
Mar 21, 2019, 2:38:29 PM3/21/19
to discuss...@googlegroups.com
On Thu, Mar 21, 2019 at 8:00 PM <ami...@webrtc.org> wrote:
And if the SFU is creating the offer, then it should specify the streams it wants to receive:
a=rid:f send
a=rid:h send
a=rid:q send
a=simulcast:recv f;h;q

The accepting PeerConnection should respond with the symmetric
a=rid:f send
a=rid:h send
a=rid:q send
a=simulcast:send f;h;q

The application should set the parameters on the transceiver before calling SetLocalDescription().
I believe you also need to set the direction to SendReceive (or SendOnly) to enable the transceiver to send video.

How can the application set the parameters on the transceiver before calling setLocalDescription()?
If the SFU sends the first offer, the application won't have a transceiver yet. The application can add another transceiver but we'll have two transceivers instead of one.

This is what the spec says which seems very limiting:
Another implication is that the answerer cannot set the simulcast envelope directly. Upon calling the setRemoteDescription method of the RTCPeerConnection object, the simulcast envelope is configured on the RTCRtpTransceiver to contain the layers described by the specified RTCSessionDescription

 
--

---
You received this message because you are subscribed to the Google Groups "discuss-webrtc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to discuss-webrt...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/discuss-webrtc/834ece6b-5da3-421b-a581-909e4e2ce7a7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Harald Alvestrand

unread,
Mar 21, 2019, 3:26:09 PM3/21/19
to discuss...@googlegroups.com
Yes, allowing the initiator to decide the number of simulcast layers is limiting.
It  is, however, not a very limiting limitation. If you have control over both ends, just send the max number of layers that is reasonable to use.
If you don't have control over both ends, staying within the restrictions proposed by the initiator seems like a good idea.


ami...@webrtc.org

unread,
Mar 21, 2019, 6:18:55 PM3/21/19
to discuss-webrtc
1. SFU creates and sends an offer with a=simulcast:recv 1;2;3
2. PC client calls setRemoteDescription(offer)
at this point a transceiver will be created in PC for the simulcast media section with 3 layers with RIDs 1,2,3.
3. PC client calls getTransceivers(), finds the simulcast transceiver and uses getParameters() + setParameters() to configure the layers (or disable them)
4. PC client calls createAnswer() + setLocalDescription(answer)

so the envelope is only set by the initiator correct, but that isn't the real limitation. it appears that much of simulcast is left to the application layer logic (such as communicating what the actual layers are), it's not unreasonable to assume that applications can use some maximum or signal the requested number of layers off-band. the answerer can 'reduce' the envelope and reject unwanted layers.

pablo platt

unread,
Mar 21, 2019, 6:26:30 PM3/21/19
to discuss...@googlegroups.com
Thanks Amit and Harald.

pablo platt

unread,
Mar 25, 2019, 4:16:13 AM3/25/19
to discuss...@googlegroups.com
I'm not able to get simulcast RTP packets from Chrome 74 Beta on Ubuntu 18.04.
Audio track and video track without simulcast work fine.

The SFU sends an offer with:
a=rid:h send
a=rid:m send
a=rid:l send
a=simulcast:recv h;m;l

Chrome call pc.setRemoteDescription(offer). A transceiver is created and transceiver.getParameters() gives:
{
  encodings: [
    {rid: "h", active: true, networkPriority: "low", priority: "low"}
    {rid: "m", active: true, networkPriority: "low", priority: "low"}
    {rid: "l", active: true, networkPriority: "low", priority: "low"}
  ],
  codecs: [],
  headerExtensions: [],
  rtcp: {cname: "", reducedSize: false},
  transactionId: "b8641e8c-91a9-4840-a61a-0dc77e307275"
}

Chrome creates an answer with:
a=rid:h send
a=rid:m send
a=rid:l send
a=simulcast:send h;m;l

I'm not getting any error but the SFU doesn't receive RTP and RTCP packets from this track.
Am I missing a step?





Lorenzo Miniero

unread,
Mar 25, 2019, 4:23:58 AM3/25/19
to discuss-webrtc
Pablo, you have 'send' in your SFU offer for the rid lines, it should be 'recv' I believe.

Lorenzo

pablo platt

unread,
Mar 25, 2019, 4:28:57 AM3/25/19
to discuss...@googlegroups.com
I've tried both send and recv. The spec is a bit confusing [1]:

As defined in [JSEP] (section 3.7.), an offer from a user-agent will only contain a "send" description and no "recv" description on the "a=simulcast" line. Alternatives and restrictions (described in [MMUSIC-SIMULCAST]) are not supported.
 

ami...@webrtc.org

unread,
Mar 25, 2019, 1:16:54 PM3/25/19
to discuss-webrtc
That's not it. The direction in a=rid lines is arbitrary in webrtc, because it relates to the direction of restrictions, which are not in the webrtc spec.
Did you remember to set the direction on the transceiver to send or send/receive?
Because the offer is incoming, the transceiver is created as recv only.

pablo platt

unread,
Mar 25, 2019, 1:46:36 PM3/25/19
to discuss...@googlegroups.com
Yes, I've set the transceiver.direction to 'sendonly'.
If I'm removing a=rid and a=simulcast lines Chrome sends rtp packets so my setup should be good.

Do I need to call sender.setParameters() between setRemoteDescription() and setLocalDescription() or should it send rtp packets with the default settings?
I'm only adding the track in the second negotiation, could this be the problem?

1. SFU sends offer with a=rid and a=simulcast:recv, a=recvonly lines.
2. Chrome call pc.setRemoteDescription(), pc.createAnswer() and pc.setLocalDescription()
3. Chrome call getUserMedia, let transceiver = pc.getTransceivers()[0], transceiver.sender.replaceTrack(track), transceiver.direction = 'sendonly'
4. SFU sends offer, Chrome call pc.setRemoteDescription(), pc.createAnswer() and pc.setLocalDescription()




ami...@webrtc.org

unread,
Mar 25, 2019, 2:14:43 PM3/25/19
to discuss-webrtc
Are you still negotiating it fully in the first negotiation? i.e. are you sending a=simulcast and a=rid lines in the initial answer?
Does it work if you add the track in the initial negotiation?

Make sure that SRD is the one that creates the transceiver for you. you should only add the track after SRD. check how many layers you have in getParameters()

It should send rtp packets without having to setParameters, but i guess you should call that anyway to set the layer characteristics.

pablo platt

unread,
Mar 25, 2019, 2:33:06 PM3/25/19
to discuss...@googlegroups.com
On Mon, Mar 25, 2019 at 8:14 PM <ami...@webrtc.org> wrote:
Are you still negotiating it fully in the first negotiation? i.e. are you sending a=simulcast and a=rid lines in the initial answer?

Yes, I'm sending  a=simulcast and a=rid with recv or send direction in all offers and answers.

Does it work if you add the track in the initial negotiation?

I've tried it now and I'm still not getting rtp packets:

1. SFU send offer with a=simulcast, a=rid and a=recvonly lines.
2. Chrome call pc.setRemoteDescription(offer)
3. Chrome calls console.log(pc.getTransceivers()[1].sender.getParameters()). Result below.
4. Chrome call let transceiver = pc.getTransceivers()[1]; transceiver.sender.replaceTrack(localVideoTrack); transceiver.direction = 'sendonly';
5. Chrome call pc.createAnswer(); pc.setLocalDescription(answer);

pc.getTransceivers()[1].sender.getParameters() after pc.setRemoteDescription(offer) gives me:
{
  encodings: [
    {rid: "h", active: true, networkPriority: "low", priority: "low"}
    {rid: "m", active: true, networkPriority: "low", priority: "low"}
    {rid: "l", active: true, networkPriority: "low", priority: "low"}
  ],
  codecs: [],
  headerExtensions: [],
  rtcp: {cname: "", reducedSize: false},
  transactionId: "b8641e8c-91a9-4840-a61a-0dc77e307275"
}

Maybe unrelated small issue:
If the SFU sends only one a=rid line, Chrome doesn't include a=rid and a=simulcast lines in the answer. I know it doesn't really make sense to have only one rid line.

ami...@webrtc.org

unread,
Mar 25, 2019, 4:14:54 PM3/25/19
to discuss-webrtc
I cannot think of something off the top of my head. i will try it on my playground.


On Monday, March 25, 2019 at 11:33:06 AM UTC-7, pablo wrote:


On Mon, Mar 25, 2019 at 8:14 PM <ami...@webrtc.org> wrote:
Are you still negotiating it fully in the first negotiation? i.e. are you sending a=simulcast and a=rid lines in the initial answer?

Yes, I'm sending  a=simulcast and a=rid with recv or send direction in all offers and answers.

Does it work if you add the track in the initial negotiation?

I've tried it now and I'm still not getting rtp packets:

1. SFU send offer with a=simulcast, a=rid and a=recvonly lines.
2. Chrome call pc.setRemoteDescription(offer)
3. Chrome calls console.log(pc.getTransceivers()[1].sender.getParameters()). Result below.
4. Chrome call let transceiver = pc.getTransceivers()[1]; transceiver.sender.replaceTrack(localVideoTrack); transceiver.direction = 'sendonly';
5. Chrome call pc.createAnswer(); pc.setLocalDescription(answer);

pc.getTransceivers()[1].sender.getParameters() after pc.setRemoteDescription(offer) gives me:
{
  encodings: [
    {rid: "h", active: true, networkPriority: "low", priority: "low"}
    {rid: "m", active: true, networkPriority: "low", priority: "low"}
    {rid: "l", active: true, networkPriority: "low", priority: "low"}
  ],
  codecs: [],
  headerExtensions: [],
  rtcp: {cname: "", reducedSize: false},
  transactionId: "b8641e8c-91a9-4840-a61a-0dc77e307275"
}

Maybe unrelated small issue:
If the SFU sends only one a=rid line, Chrome doesn't include a=rid and a=simulcast lines in the answer. I know it doesn't really make sense to have only one rid line.
The spec says that a single rid should be removed, so when there is only one, it does not trigger simulcast. 

篠原俊一

unread,
Mar 31, 2019, 11:30:42 PM3/31/19
to discuss...@googlegroups.com
By following the discuttion in this thread, I also tried
server(SFU)-offer simucast signaling.
As pablo did, I confirmed no RTP packets came from Chrome.

What I noticed so far are:
- The sdp generated by createAnswer at Chrome **has** "a=rid" lines of recv, but
- the sdp obtained by PeerConnection.localDescription after
setLocalDescription does **NOT**.

The phenomena can be reproduced Chrome side only and the snippet is
at: https://gist.github.com/shino/c950790644d5dcdee80322e03ae2d6f6
The version of Chrome I tried are:
- Version 75.0.3752.0 (Official Build) canary (64-bit)
- Version 74.0.3729.40 (Official Build) beta (64-bit)

I'm not sure this has something with no RTP transmission... but I'm wondering
whether lack of a=rid lines is normal/proper thing or not.

Thanks,
Shino

2019年3月26日(火) 5:15 <ami...@webrtc.org>:
> To view this discussion on the web visit https://groups.google.com/d/msgid/discuss-webrtc/8b97c62a-5ad5-462e-9aa5-865f764cb70f%40googlegroups.com.

ami...@webrtc.org

unread,
Apr 2, 2019, 3:51:50 PM4/2/19
to discuss-webrtc
Important clarification about the backwards compatibility statement in this PSA.

If you are currently using a=simulcast: in your SDP chrome behavior *will* change and possibly break your application.
If you are relying on chrome ignoring a=simulcast lines, then your application will undoubtedly break.

Chrome will no longer ignore a=simulcast: lines, but will treat them as simulcast.
As such:
If a=simulcast lines are not compliant to the spec (the format has been stable since version #04 in 2016), then chrome will:
1. Reject the SDP with error, or
2. Misinterpret the lines.
If the line is understood (or misunderstood without error) then:
1. If this is an incoming offer requesting the platform to send simulcast, then a transceiver will be created with the RIDs from the simulcast attribute
2. If this is an incoming answer, then layers may be removed for RIDs that do not appear in the simulcast attribute.

If you are currently using a=simulcast and your application relies on chrome ignoring these lines or you fear that your application may break, I ask that you please respond back (privately, or publicly, your choice) so that we can work out the details and resolve them to the best of the community.

Thanks,
Amit

Alexander Abagian

unread,
Apr 5, 2019, 6:41:55 PM4/5/19
to discuss-webrtc
Sorry, what rrid extenstion do you mean ? Is it urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id ?

ami...@webrtc.org

unread,
Apr 5, 2019, 7:12:00 PM4/5/19
to discuss-webrtc
Correct. rrid is the repaired-rid used for RTX packets. That is the header extension uri.

pablo platt

unread,
Apr 8, 2019, 8:22:03 AM4/8/19
to discuss...@googlegroups.com
Is it possible to control or detect the number of temporal layers per rid?
Is it possible to get only one stream with 3 temporal layers?

--

---
You received this message because you are subscribed to the Google Groups "discuss-webrtc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to discuss-webrt...@googlegroups.com.

Harald Alvestrand

unread,
Apr 8, 2019, 9:08:45 AM4/8/19
to discuss...@googlegroups.com
RIDs only work with simulcast (independent encodings).
You can get varying framerates from the simulcast streams, but I don't think it's correct to call these "temporal layers".


Alexander Abagian

unread,
Apr 8, 2019, 8:38:57 PM4/8/19
to discuss-webrtc
And the RTX packets are really required for simulcast ?

ami...@webrtc.org

unread,
Apr 9, 2019, 12:22:57 PM4/9/19
to discuss-webrtc
No, RTX is not required for simulcast. you can disable RTX by not signaling the codec for it or by indicating that you do not support rrid (not signaling the extension header).
The platform will not attempt to send them in these cases.

pablo platt

unread,
Apr 12, 2019, 6:09:47 AM4/12/19
to discuss...@googlegroups.com
Did you reproduce the issue where the sfu is sending an offer with simulcast and Chrome doesn't send media packets?

--

---
You received this message because you are subscribed to the Google Groups "discuss-webrtc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to discuss-webrt...@googlegroups.com.

ami...@webrtc.org

unread,
Apr 12, 2019, 7:56:58 PM4/12/19
to discuss-webrtc
I think i have something that reproduces it, we need to run more tests to make sure and find root cause.
To unsubscribe from this group and stop receiving emails from it, send an email to discuss...@googlegroups.com.

ami...@webrtc.org

unread,
Apr 15, 2019, 6:43:44 PM4/15/19
to discuss-webrtc
Track this bug through:
http://bugs.webrtc.org/10551

Currently planning on fixing this in M75.
Reply all
Reply to author
Forward
0 new messages