Bug 1213517 - Lift correct constraint out of lower-level code for OverconstrainedError. draft
authorJan-Ivar Bruaroey <jib@mozilla.com>
Mon, 20 Jun 2016 20:15:39 -0400
changeset 388777 09ff1385083590ce8b27cd83e857be7516c8d4de
parent 388776 a7990ecb80257445e725b9a21b9b5b6aa57f435c
child 388778 cf0d912ad220774d0b3661864ac01b51186fc8a5
push id23232
push userjbruaroey@mozilla.com
push dateSun, 17 Jul 2016 21:00:46 +0000
bugs1213517
milestone50.0a1
Bug 1213517 - Lift correct constraint out of lower-level code for OverconstrainedError. MozReview-Commit-ID: EWUjVBUrAps
dom/media/webrtc/MediaEngine.h
dom/media/webrtc/MediaEngineCameraVideoSource.cpp
dom/media/webrtc/MediaEngineCameraVideoSource.h
dom/media/webrtc/MediaEngineDefault.cpp
dom/media/webrtc/MediaEngineDefault.h
dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
dom/media/webrtc/MediaEngineRemoteVideoSource.h
dom/media/webrtc/MediaEngineTabVideoSource.cpp
dom/media/webrtc/MediaEngineTabVideoSource.h
dom/media/webrtc/MediaEngineWebRTC.h
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
dom/media/webrtc/MediaTrackConstraints.cpp
dom/media/webrtc/MediaTrackConstraints.h
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -109,20 +109,20 @@ public:
   static const unsigned int kMaxDeviceNameLength = 128;
   static const unsigned int kMaxUniqueIdLength = 256;
 
   virtual ~MediaEngineSource() {}
 
   virtual void Shutdown() = 0;
 
   /* Populate the human readable name of this device in the nsAString */
-  virtual void GetName(nsAString&) = 0;
+  virtual void GetName(nsAString&) const = 0;
 
   /* Populate the UUID of this device in the nsACString */
-  virtual void GetUUID(nsACString&) = 0;
+  virtual void GetUUID(nsACString&) const = 0;
 
   class BaseAllocationHandle
   {
   public:
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseAllocationHandle);
   protected:
     virtual ~BaseAllocationHandle() {}
   };
@@ -190,17 +190,17 @@ public:
                             const MediaEnginePrefs &aPrefs,
                             const nsString& aDeviceId,
                             const nsACString& aOrigin,
                             BaseAllocationHandle** aOutHandle,
                             const char** aOutBadConstraint) = 0;
 
   virtual uint32_t GetBestFitnessDistance(
       const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-      const nsString& aDeviceId) = 0;
+      const nsString& aDeviceId) const = 0;
 
 protected:
   // Only class' own members can be initialized in constructor initializer list.
   explicit MediaEngineSource(MediaEngineState aState)
     : mState(aState)
 #ifdef DEBUG
     , mOwningThread(PR_GetCurrentThread())
 #endif
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.cpp
@@ -34,34 +34,34 @@ bool MediaEngineCameraVideoSource::Appen
   // This can fail if either a) we haven't added the track yet, or b)
   // we've removed or finished the track.
   return aSource->AppendToTrack(aID, &(segment));
 }
 
 // Sub-classes (B2G or desktop) should overload one of both of these two methods
 // to provide capabilities
 size_t
