W3C

- DRAFT -

WebRTC Virtual Interim

02 Jul 2019

Agenda

Attendees

Present
Bernard, Jan-Ivar, Harald, Henrik, Lennart_Schulte, Marten, Pallab_Gain, Patrick_Rockhill, Karthik, Dom, Lennart_Grahl, Carine, Alexandre_Gouaillard
Regrets
Chair
jib, harald, bernard
Scribe
dom

Contents


<scribe> ScribeNick: dom

Intro to Perfect Negotiation

Jan-Ivar: a number of issues are related to a unique problem that I want to introduce
... what if we could add/remove media without worrying about state, glare, role or condition
... perfect handling includes handling glare with rollback
... (only Firefox has rollback at the moment)

Perfect negotiation in WebRTC

scribe: Perfect negotiation works in Firefox but shows issues on our API
... [slide: Permise: Perfect negotiation]
... [slide: Premise: Perfect negotiation 2]

A simpler glare-proof setLocalDescription() #2165

A simpler non-racy rollback #2166

{iceRestart: true} works poorly with negotiationneeded #2167

Spec steps on stop() underestimate BUNDLE problem. #2176

transceiver.stop() needs more work (avoid BUNDLE footgun) #2150

jib: today, calling stop on the offerer side works well
... now, when the answerer calls tc1.stop() there is a problem, even in stable state
... JSEP and BUNDLE don't give affordance to stop only one of the transceivers
... it stops all transceivers
... it also creates a racy behavior that breaks the abstraction
... we can't fix JSEP and BUNDLE at this stage
... it's even worse than we thought since it affects the stable state as well - you don't know in stable what comes next (SRD vs SLD)
... the problem is that there is only one synchronous stopped state
... the solution we came up with is a safer stop() method that works only in createOffer, and a reject() method that only works in have-local-offer
... JSEP doesn't foresee that approach
... Do we really need stop, though?
... addTrack and removeTrack were used together as participants join/leave in Plan B
... but in Unified Plan, this accumulates resources - transceiver are set as inactive, not ended
... the API is complicated due to having both tracks and transceivers
... and transceivers need to be stopped explicitly - can't be done automatically by the browser
... we had looked at a workaround using a dummy transceiver - but that creates a separate footgun when using addTrack

Henrik: also has backwards compat issues

jib: also if done on both sides, this would waste m-lines and create confusion
... so we want people to use stop(), but not having to think about it
... Add reject() + make stop() safe. New stopping state affects createOffer only. #2220

Add reject() + make stop() safe. New stopping state affects createOffer only. #2220

jib: PR 2220 address this with a new reject method, a new stopping attribute
... we trick JSEP in doing the right thing
... stopping still stops sending and receiving locally
... stop() for remote
... stopping is the synchronous local part
... and the rest is done asynchronously with negotiation
... this also sidesteps the whole bundle problem
... the reject() method sets both stopping (local) and stopped (remote)
... reject() throw an error when not in have-remove-offer, which is safer

henrik: there is such a thing as stopping before you are fully stopped - there may be discussion about how to expose it in the API, but the states exist

bernard: is stop() being used?

jib: it's not in Chrome, so few people are using it
... we do need stop()

bernard: but do we need reject()?

henrik: I agree reject() may not be as needed

jib: the PR looks at splitting the states - we can then talk about the reject() method is needed
... [PR 2220: stopping solution to BUNDLE problem illustrated (1/2)]
... when stopping is set, JSEP ignores it and negotiation happens with tc1 not being stopping or stopped
... but its receiver track has ended through RTCP signaling
... [PR 2220: stopping solution to BUNDLE problem illustrated (2/2)]
... when tc1 is stopped, JSEP gets into play
... [PR 2220: stopping solution in simple case illustrated (1/1)]
... still works in the simpler case (stop on offerer side)
... [PR 2220: stop() sets new tc.stopping, affecting createOffer only]
... [text from PR 2220]
... the important piece is that stopping-but-not-stopped transceiver needs negotiation

henrik: does it matter if we don't reach stopped?

jib: we don't free resources until we get to stopped
... most of the negotiation needed is orthogonal to the stopped state

