Bug 1378123 - Make inner window track whether there is an active PeerConnection. draft
authorHenri Sivonen <hsivonen@hsivonen.fi>
Fri, 04 Aug 2017 14:41:03 +0300
changeset 621125 15b8bf9702325702c5f8fb2de44781866c3e2353
parent 621124 7cc822673be9aa045a53452dec595d8d3b49eec6
child 640913 299b15ee6a0f93db238c0e74e0d5b1d36e1686f4
push id72274
push userbmo:hsivonen@hsivonen.fi
push dateFri, 04 Aug 2017 11:41:26 +0000
bugs1378123
milestone57.0a1
Bug 1378123 - Make inner window track whether there is an active PeerConnection. MozReview-Commit-ID: 98Hwhnxtt1T
dom/base/TimeoutManager.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsPIDOMWindow.h
dom/media/PeerConnection.js
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -15,20 +15,16 @@
 #include "nsITimeoutHandler.h"
 #include "mozilla/dom/TabGroup.h"
 #include "OrderedTimeoutIterator.h"
 #include "TimeoutExecutor.h"
 #include "TimeoutBudgetManager.h"
 #include "mozilla/net/WebSocketEventService.h"
 #include "mozilla/MediaManager.h"
 
-#ifdef MOZ_WEBRTC
-#include "IPeerConnection.h"
-#endif // MOZ_WEBRTC
-
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static LazyLogModule gLog("Timeout");
 
 static int32_t              gRunningTimeoutDepth       = 0;
 
 // The default shortest interval/timeout we permit
@@ -1238,36 +1234,21 @@ TimeoutManager::BudgetThrottlingEnabled(
   }
 
   // Check if we have active GetUserMedia
   if (MediaManager::Exists() &&
       MediaManager::Get()->IsWindowStillActive(mWindow.WindowID())) {
     return false;
   }
 
