Backout b53e8a614a4c, bustage
authorAnant Narayanan <anant@kix.in>
Wed, 11 Jul 2012 21:43:48 -0700
changeset 99037 0bdcca132fcfae5b7ec75679cb57224e705201e5
parent 99036 f22ca97a03ea9b4d6c2582afdae19237c0027daf
child 99038 d28330b09a8aa9d262773f7c568b2f0029797437
push id23099
push useremorley@mozilla.com
push dateThu, 12 Jul 2012 16:29:09 +0000
treeherderautoland@f9499238bd4b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.0a1
backs outb53e8a614a4cd3a8747e0869fcb49ce3dcd3f964
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
Backout b53e8a614a4c, bustage
browser/confvars.sh
dom/media/Makefile.in
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -38,9 +38,8 @@ MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3
 # of values.
 ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
 # The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
 MAR_CHANNEL_ID=firefox-mozilla-central
 MOZ_PROFILE_MIGRATOR=1
 MOZ_EXTENSION_MANAGER=1
 MOZ_APP_STATIC_INI=1
 MOZ_WEBAPP_RUNTIME=1
-MOZ_MEDIA_NAVIGATOR=1
--- a/dom/media/Makefile.in
+++ b/dom/media/Makefile.in
@@ -29,14 +29,10 @@ EXPORTS_NAMESPACE = mozilla
 EXPORTS_mozilla = \
   MediaManager.h \
   $(NULL)
 
 CPPSRCS = \
   MediaManager.cpp \
   $(NULL)
 
-LOCAL_INCLUDES += \
-  -I$(topsrcdir)/media/webrtc/trunk/src \
-  $(NULL)
-
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1,31 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaManager.h"
 
 #include "MediaStreamGraph.h"
+#include "MediaEngineDefault.h"
+
 #include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIPopupWindowManager.h"
 
 #include "nsJSUtils.h"
 #include "nsDOMFile.h"
 #include "nsGlobalWindow.h"
 