henrik: the transceiver object still exists, but the expensive stuff (encoding, decoding) is gone
... only the transport is left, but it is bundled anyway

jib: fair enough
... resources could already be cleaned up under the hood indeed
... we mention specifically that stopping-but-not-stopped transceiver doesn't affect createAnswer, to trick JSEP
... there is a note about the risks of using reject()

henrik: reject() doesn't remove the bundle footgun

jib: it's a bit safer since the method throw an exception if in the wrong state
... it's only in rollback that you can get into trouble

henrik: the different between stopping and rejecting is that when you're stopping, you're waiting for an answer with an ack from the other side
... if you reject, you're sending the fact that you're stopping but without ack
... this creates an additional risk of glare
... you get rid of a O/A exchange, but there is only limited benefit beyond that
... and this makes the API more complex, with a footgun
... doesn't feel like an API I can imagine advise using

jib: my goal was to reduce the number of ennemies - not removing functionality
... reject() reflects the current API feature
... I didn't want to assume nobody still needs that particular feature

henrik: I'm fine with having this discussion separately
... to me, the key thing is the distinction between stopping and stopped

jib: these states are needed, at least as internal slots not matter what since it affects other algorithms

bernard: can we get consensus on the stopping addition, and then on reject?
... any objection to the addition of stopping?

[silence]

RESOLUTION: consensus to add stopping state to the transceiver API

Bernard: what about reject()?

Henrik: I have an issue with it

Bernard: so do I

harald: removing it kind of violates the assumption that any SDP state machine action can be accomplished
... but it has always been a weak assumption
... I won't fight for it - would happy to not have it

Henrik: to me, SDP is a tool for our API - not everything that can be done in SDP needs to be exposed in the API, esp if it's a footgun

jib: Mozilla is also happy to lose reject()
... would like to check with Cullen

Henrik: reject() is mostly an optimization to skip a O/A
... also, does reject() interfere with rollback?

jib: no, neither stop nor reject can be rolled back
... but there is a footgun if rejecting after a rollback

bernard: so I think we should merge stopping, and keep the reject() piece separate and seek whether there is consensus to bring it in

jib: I think I'm too in favor of removing it too

dom: what about implementation plans/

s_/_?

jib: Firefox will implement this - I have buy-in from the developer, and it shouldn't be hard to do, so soon

henrik: I want this to be implemented but can't commit for the short term

bernard: we do care about a bunch of these things; I want to wait until we hear all the proposed changes before making commitments
... we care about cleaning things about rollback

henrik: I feel perfect negotiation is a key part to completing WebRTC

{iceRestart: true} works poorly with ONN

{iceRestart: true} works poorly with negotiationneeded #2167

Add pc.restartIce() method. #2169

jib: the proposal is to add a pc.restartIce() method that fires onnegotiationneeded
... it is implemented behind a pref in Firefox
... (only took a day or two implement in Firefox)

henrik: if you're already implementing ice restart, adding that method should indeed be quick

jib: most of the work was writing the tests indeed

henrik: I think we should do this - it is simple and avoid problems

bernard: any object to adopting 2169?

RESOLUTION: consensus to add restartIce method per PR 2169

Race issues 2165 2166 2167

A simpler glare-proof setLocalDescription() #2165

A simpler non-racy rollback #2166

{iceRestart: true} works poorly with negotiationneeded #2167

jib: the problem here is how to deal with rollback when avoiding glare
... the issue is what happens when an ice candidate arrives at the wrong time; we have an operations queue that helps here, but this requires Promise.all to queue operations in the right order, which isn't intuitive and is unlikely to happen
... the proposed approach is to use an option to SRD for rollback instead of considering as a separate type

henrik: only Firefox has implemented rollback; if one is to start from scratch, any reason to implement rollback in SLD?

jib: deprecating that would make sense to me
... but that's removing a feature again
... although rollback is at risk in any case
... an alternative would be to always do the rollback dance implicitly (assuming rollback true always)

harald: it would change the behavior of SRD by making it accept descriptions it would have rejected before

jib: right

