Bug 1062876: refactor window iteration code for MediaManager r=jib
authorRandell Jesup <rjesup@jesup.org>
Fri, 19 Sep 2014 17:24:28 -0400
changeset 229532 786737c759d771029d393d793dff207d86f18faf
parent 229531 f152a52a80e1ada09bbd8e877ab6b8c7f9be8b56
child 229533 1a471705762334cd160bf60e3653a7497a340f4b
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib
bugs1062876
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1062876: refactor window iteration code for MediaManager r=jib
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1888,52 +1888,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
@@ -2208,162 +2221,159 @@ 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;
+  bool *mAppShare;
+};
+
+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;
+      }
+      if (listener->CapturingApplication()) {
+        *data->mAppShare = true;
+      }
+    }
+  }
+}
+
+
 NS_IMETHODIMP
 MediaManager::MediaCaptureWindowState(nsIDOMWindow* aWindow, bool* aVideo,
                                       bool* aAudio, bool *aScreenShare,
                                       bool* aWindowShare, bool *aAppShare)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+  struct CaptureWindowStateData data;
+  data.mVideo = aVideo;
+  data.mAudio = aAudio;
+  data.mScreenShare = aScreenShare;
+  data.mWindowShare = aWindowShare;
+  data.mAppShare = aAppShare;
+
   *aVideo = false;
   *aAudio = false;
   *aScreenShare = false;
   *aWindowShare = false;
   *aAppShare = false;
 
-  nsresult rv = MediaCaptureWindowStateInternal(aWindow, aVideo, aAudio, aScreenShare, aWindowShare, aAppShare);
+  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 %s", __FUNCTION__, piWin ? piWin->WindowID() : -1,
        *aVideo ? "video" : "", *aAudio ? "audio" : "",
        *aScreenShare ? "screenshare" : "",  *aWindowShare ? "windowshare" : "",
        *aAppShare ? "appshare" : ""));
 #endif
-  return rv;
-}
-
-nsresult
-MediaManager::MediaCaptureWindowStateInternal(nsIDOMWindow* aWindow, bool* aVideo,
-                                              bool* aAudio, bool *aScreenShare,
-                                              bool* aWindowShare, bool *aAppShare)
-{
-  // 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->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) {
-          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;
-          }
-          if (listener->CapturingApplication()) {
-            *aAppShare = 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, aAppShare);
-      }
-    }
-  }
   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
@@ -523,16 +523,22 @@ public:
 class AudioDevice : public MediaDevice
 {
 public:
   explicit 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
@@ -595,22 +601,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, bool *aAppShare);
-
   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