Bug 1286096 - Move UpdateSingleSource pattern to MediaEngine base class for reuse. r=padenot
authorJan-Ivar Bruaroey <jib@mozilla.com>
Wed, 13 Jul 2016 16:07:03 -0400
changeset 332118 e3354c94965925a82cf4c2d56c20aa07ad79bd99
parent 332117 3b9c5f9d8a429e7b97ba54165934c46bdb777f49
child 332119 274a3c105eb5925b05251990c519f78b6d46f436
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1286096
milestone50.0a1
Bug 1286096 - Move UpdateSingleSource pattern to MediaEngine base class for reuse. r=padenot MozReview-Commit-ID: IJjZayOSxp4
dom/media/webrtc/MediaEngine.h
dom/media/webrtc/MediaEngineCameraVideoSource.h
dom/media/webrtc/MediaEngineDefault.h
dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
dom/media/webrtc/MediaEngineRemoteVideoSource.h
dom/media/webrtc/MediaEngineTabVideoSource.h
dom/media/webrtc/MediaEngineWebRTC.h
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MEDIAENGINE_H_
 #define MEDIAENGINE_H_
 
 #include "mozilla/RefPtr.h"
 #include "DOMMediaStream.h"
 #include "MediaStreamGraph.h"
+#include "MediaTrackConstraints.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 
 namespace mozilla {
 
 namespace dom {
 class Blob;
 } // namespace dom
@@ -168,28 +169,44 @@ public:
   virtual nsresult PhotoError(nsresult aRv) = 0;
 
 protected:
   virtual ~MediaEnginePhotoCallback() {}
 };
 
 /**
  * Common abstract base class for audio and video sources.
+ *
+ * By default, the base class implements Allocate and Deallocate using its
+ * UpdateSingleSource pattern, which manages allocation handles and calculates
+ * net constraints from competing allocations and updates a single shared device.
+ *
+ * Classes that don't operate as a single shared device can override Allocate
+ * and Deallocate and simply not pass the methods up.
  */
-class MediaEngineSource : public nsISupports
+class MediaEngineSource : public nsISupports,
+                          protected MediaConstraintsHelper
 {
 public:
   // code inside webrtc.org assumes these sizes; don't use anything smaller
   // without verifying it's ok
   static const unsigned int kMaxDeviceNameLength = 128;
   static const unsigned int kMaxUniqueIdLength = 256;
 
-  virtual ~MediaEngineSource() {}
+  virtual ~MediaEngineSource()
+  {
+    if (!mInShutdown) {
+      Shutdown();
+    }
+  }
 
-  virtual void Shutdown() = 0;
+  virtual void Shutdown()
+  {
+    mInShutdown = true;
+  };
 
   /* Populate the human readable name of this device in the nsAString */
   virtual void GetName(nsAString&) const = 0;
 
   /* Populate the UUID of this device in the nsACString */
   virtual void GetUUID(nsACString&) const = 0;
 
   class AllocationHandle
@@ -210,17 +227,40 @@ public:
   public:
     NormalizedConstraints mConstraints;
     nsCString mOrigin;
     MediaEnginePrefs mPrefs;
     nsString mDeviceId;
   };
 
   /* Release the device back to the system. */
-  virtual nsresult Deallocate(AllocationHandle* aHandle) = 0;
+  virtual nsresult Deallocate(AllocationHandle* aHandle)
+  {
+    MOZ_ASSERT(aHandle);
+    RefPtr<AllocationHandle> handle = aHandle;
+
+    class Comparator {
+    public:
+      static bool Equals(const RefPtr<AllocationHandle>& a,
+                         const RefPtr<AllocationHandle>& b) {
+        return a.get() == b.get();
+      }
+    };
+    MOZ_ASSERT(mRegisteredHandles.Contains(handle, Comparator()));
+    mRegisteredHandles.RemoveElementAt(mRegisteredHandles.IndexOf(handle, 0,
+                                                                  Comparator()));
+    if (mRegisteredHandles.Length() && !mInShutdown) {
+      // Whenever constraints are removed, other parties may get closer to ideal.
+      auto& first = mRegisteredHandles[0];
+      const char* badConstraint = nullptr;
+      return ReevaluateAllocation(nullptr, nullptr, first->mPrefs,
+                                  first->mDeviceId, &badConstraint);
+    }
+    return NS_OK;
+  }
 
   /* Start the device and add the track to the provided SourceMediaStream, with
    * the provided TrackID. You may start appending data to the track
    * immediately after. */
   virtual nsresult Start(SourceMediaStream*, TrackID, const PrincipalHandle&) = 0;
 
   /* tell the source if there are any direct listeners attached */
   virtual void SetDirectListeners(bool) = 0;
@@ -269,17 +309,30 @@ public:
    * a Start(). Only Allocate() may be called after a Deallocate(). */
 
   /* This call reserves but does not start the device. */
   virtual nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                             const MediaEnginePrefs &aPrefs,
                             const nsString& aDeviceId,
                             const nsACString& aOrigin,
                             AllocationHandle** aOutHandle,
-                            const char** aOutBadConstraint) = 0;
+                            const char** aOutBadConstraint)
+  {
+    MOZ_ASSERT(aOutHandle);
+    RefPtr<AllocationHandle> handle = new AllocationHandle(aConstraints, aOrigin,
+                                                           aPrefs, aDeviceId);
+    nsresult rv = ReevaluateAllocation(handle, nullptr, aPrefs, aDeviceId,
+                                       aOutBadConstraint);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    mRegisteredHandles.AppendElement(handle);
+    handle.forget(aOutHandle);
+    return NS_OK;
+  }
 
   virtual uint32_t GetBestFitnessDistance(
       const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
       const nsString& aDeviceId) const = 0;
 
   void GetSettings(dom::MediaTrackSettings& aOutSettings)
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -288,27 +341,103 @@ public:
 
 protected:
   // Only class' own members can be initialized in constructor initializer list.
   explicit MediaEngineSource(MediaEngineState aState)
     : mState(aState)
 #ifdef DEBUG
     , mOwningThread(PR_GetCurrentThread())
 #endif
+    , mInShutdown(false)
   {}
 
+  /* UpdateSingleSource - Centralized abstract function to implement in those
+   * cases where a single device is being shared between users. Should apply net
+   * constraints and restart the device as needed.
+   *
+   * aHandle           - New or existing handle, or null to update after removal.
+   * aNetConstraints   - Net constraints to be applied to the single device.
+   * aPrefs            - As passed in (in case of changes in about:config).
+   * aDeviceId         - As passed in (origin dependent).
+   * aOutBadConstraint - Result: nonzero if failed to apply. Name of culprit.
+   */
+
+  virtual nsresult
+  UpdateSingleSource(const AllocationHandle* aHandle,
+                     const NormalizedConstraints& aNetConstraints,
+                     const MediaEnginePrefs& aPrefs,
+                     const nsString& aDeviceId,
+                     const char** aOutBadConstraint) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  };
+
+  /* ReevaluateAllocation - Call to change constraints for an allocation of
+   * a single device. Manages allocation handles, calculates net constraints
+   * from all competing allocations, and calls UpdateSingleSource with the net
+   * result, to restart the single device as needed.
+   *
+   * aHandle            - New or existing handle, or null to update after removal.
+   * aConstraintsUpdate - Constraints to be applied to existing handle, or null.
+   * aPrefs             - As passed in (in case of changes from about:config).
+   * aDeviceId          - As passed in (origin-dependent id).
+   * aOutBadConstraint  - Result: nonzero if failed to apply. Name of culprit.
+   */
+
+  nsresult
+  ReevaluateAllocation(AllocationHandle* aHandle,
+                       NormalizedConstraints* aConstraintsUpdate,
+                       const MediaEnginePrefs& aPrefs,
+                       const nsString& aDeviceId,
+                       const char** aOutBadConstraint)
+  {
+    // aHandle and/or aConstraintsUpdate may be nullptr (see below)
+
+    AutoTArray<const NormalizedConstraints*, 10> allConstraints;
+    for (auto& registered : mRegisteredHandles) {
+      if (aConstraintsUpdate && registered.get() == aHandle) {
+        continue; // Don't count old constraints
+      }
+      allConstraints.AppendElement(&registered->mConstraints);
+    }
+    if (aConstraintsUpdate) {
+      allConstraints.AppendElement(aConstraintsUpdate);
+    } else if (aHandle) {
+      // In the case of AddShareOfSingleSource, the handle isn't registered yet.
+      allConstraints.AppendElement(&aHandle->mConstraints);
+    }
+
+    NormalizedConstraints netConstraints(allConstraints);
+    if (netConstraints.mBadConstraint) {
+      *aOutBadConstraint = netConstraints.mBadConstraint;
+      return NS_ERROR_FAILURE;
+    }
+
+    nsresult rv = UpdateSingleSource(aHandle, netConstraints, aPrefs, aDeviceId,
+                                     aOutBadConstraint);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    if (aHandle && aConstraintsUpdate) {
+      aHandle->mConstraints = *aConstraintsUpdate;
+    }
+    return NS_OK;
+  }
+
   void AssertIsOnOwningThread()
   {
     MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
   }
 
   MediaEngineState mState;
 #ifdef DEBUG
   PRThread* mOwningThread;
 #endif
+  nsTArray<RefPtr<AllocationHandle>> mRegisteredHandles;
+  bool mInShutdown;
+
   // Main-thread only:
   dom::MediaTrackSettings mSettings;
 };
 
 class MediaEngineVideoSource : public MediaEngineSource
 {
 public:
   virtual ~MediaEngineVideoSource() {}
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h
@@ -1,45 +1,42 @@
 /* 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/. */
 
 #ifndef MediaEngineCameraVideoSource_h
 #define MediaEngineCameraVideoSource_h
 
 #include "MediaEngine.h"
-#include "MediaTrackConstraints.h"
 
 #include "nsDirectoryServiceDefs.h"
 
 // conflicts with #include of scoped_ptr.h
 #undef FF
 #include "webrtc/video_engine/include/vie_capture.h"
 
 namespace mozilla {
 
 bool operator == (const webrtc::CaptureCapability& a,
                   const webrtc::CaptureCapability& b);
 bool operator != (const webrtc::CaptureCapability& a,
                   const webrtc::CaptureCapability& b);
 
-class MediaEngineCameraVideoSource : public MediaEngineVideoSource,
-                                     protected MediaConstraintsHelper
+class MediaEngineCameraVideoSource : public MediaEngineVideoSource
 {
 public:
   // Some subclasses use an index to track multiple instances.
   explicit MediaEngineCameraVideoSource(int aIndex,
                                         const char* aMonitorName = "Camera.Monitor")
     : MediaEngineVideoSource(kReleased)
     , mMonitor(aMonitorName)
     , mWidth(0)
     , mHeight(0)
     , mInitDone(false)
     , mHasDirectListeners(false)
-    , mNrAllocations(0)
     , mCaptureIndex(aIndex)
     , mTrackID(0)
   {}
 
   explicit MediaEngineCameraVideoSource(const char* aMonitorName = "Camera.Monitor")
     : MediaEngineCameraVideoSource(0, aMonitorName) {}
 
   void GetName(nsAString& aName) const override;
@@ -112,17 +109,16 @@ protected:
   RefPtr<layers::Image> mImage;
   RefPtr<layers::ImageContainer> mImageContainer;
   int mWidth, mHeight; // protected with mMonitor on Gonk due to different threading
   // end of data protected by mMonitor
 
 
   bool mInitDone;
   bool mHasDirectListeners;
-  int mNrAllocations; // When this becomes 0, we shut down HW
   int mCaptureIndex;
   TrackID mTrackID;
 
   webrtc::CaptureCapability mCapability;
 
   mutable nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities;
 private:
   nsString mDeviceName;
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -34,18 +34,16 @@ class MediaEngineDefault;
  * The default implementation of the MediaEngine interface.
  */
 class MediaEngineDefaultVideoSource : public nsITimerCallback,
                                       public MediaEngineCameraVideoSource
 {
 public:
   MediaEngineDefaultVideoSource();
 
-  void Shutdown() override {};
-
   void GetName(nsAString&) const override;
   void GetUUID(nsACString&) const override;
 
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                     const MediaEnginePrefs &aPrefs,
                     const nsString& aDeviceId,
                     const nsACString& aOrigin,
                     AllocationHandle** aOutHandle,
@@ -103,24 +101,21 @@ protected:
   MediaEnginePrefs mOpts;
   int mCb;
   int mCr;
 };
 
 class SineWaveGenerator;
 
 class MediaEngineDefaultAudioSource : public nsITimerCallback,
-                                      public MediaEngineAudioSource,
-                                      private MediaConstraintsHelper
+                                      public MediaEngineAudioSource
 {
 public:
   MediaEngineDefaultAudioSource();
 
-  void Shutdown() override {};
-
   void GetName(nsAString&) const override;
   void GetUUID(nsACString&) const override;
 
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                     const MediaEnginePrefs &aPrefs,
                     const nsString& aDeviceId,
                     const nsACString& aOrigin,
                     AllocationHandle** aOutHandle,
@@ -192,34 +187,33 @@ protected:
 
   SourceMediaStream* mSource;
   nsAutoPtr<SineWaveGenerator> mSineGenerator;
 };
 
 
 class MediaEngineDefault : public MediaEngine
 {
+  typedef MediaEngine Super;
 public:
   explicit MediaEngineDefault() : mMutex("mozilla::MediaEngineDefault") {}
 
   void EnumerateVideoDevices(dom::MediaSourceEnum,
                              nsTArray<RefPtr<MediaEngineVideoSource> >*) override;
   void EnumerateAudioDevices(dom::MediaSourceEnum,
                              nsTArray<RefPtr<MediaEngineAudioSource> >*) override;
   void Shutdown() override {
     MutexAutoLock lock(mMutex);
 
     mVSources.Clear();
     mASources.Clear();
   };
 
 private:
-  ~MediaEngineDefault() {
-    Shutdown();
-  }
+  ~MediaEngineDefault() {}
 
   Mutex mMutex;
   // protected with mMutex:
 
   nsTArray<RefPtr<MediaEngineVideoSource> > mVSources;
   nsTArray<RefPtr<MediaEngineAudioSource> > mASources;
 };
 
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -27,18 +27,17 @@ using dom::ConstrainLongRange;
 
 NS_IMPL_ISUPPORTS0(MediaEngineRemoteVideoSource)
 
 MediaEngineRemoteVideoSource::MediaEngineRemoteVideoSource(
   int aIndex, mozilla::camera::CaptureEngine aCapEngine,
   dom::MediaSourceEnum aMediaSource, const char* aMonitorName)
   : MediaEngineCameraVideoSource(aIndex, aMonitorName),
     mMediaSource(aMediaSource),
-    mCapEngine(aCapEngine),
-    mInShutdown(false)
+    mCapEngine(aCapEngine)
 {
   MOZ_ASSERT(aMediaSource != dom::MediaSourceEnum::Other);
   mSettings.mWidth.Construct(0);
   mSettings.mHeight.Construct(0);
   mSettings.mFrameRate.Construct(0);
   Init();
 }
 
@@ -67,17 +66,17 @@ MediaEngineRemoteVideoSource::Init()
 
 void
 MediaEngineRemoteVideoSource::Shutdown()
 {
   LOG((__PRETTY_FUNCTION__));
   if (!mInitDone) {
     return;
   }
-  mInShutdown = true;
+  Super::Shutdown();
   if (mState == kStarted) {
     SourceMediaStream *source;
     bool empty;
 
     while (1) {
       {
         MonitorAutoLock lock(mMonitor);
         empty = mSources.IsEmpty();
@@ -114,79 +113,53 @@ MediaEngineRemoteVideoSource::Allocate(
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
 
   if (!mInitDone) {
     LOG(("Init not done"));
     return NS_ERROR_FAILURE;
   }
 
-  RefPtr<AllocationHandle> handle = new AllocationHandle(aConstraints, aOrigin,
-                                                         aPrefs, aDeviceId);
-
-  nsresult rv = UpdateNew(handle, aPrefs, aDeviceId, aOutBadConstraint);
+  nsresult rv = Super::Allocate(aConstraints, aPrefs, aDeviceId, aOrigin,
+                                aOutHandle, aOutBadConstraint);
   if (NS_FAILED(rv)) {
     return rv;
   }
   if (mState == kStarted &&
       MOZ_LOG_TEST(GetMediaManagerLog(), mozilla::LogLevel::Debug)) {
     MonitorAutoLock lock(mMonitor);
     if (mSources.IsEmpty()) {
       MOZ_ASSERT(mPrincipalHandles.IsEmpty());
       LOG(("Video device %d reallocated", mCaptureIndex));
     } else {
       LOG(("Video device %d allocated shared", mCaptureIndex));
     }
   }
-  mRegisteredHandles.AppendElement(handle);
-  ++mNrAllocations;
-  handle.forget(aOutHandle);
   return NS_OK;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Deallocate(AllocationHandle* aHandle)
 {
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
-  MOZ_ASSERT(aHandle);
-  RefPtr<AllocationHandle> handle = aHandle;
 
-  class Comparator {
-  public:
-    static bool Equals(const RefPtr<AllocationHandle>& a,
-                       const RefPtr<AllocationHandle>& b) {
-      return a.get() == b.get();
-    }
-  };
-  MOZ_ASSERT(mRegisteredHandles.Contains(handle, Comparator()));
-  mRegisteredHandles.RemoveElementAt(mRegisteredHandles.IndexOf(handle, 0,
-                                                                Comparator()));
-  --mNrAllocations;
-  MOZ_ASSERT(mNrAllocations >= 0, "Double-deallocations are prohibited");
+  Super::Deallocate(aHandle);
 
-  if (mNrAllocations == 0) {
-    MOZ_ASSERT(!mRegisteredHandles.Length());
+  if (!mRegisteredHandles.Length()) {
     if (mState != kStopped && mState != kAllocated) {
       return NS_ERROR_FAILURE;
     }
     mozilla::camera::GetChildAndCall(
       &mozilla::camera::CamerasChild::ReleaseCaptureDevice,
       mCapEngine, mCaptureIndex);
     mState = kReleased;
     LOG(("Video device %d deallocated", mCaptureIndex));
   } else {
     LOG(("Video device %d deallocated but still in use", mCaptureIndex));
-    MOZ_ASSERT(mRegisteredHandles.Length());
-    if (!mInShutdown) {
-      // Whenever constraints are removed, other parties may get closer to ideal.
-      auto& first = mRegisteredHandles[0];
-      const char* badConstraint = nullptr;
-      return UpdateRemove(first->mPrefs, first->mDeviceId, &badConstraint);
-    }
   }
   return NS_OK;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Start(SourceMediaStream* aStream, TrackID aID,
                                     const PrincipalHandle& aPrincipalHandle)
 {
@@ -275,58 +248,36 @@ MediaEngineRemoteVideoSource::Restart(Al
 {
   AssertIsOnOwningThread();
   if (!mInitDone) {
     LOG(("Init not done"));
     return NS_ERROR_FAILURE;
   }
   MOZ_ASSERT(aHandle);
   NormalizedConstraints constraints(aConstraints);
-  return UpdateExisting(aHandle, &constraints, aPrefs, aDeviceId, aOutBadConstraint);
+  return ReevaluateAllocation(aHandle, &constraints, aPrefs, aDeviceId,
+                              aOutBadConstraint);
 }
 
 nsresult
-MediaEngineRemoteVideoSource::UpdateExisting(AllocationHandle* aHandle,
-                                             NormalizedConstraints* aNewConstraints,
-                                             const MediaEnginePrefs& aPrefs,
-                                             const nsString& aDeviceId,
-                                             const char** aOutBadConstraint)
+MediaEngineRemoteVideoSource::UpdateSingleSource(
+    const AllocationHandle* aHandle,
+    const NormalizedConstraints& aNetConstraints,
+    const MediaEnginePrefs& aPrefs,
+    const nsString& aDeviceId,
+    const char** aOutBadConstraint)
 {
-  // aHandle and/or aNewConstraints may be nullptr
-
-  AutoTArray<const NormalizedConstraints*, 10> allConstraints;
-  for (auto& registered : mRegisteredHandles) {
-    if (aNewConstraints && registered.get() == aHandle) {
-      continue; // Don't count old constraints
-    }
-    allConstraints.AppendElement(&registered->mConstraints);
-  }
-  if (aNewConstraints) {
-    allConstraints.AppendElement(aNewConstraints);
-  } else if (aHandle) {
-    // In the case of UpdateNew, the handle isn't registered yet.
-    allConstraints.AppendElement(&aHandle->mConstraints);
-  }
-
-  NormalizedConstraints netConstraints(allConstraints);
-  if (netConstraints.mBadConstraint) {
-    *aOutBadConstraint = netConstraints.mBadConstraint;
-    return NS_ERROR_FAILURE;
-  }
-
-  if (!ChooseCapability(netConstraints, aPrefs, aDeviceId)) {
-    *aOutBadConstraint = FindBadConstraint(netConstraints, *this, aDeviceId);
+  if (!ChooseCapability(aNetConstraints, aPrefs, aDeviceId)) {
+    *aOutBadConstraint = FindBadConstraint(aNetConstraints, *this, aDeviceId);
     return NS_ERROR_FAILURE;
   }
 
   switch (mState) {
     case kReleased:
       MOZ_ASSERT(aHandle);
-      MOZ_ASSERT(!aNewConstraints);
-      MOZ_ASSERT(!mRegisteredHandles.Length());
       if (camera::GetChildAndCall(&camera::CamerasChild::AllocateCaptureDevice,
                                   mCapEngine, GetUUID().get(),
                                   kMaxUniqueIdLength, mCaptureIndex,
                                   aHandle->mOrigin)) {
         return NS_ERROR_FAILURE;
       }
       mState = kAllocated;
       SetLastCapability(mCapability);
@@ -348,19 +299,16 @@ MediaEngineRemoteVideoSource::UpdateExis
       }
       break;
 
     default:
       LOG(("Video device %d %s in ignored state %d", mCaptureIndex,
              (aHandle? aHandle->mOrigin.get() : ""), mState));
       break;
   }
-  if (aHandle && aNewConstraints) {
-    aHandle->mConstraints = *aNewConstraints;
-  }
   return NS_OK;
 }
 
 void
 MediaEngineRemoteVideoSource::SetLastCapability(
     const webrtc::CaptureCapability& aCapability)
 {
   mLastCapability = mCapability;
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -45,16 +45,17 @@ class I420VideoFrame;
 namespace mozilla {
 
 /**
  * The WebRTC implementation of the MediaEngine interface.
  */
 class MediaEngineRemoteVideoSource : public MediaEngineCameraVideoSource,
                                      public webrtc::ExternalRenderer
 {
+  typedef MediaEngineCameraVideoSource Super;
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   // ExternalRenderer
   int FrameSizeChange(unsigned int w, unsigned int h,
                       unsigned int streams) override;
   int DeliverFrame(unsigned char* buffer,
                    size_t size,
@@ -98,62 +99,34 @@ public:
                         const MediaEnginePrefs &aPrefs,
                         const nsString& aDeviceId) override;
 
   void Refresh(int aIndex);
 
   void Shutdown() override;
 
 protected:
-  ~MediaEngineRemoteVideoSource() { Shutdown(); }
+  ~MediaEngineRemoteVideoSource() { }
 
 private:
   // Initialize the needed Video engine interfaces.
   void Init();
   size_t NumCapabilities() const override;
   void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) const override;
   void SetLastCapability(const webrtc::CaptureCapability& aCapability);
 
-  /* UpdateExisting - Centralized function to apply constraints and restart
-   * device as needed, considering all allocations and changes to one.
-   *
-   * aHandle           - New or existing handle, or null to update after removal.
-   * aNewConstraints   - Constraints to be applied to existing handle, or null.
-   * aPrefs            - As passed in (in case of changes in about:config).
-   * aDeviceId         - As passed in (origin dependent).
-   * aOutBadConstraint - Result: nonzero if failed to apply. Name of culprit.
-   */
-
   nsresult
-  UpdateExisting(AllocationHandle* aHandle,
-                 NormalizedConstraints* aNewConstraints,
-                 const MediaEnginePrefs& aPrefs,
-                 const nsString& aDeviceId,
-                 const char** aOutBadConstraint);
-
-  nsresult
-  UpdateNew(AllocationHandle* aHandle,
-            const MediaEnginePrefs& aPrefs,
-            const nsString& aDeviceId,
-            const char** aOutBadConstraint) {
-    return UpdateExisting(aHandle, nullptr, aPrefs, aDeviceId, aOutBadConstraint);
-  }
-
-  nsresult
-  UpdateRemove(const MediaEnginePrefs& aPrefs,
-               const nsString& aDeviceId,
-               const char** aOutBadConstraint) {
-    return UpdateExisting(nullptr, nullptr, aPrefs, aDeviceId, aOutBadConstraint);
-  }
+  UpdateSingleSource(const AllocationHandle* aHandle,
+                     const NormalizedConstraints& aNetConstraints,
+                     const MediaEnginePrefs& aPrefs,
+                     const nsString& aDeviceId,
+                     const char** aOutBadConstraint) override;
 
   dom::MediaSourceEnum mMediaSource; // source of media (camera | application | screen)
   mozilla::camera::CaptureEngine mCapEngine;
 
-  nsTArray<RefPtr<AllocationHandle>> mRegisteredHandles;
-
   // To only restart camera when needed, we keep track previous settings.
   webrtc::CaptureCapability mLastCapability;
-  bool mInShutdown;
 };
 
 }
 
 #endif /* MEDIAENGINE_REMOTE_VIDEO_SOURCE_H_ */
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -14,17 +14,16 @@ namespace mozilla {
 
 class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventListener, nsITimerCallback {
   public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIDOMEVENTLISTENER
     NS_DECL_NSITIMERCALLBACK
     MediaEngineTabVideoSource();
 
-    void Shutdown() override {};
     void GetName(nsAString_internal&) const override;
     void GetUUID(nsACString_internal&) const override;
     nsresult Allocate(const dom::MediaTrackConstraints &,
                       const mozilla::MediaEnginePrefs&,
                       const nsString& aDeviceId,
                       const nsACString& aOrigin,
                       AllocationHandle** aOutHandle,
                       const char** aOutBadConstraint) override;
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -86,20 +86,16 @@ public:
     return NS_OK;
   }
   nsresult Deallocate(AllocationHandle* aHandle) override
   {
     // Nothing to do here, everything is managed in MediaManager.cpp
     MOZ_ASSERT(!aHandle);
     return NS_OK;
   }
-  void Shutdown() override
-  {
-    // Nothing to do here, everything is managed in MediaManager.cpp
-  }
   nsresult Start(SourceMediaStream* aMediaStream,
                  TrackID aId,
                  const PrincipalHandle& aPrincipalHandle) override;
   nsresult Stop(SourceMediaStream* aMediaStream, TrackID aId) override;
   nsresult Restart(AllocationHandle* aHandle,
                    const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId,
@@ -134,17 +130,17 @@ public:
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   uint32_t GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
     const nsString& aDeviceId) const override;
 
 protected:
-  virtual ~MediaEngineWebRTCAudioCaptureSource() { Shutdown(); }
+  virtual ~MediaEngineWebRTCAudioCaptureSource() {}
   nsCString mUUID;
 };
 
 // Small subset of VoEHardware
 class AudioInput
 {
 public:
   explicit AudioInput(webrtc::VoiceEngine* aVoiceEngine) : mVoiceEngine(aVoiceEngine) {};
@@ -414,19 +410,19 @@ public:
   }
 
 private:
   Mutex mMutex;
   RefPtr<MediaEngineAudioSource> mAudioSource;
 };
 
 class MediaEngineWebRTCMicrophoneSource : public MediaEngineAudioSource,
-                                          public webrtc::VoEMediaProcess,
-                                          private MediaConstraintsHelper
+                                          public webrtc::VoEMediaProcess
 {
+  typedef MediaEngineAudioSource Super;
 public:
   MediaEngineWebRTCMicrophoneSource(nsIThread* aThread,
                                     webrtc::VoiceEngine* aVoiceEnginePtr,
                                     mozilla::AudioInput* aAudioInput,
                                     int aIndex,
                                     const char* name,
                                     const char* uuid)
     : MediaEngineAudioSource(kReleased)
@@ -510,19 +506,17 @@ public:
                int16_t audio10ms[], int length,
                int samplingFreq, bool isStereo) override;
 
   void Shutdown() override;
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
 protected:
-  ~MediaEngineWebRTCMicrophoneSource() {
-    Shutdown();
-  }
+  ~MediaEngineWebRTCMicrophoneSource() {}
 
 private:
   // These allocate/configure and release the channel
   bool AllocChannel();
   void FreeChannel();
   // These start/stop VoEBase and associated interfaces
   bool InitEngine();
   void DeInitEngine();
@@ -586,33 +580,33 @@ private:
   // mSkipProcessing is true if none of the processing passes are enabled,
   // because of prefs or constraints. This allows simply copying the audio into
   // the MSG, skipping resampling and the whole webrtc.org code.
   bool mSkipProcessing;
 };
 
 class MediaEngineWebRTC : public MediaEngine
 {
+  typedef MediaEngine Super;
 public:
   explicit MediaEngineWebRTC(MediaEnginePrefs& aPrefs);
 
   // Clients should ensure to clean-up sources video/audio sources
   // before invoking Shutdown on this class.
   void Shutdown() override;
 
   // Returns whether the host supports duplex audio stream.
   bool SupportsDuplex();
 
   void EnumerateVideoDevices(dom::MediaSourceEnum,
                              nsTArray<RefPtr<MediaEngineVideoSource>>*) override;
   void EnumerateAudioDevices(dom::MediaSourceEnum,
                              nsTArray<RefPtr<MediaEngineAudioSource>>*) override;
 private:
   ~MediaEngineWebRTC() {
-    Shutdown();
 #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
     AsyncLatencyLogger::Get()->Release();
 #endif
     gFarendObserver = nullptr;
   }
 
   nsCOMPtr<nsIThread> mThread;
 
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -709,16 +709,17 @@ MediaEngineWebRTCMicrophoneSource::FreeC
     mChannel = -1;
   }
   mState = kReleased;
 }
 
 void
 MediaEngineWebRTCMicrophoneSource::Shutdown()
 {
+  Super::Shutdown();
   if (mListener) {
     // breaks a cycle, since the WebRTCAudioDataListener has a RefPtr to us
     mListener->Shutdown();
     // Don't release the webrtc.org pointers yet until the Listener is (async) shutdown
     mListener = nullptr;
   }
 
   if (mState == kStarted) {