-MediaEngineCameraVideoSource::NumCapabilities()
+MediaEngineCameraVideoSource::NumCapabilities() const
 {
   return mHardcodedCapabilities.Length();
 }
 
 void
 MediaEngineCameraVideoSource::GetCapability(size_t aIndex,
-                                            webrtc::CaptureCapability& aOut)
+                                            webrtc::CaptureCapability& aOut) const
 {
   MOZ_ASSERT(aIndex < mHardcodedCapabilities.Length());
   aOut = mHardcodedCapabilities[aIndex];
 }
 
 uint32_t
 MediaEngineCameraVideoSource::GetFitnessDistance(
     const webrtc::CaptureCapability& aCandidate,
     const NormalizedConstraintSet &aConstraints,
-    const nsString& aDeviceId)
+    const nsString& aDeviceId) const
 {
   // Treat width|height|frameRate == 0 on capability as "can do any".
   // This allows for orthogonal capabilities that are not in discrete steps.
 
   uint64_t distance =
     uint64_t(FitnessDistance(aDeviceId, aConstraints.mDeviceId)) +
     uint64_t(FitnessDistance(mFacingMode, aConstraints.mFacingMode)) +
     uint64_t(aCandidate.width? FitnessDistance(int32_t(aCandidate.width),
@@ -99,17 +99,17 @@ MediaEngineCameraVideoSource::TrimLessFi
 // Plain values are treated as Ideal in the first ConstraintSet.
 // Plain values are treated as Exact in subsequent ConstraintSets.
 // Infinity = UINT32_MAX e.g. device cannot satisfy accumulated ConstraintSets.
 // A finite result may be used to calculate this device's ranking as a choice.
 
 uint32_t
 MediaEngineCameraVideoSource::GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-    const nsString& aDeviceId)
+    const nsString& aDeviceId) const
 {
   size_t num = NumCapabilities();
 
   CapabilitySet candidateSet;
   for (size_t i = 0; i < num; i++) {
     candidateSet.AppendElement(i);
   }
 
@@ -359,35 +359,35 @@ MediaEngineCameraVideoSource::SetName(ns
     mFacingMode.Assign(NS_ConvertUTF8toUTF16(
         VideoFacingModeEnumValues::strings[uint32_t(facingMode)].value));
   } else {
     mFacingMode.Truncate();
   }
 }
 
 void
-MediaEngineCameraVideoSource::GetName(nsAString& aName)
+MediaEngineCameraVideoSource::GetName(nsAString& aName) const
 {
   aName = mDeviceName;
 }
 
 void
 MediaEngineCameraVideoSource::SetUUID(const char* aUUID)
 {
   mUniqueId.Assign(aUUID);
 }
 
 void
-MediaEngineCameraVideoSource::GetUUID(nsACString& aUUID)
+MediaEngineCameraVideoSource::GetUUID(nsACString& aUUID) const
 {
   aUUID = mUniqueId;
 }
 
 const nsCString&
-MediaEngineCameraVideoSource::GetUUID()
+MediaEngineCameraVideoSource::GetUUID() const
 {
   return mUniqueId;
 }
 
 
 void
 MediaEngineCameraVideoSource::SetDirectListeners(bool aHasDirectListeners)
 {
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h
@@ -12,50 +12,50 @@
 
 // conflicts with #include of scoped_ptr.h
 #undef FF
 #include "webrtc/video_engine/include/vie_capture.h"
 
 namespace mozilla {
 
 class MediaEngineCameraVideoSource : public MediaEngineVideoSource,
-                                     private MediaConstraintsHelper
+                                     protected MediaConstraintsHelper
 {
 public:
   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)
   {}
 
 
-  void GetName(nsAString& aName) override;
-  void GetUUID(nsACString& aUUID) override;
+  void GetName(nsAString& aName) const override;
+  void GetUUID(nsACString& aUUID) const override;
   void SetDirectListeners(bool aHasListeners) override;
 
   bool IsFake() override
   {
     return false;
   }
 
   nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) override
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   uint32_t GetBestFitnessDistance(
       const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-      const nsString& aDeviceId) override;
+      const nsString& aDeviceId) const override;
 
   void Shutdown() override {};
 
 protected:
   struct CapabilityCandidate {
     explicit CapabilityCandidate(uint8_t index, uint32_t distance = 0)
     : mIndex(index), mDistance(distance) {}
 
@@ -69,30 +69,30 @@ protected:
   // guts for appending data to the MSG track
   virtual bool AppendToTrack(SourceMediaStream* aSource,
                              layers::Image* aImage,
                              TrackID aID,
                              StreamTime delta,
                              const PrincipalHandle& aPrincipalHandle);
   uint32_t GetFitnessDistance(const webrtc::CaptureCapability& aCandidate,
                               const NormalizedConstraintSet &aConstraints,
-                              const nsString& aDeviceId);
+                              const nsString& aDeviceId) const;
   static void TrimLessFitCandidates(CapabilitySet& set);
   static void LogConstraints(const NormalizedConstraintSet& aConstraints);
   static void LogCapability(const char* aHeader,
                             const webrtc::CaptureCapability &aCapability,
                             uint32_t aDistance);
-  virtual size_t NumCapabilities();
-  virtual void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut);
+  virtual size_t NumCapabilities() const;
+  virtual void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) const;
   virtual bool ChooseCapability(const NormalizedConstraints &aConstraints,
                                 const MediaEnginePrefs &aPrefs,
                                 const nsString& aDeviceId);
   void SetName(nsString aName);
   void SetUUID(const char* aUUID);
