tor-browser

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

JsepCodecDescription.h (51424B)


      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 #ifndef _JSEPCODECDESCRIPTION_H_
      6 #define _JSEPCODECDESCRIPTION_H_
      7 
      8 #include <cmath>
      9 #include <set>
     10 #include <string>
     11 
     12 #include "mozilla/Preferences.h"
     13 #include "mozilla/net/DataChannelProtocol.h"
     14 #include "nsCRT.h"
     15 #include "nsString.h"
     16 #include "sdp/SdpHelper.h"
     17 #include "sdp/SdpMediaSection.h"
     18 
     19 namespace mozilla {
     20 
     21 // These preferences are used to control the various default codec settings.
     22 // An implementation is expected to be provided to JSEP when generating default
     23 // codecs.
     24 class JsepCodecPreferences {
     25 public:
     26  JsepCodecPreferences() = default;
     27  virtual ~JsepCodecPreferences() = default;
     28 
     29  virtual bool AV1Enabled() const = 0;
     30  virtual bool AV1Preferred() const = 0;
     31  virtual bool H264Enabled() const = 0;
     32  virtual bool SoftwareH264Enabled() const = 0;
     33  virtual bool SendingH264PacketizationModeZeroSupported() const = 0;
     34  virtual bool H264BaselineDisabled() const = 0;
     35  virtual int32_t H264Level() const = 0;
     36  virtual int32_t H264MaxBr() const = 0;
     37  virtual int32_t H264MaxMbps() const = 0;
     38  virtual bool VP9Enabled() const = 0;
     39  virtual bool VP9Preferred() const = 0;
     40  virtual int32_t VP8MaxFs() const = 0;
     41  virtual int32_t VP8MaxFr() const = 0;
     42  virtual bool UseTmmbr() const = 0;
     43  virtual bool UseRemb() const = 0;
     44  virtual bool UseRtx() const = 0;
     45  virtual bool UseTransportCC() const = 0;
     46  virtual bool UseAudioFec() const = 0;
     47  virtual bool RedUlpfecEnabled() const = 0;
     48 
     49  friend std::ostream& operator<<(std::ostream& os,
     50                                  const JsepCodecPreferences& aPrefs) {
     51    os << "JsepCodecPreferences {\n";
     52 
     53    // Video codec support
     54    os << "  AV1Enabled: " << (aPrefs.AV1Enabled() ? "true" : "false") << "\n";
     55    os << "  H264Enabled: " << (aPrefs.H264Enabled() ? "true" : "false")
     56       << "\n";
     57    os << "  SoftwareH264Enabled: "
     58       << (aPrefs.SoftwareH264Enabled() ? "true" : "false") << "\n";
     59    os << "  SendingH264PacketizationModeZeroSupported: "
     60       << (aPrefs.SendingH264PacketizationModeZeroSupported() ? "true"
     61                                                              : "false")
     62       << "\n";
     63    os << "  H264Level: " << aPrefs.H264Level() << "\n";
     64    os << "  H264MaxBr: " << aPrefs.H264MaxBr() << "\n";
     65    os << "  H264MaxMbps: " << aPrefs.H264MaxMbps() << "\n";
     66 
     67    // VP8/VP9 support
     68    os << "  VP9Enabled: " << (aPrefs.VP9Enabled() ? "true" : "false") << "\n";
     69    os << "  VP9Preferred: " << (aPrefs.VP9Preferred() ? "true" : "false")
     70       << "\n";
     71    os << "  VP8MaxFs: " << aPrefs.VP8MaxFs() << "\n";
     72    os << "  VP8MaxFr: " << aPrefs.VP8MaxFr() << "\n";
     73 
     74    // RTP/RTCP features
     75    os << "  UseTmmbr: " << (aPrefs.UseTmmbr() ? "true" : "false") << "\n";
     76    os << "  UseRemb: " << (aPrefs.UseRemb() ? "true" : "false") << "\n";
     77    os << "  UseRtx: " << (aPrefs.UseRtx() ? "true" : "false") << "\n";
     78    os << "  UseTransportCC: " << (aPrefs.UseTransportCC() ? "true" : "false")
     79       << "\n";
     80 
     81    // Error correction
     82    os << "  UseAudioFec: " << (aPrefs.UseAudioFec() ? "true" : "false")
     83       << "\n";
     84    os << "  RedUlpfecEnabled: "
     85       << (aPrefs.RedUlpfecEnabled() ? "true" : "false") << "\n";
     86 
     87    os << "}";
     88    return os;
     89  }
     90 };
     91 
     92 #define JSEP_CODEC_CLONE(T) \
     93  JsepCodecDescription* Clone() const override { return new T(*this); }
     94 
     95 // A single entry in our list of known codecs.
     96 class JsepCodecDescription {
     97 public:
     98  JsepCodecDescription(const std::string& defaultPt, const std::string& name,
     99                       uint32_t clock, uint32_t channels)
    100      : mSupportedDirection(sdp::kSend | sdp::kRecv),
    101        mDefaultPt(defaultPt),
    102        mName(name),
    103        mClock(clock),
    104        mChannels(channels),
    105        mEnabled(true),
    106        mStronglyPreferred(false),
    107        mDirection(sdp::kSend) {}
    108  virtual ~JsepCodecDescription() {}
    109 
    110  virtual SdpMediaSection::MediaType Type() const = 0;
    111 
    112  virtual JsepCodecDescription* Clone() const = 0;
    113 
    114  bool GetPtAsInt(uint16_t* ptOutparam) const {
    115    return SdpHelper::GetPtAsInt(mDefaultPt, ptOutparam);
    116  }
    117 
    118  // The id used for codec stats, to uniquely identify this codec configuration
    119  // within a transport.
    120  const nsString& StatsId() const {
    121    if (!mStatsId) {
    122      mStatsId.emplace();
    123      mStatsId->AppendPrintf(
    124          "_%s_%s/%s_%u_%u_%s", mDefaultPt.c_str(),
    125          Type() == SdpMediaSection::kVideo ? "video" : "audio", mName.c_str(),
    126          mClock, mChannels, mSdpFmtpLine ? mSdpFmtpLine->c_str() : "nothing");
    127    }
    128    return *mStatsId;
    129  }
    130 
    131  virtual bool Matches(const std::string& fmt,
    132                       const SdpMediaSection& remoteMsection) const {
    133    // note: fmt here is remote fmt (to go with remoteMsection)
    134    if (Type() != remoteMsection.GetMediaType()) {
    135      return false;
    136    }
    137 
    138    const SdpRtpmapAttributeList::Rtpmap* entry(remoteMsection.FindRtpmap(fmt));
    139 
    140    if (entry) {
    141      if (!nsCRT::strcasecmp(mName.c_str(), entry->name.c_str()) &&
    142          (mClock == entry->clock) && (mChannels == entry->channels)) {
    143        return ParametersMatch(fmt, remoteMsection);
    144      }
    145    } else if (!fmt.compare("9") && mName == "G722") {
    146      return true;
    147    } else if (!fmt.compare("0") && mName == "PCMU") {
    148      return true;
    149    } else if (!fmt.compare("8") && mName == "PCMA") {
    150      return true;
    151    }
    152    return false;
    153  }
    154 
    155  virtual bool ParametersMatch(const std::string& fmt,
    156                               const SdpMediaSection& remoteMsection) const {
    157    return true;
    158  }
    159 
    160  Maybe<std::string> GetMatchingFormat(
    161      const SdpMediaSection& remoteMsection) const {
    162    for (const auto& fmt : remoteMsection.GetFormats()) {
    163      if (Matches(fmt, remoteMsection)) {
    164        return Some(fmt);
    165      }
    166    }
    167    return Nothing();
    168  }
    169 
    170  bool DirectionSupported(sdp::Direction aDirection) const {
    171    return mSupportedDirection & aDirection;
    172  }
    173 
    174  bool MsectionDirectionSupported(
    175      SdpDirectionAttribute::Direction aDirection) const {
    176    auto dir = static_cast<sdp::Direction>(aDirection);
    177    return (mSupportedDirection & dir) == dir;
    178  }
    179 
    180  virtual bool Negotiate(const std::string& pt,
    181                         const SdpMediaSection& remoteMsection,
    182                         bool remoteIsOffer,
    183                         Maybe<const SdpMediaSection&> localMsection) {
    184    // Configuration might change. Invalidate the stats id.
    185    mStatsId = Nothing();
    186    if (mDirection == sdp::kSend || remoteIsOffer) {
    187      mDefaultPt = pt;
    188    }
    189    if (localMsection) {
    190      // Offer/answer is concluding. Update the sdpFmtpLine.
    191      MOZ_ASSERT(mDirection == sdp::kSend || mDirection == sdp::kRecv);
    192      const SdpMediaSection& msection =
    193          mDirection == sdp::kSend ? remoteMsection : *localMsection;
    194      UpdateSdpFmtpLine(ToMaybeRef(msection.FindFmtp(mDefaultPt)));
    195    }
    196    return true;
    197  }
    198 
    199  virtual void ApplyConfigToFmtp(
    200      UniquePtr<SdpFmtpAttributeList::Parameters>& aFmtp) const = 0;
    201 
    202  virtual void AddToMediaSection(SdpMediaSection& msection) const {
    203    if (!mEnabled || msection.GetMediaType() != Type()) {
    204      return;
    205    }
    206    if (!MsectionDirectionSupported(msection.GetDirection())) {
    207      // Don't add this codec if there's no codec impl fully supporting the
    208      // msection direction.
    209      return;
    210    }
    211 
    212    if (mDirection == sdp::kRecv) {
    213      msection.AddCodec(mDefaultPt, mName, mClock, mChannels);
    214    }
    215 
    216    AddParametersToMSection(msection);
    217  }
    218 
    219  virtual void AddParametersToMSection(SdpMediaSection& msection) const {}
    220 
    221  virtual void EnsureNoDuplicatePayloadTypes(std::set<std::string>& aUsedPts) {
    222    mEnabled = EnsurePayloadTypeNotDuplicate(aUsedPts, mDefaultPt);
    223  }
    224 
    225  bool EnsurePayloadTypeNotDuplicate(std::set<std::string>& aUsedPts,
    226                                     std::string& aPtToCheck) {
    227    if (!mEnabled) {
    228      return false;
    229    }
    230 
    231    if (!aUsedPts.count(aPtToCheck)) {
    232      aUsedPts.insert(aPtToCheck);
    233      return true;
    234    }
    235 
    236    // |codec| cannot use its current payload type. Try to find another.
    237    for (uint16_t freePt = 96; freePt <= 127; ++freePt) {
    238      // Not super efficient, but readability is probably more important.
    239      std::ostringstream os;
    240      os << freePt;
    241      std::string freePtAsString = os.str();
    242 
    243      if (!aUsedPts.count(freePtAsString)) {
    244        aUsedPts.insert(freePtAsString);
    245        aPtToCheck = freePtAsString;
    246        return true;
    247      }
    248    }
    249 
    250    return false;
    251  }
    252 
    253  // TODO Bug 1751671: Take a verbatim fmtp line (std::string or eq.) instead
    254  // of fmtp parameters that have to be (re-)serialized.
    255  void UpdateSdpFmtpLine(
    256      const Maybe<const SdpFmtpAttributeList::Parameters&> aParams) {
    257    mSdpFmtpLine = aParams.map([](const auto& aFmtp) {
    258      std::stringstream ss;
    259      aFmtp.Serialize(ss);
    260      return ss.str();
    261    });
    262  }
    263 
    264  // The direction supported by encoders and decoders, to distinguish recvonly
    265  // codecs from sendrecv.
    266  sdp::Direction mSupportedDirection;
    267  std::string mDefaultPt;
    268  std::string mName;
    269  Maybe<std::string> mSdpFmtpLine;
    270  mutable Maybe<nsString> mStatsId;
    271  uint32_t mClock;
    272  uint32_t mChannels;
    273  bool mEnabled;
    274  bool mStronglyPreferred;
    275  sdp::Direction mDirection;
    276  // Will hold constraints from both fmtp and rid
    277  VideoEncodingConstraints mConstraints;
    278 };
    279 
    280 class JsepAudioCodecDescription final : public JsepCodecDescription {
    281 public:
    282  JsepAudioCodecDescription(const std::string& defaultPt,
    283                            const std::string& name, uint32_t clock,
    284                            uint32_t channels)
    285      : JsepCodecDescription(defaultPt, name, clock, channels),
    286        mMaxPlaybackRate(0),
    287        mForceMono(false),
    288        mFECEnabled(false),
    289        mDtmfEnabled(false),
    290        mMaxAverageBitrate(0),
    291        mDTXEnabled(false),
    292        mFrameSizeMs(0),
    293        mMinFrameSizeMs(0),
    294        mMaxFrameSizeMs(0),
    295        mCbrEnabled(false) {}
    296 
    297  static constexpr SdpMediaSection::MediaType type = SdpMediaSection::kAudio;
    298 
    299  SdpMediaSection::MediaType Type() const override { return type; }
    300 
    301  JSEP_CODEC_CLONE(JsepAudioCodecDescription)
    302 public:
    303  static UniquePtr<JsepAudioCodecDescription> CreateDefaultOpus(
    304      const JsepCodecPreferences& aPrefs) {
    305    // Per jmspeex on IRC:
    306    // For 32KHz sampling, 28 is ok, 32 is good, 40 should be really good
    307    // quality.  Note that 1-2Kbps will be wasted on a stereo Opus channel
    308    // with mono input compared to configuring it for mono.
    309    // If we reduce bitrate enough Opus will low-pass us; 16000 will kill a
    310    // 9KHz tone.  This should be adaptive when we're at the low-end of video
    311    // bandwidth (say <100Kbps), and if we're audio-only, down to 8 or
    312    // 12Kbps.
    313    auto codec = MakeUnique<JsepAudioCodecDescription>("109", "opus", 48000, 2);
    314    codec->mFECEnabled = aPrefs.UseAudioFec();
    315    return codec;
    316  }
    317 
    318  static UniquePtr<JsepAudioCodecDescription> CreateDefaultG722() {
    319    return MakeUnique<JsepAudioCodecDescription>("9", "G722", 8000, 1);
    320  }
    321 
    322  static UniquePtr<JsepAudioCodecDescription> CreateDefaultPCMU() {
    323    return MakeUnique<JsepAudioCodecDescription>("0", "PCMU", 8000, 1);
    324  }
    325 
    326  static UniquePtr<JsepAudioCodecDescription> CreateDefaultPCMA() {
    327    return MakeUnique<JsepAudioCodecDescription>("8", "PCMA", 8000, 1);
    328  }
    329 
    330  static UniquePtr<JsepAudioCodecDescription> CreateDefaultTelephoneEvent() {
    331    return MakeUnique<JsepAudioCodecDescription>("101", "telephone-event", 8000,
    332                                                 1);
    333  }
    334 
    335  SdpFmtpAttributeList::OpusParameters GetOpusParameters(
    336      const std::string& pt, const SdpMediaSection& msection) const {
    337    // Will contain defaults if nothing else
    338    SdpFmtpAttributeList::OpusParameters result;
    339    auto* params = msection.FindFmtp(pt);
    340 
    341    if (params && params->codec_type == SdpRtpmapAttributeList::kOpus) {
    342      result =
    343          static_cast<const SdpFmtpAttributeList::OpusParameters&>(*params);
    344    }
    345 
    346    return result;
    347  }
    348 
    349  SdpFmtpAttributeList::TelephoneEventParameters GetTelephoneEventParameters(
    350      const std::string& pt, const SdpMediaSection& msection) const {
    351    // Will contain defaults if nothing else
    352    SdpFmtpAttributeList::TelephoneEventParameters result;
    353    auto* params = msection.FindFmtp(pt);
    354 
    355    if (params &&
    356        params->codec_type == SdpRtpmapAttributeList::kTelephoneEvent) {
    357      result =
    358          static_cast<const SdpFmtpAttributeList::TelephoneEventParameters&>(
    359              *params);
    360    }
    361 
    362    return result;
    363  }
    364 
    365  void AddParametersToMSection(SdpMediaSection& msection) const override {
    366    if (mDirection == sdp::kSend) {
    367      return;
    368    }
    369 
    370    if (mName == "opus") {
    371      UniquePtr<SdpFmtpAttributeList::Parameters> opusParams =
    372          MakeUnique<SdpFmtpAttributeList::OpusParameters>(
    373              GetOpusParameters(mDefaultPt, msection));
    374 
    375      ApplyConfigToFmtp(opusParams);
    376 
    377      msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, *opusParams));
    378    } else if (mName == "telephone-event") {
    379      // add the default dtmf tones
    380      SdpFmtpAttributeList::TelephoneEventParameters teParams(
    381          GetTelephoneEventParameters(mDefaultPt, msection));
    382      msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, teParams));
    383    }
    384  }
    385 
    386  bool Negotiate(const std::string& pt, const SdpMediaSection& remoteMsection,
    387                 bool remoteIsOffer,
    388                 Maybe<const SdpMediaSection&> localMsection) override {
    389    JsepCodecDescription::Negotiate(pt, remoteMsection, remoteIsOffer,
    390                                    localMsection);
    391    if (mName == "opus" && mDirection == sdp::kSend) {
    392      SdpFmtpAttributeList::OpusParameters opusParams(
    393          GetOpusParameters(mDefaultPt, remoteMsection));
    394 
    395      mMaxPlaybackRate = opusParams.maxplaybackrate;
    396      mForceMono = !opusParams.stereo;
    397      // draft-ietf-rtcweb-fec-03.txt section 4.2 says support for FEC
    398      // at the received side is declarative and can be negotiated
    399      // separately for either media direction.
    400      mFECEnabled = opusParams.useInBandFec;
    401      if ((opusParams.maxAverageBitrate >= 6000) &&
    402          (opusParams.maxAverageBitrate <= 510000)) {
    403        mMaxAverageBitrate = opusParams.maxAverageBitrate;
    404      }
    405      mDTXEnabled = opusParams.useDTX;
    406      if (remoteMsection.GetAttributeList().HasAttribute(
    407              SdpAttribute::kPtimeAttribute)) {
    408        mFrameSizeMs = remoteMsection.GetAttributeList().GetPtime();
    409      } else {
    410        mFrameSizeMs = opusParams.frameSizeMs;
    411      }
    412      mMinFrameSizeMs = opusParams.minFrameSizeMs;
    413      if (remoteMsection.GetAttributeList().HasAttribute(
    414              SdpAttribute::kMaxptimeAttribute)) {
    415        mMaxFrameSizeMs = remoteMsection.GetAttributeList().GetMaxptime();
    416      } else {
    417        mMaxFrameSizeMs = opusParams.maxFrameSizeMs;
    418      }
    419      mCbrEnabled = opusParams.useCbr;
    420    }
    421 
    422    return true;
    423  }
    424 
    425  void ApplyConfigToFmtp(
    426      UniquePtr<SdpFmtpAttributeList::Parameters>& aFmtp) const override {
    427    if (mName == "opus") {
    428      SdpFmtpAttributeList::OpusParameters opusParams;
    429      if (aFmtp) {
    430        MOZ_RELEASE_ASSERT(aFmtp->codec_type == SdpRtpmapAttributeList::kOpus);
    431        opusParams =
    432            static_cast<const SdpFmtpAttributeList::OpusParameters&>(*aFmtp);
    433        opusParams.useInBandFec = mFECEnabled ? 1 : 0;
    434      } else {
    435        // If we weren't passed a fmtp to use then show we can do in band FEC
    436        // for getCapabilities queries.
    437        opusParams.useInBandFec = 1;
    438      }
    439      if (mMaxPlaybackRate) {
    440        opusParams.maxplaybackrate = mMaxPlaybackRate;
    441      }
    442      opusParams.maxAverageBitrate = mMaxAverageBitrate;
    443 
    444      if (mChannels == 2 &&
    445          !Preferences::GetBool("media.peerconnection.sdp.disable_stereo_fmtp",
    446                                false) &&
    447          !mForceMono) {
    448        // We prefer to receive stereo, if available.
    449        opusParams.stereo = 1;
    450      }
    451      opusParams.useDTX = mDTXEnabled;
    452      opusParams.frameSizeMs = mFrameSizeMs;
    453      opusParams.minFrameSizeMs = mMinFrameSizeMs;
    454      opusParams.maxFrameSizeMs = mMaxFrameSizeMs;
    455      opusParams.useCbr = mCbrEnabled;
    456      aFmtp.reset(opusParams.Clone());
    457    } else if (mName == "telephone-event") {
    458      if (!aFmtp) {
    459        // We only use the default right now
    460        aFmtp.reset(new SdpFmtpAttributeList::TelephoneEventParameters);
    461      }
    462    }
    463  };
    464 
    465  uint32_t mMaxPlaybackRate;
    466  bool mForceMono;
    467  bool mFECEnabled;
    468  bool mDtmfEnabled;
    469  uint32_t mMaxAverageBitrate;
    470  bool mDTXEnabled;
    471  uint32_t mFrameSizeMs;
    472  uint32_t mMinFrameSizeMs;
    473  uint32_t mMaxFrameSizeMs;
    474  bool mCbrEnabled;
    475 };
    476 
    477 class JsepVideoCodecDescription final : public JsepCodecDescription {
    478 public:
    479  JsepVideoCodecDescription(const std::string& defaultPt,
    480                            const std::string& name, uint32_t clock)
    481      : JsepCodecDescription(defaultPt, name, clock, 0),
    482        mTmmbrEnabled(false),
    483        mRembEnabled(false),
    484        mFECEnabled(false),
    485        mTransportCCEnabled(false),
    486        mRtxEnabled(false),
    487        mProfileLevelId(0),
    488        mPacketizationMode(0) {
    489    // Add supported rtcp-fb types
    490    mNackFbTypes.push_back("");
    491    mNackFbTypes.push_back(SdpRtcpFbAttributeList::pli);
    492    mCcmFbTypes.push_back(SdpRtcpFbAttributeList::fir);
    493  }
    494 
    495  static constexpr SdpMediaSection::MediaType type = SdpMediaSection::kVideo;
    496 
    497  SdpMediaSection::MediaType Type() const override { return type; }
    498 
    499  static auto ConfigureCommonVideoCodec(
    500      UniquePtr<JsepVideoCodecDescription> aCodec,
    501      const JsepCodecPreferences& aPrefs) {
    502    if (aPrefs.UseTmmbr()) {
    503      aCodec->EnableTmmbr();
    504    }
    505    if (aPrefs.UseRemb()) {
    506      aCodec->EnableRemb();
    507    }
    508    if (aPrefs.UseTransportCC()) {
    509      aCodec->EnableTransportCC();
    510    }
    511    return aCodec;
    512  }
    513 
    514  static UniquePtr<JsepVideoCodecDescription> CreateDefaultAV1(
    515      const JsepCodecPreferences& aPrefs) {
    516    // AV1 has no required RFC 8851 parameters
    517    // See:
    518    // https://aomediacodec.github.io/av1-rtp-spec/#722-rid-restrictions-mapping-for-av1
    519    auto codec = MakeUnique<JsepVideoCodecDescription>("99", "AV1", 90000);
    520    codec->mEnabled = aPrefs.AV1Enabled();
    521    codec->mStronglyPreferred = aPrefs.AV1Preferred();
    522    codec->mAv1Config.mProfile = Nothing();
    523    if (aPrefs.UseRtx()) {
    524      codec->EnableRtx("100");
    525    }
    526    return ConfigureCommonVideoCodec(std::move(codec), aPrefs);
    527  }
    528 
    529  static UniquePtr<JsepVideoCodecDescription> CreateDefaultVP8(
    530      const JsepCodecPreferences& aPrefs) {
    531    auto codec = MakeUnique<JsepVideoCodecDescription>("120", "VP8", 90000);
    532    // Defaults for mandatory params
    533    codec->mConstraints.maxFs = aPrefs.VP8MaxFs();
    534    codec->mConstraints.maxFps = Some(aPrefs.VP8MaxFr());
    535    if (aPrefs.UseRtx()) {
    536      codec->EnableRtx("124");
    537    }
    538    return ConfigureCommonVideoCodec(std::move(codec), aPrefs);
    539  }
    540 
    541  static UniquePtr<JsepVideoCodecDescription> CreateDefaultVP9(
    542      const JsepCodecPreferences& aPrefs) {
    543    auto codec = MakeUnique<JsepVideoCodecDescription>("121", "VP9", 90000);
    544    codec->mEnabled = aPrefs.VP9Enabled();
    545    // Defaults for mandatory params
    546    codec->mConstraints.maxFs = aPrefs.VP8MaxFs();
    547    codec->mConstraints.maxFps = Some(aPrefs.VP8MaxFr());
    548    if (aPrefs.UseRtx()) {
    549      codec->EnableRtx("125");
    550    }
    551    if (aPrefs.VP9Preferred() && aPrefs.VP9Enabled()) {
    552      codec->mStronglyPreferred = true;
    553    }
    554    return ConfigureCommonVideoCodec(std::move(codec), aPrefs);
    555  }
    556 
    557  static auto ConfigureCommonH264Codec(
    558      UniquePtr<JsepVideoCodecDescription> aCodec,
    559      const JsepCodecPreferences& aPrefs)
    560      -> UniquePtr<JsepVideoCodecDescription> {
    561    MOZ_ASSERT(aCodec->mName == "H264");
    562    if (JsepVideoCodecDescription::GetSubprofile(aCodec->mProfileLevelId) ==
    563        JsepVideoCodecDescription::kH264ConstrainedBaseline) {
    564      // Override level but not for the pure Baseline codec
    565      aCodec->mProfileLevelId &= 0xFFFF00;
    566      aCodec->mProfileLevelId |= aPrefs.H264Level();
    567    }
    568    aCodec->mConstraints.maxBr = aPrefs.H264MaxBr();
    569    aCodec->mConstraints.maxMbps = aPrefs.H264MaxMbps();
    570    return ConfigureCommonVideoCodec(std::move(aCodec), aPrefs);
    571  }
    572 
    573  static UniquePtr<JsepVideoCodecDescription> CreateDefaultH264_0(
    574      const JsepCodecPreferences& aPrefs) {
    575    auto codec = MakeUnique<JsepVideoCodecDescription>("97", "H264", 90000);
    576    codec->mEnabled = aPrefs.H264Enabled();
    577    codec->mPacketizationMode = 0;
    578    // Defaults for mandatory params
    579    codec->mProfileLevelId = 0x42E01F;
    580    if (!aPrefs.SendingH264PacketizationModeZeroSupported()) {
    581      codec->mSupportedDirection &= sdp::kRecv;
    582    }
    583    if (aPrefs.UseRtx()) {
    584      codec->EnableRtx("98");
    585    }
    586    return ConfigureCommonH264Codec(std::move(codec), aPrefs);
    587  }
    588 
    589  static UniquePtr<JsepVideoCodecDescription> CreateDefaultH264_1(
    590      const JsepCodecPreferences& aPrefs) {
    591    auto codec = MakeUnique<JsepVideoCodecDescription>("126", "H264", 90000);
    592    codec->mEnabled = aPrefs.H264Enabled();
    593    codec->mPacketizationMode = 1;
    594    // Defaults for mandatory params
    595    codec->mProfileLevelId = 0x42E01F;
    596    if (aPrefs.UseRtx()) {
    597      codec->EnableRtx("127");
    598    }
    599    return ConfigureCommonH264Codec(std::move(codec), aPrefs);
    600  }
    601 
    602  static UniquePtr<JsepVideoCodecDescription> CreateDefaultH264Baseline_0(
    603      const JsepCodecPreferences& aPrefs) {
    604    auto codec = MakeUnique<JsepVideoCodecDescription>("103", "H264", 90000);
    605    codec->mEnabled = aPrefs.H264Enabled() && !aPrefs.H264BaselineDisabled();
    606    codec->mPacketizationMode = 0;
    607    // Defaults for mandatory params
    608    codec->mProfileLevelId = 0x42001F;
    609    if (!aPrefs.SendingH264PacketizationModeZeroSupported()) {
    610      codec->mSupportedDirection &= sdp::kRecv;
    611    }
    612    if (aPrefs.UseRtx()) {
    613      codec->EnableRtx("104");
    614    }
    615    return ConfigureCommonH264Codec(std::move(codec), aPrefs);
    616  }
    617 
    618  static UniquePtr<JsepVideoCodecDescription> CreateDefaultH264Baseline_1(
    619      const JsepCodecPreferences& aPrefs) {
    620    auto codec = MakeUnique<JsepVideoCodecDescription>("105", "H264", 90000);
    621    codec->mEnabled = aPrefs.H264Enabled() && !aPrefs.H264BaselineDisabled();
    622    codec->mPacketizationMode = 1;
    623    // Defaults for mandatory params
    624    codec->mProfileLevelId = 0x42001F;
    625    if (aPrefs.UseRtx()) {
    626      codec->EnableRtx("106");
    627    }
    628    return ConfigureCommonH264Codec(std::move(codec), aPrefs);
    629  }
    630 
    631  static UniquePtr<JsepVideoCodecDescription> CreateDefaultUlpFec(
    632      const JsepCodecPreferences& aPrefs) {
    633    auto codec = MakeUnique<JsepVideoCodecDescription>(
    634        "123",     // payload type
    635        "ulpfec",  // codec name
    636        90000      // clock rate (match other video codecs)
    637    );
    638    codec->mEnabled = aPrefs.RedUlpfecEnabled();
    639    return ConfigureCommonVideoCodec(std::move(codec), aPrefs);
    640  }
    641 
    642  static UniquePtr<JsepVideoCodecDescription> CreateDefaultRed(
    643      const JsepCodecPreferences& aPrefs) {
    644    auto codec = MakeUnique<JsepVideoCodecDescription>(
    645        "122",  // payload type
    646        "red",  // codec name
    647        90000   // clock rate (match other video codecs)
    648    );
    649    codec->mEnabled = aPrefs.RedUlpfecEnabled();
    650    codec->EnableRtx("119");
    651    return ConfigureCommonVideoCodec(std::move(codec), aPrefs);
    652  }
    653 
    654  void ApplyConfigToFmtp(
    655      UniquePtr<SdpFmtpAttributeList::Parameters>& aFmtp) const override {
    656    if (mName == "H264") {
    657      SdpFmtpAttributeList::H264Parameters h264Params;
    658      if (aFmtp) {
    659        MOZ_RELEASE_ASSERT(aFmtp->codec_type == SdpRtpmapAttributeList::kH264);
    660        h264Params =
    661            static_cast<const SdpFmtpAttributeList::H264Parameters&>(*aFmtp);
    662      }
    663 
    664      if (mDirection == sdp::kSend) {
    665        if (!h264Params.level_asymmetry_allowed) {
    666          // First time the fmtp has been set; set just in case this is for a
    667          // sendonly m-line, since even though we aren't receiving the level
    668          // negotiation still needs to happen (sigh).
    669          h264Params.profile_level_id = mProfileLevelId;
    670        }
    671      } else {
    672        // Parameters that only apply to what we receive
    673        h264Params.max_mbps = mConstraints.maxMbps;
    674        h264Params.max_fs = mConstraints.maxFs;
    675        h264Params.max_cpb = mConstraints.maxCpb;
    676        h264Params.max_dpb = mConstraints.maxDpb;
    677        h264Params.max_br = mConstraints.maxBr;
    678        strncpy(h264Params.sprop_parameter_sets, mSpropParameterSets.c_str(),
    679                sizeof(h264Params.sprop_parameter_sets) - 1);
    680        h264Params.profile_level_id = mProfileLevelId;
    681      }
    682 
    683      // Parameters that apply to both the send and recv directions
    684      h264Params.packetization_mode = mPacketizationMode;
    685      // Hard-coded, may need to change someday?
    686      h264Params.level_asymmetry_allowed = true;
    687 
    688      // Parameters that apply to both the send and recv directions
    689      h264Params.packetization_mode = mPacketizationMode;
    690      // Hard-coded, may need to change someday?
    691      h264Params.level_asymmetry_allowed = true;
    692      aFmtp.reset(h264Params.Clone());
    693    } else if (mName == "VP8" || mName == "VP9") {
    694      SdpRtpmapAttributeList::CodecType type =
    695          mName == "VP8" ? SdpRtpmapAttributeList::CodecType::kVP8
    696                         : SdpRtpmapAttributeList::CodecType::kVP9;
    697      auto vp8Params = SdpFmtpAttributeList::VP8Parameters(type);
    698 
    699      if (aFmtp) {
    700        MOZ_RELEASE_ASSERT(aFmtp->codec_type == type);
    701        vp8Params =
    702            static_cast<const SdpFmtpAttributeList::VP8Parameters&>(*aFmtp);
    703      }
    704      // VP8 and VP9 share the same SDP parameters thus far
    705      vp8Params.max_fs = mConstraints.maxFs;
    706      if (mConstraints.maxFps.isSome()) {
    707        vp8Params.max_fr =
    708            static_cast<unsigned int>(std::round(*mConstraints.maxFps));
    709      } else {
    710        vp8Params.max_fr = 60;
    711      }
    712      aFmtp.reset(vp8Params.Clone());
    713    } else if (mName == "AV1") {
    714      auto av1Params = SdpFmtpAttributeList::Av1Parameters();
    715      if (aFmtp) {
    716        MOZ_RELEASE_ASSERT(aFmtp->codec_type == SdpRtpmapAttributeList::kAV1);
    717        av1Params =
    718            static_cast<const SdpFmtpAttributeList::Av1Parameters&>(*aFmtp);
    719        av1Params.profile = mAv1Config.mProfile;
    720        av1Params.levelIdx = mAv1Config.mLevelIdx;
    721        av1Params.tier = mAv1Config.mTier;
    722      }
    723      aFmtp.reset(av1Params.Clone());
    724    }
    725  }
    726 
    727  void EnableTmmbr() {
    728    // EnableTmmbr can be called multiple times due to multiple calls to
    729    // PeerConnectionImpl::ConfigureJsepSessionCodecs
    730    if (!mTmmbrEnabled) {
    731      mTmmbrEnabled = true;
    732      mCcmFbTypes.push_back(SdpRtcpFbAttributeList::tmmbr);
    733    }
    734  }
    735 
    736  void EnableRemb() {
    737    // EnableRemb can be called multiple times due to multiple calls to
    738    // PeerConnectionImpl::ConfigureJsepSessionCodecs
    739    if (!mRembEnabled) {
    740      mRembEnabled = true;
    741      mOtherFbTypes.push_back({"", SdpRtcpFbAttributeList::kRemb, "", ""});
    742    }
    743  }
    744 
    745  void EnableFec(std::string redPayloadType, std::string ulpfecPayloadType,
    746                 std::string redRtxPayloadType) {
    747    // Enabling FEC for video works a little differently than enabling
    748    // REMB or TMMBR.  Support for FEC is indicated by the presence of
    749    // particular codes (red and ulpfec) instead of using rtcpfb
    750    // attributes on a given codec.  There is no rtcpfb to push for FEC
    751    // as can be seen above when REMB or TMMBR are enabled.
    752 
    753    // Ensure we have valid payload types. This returns zero on failure, which
    754    // is a valid payload type.
    755    uint16_t redPt, ulpfecPt, redRtxPt;
    756    if (!SdpHelper::GetPtAsInt(redPayloadType, &redPt) ||
    757        !SdpHelper::GetPtAsInt(ulpfecPayloadType, &ulpfecPt) ||
    758        !SdpHelper::GetPtAsInt(redRtxPayloadType, &redRtxPt)) {
    759      return;
    760    }
    761 
    762    mFECEnabled = true;
    763    mREDPayloadType = redPayloadType;
    764    mULPFECPayloadType = ulpfecPayloadType;
    765    mREDRTXPayloadType = redRtxPayloadType;
    766  }
    767 
    768  void EnableTransportCC() {
    769    if (!mTransportCCEnabled) {
    770      mTransportCCEnabled = true;
    771      mOtherFbTypes.push_back(
    772          {"", SdpRtcpFbAttributeList::kTransportCC, "", ""});
    773    }
    774  }
    775 
    776  void EnableRtx(const std::string& rtxPayloadType) {
    777    mRtxEnabled = true;
    778    mRtxPayloadType = rtxPayloadType;
    779  }
    780 
    781  void AddParametersToMSection(SdpMediaSection& msection) const override {
    782    AddFmtpsToMSection(msection);
    783    AddRtcpFbsToMSection(msection);
    784  }
    785 
    786  void AddFmtpsToMSection(SdpMediaSection& msection) const {
    787    MOZ_ASSERT(mEnabled);
    788    MOZ_ASSERT(MsectionDirectionSupported(msection.GetDirection()));
    789 
    790    if (mName == "H264") {
    791      UniquePtr<SdpFmtpAttributeList::Parameters> h264Params =
    792          MakeUnique<SdpFmtpAttributeList::H264Parameters>(
    793              GetH264Parameters(mDefaultPt, msection));
    794 
    795      ApplyConfigToFmtp(h264Params);
    796 
    797      msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, *h264Params));
    798    } else if (mName == "VP8" || mName == "VP9") {
    799      if (mDirection == sdp::kRecv) {
    800        // VP8 and VP9 share the same SDP parameters thus far
    801        UniquePtr<SdpFmtpAttributeList::Parameters> vp8Params =
    802            MakeUnique<SdpFmtpAttributeList::VP8Parameters>(
    803                GetVP8Parameters(mDefaultPt, msection));
    804        ApplyConfigToFmtp(vp8Params);
    805        msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, *vp8Params));
    806      }
    807    } else if (mName == "AV1") {
    808      UniquePtr<SdpFmtpAttributeList::Parameters> av1Params =
    809          MakeUnique<SdpFmtpAttributeList::Av1Parameters>(
    810              GetAv1Parameters(mDefaultPt, msection));
    811      ApplyConfigToFmtp(av1Params);
    812      msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, *av1Params));
    813    }
    814 
    815    if (mRtxEnabled && mDirection == sdp::kRecv) {
    816      SdpFmtpAttributeList::RtxParameters params(
    817          GetRtxParameters(mDefaultPt, msection));
    818      uint16_t apt;
    819      if (SdpHelper::GetPtAsInt(mDefaultPt, &apt)) {
    820        if (apt <= 127) {
    821          msection.AddCodec(mRtxPayloadType, "rtx", mClock, mChannels);
    822 
    823          params.apt = apt;
    824          msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mRtxPayloadType, params));
    825        }
    826      }
    827    }
    828  }
    829 
    830  void AddRtcpFbsToMSection(SdpMediaSection& msection) const {
    831    MOZ_ASSERT(mEnabled);
    832    MOZ_ASSERT(MsectionDirectionSupported(msection.GetDirection()));
    833 
    834    SdpRtcpFbAttributeList rtcpfbs(msection.GetRtcpFbs());
    835    for (const auto& rtcpfb : rtcpfbs.mFeedbacks) {
    836      if (rtcpfb.pt == mDefaultPt) {
    837        // Already set by the codec for the other direction.
    838        return;
    839      }
    840    }
    841 
    842    for (const std::string& type : mAckFbTypes) {
    843      rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kAck, type);
    844    }
    845    for (const std::string& type : mNackFbTypes) {
    846      rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kNack, type);
    847    }
    848    for (const std::string& type : mCcmFbTypes) {
    849      rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kCcm, type);
    850    }
    851    for (const auto& fb : mOtherFbTypes) {
    852      rtcpfbs.PushEntry(mDefaultPt, fb.type, fb.parameter, fb.extra);
    853    }
    854 
    855    msection.SetRtcpFbs(rtcpfbs);
    856  }
    857 
    858  SdpFmtpAttributeList::H264Parameters GetH264Parameters(
    859      const std::string& pt, const SdpMediaSection& msection) const {
    860    // Will contain defaults if nothing else
    861    SdpFmtpAttributeList::H264Parameters result;
    862    auto* params = msection.FindFmtp(pt);
    863 
    864    if (params && params->codec_type == SdpRtpmapAttributeList::kH264) {
    865      result =
    866          static_cast<const SdpFmtpAttributeList::H264Parameters&>(*params);
    867    }
    868 
    869    return result;
    870  }
    871 
    872  SdpFmtpAttributeList::RedParameters GetRedParameters(
    873      const std::string& pt, const SdpMediaSection& msection) const {
    874    SdpFmtpAttributeList::RedParameters result;
    875    auto* params = msection.FindFmtp(pt);
    876 
    877    if (params && params->codec_type == SdpRtpmapAttributeList::kRed) {
    878      result = static_cast<const SdpFmtpAttributeList::RedParameters&>(*params);
    879    }
    880 
    881    return result;
    882  }
    883 
    884  SdpFmtpAttributeList::RtxParameters GetRtxParameters(
    885      const std::string& pt, const SdpMediaSection& msection) const {
    886    SdpFmtpAttributeList::RtxParameters result;
    887    const auto* params = msection.FindFmtp(pt);
    888 
    889    if (params && params->codec_type == SdpRtpmapAttributeList::kRtx) {
    890      result = static_cast<const SdpFmtpAttributeList::RtxParameters&>(*params);
    891    }
    892 
    893    return result;
    894  }
    895 
    896  Maybe<std::string> GetRtxPtByApt(const std::string& apt,
    897                                   const SdpMediaSection& msection) const {
    898    Maybe<std::string> result;
    899    uint16_t aptAsInt;
    900    if (!SdpHelper::GetPtAsInt(apt, &aptAsInt)) {
    901      return result;
    902    }
    903 
    904    const SdpAttributeList& attrs = msection.GetAttributeList();
    905    if (attrs.HasAttribute(SdpAttribute::kFmtpAttribute)) {
    906      for (const auto& fmtpAttr : attrs.GetFmtp().mFmtps) {
    907        if (fmtpAttr.parameters) {
    908          auto* params = fmtpAttr.parameters.get();
    909          if (params && params->codec_type == SdpRtpmapAttributeList::kRtx) {
    910            const SdpFmtpAttributeList::RtxParameters* rtxParams =
    911                static_cast<const SdpFmtpAttributeList::RtxParameters*>(params);
    912            if (rtxParams->apt == aptAsInt) {
    913              result = Some(fmtpAttr.format);
    914              break;
    915            }
    916          }
    917        }
    918      }
    919    }
    920    return result;
    921  }
    922 
    923  SdpFmtpAttributeList::VP8Parameters GetVP8Parameters(
    924      const std::string& pt, const SdpMediaSection& msection) const {
    925    SdpRtpmapAttributeList::CodecType expectedType(
    926        mName == "VP8" ? SdpRtpmapAttributeList::kVP8
    927                       : SdpRtpmapAttributeList::kVP9);
    928 
    929    // Will contain defaults if nothing else
    930    SdpFmtpAttributeList::VP8Parameters result(expectedType);
    931    auto* params = msection.FindFmtp(pt);
    932 
    933    if (params && params->codec_type == expectedType) {
    934      result = static_cast<const SdpFmtpAttributeList::VP8Parameters&>(*params);
    935    }
    936 
    937    return result;
    938  }
    939 
    940  SdpFmtpAttributeList::Av1Parameters GetAv1Parameters(
    941      const std::string& pt, const SdpMediaSection& msection) const {
    942    SdpRtpmapAttributeList::CodecType expectedType(
    943        SdpRtpmapAttributeList::kAV1);
    944 
    945    // Will contain defaults if nothing else
    946    SdpFmtpAttributeList::Av1Parameters result;
    947    const auto* params = msection.FindFmtp(pt);
    948 
    949    if (params && params->codec_type == expectedType) {
    950      result = static_cast<const SdpFmtpAttributeList::Av1Parameters&>(*params);
    951    }
    952 
    953    return result;
    954  }
    955 
    956  void NegotiateRtcpFb(const SdpMediaSection& remoteMsection,
    957                       SdpRtcpFbAttributeList::Type type,
    958                       std::vector<std::string>* supportedTypes) {
    959    Maybe<std::string> remoteFmt = GetMatchingFormat(remoteMsection);
    960    if (!remoteFmt) {
    961      return;
    962    }
    963    std::vector<std::string> temp;
    964    for (auto& subType : *supportedTypes) {
    965      if (remoteMsection.HasRtcpFb(*remoteFmt, type, subType)) {
    966        temp.push_back(subType);
    967      }
    968    }
    969    *supportedTypes = temp;
    970  }
    971 
    972  void NegotiateRtcpFb(
    973      const SdpMediaSection& remoteMsection,
    974      std::vector<SdpRtcpFbAttributeList::Feedback>* supportedFbs) {
    975    Maybe<std::string> remoteFmt = GetMatchingFormat(remoteMsection);
    976    if (!remoteFmt) {
    977      return;
    978    }
    979    std::vector<SdpRtcpFbAttributeList::Feedback> temp;
    980    for (auto& fb : *supportedFbs) {
    981      if (remoteMsection.HasRtcpFb(*remoteFmt, fb.type, fb.parameter)) {
    982        temp.push_back(fb);
    983      }
    984    }
    985    *supportedFbs = temp;
    986  }
    987 
    988  void NegotiateRtcpFb(const SdpMediaSection& remote) {
    989    // Removes rtcp-fb types that the other side doesn't support
    990    NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kAck, &mAckFbTypes);
    991    NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kNack, &mNackFbTypes);
    992    NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kCcm, &mCcmFbTypes);
    993    NegotiateRtcpFb(remote, &mOtherFbTypes);
    994  }
    995 
    996  // Some parameters are hierarchical, meaning that a lower value reflects a
    997  // lower capability.  In these cases, we want the sender to use the lower of
    998  // the two values. There is also an implied default value which may be higher
    999  // than the signalled value.
   1000  template <typename T>
   1001  static auto NegotiateHierarchicalParam(const sdp::Direction direction,
   1002                                         const Maybe<T>& localParam,
   1003                                         const Maybe<T>& remoteParam,
   1004                                         const T& defaultValue) -> Maybe<T> {
   1005    const auto maybe_min = [&](const Maybe<T>& a,
   1006                               const Maybe<T>& b) -> Maybe<T> {
   1007      auto val = std::min(a.valueOr(defaultValue), b.valueOr(defaultValue));
   1008      if (val == defaultValue) {
   1009        // Are we using defaultValue because we fell back on it, or because it
   1010        // was actually signaled?
   1011        if (a != Some(defaultValue) && b != Some(defaultValue)) {
   1012          return Nothing();
   1013        }
   1014      }
   1015      return Some(val);
   1016    };
   1017    if (direction == sdp::kSend) {
   1018      return maybe_min(localParam, remoteParam);
   1019    }
   1020    return localParam;
   1021  }
   1022 
   1023  bool Negotiate(const std::string& pt, const SdpMediaSection& remoteMsection,
   1024                 bool remoteIsOffer,
   1025                 Maybe<const SdpMediaSection&> localMsection) override {
   1026    JsepCodecDescription::Negotiate(pt, remoteMsection, remoteIsOffer,
   1027                                    localMsection);
   1028    if (mName == "H264") {
   1029      SdpFmtpAttributeList::H264Parameters h264Params(
   1030          GetH264Parameters(mDefaultPt, remoteMsection));
   1031 
   1032      // Level is negotiated symmetrically if level asymmetry is disallowed
   1033      if (!h264Params.level_asymmetry_allowed) {
   1034        SetSaneH264Level(std::min(GetSaneH264Level(h264Params.profile_level_id),
   1035                                  GetSaneH264Level(mProfileLevelId)),
   1036                         &mProfileLevelId);
   1037      }
   1038 
   1039      if (mDirection == sdp::kSend) {
   1040        // Remote values of these apply only to the send codec.
   1041        mConstraints.maxFs = h264Params.max_fs;
   1042        mConstraints.maxMbps = h264Params.max_mbps;
   1043        mConstraints.maxCpb = h264Params.max_cpb;
   1044        mConstraints.maxDpb = h264Params.max_dpb;
   1045        mConstraints.maxBr = h264Params.max_br;
   1046        mSpropParameterSets = h264Params.sprop_parameter_sets;
   1047        // Only do this if we didn't symmetrically negotiate above
   1048        if (h264Params.level_asymmetry_allowed) {
   1049          SetSaneH264Level(GetSaneH264Level(h264Params.profile_level_id),
   1050                           &mProfileLevelId);
   1051        }
   1052      } else {
   1053        // TODO(bug 1143709): max-recv-level support
   1054      }
   1055    } else if (mName == "VP8" || mName == "VP9") {
   1056      if (mDirection == sdp::kSend) {
   1057        SdpFmtpAttributeList::VP8Parameters vp8Params(
   1058            GetVP8Parameters(mDefaultPt, remoteMsection));
   1059 
   1060        mConstraints.maxFs = vp8Params.max_fs;
   1061        // Right now, we treat max-fr=0 (or the absence of max-fr) as no limit.
   1062        // We will eventually want to stop doing this (bug 1762600).
   1063        if (vp8Params.max_fr) {
   1064          mConstraints.maxFps = Some(vp8Params.max_fr);
   1065        }
   1066      }
   1067    } else if (mName == "AV1") {
   1068      using Av1Params = SdpFmtpAttributeList::Av1Parameters;
   1069      Av1Params av1Params(GetAv1Parameters(mDefaultPt, remoteMsection));
   1070 
   1071      Maybe<SdpFmtpAttributeList::Av1Parameters> localParams =
   1072          localMsection.isSome()
   1073              ? Some(GetAv1Parameters(mDefaultPt, *localMsection))
   1074              : Nothing();
   1075      auto localProfile =
   1076          localParams.isSome() ? localParams.value().profile : Nothing();
   1077      auto localLevelIdx =
   1078          localParams.isSome() ? localParams.value().levelIdx : Nothing();
   1079      auto tier = localParams.isSome() ? localParams.value().tier : Nothing();
   1080 
   1081      av1Params.profile = NegotiateHierarchicalParam(
   1082          mDirection, localProfile, av1Params.profile,
   1083          Av1Params::kDefaultProfile);
   1084      av1Params.levelIdx = NegotiateHierarchicalParam(
   1085          mDirection, localLevelIdx, av1Params.levelIdx,
   1086          Av1Params::kDefaultLevelIdx);
   1087      av1Params.tier = NegotiateHierarchicalParam(
   1088          mDirection, tier, av1Params.tier, Av1Params::kDefaultTier);
   1089      mAv1Config = Av1Config(av1Params);
   1090    }
   1091 
   1092    if (mRtxEnabled && (mDirection == sdp::kSend || remoteIsOffer)) {
   1093      Maybe<std::string> rtxPt = GetRtxPtByApt(mDefaultPt, remoteMsection);
   1094      if (rtxPt.isSome()) {
   1095        EnableRtx(*rtxPt);
   1096      } else {
   1097        mRtxEnabled = false;
   1098        mRtxPayloadType = "";
   1099      }
   1100    }
   1101 
   1102    NegotiateRtcpFb(remoteMsection);
   1103    return true;
   1104  }
   1105 
   1106  // Maps the not-so-sane encoding of H264 level into something that is
   1107  // ordered in the way one would expect
   1108  // 1b is 0xAB, everything else is the level left-shifted one half-byte
   1109  // (eg; 1.0 is 0xA0, 1.1 is 0xB0, 3.1 is 0x1F0)
   1110  static uint32_t GetSaneH264Level(uint32_t profileLevelId) {
   1111    uint32_t profileIdc = (profileLevelId >> 16);
   1112 
   1113    if (profileIdc == 0x42 || profileIdc == 0x4D || profileIdc == 0x58) {
   1114      if ((profileLevelId & 0x10FF) == 0x100B) {
   1115        // Level 1b
   1116        return 0xAB;
   1117      }
   1118    }
   1119 
   1120    uint32_t level = profileLevelId & 0xFF;
   1121 
   1122    if (level == 0x09) {
   1123      // Another way to encode level 1b
   1124      return 0xAB;
   1125    }
   1126 
   1127    return level << 4;
   1128  }
   1129 
   1130  static void SetSaneH264Level(uint32_t level, uint32_t* profileLevelId) {
   1131    uint32_t profileIdc = (*profileLevelId >> 16);
   1132    uint32_t levelMask = 0xFF;
   1133 
   1134    if (profileIdc == 0x42 || profileIdc == 0x4d || profileIdc == 0x58) {
   1135      levelMask = 0x10FF;
   1136      if (level == 0xAB) {
   1137        // Level 1b
   1138        level = 0x100B;
   1139      } else {
   1140        // Not 1b, just shift
   1141        level = level >> 4;
   1142      }
   1143    } else if (level == 0xAB) {
   1144      // Another way to encode 1b
   1145      level = 0x09;
   1146    } else {
   1147      // Not 1b, just shift
   1148      level = level >> 4;
   1149    }
   1150 
   1151    *profileLevelId = (*profileLevelId & ~levelMask) | level;
   1152  }
   1153 
   1154  enum Subprofile {
   1155    kH264ConstrainedBaseline,
   1156    kH264Baseline,
   1157    kH264Main,
   1158    kH264Extended,
   1159    kH264High,
   1160    kH264High10,
   1161    kH264High42,
   1162    kH264High44,
   1163    kH264High10I,
   1164    kH264High42I,
   1165    kH264High44I,
   1166    kH264CALVC44,
   1167    kH264UnknownSubprofile
   1168  };
   1169 
   1170  static Subprofile GetSubprofile(uint32_t profileLevelId) {
   1171    // Based on Table 5 from RFC 6184:
   1172    //        Profile     profile_idc        profile-iop
   1173    //                    (hexadecimal)      (binary)
   1174 
   1175    //        CB          42 (B)             x1xx0000
   1176    //           same as: 4D (M)             1xxx0000
   1177    //           same as: 58 (E)             11xx0000
   1178    //        B           42 (B)             x0xx0000
   1179    //           same as: 58 (E)             10xx0000
   1180    //        M           4D (M)             0x0x0000
   1181    //        E           58                 00xx0000
   1182    //        H           64                 00000000
   1183    //        H10         6E                 00000000
   1184    //        H42         7A                 00000000
   1185    //        H44         F4                 00000000
   1186    //        H10I        6E                 00010000
   1187    //        H42I        7A                 00010000
   1188    //        H44I        F4                 00010000
   1189    //        C44I        2C                 00010000
   1190 
   1191    if ((profileLevelId & 0xFF4F00) == 0x424000) {
   1192      // 01001111 (mask, 0x4F)
   1193      // x1xx0000 (from table)
   1194      // 01000000 (expected value, 0x40)
   1195      return kH264ConstrainedBaseline;
   1196    }
   1197 
   1198    if ((profileLevelId & 0xFF8F00) == 0x4D8000) {
   1199      // 10001111 (mask, 0x8F)
   1200      // 1xxx0000 (from table)
   1201      // 10000000 (expected value, 0x80)
   1202      return kH264ConstrainedBaseline;
   1203    }
   1204 
   1205    if ((profileLevelId & 0xFFCF00) == 0x58C000) {
   1206      // 11001111 (mask, 0xCF)
   1207      // 11xx0000 (from table)
   1208      // 11000000 (expected value, 0xC0)
   1209      return kH264ConstrainedBaseline;
   1210    }
   1211 
   1212    if ((profileLevelId & 0xFF4F00) == 0x420000) {
   1213      // 01001111 (mask, 0x4F)
   1214      // x0xx0000 (from table)
   1215      // 00000000 (expected value)
   1216      return kH264Baseline;
   1217    }
   1218 
   1219    if ((profileLevelId & 0xFFCF00) == 0x588000) {
   1220      // 11001111 (mask, 0xCF)
   1221      // 10xx0000 (from table)
   1222      // 10000000 (expected value, 0x80)
   1223      return kH264Baseline;
   1224    }
   1225 
   1226    if ((profileLevelId & 0xFFAF00) == 0x4D0000) {
   1227      // 10101111 (mask, 0xAF)
   1228      // 0x0x0000 (from table)
   1229      // 00000000 (expected value)
   1230      return kH264Main;
   1231    }
   1232 
   1233    if ((profileLevelId & 0xFF0000) == 0x580000) {
   1234      // 11001111 (mask, 0xCF)
   1235      // 00xx0000 (from table)
   1236      // 00000000 (expected value)
   1237      return kH264Extended;
   1238    }
   1239 
   1240    if ((profileLevelId & 0xFFFF00) == 0x640000) {
   1241      return kH264High;
   1242    }
   1243 
   1244    if ((profileLevelId & 0xFFFF00) == 0x6E0000) {
   1245      return kH264High10;
   1246    }
   1247 
   1248    if ((profileLevelId & 0xFFFF00) == 0x7A0000) {
   1249      return kH264High42;
   1250    }
   1251 
   1252    if ((profileLevelId & 0xFFFF00) == 0xF40000) {
   1253      return kH264High44;
   1254    }
   1255 
   1256    if ((profileLevelId & 0xFFFF00) == 0x6E1000) {
   1257      return kH264High10I;
   1258    }
   1259 
   1260    if ((profileLevelId & 0xFFFF00) == 0x7A1000) {
   1261      return kH264High42I;
   1262    }
   1263 
   1264    if ((profileLevelId & 0xFFFF00) == 0xF41000) {
   1265      return kH264High44I;
   1266    }
   1267 
   1268    if ((profileLevelId & 0xFFFF00) == 0x2C1000) {
   1269      return kH264CALVC44;
   1270    }
   1271 
   1272    return kH264UnknownSubprofile;
   1273  }
   1274 
   1275  bool ParametersMatch(const std::string& fmt,
   1276                       const SdpMediaSection& remoteMsection) const override {
   1277    if (mName == "H264") {
   1278      SdpFmtpAttributeList::H264Parameters h264Params(
   1279          GetH264Parameters(fmt, remoteMsection));
   1280 
   1281      if (h264Params.packetization_mode != mPacketizationMode) {
   1282        return false;
   1283      }
   1284 
   1285      if (GetSubprofile(h264Params.profile_level_id) !=
   1286          GetSubprofile(mProfileLevelId)) {
   1287        return false;
   1288      }
   1289    }
   1290 
   1291    return true;
   1292  }
   1293 
   1294  bool RtcpFbRembIsSet() const {
   1295    for (const auto& fb : mOtherFbTypes) {
   1296      if (fb.type == SdpRtcpFbAttributeList::kRemb) {
   1297        return true;
   1298      }
   1299    }
   1300    return false;
   1301  }
   1302 
   1303  bool RtcpFbTransportCCIsSet() const {
   1304    for (const auto& fb : mOtherFbTypes) {
   1305      if (fb.type == SdpRtcpFbAttributeList::kTransportCC) {
   1306        return true;
   1307      }
   1308    }
   1309    return false;
   1310  }
   1311 
   1312  void EnsureNoDuplicatePayloadTypes(std::set<std::string>& aUsedPts) override {
   1313    JsepCodecDescription::EnsureNoDuplicatePayloadTypes(aUsedPts);
   1314    if (mFECEnabled) {
   1315      mFECEnabled = EnsurePayloadTypeNotDuplicate(aUsedPts, mREDPayloadType) &&
   1316                    EnsurePayloadTypeNotDuplicate(aUsedPts, mULPFECPayloadType);
   1317    }
   1318    if (mRtxEnabled) {
   1319      mRtxEnabled = EnsurePayloadTypeNotDuplicate(aUsedPts, mRtxPayloadType);
   1320    }
   1321  }
   1322 
   1323  JSEP_CODEC_CLONE(JsepVideoCodecDescription)
   1324 
   1325  std::vector<std::string> mAckFbTypes;
   1326  std::vector<std::string> mNackFbTypes;
   1327  std::vector<std::string> mCcmFbTypes;
   1328  std::vector<SdpRtcpFbAttributeList::Feedback> mOtherFbTypes;
   1329  bool mTmmbrEnabled;
   1330  bool mRembEnabled;
   1331  bool mFECEnabled;
   1332  bool mTransportCCEnabled;
   1333  bool mRtxEnabled;
   1334  std::string mREDPayloadType;
   1335  std::string mREDRTXPayloadType;
   1336  std::string mULPFECPayloadType;
   1337  std::string mRtxPayloadType;
   1338 
   1339  // H264-specific stuff
   1340  uint32_t mProfileLevelId;
   1341  uint32_t mPacketizationMode;
   1342  std::string mSpropParameterSets;
   1343 
   1344  // AV1-specific stuff
   1345  struct Av1Config {
   1346    Maybe<uint8_t> mProfile = Nothing();
   1347    Maybe<uint8_t> mLevelIdx = Nothing();
   1348    Maybe<uint8_t> mTier = Nothing();
   1349    Av1Config() = default;
   1350    explicit Av1Config(const SdpFmtpAttributeList::Av1Parameters& aParams)
   1351        : mProfile(aParams.profile),
   1352          mLevelIdx(aParams.levelIdx),
   1353          mTier(aParams.tier) {}
   1354    auto ProfileOrDefault() const -> uint8_t { return mProfile.valueOr(0); }
   1355    auto LevelIdxDefault() const -> uint8_t { return mLevelIdx.valueOr(5); }
   1356    auto TierOrDefault() const -> uint8_t { return mTier.valueOr(0); }
   1357    auto operator==(const Av1Config& aOther) const -> bool {
   1358      return ProfileOrDefault() == aOther.ProfileOrDefault() &&
   1359             LevelIdxDefault() == aOther.LevelIdxDefault() &&
   1360             TierOrDefault() == aOther.TierOrDefault();
   1361    }
   1362  } mAv1Config;
   1363 };
   1364 
   1365 class JsepApplicationCodecDescription final : public JsepCodecDescription {
   1366  // This is the new draft-21 implementation
   1367 public:
   1368  JsepApplicationCodecDescription(const std::string& name, uint16_t channels,
   1369                                  uint16_t localPort,
   1370                                  uint32_t localMaxMessageSize)
   1371      : JsepCodecDescription("", name, 0, channels),
   1372        mLocalPort(localPort),
   1373        mLocalMaxMessageSize(localMaxMessageSize),
   1374        mRemotePort(0),
   1375        mRemoteMaxMessageSize(0) {}
   1376 
   1377  static constexpr SdpMediaSection::MediaType type =
   1378      SdpMediaSection::kApplication;
   1379 
   1380  SdpMediaSection::MediaType Type() const override { return type; }
   1381 
   1382  JSEP_CODEC_CLONE(JsepApplicationCodecDescription)
   1383 
   1384  static UniquePtr<JsepApplicationCodecDescription> CreateDefault() {
   1385    return MakeUnique<JsepApplicationCodecDescription>(
   1386        "webrtc-datachannel", WEBRTC_DATACHANNEL_STREAMS_DEFAULT,
   1387        WEBRTC_DATACHANNEL_PORT_DEFAULT,
   1388        WEBRTC_DATACHANNEL_MAX_MESSAGE_SIZE_LOCAL);
   1389  }
   1390 
   1391  // Override, uses sctpport or sctpmap instead of rtpmap
   1392  bool Matches(const std::string& fmt,
   1393               const SdpMediaSection& remoteMsection) const override {
   1394    if (type != remoteMsection.GetMediaType()) {
   1395      return false;
   1396    }
   1397 
   1398    int sctp_port = remoteMsection.GetSctpPort();
   1399    bool fmt_matches =
   1400        nsCRT::strcasecmp(mName.c_str(),
   1401                          remoteMsection.GetFormats()[0].c_str()) == 0;
   1402    if (sctp_port && fmt_matches) {
   1403      // New sctp draft 21 format
   1404      return true;
   1405    }
   1406 
   1407    const SdpSctpmapAttributeList::Sctpmap* sctp_map(
   1408        remoteMsection.GetSctpmap());
   1409    if (sctp_map) {
   1410      // Old sctp draft 05 format
   1411      return nsCRT::strcasecmp(mName.c_str(), sctp_map->name.c_str()) == 0;
   1412    }
   1413 
   1414    return false;
   1415  }
   1416 
   1417  void AddToMediaSection(SdpMediaSection& msection) const override {
   1418    if (mEnabled && msection.GetMediaType() == type) {
   1419      if (mDirection == sdp::kRecv) {
   1420        msection.AddDataChannel(mName, mLocalPort, mChannels,
   1421                                mLocalMaxMessageSize);
   1422      }
   1423 
   1424      AddParametersToMSection(msection);
   1425    }
   1426  }
   1427 
   1428  bool Negotiate(const std::string& pt, const SdpMediaSection& remoteMsection,
   1429                 bool remoteIsOffer,
   1430                 Maybe<const SdpMediaSection&> localMsection) override {
   1431    JsepCodecDescription::Negotiate(pt, remoteMsection, remoteIsOffer,
   1432                                    localMsection);
   1433 
   1434    bool wasSet = remoteMsection.GetMaxMessageSize(&mRemoteMaxMessageSize);
   1435    if (!wasSet) {
   1436      mRemoteMaxMessageSize =
   1437          WEBRTC_DATACHANNEL_MAX_MESSAGE_SIZE_REMOTE_DEFAULT;
   1438    }
   1439 
   1440    int sctp_port = remoteMsection.GetSctpPort();
   1441    if (sctp_port) {
   1442      mRemotePort = sctp_port;
   1443      return true;
   1444    }
   1445 
   1446    const SdpSctpmapAttributeList::Sctpmap* sctp_map(
   1447        remoteMsection.GetSctpmap());
   1448    if (sctp_map) {
   1449      mRemotePort = std::stoi(sctp_map->pt);
   1450      return true;
   1451    }
   1452 
   1453    return false;
   1454  }
   1455 
   1456  // We only support one datachannel per m-section
   1457  void EnsureNoDuplicatePayloadTypes(std::set<std::string>& aUsedPts) override {
   1458  }
   1459 
   1460  void ApplyConfigToFmtp(
   1461      UniquePtr<SdpFmtpAttributeList::Parameters>& aFmtp) const override {};
   1462 
   1463  uint16_t mLocalPort;
   1464  uint32_t mLocalMaxMessageSize;
   1465  uint16_t mRemotePort;
   1466  uint32_t mRemoteMaxMessageSize;
   1467  bool mRemoteMMSSet;
   1468 };
   1469 
   1470 }  // namespace mozilla
   1471 
   1472 #endif