Backed out changeset ea436c6f7d2d (bug 803799), landed on a CLOSED TREE
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 24 Oct 2012 20:30:08 -0400
changeset 119242 834551729be15b81a971a34cce844eaabaeae807
parent 119241 7f7c32980d872349dd946039cb3911851ce20a74
child 119243 d408a2592685803980fd331ee6a0690fcf7ab951
push id1997
push userakeybl@mozilla.com
push dateMon, 07 Jan 2013 21:25:26 +0000
treeherdermozilla-beta@4baf45cdcf21 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs803799
milestone19.0a1
backs outea436c6f7d2de0ac0ccf4709efb63513ac9387b0
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
Backed out changeset ea436c6f7d2d (bug 803799), landed on a CLOSED TREE
content/media/webrtc/MediaEngineWebRTCAudio.cpp
content/media/webrtc/MediaEngineWebRTCVideo.cpp
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -134,23 +134,16 @@ MediaEngineWebRTCAudioSource::Stop()
   return NS_OK;
 }
 
 void
 MediaEngineWebRTCAudioSource::NotifyPull(MediaStreamGraph* aGraph,
                                          StreamTime aDesiredTime)
 {
   // Ignore - we push audio data
-#ifdef DEBUG
-  static TrackTicks mLastEndTime = 0;
-  TrackTicks target = TimeToTicksRoundUp(SAMPLE_FREQUENCY, aDesiredTime);
-  TrackTicks delta = target - mLastEndTime;
-  LOG(("Audio:NotifyPull: target %lu, delta %lu",(uint32_t) target, (uint32_t) delta));
-  mLastEndTime = target;
-#endif
 }
 
 nsresult
 MediaEngineWebRTCAudioSource::Snapshot(uint32_t aDuration, nsIDOMFile** aFile)
 {
    return NS_ERROR_NOT_IMPLEMENTED;
 }
 
--- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -246,32 +246,32 @@ MediaEngineWebRTCVideoSource::Start(Sour
   mSource = aStream;
   mTrackID = aID;
 
   mImageContainer = layers::LayerManager::CreateImageContainer();
 
   mSource->AddTrack(aID, USECS_PER_S, 0, new VideoSegment());
   mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
   mLastEndTime = 0;
-  mState = kStarted;
 
   error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this);
   if (error == -1) {
     return NS_ERROR_FAILURE;
   }
 
   error = mViERender->StartRender(mCaptureIndex);
   if (error == -1) {
     return NS_ERROR_FAILURE;
   }
 
   if (mViECapture->StartCapture(mCaptureIndex, mCapability) < 0) {
     return NS_ERROR_FAILURE;
   }
 