-  const nsCString& GetUUID(); // protected access
+  const nsCString& GetUUID() const; // protected access
 
   // Engine variables.
 
   // mMonitor protects mImage access/changes, and transitions of mState
   // from kStarted to kStopped (which are combined with EndTrack() and
   // image changes).
   // mMonitor also protects mSources[] and mPrincipalHandles[] access/changes.
   // mSources[] and mPrincipalHandles[] are accessed from webrtc threads.
@@ -110,17 +110,17 @@ protected:
   bool mInitDone;
   bool mHasDirectListeners;
   int mNrAllocations; // When this becomes 0, we shut down HW
   int mCaptureIndex;
   TrackID mTrackID;
 
   webrtc::CaptureCapability mCapability;
 
-  nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities; // For OSX & B2G
+  mutable nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities;
 private:
   nsString mDeviceName;
   nsCString mUniqueId;
   nsString mFacingMode;
 };
 
 
 } // namespace mozilla
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -52,33 +52,33 @@ MediaEngineDefaultVideoSource::MediaEngi
   mImageContainer =
     layers::LayerManager::CreateImageContainer(layers::ImageContainer::ASYNCHRONOUS);
 }
 
 MediaEngineDefaultVideoSource::~MediaEngineDefaultVideoSource()
 {}
 
 void
-MediaEngineDefaultVideoSource::GetName(nsAString& aName)
+MediaEngineDefaultVideoSource::GetName(nsAString& aName) const
 {
   aName.AssignLiteral(MOZ_UTF16("Default Video Device"));
   return;
 }
 
 void
-MediaEngineDefaultVideoSource::GetUUID(nsACString& aUUID)
+MediaEngineDefaultVideoSource::GetUUID(nsACString& aUUID) const
 {
   aUUID.AssignLiteral("1041FCBD-3F12-4F7B-9E9B-1EC556DD5676");
   return;
 }
 
 uint32_t
 MediaEngineDefaultVideoSource::GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-    const nsString& aDeviceId)
+    const nsString& aDeviceId) const
 {
   uint32_t distance = 0;
 #ifdef MOZ_WEBRTC
   for (const auto* cs : aConstraintSets) {
     distance = GetMinimumFitnessDistance(*cs, aDeviceId);
     break; // distance is read from first entry only
   }
 #endif
@@ -380,33 +380,33 @@ MediaEngineDefaultAudioSource::MediaEngi
   , mTimer(nullptr)
 {
 }
 
 MediaEngineDefaultAudioSource::~MediaEngineDefaultAudioSource()
 {}
 
 void
-MediaEngineDefaultAudioSource::GetName(nsAString& aName)
+MediaEngineDefaultAudioSource::GetName(nsAString& aName) const
 {
   aName.AssignLiteral(MOZ_UTF16("Default Audio Device"));
   return;
 }
 
 void
-MediaEngineDefaultAudioSource::GetUUID(nsACString& aUUID)
+MediaEngineDefaultAudioSource::GetUUID(nsACString& aUUID) const
 {
   aUUID.AssignLiteral("B7CBD7C1-53EF-42F9-8353-73F61C70C092");
   return;
 }
 
 uint32_t
 MediaEngineDefaultAudioSource::GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-    const nsString& aDeviceId)
