Bug 1062876 - Refactor window iteration code for MediaManager. r=jib, a=abillings
authorRandell Jesup <rjesup@jesup.org>
Fri, 19 Sep 2014 17:24:28 -0400
changeset 216818 d508b53c3dee
parent 216817 9337f5dcf107
child 216819 232c3b4708b9
child 216821 85d8d6fa7f50
child 216823 e907d76ec004
push id3925
push userrjesup@wgate.com
push date2014-09-22 18:56 +0000
treeherdermozilla-beta@d508b53c3dee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, abillings
bugs1062876
milestone33.0
Bug 1062876 - Refactor window iteration code for MediaManager. r=jib, a=abillings
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1799,52 +1799,65 @@ MediaManager::GetBackend(uint64_t aWindo
     mBackend = new MediaEngineWebRTC(mPrefs);
 #else
     mBackend = new MediaEngineDefault();
 #endif
   }
   return mBackend;
 }
 
+static void
+StopSharingCallback(MediaManager *aThis,
+                    uint64_t aWindowID,
+                    StreamListeners *aListeners,
+                    void *aData)
+{
+  if (aListeners) {
+    auto length = aListeners->Length();
+    for (size_t i = 0; i < length; ++i) {
+      GetUserMediaCallbackMediaStreamListener *listener = aListeners->ElementAt(i);
+
+      if (listener->Stream()) { // aka HasBeenActivate()ed
+        listener->Invalidate();
+      }
+      listener->Remove();
+      listener->StopScreenWindowSharing();
+    }
+    aListeners->Clear();
+    aThis->RemoveWindowID(aWindowID);
+  }
+}
+
+
 void
 MediaManager::OnNavigation(uint64_t aWindowID)
 {
   NS_ASSERTION(NS_IsMainThread(), "OnNavigation called off main thread");
+  LOG(("OnNavigation for %llu", aWindowID));
 
   // Invalidate this window. The runnables check this value before making
   // a call to content.
 
   nsTArray<nsString>* callIds;
   if (mCallIds.Get(aWindowID, &callIds)) {
     for (int i = 0, len = callIds->Length(); i < len; ++i) {
       mActiveCallbacks.Remove((*callIds)[i]);
     }
     mCallIds.Remove(aWindowID);
   }
 
   // This is safe since we're on main-thread, and the windowlist can only
   // be added to from the main-thread
-  StreamListeners* listeners = GetWindowListeners(aWindowID);
-  if (!listeners) {
-    return;
+  nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
+      (nsGlobalWindow::GetInnerWindowWithId(aWindowID));
+  if (window) {
+    IterateWindowListeners(window, StopSharingCallback, nullptr);
+  } else {
+    RemoveWindowID(aWindowID);
   }
-
-  uint32_t length = listeners->Length();
-  for (uint32_t i = 0; i < length; i++) {
-    nsRefPtr<GetUserMediaCallbackMediaStreamListener> listener =
-      listeners->ElementAt(i);
-    if (listener->Stream()) { // aka HasBeenActivate()ed
-      listener->Invalidate();
-    }
-    listener->Remove();
-  }
-  listeners->Clear();
-
-  RemoveWindowID(aWindowID);
-  // listeners has been deleted
 }
 
 void
 MediaManager::RemoveWindowID(uint64_t aWindowId)
 {
   mActiveWindows.Remove(aWindowId);
 
   // get outer windowID
@@ -2118,157 +2131,152 @@ MediaManager::GetActiveMediaCaptureWindo
     return rv;
 
   mActiveWindows.EnumerateRead(WindowsHashToArrayFunc, array);
 
   *aArray = array;
   return NS_OK;
 }
 
+// XXX flags might be better...
+struct CaptureWindowStateData {
+  bool *mVideo;
+  bool *mAudio;
+  bool *mScreenShare;
+  bool *mWindowShare;
+};
+
+static void
+CaptureWindowStateCallback(MediaManager *aThis,
+                           uint64_t aWindowID,
+                           StreamListeners *aListeners,
+                           void *aData)
+{
+  struct CaptureWindowStateData *data = (struct CaptureWindowStateData *) aData;
+
+  if (aListeners) {
+    auto length = aListeners->Length();
+    for (size_t i = 0; i < length; ++i) {
+      GetUserMediaCallbackMediaStreamListener *listener = aListeners->ElementAt(i);
+
+      if (listener->CapturingVideo()) {
+        *data->mVideo = true;
+      }
+      if (listener->CapturingAudio()) {
+        *data->mAudio = true;
+      }
+      if (listener->CapturingScreen()) {
+        *data->mScreenShare = true;
+      }
+      if (listener->CapturingWindow()) {
+        *data->mWindowShare = true;
+      }
+    }
+  }
+}
+
+
 NS_IMETHODIMP
 MediaManager::MediaCaptureWindowState(nsIDOMWindow* aWindow, bool* aVideo,
                                       bool* aAudio, bool *aScreenShare,
                                       bool* aWindowShare)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+  struct CaptureWindowStateData data;
+  data.mVideo = aVideo;
+  data.mAudio = aAudio;
+  data.mScreenShare = aScreenShare;
+  data.mWindowShare = aWindowShare;
+
   *aVideo = false;
   *aAudio = false;
   *aScreenShare = false;
   *aWindowShare = false;
 
-  nsresult rv = MediaCaptureWindowStateInternal(aWindow, aVideo, aAudio, aScreenShare, aWindowShare);
+  nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
+  if (piWin) {
+    IterateWindowListeners(piWin, CaptureWindowStateCallback, &data);
+  }
 #ifdef DEBUG
-  nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
   LOG(("%s: window %lld capturing %s %s %s %s", __FUNCTION__, piWin ? piWin->WindowID() : -1,
        *aVideo ? "video" : "", *aAudio ? "audio" : "",
        *aScreenShare ? "screenshare" : "",  *aWindowShare ? "windowshare" : ""));
 #endif
-  return rv;
-}
-
-nsresult
-MediaManager::MediaCaptureWindowStateInternal(nsIDOMWindow* aWindow, bool* aVideo,
-                                              bool* aAudio, bool *aScreenShare,
-                                              bool* aWindowShare)
-{
-  // We need to return the union of all streams in all innerwindows that
-  // correspond to that outerwindow.
-
-  // Iterate the docshell tree to find all the child windows, find
-  // all the listeners for each one, get the booleans, and merge the
-  // results.
-  nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
-  if (piWin) {
-    if (piWin->GetCurrentInnerWindow() || piWin->IsInnerWindow()) {
-      uint64_t windowID;
-      if (piWin->GetCurrentInnerWindow()) {
-        windowID = piWin->GetCurrentInnerWindow()->WindowID();
-      } else {
-        windowID = piWin->WindowID();
-      }
-      StreamListeners* listeners = GetActiveWindows()->Get(windowID);
-      if (listeners) {
-        uint32_t length = listeners->Length();
-        for (uint32_t i = 0; i < length; ++i) {
-          nsRefPtr<GetUserMediaCallbackMediaStreamListener> listener =
-            listeners->ElementAt(i);
-          if (listener->CapturingVideo()) {
-            *aVideo = true;
-          }
-          if (listener->CapturingAudio()) {
-            *aAudio = true;
-          }
-          if (listener->CapturingScreen()) {
-            *aScreenShare = true;
-          }
-          if (listener->CapturingWindow()) {
-            *aWindowShare = true;
-          }
-        }
-      }
-    }
-
-    // iterate any children of *this* window (iframes, etc)
-    nsCOMPtr<nsIDocShell> docShell = piWin->GetDocShell();
-    if (docShell) {
-      int32_t i, count;
-      docShell->GetChildCount(&count);
-      for (i = 0; i < count; ++i) {
-        nsCOMPtr<nsIDocShellTreeItem> item;
-        docShell->GetChildAt(i, getter_AddRefs(item));
-        nsCOMPtr<nsPIDOMWindow> win = item ? item->GetWindow() : nullptr;
-
-        MediaCaptureWindowStateInternal(win, aVideo, aAudio, aScreenShare, aWindowShare);
-      }
-    }
-  }
   return NS_OK;
 }
 