henrik: the breaking change is implicit rollback hides a possible mistake
... that doesn't sound bad to me - implicit would work for me, although I could go with explicit as well

jib: the issue with implicit is that rollback is not necessarily obvious to manage, leading the JS to a weird state

bernard: any preference on proposal A (explicit) vs B (implicit)?

harald: slight preference for implicit, but won't die on that hill

bernard: anyone prefers A over B?

[silence]

bernard: sounds like a marginal preference for B

jib: the only downside is that it's less explicit
... in any case, I'm not hearing push back against doing something to that effect (A or B)

henrik: the advantage of B is that it simplifies the usage of the API - makes it harder to mis-use it

bernard: but it makes rollback an essential feature of SRD

henrik: indeed, it makes not supporting rollback create interop issues
... so rollback is implemented, B sounds better

dom: what about implementation plans for rollback?

bernard: microsoft is ready to allocate resources to implement this - not sure how long it will take, it's complex

jib: wpt tests are pretty thorough on rollbacks

henrik: great to hear resources coming from microsoft on this

bernard: it will be a priority, but not sure about schedule

henrik: will be happy to code-review

jib: pranswer is not implemented in Firefox, so not sure about interferences with rollback
... may be useful to consider keeping rollback and pranswer uncoupled

bernard: I think this will increase the chance of getting rollback done
... rollback is already marked at risk - this increases the motivation of doing it
... so how about going with proposal B?

RESOLUTION: we add implict rollback to SRD per Proposal B (with updated PR2212)

harald: this can be feature-detected too

ISSUE 2165

jib: onnegotiationneeded appears to be racy and glare-prone from our earlier "polite peer" exercise
... again, the current API can be made to avoid this issue, but is unlikely to be used correctly
... two proposals: implict call createOffer/createAnswer if no sdp given to SLD
... or automatically set the right type based on signaling state
... the SDP argument passed to SLD is in fact unused today
... both proposals are 100% backwards compatible, and SRD wouldn't be affected

henrik: I like this
... now that SDP munging prohibited, the split between createO/A and SL/RD is artificial, and making them race-free sounds good
... between A or B, I prefer type to be explicit - otherwise makes it harder to debug, so prefer A

bernard: anyone prefers B over A?

jib: I prefer B over A because it's a nicer API
... we can infer from the state what is being asked

harald: you have to do a state switch in any case to send it conditionally

henrik: also could lead to errors in assumptions of current state

jib: the assumption is already that the JS has to know the state it is in before calling this

bernard: it's not that you never have to provide a type - you can skip providing it (in proposal B)

henrik: so in B, if you do provide a type, you can still get an error?

jib: yes

henrik: then I'm fine with that

RESOLUTION: adopt proposal B in glare-proof SLD

Negotiation methods are vestigial, racy with a pushy SFU. #2221

Negotiation methods are vestigial, racy with a pushy SFU. #2221

jib: a problem spotted by fippo with "push" SFUs that keep pushying offers
... the strategy to deal with this still needs to use Promise.all
... there is a proposal here to fix this with a combined setRemoveAndLocalDescriptions

harald: there is another strategy: you process incoming messages as they come in
... that's why we allow SRD in have-remove-offer state
... if you want to do FIFO, you use Promise.all
... if you want to do LIFO, you don't need it

jib: you could also rollback
... what I wanted to solve is avoiding signaling states collision
... this shows that our negotiation methods were built for another time

henrik: yes, a lot of these 4 steps should really just be 2 steps
... in that sense, combining them is good idea - would also be easy to implement
... one argument against this is about pushy SFUs
... if we implement perfect negotiation, I don't think we would have a pushy peer

bernard: the case I typicall see, the conference unit is the one making the offer
... when people keep coming in, it needs to keep sending offers
... so that situation happens a lot

henrik: my point was that if perfect negotiation is framed in terms of p2p, and that an SFU does something out of this context, then it's the responsibility of the SFU to take care of Promise.all
... but I can see the value of dealing easily with pushy SFUs

harald: it feels like an optimization that forces a specific type of negotiation
... it feels wrong to munge so much into one thing