+    const nsString& aDeviceId) const
 {
   uint32_t distance = 0;
 #ifdef MOZ_WEBRTC
   for (const auto* cs : aConstraintSets) {
     distance = GetMinimumFitnessDistance(*cs, aDeviceId);
     break; // distance is read from first entry only
   }
 #endif
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -36,18 +36,18 @@ class MediaEngineDefaultVideoSource : pu
                                       public MediaEngineVideoSource,
                                       private MediaConstraintsHelper
 {
 public:
   MediaEngineDefaultVideoSource();
 
   void Shutdown() override {};
 
-  void GetName(nsAString&) override;
-  void GetUUID(nsACString&) 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,
                     BaseAllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override;
   nsresult Deallocate(BaseAllocationHandle* aHandle) override;
@@ -61,17 +61,17 @@ public:
   void SetDirectListeners(bool aHasDirectListeners) override {};
   void NotifyPull(MediaStreamGraph* aGraph,
                   SourceMediaStream *aSource,
                   TrackID aId,
                   StreamTime aDesiredTime,
                   const PrincipalHandle& aPrincipalHandle) override;
   uint32_t GetBestFitnessDistance(
       const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-      const nsString& aDeviceId) override;
+      const nsString& aDeviceId) const override;
 
   bool IsFake() override {
     return true;
   }
 
   dom::MediaSourceEnum GetMediaSource() const override {
     return dom::MediaSourceEnum::Camera;
   }
@@ -111,18 +111,18 @@ class MediaEngineDefaultAudioSource : pu
                                       public MediaEngineAudioSource,
                                       private MediaConstraintsHelper
 {
 public:
   MediaEngineDefaultAudioSource();
 
   void Shutdown() override {};
 
-  void GetName(nsAString&) override;
-  void GetUUID(nsACString&) 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,
                     BaseAllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override;
   nsresult Deallocate(BaseAllocationHandle* aHandle) override;
@@ -170,17 +170,17 @@ public:
 
   nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) override
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   uint32_t GetBestFitnessDistance(
       const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-      const nsString& aDeviceId) override;
+      const nsString& aDeviceId) const override;
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
 
 protected:
   ~MediaEngineDefaultAudioSource();
 
   TrackID mTrackID;
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -123,16 +123,17 @@ MediaEngineRemoteVideoSource::Allocate(
 
   NormalizedConstraints netConstraints(allConstraints);
   if (netConstraints.mBadConstraint) {
     *aOutBadConstraint = netConstraints.mBadConstraint;
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!ChooseCapability(netConstraints, aPrefs, aDeviceId)) {
+    *aOutBadConstraint = FindBadConstraint(netConstraints, *this, aDeviceId);
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (mState == kReleased) {
     if (mozilla::camera::GetChildAndCall(
       &mozilla::camera::CamerasChild::AllocateCaptureDevice,
       mCapEngine, GetUUID().get(), kMaxUniqueIdLength, mCaptureIndex, aOrigin)) {
       return NS_ERROR_FAILURE;
@@ -309,16 +310,17 @@ MediaEngineRemoteVideoSource::Restart(Ba
 
   NormalizedConstraints netConstraints(allConstraints);
   if (netConstraints.mBadConstraint) {
     *aOutBadConstraint = netConstraints.mBadConstraint;
     return NS_ERROR_FAILURE;
   }
 
   if (!ChooseCapability(netConstraints, aPrefs, aDeviceId)) {
+    *aOutBadConstraint = FindBadConstraint(netConstraints, *this, aDeviceId);
     return NS_ERROR_FAILURE;
   }
   if (mState != kStarted) {
     return NS_OK;
   }
 
   mozilla::camera::GetChildAndCall(
     &mozilla::camera::CamerasChild::StopCapture,
@@ -421,17 +423,17 @@ MediaEngineRemoteVideoSource::DeliverFra
   // We'll push the frame into the MSG on the next NotifyPull. This will avoid
   // swamping the MSG with frames should it be taking longer than normal to run
   // an iteration.
 
   return 0;
 }
 
 size_t
-MediaEngineRemoteVideoSource::NumCapabilities()
+MediaEngineRemoteVideoSource::NumCapabilities() const
 {
   int num = mozilla::camera::GetChildAndCall(
       &mozilla::camera::CamerasChild::NumberOfCapabilities,
       mCapEngine,
       GetUUID().get());
   if (num > 0) {
     return num;
   }
@@ -504,17 +506,17 @@ MediaEngineRemoteVideoSource::ChooseCapa
     default:
       return MediaEngineCameraVideoSource::ChooseCapability(aConstraints, aPrefs, aDeviceId);
   }
 
 }
 
 void
 MediaEngineRemoteVideoSource::GetCapability(size_t aIndex,
-                                            webrtc::CaptureCapability& aOut)
+                                            webrtc::CaptureCapability& aOut) const
 {
   if (!mHardcodedCapabilities.IsEmpty()) {
     MediaEngineCameraVideoSource::GetCapability(aIndex, aOut);
   }
   mozilla::camera::GetChildAndCall(
     &mozilla::camera::CamerasChild::GetCaptureCapability,
     mCapEngine,
     GetUUID().get(),
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -114,18 +114,18 @@ public:
   void Shutdown() override;
 
 protected:
   ~MediaEngineRemoteVideoSource() { Shutdown(); }
 
 private:
   // Initialize the needed Video engine interfaces.
   void Init();
-  size_t NumCapabilities() override;
-  void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) override;
+  size_t NumCapabilities() const override;
+  void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) const override;
 
   dom::MediaSourceEnum mMediaSource; // source of media (camera | application | screen)
   mozilla::camera::CaptureEngine mCapEngine;
 
   nsTArray<RefPtr<AllocationHandle>> mRegisteredHandles;
 };
 
 }
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -115,23 +115,23 @@ MediaEngineTabVideoSource::InitRunnable:
     MOZ_ASSERT(mVideoSource->mWindow);
   }
   nsCOMPtr<nsIRunnable> start(new StartRunnable(mVideoSource));
   start->Run();
   return NS_OK;
 }
 
 void