-  bool active = false;
-#if 0
-  // Check if we have active PeerConnections This doesn't actually
-  // work, since we sometimes call IsActive from Resume, which in turn
-  // is sometimes called from nsGlobalWindow::LeaveModalState. The
-  // problem here is that LeaveModalState can be called with pending
-  // exeptions on the js context, and the following call to
-  // HasActivePeerConnection is a JS call, which will assert on that
-  // exception. Also, calling JS is expensive so we should try to fix
-  // this in some other way.
-  nsCOMPtr<IPeerConnectionManager> pcManager =
-    do_GetService(IPEERCONNECTION_MANAGER_CONTRACTID);
-
-  if (pcManager && NS_SUCCEEDED(pcManager->HasActivePeerConnection(
-                     mWindow.WindowID(), &active)) &&
-      active) {
+  if (mWindow.AsInner()->HasActivePeerConnections()) {
     return false;
   }
-#endif // MOZ_WEBRTC
 
+  bool active;
   // Check if we have web sockets
   RefPtr<WebSocketEventService> eventService = WebSocketEventService::Get();
   if (eventService &&
       NS_SUCCEEDED(eventService->HasListenerFor(mWindow.WindowID(), &active)) &&
       active) {
     return false;
   }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4438,16 +4438,22 @@ nsPIDOMWindowInner::AddPeerConnection()
 
 void
 nsPIDOMWindowInner::RemovePeerConnection()
 {
   nsGlobalWindow::Cast(this)->RemovePeerConnection();
 }
 
 bool
+nsPIDOMWindowInner::HasActivePeerConnections()
+{
+  return nsGlobalWindow::Cast(this)->HasActivePeerConnections();
+}
+
+bool
 nsPIDOMWindowInner::IsPlayingAudio()
 {
   for (uint32_t i = 0; i < mAudioContexts.Length(); i++) {
     if (mAudioContexts[i]->IsRunning()) {
       return true;
     }
   }
   RefPtr<AudioChannelService> acs = AudioChannelService::Get();
@@ -12794,26 +12800,34 @@ void
 nsGlobalWindow::AddPeerConnection()
 {
   MOZ_ASSERT(IsInnerWindow());
   MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
   mActivePeerConnections++;
 }
 
 void
-nsGlobalWindow::AddPeerConnection()
+nsGlobalWindow::RemovePeerConnection()
 {
   MOZ_ASSERT(IsInnerWindow());
   MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
   if (!mActivePeerConnections) {
     return;
   }
   mActivePeerConnections--;
 }
 
+bool
+nsGlobalWindow::HasActivePeerConnections()
+{
+  MOZ_ASSERT(IsInnerWindow());
+  MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
+  return mActivePeerConnections;
+}
+
 template<typename Method>
 void
 nsGlobalWindow::CallOnChildren(Method aMethod)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(IsInnerWindow());
   MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -402,16 +402,17 @@ public:
   void Resume();
   virtual bool IsSuspended() const override;
   void Freeze();
   void Thaw();
   virtual bool IsFrozen() const override;
   void SyncStateFromParentWindow();
   void AddPeerConnection();
   void RemovePeerConnection();
+  bool HasActivePeerConnections();
 
   virtual nsresult FireDelayedDOMEvents() override;
 
   // Outer windows only.
   virtual bool WouldReuseInnerWindow(nsIDocument* aNewDocument) override;
 
   virtual void SetDocShell(nsIDocShell* aDocShell) override;
   virtual void DetachFromDocShell() override;
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -922,16 +922,21 @@ public:
    */
   void AddPeerConnection();
 
   /**
    * Decrement active peer connection count.
    */
   void RemovePeerConnection();
 
+  /**
+   * Check whether the active peer connection count is non-zero.
+   */
+  bool HasActivePeerConnections();
+
   bool IsPlayingAudio();
 
   bool IsDocumentLoaded() const;
 
   mozilla::dom::TimeoutManager& TimeoutManager();
 
   bool IsRunningTimeout();
 
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -373,18 +373,18 @@ class RTCPeerConnection {
   this._onGetStatsIsLegacy = false;
   }
 
   init(win) {
     this._win = win;
   }
 
   __init(rtcConfig) {
-    this._winID = this._win.QueryInterface(Ci.nsIInterfaceRequestor)
-    .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
+    let winUtil = this._win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+    this._winID = winUtil.currentInnerWindowID;
     // TODO: Update this code once we support pc.setConfiguration, to track
     // setting from content independently from pref (Bug 1181768).
     if (rtcConfig.iceTransportPolicy == "all" &&
         Services.prefs.getBoolPref("media.peerconnection.ice.relay_only")) {
       rtcConfig.iceTransportPolicy = "relay";
     }
     this._config = Object.assign({}, rtcConfig);
 
@@ -447,16 +447,17 @@ class RTCPeerConnection {
                       "See http://w3c.github.io/webrtc-pc/#getstats-example for usage.") };
 
     this._warnDeprecatedStatsCallbacksNullable = { warn: () =>
       this.logWarning("Callback-based pc.getStats is deprecated, and will be removed in the near future! Use promise-version! " +
                       "See http://w3c.github.io/webrtc-pc/#getstats-example for usage.") };
 
     // Add a reference to the PeerConnection to global list (before init).
     _globalPCList.addPC(this);
+    winUtil.addPeerConnection();
 
     this._impl.initialize(this._observer, this._win, rtcConfig,
                           Services.tm.currentThread);
 
     this._certificateReady = this._initCertificate(rtcConfig.certificates);
     this._initIdp();
     _globalPCList.notifyLifecycleObservers(this, "initialized");
   }
@@ -1135,16 +1136,23 @@ class RTCPeerConnection {
     return this._impl.getParameters(track);
   }
 
   close() {
     if (this._closed) {
       return;
     }
     this._closed = true;
+    try {
+      let winUtil = this._win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+      winUtil.removePeerConnection();
+    } catch (e) {
+      this.logWarning(
+          "Could not inform window object of peer connection getting closed.");
+    }
     this._inClose = true;
     this.changeIceConnectionState("closed");
     this._localIdp.close();
     this._remoteIdp.close();
     this._impl.close();
     this._inClose = false;
   }