From 2fda5e9751d14a520a4d1d327a5d8e10dd67b097 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Fri, 28 Feb 2020 21:56:52 +0000 Subject: [PATCH] Bug 1600824 - Fix operations queue to run 1st operation synchronously. r=bwc Differential Revision: https://phabricator.services.mozilla.com/D55585 --HG-- extra : moz-landing-system : lando --- dom/media/PeerConnection.jsm | 29 ++- ...TCPeerConnection-operations.https.html.ini | 22 ++ .../RTCPeerConnection-operations.https.html | 211 ++++++++++++++++++ 3 files changed, 251 insertions(+), 11 deletions(-) create mode 100644 testing/web-platform/meta/webrtc/RTCPeerConnection-operations.https.html.ini create mode 100644 testing/web-platform/tests/webrtc/RTCPeerConnection-operations.https.html diff --git a/dom/media/PeerConnection.jsm b/dom/media/PeerConnection.jsm index d47cbfcdab56..8691a1dfa0ca 100644 --- a/dom/media/PeerConnection.jsm +++ b/dom/media/PeerConnection.jsm @@ -519,7 +519,7 @@ class RTCPeerConnection { this.makeGetterSetterEH("onidpvalidationerror"); this._pc = new this._win.PeerConnectionImpl(); - this._operationsChain = this._win.Promise.resolve(); + this._operations = 0; this.__DOM_IMPL__._innerObject = this; const observer = new this._win.PeerConnectionObserver(this.__DOM_IMPL__); @@ -586,20 +586,20 @@ class RTCPeerConnection { // Add a function to the internal operations chain. async _chain(func) { - let p = (async () => { - await this._operationsChain; - // Don't _checkClosed() inside the chain, because it throws, and spec - // behavior is to NOT reject outstanding promises on close. This is what - // happens most of the time anyways, as the c++ code stops calling us once - // closed, hanging the chain. However, c++ may already have queued tasks - // on us, so if we're one of those then sit back. + const p = (async () => { + if (this._operations++) { + await this._operationsChain; + } if (this._closed) { return null; } return func(); })(); // don't propagate errors in the operations chain (this is a fork of p). - this._operationsChain = p.catch(() => {}); + this._operationsChain = p.then( + () => this._operations--, + () => this._operations-- + ); return p; } @@ -1085,12 +1085,18 @@ class RTCPeerConnection { this._sanityCheckSdp(action, type, sdp); return this._chain(async () => { - await this._getPermission(); + // Avoid Promise.all ahead of synchronous part of spec algorithm, since it + // defers. NOTE: The spec says to return an already-rejected promise in + // some cases, which is difficult to achieve in practice from JS (would + // require avoiding await and then() entirely), but we want to come as + // close as we reasonably can. + const p = this._getPermission(); await new Promise((resolve, reject) => { this._onSetDescriptionSuccess = resolve; this._onSetDescriptionFailure = reject; this._impl.setLocalDescription(action, sdp); }); + await p; this._negotiationNeeded = false; if (type == "answer") { if (this._localUfragsToReplace.size > 0) { @@ -1178,7 +1184,6 @@ class RTCPeerConnection { return this._chain(async () => { const haveSetRemote = (async () => { - await this._getPermission(); if (type == "offer" && this.signalingState == "have-local-offer") { await new Promise((resolve, reject) => { this._onSetDescriptionSuccess = resolve; @@ -1193,11 +1198,13 @@ class RTCPeerConnection { this._transceivers = this._transceivers.filter(t => !t.shouldRemove); this._updateCanTrickle(); } + const p = this._getPermission(); await new Promise((resolve, reject) => { this._onSetDescriptionSuccess = resolve; this._onSetDescriptionFailure = reject; this._impl.setRemoteDescription(action, sdp); }); + await p; this._processTrackAdditionsAndRemovals(); this._fireLegacyAddStreamEvents(); this._transceivers = this._transceivers.filter(t => !t.shouldRemove); diff --git a/testing/web-platform/meta/webrtc/RTCPeerConnection-operations.https.html.ini b/testing/web-platform/meta/webrtc/RTCPeerConnection-operations.https.html.ini new file mode 100644 index 000000000000..5ba5934415e5 --- /dev/null +++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-operations.https.html.ini @@ -0,0 +1,22 @@ +[RTCPeerConnection-operations.https.html] + [SLD(offer) must validate against LastCreatedOffer early (prerequisite)] + expected: FAIL + + [setLocalDescription uses operations chain] + expected: FAIL + + [addIceCandidate uses operations chain] + expected: FAIL + + [setRemoteDescription uses operations chain] + expected: FAIL + + [SLD(offer) must validate input before signaling state (prerequisite)] + expected: FAIL + + [createAnswer uses operations chain] + expected: FAIL + + [createOffer uses operations chain] + expected: FAIL + diff --git a/testing/web-platform/tests/webrtc/RTCPeerConnection-operations.https.html b/testing/web-platform/tests/webrtc/RTCPeerConnection-operations.https.html new file mode 100644 index 000000000000..e88c8b28172c --- /dev/null +++ b/testing/web-platform/tests/webrtc/RTCPeerConnection-operations.https.html @@ -0,0 +1,211 @@ + + + + + +