Bug 1109087 - Handle WebRTC indicators' states across multiple processes. r=florian
authorFelipe Gomes <felipc@gmail.com>
Wed, 12 Aug 2015 16:50:55 -0300
changeset 284883 b6de7762bd17869f5e9d8d5fa1cce0f1194796e7
parent 284882 ff2c8e408a9dfff4601735c9b3019f0606c91107
child 284884 7ac5ef42b07a28d6a25a1eece7f0be113a9196fa
push id4363
push usergijskruitbosch@gmail.com
push dateThu, 13 Aug 2015 15:59:24 +0000
reviewersflorian
bugs1109087
milestone43.0a1
Bug 1109087 - Handle WebRTC indicators' states across multiple processes. r=florian
browser/modules/ContentWebRTC.jsm
browser/modules/webrtcUI.jsm
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -21,16 +21,27 @@ this.ContentWebRTC = {
     if (this._initialized)
       return;
 
     this._initialized = true;
     Services.obs.addObserver(handleGUMRequest, "getUserMedia:request", false);
     Services.obs.addObserver(handlePCRequest, "PeerConnection:request", false);
     Services.obs.addObserver(updateIndicators, "recording-device-events", false);
     Services.obs.addObserver(removeBrowserSpecificIndicator, "recording-window-ended", false);
+
+    if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT)
+      Services.obs.addObserver(processShutdown, "content-child-shutdown", false);
+  },
+
+  uninit: function() {
+    Services.obs.removeObserver(handleRequest, "getUserMedia:request");
+    Services.obs.removeObserver(updateIndicators, "recording-device-events");
+    Services.obs.removeObserver(removeBrowserSpecificIndicator, "recording-window-ended");
+    Services.obs.removeObserver(processShutdown, "content-child-shutdown");
+    this._initialized = false;
   },
 
   // Called only for 'unload' to remove pending gUM prompts in reloaded frames.
   handleEvent: function(aEvent) {
     let contentWindow = aEvent.target.defaultView;
     let mm = getMessageManagerForWindow(contentWindow);
     for (let key of contentWindow.pendingGetUserMediaRequests.keys()) {
       mm.sendAsyncMessage("webrtc:CancelRequest", key);
@@ -311,8 +322,12 @@ function getMessageManagerForWindow(aCon
                          .QueryInterface(Ci.nsIInterfaceRequestor);
   try {
     // If e10s is disabled, this throws NS_NOINTERFACE for closed tabs.
     return ir.getInterface(Ci.nsIContentFrameMessageManager);
   } catch(e if e.result == Cr.NS_NOINTERFACE) {
     return null;
   }
 }
+
+function processShutdown() {
+  ContentWebRTC.uninit();
+}
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -21,16 +21,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 this.webrtcUI = {
   init: function () {
     Services.obs.addObserver(maybeAddMenuIndicator, "browser-delayed-startup-finished", false);
 
     let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
                  .getService(Ci.nsIMessageBroadcaster);
     ppmm.addMessageListener("webrtc:UpdatingIndicators", this);
     ppmm.addMessageListener("webrtc:UpdateGlobalIndicators", this);
+    ppmm.addMessageListener("child-process-shutdown", this);
 
     let mm = Cc["@mozilla.org/globalmessagemanager;1"]
                .getService(Ci.nsIMessageListenerManager);
     mm.addMessageListener("rtcpeer:Request", this);
     mm.addMessageListener("rtcpeer:CancelRequest", this);
     mm.addMessageListener("webrtc:Request", this);
     mm.addMessageListener("webrtc:CancelRequest", this);
     mm.addMessageListener("webrtc:UpdateBrowserIndicators", this);
@@ -48,20 +49,57 @@ this.webrtcUI = {
                .getService(Ci.nsIMessageListenerManager);
     mm.removeMessageListener("rtcpeer:Request", this);
     mm.removeMessageListener("rtcpeer:CancelRequest", this);
     mm.removeMessageListener("webrtc:Request", this);
     mm.removeMessageListener("webrtc:CancelRequest", this);
     mm.removeMessageListener("webrtc:UpdateBrowserIndicators", this);
   },
 
-  showGlobalIndicator: false,
-  showCameraIndicator: false,
-  showMicrophoneIndicator: false,
-  showScreenSharingIndicator: "", // either "Application", "Screen", "Window" or "Browser"
+  processIndicators: new Map(),
+
+  get showGlobalIndicator() {
+    for (let [, indicators] of this.processIndicators) {
+      if (indicators.showGlobalIndicator)
+        return true;
+    }
+    return false;
+  },
+
+  get showCameraIndicator() {
+    for (let [, indicators] of this.processIndicators) {
+      if (indicators.showCameraIndicator)
+        return true;
+    }
+    return false;
+  },
+
+  get showMicrophoneIndicator() {
+    for (let [, indicators] of this.processIndicators) {
+      if (indicators.showMicrophoneIndicator)
+        return true;
+    }
+    return false;
+  },
+
+  get showScreenSharingIndicator() {
+    let list = [""];
+    for (let [, indicators] of this.processIndicators) {
+      if (indicators.showScreenSharingIndicator)
+        list.push(indicators.showScreenSharingIndicator);
+    }
+
+    let precedence =
+      ["Screen", "Window", "Application", "Browser", ""];
+
+    list.sort((a, b) => { return precedence.indexOf(a) -
+                                 precedence.indexOf(b); });
+
+    return list[0];
+  },
 
   _streams: [],
   // The boolean parameters indicate which streams should be included in the result.
   getActiveStreams: function(aCamera, aMicrophone, aScreen) {
     return webrtcUI._streams.filter(aStream => {
       let state = aStream.state;
       return aCamera && state.camera ||
              aMicrophone && state.microphone ||
@@ -174,22 +212,26 @@ this.webrtcUI = {
         break;
       case "webrtc:CancelRequest":
         removePrompt(aMessage.target, aMessage.data);
         break;
       case "webrtc:UpdatingIndicators":
         webrtcUI._streams = [];
         break;
       case "webrtc:UpdateGlobalIndicators":
-        updateIndicators(aMessage.data)
+        updateIndicators(aMessage.data, aMessage.target);
         break;
       case "webrtc:UpdateBrowserIndicators":
         webrtcUI._streams.push({browser: aMessage.target, state: aMessage.data});
         updateBrowserSpecificIndicator(aMessage.target, aMessage.data);
         break;
+      case "child-process-shutdown":
+        webrtcUI.processIndicators.delete(aMessage.target);
+        updateIndicators(null, null);
+        break;
     }
   }
 };
 
 function getBrowserForWindow(aContentWindow) {
   return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIWebNavigation)
                        .QueryInterface(Ci.nsIDocShell)
@@ -736,21 +778,32 @@ function showOrCreateMenuForWindow(aWind
 function maybeAddMenuIndicator(window) {
   if (webrtcUI.showGlobalIndicator) {
     showOrCreateMenuForWindow(window);
   }
 }
 
 var gIndicatorWindow = null;
 
-function updateIndicators(data) {
-  webrtcUI.showGlobalIndicator = data.showGlobalIndicator;
-  webrtcUI.showCameraIndicator = data.showCameraIndicator;
-  webrtcUI.showMicrophoneIndicator = data.showMicrophoneIndicator;
-  webrtcUI.showScreenSharingIndicator = data.showScreenSharingIndicator;
+function updateIndicators(data, target) {
+  if (data) {
+    // the global indicators specific to this process
+    let indicators;
+    if (webrtcUI.processIndicators.has(target)) {
+      indicators = webrtcUI.processIndicators.get(target);
+    } else {
+      indicators = {};
+      webrtcUI.processIndicators.set(target, indicators);
+    }
+
+    indicators.showGlobalIndicator = data.showGlobalIndicator;
+    indicators.showCameraIndicator = data.showCameraIndicator;
+    indicators.showMicrophoneIndicator = data.showMicrophoneIndicator;
+    indicators.showScreenSharingIndicator = data.showScreenSharingIndicator;
+  }
 
   let browserWindowEnum = Services.wm.getEnumerator("navigator:browser");
   while (browserWindowEnum.hasMoreElements()) {
     let chromeWin = browserWindowEnum.getNext();
     if (webrtcUI.showGlobalIndicator) {
       showOrCreateMenuForWindow(chromeWin);
     } else {
       let doc = chromeWin.document;