-MediaEngineTabVideoSource::GetName(nsAString_internal& aName)
+MediaEngineTabVideoSource::GetName(nsAString_internal& aName) const
 {
   aName.AssignLiteral(MOZ_UTF16("&getUserMedia.videoSource.tabShare;"));
 }
 
 void
-MediaEngineTabVideoSource::GetUUID(nsACString_internal& aUuid)
+MediaEngineTabVideoSource::GetUUID(nsACString_internal& aUuid) const
 {
   aUuid.AssignLiteral("tab");
 }
 
 #define DEFAULT_TABSHARE_VIDEO_MAX_WIDTH 4096
 #define DEFAULT_TABSHARE_VIDEO_MAX_HEIGHT 4096
 #define DEFAULT_TABSHARE_VIDEO_FRAMERATE 30
 
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -15,18 +15,18 @@ 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&) override;
-    void GetUUID(nsACString_internal&) 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,
                       BaseAllocationHandle** aOutHandle,
                       const char** aOutBadConstraint) override;
     nsresult Deallocate(BaseAllocationHandle* aHandle) override;
     nsresult Start(mozilla::SourceMediaStream*, mozilla::TrackID, const mozilla::PrincipalHandle&) override;
@@ -39,17 +39,17 @@ class MediaEngineTabVideoSource : public
                      const nsString& aDeviceId,
                      const char** aOutBadConstraint) override;
     bool IsFake() override;
     dom::MediaSourceEnum GetMediaSource() const override {
       return dom::MediaSourceEnum::Browser;
     }
     uint32_t GetBestFitnessDistance(
       const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-      const nsString& aDeviceId) override
+      const nsString& aDeviceId) const override
     {
       return 0;
     }
 
     nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) override
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -67,18 +67,18 @@ class MediaEngineWebRTCAudioCaptureSourc
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   explicit MediaEngineWebRTCAudioCaptureSource(const char* aUuid)
     : MediaEngineAudioSource(kReleased)
   {
   }
-  void GetName(nsAString& aName) override;
-  void GetUUID(nsACString& aUUID) override;
+  void GetName(nsAString& aName) const override;
+  void GetUUID(nsACString& aUUID) const override;
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
                     const nsString& aDeviceId,
                     const nsACString& aOrigin,
                     BaseAllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override
   {
     // Nothing to do here, everything is managed in MediaManager.cpp
@@ -131,17 +131,17 @@ public:
     return false;
   }
   nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) override
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   uint32_t GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-    const nsString& aDeviceId) override;
+    const nsString& aDeviceId) const override;
 
 protected:
   virtual ~MediaEngineWebRTCAudioCaptureSource() { Shutdown(); }
   nsCString mUUID;
 };
 
 // Small subset of VoEHardware
 class AudioInput
@@ -446,18 +446,18 @@ public:
     MOZ_ASSERT(aVoiceEnginePtr);
     MOZ_ASSERT(aAudioInput);
     mDeviceName.Assign(NS_ConvertUTF8toUTF16(name));
     mDeviceUUID.Assign(uuid);
     mListener = new mozilla::WebRTCAudioDataListener(this);
     // We'll init lazily as needed
   }
 