henrik: feels not very high value (but also not very hard to implement)
... the other things presented earlier felt more important

harald: with a pushy SFU, you need to pick a FIFO or LIFO strategy - I don't think the API should force one approach or not

jib: the main issue is that it's easy to do it wrong
... although it gets exposed as invalidstateerror, so it can be detected

henrik: my main point is that the SFU use case targets a different type of developers than a typical P2P connection

jib: a peer could act as a pushy peer with rollback

henrik: can a pushy peer exist with perfect negotiation?

bernard: I don't think so

henrik: if perfect negotiation has that problem, I would agree with adding the API to avoid races
... but if not in the context of perfect negotiation, feels like a nice to have, not essential

bernard: right - it's an edge case

dom: if only nice to have, would prefer not to have it in 1.0

harald: would also prefer not having this in

RESOLUTION: no consensus to add setRemoteAndLocalDescriptions

Tweaking Jan-Ivar’s stop() - if time allows (2/2)

henrik: we agreed that tc.stopping is a good idea and not have reject()
... you rarely care about stopping vs stopped
... the only reason we deal with this is to avoid the BUNDLE footgun
... do we really need this amount of granularity?
... can this be exposed with fewer API changes?
... my proposal is to treat stopping as a "stopped" direction
... then the difference is between stopped and stopping is then visible by looking at direction vs currentDirection
... we can even remove the stop() method if so (could set the attribute instead)
... the only limitation is that you can no longer checker the direction when stopping
... but once you're stopping, the direction doesn't really matter at that point
... it makes the API a bit cleaner and hides the complexity some more

jib: I don't think I like this - 3 problems with it
... direction has matched JSEP / SDP for a long time, and this breaks this
... worry about the edge case about when you're locally stopped and the other side doesn't know yet, directions may change

henrik: I'm not suggestion we change the [[Direction]] internal slot, but the attribute only would reflect a different value
... once it's stopping, it's not sending or receiving - the direction no longer matters

jib: I'm not sure I understand when that is set - when stopping or stopped?

henrik: t.direction= "stopped" is stopping, t.currentDirection = "stopped" is stopped

jib: think I like the old API better

harald: I like the stop() method - it's more explicit

henrik: fine with the stop() method, but would use direction to keep track of the state

jib: but JSEP defines stopped, we can't remove it

harald: I like the proposal (having seen it an hour ago)

bernard: can't record a consensus at the moment

Summary of Action Items

Summary of Resolutions

  1. consensus to add stopping state to the transceiver API
  2. consensus to add restartIce method per PR 2169
  3. we add implict rollback to SRD per Proposal B (with updated PR2212)
  4. adopt proposal B in glare-proof SLD
  5. no consensus to add setRemoteAndLocalDescriptions
[End of minutes]

Minutes manually created (not a transcript), formatted by David Booth's scribe.perl version 1.154 (CVS log)
$Date: 2019/07/02 16:40:55 $

Scribe.perl diagnostic output

[Delete this section before finalizing the minutes.]
This is scribe.perl Revision: 1.154  of Date: 2018/09/25 16:35:56  
Check for newer version at http://dev.w3.org/cvsweb/~checkout~/2002/scribe/

Guessing input format: Irssi_ISO8601_Log_Text_Format (score 1.00)

Succeeded: s/stop()/stopping/
Succeeded: s/reject()/stop()/
Succeeded: s/push/pushy/
Present: Bernard Jan-Ivar Harald Henrik Lennart_Schulte Marten Pallab_Gain Patrick_Rockhill Karthik Dom Lennart_Grahl Carine Alexandre_Gouaillard
Found ScribeNick: dom
Inferring Scribes: dom
Agenda: https://www.w3.org/2011/04/webrtc/wiki/July_2_2019

WARNING: No date found!  Assuming today.  (Hint: Specify
the W3C IRC log URL, and the date will be determined from that.)
Or specify the date like this:
<dbooth> Date: 12 Sep 2002

People with action items: 

WARNING: IRC log location not specified!  (You can ignore this 
warning if you do not want the generated minutes to contain 
a link to the original IRC log.)


[End of scribe.perl diagnostic output]