--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -212,30 +212,35 @@ public:
virtual bool GetScary() const { return false; };
class AllocationHandle
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AllocationHandle);
protected:
~AllocationHandle() {}
+ static uint64_t sId;
public:
AllocationHandle(const dom::MediaTrackConstraints& aConstraints,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId)
: mConstraints(aConstraints),
mPrincipalInfo(aPrincipalInfo),
mPrefs(aPrefs),
+#ifdef MOZ_WEBRTC
+ mId(sId++),
+#endif
mDeviceId(aDeviceId) {}
public:
NormalizedConstraints mConstraints;
mozilla::ipc::PrincipalInfo mPrincipalInfo;
MediaEnginePrefs mPrefs;
+ uint64_t mId;
nsString mDeviceId;
};
/* Release the device back to the system. */
virtual nsresult Deallocate(AllocationHandle* aHandle)
{
MOZ_ASSERT(aHandle);
RefPtr<AllocationHandle> handle = aHandle;
@@ -361,16 +366,17 @@ protected:
* 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 NormalizedConstraints& aNewConstraint,
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
@@ -389,36 +395,42 @@ protected:
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;
+ AutoTArray<const NormalizedConstraints*, 1> updatedConstraint;
for (auto& registered : mRegisteredHandles) {
if (aConstraintsUpdate && registered.get() == aHandle) {
continue; // Don't count old constraints
}
allConstraints.AppendElement(®istered->mConstraints);
}
if (aConstraintsUpdate) {
allConstraints.AppendElement(aConstraintsUpdate);
+ updatedConstraint.AppendElement(aConstraintsUpdate);
} else if (aHandle) {
// In the case of AddShareOfSingleSource, the handle isn't registered yet.
allConstraints.AppendElement(&aHandle->mConstraints);
+ updatedConstraint.AppendElement(&aHandle->mConstraints);
+ } else {
+ updatedConstraint.AppendElements(allConstraints);
}
NormalizedConstraints netConstraints(allConstraints);
if (netConstraints.mBadConstraint) {
*aOutBadConstraint = netConstraints.mBadConstraint;
return NS_ERROR_FAILURE;
}
- nsresult rv = UpdateSingleSource(aHandle, netConstraints, aPrefs, aDeviceId,
+ NormalizedConstraints newConstraint(updatedConstraint);
+ nsresult rv = UpdateSingleSource(aHandle, netConstraints, newConstraint, aPrefs, aDeviceId,
aOutBadConstraint);
if (NS_FAILED(rv)) {
return rv;
}
if (aHandle && aConstraintsUpdate) {
aHandle->mConstraints = *aConstraintsUpdate;
}
return NS_OK;
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.cpp
@@ -50,16 +50,29 @@ void
MediaEngineCameraVideoSource::GetCapability(size_t aIndex,
webrtc::CaptureCapability& aOut) const
{
MOZ_ASSERT(aIndex < mHardcodedCapabilities.Length());
aOut = mHardcodedCapabilities.SafeElementAt(aIndex, webrtc::CaptureCapability());
}
uint32_t
+MediaEngineCameraVideoSource::GetDistance(
+ const webrtc::CaptureCapability& aCandidate,
+ const NormalizedConstraintSet &aConstraints,
+ const nsString& aDeviceId,
+ const DistanceCalculation aCalculate) const
+{
+ if (aCalculate == kFeasibility) {
+ return GetFeasibilityDistance(aCandidate, aConstraints, aDeviceId);
+ }
+ return GetFitnessDistance(aCandidate, aConstraints, aDeviceId);
+}
+
+uint32_t
MediaEngineCameraVideoSource::GetFitnessDistance(
const webrtc::CaptureCapability& aCandidate,
const NormalizedConstraintSet &aConstraints,
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.
@@ -70,16 +83,37 @@ MediaEngineCameraVideoSource::GetFitness
aConstraints.mWidth) : 0) +
uint64_t(aCandidate.height? FitnessDistance(int32_t(aCandidate.height),
aConstraints.mHeight) : 0) +
uint64_t(aCandidate.maxFPS? FitnessDistance(double(aCandidate.maxFPS),
aConstraints.mFrameRate) : 0);
return uint32_t(std::min(distance, uint64_t(UINT32_MAX)));
}
+uint32_t
+MediaEngineCameraVideoSource::GetFeasibilityDistance(
+ const webrtc::CaptureCapability& aCandidate,
+ const NormalizedConstraintSet &aConstraints,
+ 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? FeasibilityDistance(int32_t(aCandidate.width),
+ aConstraints.mWidth) : 0) +
+ uint64_t(aCandidate.height? FeasibilityDistance(int32_t(aCandidate.height),
+ aConstraints.mHeight) : 0) +
+ uint64_t(aCandidate.maxFPS? FeasibilityDistance(double(aCandidate.maxFPS),
+ aConstraints.mFrameRate) : 0);
+ return uint32_t(std::min(distance, uint64_t(UINT32_MAX)));
+}
+
// Find best capability by removing inferiors. May leave >1 of equal distance
/* static */ void
MediaEngineCameraVideoSource::TrimLessFitCandidates(CapabilitySet& set) {
uint32_t best = UINT32_MAX;
for (auto& candidate : set) {
if (best > candidate.mDistance) {
best = candidate.mDistance;
@@ -213,17 +247,19 @@ MediaEngineCameraVideoSource::LogCapabil
uint32_t(sizeof(codec) / sizeof(*codec) - 1))],
aDistance));
}
bool
MediaEngineCameraVideoSource::ChooseCapability(
const NormalizedConstraints &aConstraints,
const MediaEnginePrefs &aPrefs,
- const nsString& aDeviceId)
+ const nsString& aDeviceId,
+ webrtc::CaptureCapability& aCapability,
+ const DistanceCalculation aCalculate)
{
if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
LOG(("ChooseCapability: prefs: %dx%d @%dfps",
aPrefs.GetWidth(), aPrefs.GetHeight(),
aPrefs.mFPS));
LogConstraints(aConstraints);
if (!aConstraints.mAdvanced.empty()) {
LOG(("Advanced array[%zu]:", aConstraints.mAdvanced.size()));
@@ -241,17 +277,17 @@ MediaEngineCameraVideoSource::ChooseCapa
}
// First, filter capabilities by required constraints (min, max, exact).
for (size_t i = 0; i < candidateSet.Length();) {
auto& candidate = candidateSet[i];
webrtc::CaptureCapability cap;
GetCapability(candidate.mIndex, cap);
- candidate.mDistance = GetFitnessDistance(cap, aConstraints, aDeviceId);
+ candidate.mDistance = GetDistance(cap, aConstraints, aDeviceId, aCalculate);
LogCapability("Capability", cap, candidate.mDistance);
if (candidate.mDistance == UINT32_MAX) {
candidateSet.RemoveElementAt(i);
} else {
++i;
}
}
@@ -263,17 +299,17 @@ MediaEngineCameraVideoSource::ChooseCapa
// Filter further with all advanced constraints (that don't overconstrain).
for (const auto &cs : aConstraints.mAdvanced) {
CapabilitySet rejects;
for (size_t i = 0; i < candidateSet.Length();) {
auto& candidate = candidateSet[i];
webrtc::CaptureCapability cap;
GetCapability(candidate.mIndex, cap);
- if (GetFitnessDistance(cap, cs, aDeviceId) == UINT32_MAX) {
+ if (GetDistance(cap, cs, aDeviceId, aCalculate) == UINT32_MAX) {
rejects.AppendElement(candidate);
candidateSet.RemoveElementAt(i);
} else {
++i;
}
}
if (!candidateSet.Length()) {
candidateSet.AppendElements(Move(rejects));
@@ -294,39 +330,39 @@ MediaEngineCameraVideoSource::ChooseCapa
prefs.mWidth.SetAsLong() = aPrefs.GetWidth();
prefs.mHeight.SetAsLong() = aPrefs.GetHeight();
prefs.mFrameRate.SetAsDouble() = aPrefs.mFPS;
NormalizedConstraintSet normPrefs(prefs, false);
for (auto& candidate : candidateSet) {
webrtc::CaptureCapability cap;
GetCapability(candidate.mIndex, cap);
- candidate.mDistance = GetFitnessDistance(cap, normPrefs, aDeviceId);
+ candidate.mDistance = GetDistance(cap, normPrefs, aDeviceId, aCalculate);
}
TrimLessFitCandidates(candidateSet);
}
// Any remaining multiples all have the same distance, but may vary on
// format. Some formats are more desirable for certain use like WebRTC.
// E.g. I420 over RGB24 can remove a needless format conversion.
bool found = false;
for (auto& candidate : candidateSet) {
webrtc::CaptureCapability cap;
GetCapability(candidate.mIndex, cap);
if (cap.rawType == webrtc::RawVideoType::kVideoI420 ||
cap.rawType == webrtc::RawVideoType::kVideoYUY2 ||
cap.rawType == webrtc::RawVideoType::kVideoYV12) {
- mCapability = cap;
+ aCapability = cap;
found = true;
break;
}
}
if (!found) {
- GetCapability(candidateSet[0].mIndex, mCapability);
+ GetCapability(candidateSet[0].mIndex, aCapability);
}
LogCapability("Chosen capability", mCapability, sameDistance);
return true;
}
void
MediaEngineCameraVideoSource::SetName(nsString aName)
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h
@@ -19,16 +19,29 @@
#include "webrtc/modules/video_capture/video_capture_defines.h"
namespace webrtc {
using CaptureCapability = VideoCaptureCapability;
}
namespace mozilla {
+// Fitness distance is defined in
+// https://www.w3.org/TR/2017/CR-mediacapture-streams-20171003/#dfn-selectsettings
+// The main difference of feasibility and fitness distance is that if the
+// constraint is required ('max', or 'exact'), and the settings dictionary's value
+// for the constraint does not satisfy the constraint, the fitness distance is
+// positive infinity. Given a continuous space of settings dictionaries comprising
+// all discrete combinations of dimension and frame-rate related properties,
+// the feasibility distance is still in keeping with the constraints algorithm.
+enum DistanceCalculation {
+ kFitness,
+ kFeasibility
+};
+
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)
@@ -81,29 +94,40 @@ protected:
~MediaEngineCameraVideoSource() {}
// 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 GetDistance(const webrtc::CaptureCapability& aCandidate,
+ const NormalizedConstraintSet &aConstraints,
+ const nsString& aDeviceId,
+ const DistanceCalculation aCalculate) const;
uint32_t GetFitnessDistance(const webrtc::CaptureCapability& aCandidate,
const NormalizedConstraintSet &aConstraints,
const nsString& aDeviceId) const;
+ uint32_t GetFeasibilityDistance(const webrtc::CaptureCapability& aCandidate,
+ const NormalizedConstraintSet &aConstraints,
+ 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() const;
virtual void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) const;
- virtual bool ChooseCapability(const NormalizedConstraints &aConstraints,
- const MediaEnginePrefs &aPrefs,
- const nsString& aDeviceId);
+ virtual bool ChooseCapability(
+ const NormalizedConstraints &aConstraints,
+ const MediaEnginePrefs &aPrefs,
+ const nsString& aDeviceId,
+ webrtc::CaptureCapability& aCapability,
+ const DistanceCalculation aCalculate
+ );
void SetName(nsString aName);
void SetUUID(const char* aUUID);
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
@@ -111,25 +135,29 @@ protected:
// mMonitor also protects mSources[] and mPrincipalHandles[] access/changes.
// mSources[] and mPrincipalHandles[] are accessed from webrtc threads.
// All the mMonitor accesses are from the child classes.
Monitor mMonitor; // Monitor for processing Camera frames.
nsTArray<RefPtr<SourceMediaStream>> mSources; // When this goes empty, we shut down HW
nsTArray<PrincipalHandle> mPrincipalHandles; // Directly mapped to mSources.
RefPtr<layers::Image> mImage;
+ nsTArray<webrtc::CaptureCapability> mTargetCapabilities;
+ nsTArray<uint64_t> mHandleIds;
RefPtr<layers::ImageContainer> mImageContainer;
// end of data protected by mMonitor
int mWidth, mHeight;
bool mInitDone;
int mCaptureIndex;
TrackID mTrackID;
webrtc::CaptureCapability mCapability;
+ webrtc::CaptureCapability mTargetCapability;
+ uint64_t mHandleId;
mutable nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities;
private:
nsString mDeviceName;
nsCString mUniqueId;
nsString mFacingMode;
};
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -12,16 +12,18 @@
#include "CamerasChild.h"
extern mozilla::LogModule* GetMediaManagerLog();
#define LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg)
#define LOGFRAME(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Verbose, msg)
namespace mozilla {
+uint64_t MediaEngineCameraVideoSource::AllocationHandle::sId = 0;
+
// These need a definition somewhere because template
// code is allowed to take their address, and they aren't
// guaranteed to have one without this.
const unsigned int MediaEngineSource::kMaxDeviceNameLength;
const unsigned int MediaEngineSource::kMaxUniqueIdLength;;
using dom::ConstrainLongRange;
@@ -75,16 +77,18 @@ MediaEngineRemoteVideoSource::Shutdown()
bool empty;
while (1) {
{
MonitorAutoLock lock(mMonitor);
empty = mSources.IsEmpty();
if (empty) {
MOZ_ASSERT(mPrincipalHandles.IsEmpty());
+ MOZ_ASSERT(mTargetCapabilities.IsEmpty());
+ MOZ_ASSERT(mHandleIds.IsEmpty());
break;
}
source = mSources[0];
}
Stop(source, kVideoTrack); // XXX change to support multiple tracks
}
MOZ_ASSERT(mState == kStopped);
}
@@ -121,16 +125,18 @@ MediaEngineRemoteVideoSource::Allocate(
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());
+ MOZ_ASSERT(mTargetCapabilities.IsEmpty());
+ MOZ_ASSERT(mHandleIds.IsEmpty());
LOG(("Video device %d reallocated", mCaptureIndex));
} else {
LOG(("Video device %d allocated shared", mCaptureIndex));
}
}
return NS_OK;
}
@@ -167,17 +173,22 @@ MediaEngineRemoteVideoSource::Start(Sour
LOG(("No stream or init not done"));
return NS_ERROR_FAILURE;
}
{
MonitorAutoLock lock(mMonitor);
mSources.AppendElement(aStream);
mPrincipalHandles.AppendElement(aPrincipalHandle);
+ mTargetCapabilities.AppendElement(mTargetCapability);
+ mHandleIds.AppendElement(mHandleId);
+
MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
+ MOZ_ASSERT(mSources.Length() == mTargetCapabilities.Length());
+ MOZ_ASSERT(mSources.Length() == mHandleIds.Length());
}
aStream->AddTrack(aID, 0, new VideoSegment(), SourceMediaStream::ADDTRACK_QUEUED);
if (mState == kStarted) {
return NS_OK;
}
mImageContainer =
@@ -213,18 +224,22 @@ MediaEngineRemoteVideoSource::Stop(mozil
size_t i = mSources.IndexOf(aSource);
if (i == mSources.NoIndex) {
// Already stopped - this is allowed
return NS_OK;
}
MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
+ MOZ_ASSERT(mSources.Length() == mTargetCapabilities.Length());
+ MOZ_ASSERT(mSources.Length() == mHandleIds.Length());
mSources.RemoveElementAt(i);
mPrincipalHandles.RemoveElementAt(i);
+ mTargetCapabilities.RemoveElementAt(i);
+ mHandleIds.RemoveElementAt(i);
aSource->EndTrack(aID);
if (!mSources.IsEmpty()) {
return NS_OK;
}
if (mState != kStarted) {
return NS_ERROR_FAILURE;
@@ -257,52 +272,79 @@ MediaEngineRemoteVideoSource::Restart(Al
return ReevaluateAllocation(aHandle, &constraints, aPrefs, aDeviceId,
aOutBadConstraint);
}
nsresult
MediaEngineRemoteVideoSource::UpdateSingleSource(
const AllocationHandle* aHandle,
const NormalizedConstraints& aNetConstraints,
+ const NormalizedConstraints& aNewConstraint,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint)
{
- if (!ChooseCapability(aNetConstraints, aPrefs, aDeviceId)) {
- *aOutBadConstraint = FindBadConstraint(aNetConstraints, *this, aDeviceId);
- return NS_ERROR_FAILURE;
- }
-
switch (mState) {
case kReleased:
MOZ_ASSERT(aHandle);
+ mHandleId = aHandle->mId;
+ if (!ChooseCapability(aNetConstraints, aPrefs, aDeviceId, mCapability, kFitness)) {
+ *aOutBadConstraint = FindBadConstraint(aNetConstraints, *this, aDeviceId);
+ return NS_ERROR_FAILURE;
+ }
+ mTargetCapability = mCapability;
+
if (camera::GetChildAndCall(&camera::CamerasChild::AllocateCaptureDevice,
mCapEngine, GetUUID().get(),
kMaxUniqueIdLength, mCaptureIndex,
aHandle->mPrincipalInfo)) {
return NS_ERROR_FAILURE;
}
mState = kAllocated;
SetLastCapability(mCapability);
LOG(("Video device %d allocated", mCaptureIndex));
break;
case kStarted:
- if (mCapability != mLastCapability) {
- camera::GetChildAndCall(&camera::CamerasChild::StopCapture,
- mCapEngine, mCaptureIndex);
- if (camera::GetChildAndCall(&camera::CamerasChild::StartCapture,
- mCapEngine, mCaptureIndex, mCapability,
- this)) {
- LOG(("StartCapture failed"));
+ {
+ size_t index = mHandleIds.NoIndex;
+ if (aHandle) {
+ mHandleId = aHandle->mId;
+ index = mHandleIds.IndexOf(mHandleId);
+ }
+
+ if (!ChooseCapability(aNewConstraint, aPrefs, aDeviceId, mTargetCapability,
+ kFitness)) {
+ *aOutBadConstraint = FindBadConstraint(aNewConstraint, *this, aDeviceId);
return NS_ERROR_FAILURE;
}
- SetLastCapability(mCapability);
+
+ if (index != mHandleIds.NoIndex) {
+ mTargetCapabilities[index] = mTargetCapability;
+ }
+
+ if (!ChooseCapability(aNetConstraints, aPrefs, aDeviceId, mCapability,
+ kFeasibility)) {
+ *aOutBadConstraint = FindBadConstraint(aNetConstraints, *this, aDeviceId);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (mCapability != mLastCapability) {
+ camera::GetChildAndCall(&camera::CamerasChild::StopCapture,
+ mCapEngine, mCaptureIndex);
+ if (camera::GetChildAndCall(&camera::CamerasChild::StartCapture,
+ mCapEngine, mCaptureIndex, mCapability,
+ this)) {
+ LOG(("StartCapture failed"));
+ return NS_ERROR_FAILURE;
+ }
+ SetLastCapability(mCapability);
+ }
+ break;
}
- break;
default:
LOG(("Video device %d in ignored state %d", mCaptureIndex, mState));
break;
}
return NS_OK;
}
@@ -459,38 +501,41 @@ MediaEngineRemoteVideoSource::NumCapabil
}
return num;
}
bool
MediaEngineRemoteVideoSource::ChooseCapability(
const NormalizedConstraints &aConstraints,
const MediaEnginePrefs &aPrefs,
- const nsString& aDeviceId)
+ const nsString& aDeviceId,
+ webrtc::CaptureCapability& aCapability,
+ const DistanceCalculation aCalculate)
{
AssertIsOnOwningThread();
switch(mMediaSource) {
case dom::MediaSourceEnum::Screen:
case dom::MediaSourceEnum::Window:
case dom::MediaSourceEnum::Application: {
FlattenedConstraints c(aConstraints);
// The actual resolution to constrain around is not easy to find ahead of
// time (and may in fact change over time), so as a hack, we push ideal
// and max constraints down to desktop_capture_impl.cc and finish the
// algorithm there.
- mCapability.width = (c.mWidth.mIdeal.valueOr(0) & 0xffff) << 16 |
- (c.mWidth.mMax & 0xffff);
- mCapability.height = (c.mHeight.mIdeal.valueOr(0) & 0xffff) << 16 |
- (c.mHeight.mMax & 0xffff);
- mCapability.maxFPS = c.mFrameRate.Clamp(c.mFrameRate.mIdeal.valueOr(aPrefs.mFPS));
+ aCapability.width =
+ (c.mWidth.mIdeal.valueOr(0) & 0xffff) << 16 | (c.mWidth.mMax & 0xffff);
+ aCapability.height =
+ (c.mHeight.mIdeal.valueOr(0) & 0xffff) << 16 | (c.mHeight.mMax & 0xffff);
+ aCapability.maxFPS =
+ c.mFrameRate.Clamp(c.mFrameRate.mIdeal.valueOr(aPrefs.mFPS));
return true;
}
default:
- return MediaEngineCameraVideoSource::ChooseCapability(aConstraints, aPrefs, aDeviceId);
+ return MediaEngineCameraVideoSource::ChooseCapability(aConstraints, aPrefs, aDeviceId, aCapability, aCalculate);
}
}
void
MediaEngineRemoteVideoSource::GetCapability(size_t aIndex,
webrtc::CaptureCapability& aOut) const
{
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -79,19 +79,22 @@ public:
SourceMediaStream* aSource,
TrackID aId,
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle) override;
dom::MediaSourceEnum GetMediaSource() const override {
return mMediaSource;
}
- bool ChooseCapability(const NormalizedConstraints &aConstraints,
- const MediaEnginePrefs &aPrefs,
- const nsString& aDeviceId) override;
+ bool ChooseCapability(
+ const NormalizedConstraints &aConstraints,
+ const MediaEnginePrefs &aPrefs,
+ const nsString& aDeviceId,
+ webrtc::CaptureCapability& aCapability,
+ const DistanceCalculation aCalculate) override;
void Refresh(int aIndex);
void Shutdown() override;
bool GetScary() const override { return mScary; }
protected:
@@ -102,16 +105,17 @@ private:
void Init();
size_t NumCapabilities() const override;
void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) const override;
void SetLastCapability(const webrtc::CaptureCapability& aCapability);
nsresult
UpdateSingleSource(const AllocationHandle* aHandle,
const NormalizedConstraints& aNetConstraints,
+ const NormalizedConstraints& aNewConstraint,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint) override;
dom::MediaSourceEnum mMediaSource; // source of media (camera | application | screen)
mozilla::camera::CaptureEngine mCapEngine;
// To only restart camera when needed, we keep track previous settings.
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -561,16 +561,17 @@ public:
protected:
~MediaEngineWebRTCMicrophoneSource() {}
private:
nsresult
UpdateSingleSource(const AllocationHandle* aHandle,
const NormalizedConstraints& aNetConstraints,
+ const NormalizedConstraints& aNewConstraint,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint) override;
void SetLastPrefs(const MediaEnginePrefs& aPrefs);
// These allocate/configure and release the channel
bool AllocChannel();
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -274,16 +274,17 @@ bool operator == (const MediaEnginePrefs
{
return !memcmp(&a, &b, sizeof(MediaEnginePrefs));
};
nsresult
MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
const AllocationHandle* aHandle,
const NormalizedConstraints& aNetConstraints,
+ const NormalizedConstraints& aNewConstraint, /* Ignored */
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint)
{
FlattenedConstraints c(aNetConstraints);
MediaEnginePrefs prefs = aPrefs;
prefs.mAecOn = c.mEchoCancellation.Get(prefs.mAecOn);
--- a/dom/media/webrtc/MediaTrackConstraints.cpp
+++ b/dom/media/webrtc/MediaTrackConstraints.cpp
@@ -412,16 +412,38 @@ MediaConstraintsHelper::FitnessDistance(
}
if (aN == aRange.mIdeal.valueOr(aN)) {
return 0;
}
return uint32_t(ValueType((std::abs(aN - aRange.mIdeal.value()) * 1000) /
std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
}
+template<class ValueType, class NormalizedRange>
+/* static */ uint32_t
+MediaConstraintsHelper::FeasibilityDistance(ValueType aN,
+ const NormalizedRange& aRange)
+{
+ if (aRange.mMin > aN) {
+ return UINT32_MAX;
+ }
+ // We prefer larger resolution because now we support downscaling
+ if (aN == aRange.mIdeal.valueOr(aN)) {
+ return 0;
+ }
+
+ if (aN > aRange.mIdeal.value()) {
+ return uint32_t(ValueType((std::abs(aN - aRange.mIdeal.value()) * 1000) /
+ std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
+ }
+
+ return 10000 + uint32_t(ValueType((std::abs(aN - aRange.mIdeal.value()) * 1000) /
+ std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
+}
+
// Fitness distance returned as integer math * 1000. Infinity = UINT32_MAX
/* static */ uint32_t
MediaConstraintsHelper::FitnessDistance(
nsString aN,
const NormalizedConstraintSet::StringRange& aParams)
{
if (!aParams.mExact.empty() && aParams.mExact.find(aN) == aParams.mExact.end()) {
--- a/dom/media/webrtc/MediaTrackConstraints.h
+++ b/dom/media/webrtc/MediaTrackConstraints.h
@@ -80,22 +80,29 @@ public:
ValueType Clamp(ValueType n) const { return std::max(mMin, std::min(n, mMax)); }
ValueType Get(ValueType defaultValue) const {
return Clamp(mIdeal.valueOr(defaultValue));
}
bool Intersects(const Range& aOther) const {
return mMax >= aOther.mMin && mMin <= aOther.mMax;
}
void Intersect(const Range& aOther) {
- MOZ_ASSERT(Intersects(aOther));
mMin = std::max(mMin, aOther.mMin);
- mMax = std::min(mMax, aOther.mMax);
+ if (Intersects(aOther)) {
+ mMax = std::min(mMax, aOther.mMax);
+ } else {
+ // If there is no intersection, we will down-scale or drop frame
+ mMax = std::max(mMax, aOther.mMax);
+ }
}
bool Merge(const Range& aOther) {
- if (!Intersects(aOther)) {
+ if (strcmp(mName, "width") != 0 &&
+ strcmp(mName, "height") != 0 &&
+ strcmp(mName, "frameRate") != 0 &&
+ !Intersects(aOther)) {
return false;
}
Intersect(aOther);
if (aOther.mIdeal.isSome()) {
// Ideal values, as stored, may be outside their min max range, so use
// clamped values in averaging, to avoid extreme outliers skewing results.
if (mIdeal.isNothing()) {
@@ -292,16 +299,18 @@ struct FlattenedConstraints : public Nor
// A helper class for MediaEngines
class MediaConstraintsHelper
{
protected:
template<class ValueType, class NormalizedRange>
static uint32_t FitnessDistance(ValueType aN, const NormalizedRange& aRange);
+ template<class ValueType, class NormalizedRange>
+ static uint32_t FeasibilityDistance(ValueType aN, const NormalizedRange& aRange);
static uint32_t FitnessDistance(nsString aN,
const NormalizedConstraintSet::StringRange& aConstraint);
static uint32_t
GetMinimumFitnessDistance(const NormalizedConstraintSet &aConstraints,
const nsString& aDeviceId);
template<class DeviceType>