-/* Using WebRTC backend on Desktops (Mac, Windows, Linux), otherwise default */
-#if defined(XP_WIN) || defined(XP_UNIX)
-#include "MediaEngineWebRTC.h"
-#else
-#include "MediaEngineDefault.h"
-#endif
-
 namespace mozilla {
 
 /**
  * Send an error back to content. The error is the form a string.
  * Do this only on the main thread.
  */
 class ErrorCallbackRunnable : public nsRunnable
 {
@@ -63,123 +58,224 @@ class SuccessCallbackRunnable : public n
 {
 public:
   SuccessCallbackRunnable(nsIDOMGetUserMediaSuccessCallback* aSuccess,
     nsIDOMFile* aFile, PRUint64 aWindowID)
     : mSuccess(aSuccess)
     , mFile(aFile)
     , mWindowID(aWindowID) {}
 
+  SuccessCallbackRunnable(nsIDOMGetUserMediaSuccessCallback* aSuccess,
+    nsIDOMMediaStream* aStream, PRUint64 aWindowID)
+    : mSuccess(aSuccess)
+    , mStream(aStream)
+    , mWindowID(aWindowID) {}
+
   NS_IMETHOD
   Run()
   {
     // Only run if the window is still active.
     WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
     if (activeWindows->Get(mWindowID)) {
       // XPConnect is a magical unicorn.
-      mSuccess->OnSuccess(mFile);
+      if (mFile) {
+        mSuccess->OnSuccess(mFile);
+      } else if (mStream) {
+        mSuccess->OnSuccess(mStream);
+      }
     }
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   nsCOMPtr<nsIDOMFile> mFile;
+  nsCOMPtr<nsIDOMMediaStream> mStream;
   PRUint64 mWindowID;
 };
 
 /**
- * Creates a MediaStream, attaches a listener and fires off a success callback
- * to the DOM with the stream.
- *
- * All of this must be done on the main thread!
+ * This runnable creates a nsDOMMediaStream from a given MediaEngineSource
+ * and returns it via a success callback. Both must be done on the main thread.
  */
-class GetUserMediaStreamRunnable : public nsRunnable
+class GetUserMediaCallbackRunnable : public nsRunnable
 {
 public:
-  GetUserMediaStreamRunnable(nsIDOMGetUserMediaSuccessCallback* aSuccess,
-    MediaEngineSource* aSource, StreamListeners* aListeners,
-    PRUint64 aWindowID, TrackID aTrackID)
-    : mSuccess(aSuccess)
-    , mSource(aSource)
-    , mListeners(aListeners)
+  GetUserMediaCallbackRunnable(MediaEngineSource* aSource, TrackID aId,
+    nsIDOMGetUserMediaSuccessCallback* aSuccess,
+    nsIDOMGetUserMediaErrorCallback* aError,
+    PRUint64 aWindowID,
+    StreamListeners* aListeners)
+    : mSource(aSource)
+    , mId(aId)
+    , mSuccess(aSuccess)
+    , mError(aError)
     , mWindowID(aWindowID)
-    , mTrackID(aTrackID) {}
-
-  ~GetUserMediaStreamRunnable() {}
+    , mListeners(aListeners) {}
 
   NS_IMETHOD
   Run()
   {
-    // Create a media stream.
-    nsCOMPtr<nsDOMMediaStream> stream = nsDOMMediaStream::CreateInputStream();
+    /**
+     * Normally we would now get the name & UUID for the device and ask the
+     * user permission. We will do that when we have some UI. Currently,
+     * only the Android {picture:true} backend is functional, which does not
+     * need a permission prompt, as permission is implicit by user action.
+     *
+     * See bug 748835 for progress on the desktop UI.
+     */
+    nsCOMPtr<nsDOMMediaStream> comStream = mSource->Allocate();
+    if (!comStream) {
+      NS_DispatchToMainThread(new ErrorCallbackRunnable(
+        mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
+      ));
+      return NS_OK;
+    }
 
     // Add our listener. We'll call Start() on the source when get a callback
     // that the MediaStream has started consuming. The listener is freed
     // when the page is invalidated (on navigation or close).
     GetUserMediaCallbackMediaStreamListener* listener =
-      new GetUserMediaCallbackMediaStreamListener(mSource, stream, mTrackID);
-    stream->GetStream()->AddListener(listener);
+      new GetUserMediaCallbackMediaStreamListener(mSource, comStream, mId);
+    comStream->GetStream()->AddListener(listener);
 
-    // No need for locking because we always do this in the main thread.
-    mListeners->AppendElement(listener);
-
-    // We're in the main thread, so no worries here either.
-    WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
-    if (activeWindows->Get(mWindowID)) {
-      mSuccess->OnSuccess(stream);
+    {
+      MutexAutoLock lock(*(MediaManager::Get()->GetLock()));
+      mListeners->AppendElement(listener);
     }
 
+    // Add the listener to CallbackRunnables so it can be invalidated.
+    NS_DispatchToMainThread(new SuccessCallbackRunnable(
+      mSuccess, comStream.get(), mWindowID
+    ));
     return NS_OK;
   }
 
 private:
+  nsCOMPtr<MediaEngineSource> mSource;
+  TrackID mId;
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
-  nsRefPtr<MediaEngineSource> mSource;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  PRUint64 mWindowID;
   StreamListeners* mListeners;
+};
+
+/**
+ * This runnable creates a nsIDOMFile from a MediaEngineVideoSource and
+ * passes the result back via a SuccessRunnable. Both must be done on the
+ * main thread.
+ */
+class GetUserMediaSnapshotCallbackRunable : public nsRunnable
+{
+public:
+  GetUserMediaSnapshotCallbackRunable(MediaEngineSource* aSource,
+    PRUint32 aDuration,
+    nsIDOMGetUserMediaSuccessCallback* aSuccessCallback,
+    nsIDOMGetUserMediaErrorCallback* aErrorCallback,
+    nsPIDOMWindow* aWindow)
+    : mSource(aSource)
+    , mDuration(aDuration)
+    , mSuccessCallback(aSuccessCallback)
+    , mErrorCallback(aErrorCallback)
+    , mWindow(aWindow) {}
+
+  NS_IMETHOD
+  Run()
+  {
+    mWindowID = mWindow->WindowID();
+
+    // Before getting a snapshot, check if page is allowed to open a popup.
+    // We do this because {picture:true} on all platforms will open a new
+    // "window" to let the user preview or select an image.
+
+    if (mWindow->GetPopupControlState() <= openControlled) {
+      return NS_OK;
+    }
+    
+    nsCOMPtr<nsIPopupWindowManager> pm =
+      do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
+    if (!pm) {
+      return NS_OK;
+    }
+
+    PRUint32 permission;
+    nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
+    pm->TestPermission(doc->GetDocumentURI(), &permission);
+    if (permission == nsIPopupWindowManager::DENY_POPUP) {
+      nsCOMPtr<nsIDOMDocument> domDoc = mWindow->GetExtantDocument();
+      nsGlobalWindow::FirePopupBlockedEvent(
+        domDoc, mWindow, nsnull, EmptyString(), EmptyString()
+      );
+      return NS_OK;
+    }
+
+    nsCOMPtr<nsDOMMediaStream> comStream = mSource->Allocate();
+    if (!comStream) {
+      NS_DispatchToMainThread(new ErrorCallbackRunnable(
+        mErrorCallback, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
+      ));
+      return NS_OK;
+    }
+
+    nsCOMPtr<nsIDOMFile> file;
+    mSource->Snapshot(mDuration, getter_AddRefs(file));
+    mSource->Deallocate();
+
+    NS_DispatchToMainThread(new SuccessCallbackRunnable(
+      mSuccessCallback, file, mWindowID
+    ));
+    return NS_OK;
+  }
+
+private:
+  nsCOMPtr<MediaEngineSource> mSource;
+  PRUint32 mDuration;
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccessCallback;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback>  mErrorCallback;
+  nsCOMPtr<nsPIDOMWindow> mWindow;
+
   PRUint64 mWindowID;
-  TrackID mTrackID;
 };
 
 /**
  * Runs on a seperate thread and is responsible for enumerating devices.
  * Depending on whether a picture or stream was asked for, either
- * ProcessGetUserMedia or ProcessGetUserMediaSnapshot is called, and the results
- * are sent back to the DOM.
+ * GetUserMediaCallbackRunnable or GetUserMediaSnapshotCallbackRunnable
+ * will be dispatched to the main thread to return the result to DOM.
  *
- * Do not run this on the main thread. The success and error callbacks *MUST*
- * be dispatched on the main thread!
+ * Do not run this on the main thread.
  */
 class GetUserMediaRunnable : public nsRunnable
 {
 public:
   GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture,
     nsIDOMGetUserMediaSuccessCallback* aSuccess,
     nsIDOMGetUserMediaErrorCallback* aError,
-    StreamListeners* aListeners, PRUint64 aWindowID)
+    nsPIDOMWindow* aWindow, StreamListeners* aListeners)
     : mAudio(aAudio)
     , mVideo(aVideo)
     , mPicture(aPicture)
     , mSuccess(aSuccess)
     , mError(aError)
-    , mListeners(aListeners)
-    , mWindowID(aWindowID) {}
+    , mWindow(aWindow)
+    , mListeners(aListeners) {}
 
   ~GetUserMediaRunnable() {}
 
   // We only support 1 audio and 1 video track for now.
   enum {
     kVideoTrack = 1,
     kAudioTrack = 2
   };
 
   NS_IMETHOD
   Run()
   {
     mManager = MediaManager::Get();
+    mWindowID = mWindow->WindowID();
 
     if (mPicture) {
       SendPicture();
       return NS_OK;
     }
 
     // XXX: Implement merging two streams (See bug 758391).
     if (mAudio && mVideo) {
@@ -197,89 +293,34 @@ public:
     if (mAudio) {
       SendAudio();
       return NS_OK;
     }
 
     return NS_OK;
   }
 
-  /**
-   * Allocates a video or audio device and returns a MediaStream via
-   * a GetUserMediaStreamRunnable. Runs off the main thread.
-   */
-  void
-  ProcessGetUserMedia(MediaEngineSource* aSource, TrackID aTrackID)
-  {
-    /**
-     * Normally we would now get the name & UUID for the device and ask the
-     * user permission. We will do that when we have some UI. Currently,
-     * only the Android {picture:true} backend is functional, which does not
-     * need a permission prompt, as permission is implicit by user action.
-     *
-     * See bug 748835 for progress on the desktop UI.
-     */
-    nsresult rv = aSource->Allocate();
-    if (NS_FAILED(rv)) {
-      NS_DispatchToMainThread(new ErrorCallbackRunnable(
-        mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
-      ));
-      return;
-    }
-
-    NS_DispatchToMainThread(new GetUserMediaStreamRunnable(
-      mSuccess.get(), aSource, mListeners, mWindowID, aTrackID
-    ));
-    return;
-  }
-
-  /**
-   * Allocates a video device, takes a snapshot and returns a DOMFile via
-   * a SuccessRunnable or an error via the ErrorRunnable. Off the main thread.
-   */
-  void
-  ProcessGetUserMediaSnapshot(MediaEngineSource* aSource, int aDuration)
-  {
-    nsresult rv = aSource->Allocate();
-    if (NS_FAILED(rv)) {
-      NS_DispatchToMainThread(new ErrorCallbackRunnable(
-        mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
-      ));
-      return;
-    }
-
-    nsCOMPtr<nsIDOMFile> file;
-    aSource->Snapshot(aDuration, getter_AddRefs(file));
-    aSource->Deallocate();
-
-    NS_DispatchToMainThread(new SuccessCallbackRunnable(
-      mSuccess, file, mWindowID
-    ));
-    return;
-  }
-
   // {picture:true}
   void
   SendPicture()
   {
     nsTArray<nsRefPtr<MediaEngineVideoSource> > videoSources;
     mManager->GetBackend()->EnumerateVideoDevices(&videoSources);
 
     PRUint32 count = videoSources.Length();
     if (!count) {
       NS_DispatchToMainThread(new ErrorCallbackRunnable(
         mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID
       ));
       return;
     }
-
-    // We pick the first source as the "default". Work is needed here in the
-    // form of UI to let the user pick a source. (Also true for audio).
-    MediaEngineVideoSource* videoSource = videoSources[0];
-    ProcessGetUserMediaSnapshot(videoSource, 0 /* duration */);
+    MediaEngineVideoSource* videoSource = videoSources[count - 1];
+    NS_DispatchToMainThread(new GetUserMediaSnapshotCallbackRunable(
+      videoSource, 0 /* duration */, mSuccess, mError, mWindow
+    ));
   }
 
   // {video:true}
   void
   SendVideo()
   {
     nsTArray<nsRefPtr<MediaEngineVideoSource> > videoSources;
     mManager->GetBackend()->EnumerateVideoDevices(&videoSources);
@@ -287,18 +328,20 @@ public:
     PRUint32 count = videoSources.Length();
     if (!count) {
       NS_DispatchToMainThread(new ErrorCallbackRunnable(
         mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID
       ));
       return;
     }
 
-    MediaEngineVideoSource* videoSource = videoSources[0];
-    ProcessGetUserMedia(videoSource, kVideoTrack);
+    MediaEngineVideoSource* videoSource = videoSources[count - 1];
+    NS_DispatchToMainThread(new GetUserMediaCallbackRunnable(
+      videoSource, kVideoTrack, mSuccess, mError, mWindowID, mListeners
+    ));
   }
 
   // {audio:true}
   void
   SendAudio()
   {
     nsTArray<nsRefPtr<MediaEngineAudioSource> > audioSources;
     mManager->GetBackend()->EnumerateAudioDevices(&audioSources);
@@ -306,31 +349,34 @@ public:
     PRUint32 count = audioSources.Length();
     if (!count) {
       NS_DispatchToMainThread(new ErrorCallbackRunnable(
         mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID
       ));
       return;
     }
 
-    MediaEngineAudioSource* audioSource = audioSources[0];
-    ProcessGetUserMedia(audioSource, kAudioTrack);
+    MediaEngineAudioSource* audioSource = audioSources[count - 1];
+    NS_DispatchToMainThread(new GetUserMediaCallbackRunnable(
+      audioSource, kAudioTrack, mSuccess, mError, mWindowID, mListeners
+    ));
   }
 
 private:
   bool mAudio;
   bool mVideo;
   bool mPicture;
 
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  nsCOMPtr<nsPIDOMWindow> mWindow;
   StreamListeners* mListeners;
-  PRUint64 mWindowID;
 
   MediaManager* mManager;
+  PRUint64 mWindowID;
 };
 
 
 nsRefPtr<MediaManager> MediaManager::sSingleton;
 
 NS_IMPL_ISUPPORTS1(MediaManager, nsIObserver)
 
 /**
@@ -339,53 +385,20 @@ NS_IMPL_ISUPPORTS1(MediaManager, nsIObse
  * for handling all incoming getUserMedia calls from every window.
  */
 nsresult
 MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, nsIMediaStreamOptions* aParams,
   nsIDOMGetUserMediaSuccessCallback* onSuccess,
   nsIDOMGetUserMediaErrorCallback* onError)
 {
   NS_ENSURE_TRUE(aParams, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
 
   bool audio, video, picture;
-
   nsresult rv = aParams->GetPicture(&picture);
   NS_ENSURE_SUCCESS(rv, rv);
-  
-  /**
-   * If we were asked to get a picture, before getting a snapshot, we check if
-   * the calling page is allowed to open a popup. We do this because
-   * {picture:true} will open a new "window" to let the user preview or select
-   * an image, on Android. The desktop UI for {picture:true} is TBD, at which
-   * may point we can decide whether to extend this test there as well.
-   */
-#if !defined(XP_WIN) && !defined(XP_UNIX)
-  if (picture) {
-    if (aWindow->GetPopupControlState() <= openControlled) {
-      return NS_ERROR_FAILURE;
-    }
-    nsCOMPtr<nsIPopupWindowManager> pm =
-      do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
-    if (!pm) {
-      return NS_ERROR_FAILURE;
-    }
-
-    PRUint32 permission;
-    nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
-    pm->TestPermission(doc->GetDocumentURI(), &permission);
-    if (mWindow && (permission == nsIPopupWindowManager::DENY_POPUP)) {
-      nsCOMPtr<nsIDOMDocument> domDoc = mWindow->GetExtantDocument();
-      nsGlobalWindow::FirePopupBlockedEvent(
-        domDoc, mWindow, nsnull, EmptyString(), EmptyString()
-      );
-      return NS_ERROR_FAILURE;
-    }
-  }
-#endif
 
   rv = aParams->GetAudio(&audio);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aParams->GetVideo(&video);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We only support "front" or "back". TBD: Send to GetUserMediaRunnable.
@@ -397,45 +410,40 @@ MediaManager::GetUserMedia(nsPIDOMWindow
   // when this window is closed or navigated away from.
   PRUint64 windowID = aWindow->WindowID();
   StreamListeners* listeners = mActiveWindows.Get(windowID);
   if (!listeners) {
     listeners = new StreamListeners;
     mActiveWindows.Put(windowID, listeners);
   }
 
-  // Pass runnables along to GetUserMediaRunnable so it can add the
+  // Pass runanbles along to GetUserMediaRunnable so it can add the
   // MediaStreamListener to the runnable list.
   nsCOMPtr<nsIRunnable> gUMRunnable = new GetUserMediaRunnable(
-    audio, video, picture, onSuccess, onError, listeners, windowID
+    audio, video, picture, onSuccess, onError, aWindow, listeners
   );
 
   // Reuse the same thread to save memory.
   if (!mMediaThread) {
     rv = NS_NewThread(getter_AddRefs(mMediaThread));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
 MediaEngine*
 MediaManager::GetBackend()
 {
-  // Plugin backends as appropriate. The default engine also currently
-  // includes picture support for Android.
+  // Plugin backends as appropriate. Only default is available for now, which
+  // also includes picture support for Android.
   if (!mBackend) {
-#if defined(XP_WIN) || defined(XP_UNIX)
-    mBackend = new MediaEngineWebRTC();
-#else
     mBackend = new MediaEngineDefault();
-#endif
   }
-
   return mBackend;
 }
 
 WindowTable*
 MediaManager::GetActiveWindows()
 {
   return &mActiveWindows;
 }
@@ -445,16 +453,17 @@ MediaManager::OnNavigation(PRUint64 aWin
 {
   // Invalidate this window. The runnables check this value before making
   // a call to content.
   StreamListeners* listeners = mActiveWindows.Get(aWindowID);
   if (!listeners) {
     return;
   }
 
+  MutexAutoLock lock(*mLock);
   PRUint32 length = listeners->Length();
   for (PRUint32 i = 0; i < length; i++) {
     nsRefPtr<GetUserMediaCallbackMediaStreamListener> listener =
       listeners->ElementAt(i);
     listener->Invalidate();
     listener = nsnull;
   }
   listeners->Clear();
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -22,17 +22,17 @@ namespace mozilla {
  */
 class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
 {
 public:
   GetUserMediaCallbackMediaStreamListener(MediaEngineSource* aSource,
     nsDOMMediaStream* aStream, TrackID aListenId)
     : mSource(aSource)
     , mStream(aStream)
-    , mID(aListenId)
+    , mId(aListenId)
     , mValid(true) {}
 
   void
   Invalidate()
   {
     if (!mValid) {
       return;
     }
@@ -41,37 +41,38 @@ public:
     mSource->Stop();
     mSource->Deallocate();
   }
 
   void
   NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming)
   {
     if (aConsuming == CONSUMED) {
-      SourceMediaStream* stream = mStream->GetStream()->AsSourceStream();
-      mSource->Start(stream, mID);
+      nsRefPtr<SourceMediaStream> stream = mStream->GetStream()->AsSourceStream();
+      mSource->Start(stream, mId);
       return;
     }
 
     // NOT_CONSUMED
     Invalidate();
     return;
   }
 
   void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {}
   void NotifyOutput(MediaStreamGraph* aGraph) {}
   void NotifyFinished(MediaStreamGraph* aGraph) {}
   void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
     TrackRate aTrackRate, TrackTicks aTrackOffset,
     PRUint32 aTrackEvents, const MediaSegment& aQueuedMedia) {}
+  nsresult Run() { return NS_OK; }
 
 private:
-  nsRefPtr<MediaEngineSource> mSource;
+  nsCOMPtr<MediaEngineSource> mSource;
   nsCOMPtr<nsDOMMediaStream> mStream;
-  TrackID mID;
+  TrackID mId;
   bool mValid;
 };
 
 typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
 
 class MediaManager MOZ_FINAL : public nsIObserver {
 public:
@@ -83,38 +84,45 @@ public:
       obs->AddObserver(sSingleton, "xpcom-shutdown", false);
     }
     return sSingleton;
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
+  Mutex* GetLock() {
+    return mLock;
+  }
+
   MediaEngine* GetBackend();
   WindowTable* GetActiveWindows();
 
   nsresult GetUserMedia(nsPIDOMWindow* aWindow, nsIMediaStreamOptions* aParams,
     nsIDOMGetUserMediaSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
   void OnNavigation(PRUint64 aWindowID);
 
 private:
   // Make private because we want only one instance of this class
   MediaManager()
   : mBackend(nsnull)
   , mMediaThread(nsnull) {
+    mLock = new mozilla::Mutex("MediaManager::StreamListenersLock");
     mActiveWindows.Init();
   };
   MediaManager(MediaManager const&) {};
 
   ~MediaManager() {
+    delete mLock;
     delete mBackend;
   };
 
   MediaEngine* mBackend;
   nsCOMPtr<nsIThread> mMediaThread;
 
+  Mutex* mLock;
   WindowTable mActiveWindows;
 
   static nsRefPtr<MediaManager> sSingleton;
 };
 
 } // namespace mozilla