-  void GetName(nsAString& aName) override;
-  void GetUUID(nsACString& aUUID) override;
+  void GetName(nsAString& aName) const override;
+  void GetUUID(nsACString& aUUID) const override;
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
                     const nsString& aDeviceId,
                     const nsACString& aOrigin,
                     BaseAllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override;
   nsresult Deallocate(BaseAllocationHandle* aHandle) override;
@@ -498,17 +498,17 @@ public:
 
   nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) override
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   uint32_t GetBestFitnessDistance(
       const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-      const nsString& aDeviceId) override;
+      const nsString& aDeviceId) const override;
 
   // VoEMediaProcess.
   void Process(int channel, webrtc::ProcessingTypes type,
                int16_t audio10ms[], int length,
                int samplingFreq, bool isStereo) override;
 
   void Shutdown() override;
 
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -179,40 +179,40 @@ AudioOutputObserver::InsertFarEnd(const 
         mSaved = nullptr;
         mSamplesSaved = 0;
       }
     }
   }
 }
 
 void
-MediaEngineWebRTCMicrophoneSource::GetName(nsAString& aName)
+MediaEngineWebRTCMicrophoneSource::GetName(nsAString& aName) const
 {
   aName.Assign(mDeviceName);
   return;
 }
 
 void
-MediaEngineWebRTCMicrophoneSource::GetUUID(nsACString& aUUID)
+MediaEngineWebRTCMicrophoneSource::GetUUID(nsACString& aUUID) const
 {
   aUUID.Assign(mDeviceUUID);
   return;
 }
 
 // GetBestFitnessDistance returns the best distance the capture device can offer
 // as a whole, given an accumulated number of ConstraintSets.
 // Ideal values are considered in the first ConstraintSet only.
 // Plain values are treated as Ideal in the first ConstraintSet.
 // Plain values are treated as Exact in subsequent ConstraintSets.
 // Infinity = UINT32_MAX e.g. device cannot satisfy accumulated ConstraintSets.
 // A finite result may be used to calculate this device's ranking as a choice.
 
 uint32_t MediaEngineWebRTCMicrophoneSource::GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-    const nsString& aDeviceId)
+    const nsString& aDeviceId) const
 {
   uint32_t distance = 0;
 
   for (const auto* cs : aConstraintSets) {
     distance = GetMinimumFitnessDistance(*cs, aDeviceId);
     break; // distance is read from first entry only
   }
   return distance;
@@ -794,23 +794,23 @@ MediaEngineWebRTCMicrophoneSource::Proce
     MOZ_ASSERT(!isStereo);
     InsertInGraph<int16_t>(audio10ms, length, 1);
   }
 
   return;
 }
 
 void
-MediaEngineWebRTCAudioCaptureSource::GetName(nsAString &aName)
+MediaEngineWebRTCAudioCaptureSource::GetName(nsAString &aName) const
 {
   aName.AssignLiteral("AudioCapture");
 }
 
 void
-MediaEngineWebRTCAudioCaptureSource::GetUUID(nsACString &aUUID)
+MediaEngineWebRTCAudioCaptureSource::GetUUID(nsACString &aUUID) const
 {
   nsID uuid;
   char uuidBuffer[NSID_LENGTH];
   nsCString asciiString;
   ErrorResult rv;
 
   rv = nsContentUtils::GenerateUUIDInPlace(uuid);
   if (rv.Failed()) {
@@ -855,15 +855,15 @@ MediaEngineWebRTCAudioCaptureSource::Res
 {
   MOZ_ASSERT(!aHandle);
   return NS_OK;
 }
 
 uint32_t
 MediaEngineWebRTCAudioCaptureSource::GetBestFitnessDistance(
     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
-    const nsString& aDeviceId)
+    const nsString& aDeviceId) const
 {
   // There is only one way of capturing audio for now, and it's always adequate.
   return 0;
 }
 
 }
--- a/dom/media/webrtc/MediaTrackConstraints.cpp
+++ b/dom/media/webrtc/MediaTrackConstraints.cpp
@@ -387,9 +387,48 @@ MediaConstraintsHelper::FitnessDistance(
     return UINT32_MAX;
   }
   if (aParams.mIdeal.size() && aParams.mIdeal.find(aN) == aParams.mIdeal.end()) {
     return 1000;
   }
   return 0;
 }
 
