New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Undefined RTCRtpListener behavior #48
Comments
Currently the RtcRtpReceiver object is setup to match incoming RTP streams based on 3 configurable options:
Each one of these is "nullable" meaning, you can specify some combination of rules to match an incoming stream. While this is simple, it can create some ambiguities which I will attempt to illustrate and suggest possible resolutions. Use case (1): Specify an RtcRtpReceiver matching as:
Then any stream which has a receiverId as "foo" and a payload of "96" will match that RtcRtpReceiver object. Any stream that does not match will be treated as "unhandled" and an "unhandled" event will fire. Use case (2): Specify an RtcRtpReceiver matching as receiverId = "foo" but RTP stream drops "foo" receiverId header after first RTCP "ack" of that RTP stream If a receiverId (DOMString) of "foo" comes in with an SSRC of "1000", as soon as the RTP stream gets acknowledged via an RTCP report then the receiverId can be dropped from the RTP packet extension header. But an implicit receiverId of "foo" must remain attached to every SSRC "1000" even though the receiverId is no longer present to continue allowing the RtcRtpReceiver matching rules to apply. In my mind, the best way to handle this scenario. If later suddenly another RTP SSRC stream of 1000 added a receiverId of "bar" instead of "foo", then that SSRC 1000 RTP stream no longer would match the "foo" rule and any further SSRC of 1000 without any receiverId would be considered as having a "bar" receiverId and not "foo". Use case (3): Two RtcRtpReceiver objects matching as: In this case, an RTP stream with 5000 and a payload ID that did not match 101 would match to RtcRtpReceiver object (a) and an RTP stream with SSRC 5000 but a payload ID of 101 would match to RtcRtpReceiver object (b). In other words, the most specific match wins over the general match. Use case (4): Two RtcRtpReceiver objects matching as: In this case, an RTP stream with SSRC 5000 and a payload ID of 96 would match (a). An RTP stream with SSRC 5000 and payload ID of 101 with no receiverId would not match (a) or (b) and would be "unhandled". An RTP stream with SSRC 5000, payload ID of 96 and receiverId of "foo" would be ambiguous as both (a) or (b) could match. I think there needs to be precedence rules for matching in such cases. I'm open to debate as to what those rules should be. Would payload trump receiverId? Would it depend on RtcRtpReceiver construction order? Would it go to "unhandled" for the web app developer to resolve the conflict? Use case (5): One RtcRtpReceiver object matching as:
RTP stream (A) arrives with receiverId = "foo". RTP stream (B) arrives with receiverId = "foo". Since there's only one "MediaStreamTrack" associated to the RtcRtpReceiver object, what happens to these two RTP streams? Yes, it's possible (perhaps likely) that one stream is replacing the other thus "last one wins" is an acceptable rule. However, it's also possible this is not the case you have two streams and you need to decide what to do. Options: Thoughts? |
Don't make it so complex. Here's some simple rules.
Once a match is made, the SSRC is copied in and then rule 1 is used from then on. Mismatches are only a problem (and worth reporting perhaps ... but in something like stats) when: a. Payload type for a known SSRC isn't known. Both indicate either misconfiguration or SSRC collision between remote peers in the RTP session. Neither is of particular concern. |
The would presume that once an RtpReceiver is locked onto a stream, it's locked onto that stream forever and any new stream that comes in has to be fired as an unhandled event which needs a new RtpReceiver as oppose to allowing a receiver to be repurposed. In a conference scenario where streams are constantly changed, that means every change would need a new RtpReceiver per changed RTP stream (assuming it was coming from an SFU that didn't re-write the SSRC). I'm okay with that, but we do still need to have exact rules. |
See my response to Bernard. I think that you should be including the receiver ID header extension if you are forced to move to another SSRC. That would allow the new SSRC to be switched to if the SSRC had to change. |
Suggestion from Peter:
|
Here is a strawman proposal: |
A revised strawman: |
A few comments:
a. (Fill ssrc => receiver) Set ssrc_table[ssrc] = receiver for each ssrc e. (SSRC match) If receiver = ssrc_table[packet.ssrc] is set, route the Not that this means empty muxId is not wildcard, and receivers with set What do you think? On Tue, Dec 2, 2014 at 11:37 PM, aboba notifications@github.com wrote:
|
Here are some thoughts from Peter: |
Peter Thatcher said: “As an alternative to the receiver table, I suggest a ruleset using just three simple maps: ssrc => receiver, muxId => receiver, and PT => receiver. Then the rules would be: a. (Fill ssrc => receiver) Set ssrc_table[ssrc] = receiver for each ssrc in the parameters.encodings passed to each receiver by RtpReceiver.receive(). [BA] OK. b. (Fill muxid => receiver) Set muxid_table[muxId] = receiver for the parameter.muxId passed to each receiver by Receiver.receive() [BA] OK. c. (Fill PT => receiver) Set pt_table[pt] = receiver for each pt in parameters.codecs passed to each receiver by Receiver.receiver(), but only if parameters.muxId is unset and no ssrcs are in parameters.encodings. [BA] Not sure what the "but only" means. Are we saying that if parameters.muxId is unset or there are ssrcs in parameters.encodings that we don't create a pt_table[pt] entry? d. (Avoid collisions) If ssrt_table[ssrc], muxid_table[muxId], or pt_table[pt] would ever be set to a conflicting value, the call to Receiver.receive (or Receiver.setTransport) will fail with an exception. [BA] OK. e. (SSRC match) If receiver = ssrc_table[packet.ssrc] is set, route the packet to the receiver. But if the receiver does not understand packet.PT, fire the unhandledrtp event. [BA] If we were allowed to set a pt_table[pt] entry in c), then the last sentence could be replaced by: f. (muxId match and SSRC latch) If packet.muxId is set and receiver = muxid_table[packet.muxId] is set, route the packet to the receiver and set ssrc_table[packet.ssrc] = receiver. But if the receiver does not understand packet.PT, fire the unhandledrtp event. [BA] If we were allowed to set a pt_table[pt] entry in c), then the last sentence could be replaced by: g. (muxId unmatched) If packet.muxId is set and muxid_table[packet.muxId] is unset, fire the unhandledrtp event. [BA] OK. d. (PT match and SSRC latch) If receiver = pt_table[packet.pt] is set, route the packet to the receiver and set ssrc_table[packet.ssrc] = receiver.” [BA] It is sometimes desirable to allow a sender to switch between sources, though it only sends one source at a time. In such a scenario we might route the first source to the receiver, then set ssrc_table[packet.ssrc] = receiver. When the sender switches sources, will the new source also be routed to the same receiver via the PT match rule, with another ssrc_table[packet.ssrc] = receiver entry being created, or will c) cause the PT match to no longer be operational, resulting in an unhandledrtp event? |
Here a draft of proposed text for Section 8.3: 8.3 Matching rules When the RTCRtpListener object receives an RTP packet over an RTCDtlsTransport, the RTCRtpListener attempts to determine which RTCRtpReceiver object to deliver the packet to, based on the values of the SSRC and payload type fields in the RTP header, as well as the value of the MID RTP header extension, if present. The RTCRtpListener maintains four tables in order to facilitate matching: the ssrc_table which maps SSRC values to RTCRtpReceiver objects; the muxId_table which maps values of the MID header extension to RTCRtpReceiverobjects, the pt_table which maps payload type values to RTCRtpReceiver objects, and the receiver_table which keeps track of payload types supported by each receiver. For an RTCRtpReceiver object receiver, table entries are added when receiver.receive(parameters) is called, and are removed when receiver.stop() is called. If receiver.receive(parameters) is called again, all entries referencing receiver are removed prior to adding new entries. SSRC table: ssrc_table[parameters.encodings[i].ssrc] is set to receiver for each entry where parameters.encodings[i].ssrc is set, for values of i from 0 to the number of encodings. If ssrc_table[ssrc] is already set to a value other than receiver, then receiver.receive(parameters) will throw an InvalidParameters exception. muxId table: If parameters.muxId is set, muxId_table[parameters.muxId] is set to receiver. If muxId_table[muxId] is already set to a value other than receiver, then receiver.receive(parameters) will throw an InvalidParameters exception. payload type table: If parameters.muxId is unset and parameters.encodings[i].ssrc is unset for all values of i from 0 to the number of encodings, then add entries to pt_table by setting pt_table[parameters.codecs[j].payloadType] to receiver, for values of j from 0 to the number of codecs. If pt_table[pt] is already set to a value other than receiver, or parameters.codecs[j].payloadType is unset for any value of j from 0 to the number of codecs, then receiver.receive(parameters) will throw an InvalidParameters exception. Receiver table: receiver_table[receiver] is set to an array of payload types, parameters.codecs[j].payloadtype, where j varies from 0 to the number of codecs. When an RTP packet arrives, if ssrc_table[packet.ssrc] is set: set packet_receiver to ssrc_table[packet.ssrc] and check whether the value of packet.pt is included in any of the entries in receiver_table[packet_receiver]. If so, route the packet to packet_receiver. If packet.pt does not match, unhandledrtp event. Else if packet.muxId is set: If muxId_table[packet.muxId] is unset, fire the unhandledrtp event, else set packet_receiver to muxId_table[packet.muxId] and check whether the value of packet.pt is included in any of the entries in receiver_table[packet_receiver]. If so, set ssrc_table[packet.ssrc] to packet_receiver and route the packet to packet_receiver. If packet.pt does not match, fire the unhandledrtp event. Else if pt_table[packet.pt] is set: set packet_receiver to pt_table[packet.pt], set ssrc_table[packet.ssrc] to packet_receiver and route the packet to packet_receiver. Question: Do we also remove the pt_table[packet.pt] entry? Else, fire the unhandledrtp event. TODO: Revise this paragraph based on the outcome of the discussion on FEC/RTX/RED. |
#48 Update to the Statistics API, reflecting: #85 Update on 'automatic' use of scalable video coding, as noted in: #156 Update to the H.264 parameters, as noted in: #158 Update to the 'Big Picture', as noted in: #159 Added support for maxptime, as noted in: #160 Changed 'RTCIceTransportEvent' to 'RTCIceGathererEvent' as noted in: #161 Update to RTCRtpUnhandledEvent as noted in: #163 Added support for RTCIceGatherer.state as noted in: #164 Revised the text relating to RTCIceTransport.start() as noted in: #166 Added text relating to DTLS interoperability with WebRTC 1.0, as noted in: #167 Revised the text relating to RTCDtlsTransport.start() as noted in: #168 Clarified handling of incoming connectivity checks by the RTCIceGatherer as noted in: #170 Added a reference to the ICE consent specification, as noted in: #171
On Mon, Jan 5, 2015 at 12:41 PM, aboba notifications@github.com wrote:
d. (Avoid collisions) If ssrt_table[ssrc], muxid_table[muxId], or
I think you'd end up with another ssrc_table[packet.ssrc] entry. In other
|
That sounds pretty good to me. The only thing I'm not sure about is On Mon, Jan 12, 2015 at 12:12 PM, aboba notifications@github.com wrote:
|
By the way, it's worth pointing out that at the end of the day, we might On Mon, Jan 26, 2015 at 1:28 PM, Peter Thatcher pthatcher@google.com
|
Agree that ORTC API needs to behave the same way as WebRTC 1.0. The On Tue, Jan 27, 2015 at 9:01 AM, pthatcherg notifications@github.com
|
https://tools.ietf.org/html/draft-roach-mmusic-unified-plan-00#section-3.2 On Wed, Jan 28, 2015 at 8:04 AM, aboba notifications@github.com wrote:
|
https://datatracker.ietf.org/doc/draft-ietf-mmusic-sdp-bundle-negotiation/?include_text=1 Section 9+10 are applicable. |
Looking at draft-roach-mmusic-unified-plan Section 3.2, it would appear that the muxId and ssrc tables from Peter's proposal are consistent with the advise given there. The concerns so far seem to arise with respect to payload type demultiplexing, covered in Section 3.2.1.2. Since Peter's proposal requires PT uniqueness, I believe it behaves as though the constraint is set in Section 3.2.1.2 below: 3.2.1.2. Payload Type Correlation To support implementations that cannot implement the RTP header Because of its inherent limitations, it is advisable to use other If this constraint is set, the browser MUST behave as described in When such a constraint is present, implementations attempt to
|
I think my proposal is very similar to this draft in the sense that if you The part that seems difficult for us is what we do about SSRC latching, and On Thu, Jan 29, 2015 at 7:01 AM, aboba notifications@github.com wrote:
|
- Revised the text relating to RTCDtlsTransport.start(), as noted in: Issue #168 - Clarified pruning of local candidates within the RTCIceGatherer, as noted in: Issue #174 - Clarified handling of incoming connectivity checks by the RTCIceGatherer, as noted in: Issue #170 - Added Section 9.3.2.1, defining DTMF capabilities and settings, as noted in: Issue #177 - Clarified pre-requisites for insertDTMF(), based on: Issue #178 - Added Section 8.3.2 and updated Section 9.5.1 to clarify aspects of RTCP sending and receiving, based on: Issue #180
Here is an analysis from Peter Thatcher of several options for handling two use cases:
Option A: Only 1 SSRC per RtpReceiver gets routed because of PT, after that it's unhandled "muxID or PTs choose RtpReceiver" Use case 1: Simple case with RTX. Option A: Have to listen to unhandled, but then when you add that one, the first one gets lost.. Use case 2: Conference audio. Option A: Works. |
Recent comment from Magnus relating to JSEP that may be relevant to this issue: |
I would like to propose that we close this general bug, and work on the more specific ones (e.g. relating to RED/RTX/FEC). |
Currently, it is not clear how the RTCRtpLIstener determines whether an RTP stream is configured to be processed by an existing RTCRtpReceiver object. Presumably this is based on the
RTCRtpReceiver.RTCRtpParameters.RTCRtpCodecParameters.payLoadType, RTCRtpReceiver.RTCRtpParameters.RTCRtpEncodingParameters.ssrc, and RTCRtpReceiver.RTCRtpParameters.receiverId attributes,
but how?
The text was updated successfully, but these errors were encountered: