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 349154 e3354c94965925a82cf4c2d56c20aa07ad79bd99
parent 349153 3b9c5f9d8a429e7b97ba54165934c46bdb777f49
child 349155 274a3c105eb5925b05251990c519f78b6d46f436
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1286096
milestone50.0a1
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
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) {