+template<class MediaEngineSourceType>
+const char*
+MediaConstraintsHelper::FindBadConstraint(
+    const NormalizedConstraints& aConstraints,
+    const MediaEngineSourceType& aMediaEngineSource,
+    const nsString& aDeviceId)
+{
+  class MockDevice
+  {
+  public:
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MockDevice);
+
+    explicit MockDevice(const MediaEngineSourceType* aMediaEngineSource,
+                        const nsString& aDeviceId)
+    : mMediaEngineSource(aMediaEngineSource),
+      // The following dud code exists to avoid 'unused typedef' error on linux.
+      mDeviceId(MockDevice::HasThreadSafeRefCnt::value ? aDeviceId : nsString()) {}
+
+    uint32_t GetBestFitnessDistance(
+        const nsTArray<const NormalizedConstraintSet*>& aConstraintSets)
+    {
+      return mMediaEngineSource->GetBestFitnessDistance(aConstraintSets,
+                                                        mDeviceId);
+    }
+
+  private:
+    ~MockDevice() {}
+
+    const MediaEngineSourceType* mMediaEngineSource;
+    nsString mDeviceId;
+  };
+
+  Unused << typename MockDevice::HasThreadSafeRefCnt();
+
+  nsTArray<RefPtr<MockDevice>> devices;
+  devices.AppendElement(new MockDevice(&aMediaEngineSource, aDeviceId));
+  return FindBadConstraint(aConstraints, devices);
 }