-// XXX abstract out the iteration over all children and provide a function pointer and data ptr
+static void
+StopScreensharingCallback(MediaManager *aThis,
+                          uint64_t aWindowID,
+                          StreamListeners *aListeners,
+                          void *aData)
+{
+  if (aListeners) {
+    auto length = aListeners->Length();
+    for (size_t i = 0; i < length; ++i) {
+      aListeners->ElementAt(i)->StopScreenWindowSharing();
+    }
+  }
+}
 
 void
 MediaManager::StopScreensharing(uint64_t aWindowID)
 {
   // We need to stop window/screensharing for all streams in all innerwindows that
   // correspond to that outerwindow.
 
   nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
       (nsGlobalWindow::GetInnerWindowWithId(aWindowID));
   if (!window) {
     return;
   }
-  StopScreensharing(window);
+  IterateWindowListeners(window, &StopScreensharingCallback, nullptr);
 }
 
+// lets us do all sorts of things to the listeners
 void
-MediaManager::StopScreensharing(nsPIDOMWindow *aWindow)
+MediaManager::IterateWindowListeners(nsPIDOMWindow *aWindow,
+                                     WindowListenerCallback aCallback,
+                                     void *aData)
 {
-  // We need to stop window/screensharing for all streams in all innerwindows that
-  // correspond to that outerwindow.
-
-  // Iterate the docshell tree to find all the child windows, find
-  // all the listeners for each one, and tell them to stop
-  // window/screensharing
+  // Iterate the docshell tree to find all the child windows, and for each
+  // invoke the callback
   nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
   if (piWin) {
     if (piWin->IsInnerWindow() || piWin->GetCurrentInnerWindow()) {
       uint64_t windowID;
       if (piWin->IsInnerWindow()) {
         windowID = piWin->WindowID();
       } else {
         windowID = piWin->GetCurrentInnerWindow()->WindowID();
       }
       StreamListeners* listeners = GetActiveWindows()->Get(windowID);
-      if (listeners) {
-        uint32_t length = listeners->Length();
-        for (uint32_t i = 0; i < length; ++i) {
-          listeners->ElementAt(i)->StopScreenWindowSharing();
-        }
-      }
+      // pass listeners so it can modify/delete the list
+      (*aCallback)(this, windowID, listeners, aData);
     }
 
     // iterate any children of *this* window (iframes, etc)
     nsCOMPtr<nsIDocShell> docShell = piWin->GetDocShell();
     if (docShell) {
       int32_t i, count;
       docShell->GetChildCount(&count);
       for (i = 0; i < count; ++i) {
         nsCOMPtr<nsIDocShellTreeItem> item;
         docShell->GetChildAt(i, getter_AddRefs(item));
         nsCOMPtr<nsPIDOMWindow> win = item ? item->GetWindow() : nullptr;
 
         if (win) {
-          StopScreensharing(win);
+          IterateWindowListeners(win, aCallback, aData);
         }
       }
     }
   }
 }
 
