w3c / ortc

ORTC Community Group specification repository (see W3C WebRTC for official standards track)
http://www.w3.org/community/ortc/
122 stars 42 forks source link

SSRC values should not be entered by the user #438

Closed ibc closed 8 years ago

ibc commented 8 years ago

Currently, if the user calls RtpSender.send() without setting specific SSRC values, the browser will choose them. This is fine. The problem is that, at that point, RTP negotiation is already supposed to be done so we cannot signal our SSRC. Even worse: RtpSender does not have a getRtpParameters() method that retrieves the effective parameters (including SSRC values chosen by the browser).

This basically means that the user (the JS) is required to manually set a random SSRC which IMHO is not very cool.

NOTE: I do know that, given "RTP Matching Rules" the receiver may be able to somehow correlate received RTP packets, but that is not valid for all the cases (if I send two video tracks over two RtpSenders over the same DtlsTransport and choose the same PT value for both, the receiver won't be able to properly demux RTP packets belonging to both video streams, so SSRC values are required).

ibc commented 8 years ago

For example:

9.11.1 Dictionary RTCRtpFecParameters Members

mechanism of type DOMString The Forward Error Correction (FEC) mechanism to use.

ssrc of type unsigned long The SSRC to use for FEC. If unset in an RTCRtpSender object, the browser will choose.

What does it mean? I the browser chooses the SSRC for FEC and the user has no way to know it, how can it signal the SSRC to the peer? If the peer does not know about the SSRC used for FEC, how would the peer even know that it is receiving FEC packets?

If the answer is "by checking into the received codec sequences in which FEC PT is specified" I would answer the same as above: we should NOT delegate into simple PT value matching. When it comes to a SFU with multiple participants there can be multiple codecs or FEC streams with same PT.

To summarize: ORTC spec invites the user to leave the SSRC unset (unless the user sets it manually).

ibc commented 8 years ago

To be clear: in WebRTC (SDP O/A) the remote peer knows about our sending SSRCs for media, RTX, FEC, etc, without the user having to set them manually. We cannot do that worse in ORTC.

aboba commented 8 years ago

If the SSRC is not specified in the parameters passed to sender.send(parameters), the browser will choose. This occurs in several places:

  1. parameters.encodings[i].ssrc
  2. parameters.encodings[i].fec.ssrc
  3. parameters.encodings[i].rtx.ssrc

If the application does not choose the SSRCs and lets the browser choose them, currently it is not possible for the sender to determine what these SSRC values have been set to. This means that to signal SSRCs, the application has to choose them.

This seems like a difficult choice for developers, but there is a way for the developer to let the browser choose SSRCs while avoiding the signaling problems – using muxId (the MID header extension).

In this model, the RtpReceiver can set parameters.muxId in receiver.receive(parameters), and then signal this to the sender which will set parameters.muxId in sender.send(parameters).

If the muxId is used, the matching rules enable both media and RTX/RED/FEC to be routed to the correct receiver without the application needing to choose SSRCs or signal them.

Since ortc-lib is implementing muxId, Robin can perhaps best comment on his experience with that approach.

murillo128 commented 8 years ago

Correct me if I am wrong, for doing SDP O/A interworking with webrtc we would need the ssrc anyway to be signaled on the offer ssrc group attribute, so MID would not be useful in this case.

Moreover, event implementing a getRtpParameters()' onRTPSenderwould not work in this case, as I expect the app to create theRTPSender`when the SDP answer is received and the codec chosen, while we need the ssrcs beforehand.

ibc commented 8 years ago

I expect the app to create theRTPSender`when the SDP answer is received and the codec chosen, while we need the ssrcs beforehand.

In SDP land you can create a "fake" SDP offer with valid codecs and features (retrieved via RtpReceiver.getCapabilities() and specific SSRCs (chosen by the app). Upon receipt of the SDP answer the app should then call rtpSender.send() with updated RTP parameters (keep the original SSRC already signaled to the peer, and update the payload type values if the SDP answer did not respect the values indicated in the SDP offer).

ibc commented 8 years ago

If the muxId is used, the matching rules enable both media and RTX/RED/FEC to be routed to the correct receiver without the application needing to choose SSRCs or signal them.

The muxId solution seems indeed perfect. However I assume that, in multiple scenarios, signaling SSRCs will be needed due to interop with media servers, SFUs, etc that do not implement muxId.

robin-raymond commented 8 years ago

With the MuxID (and RID) it's possible to route packets without any SSRCs being known in advance. This is one of the reasons why these IDs are being used. There was a recent issue with regards to RTX where there would be a problem but that's been resolved. So, there is an alternative without signalling SSRCs.

Having said that, I agree there are use cases where the SSRC needs to be created. JS is perfectly able to create SSRCs but I agree expecting JS developers to know all the subtle rules about SSRC creation is a bit much.

So two options exist in my mind: 1) Create a method (somewhere) that generates new random SSRCs 2) Expose the resulting "filled" data via an event when the information in the resulting "send" (which cascades into a whole pile of other issues and is one of the reasons why we left this out)

I really hesitate to do option 2) because of the problems it will introduce. Specifically, that turns a synchronously called method into one that requires it to be asynchronous to be used properly. Further, the information may be filled in from lower layers asynchronously, and repeated calling of "send(...)" requires very careful remapping of SSRC changes that have to be respected. Plus then you need a promise (or worse, an event, on the send(...)).

murillo128 commented 8 years ago

In SDP land you can create a "fake" SDP offer with valid codecs and features (retrieved via RtpReceiver.getCapabilities() and specific SSRCs (chosen by the app).

That's what I meant, that in "SDP land" the app is always forced to choose the ssrc beforehand, and MID will not be a solution on that case.

robin-raymond commented 8 years ago

Then again, expecting an average developer to know how to fill encodings and codecs is likely a bit much too thus having the developer pick the SSRCs when using this API isn't necessarily above their skill set... And yes, any SDP shim would require picking the SSRCs.

murillo128 commented 8 years ago

2) will not solve the problem anyway.

Maybe an instance method on RTPSender like reserveSSRC() would be enough. I prefer an instance method over an static one so the reserved ssrcs could be automatically freed when object is released.

ibc commented 8 years ago

Maybe an instance method on RTPSender like reserveSSRC() would be enough.

I don't see any added value on that over just setting the desired SSRC into the RtpParameters given to the RtpSender.

murillo128 commented 8 years ago

Except that they may be invalid and the sendmay fail after you have done the negotiation.

ibc commented 8 years ago

If RtpSender.getCapabilities() has been used to retrieve supported codecs/features, I don't see how rtpSender.send() can fail later if called with those codecs.

murillo128 commented 8 years ago

I am talking about setting incorrect values for the ssrc on RTParameters, for example, you have set the same ssrc for media and rtx. I acknowledge that that should cause the negotiation to fail on the remote side.

robin-raymond commented 8 years ago

@ibc The problem with the engine choosing the SSRC in the API (option 2) is that it's never truly done in the choice. An SSRC conflict can happen later where the SSRC changes. Thus it's entirely possible for the sender to choose the SSRCs and then be forced to change it's mind upon an SSRC conflict detection.

As for the value of reserveSSRC() or something like that would be to ensure that the SSRCs were chosen according to the proper rules vs a JS developer having to figure out how to create an appropriate SSRC in JS. I'm not convinced that it's required since SSRC generation isn't that bad, unless you want the engine to take a further step of marking the SSRC in use to prevent random from accidentally choosing the same SSRC within the same context (but that still doesn't eliminate other usage later from causing other SSRC conflicts).

ibc commented 8 years ago

Not sure if I already said this, but there are no "SSRC conflics". SSRC is a 32 bits integer. SSRC conflicts do not exist.

Anyhow, the fact the SSRC conflicts "may happen" does not justify the fact that ORTC does not allow the user signal the browser chosen SSRCs before RTP is being sent.

We need an API that provides the user with full RtpParameters including codecs and the corresponding encodings (which obviously depend on the retrieved codecs, even more if there are SVC codecs):

  1. The user gets the browser sending capabilities (codecs and their properties).
  2. The user may now filter some of those codecs.
  3. The user provides the RtpSender with these filtered codecs.
  4. The RtpSender provides the user with a full RtpParameters object (including SSRCs).
  5. The user can modify them (for example muxId).
  6. Optionally the user can signal the full RtpParameters to the remote peer.
  7. The user can then invoke rtcSender.send() with those parameters.

What it makes no sense is that the user can just get the available codec capabilities and has no way to determine how to properly generate the required encodings sequence. And this would become even more complex and unfeasible when SVC is in the game.

robin-raymond commented 8 years ago

SSRC conflicts are rare but they do exist in theory and RFC requires specific handling of those conflicts to be compatible.

There are a few issues with SSRCs being filled in, and that's an issue with both sender and receiver. Right now you tell the API what you want and the rest is auto-filled. For the sender, this is relatively straight forward to pick SSRCs and the API could return the result when ready in a promise. Only in the case of an SSRC conflict might something need to change and then the question for the sender becomes "if" and "how" we handle that change.

The receiver however also auto-fills SSRCs (and even PTs). That is definitely not something that can be resolved in a promise because the SSRCs are discovered in an ongoing manner and can even change because of MuxID/RID mapping, etc. As packets arrive, new bits of information in the parameters is filled in by the receiver.

So the question there becomes, do we only have this option for the sender? Would not the receiver be important too? Would you really want two different mechanisms for the sender/receiver to handle the auto-fills?

Someone had suggested (maybe me? don't remember now) we include an API to fetch the values from the sender/receiver early on but it was rejected as it added complexity with little value because if a developer cares about fixed SSRCs they can specify their own. So if you bring this "rat hole" back up I think you need to have a good strong argument to counter this point and have a concrete proposal of what to do with auto-filled values for both the sender/receiver and your reasoning behind it. While opinions may have changed slightly since it was first brought up so consider this a friendly suggestion ;)

murillo128 commented 8 years ago

SSRC conflicts are rare but they do exist and RFC requires specific handling of those conflicts to be compatible.

Could you name one situation in which ssrc conflict can happen that it is not caused by a wrong API usage? (see #448)

murillo128 commented 8 years ago

Also, again @ibc is talking about ssrcs for RTPSender, but as we have same object for send and receive, we end up mixing both discussions.

robin-raymond commented 8 years ago

@murillo128 it wouldn't matter if they were the same object or not. Both auto-fill thus both need an answer as to what to do with auto-filled values. Do we want only one object's values? Do we want both? Do both need the same mechanics of how to fetch those auto-filled values? I don't see the structure of the params as relevant here.

murillo128 commented 8 years ago

The situation is really different for sending and receiving.

On sending API user shouldn't care which ssrcs are used, as long as they are able to fetch them to signal them to the other side.

On the receiving side, API user needs to input the ssrc/muxId in order to route the streams to the correct rtpreceiver.

robin-raymond commented 8 years ago

On the receiving side, API user needs to input the ssrc/muxId in order to route the streams to the correct rtpreceiver.

That's one use case but it's not the only use case that was considered. We do very much consider routing cases where muxid and RID are not present to be valid considerations.

To be clear, I'm not saying we should allow SSRC discover for the receiver, I'm saying you'll need to explain / justify a position why we should or should not need one versus the other since both discover SSRCs and both auto-fill values.

I personally don't see a strong value for SSRC discovery in the receiver, but then again, I don't necessarily see it for the sender either...

I'm often surprised by unexpected use cases! That's why I want you to take that into consideration so you can make a statement like "nobody needs to know the SSRCs discovered in the receiver" in any proposal thus giving others an opportunity to counter that point with use cause we (in our limited use cases) might not be appropriately considering.

murillo128 commented 8 years ago

I personally don't see a strong value for SSRC discovery in the receiver

We were not talking about the receiver until you introduced it.. :)

I don't necessarily see it for the sender either...

It is a must for interoperating with webrtc..

ibc commented 8 years ago

On the receiving side, API user needs to input the ssrc/muxId in order to route the streams to the correct rtpreceiver.

That's one use case but it's not the only use case that was considered.

Yes. the current RTP matching rules allow just PT based matching in simple scenarios, and also muxId/ssrc for more complex scenarios (example: multiple streams from multiple participants over the same transport).

The problem is that the ORTC API does not provide any way to signal the SSRCs in the RtpSender, so currently if we want to signal our sending SSRCs we must create our own hyper-complex encodings object (before calling send() with it). This is not human feasible.

And we need that for some really expected cases (such as the WebRTC 1.0 compatibility). So:

Bakwards compatible solution here: #447 (and I'd really want to hear any argument against such a proposal that breaks nothing). I really hope that the fact that some use cases do not require SSRC signaling for the sender do not prevent other current or future use cases.

aboba commented 8 years ago

@ibc If the application developer chooses the SSRC, then it can signal it. This is how adapter.js works today - so I don't really believe this is a WebRTC 1.0 API compatibility issue.

With respect to creating an RTCRtpParameters object, this is what the myCapsToSendParams() function does. Not only can it fill in the SSRCs, but it can also take the intersection of send and receive capabilities to figure out what codecs, header extensions and feedback mechanisms to configure.

A separate question is whether there should be a method (such as getParameters()) that will return the chosen SSRC if the developer lets the browser choose the SSRC.

robin-raymond commented 8 years ago

@aboba @ibc the CG has had a bunch of discussions around getting the parameters from the sender/receiver objects that we "filled in" by the engine. There was a fair amount of resistance because the feeling was that since the developer could set it, either they will specify it themselves or they just don't care. There's not a strong use-case to support where the programmer won't specify it but then be fetching the SSRCs from the engine later.

I've not been able to eloquently explain / justify a use case where there is such a strong need so as it stands based on previous conversations that getParameters() will not exist.

ibc commented 8 years ago

@aboba the application developer cannot choose SSRCs because with the current model he must be aware of the browser internal implementation regarding RTX, FEC and, worse, SVC or simulcast. That is not doable.

With respect to creating an RTCRtpParameters object, this is what the myCapsToSendParams() function does. Not only can it fill in the SSRCs, but it can also take the intersection of send and receive capabilities to figure out what codecs, header extensions and feedback mechanisms to configure.

myCapsToSendParams() is just a non existing helper function in a non existing helpers.js file. And regardless it may exist it does not solve my text above.

The fact is that ORTC is designed to prevent the app developer from setting low level parameters such as the SSRC just because in "most common use cases, by just signaling payload types is good enough for the remote given the 'RTP matching rules' section". There are more use cases than just that.

@robin-raymond

There's not a strong use-case to support where the programmer won't specify it but then be fetching the SSRCs from the engine later.

I've already explained some use cases and it seems that rationale given before it's being ignored:

I've not been able to eloquently explain / justify a use case where there is such a strong need so as it stands based on previous conversations that getParameters() will not exist.

I will be clear: the current ORTC API regarding RTP is a mesh. Theoretically the RtcParameters object allows the user to set SSRC values and so on, but the aim is to prevent the user to fill it just because "common use cases don't require it". Of course. The same as a legacy SIP device which is just happy with some PT values.

In any case, if an advanced user wants to manually fill a complete RtpParameters he must:

No advantages over taking a SDP m line and converting it into a JSON.

But the answer to all this stuff is still the same: "in most common case, signaling PT values is good enough". I just don't agree.

So please, take a look to this proposal (in early stage yet):

There you have, IMHO, a real API that allows both simple and complex scenarios. You won't find there hyper complex Objects that nobody can properly fill, but specific API getter/setter and a real RTCRtpEncoding class, so the user can do:

rtpSender.getEncodings()[0]disable();.

which IMHO is much better than storing the previously given RtpParameters blob, modifying the active JSON field in the desired encoding, and passing the full RtpParameters again to the browser.

And it allos the developer to retrieve the media SSRC via a simple rtpSender.ssrc getter. Or setting it via rtpSender.setSsrc() method if he wants to manually set it.

Simple and powerful IMHO. Exactly the same as the current ORTC API when it comes to ICE, DTLS or SCTP. But the current ORTC API fails when it comes to describe the RTP/media layer.

robin-raymond commented 8 years ago

the application developer cannot choose SSRCs because with the current model he must be aware of the browser internal implementation regarding RTX, FEC and, worse, SVC or simulcast. That is not doable.

Why is it not doable? Yes, being able to set these parameters does require detailed understanding of how SSRCs work (in general) in combination with PT but there's no missing "capability" that without it the setting of the values would be impossible (as far as I can tell). If you want a different SSRC for RTX / FEC, set it. Otherwise keep it the same and it uses the same SSRC. Am I missing something?

The ORTC API is meant to be the low level API. We always envisioned that people would write wrappers to simplify the various use case specific areas but otherwise would remain very much a "do as I say" API.

The getters/setters you envision appear to be syntactic sugar, and the same would be true for the engine setting SSRCs (and other properties). Those can be wrapped by any API of your choosing. Plus getters/setters imply the values can be changed dynamically in run time mid transaction (on their own outside of send()/receive()) and they cannot without being in inconsistent states.

Plus, I do not see a need to specify SSRCs except for legacy cases, specific SFU routing, or perhaps MRST. This is why the mux id and rid were invented. They allow routing where you only know the payload type for decoding and the mux id/rid ensure the packets get routed to the correct receiver/encoding.

In the case of requiring the SSRC (which is supported), then the developer can choose the values themselves and send them to the engine. All they need is a good crypto random function, and JS has those now. The chance of conflict is low, and if that's the major concern then we can create an allocation function if the CG feels the effort is worth it.

The API does allow simple and complex scenarios and I've yet to understand which complex scenarios cannot be handled that are inside the scope. We handle PT routing, mux id, rid, ssrc, ssrc + payload, rtx, fec, svc, simulcast, layering, etc.

I grant you that I'm no fan of some things like RTX, FEC and other things being codecs due to the annoyance of the cross referencing between codecs, but that's my largest beef.

The sender you are describing is not exactly capable of describing things we support. For example, RTX/FEC might only be of the base layer, or on selective simulcasted streams. Plus, if you had to change values 3 values from one state to another, e.g. ssrc, rtx and fec, you'd need 3 promises and the object between calls would be in an inconsistent state where not all settings were in their final state. There's a reason why we did send() as a single call with a lot of parameters at once, and that's because it needs to be a transaction - it's all or nothing not some or most.

The programmer could easily setup all the values at once without a single async operation, and without the possibility of one of those promises failing. The settings are then either accepted in batch or rejected.

The thing I may see as potentially valuable is the ability to add encodings/remove encodings without modifying the entire list and passing it in... that might be good if you planned to have hundreds or thousands of simulcasted streams inside the same sender/receiver, or rapid swap in/out of encodings. Otherwise it's a bit of overkill. This might be something an SFU might want in an API but not likely as a client API.

I do not like the codecs being inside the encoding. This removes the ability to route based on payload type alone. This removes the ability to dynamically create encodings for simulcasted streams. This also further means that a stream with a new SSRC that shows up cannot be decoded without first having a full definition of that SSRC with codec list since the codecs can only be interpreted in the context of the specific SSRC definition. That would remove a design goal that we had.

ibc commented 8 years ago

I will properly comment later, but for now:

I do not like the codecs being inside the encoding.

We should ask ourselves what a "encoding" means. AFAIK "encoding" means how the browser will encode a codec payload, which resolution properties, etc. And hence, each "encoding" has one codec. And hence having a complete codec object within the encoding is much better than having a cress-reference codecPayloadType.

What it makes no sense at all is the current design in which the "codec encoding" carries a SSRC value. That's a no sense.

robin-raymond commented 8 years ago

What it makes no sense at all is the current design in which the "codec encoding" carries a SSRC value. That's a no sense.

There's no such thing as a "codec encoding". There's a list of codecs that describes all the possible codecs and the assigned PT meaning. There's a list of encodings when you want to describe a particular single stream, stream+/-rtx+/-fec, simulcast, or layer. Yes, there's a lot it does but there's a lot of complexity in how RTP packets have to be routed, parsed, interpreted. If we were doing a fresh start RTP design things might be different, but we have a lot of RFCs to be compliant against.

As we've covered before, it is possible to have multiple codecs on a receiver where:

  1. The developer doesn't know which codec the remote party will ultimately choose to send (thus the PT value in the encoding is left intentionally unset);
  2. The developer is expecting a switching simulcast stream where one codec or the other might be used depending on the simulcast stream.

As for the sender, it too can have multiple codecs where:

  1. The developer has multiple simulcast streams, i.e. a list of encodings, with different codecs involved (thus a multiple list of codecs involved);
  2. As currently defined "feature" codecs require multiple codec definitions be required even if only one codec is used.

So in the simple case you need at minimal a list of one codec, and maybe one encoding. The encoding itself is optional and only needed if you intentionally need to fix certain values for matching on a receiver or sending.

As I said before, I don't like codecs being within the context of an encoding. When a packet arrives, it should be possible to interpret meaning based solely on the payload type if desired. Thus a receiver can dynamically create encodings based on the payloads that arrive. If you want different PT to have meaning based on the context of the SSRC or mux id then use a receiver with a fixed SSRC in an encoding (or a mux id to route the packet to the correct receiver, or both).

I don't see the major advantage to moving the codecs within the context of an encoding, and what I do see is the loss of ability to interpret media based on payload type (which is something possible in SDP) thus we remove capabilities if we went with that design.

Plus, objects in 1.0 and ORTC have been trying to keep in sync.

So to convince it would have to be:

  1. An advantage strong enough to convince 1.0 WG and ORTC CG to change to be in sync.
  2. Not remove the ability to route on PT alone, or,
  3. Convince people that routing on PT is not something needing to be supported.
ibc commented 8 years ago

Sorry for the late response.

There's a reason why we did send() as a single call with a lot of parameters at once, and that's because it needs to be a transaction - it's all or nothing not some or most.

Right. It makes sense. But do we also agree that this is so similar to setLocalDescription(blob)? By passing a so complex and error prune object to send() we open the door to so many implementation differences and issues. For example, let's assume that the rtpParameters.encodings looks as follows:

encodings: [
  {
    codecPayloadType: 101,
    ssrc: 1111,
    fec: {
      ssrc: 5555
    }    
  },
  {
    codecPayloadType: 102,
    ssrc: 1111,
    fec: {
      ssrc: 6666
    }    
  },
  {
    codecPayloadType: 103,
    ssrc: 1111
  }
]

NOTE: The spec does not state that such a encodings is wrong. It's wrong because we are setting two different SSRCs for FEC to protect the same media SSRC, and also telling that such a media SSRC does not have FEC.

I just don't believe that ORTC browsers will behave in the same way if the above abomination is given to them in send(). Also, if the spec mentioned all the constraints the RtpParameters must satisfy, that would take really so long in the text. That's why I'm trying to suggest a much more modular API and dictionaries.

The thing I may see as potentially valuable is the ability to add encodings/remove encodings without modifying the entire list and passing it in... that might be good if you planned to have hundreds or thousands of simulcasted streams inside the same sender/receiver, or rapid swap in/out of encodings.

A related issue is the fact that we don't have a getParameters() method in the RtpSender so the app is responsible of holding both RtpSender instances and their associated RtpParameters objects. This has been already discussed here and dismissed. I cannot understand the rationale of such a decision.

robin-raymond commented 8 years ago

@ibc I can sympathize.

Let me try to address some of your concerns:

  1. A lot of the objects the WebRTC 1.0 WG has already adopted, so we want to be compatible with what 1.0 is doing; diverging would "be bad";
  2. Parameters do need to be transactional, but I do agree, some use cases might want to tweak some things on a smaller scale; but that needs to be use case driven (like all API features);
  3. The ORTC API was meant to be a "minimal" low-level subset of supported stuff; there's nothing restricting anyone from expanding the API for their own implementations but this is the required set to be cross compatible; thus it was designed minimal so that higher level "simplifying" libraries can be written;
  4. I agree on the ambiguity issue (as illustrated by your SSRC comment); FYI - that looks legal to me but I get your concern about ambiguous cases; we should define these or put them "out of scope";

A related issue is the fact that we don't have a getParameters() method in the RtpSender so the app is responsible of holding both RtpSender instances and their associated RtpParameters objects. This has been already discussed here and dismissed. I cannot understand the rationale of such a decision.

Let me explain the logic. getParameters() as just returning what you put in originally set was deemed to add little value to justify expanding the "minimal" API set. Expanding getParameters() to return filled in SSRC was deemed not needed since programmer can specify those filled values if they care, or use auto routing via mux-id / rid. So that's how that decision came to be.

robin-raymond commented 8 years ago

The final summary for me is:

  1. Should the RtpSender add a getParameters() method to fetch the chosen SSRCs that were chosen by the engine (thus need to have a promise on send()`too.
  2. Should theRtpReceiveradd agetParameters() method to fetch discovered SSRCs as encodings are filled by the engine (thus we need an event to indicate when more information has been filled).

As responses (thus far):

  1. While there may be reasons for send() to return a promise (beyond SSRC choices), there's not a clear reason why it's "impossible" for app layer to chose SSRCs currently.
  2. This appears to be out of scope without a huge use case why it's needed at this time.

If there's something I'm not getting, please let me know, otherwise I too consider this a "won't fix". Again, bigger proposals should be their own issue which can explain / justify the reason for such a proposal. @ibc 's concern about ambiguities in how to properly fill out encodings are valid but are not the topic of this issue. Those kind of ambiguities should be filed as separate issues.

ibc commented 8 years ago

There's not a clear reason why it's "impossible" for app layer to chose SSRCs currently.

Currently it is perfectly possible for the app layer to choose all the SSRCs and generate a complete RtpParameters. The only requirement is that the app layer developers is a RTP expert (to know what he wants), a SDP expert (to understand which parameters to set) and a ORTC-low-level expert (to understand how to map those SDPish parameters into a big RtpParameters). This is 100% feasible with the current spec.

What is not expectable at all is that browser vendors will understand such a RtpParameters object in the same way. And given all the potential inconsistencies the RtpParameters allows (see my encodings above) I strongly expect that they will fail wretchedly when it comes to set SSRC for RTX and FEC.

Things are easy when there is a specific API for a specific task. But when we replace an API with an object everything can happen.

Said that, I want to make it clear that retrieving the sending SSRC once send() is called has no value (if the developer needs the SSRCs he probably needs them before sending media), so:

interface RTCRtpSender {
    Promise              setParameters (RTCRtpParameters parameters);
    RTCRtpParameters     getParameters ();
    void                 send ();
};
robin-raymond commented 8 years ago

I strongly expect that they will fail wretchedly when it comes to set SSRC for RTX and FEC.

Auto filling in the SSRC values by the engine and being able to fetch them by the higher level is a separate issue vs having a complete understanding of what ambiguities might exist in the way encodings can be filled. As I said, if there are ambiguities, please file separate issues for those and not confuse the two issues. If the system had the ability to return filled in SSRC values, that would not prevent someone from being able to set ambiguous configurations, so if they exist, you need to file issues specifically about those.

As I said before, the CG discussed this issue and they do not feel there's a reason why the SSRC values cannot be filled in by the higher level API when it matters (as opposed to auto-routing vs mux/rid). As such, the Promise result and getParameters() was not deemed worthy to implement as a required feature.

Again, I re-emphases, I do not see why its "impossible" for the higher level to pick those SSRC values. Yes, it requires expertise. This is a low level API. The whole thing requires expertise, but it's not "impossible".

murillo128 commented 8 years ago

https://www.w3.org/TR/2007/WD-html-design-principles-20071126/

In case of conflict, consider users over authors over implementors over specifiers over theoretical purity. In other words costs or difficulties to the user should be given more weight than costs to authors; which in turn should be given more weight than costs to implementors; which should be given more weight than costs to authors of the spec itself, which should be given more weight than those proposing changes for theoretical reasons alone. Of course, it is preferred to make things better for multiple constituencies at once.

robin-raymond commented 8 years ago

@murillo128 that is correct, which is why the surface of the API is kept down and needless additional APIs are not added. I can't help the fact that "how to define" encodings in a way to be compatible is complex by the nature of RTP and the required RFC specifications. I have to work with what the requirements are and we aren't designing a simply calling API for 1 or 2 scenarios; this is a flexible low level API to enable a variety of scenarios, including many many compatibility requirements plus matching or exceeding SDP can do...

As I said, the CG already voted on this... it was discussed and argued at length long ago. So far, nothing "new" has been brought to the table from previous arguments. FYI - I argued in favour of adding the Promise and getParameters(), but I lost. I would also suggest if you strongly disagree with that decision you bring it to the ortc-public list and try to convince those who voted previously that they were wrong and to reconsider rather than just filing an issue to the editor/authors. Then I can measure if there's will by those who already voted to reconsider. Otherwise, left as a github issue, I have to consider it "won't fix" as no new arguments have been brought forth which I can bring to the CG to get them to reconsider.

ibc commented 8 years ago

Basically the rationale here is:

The app layer should be able to set SSRC values and any other parameter if desired, so we don't need a getParameters().

And I agree: The app layer MUST be able to set all the desired low level parameters.

Now: does the current spec allow that?

Yes, because the app layer can create the desired RtpParameters with all the desired low level features.

This is well known, so why do I insist?

Because in the real world such a RtpParameters is so hard to process (given all the ambiguities and exotic combinations it allows including simulcast, SVC, etc) that there won't be two browsers behaving in the same way given the same RtpParameters object.

So, coming back to the original question: does the current spec allow setting low level params including SSRCs?

Theoretically yes. In practice no. And since refactoring the API seems not to be a feasible option I suggested an API that allows requesting the RtpSender what we want, retrieving the internally generated complete RtpParameters and sending media.

So I'm sorry, but both issues have a direct relationship. Or in other words: one exists because it seems that the other has no solution, and vice-versa.

ibc commented 8 years ago

Otherwise, left as a github issue, I have to consider it "won't fix" as no new arguments have been brought forth which I can bring to the CG to get them to reconsider.

I strongly think that new arguments have been given, but I won't complain about that. Taking our time to make a presentation (instead of reporting issues to the spec authors) and inviting all the WG to check it will be the way to go.

Thanks.

robin-raymond commented 8 years ago

does the current spec allow setting low level params including SSRCs?

Yes, the developer can specify SSRCs when they pass in encoding parameters. That is defined in the spec already. Thus they don't need to fetch SSRC if they are capable of setting them to fixed values (assuming they care).

Likewise the engine can auto-fill in the cases when the developer doesn't care what SSRCs must be used. In that case, what SSRC values the engine has chosen are not deemed important.

Routing by SSRC is NOT required for ORTC to work, which is why the developer doesn't always need or care to fill in those SSRC values, nor need to fetch them from what the engine filled. Mux/rid usage/assignment allow non pre-filled SSRC encodings to route just fine. If you care what SSRC values will be used, then pre-fill those values before calling send() thus you know those values. If you don't care and want to rely on other routing methods then don't fill them in advance and leave those unset.

I would further say, that when possible, avoid routing by SSRC. Use Mux-id and RID where possible. It's easier and less error prone.

Because in the real world such a RtpParameters is so hard to process

Again, the ability to set SSRCs and fetch then fetch them later is a separate issue from the difficulty for all implementations to interpret all the possible combinations of settings. If you are saying that the developer should NOT be allowed to set SSRC because that would lead to ambiguities then that's a different argument and a different issue. I would also disagree with that as being able to set SSRCs is needed for fixed routing scenarios.

I strongly think that new arguments have been given

It's possible I've missed something in your points, but I think I'm fully understanding them which is why I said that... this is another reason to bring to the public list rather than an issue. A wider audience might understand something I'm not getting. The original issues are auto-posted on ortc-public there but I don't believe the follow up comments are posted. The rest of the CG isn't necessarily reading the points you are trying to make.

Again, I cannot go against the previous decisions of the CG (even if personally I'm in favour of it); nor can I bring up old arguments (at least without new information). But you are welcome to try to convince others that the decision was wrong!

ibc commented 8 years ago

Yes, the developer can specify SSRCs when they pass in encoding parameters. That is defined in the spec already.

Fine.

Likewise the engine can auto-fill in the cases when the developer doesn't care what SSRCs must be used. In that case, what SSRC values the engine has chosen are not deemed important.

Agreed.

Routing by SSRC is NOT required for ORTC to work [...]

I don't want to move the discussion to the receiver side. Please understand that the receiver may be a WebRTC server or WebRTC browser so the ORTC sender may need to generate a full SDP in JS, and negotiate it before it calls send(). I hope we agree on this.

Again, the ability to set SSRCs and fetch then fetch them later is a separate issue from the difficulty for all implementations to interpret all the possible combinations of settings.

Right.

If you are saying that the developer should NOT be allowed to set SSRC because that would lead to ambiguities then that's a different argument and a different issue. I would also disagree with that as being able to set SSRCs is needed for fixed routing scenarios.

Don't go so far. Setting different SSRC values (even if we are not going to signal them) is required if the sender wants to send simulcast (1 RtpSender => 1 media codec, N encodings, N ssrcs).

I also hope we agree that in order to generate a SDP via JS we need to manually set SSRC values, and this is a MUST because ORTC must allow building a WebRTC shim on top of it.

So please, avoid mentioning "receiver RTP mathing rules" or "no need for SSRC signaling in common use cases" and let's agree on something very specific: The API must allow the user to set SSRC values. Do we agree?

Then, as you said, whether such a requirement is easy or not, given the ambiguities the RtpParameters object allows, is another subject. Let's invite the WG to discuss about that with a proposal (as you said).

Agreed?

robin-raymond commented 8 years ago

I don't want to move the discussion to the receiver side. Please understand that the receiver may be a WebRTC server or WebRTC browser so the ORTC sender may need to generate a full SDP in JS, and negotiate it before it calls send(). I hope we agree on this.

I am not debating that some scenarios require to know the SSRC, just like not all scenarios require an SSRC. The argument has always been that those scenarios which require to know the SSRC should fill in the values themselves.

Don't go so far. Setting different SSRC values (even if we are not going to signal them) is required if the sender wants to send simulcast (1 RtpSender => 1 media codec, N encodings, N ssrcs).

No, this statement is not correct. The SSRC value is not required to be pre-filled to do simulcast. Each encoding that does NOT have a dependency is simulcasted. N encodings (without a dependency) = N simulcasts.

The API must allow the user to set SSRC values. Do we agree?

That was never in dispute. The API has always allows the developer to choose their own SSRC values. Likewise, the SSRC values do NOT need to be pre-filled in scenarios where the developer need not care (as I illustrated when routing by mux id/rid).

What is in despite is when the engine chooses for the developer if the developer should then be able to fetch those chosen values. That was voted upon in the CG and rejected

given the ambiguities the RtpParameters object allows, is another subject.

As I said, file issues where ambiguities exist. The encoding example you listed above is not actually ambiguous (IMHO) but I would never go so far as to say you can't find ambiguous cases. If you file ambiguity issue, and we can deal with clarifying, or opening up bigger dialog if its not possible to clarify.

ibc commented 8 years ago

The SSRC value is not required to be pre-filled to do simulcast. Each encoding that does NOT have a dependency is simulcasted. N encodings (without a dependency) = N simulcasts.

Fine, but that also worries me. What happens if I set opus and CN in codecs and fill two encodings (one with codecPayloadType: OPUS_PT and the other with codecPayloadType: CN_PT) having both an unset ssrc? Note that those encodings don't have a "dependency" but they must be carried over the same SSRC (related to #470).

robin-raymond commented 8 years ago

What happens if I set opus and CN in codecs and fill two encodings (one with codecPayloadType: OPUS_PT and the other with codecPayloadType: CN_PT) having both an unset ssrc?

That's not legal. The CN is a magic "feature" codec like RTX and RED and ULPFEC at this point and cannot be used in codecPayloadType inside the encoding. I didn't cover CN as part of the whole "moving feature codecs as attributes of the original codec", but I think that's a likely candidate for that as well (but that's a separate issue).

ibc commented 8 years ago

Yep, handled in #472.