tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MediaTrackConstraints.h (13244B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 // This file should not be included by other includes, as it contains code
      6 
      7 #ifndef MEDIATRACKCONSTRAINTS_H_
      8 #define MEDIATRACKCONSTRAINTS_H_
      9 
     10 #include <set>
     11 #include <vector>
     12 
     13 #include "ipc/IPCMessageUtilsSpecializations.h"
     14 #include "mozilla/dom/MediaStreamTrackBinding.h"
     15 
     16 namespace mozilla {
     17 
     18 class LocalMediaDevice;
     19 class MediaDevice;
     20 class MediaEnginePrefs;
     21 
     22 // Helper classes for orthogonal constraints without interdependencies.
     23 // Instead of constraining values, constrain the constraints themselves.
     24 class NormalizedConstraintSet {
     25 protected:
     26  class BaseRange {
     27   protected:
     28    BaseRange(const nsCString& aName) : mName(aName) {}
     29    virtual ~BaseRange() = default;
     30 
     31   public:
     32    bool operator==(const BaseRange& aOther) const noexcept {
     33      return mName == aOther.mName;
     34    }
     35    BaseRange& operator=(const BaseRange& aOther) {
     36      // We want all members assignable except mName. This allows e.g.
     37      // std::swap(c.mWidth, c.mHeight) without names going out of sync.
     38      return *this;
     39    }
     40    virtual bool Merge(const BaseRange& aOther) = 0;
     41    virtual void FinalizeMerge() = 0;
     42 
     43    const nsCString mName;
     44  };
     45 
     46 public:
     47  template <class ValueType>
     48  class Range : public BaseRange {
     49   public:
     50    ValueType mMin, mMax;
     51    Maybe<ValueType> mIdeal;
     52 
     53    Range(const nsCString& aName, ValueType aMin, ValueType aMax)
     54        : BaseRange(aName), mMin(aMin), mMax(aMax), mMergeDenominator(0) {}
     55    virtual ~Range() = default;
     56 
     57    bool operator==(const Range& aOther) const noexcept {
     58      return BaseRange::operator==(aOther) && mMin == aOther.mMin &&
     59             mMax == aOther.mMax && mIdeal == aOther.mIdeal;
     60    }
     61 
     62    template <class ConstrainRange>
     63    void SetFrom(const ConstrainRange& aOther);
     64 
     65    /// Clamp n based on Range. If the Range is empty, mMin is returned.
     66    ValueType Clamp(ValueType n) const { return std::clamp(n, mMin, mMax); }
     67    ValueType Get(ValueType defaultValue) const {
     68      return Clamp(mIdeal.valueOr(defaultValue));
     69    }
     70    bool Intersects(const Range& aOther) const {
     71      return mMax >= aOther.mMin && mMin <= aOther.mMax;
     72    }
     73    void Intersect(const Range& aOther) {
     74      mMin = std::max(mMin, aOther.mMin);
     75      if (Intersects(aOther)) {
     76        mMax = std::min(mMax, aOther.mMax);
     77      } else {
     78        // If there is no intersection, we will down-scale or drop frame
     79        mMax = std::max(mMax, aOther.mMax);
     80      }
     81    }
     82    bool Merge(const Range& aOther) {
     83      if (mName != "width" && mName != "height" && mName != "frameRate" &&
     84          !Intersects(aOther)) {
     85        return false;
     86      }
     87      Intersect(aOther);
     88 
     89      if (aOther.mIdeal.isSome()) {
     90        // Ideal values, as stored, may be outside their min max range, so use
     91        // clamped values in averaging, to avoid extreme outliers skewing
     92        // results.
     93        if (mIdeal.isNothing()) {
     94          mIdeal.emplace(aOther.Get(0));
     95          mMergeDenominator = 1;
     96        } else {
     97          if (!mMergeDenominator) {
     98            *mIdeal = Get(0);
     99            mMergeDenominator = 1;
    100          }
    101          *mIdeal += aOther.Get(0);
    102          mMergeDenominator++;
    103        }
    104      }
    105      return true;
    106    }
    107    void FinalizeMerge() override {
    108      if (mMergeDenominator) {
    109        *mIdeal /= mMergeDenominator;
    110        mMergeDenominator = 0;
    111      }
    112    }
    113    void TakeHighestIdeal(const Range& aOther) {
    114      if (aOther.mIdeal.isSome()) {
    115        if (mIdeal.isNothing()) {
    116          mIdeal.emplace(aOther.Get(0));
    117        } else {
    118          *mIdeal = std::max(Get(0), aOther.Get(0));
    119        }
    120      }
    121    }
    122 
    123   private:
    124    bool Merge(const BaseRange& aOther) override {
    125      return Merge(static_cast<const Range&>(aOther));
    126    }
    127 
    128    uint32_t mMergeDenominator;
    129  };
    130 
    131  struct LongRange final : public Range<int32_t> {
    132    LongRange(const nsCString& aName,
    133              const dom::Optional<dom::OwningLongOrConstrainLongRange>& aOther,
    134              bool advanced);
    135  };
    136 
    137  struct LongLongRange final : public Range<int64_t> {
    138    LongLongRange(const nsCString& aName, const dom::Optional<int64_t>& aOther);
    139  };
    140 
    141  struct DoubleRange final : public Range<double> {
    142    DoubleRange(
    143        const nsCString& aName,
    144        const dom::Optional<dom::OwningDoubleOrConstrainDoubleRange>& aOther,
    145        bool advanced);
    146  };
    147 
    148  struct BooleanRange final : public Range<bool> {
    149    BooleanRange(
    150        const nsCString& aName,
    151        const dom::Optional<dom::OwningBooleanOrConstrainBooleanParameters>&
    152            aOther,
    153        bool advanced);
    154 
    155    BooleanRange(const nsCString& aName, const bool& aOther)
    156        : Range<bool>(aName, false, true) {
    157      mIdeal.emplace(aOther);
    158    }
    159  };
    160 
    161  struct StringRange final : public BaseRange {
    162    using ValueType = std::set<nsString>;
    163    ValueType mExact, mIdeal;
    164 
    165    StringRange(
    166        const nsCString& aName,
    167        const dom::Optional<
    168            dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters>&
    169            aOther,
    170        bool advanced);
    171 
    172    StringRange(const nsCString& aName, const dom::Optional<nsString>& aOther)
    173        : BaseRange(aName) {
    174      if (aOther.WasPassed()) {
    175        mIdeal.insert(aOther.Value());
    176      }
    177    }
    178 
    179    ~StringRange() = default;
    180 
    181    bool operator==(const StringRange& aOther) const noexcept {
    182      return BaseRange::operator==(aOther) && mExact == aOther.mExact &&
    183             mIdeal == aOther.mIdeal;
    184    }
    185 
    186    void SetFrom(const dom::ConstrainDOMStringParameters& aOther);
    187    ValueType Clamp(const ValueType& n) const;
    188    ValueType Get(const ValueType& defaultValue) const {
    189      return Clamp(mIdeal.empty() ? defaultValue : mIdeal);
    190    }
    191    bool Intersects(const StringRange& aOther) const;
    192    void Intersect(const StringRange& aOther);
    193    bool Merge(const StringRange& aOther);
    194    void FinalizeMerge() override {}
    195 
    196   private:
    197    bool Merge(const BaseRange& aOther) override {
    198      return Merge(static_cast<const StringRange&>(aOther));
    199    }
    200  };
    201 
    202  // All new constraints should be added here whether they use flattening or not
    203  LongRange mWidth, mHeight;
    204  DoubleRange mFrameRate;
    205  StringRange mFacingMode;
    206  StringRange mResizeMode;
    207  StringRange mMediaSource;
    208  LongLongRange mBrowserWindow;
    209  StringRange mDeviceId;
    210  StringRange mGroupId;
    211  LongRange mViewportOffsetX, mViewportOffsetY, mViewportWidth, mViewportHeight;
    212  BooleanRange mEchoCancellation, mNoiseSuppression, mAutoGainControl;
    213  LongRange mChannelCount;
    214 
    215 public:
    216  NormalizedConstraintSet()
    217      : NormalizedConstraintSet(dom::MediaTrackConstraintSet(),
    218                                /* advanced = */ false) {}
    219 
    220  NormalizedConstraintSet(const dom::MediaTrackConstraintSet& aOther,
    221                          bool advanced)
    222      : mWidth("width"_ns, aOther.mWidth, advanced),
    223        mHeight("height"_ns, aOther.mHeight, advanced),
    224        mFrameRate("frameRate"_ns, aOther.mFrameRate, advanced),
    225        mFacingMode("facingMode"_ns, aOther.mFacingMode, advanced),
    226        mResizeMode("resizeMode"_ns, aOther.mResizeMode, advanced),
    227        mMediaSource("mediaSource"_ns, aOther.mMediaSource),
    228        mBrowserWindow("browserWindow"_ns, aOther.mBrowserWindow),
    229        mDeviceId("deviceId"_ns, aOther.mDeviceId, advanced),
    230        mGroupId("groupId"_ns, aOther.mGroupId, advanced),
    231        mViewportOffsetX("viewportOffsetX"_ns, aOther.mViewportOffsetX,
    232                         advanced),
    233        mViewportOffsetY("viewportOffsetY"_ns, aOther.mViewportOffsetY,
    234                         advanced),
    235        mViewportWidth("viewportWidth"_ns, aOther.mViewportWidth, advanced),
    236        mViewportHeight("viewportHeight"_ns, aOther.mViewportHeight, advanced),
    237        mEchoCancellation("echoCancellation"_ns, aOther.mEchoCancellation,
    238                          advanced),
    239        mNoiseSuppression("noiseSuppression"_ns, aOther.mNoiseSuppression,
    240                          advanced),
    241        mAutoGainControl("autoGainControl"_ns, aOther.mAutoGainControl,
    242                         advanced),
    243        mChannelCount("channelCount"_ns, aOther.mChannelCount, advanced) {}
    244 
    245  bool operator==(const NormalizedConstraintSet& aOther) const noexcept {
    246    return mWidth == aOther.mWidth && mHeight == aOther.mHeight &&
    247           mFrameRate == aOther.mFrameRate &&
    248           mFacingMode == aOther.mFacingMode &&
    249           mResizeMode == aOther.mResizeMode &&
    250           mMediaSource == aOther.mMediaSource &&
    251           mBrowserWindow == aOther.mBrowserWindow &&
    252           mDeviceId == aOther.mDeviceId && mGroupId == aOther.mGroupId &&
    253           mViewportOffsetX == aOther.mViewportOffsetX &&
    254           mViewportOffsetY == aOther.mViewportOffsetY &&
    255           mViewportWidth == aOther.mViewportWidth &&
    256           mViewportHeight == aOther.mViewportHeight &&
    257           mEchoCancellation == aOther.mEchoCancellation &&
    258           mNoiseSuppression == aOther.mNoiseSuppression &&
    259           mAutoGainControl == aOther.mAutoGainControl &&
    260           mChannelCount == aOther.mChannelCount;
    261  }
    262 };
    263 
    264 template <>
    265 bool NormalizedConstraintSet::Range<bool>::Merge(const Range& aOther);
    266 template <>
    267 void NormalizedConstraintSet::Range<bool>::FinalizeMerge();
    268 
    269 // Used instead of MediaTrackConstraints in lower-level code.
    270 struct NormalizedConstraints : public NormalizedConstraintSet {
    271  NormalizedConstraints() = default;
    272  explicit NormalizedConstraints(const dom::MediaTrackConstraints& aOther);
    273 
    274  bool operator==(const NormalizedConstraints& aOther) const noexcept {
    275    return NormalizedConstraintSet::operator==(aOther) &&
    276           mAdvanced == aOther.mAdvanced;
    277  }
    278 
    279  bool operator!=(const NormalizedConstraints& aOther) const noexcept {
    280    return !(*this == aOther);
    281  }
    282 
    283  std::vector<NormalizedConstraintSet> mAdvanced;
    284 };
    285 
    286 // Flattened version is used in low-level code with orthogonal constraints only.
    287 struct FlattenedConstraints : public NormalizedConstraintSet {
    288  FlattenedConstraints() = default;
    289  explicit FlattenedConstraints(const NormalizedConstraints& aOther);
    290  explicit FlattenedConstraints(const dom::MediaTrackConstraints& aOther)
    291      : FlattenedConstraints(NormalizedConstraints(aOther)) {}
    292 
    293  bool operator==(const FlattenedConstraints& aOther) const noexcept {
    294    return NormalizedConstraintSet::operator==(aOther);
    295  }
    296 
    297  bool operator!=(const FlattenedConstraints& aOther) const noexcept {
    298    return !(*this == aOther);
    299  }
    300 };
    301 
    302 // A helper class for MediaEngineSources
    303 class MediaConstraintsHelper {
    304 public:
    305  template <class ValueType, class NormalizedRange>
    306  static uint32_t FitnessDistance(ValueType aN, const NormalizedRange& aRange) {
    307    if (aRange.mMin > aN || aRange.mMax < aN) {
    308      return UINT32_MAX;
    309    }
    310    if (aN == aRange.mIdeal.valueOr(aN)) {
    311      return 0;
    312    }
    313    return uint32_t(
    314        ValueType((std::abs(aN - aRange.mIdeal.value()) * 1000) /
    315                  std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
    316  }
    317 
    318  template <class ValueType, class NormalizedRange>
    319  static uint32_t FeasibilityDistance(ValueType aN,
    320                                      const NormalizedRange& aRange) {
    321    if (aRange.mMin > aN) {
    322      return UINT32_MAX;
    323    }
    324    // We prefer larger resolution because now we support downscaling
    325    if (aN == aRange.mIdeal.valueOr(aN)) {
    326      return 0;
    327    }
    328 
    329    if (aN > aRange.mIdeal.value()) {
    330      return uint32_t(
    331          ValueType((std::abs(aN - aRange.mIdeal.value()) * 1000) /
    332                    std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
    333    }
    334 
    335    return 10000 +
    336           uint32_t(ValueType(
    337               (std::abs(aN - aRange.mIdeal.value()) * 1000) /
    338               std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
    339  }
    340 
    341  static uint32_t FitnessDistance(
    342      const Maybe<nsString>& aN,
    343      const NormalizedConstraintSet::StringRange& aParams);
    344 
    345 protected:
    346  static bool SomeSettingsFit(
    347      const NormalizedConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
    348      const nsTArray<RefPtr<LocalMediaDevice>>& aDevices);
    349 
    350 public:
    351  static uint32_t GetMinimumFitnessDistance(
    352      const NormalizedConstraintSet& aConstraints, const nsString& aDeviceId,
    353      const nsString& aGroupId);
    354 
    355  // Apply constrains to a supplied list of devices (removes items from the
    356  // list)
    357  static const char* SelectSettings(
    358      const NormalizedConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
    359      nsTArray<RefPtr<LocalMediaDevice>>& aDevices,
    360      dom::CallerType aCallerType);
    361 
    362  static const char* FindBadConstraint(
    363      const NormalizedConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
    364      const nsTArray<RefPtr<LocalMediaDevice>>& aDevices);
    365 
    366  static const char* FindBadConstraint(
    367      const NormalizedConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
    368      const MediaDevice* aMediaDevice);
    369 
    370  static void LogConstraints(const NormalizedConstraintSet& aConstraints);
    371 
    372  static Maybe<dom::VideoResizeModeEnum> GetResizeMode(
    373      const NormalizedConstraintSet& aConstraints,
    374      const MediaEnginePrefs& aPrefs);
    375 };
    376 
    377 }  // namespace mozilla
    378 
    379 #endif /* MEDIATRACKCONSTRAINTS_H_ */