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