summaryrefslogtreecommitdiffstats
path: root/media/webrtc/signaling/src/jsep/JsepCodecDescription.h
diff options
context:
space:
mode:
Diffstat (limited to 'media/webrtc/signaling/src/jsep/JsepCodecDescription.h')
-rw-r--r--media/webrtc/signaling/src/jsep/JsepCodecDescription.h780
1 files changed, 780 insertions, 0 deletions
diff --git a/media/webrtc/signaling/src/jsep/JsepCodecDescription.h b/media/webrtc/signaling/src/jsep/JsepCodecDescription.h
new file mode 100644
index 000000000..6ae5c9380
--- /dev/null
+++ b/media/webrtc/signaling/src/jsep/JsepCodecDescription.h
@@ -0,0 +1,780 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _JSEPCODECDESCRIPTION_H_
+#define _JSEPCODECDESCRIPTION_H_
+
+#include <string>
+#include "signaling/src/sdp/SdpMediaSection.h"
+#include "signaling/src/sdp/SdpHelper.h"
+#include "nsCRT.h"
+
+namespace mozilla {
+
+#define JSEP_CODEC_CLONE(T) \
+ virtual JsepCodecDescription* Clone() const override \
+ { \
+ return new T(*this); \
+ }
+
+// A single entry in our list of known codecs.
+class JsepCodecDescription {
+ public:
+ JsepCodecDescription(mozilla::SdpMediaSection::MediaType type,
+ const std::string& defaultPt,
+ const std::string& name,
+ uint32_t clock,
+ uint32_t channels,
+ bool enabled)
+ : mType(type),
+ mDefaultPt(defaultPt),
+ mName(name),
+ mClock(clock),
+ mChannels(channels),
+ mEnabled(enabled),
+ mStronglyPreferred(false),
+ mDirection(sdp::kSend)
+ {
+ }
+ virtual ~JsepCodecDescription() {}
+
+ virtual JsepCodecDescription* Clone() const = 0;
+
+ bool
+ GetPtAsInt(uint16_t* ptOutparam) const
+ {
+ return SdpHelper::GetPtAsInt(mDefaultPt, ptOutparam);
+ }
+
+ virtual bool
+ Matches(const std::string& fmt, const SdpMediaSection& remoteMsection) const
+ {
+ // note: fmt here is remote fmt (to go with remoteMsection)
+ if (mType != remoteMsection.GetMediaType()) {
+ return false;
+ }
+
+ const SdpRtpmapAttributeList::Rtpmap* entry(remoteMsection.FindRtpmap(fmt));
+
+ if (entry) {
+ if (!nsCRT::strcasecmp(mName.c_str(), entry->name.c_str())
+ && (mClock == entry->clock)
+ && (mChannels == entry->channels)) {
+ return ParametersMatch(fmt, remoteMsection);
+ }
+ } else if (!fmt.compare("9") && mName == "G722") {
+ return true;
+ } else if (!fmt.compare("0") && mName == "PCMU") {
+ return true;
+ } else if (!fmt.compare("8") && mName == "PCMA") {
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool
+ ParametersMatch(const std::string& fmt,
+ const SdpMediaSection& remoteMsection) const
+ {
+ return true;
+ }
+
+ virtual bool
+ Negotiate(const std::string& pt, const SdpMediaSection& remoteMsection)
+ {
+ mDefaultPt = pt;
+ return true;
+ }
+
+ virtual void
+ AddToMediaSection(SdpMediaSection& msection) const
+ {
+ if (mEnabled && msection.GetMediaType() == mType) {
+ // Both send and recv codec will have the same pt, so don't add twice
+ if (!msection.HasFormat(mDefaultPt)) {
+ if (mType == SdpMediaSection::kApplication) {
+ // Hack: using mChannels for number of streams
+ msection.AddDataChannel(mDefaultPt, mName, mChannels);
+ } else {
+ msection.AddCodec(mDefaultPt, mName, mClock, mChannels);
+ }
+ }
+
+ AddParametersToMSection(msection);
+ }
+ }
+
+ virtual void AddParametersToMSection(SdpMediaSection& msection) const {}
+
+ mozilla::SdpMediaSection::MediaType mType;
+ std::string mDefaultPt;
+ std::string mName;
+ uint32_t mClock;
+ uint32_t mChannels;
+ bool mEnabled;
+ bool mStronglyPreferred;
+ sdp::Direction mDirection;
+ // Will hold constraints from both fmtp and rid
+ EncodingConstraints mConstraints;
+};
+
+class JsepAudioCodecDescription : public JsepCodecDescription {
+ public:
+ JsepAudioCodecDescription(const std::string& defaultPt,
+ const std::string& name,
+ uint32_t clock,
+ uint32_t channels,
+ uint32_t packetSize,
+ uint32_t bitRate,
+ bool enabled = true)
+ : JsepCodecDescription(mozilla::SdpMediaSection::kAudio, defaultPt, name,
+ clock, channels, enabled),
+ mPacketSize(packetSize),
+ mBitrate(bitRate),
+ mMaxPlaybackRate(0),
+ mForceMono(false),
+ mFECEnabled(false),
+ mDtmfEnabled(false)
+ {
+ }
+
+ JSEP_CODEC_CLONE(JsepAudioCodecDescription)
+
+ SdpFmtpAttributeList::OpusParameters
+ GetOpusParameters(const std::string& pt,
+ const SdpMediaSection& msection) const
+ {
+ // Will contain defaults if nothing else
+ SdpFmtpAttributeList::OpusParameters result;
+ auto* params = msection.FindFmtp(pt);
+
+ if (params && params->codec_type == SdpRtpmapAttributeList::kOpus) {
+ result =
+ static_cast<const SdpFmtpAttributeList::OpusParameters&>(*params);
+ }
+
+ return result;
+ }
+
+ SdpFmtpAttributeList::TelephoneEventParameters
+ GetTelephoneEventParameters(const std::string& pt,
+ const SdpMediaSection& msection) const
+ {
+ // Will contain defaults if nothing else
+ SdpFmtpAttributeList::TelephoneEventParameters result;
+ auto* params = msection.FindFmtp(pt);
+
+ if (params && params->codec_type == SdpRtpmapAttributeList::kTelephoneEvent) {
+ result =
+ static_cast<const SdpFmtpAttributeList::TelephoneEventParameters&>
+ (*params);
+ }
+
+ return result;
+ }
+
+ void
+ AddParametersToMSection(SdpMediaSection& msection) const override
+ {
+ if (mDirection == sdp::kSend) {
+ return;
+ }
+
+ if (mName == "opus") {
+ SdpFmtpAttributeList::OpusParameters opusParams(
+ GetOpusParameters(mDefaultPt, msection));
+ if (mMaxPlaybackRate) {
+ opusParams.maxplaybackrate = mMaxPlaybackRate;
+ }
+ if (mChannels == 2 && !mForceMono) {
+ // We prefer to receive stereo, if available.
+ opusParams.stereo = 1;
+ }
+ opusParams.useInBandFec = mFECEnabled ? 1 : 0;
+ msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, opusParams));
+ } else if (mName == "telephone-event") {
+ // add the default dtmf tones
+ SdpFmtpAttributeList::TelephoneEventParameters teParams(
+ GetTelephoneEventParameters(mDefaultPt, msection));
+ msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, teParams));
+ }
+ }
+
+ bool
+ Negotiate(const std::string& pt,
+ const SdpMediaSection& remoteMsection) override
+ {
+ JsepCodecDescription::Negotiate(pt, remoteMsection);
+ if (mName == "opus" && mDirection == sdp::kSend) {
+ SdpFmtpAttributeList::OpusParameters opusParams(
+ GetOpusParameters(mDefaultPt, remoteMsection));
+
+ mMaxPlaybackRate = opusParams.maxplaybackrate;
+ mForceMono = !opusParams.stereo;
+ // draft-ietf-rtcweb-fec-03.txt section 4.2 says support for FEC
+ // at the received side is declarative and can be negotiated
+ // separately for either media direction.
+ mFECEnabled = opusParams.useInBandFec;
+ }
+
+ return true;
+ }
+
+ uint32_t mPacketSize;
+ uint32_t mBitrate;
+ uint32_t mMaxPlaybackRate;
+ bool mForceMono;
+ bool mFECEnabled;
+ bool mDtmfEnabled;
+};
+
+class JsepVideoCodecDescription : public JsepCodecDescription {
+ public:
+ JsepVideoCodecDescription(const std::string& defaultPt,
+ const std::string& name,
+ uint32_t clock,
+ bool enabled = true)
+ : JsepCodecDescription(mozilla::SdpMediaSection::kVideo, defaultPt, name,
+ clock, 0, enabled),
+ mTmmbrEnabled(false),
+ mRembEnabled(false),
+ mFECEnabled(false),
+ mPacketizationMode(0)
+ {
+ // Add supported rtcp-fb types
+ mNackFbTypes.push_back("");
+ mNackFbTypes.push_back(SdpRtcpFbAttributeList::pli);
+ mCcmFbTypes.push_back(SdpRtcpFbAttributeList::fir);
+ }
+
+ virtual void
+ EnableTmmbr() {
+ // EnableTmmbr can be called multiple times due to multiple calls to
+ // PeerConnectionImpl::ConfigureJsepSessionCodecs
+ if (!mTmmbrEnabled) {
+ mTmmbrEnabled = true;
+ mCcmFbTypes.push_back(SdpRtcpFbAttributeList::tmmbr);
+ }
+ }
+
+ virtual void
+ EnableRemb() {
+ // EnableRemb can be called multiple times due to multiple calls to
+ // PeerConnectionImpl::ConfigureJsepSessionCodecs
+ if (!mRembEnabled) {
+ mRembEnabled = true;
+ mOtherFbTypes.push_back({ "", SdpRtcpFbAttributeList::kRemb, "", ""});
+ }
+ }
+
+ virtual void
+ EnableFec() {
+ // Enabling FEC for video works a little differently than enabling
+ // REMB or TMMBR. Support for FEC is indicated by the presence of
+ // particular codes (red and ulpfec) instead of using rtcpfb
+ // attributes on a given codec. There is no rtcpfb to push for FEC
+ // as can be seen above when REMB or TMMBR are enabled.
+ mFECEnabled = true;
+ }
+
+ void
+ AddParametersToMSection(SdpMediaSection& msection) const override
+ {
+ AddFmtpsToMSection(msection);
+ AddRtcpFbsToMSection(msection);
+ }
+
+ void
+ AddFmtpsToMSection(SdpMediaSection& msection) const
+ {
+ if (mName == "H264") {
+ SdpFmtpAttributeList::H264Parameters h264Params(
+ GetH264Parameters(mDefaultPt, msection));
+
+ if (mDirection == sdp::kSend) {
+ if (!h264Params.level_asymmetry_allowed) {
+ // First time the fmtp has been set; set just in case this is for a
+ // sendonly m-line, since even though we aren't receiving the level
+ // negotiation still needs to happen (sigh).
+ h264Params.profile_level_id = mProfileLevelId;
+ }
+ } else {
+ // Parameters that only apply to what we receive
+ h264Params.max_mbps = mConstraints.maxMbps;
+ h264Params.max_fs = mConstraints.maxFs;
+ h264Params.max_cpb = mConstraints.maxCpb;
+ h264Params.max_dpb = mConstraints.maxDpb;
+ h264Params.max_br = mConstraints.maxBr;
+ strncpy(h264Params.sprop_parameter_sets,
+ mSpropParameterSets.c_str(),
+ sizeof(h264Params.sprop_parameter_sets) - 1);
+ h264Params.profile_level_id = mProfileLevelId;
+ }
+
+ // Parameters that apply to both the send and recv directions
+ h264Params.packetization_mode = mPacketizationMode;
+ // Hard-coded, may need to change someday?
+ h264Params.level_asymmetry_allowed = true;
+
+ msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, h264Params));
+ } else if (mName == "red") {
+ SdpFmtpAttributeList::RedParameters redParams(
+ GetRedParameters(mDefaultPt, msection));
+ redParams.encodings = mRedundantEncodings;
+ msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, redParams));
+ } else if (mName == "VP8" || mName == "VP9") {
+ if (mDirection == sdp::kRecv) {
+ // VP8 and VP9 share the same SDP parameters thus far
+ SdpFmtpAttributeList::VP8Parameters vp8Params(
+ GetVP8Parameters(mDefaultPt, msection));
+
+ vp8Params.max_fs = mConstraints.maxFs;
+ vp8Params.max_fr = mConstraints.maxFps;
+ msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, vp8Params));
+ }
+ }
+ }
+
+ void
+ AddRtcpFbsToMSection(SdpMediaSection& msection) const
+ {
+ SdpRtcpFbAttributeList rtcpfbs(msection.GetRtcpFbs());
+ for (const auto& rtcpfb : rtcpfbs.mFeedbacks) {
+ if (rtcpfb.pt == mDefaultPt) {
+ // Already set by the codec for the other direction.
+ return;
+ }
+ }
+
+ for (const std::string& type : mAckFbTypes) {
+ rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kAck, type);
+ }
+ for (const std::string& type : mNackFbTypes) {
+ rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kNack, type);
+ }
+ for (const std::string& type : mCcmFbTypes) {
+ rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kCcm, type);
+ }
+ for (const auto& fb : mOtherFbTypes) {
+ rtcpfbs.PushEntry(mDefaultPt, fb.type, fb.parameter, fb.extra);
+ }
+
+ msection.SetRtcpFbs(rtcpfbs);
+ }
+
+ SdpFmtpAttributeList::H264Parameters
+ GetH264Parameters(const std::string& pt,
+ const SdpMediaSection& msection) const
+ {
+ // Will contain defaults if nothing else
+ SdpFmtpAttributeList::H264Parameters result;
+ auto* params = msection.FindFmtp(pt);
+
+ if (params && params->codec_type == SdpRtpmapAttributeList::kH264) {
+ result =
+ static_cast<const SdpFmtpAttributeList::H264Parameters&>(*params);
+ }
+
+ return result;
+ }
+
+ SdpFmtpAttributeList::RedParameters
+ GetRedParameters(const std::string& pt,
+ const SdpMediaSection& msection) const
+ {
+ SdpFmtpAttributeList::RedParameters result;
+ auto* params = msection.FindFmtp(pt);
+
+ if (params && params->codec_type == SdpRtpmapAttributeList::kRed) {
+ result =
+ static_cast<const SdpFmtpAttributeList::RedParameters&>(*params);
+ }
+
+ return result;
+ }
+
+ SdpFmtpAttributeList::VP8Parameters
+ GetVP8Parameters(const std::string& pt,
+ const SdpMediaSection& msection) const
+ {
+ SdpRtpmapAttributeList::CodecType expectedType(
+ mName == "VP8" ?
+ SdpRtpmapAttributeList::kVP8 :
+ SdpRtpmapAttributeList::kVP9);
+
+ // Will contain defaults if nothing else
+ SdpFmtpAttributeList::VP8Parameters result(expectedType);
+ auto* params = msection.FindFmtp(pt);
+
+ if (params && params->codec_type == expectedType) {
+ result =
+ static_cast<const SdpFmtpAttributeList::VP8Parameters&>(*params);
+ }
+
+ return result;
+ }
+
+ void
+ NegotiateRtcpFb(const SdpMediaSection& remoteMsection,
+ SdpRtcpFbAttributeList::Type type,
+ std::vector<std::string>* supportedTypes)
+ {
+ std::vector<std::string> temp;
+ for (auto& subType : *supportedTypes) {
+ if (remoteMsection.HasRtcpFb(mDefaultPt, type, subType)) {
+ temp.push_back(subType);
+ }
+ }
+ *supportedTypes = temp;
+ }
+
+ void
+ NegotiateRtcpFb(const SdpMediaSection& remoteMsection,
+ std::vector<SdpRtcpFbAttributeList::Feedback>* supportedFbs) {
+ std::vector<SdpRtcpFbAttributeList::Feedback> temp;
+ for (auto& fb : *supportedFbs) {
+ if (remoteMsection.HasRtcpFb(mDefaultPt, fb.type, fb.parameter)) {
+ temp.push_back(fb);
+ }
+ }
+ *supportedFbs = temp;
+ }
+
+ void
+ NegotiateRtcpFb(const SdpMediaSection& remote)
+ {
+ // Removes rtcp-fb types that the other side doesn't support
+ NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kAck, &mAckFbTypes);
+ NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kNack, &mNackFbTypes);
+ NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kCcm, &mCcmFbTypes);
+ NegotiateRtcpFb(remote, &mOtherFbTypes);
+ }
+
+ virtual bool
+ Negotiate(const std::string& pt,
+ const SdpMediaSection& remoteMsection) override
+ {
+ JsepCodecDescription::Negotiate(pt, remoteMsection);
+ if (mName == "H264") {
+ SdpFmtpAttributeList::H264Parameters h264Params(
+ GetH264Parameters(mDefaultPt, remoteMsection));
+
+ // Level is negotiated symmetrically if level asymmetry is disallowed
+ if (!h264Params.level_asymmetry_allowed) {
+ SetSaneH264Level(std::min(GetSaneH264Level(h264Params.profile_level_id),
+ GetSaneH264Level(mProfileLevelId)),
+ &mProfileLevelId);
+ }
+
+ if (mDirection == sdp::kSend) {
+ // Remote values of these apply only to the send codec.
+ mConstraints.maxFs = h264Params.max_fs;
+ mConstraints.maxMbps = h264Params.max_mbps;
+ mConstraints.maxCpb = h264Params.max_cpb;
+ mConstraints.maxDpb = h264Params.max_dpb;
+ mConstraints.maxBr = h264Params.max_br;
+ mSpropParameterSets = h264Params.sprop_parameter_sets;
+ // Only do this if we didn't symmetrically negotiate above
+ if (h264Params.level_asymmetry_allowed) {
+ SetSaneH264Level(GetSaneH264Level(h264Params.profile_level_id),
+ &mProfileLevelId);
+ }
+ } else {
+ // TODO(bug 1143709): max-recv-level support
+ }
+ } else if (mName == "red") {
+ SdpFmtpAttributeList::RedParameters redParams(
+ GetRedParameters(mDefaultPt, remoteMsection));
+ mRedundantEncodings = redParams.encodings;
+ } else if (mName == "VP8" || mName == "VP9") {
+ if (mDirection == sdp::kSend) {
+ SdpFmtpAttributeList::VP8Parameters vp8Params(
+ GetVP8Parameters(mDefaultPt, remoteMsection));
+
+ mConstraints.maxFs = vp8Params.max_fs;
+ mConstraints.maxFps = vp8Params.max_fr;
+ }
+ }
+
+ NegotiateRtcpFb(remoteMsection);
+ return true;
+ }
+
+ // Maps the not-so-sane encoding of H264 level into something that is
+ // ordered in the way one would expect
+ // 1b is 0xAB, everything else is the level left-shifted one half-byte
+ // (eg; 1.0 is 0xA0, 1.1 is 0xB0, 3.1 is 0x1F0)
+ static uint32_t
+ GetSaneH264Level(uint32_t profileLevelId)
+ {
+ uint32_t profileIdc = (profileLevelId >> 16);
+
+ if (profileIdc == 0x42 || profileIdc == 0x4D || profileIdc == 0x58) {
+ if ((profileLevelId & 0x10FF) == 0x100B) {
+ // Level 1b
+ return 0xAB;
+ }
+ }
+
+ uint32_t level = profileLevelId & 0xFF;
+
+ if (level == 0x09) {
+ // Another way to encode level 1b
+ return 0xAB;
+ }
+
+ return level << 4;
+ }
+
+ static void
+ SetSaneH264Level(uint32_t level, uint32_t* profileLevelId)
+ {
+ uint32_t profileIdc = (*profileLevelId >> 16);
+ uint32_t levelMask = 0xFF;
+
+ if (profileIdc == 0x42 || profileIdc == 0x4d || profileIdc == 0x58) {
+ levelMask = 0x10FF;
+ if (level == 0xAB) {
+ // Level 1b
+ level = 0x100B;
+ } else {
+ // Not 1b, just shift
+ level = level >> 4;
+ }
+ } else if (level == 0xAB) {
+ // Another way to encode 1b
+ level = 0x09;
+ } else {
+ // Not 1b, just shift
+ level = level >> 4;
+ }
+
+ *profileLevelId = (*profileLevelId & ~levelMask) | level;
+ }
+
+ enum Subprofile {
+ kH264ConstrainedBaseline,
+ kH264Baseline,
+ kH264Main,
+ kH264Extended,
+ kH264High,
+ kH264High10,
+ kH264High42,
+ kH264High44,
+ kH264High10I,
+ kH264High42I,
+ kH264High44I,
+ kH264CALVC44,
+ kH264UnknownSubprofile
+ };
+
+ static Subprofile
+ GetSubprofile(uint32_t profileLevelId)
+ {
+ // Based on Table 5 from RFC 6184:
+ // Profile profile_idc profile-iop
+ // (hexadecimal) (binary)
+
+ // CB 42 (B) x1xx0000
+ // same as: 4D (M) 1xxx0000
+ // same as: 58 (E) 11xx0000
+ // B 42 (B) x0xx0000
+ // same as: 58 (E) 10xx0000
+ // M 4D (M) 0x0x0000
+ // E 58 00xx0000
+ // H 64 00000000
+ // H10 6E 00000000
+ // H42 7A 00000000
+ // H44 F4 00000000
+ // H10I 6E 00010000
+ // H42I 7A 00010000
+ // H44I F4 00010000
+ // C44I 2C 00010000
+
+ if ((profileLevelId & 0xFF4F00) == 0x424000) {
+ // 01001111 (mask, 0x4F)
+ // x1xx0000 (from table)
+ // 01000000 (expected value, 0x40)
+ return kH264ConstrainedBaseline;
+ }
+
+ if ((profileLevelId & 0xFF8F00) == 0x4D8000) {
+ // 10001111 (mask, 0x8F)
+ // 1xxx0000 (from table)
+ // 10000000 (expected value, 0x80)
+ return kH264ConstrainedBaseline;
+ }
+
+ if ((profileLevelId & 0xFFCF00) == 0x58C000) {
+ // 11001111 (mask, 0xCF)
+ // 11xx0000 (from table)
+ // 11000000 (expected value, 0xC0)
+ return kH264ConstrainedBaseline;
+ }
+
+ if ((profileLevelId & 0xFF4F00) == 0x420000) {
+ // 01001111 (mask, 0x4F)
+ // x0xx0000 (from table)
+ // 00000000 (expected value)
+ return kH264Baseline;
+ }
+
+ if ((profileLevelId & 0xFFCF00) == 0x588000) {
+ // 11001111 (mask, 0xCF)
+ // 10xx0000 (from table)
+ // 10000000 (expected value, 0x80)
+ return kH264Baseline;
+ }
+
+ if ((profileLevelId & 0xFFAF00) == 0x4D0000) {
+ // 10101111 (mask, 0xAF)
+ // 0x0x0000 (from table)
+ // 00000000 (expected value)
+ return kH264Main;
+ }
+
+ if ((profileLevelId & 0xFF0000) == 0x580000) {
+ // 11001111 (mask, 0xCF)
+ // 00xx0000 (from table)
+ // 00000000 (expected value)
+ return kH264Extended;
+ }
+
+ if ((profileLevelId & 0xFFFF00) == 0x640000) {
+ return kH264High;
+ }
+
+ if ((profileLevelId & 0xFFFF00) == 0x6E0000) {
+ return kH264High10;
+ }
+
+ if ((profileLevelId & 0xFFFF00) == 0x7A0000) {
+ return kH264High42;
+ }
+
+ if ((profileLevelId & 0xFFFF00) == 0xF40000) {
+ return kH264High44;
+ }
+
+ if ((profileLevelId & 0xFFFF00) == 0x6E1000) {
+ return kH264High10I;
+ }
+
+ if ((profileLevelId & 0xFFFF00) == 0x7A1000) {
+ return kH264High42I;
+ }
+
+ if ((profileLevelId & 0xFFFF00) == 0xF41000) {
+ return kH264High44I;
+ }
+
+ if ((profileLevelId & 0xFFFF00) == 0x2C1000) {
+ return kH264CALVC44;
+ }
+
+ return kH264UnknownSubprofile;
+ }
+
+ virtual bool
+ ParametersMatch(const std::string& fmt,
+ const SdpMediaSection& remoteMsection) const override
+ {
+ if (mName == "H264") {
+ SdpFmtpAttributeList::H264Parameters h264Params(
+ GetH264Parameters(fmt, remoteMsection));
+
+ if (h264Params.packetization_mode != mPacketizationMode) {
+ return false;
+ }
+
+ if (GetSubprofile(h264Params.profile_level_id) !=
+ GetSubprofile(mProfileLevelId)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ virtual bool
+ RtcpFbRembIsSet() const
+ {
+ for (const auto& fb : mOtherFbTypes) {
+ if (fb.type == SdpRtcpFbAttributeList::kRemb) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ virtual void
+ UpdateRedundantEncodings(std::vector<JsepCodecDescription*> codecs)
+ {
+ for (const auto codec : codecs) {
+ if (codec->mType == SdpMediaSection::kVideo &&
+ codec->mEnabled &&
+ codec->mName != "red") {
+ uint8_t pt = (uint8_t)strtoul(codec->mDefaultPt.c_str(), nullptr, 10);
+ // returns 0 if failed to convert, and since zero could
+ // be valid, check the defaultPt for 0
+ if (pt == 0 && codec->mDefaultPt != "0") {
+ continue;
+ }
+ mRedundantEncodings.push_back(pt);
+ }
+ }
+ }
+
+ JSEP_CODEC_CLONE(JsepVideoCodecDescription)
+
+ std::vector<std::string> mAckFbTypes;
+ std::vector<std::string> mNackFbTypes;
+ std::vector<std::string> mCcmFbTypes;
+ std::vector<SdpRtcpFbAttributeList::Feedback> mOtherFbTypes;
+ bool mTmmbrEnabled;
+ bool mRembEnabled;
+ bool mFECEnabled;
+ std::vector<uint8_t> mRedundantEncodings;
+
+ // H264-specific stuff
+ uint32_t mProfileLevelId;
+ uint32_t mPacketizationMode;
+ std::string mSpropParameterSets;
+};
+
+class JsepApplicationCodecDescription : public JsepCodecDescription {
+ public:
+ JsepApplicationCodecDescription(const std::string& defaultPt,
+ const std::string& name,
+ uint16_t channels,
+ bool enabled = true)
+ : JsepCodecDescription(mozilla::SdpMediaSection::kApplication, defaultPt,
+ name, 0, channels, enabled)
+ {
+ }
+
+ JSEP_CODEC_CLONE(JsepApplicationCodecDescription)
+
+ // Override, uses sctpmap instead of rtpmap
+ virtual bool
+ Matches(const std::string& fmt,
+ const SdpMediaSection& remoteMsection) const override
+ {
+ if (mType != remoteMsection.GetMediaType()) {
+ return false;
+ }
+
+ const SdpSctpmapAttributeList::Sctpmap* entry(
+ remoteMsection.FindSctpmap(fmt));
+
+ if (entry && !nsCRT::strcasecmp(mName.c_str(), entry->name.c_str())) {
+ return true;
+ }
+ return false;
+ }
+};
+
+} // namespace mozilla
+
+#endif