WebRTC “perfect negotiation” issues

时光毁灭记忆、已成空白 提交于 2020-06-28 03:59:13

问题


I have been trying to implement WebRTC "perfect negotiation" as explained in this blog post. Unfortunately, I'm very often triggering errors on the polite side of the conversation (in the following linked code, this is the last peer to join).

The two most frequent errors are InvalidStateError: Cannot rollback local description in stable caused by this line and ONN DOMException: "Cannot set local offer in state have-remote-offer" triggered here and caused by this line. That second error is quite inexplicable to me since the line before checks that we should be in stable state and it is the first async call following that.

If you want to try it for yourself, my code is hosted on GitHub. It can be deployed directly on Heroku:

heroku create
git push heroku master

or can be tested locally with a self-signed certificate by changing lines 1, 7-10 and 15 of server.js.

I have had those issues when testing with desktop Firefox at versions 76, 73, desktop Chromium 80 and their up-to-date mobile versions on Android. Any help on this would be very much appreciated. And I'd love to also have this reliably working on iPads (Safari >= 11) which I can't personally test.


回答1:


TL;DR: Browser bugs fixed in Firefox 77 & the spec, as well as a separate bug in Chrome.

ONN DOMException: "Cannot set local offer in state have-remote-offer" ... That second error is quite inexplicable to me since the line before checks that we should be in stable state and it is the first async call following that.

WebRTC negotiation code has the tricky task of translating synchronous signaling messages into asynchronous operations on the RTCPeerConnection object. To ensure order, these asynchronous methods are chained internally, so only one runs at a time, because state machine.

Under signaling stress, it's possible for this internal chain to fill up, which complicates things, because methods you invoke end up running later, not immediately in the state you just observed synchronously.

The "second error" happened because the browser erroneously fired the negotiationneeded event while the RTCPeerConnection object's internal operations chain was non-empty. The spec has now been fixed so this won't happen.

Since the browser controls when the negotiationneeded event is fired, this takes care of it.

InvalidStateError: Cannot rollback local description in stable

The "first error" on the impolite side is similarly a symptom of an overloaded chain: synchronous state check that we're NOT in stable, followed by this:

if (offerCollision) { // pc.signalingState != "stable"
  await Promise.all([
    pc.setLocalDescription({ type: "rollback" }),
    pc.setRemoteDescription(description),
  ]);
}

I suspect other negotiation methods are on the chain at this time that take us back to "stable" before this setLocalDescription rollback gets to run.

To solve this, the spec added implicit rollback, so you can replace the above with:

await pc.setRemoteDescription(description); // implicit rollback only if needed

This works better because the decision of whether rollback is needed or not is made inside the chained method, looking at the correct signaling state at that (potentially later) time.

This unfortunately is not that easy to polyfill. You might attempt something like:

if (offerCollision) { // pc.signalingState != "stable"
  await Promise.all([
    pc.setLocalDescription({type: "rollback"}).catch(() => {}), // ignore failure
    pc.setRemoteDescription(description),
  ]);
}

Or wait for browsers to implement implicit rollback.



来源:https://stackoverflow.com/questions/61956693/webrtc-perfect-negotiation-issues

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!