Bug 1213517 - Lift correct constraint out of lower-level code for OverconstrainedError. r=padenot
authorJan-Ivar Bruaroey <jib@mozilla.com>
Mon, 20 Jun 2016 20:15:39 -0400
changeset 347521 3110045d432e4e27886aa0bfdef46ef0c87888be
parent 347520 e202052952d576a44129413388f01c0293429e08
child 347522 2a924630566f530e4d80d9f24c714d9eecb2edfa
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
bugs1213517
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 1213517 - Lift correct constraint out of lower-level code for OverconstrainedError. r=padenot 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_ */