Backout b53e8a614a4c, bustage
authorAnant Narayanan <anant@kix.in>
Wed, 11 Jul 2012 21:43:48 -0700
changeset 101752 0bdcca132fcfae5b7ec75679cb57224e705201e5
parent 101751 f22ca97a03ea9b4d6c2582afdae19237c0027daf
child 101753 d28330b09a8aa9d262773f7c568b2f0029797437
push id1729
push userlsblakk@mozilla.com
push dateMon, 16 Jul 2012 20:02:43 +0000
treeherdermozilla-aurora@f4e75e148951 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.0a1
backs outb53e8a614a4cd3a8747e0869fcb49ce3dcd3f964
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