+  mState = kStarted;
   return NS_OK;
 }
 
 nsresult
 MediaEngineWebRTCVideoSource::Stop()
 {
   if (mState != kStarted) {
     return NS_ERROR_FAILURE;
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -57,22 +57,19 @@ public:
   Run()
   {
     // Only run if the window is still active.
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
     nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
-    {
-      MutexAutoLock lock(MediaManager::Get()->GetMutex());
-      WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
-      if (activeWindows->Get(mWindowID)) {
-        error->OnError(mErrorMsg);
-      }
+    WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
+    if (activeWindows->Get(mWindowID)) {
+      error->OnError(mErrorMsg);
     }
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   const nsString mErrorMsg;
@@ -101,23 +98,20 @@ public:
   Run()
   {
     // Only run if the window is still active.
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
     nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
-    {
-      MutexAutoLock lock(MediaManager::Get()->GetMutex());
-      WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
-      if (activeWindows->Get(mWindowID)) {
-        // XPConnect is a magical unicorn.
-        success->OnSuccess(mFile);
-      }
+    WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
+    if (activeWindows->Get(mWindowID)) {
+      // XPConnect is a magical unicorn.
+      success->OnSuccess(mFile);
     }
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsCOMPtr<nsIDOMFile> mFile;
@@ -210,17 +204,17 @@ MediaDevice::GetSource()
  * to the DOM with the stream. We also pass in the error callback so it can
  * be released correctly.
  *
  * All of this must be done on the main thread!
  *
  * Note that the various GetUserMedia Runnable classes currently allow for
  * two streams.  If we ever need to support getting more than two streams
  * at once, we could convert everything to nsTArray<nsRefPtr<blah> >'s,
- * though that would complicate the constructors some.  Currently the
+ * though that would complicate the constructors some.  Currently the 
  * GetUserMedia spec does not allow for more than 2 streams to be obtained in
  * one call, to simplify handling of constraints.
  */
 class GetUserMediaStreamRunnable : public nsRunnable
 {
 public:
   GetUserMediaStreamRunnable(
     already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
@@ -248,64 +242,48 @@ public:
     uint32_t hints = (mAudioSource ? nsDOMMediaStream::HINT_CONTENTS_AUDIO : 0);
     hints |= (mVideoSource ? nsDOMMediaStream::HINT_CONTENTS_VIDEO : 0);
 
     stream = nsDOMMediaStream::CreateInputStream(hints);
 
     nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
       (nsGlobalWindow::GetInnerWindowWithId(mWindowID));
     WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
-    {
-      MutexAutoLock lock(MediaManager::Get()->GetMutex());
 
-      if (!stream) {
-        if (activeWindows->Get(mWindowID)) {
-          nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
-          LOG(("Returning error for getUserMedia() - no stream"));
-          error->OnError(NS_LITERAL_STRING("NO_STREAM"));
-        }
-        return NS_OK;
+    if (!stream) {
+      if (activeWindows->Get(mWindowID)) {
+        nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
+        LOG(("Returning error for getUserMedia() - no stream"));
+        error->OnError(NS_LITERAL_STRING("NO_STREAM"));
       }
+      return NS_OK;
     }
+
     if (window && window->GetExtantDoc()) {
       stream->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
     }
 
-    // Ensure there's a thread for gum to proxy to off main thread
-    nsIThread *mediaThread = MediaManager::GetThread();
-
     // 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(mediaThread, stream,
-                                                  mAudioSource,
+      new GetUserMediaCallbackMediaStreamListener(stream, mAudioSource,
                                                   mVideoSource);
     stream->GetStream()->AddListener(listener);
 
     // No need for locking because we always do this in the main thread.
     mListeners->AppendElement(listener);
 
-    // Dispatch to the media thread to ask it to start the sources,
-    // because that can take a while
-    nsRefPtr<MediaOperationRunnable> runnable(
-      new MediaOperationRunnable(MEDIA_START, stream,
-                                 mAudioSource, mVideoSource));
-    mediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
-
     // We're in the main thread, so no worries here either.
     nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
-    {
-      MutexAutoLock lock(MediaManager::Get()->GetMutex());
-      if (activeWindows->Get(mWindowID)) {
-        LOG(("Returning success for getUserMedia()"));
-        success->OnSuccess(stream);
-      }
+    if (activeWindows->Get(mWindowID)) {
+      LOG(("Returning success for getUserMedia()"));
+      success->OnSuccess(stream);
     }
 
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
@@ -329,31 +307,31 @@ class GetUserMediaRunnable : public nsRu
 public:
   /**
    * The caller can choose to provide a MediaDevice as the last argument,
    * if one is not provided, a default device is automatically chosen.
    */
   GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture,
     already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
     already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
-    StreamListeners* aListeners, uint64_t aWindowID,
+    StreamListeners* aListeners, uint64_t aWindowID, 
     MediaDevice* aAudioDevice, MediaDevice* aVideoDevice)
     : mAudio(aAudio)
     , mVideo(aVideo)
     , mPicture(aPicture)
     , mSuccess(aSuccess)
     , mError(aError)
     , mListeners(aListeners)
     , mWindowID(aWindowID)
     , mDeviceChosen(true)
     , mBackendChosen(false)
     {
       if (mAudio) {
         mAudioDevice = aAudioDevice;
-      }
+      } 
       if (mVideo) {
         mVideoDevice = aVideoDevice;
       }
     }
 
   GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture,
     already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
     already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
@@ -776,73 +754,73 @@ MediaManager::GetUserMedia(bool aPrivile
       }
     }
   }
 #endif
 
   // Store the WindowID in a hash table and mark as active. The entry is removed
   // when this window is closed or navigated away from.
   uint64_t windowID = aWindow->WindowID();
-  nsRefPtr<GetUserMediaRunnable> gUMRunnable;
-  {
-    MutexAutoLock lock(mMutex);
-    StreamListeners* listeners = mActiveWindows.Get(windowID);
-    if (!listeners) {
-      listeners = new StreamListeners;
-      mActiveWindows.Put(windowID, listeners);
-    }
-
-    // Developer preference for turning off permission check.
-    if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
-      aPrivileged = true;
-    }
+  StreamListeners* listeners = mActiveWindows.Get(windowID);
+  if (!listeners) {
+    listeners = new StreamListeners;
+    mActiveWindows.Put(windowID, listeners);
+  }
 
-    /**
-     * Pass runnables along to GetUserMediaRunnable so it can add the
-     * MediaStreamListener to the runnable list. The last argument can
-     * optionally be a MediaDevice object, which should provided if one was
-     * selected by the user via the UI, or was provided by privileged code
-     * via the device: attribute via nsIMediaStreamOptions.
-     *
-     * If a fake stream was requested, we force the use of the default backend.
-     */
-    if (fake) {
-      // Fake stream from default backend.
-      gUMRunnable = new GetUserMediaRunnable(
-        audio, video, onSuccess.forget(), onError.forget(), listeners,
-        windowID, new MediaEngineDefault()
-                                             );
-    } else if (audiodevice || videodevice) {
-      // Stream from provided device.
-      gUMRunnable = new GetUserMediaRunnable(
-        audio, video, picture, onSuccess.forget(), onError.forget(), listeners,
-        windowID,
-        static_cast<MediaDevice*>(audiodevice.get()),
-        static_cast<MediaDevice*>(videodevice.get())
-                                             );
-    } else {
-      // Stream from default device from WebRTC backend.
-      gUMRunnable = new GetUserMediaRunnable(
-        audio, video, picture, onSuccess.forget(), onError.forget(), listeners,
-        windowID
-                                             );
-    }
+  // Developer preference for turning off permission check.
+  if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
+    aPrivileged = true;
   }
 
+  /**
+   * Pass runnables along to GetUserMediaRunnable so it can add the
+   * MediaStreamListener to the runnable list. The last argument can
+   * optionally be a MediaDevice object, which should provided if one was
+   * selected by the user via the UI, or was provided by privileged code
+   * via the device: attribute via nsIMediaStreamOptions.
+   *
+   * If a fake stream was requested, we force the use of the default backend.
+   */
+  nsRefPtr<GetUserMediaRunnable> gUMRunnable;
+  if (fake) {
+    // Fake stream from default backend.
+    gUMRunnable = new GetUserMediaRunnable(
+      audio, video, onSuccess.forget(), onError.forget(), listeners,
+      windowID, new MediaEngineDefault()
+    );
+  } else if (audiodevice || videodevice) {
+    // Stream from provided device.
+    gUMRunnable = new GetUserMediaRunnable(
+      audio, video, picture, onSuccess.forget(), onError.forget(), listeners,
+      windowID, 
+      static_cast<MediaDevice*>(audiodevice.get()),
+      static_cast<MediaDevice*>(videodevice.get())
+    );
+  } else {
+    // Stream from default device from WebRTC backend.
+    gUMRunnable = new GetUserMediaRunnable(
+      audio, video, picture, onSuccess.forget(), onError.forget(), listeners,
+      windowID
+    );
+  }
 
 #ifdef ANDROID
   if (picture) {
     // ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
     NS_DispatchToMainThread(gUMRunnable);
   }
   // XXX No support for Audio or Video in Android yet
 #else
   // XXX No full support for picture in Desktop yet (needs proper UI)
   if (aPrivileged || fake) {
-    (void) MediaManager::GetThread();
+    if (!mMediaThread) {
+      nsresult rv = NS_NewThread(getter_AddRefs(mMediaThread));
+      NS_ENSURE_SUCCESS(rv, rv);
+      LOG(("New Media thread for gum"));
+    }
     mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL);
   } else {
     // Ask for user permission, and dispatch runnable (or not) when a response
     // is received via an observer notification. Each call is paired with its
     // runnable by a GUID.
     nsresult rv;
     nsCOMPtr<nsIUUIDGenerator> uuidgen =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
@@ -853,20 +831,17 @@ MediaManager::GetUserMedia(bool aPrivile
     rv = uuidgen->GenerateUUIDInPlace(&id);
     NS_ENSURE_SUCCESS(rv, rv);
 
     char buffer[NSID_LENGTH];
     id.ToProvidedString(buffer);
     NS_ConvertUTF8toUTF16 callID(buffer);
 
     // Store the current callback.
-    {
-      MutexAutoLock lock(mMutex);
-      mActiveCallbacks.Put(callID, gUMRunnable);
-    }
+    mActiveCallbacks.Put(callID, gUMRunnable);
 
     // Construct JSON structure with both the windowID and the callID.
     nsAutoString data;
     data.Append(NS_LITERAL_STRING("{\"windowID\":"));
 
     // Convert window ID to string.
     char windowBuffer[32];
     PR_snprintf(windowBuffer, 32, "%llu", aWindow->GetOuterWindow()->WindowID());
@@ -932,71 +907,68 @@ MediaManager::GetActiveWindows()
   return &mActiveWindows;
 }
 
 void
 MediaManager::OnNavigation(uint64_t aWindowID)
 {
   // Invalidate this window. The runnables check this value before making
   // a call to content.
-  {
-    MutexAutoLock lock(mMutex);
-    StreamListeners* listeners = mActiveWindows.Get(aWindowID);
-    if (!listeners) {
-      return;
-    }
+  StreamListeners* listeners = mActiveWindows.Get(aWindowID);
+  if (!listeners) {
+    return;
+  }
 
-    uint32_t length = listeners->Length();
-    for (uint32_t i = 0; i < length; i++) {
-      nsRefPtr<GetUserMediaCallbackMediaStreamListener> listener =
-        listeners->ElementAt(i);
-      listener->Invalidate();
-      listener = nullptr;
-    }
-    listeners->Clear();
+  uint32_t length = listeners->Length();
+  for (uint32_t i = 0; i < length; i++) {
+    nsRefPtr<GetUserMediaCallbackMediaStreamListener> listener =
+      listeners->ElementAt(i);
+    listener->Invalidate();
+    listener = nullptr;
+  }
+  listeners->Clear();
 
-    mActiveWindows.Remove(aWindowID);
-  }
+  mActiveWindows.Remove(aWindowID);
 }
 
 nsresult
 MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
   const PRUnichar* aData)
 {
   NS_ASSERTION(NS_IsMainThread(), "Observer invoked off the main thread");
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 
   if (!strcmp(aTopic, "xpcom-shutdown")) {
     obs->RemoveObserver(this, "xpcom-shutdown");
     obs->RemoveObserver(this, "getUserMedia:response:allow");
     obs->RemoveObserver(this, "getUserMedia:response:deny");
 
     // Close off any remaining active windows.
-    {
-      MutexAutoLock lock(mMutex);
-      mActiveWindows.Clear();
-      mActiveCallbacks.Clear();
-      sSingleton = nullptr;
-    }
+    mActiveWindows.Clear();
+    mActiveCallbacks.Clear();
+    sSingleton = nullptr;
 
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "getUserMedia:response:allow")) {
     nsString key(aData);
     nsRefPtr<nsRunnable> runnable;
-    {
-      MutexAutoLock lock(mMutex);
-      if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
-        return NS_OK;
-      }
+    if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
+      return NS_OK;
     }
 
     // Reuse the same thread to save memory.
-    (void) MediaManager::GetThread();
+    if (!mMediaThread) {
+      LOG(("New Media thread for gum on allow"));
+      nsresult rv = NS_NewThread(getter_AddRefs(mMediaThread));
+      NS_ENSURE_SUCCESS(rv, rv);
+    } else {
+      LOG(("Reused Media thread for gum on allow"));
+    }
 
     if (aSubject) {
       // A particular device was chosen by the user.
       // NOTE: does not allow setting a device to null; assumes nullptr
       nsCOMPtr<nsIMediaDevice> device = do_QueryInterface(aSubject);
       if (device) {
         GetUserMediaRunnable* gUMRunnable =
           static_cast<GetUserMediaRunnable*>(runnable.get());
@@ -1008,34 +980,29 @@ MediaManager::Observe(nsISupports* aSubj
           gUMRunnable->SetAudioDevice(static_cast<MediaDevice*>(device.get()));
         } else {
           NS_WARNING("Unknown device type in getUserMedia");
         }
       }
     }
 
     mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
-    {
-      MutexAutoLock lock(mMutex);
-      mActiveCallbacks.Remove(key);
-    }
+    mActiveCallbacks.Remove(key);
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "getUserMedia:response:deny")) {
     nsString key(aData);
     nsRefPtr<nsRunnable> runnable;
-    {
-      MutexAutoLock lock(mMutex);
-      if (mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
-        GetUserMediaRunnable* gUMRunnable =
+    if (mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
+      GetUserMediaRunnable* gUMRunnable =
           static_cast<GetUserMediaRunnable*>(runnable.get());
-        gUMRunnable->Denied();
-        mActiveCallbacks.Remove(key);
-      }
+      gUMRunnable->Denied();
+      mActiveCallbacks.Remove(key);
     }
+
     return NS_OK;
   }
 
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -60,162 +60,89 @@ class GetUserMediaNotificationEvent: pub
       }
       return NS_OK;
     }
 
   protected:
     GetUserMediaStatus mStatus;
 };
 
-typedef enum {
-  MEDIA_START,
-  MEDIA_STOP,
-  MEDIA_RELEASE
-} MediaOperation;
-
-// Generic class for running long media operations off the main thread, and
-// then (because nsDOMMediaStreams aren't threadsafe), re-sends itseld to
-// MainThread to release mStream.  This is part of the reason we use an
-// operation type - we can change it to repost the runnable to MainThread
-// to do operations with the nsDOMMediaStreams, while we can't assign or
-// copy a nsRefPtr to a nsDOMMediaStream
-class MediaOperationRunnable : public nsRunnable
-{
-public:
-  MediaOperationRunnable(MediaOperation aType,
-    nsDOMMediaStream* aStream,
-    MediaEngineSource* aAudioSource,
-    MediaEngineSource* aVideoSource)
-    : mType(aType)
-    , mAudioSource(aAudioSource)
-    , mVideoSource(aVideoSource)
-    , mStream(aStream)
-    {}
-
-  MediaOperationRunnable(MediaOperation aType,
-    SourceMediaStream* aStream,
-    MediaEngineSource* aAudioSource,
-    MediaEngineSource* aVideoSource)
-    : mType(aType)
-    , mAudioSource(aAudioSource)
-    , mVideoSource(aVideoSource)
-    , mStream(nullptr)
-    , mSourceStream(aStream)
-    {}
-
-  NS_IMETHOD
-  Run()
-  {
-    // No locking between these is required as all the callbacks (other
-    // than MEDIA_RELEASE) for the same MediaStream will occur on the same
-    // thread.
-    if (mStream) {
-      mSourceStream = mStream->GetStream()->AsSourceStream();
-    }
-    switch (mType) {
-      case MEDIA_START:
-        {
-          NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
-          nsresult rv;
-
-          mSourceStream->SetPullEnabled(true);
-
-          if (mAudioSource) {
-            rv = mAudioSource->Start(mSourceStream, kAudioTrack);
-            if (NS_FAILED(rv)) {
-              MM_LOG(("Starting audio failed, rv=%d",rv));
-            }
-          }
-          if (mVideoSource) {
-            rv = mVideoSource->Start(mSourceStream, kVideoTrack);
-            if (NS_FAILED(rv)) {
-              MM_LOG(("Starting video failed, rv=%d",rv));
-            }
-          }
-
-          MM_LOG(("started all sources"));
-          nsCOMPtr<GetUserMediaNotificationEvent> event =
-            new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING);
-
-          NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
-        }
-        break;
-
-      case MEDIA_STOP:
-        {
-          NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
-          if (mAudioSource) {
-            mAudioSource->Stop();
-            mAudioSource->Deallocate();
-          }
-          if (mVideoSource) {
-            mVideoSource->Stop();
-            mVideoSource->Deallocate();
-          }
-          // Do this after stopping all tracks with EndTrack()
-          mSourceStream->Finish();
-
-          nsCOMPtr<GetUserMediaNotificationEvent> event =
-            new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING);
-
-          NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
-        }
-        break;
-      case MEDIA_RELEASE:
-        // We go to MainThread to die
-        break;
-    }
-    if (mType != MEDIA_RELEASE) {
-      // nsDOMMediaStreams aren't thread-safe... sigh.
-      mType = MEDIA_RELEASE;
-      NS_DispatchToMainThread(this);
-    }
-    return NS_OK;
-  }
-
-private:
-  MediaOperation mType;
-  nsRefPtr<MediaEngineSource> mAudioSource;
-  nsRefPtr<MediaEngineSource> mVideoSource;
-  nsCOMPtr<nsDOMMediaStream> mStream;
-  SourceMediaStream *mSourceStream;
-};
-
 /**
  * This class is an implementation of MediaStreamListener. This is used
  * to Start() and Stop() the underlying MediaEngineSource when MediaStreams
  * are assigned and deassigned in content.
  */
 class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
 {
 public:
-  GetUserMediaCallbackMediaStreamListener(nsIThread *aThread,
-    nsDOMMediaStream* aStream,
+  GetUserMediaCallbackMediaStreamListener(nsDOMMediaStream* aStream,
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource)
-    : mMediaThread(aThread)
-    , mAudioSource(aAudioSource)
+    : mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mStream(aStream)
     , mValid(true) {}
 
   void
   Invalidate()
   {
-    nsRefPtr<MediaOperationRunnable> runnable;
+    if (!mValid) {
+      return;
+    }
+
+    mValid = false;
+    if (mAudioSource) {
+      mAudioSource->Stop();
+      mAudioSource->Deallocate();
+    }
+    if (mVideoSource) {
+      mVideoSource->Stop();
+      mVideoSource->Deallocate();
+    }
+    // Do this after stopping all tracks with EndTrack()
+    mStream->GetStream()->AsSourceStream()->Finish();
+
+    nsCOMPtr<GetUserMediaNotificationEvent> event =
+      new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING);
+
+    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
+  }
 
-    // We can't take a chance on blocking here, so proxy this to another
-    // thread.
-    // XXX FIX! I'm cheating and passing a raw pointer to the sourcestream
-    // which is valid as long as the mStream pointer here is.  Need a better solution.
-    runnable = new MediaOperationRunnable(MEDIA_STOP, 
-                                          mStream->GetStream()->AsSourceStream(),
-                                          mAudioSource, mVideoSource);
-    mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
+  void
+  NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming)
+  {
+    if (aConsuming == CONSUMED) {
+      nsresult rv;
+
+      SourceMediaStream* stream = mStream->GetStream()->AsSourceStream();
+      stream->SetPullEnabled(true);
 
+      if (mAudioSource) {
+        rv = mAudioSource->Start(stream, kAudioTrack);
+        if (NS_FAILED(rv)) {
+          MM_LOG(("Starting audio failed, rv=%d",rv));
+        }
+      }
+      if (mVideoSource) {
+        rv = mVideoSource->Start(stream, kVideoTrack);
+        if (NS_FAILED(rv)) {
+          MM_LOG(("Starting video failed, rv=%d",rv));
+        }
+      }
+
+      MM_LOG(("started all sources"));
+      nsCOMPtr<GetUserMediaNotificationEvent> event =
+        new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING);
+
+      NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
+      return;
+    }
+
+    // NOT_CONSUMED
+    Invalidate();
     return;
   }
 
   // Proxy NotifyPull() to sources
   void
   NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime)
   {
     // Currently audio sources ignore NotifyPull, but they could
@@ -224,17 +151,16 @@ public:
       mAudioSource->NotifyPull(aGraph, aDesiredTime);
     }
     if (mVideoSource) {
       mVideoSource->NotifyPull(aGraph, aDesiredTime);
     }
   }
 
 private:
-  nsCOMPtr<nsIThread> mMediaThread;
   nsRefPtr<MediaEngineSource> mAudioSource;
   nsRefPtr<MediaEngineSource> mVideoSource;
   nsCOMPtr<nsDOMMediaStream> mStream;
   bool mValid;
 };
 
 typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
@@ -273,27 +199,16 @@ public:
 
       nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
       obs->AddObserver(sSingleton, "xpcom-shutdown", false);
       obs->AddObserver(sSingleton, "getUserMedia:response:allow", false);
       obs->AddObserver(sSingleton, "getUserMedia:response:deny", false);
     }
     return sSingleton;
   }
-  static Mutex& GetMutex() {
-    return Get()->mMutex;
-  }
-  static nsIThread* GetThread() {
-    MutexAutoLock lock(Get()->mMutex); // only need to call Get() once
-    if (!sSingleton->mMediaThread) {
-      NS_NewThread(getter_AddRefs(sSingleton->mMediaThread));
-      MM_LOG(("New Media thread for gum"));
-    }
-    return sSingleton->mMediaThread;
-  }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   MediaEngine* GetBackend();
   WindowTable* GetActiveWindows();
 
   nsresult GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
@@ -303,29 +218,27 @@ public:
   nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
     nsIGetUserMediaDevicesSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
   void OnNavigation(uint64_t aWindowID);
 
 private:
   // Make private because we want only one instance of this class
   MediaManager()
-  : mMutex("mozilla::MediaManager")
-  , mBackend(nullptr)
+  : mBackend(nullptr)
   , mMediaThread(nullptr) {
     mActiveWindows.Init();
     mActiveCallbacks.Init();
   };
+  MediaManager(MediaManager const&) {};
 
   ~MediaManager() {
     delete mBackend;
   };
 
-  Mutex mMutex;
-  // protected with mMutex:
   MediaEngine* mBackend;
   nsCOMPtr<nsIThread> mMediaThread;
   WindowTable mActiveWindows;
   nsRefPtrHashtable<nsStringHashKey, nsRunnable> mActiveCallbacks;
 
   static nsRefPtr<MediaManager> sSingleton;
 };