+
+}
--- a/dom/media/webrtc/MediaTrackConstraints.h
+++ b/dom/media/webrtc/MediaTrackConstraints.h
@@ -283,142 +283,148 @@ protected:
 
   static uint32_t
   GetMinimumFitnessDistance(const NormalizedConstraintSet &aConstraints,
                             const nsString& aDeviceId);
 
   template<class DeviceType>
   static bool
   SomeSettingsFit(const NormalizedConstraints &aConstraints,
-                  nsTArray<RefPtr<DeviceType>>& aSources)
+                  nsTArray<RefPtr<DeviceType>>& aDevices)
   {
     nsTArray<const NormalizedConstraintSet*> sets;
     sets.AppendElement(&aConstraints);
 
-    MOZ_ASSERT(aSources.Length());
-    for (auto& source : aSources) {
-      if (source->GetBestFitnessDistance(sets) != UINT32_MAX) {
+    MOZ_ASSERT(aDevices.Length());
+    for (auto& device : aDevices) {
+      if (device->GetBestFitnessDistance(sets) != UINT32_MAX) {
         return true;
       }
     }
     return false;
   }
 
 public:
-  // Apply constrains to a supplied list of sources (removes items from the list)
+  // Apply constrains to a supplied list of devices (removes items from the list)
 
   template<class DeviceType>
   static const char*
   SelectSettings(const NormalizedConstraints &aConstraints,
-                 nsTArray<RefPtr<DeviceType>>& aSources)
+                 nsTArray<RefPtr<DeviceType>>& aDevices)
   {
     auto& c = aConstraints;
 
     // First apply top-level constraints.
 
     // Stack constraintSets that pass, starting with the required one, because the
     // whole stack must be re-satisfied each time a capability-set is ruled out
     // (this avoids storing state or pushing algorithm into the lower-level code).
     nsTArray<RefPtr<DeviceType>> unsatisfactory;
     nsTArray<const NormalizedConstraintSet*> aggregateConstraints;
     aggregateConstraints.AppendElement(&c);
 
     std::multimap<uint32_t, RefPtr<DeviceType>> ordered;
 
-    for (uint32_t i = 0; i < aSources.Length();) {
-      uint32_t distance = aSources[i]->GetBestFitnessDistance(aggregateConstraints);
+    for (uint32_t i = 0; i < aDevices.Length();) {
+      uint32_t distance = aDevices[i]->GetBestFitnessDistance(aggregateConstraints);
       if (distance == UINT32_MAX) {
-        unsatisfactory.AppendElement(aSources[i]);
-        aSources.RemoveElementAt(i);
+        unsatisfactory.AppendElement(aDevices[i]);
+        aDevices.RemoveElementAt(i);
       } else {
         ordered.insert(std::pair<uint32_t, RefPtr<DeviceType>>(distance,
-                                                                 aSources[i]));
+                                                               aDevices[i]));
         ++i;
       }
     }
-    if (!aSources.Length()) {
+    if (!aDevices.Length()) {
       return FindBadConstraint(c, unsatisfactory);
     }
 
     // Order devices by shortest distance
     for (auto& ordinal : ordered) {
-      aSources.RemoveElement(ordinal.second);
-      aSources.AppendElement(ordinal.second);
+      aDevices.RemoveElement(ordinal.second);
+      aDevices.AppendElement(ordinal.second);
     }
 
     // Then apply advanced constraints.
 
     for (int i = 0; i < int(c.mAdvanced.Length()); i++) {
       aggregateConstraints.AppendElement(&c.mAdvanced[i]);
       nsTArray<RefPtr<DeviceType>> rejects;
-      for (uint32_t j = 0; j < aSources.Length();) {
-        if (aSources[j]->GetBestFitnessDistance(aggregateConstraints) == UINT32_MAX) {
-          rejects.AppendElement(aSources[j]);
-          aSources.RemoveElementAt(j);
+      for (uint32_t j = 0; j < aDevices.Length();) {
+        if (aDevices[j]->GetBestFitnessDistance(aggregateConstraints) == UINT32_MAX) {
+          rejects.AppendElement(aDevices[j]);
+          aDevices.RemoveElementAt(j);
         } else {
           ++j;
         }
       }
-      if (!aSources.Length()) {
-        aSources.AppendElements(Move(rejects));
+      if (!aDevices.Length()) {
+        aDevices.AppendElements(Move(rejects));
         aggregateConstraints.RemoveElementAt(aggregateConstraints.Length() - 1);
       }
     }
     return nullptr;
   }
 
   template<class DeviceType>
   static const char*
   FindBadConstraint(const NormalizedConstraints& aConstraints,
-                    nsTArray<RefPtr<DeviceType>>& aSources)
+                    nsTArray<RefPtr<DeviceType>>& aDevices)
   {
     // The spec says to report a constraint that satisfies NONE
     // of the sources. Unfortunately, this is a bit laborious to find out, and
     // requires updating as new constraints are added!
     auto& c = aConstraints;
     dom::MediaTrackConstraints empty;
 
-    if (!aSources.Length() ||
-        !SomeSettingsFit(NormalizedConstraints(empty), aSources)) {
+    if (!aDevices.Length() ||
+        !SomeSettingsFit(NormalizedConstraints(empty), aDevices)) {
       return "";
     }
     {
       NormalizedConstraints fresh(empty);
       fresh.mDeviceId = c.mDeviceId;
-      if (!SomeSettingsFit(fresh, aSources)) {
+      if (!SomeSettingsFit(fresh, aDevices)) {
         return "deviceId";
       }
     }
     {
       NormalizedConstraints fresh(empty);
       fresh.mWidth = c.mWidth;
-      if (!SomeSettingsFit(fresh, aSources)) {
+      if (!SomeSettingsFit(fresh, aDevices)) {
         return "width";
       }
     }
     {
       NormalizedConstraints fresh(empty);
       fresh.mHeight = c.mHeight;
-      if (!SomeSettingsFit(fresh, aSources)) {
+      if (!SomeSettingsFit(fresh, aDevices)) {
         return "height";
       }
     }
     {
       NormalizedConstraints fresh(empty);
       fresh.mFrameRate = c.mFrameRate;
-      if (!SomeSettingsFit(fresh, aSources)) {
+      if (!SomeSettingsFit(fresh, aDevices)) {
         return "frameRate";
       }
     }
     {
       NormalizedConstraints fresh(empty);
       fresh.mFacingMode = c.mFacingMode;
-      if (!SomeSettingsFit(fresh, aSources)) {
+      if (!SomeSettingsFit(fresh, aDevices)) {
         return "facingMode";
       }
     }
     return "";
   }
+
+  template<class MediaEngineSourceType>
+  static const char*
+  FindBadConstraint(const NormalizedConstraints& aConstraints,
+                    const MediaEngineSourceType& aMediaEngineSource,
+                    const nsString& aDeviceId);
 };
 
 } // namespace mozilla
 
 #endif /* MEDIATRACKCONSTRAINTS_H_ */