+
 void
 MediaManager::StopMediaStreams()
 {
   nsCOMPtr<nsISupportsArray> array;
   GetActiveMediaCaptureWindows(getter_AddRefs(array));
   uint32_t len;
   array->Count(&len);
   for (uint32_t i = 0; i < len; i++) {
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -515,16 +515,22 @@ public:
 class AudioDevice : public MediaDevice
 {
 public:
   AudioDevice(MediaEngineAudioSource* aSource);
   NS_IMETHOD GetType(nsAString& aType);
   MediaEngineAudioSource* GetSource();
 };
 
+// we could add MediaManager if needed
+typedef void (*WindowListenerCallback)(MediaManager *aThis,
+                                       uint64_t aWindowID,
+                                       StreamListeners *aListeners,
+                                       void *aData);
+
 class MediaManager MOZ_FINAL : public nsIMediaManagerService,
                                public nsIObserver
 {
 public:
   static already_AddRefed<MediaManager> GetInstance();
 
   // NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
   // thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
@@ -587,22 +593,20 @@ private:
                    const char *aData, bool *aVal);
   void GetPrefs(nsIPrefBranch *aBranch, const char *aData);
 
   // Make private because we want only one instance of this class
   MediaManager();
 
   ~MediaManager() {}
 
-  nsresult MediaCaptureWindowStateInternal(nsIDOMWindow* aWindow, bool* aVideo,
-                                           bool* aAudio, bool *aScreenShare,
-                                           bool* aWindowShare);
-
   void StopScreensharing(uint64_t aWindowID);
-  void StopScreensharing(nsPIDOMWindow *aWindow);
+  void IterateWindowListeners(nsPIDOMWindow *aWindow,
+                              WindowListenerCallback aCallback,
+                              void *aData);
 
   void StopMediaStreams();
 
   // ONLY access from MainThread so we don't need to lock
   WindowTable mActiveWindows;
   nsClassHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
   nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
   // Always exists