Bug 1062876 - Refactor window iteration code for MediaManager. r=jib, a=abillings
--- 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