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 <string> 9 #include "signaling/src/sdp/SdpMediaSection.h" 10 #include "signaling/src/sdp/SdpHelper.h" 11 #include "nsCRT.h" 12 #include "mozilla/net/DataChannelProtocol.h" 13 14 namespace mozilla { 15 16 #define JSEP_CODEC_CLONE(T) \ 17 virtual JsepCodecDescription* Clone() const override { return new T(*this); } 18 19 // A single entry in our list of known codecs. 20 class JsepCodecDescription { 21 public: JsepCodecDescription(mozilla::SdpMediaSection::MediaType type,const std::string & defaultPt,const std::string & name,uint32_t clock,uint32_t channels,bool enabled)22 JsepCodecDescription(mozilla::SdpMediaSection::MediaType type, 23 const std::string& defaultPt, const std::string& name, 24 uint32_t clock, uint32_t channels, bool enabled) 25 : mType(type), 26 mDefaultPt(defaultPt), 27 mName(name), 28 mClock(clock), 29 mChannels(channels), 30 mEnabled(enabled), 31 mStronglyPreferred(false), 32 mDirection(sdp::kSend) {} ~JsepCodecDescription()33 virtual ~JsepCodecDescription() {} 34 35 virtual JsepCodecDescription* Clone() const = 0; 36 GetPtAsInt(uint16_t * ptOutparam)37 bool GetPtAsInt(uint16_t* ptOutparam) const { 38 return SdpHelper::GetPtAsInt(mDefaultPt, ptOutparam); 39 } 40 Matches(const std::string & fmt,const SdpMediaSection & remoteMsection)41 virtual bool Matches(const std::string& fmt, 42 const SdpMediaSection& remoteMsection) const { 43 // note: fmt here is remote fmt (to go with remoteMsection) 44 if (mType != remoteMsection.GetMediaType()) { 45 return false; 46 } 47 48 const SdpRtpmapAttributeList::Rtpmap* entry(remoteMsection.FindRtpmap(fmt)); 49 50 if (entry) { 51 if (!nsCRT::strcasecmp(mName.c_str(), entry->name.c_str()) && 52 (mClock == entry->clock) && (mChannels == entry->channels)) { 53 return ParametersMatch(fmt, remoteMsection); 54 } 55 } else if (!fmt.compare("9") && mName == "G722") { 56 return true; 57 } else if (!fmt.compare("0") && mName == "PCMU") { 58 return true; 59 } else if (!fmt.compare("8") && mName == "PCMA") { 60 return true; 61 } 62 return false; 63 } 64 ParametersMatch(const std::string & fmt,const SdpMediaSection & remoteMsection)65 virtual bool ParametersMatch(const std::string& fmt, 66 const SdpMediaSection& remoteMsection) const { 67 return true; 68 } 69 Negotiate(const std::string & pt,const SdpMediaSection & remoteMsection)70 virtual bool Negotiate(const std::string& pt, 71 const SdpMediaSection& remoteMsection) { 72 mDefaultPt = pt; 73 return true; 74 } 75 AddToMediaSection(SdpMediaSection & msection)76 virtual void AddToMediaSection(SdpMediaSection& msection) const { 77 if (mEnabled && msection.GetMediaType() == mType) { 78 // Both send and recv codec will have the same pt, so don't add twice 79 if (!msection.HasFormat(mDefaultPt)) { 80 msection.AddCodec(mDefaultPt, mName, mClock, mChannels); 81 } 82 83 AddParametersToMSection(msection); 84 } 85 } 86 AddParametersToMSection(SdpMediaSection & msection)87 virtual void AddParametersToMSection(SdpMediaSection& msection) const {} 88 89 mozilla::SdpMediaSection::MediaType mType; 90 std::string mDefaultPt; 91 std::string mName; 92 uint32_t mClock; 93 uint32_t mChannels; 94 bool mEnabled; 95 bool mStronglyPreferred; 96 sdp::Direction mDirection; 97 // Will hold constraints from both fmtp and rid 98 EncodingConstraints mConstraints; 99 }; 100 101 class JsepAudioCodecDescription : public JsepCodecDescription { 102 public: 103 JsepAudioCodecDescription(const std::string& defaultPt, 104 const std::string& name, uint32_t clock, 105 uint32_t channels, uint32_t packetSize, 106 uint32_t bitRate, bool enabled = true) JsepCodecDescription(mozilla::SdpMediaSection::kAudio,defaultPt,name,clock,channels,enabled)107 : JsepCodecDescription(mozilla::SdpMediaSection::kAudio, defaultPt, name, 108 clock, channels, enabled), 109 mPacketSize(packetSize), 110 mBitrate(bitRate), 111 mMaxPlaybackRate(0), 112 mForceMono(false), 113 mFECEnabled(false), 114 mDtmfEnabled(false) {} 115 JSEP_CODEC_CLONE(JsepAudioCodecDescription)116 JSEP_CODEC_CLONE(JsepAudioCodecDescription) 117 118 SdpFmtpAttributeList::OpusParameters GetOpusParameters( 119 const std::string& pt, const SdpMediaSection& msection) const { 120 // Will contain defaults if nothing else 121 SdpFmtpAttributeList::OpusParameters result; 122 auto* params = msection.FindFmtp(pt); 123 124 if (params && params->codec_type == SdpRtpmapAttributeList::kOpus) { 125 result = 126 static_cast<const SdpFmtpAttributeList::OpusParameters&>(*params); 127 } 128 129 return result; 130 } 131 GetTelephoneEventParameters(const std::string & pt,const SdpMediaSection & msection)132 SdpFmtpAttributeList::TelephoneEventParameters GetTelephoneEventParameters( 133 const std::string& pt, const SdpMediaSection& msection) const { 134 // Will contain defaults if nothing else 135 SdpFmtpAttributeList::TelephoneEventParameters result; 136 auto* params = msection.FindFmtp(pt); 137 138 if (params && 139 params->codec_type == SdpRtpmapAttributeList::kTelephoneEvent) { 140 result = 141 static_cast<const SdpFmtpAttributeList::TelephoneEventParameters&>( 142 *params); 143 } 144 145 return result; 146 } 147 AddParametersToMSection(SdpMediaSection & msection)148 void AddParametersToMSection(SdpMediaSection& msection) const override { 149 if (mDirection == sdp::kSend) { 150 return; 151 } 152 153 if (mName == "opus") { 154 SdpFmtpAttributeList::OpusParameters opusParams( 155 GetOpusParameters(mDefaultPt, msection)); 156 if (mMaxPlaybackRate) { 157 opusParams.maxplaybackrate = mMaxPlaybackRate; 158 } 159 if (mChannels == 2 && !mForceMono) { 160 // We prefer to receive stereo, if available. 161 opusParams.stereo = 1; 162 } 163 opusParams.useInBandFec = mFECEnabled ? 1 : 0; 164 msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, opusParams)); 165 } else if (mName == "telephone-event") { 166 // add the default dtmf tones 167 SdpFmtpAttributeList::TelephoneEventParameters teParams( 168 GetTelephoneEventParameters(mDefaultPt, msection)); 169 msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, teParams)); 170 } 171 } 172 Negotiate(const std::string & pt,const SdpMediaSection & remoteMsection)173 bool Negotiate(const std::string& pt, 174 const SdpMediaSection& remoteMsection) override { 175 JsepCodecDescription::Negotiate(pt, remoteMsection); 176 if (mName == "opus" && mDirection == sdp::kSend) { 177 SdpFmtpAttributeList::OpusParameters opusParams( 178 GetOpusParameters(mDefaultPt, remoteMsection)); 179 180 mMaxPlaybackRate = opusParams.maxplaybackrate; 181 mForceMono = !opusParams.stereo; 182 // draft-ietf-rtcweb-fec-03.txt section 4.2 says support for FEC 183 // at the received side is declarative and can be negotiated 184 // separately for either media direction. 185 mFECEnabled = opusParams.useInBandFec; 186 } 187 188 return true; 189 } 190 191 uint32_t mPacketSize; 192 uint32_t mBitrate; 193 uint32_t mMaxPlaybackRate; 194 bool mForceMono; 195 bool mFECEnabled; 196 bool mDtmfEnabled; 197 }; 198 199 class JsepVideoCodecDescription : public JsepCodecDescription { 200 public: 201 JsepVideoCodecDescription(const std::string& defaultPt, 202 const std::string& name, uint32_t clock, 203 bool enabled = true) 204 : JsepCodecDescription(mozilla::SdpMediaSection::kVideo, defaultPt, name, 205 clock, 0, enabled), 206 mTmmbrEnabled(false), 207 mRembEnabled(false), 208 mFECEnabled(false), 209 mPacketizationMode(0) { 210 // Add supported rtcp-fb types 211 mNackFbTypes.push_back(""); 212 mNackFbTypes.push_back(SdpRtcpFbAttributeList::pli); 213 mCcmFbTypes.push_back(SdpRtcpFbAttributeList::fir); 214 } 215 EnableTmmbr()216 virtual void EnableTmmbr() { 217 // EnableTmmbr can be called multiple times due to multiple calls to 218 // PeerConnectionImpl::ConfigureJsepSessionCodecs 219 if (!mTmmbrEnabled) { 220 mTmmbrEnabled = true; 221 mCcmFbTypes.push_back(SdpRtcpFbAttributeList::tmmbr); 222 } 223 } 224 EnableRemb()225 virtual void EnableRemb() { 226 // EnableRemb can be called multiple times due to multiple calls to 227 // PeerConnectionImpl::ConfigureJsepSessionCodecs 228 if (!mRembEnabled) { 229 mRembEnabled = true; 230 mOtherFbTypes.push_back({"", SdpRtcpFbAttributeList::kRemb, "", ""}); 231 } 232 } 233 EnableFec(std::string redPayloadType,std::string ulpfecPayloadType)234 virtual void EnableFec(std::string redPayloadType, 235 std::string ulpfecPayloadType) { 236 // Enabling FEC for video works a little differently than enabling 237 // REMB or TMMBR. Support for FEC is indicated by the presence of 238 // particular codes (red and ulpfec) instead of using rtcpfb 239 // attributes on a given codec. There is no rtcpfb to push for FEC 240 // as can be seen above when REMB or TMMBR are enabled. 241 242 // Ensure we have valid payload types. This returns zero on failure, which 243 // is a valid payload type. 244 uint16_t redPt, ulpfecPt; 245 if (!SdpHelper::GetPtAsInt(redPayloadType, &redPt) || 246 !SdpHelper::GetPtAsInt(ulpfecPayloadType, &ulpfecPt)) { 247 return; 248 } 249 250 mFECEnabled = true; 251 mREDPayloadType = redPt; 252 mULPFECPayloadType = ulpfecPt; 253 } 254 AddParametersToMSection(SdpMediaSection & msection)255 void AddParametersToMSection(SdpMediaSection& msection) const override { 256 AddFmtpsToMSection(msection); 257 AddRtcpFbsToMSection(msection); 258 } 259 AddFmtpsToMSection(SdpMediaSection & msection)260 void AddFmtpsToMSection(SdpMediaSection& msection) const { 261 if (mName == "H264") { 262 SdpFmtpAttributeList::H264Parameters h264Params( 263 GetH264Parameters(mDefaultPt, msection)); 264 265 if (mDirection == sdp::kSend) { 266 if (!h264Params.level_asymmetry_allowed) { 267 // First time the fmtp has been set; set just in case this is for a 268 // sendonly m-line, since even though we aren't receiving the level 269 // negotiation still needs to happen (sigh). 270 h264Params.profile_level_id = mProfileLevelId; 271 } 272 } else { 273 // Parameters that only apply to what we receive 274 h264Params.max_mbps = mConstraints.maxMbps; 275 h264Params.max_fs = mConstraints.maxFs; 276 h264Params.max_cpb = mConstraints.maxCpb; 277 h264Params.max_dpb = mConstraints.maxDpb; 278 h264Params.max_br = mConstraints.maxBr; 279 strncpy(h264Params.sprop_parameter_sets, mSpropParameterSets.c_str(), 280 sizeof(h264Params.sprop_parameter_sets) - 1); 281 h264Params.profile_level_id = mProfileLevelId; 282 } 283 284 // Parameters that apply to both the send and recv directions 285 h264Params.packetization_mode = mPacketizationMode; 286 // Hard-coded, may need to change someday? 287 h264Params.level_asymmetry_allowed = true; 288 289 msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, h264Params)); 290 } else if (mName == "red" && !mRedundantEncodings.empty()) { 291 SdpFmtpAttributeList::RedParameters redParams( 292 GetRedParameters(mDefaultPt, msection)); 293 redParams.encodings = mRedundantEncodings; 294 msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, redParams)); 295 } else if (mName == "VP8" || mName == "VP9") { 296 if (mDirection == sdp::kRecv) { 297 // VP8 and VP9 share the same SDP parameters thus far 298 SdpFmtpAttributeList::VP8Parameters vp8Params( 299 GetVP8Parameters(mDefaultPt, msection)); 300 301 vp8Params.max_fs = mConstraints.maxFs; 302 vp8Params.max_fr = mConstraints.maxFps; 303 msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, vp8Params)); 304 } 305 } 306 } 307 AddRtcpFbsToMSection(SdpMediaSection & msection)308 void AddRtcpFbsToMSection(SdpMediaSection& msection) const { 309 SdpRtcpFbAttributeList rtcpfbs(msection.GetRtcpFbs()); 310 for (const auto& rtcpfb : rtcpfbs.mFeedbacks) { 311 if (rtcpfb.pt == mDefaultPt) { 312 // Already set by the codec for the other direction. 313 return; 314 } 315 } 316 317 for (const std::string& type : mAckFbTypes) { 318 rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kAck, type); 319 } 320 for (const std::string& type : mNackFbTypes) { 321 rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kNack, type); 322 } 323 for (const std::string& type : mCcmFbTypes) { 324 rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kCcm, type); 325 } 326 for (const auto& fb : mOtherFbTypes) { 327 rtcpfbs.PushEntry(mDefaultPt, fb.type, fb.parameter, fb.extra); 328 } 329 330 msection.SetRtcpFbs(rtcpfbs); 331 } 332 GetH264Parameters(const std::string & pt,const SdpMediaSection & msection)333 SdpFmtpAttributeList::H264Parameters GetH264Parameters( 334 const std::string& pt, const SdpMediaSection& msection) const { 335 // Will contain defaults if nothing else 336 SdpFmtpAttributeList::H264Parameters result; 337 auto* params = msection.FindFmtp(pt); 338 339 if (params && params->codec_type == SdpRtpmapAttributeList::kH264) { 340 result = 341 static_cast<const SdpFmtpAttributeList::H264Parameters&>(*params); 342 } 343 344 return result; 345 } 346 GetRedParameters(const std::string & pt,const SdpMediaSection & msection)347 SdpFmtpAttributeList::RedParameters GetRedParameters( 348 const std::string& pt, const SdpMediaSection& msection) const { 349 SdpFmtpAttributeList::RedParameters result; 350 auto* params = msection.FindFmtp(pt); 351 352 if (params && params->codec_type == SdpRtpmapAttributeList::kRed) { 353 result = static_cast<const SdpFmtpAttributeList::RedParameters&>(*params); 354 } 355 356 return result; 357 } 358 GetVP8Parameters(const std::string & pt,const SdpMediaSection & msection)359 SdpFmtpAttributeList::VP8Parameters GetVP8Parameters( 360 const std::string& pt, const SdpMediaSection& msection) const { 361 SdpRtpmapAttributeList::CodecType expectedType( 362 mName == "VP8" ? SdpRtpmapAttributeList::kVP8 363 : SdpRtpmapAttributeList::kVP9); 364 365 // Will contain defaults if nothing else 366 SdpFmtpAttributeList::VP8Parameters result(expectedType); 367 auto* params = msection.FindFmtp(pt); 368 369 if (params && params->codec_type == expectedType) { 370 result = static_cast<const SdpFmtpAttributeList::VP8Parameters&>(*params); 371 } 372 373 return result; 374 } 375 NegotiateRtcpFb(const SdpMediaSection & remoteMsection,SdpRtcpFbAttributeList::Type type,std::vector<std::string> * supportedTypes)376 void NegotiateRtcpFb(const SdpMediaSection& remoteMsection, 377 SdpRtcpFbAttributeList::Type type, 378 std::vector<std::string>* supportedTypes) { 379 std::vector<std::string> temp; 380 for (auto& subType : *supportedTypes) { 381 if (remoteMsection.HasRtcpFb(mDefaultPt, type, subType)) { 382 temp.push_back(subType); 383 } 384 } 385 *supportedTypes = temp; 386 } 387 NegotiateRtcpFb(const SdpMediaSection & remoteMsection,std::vector<SdpRtcpFbAttributeList::Feedback> * supportedFbs)388 void NegotiateRtcpFb( 389 const SdpMediaSection& remoteMsection, 390 std::vector<SdpRtcpFbAttributeList::Feedback>* supportedFbs) { 391 std::vector<SdpRtcpFbAttributeList::Feedback> temp; 392 for (auto& fb : *supportedFbs) { 393 if (remoteMsection.HasRtcpFb(mDefaultPt, fb.type, fb.parameter)) { 394 temp.push_back(fb); 395 } 396 } 397 *supportedFbs = temp; 398 } 399 NegotiateRtcpFb(const SdpMediaSection & remote)400 void NegotiateRtcpFb(const SdpMediaSection& remote) { 401 // Removes rtcp-fb types that the other side doesn't support 402 NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kAck, &mAckFbTypes); 403 NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kNack, &mNackFbTypes); 404 NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kCcm, &mCcmFbTypes); 405 NegotiateRtcpFb(remote, &mOtherFbTypes); 406 } 407 Negotiate(const std::string & pt,const SdpMediaSection & remoteMsection)408 virtual bool Negotiate(const std::string& pt, 409 const SdpMediaSection& remoteMsection) override { 410 JsepCodecDescription::Negotiate(pt, remoteMsection); 411 if (mName == "H264") { 412 SdpFmtpAttributeList::H264Parameters h264Params( 413 GetH264Parameters(mDefaultPt, remoteMsection)); 414 415 // Level is negotiated symmetrically if level asymmetry is disallowed 416 if (!h264Params.level_asymmetry_allowed) { 417 SetSaneH264Level(std::min(GetSaneH264Level(h264Params.profile_level_id), 418 GetSaneH264Level(mProfileLevelId)), 419 &mProfileLevelId); 420 } 421 422 if (mDirection == sdp::kSend) { 423 // Remote values of these apply only to the send codec. 424 mConstraints.maxFs = h264Params.max_fs; 425 mConstraints.maxMbps = h264Params.max_mbps; 426 mConstraints.maxCpb = h264Params.max_cpb; 427 mConstraints.maxDpb = h264Params.max_dpb; 428 mConstraints.maxBr = h264Params.max_br; 429 mSpropParameterSets = h264Params.sprop_parameter_sets; 430 // Only do this if we didn't symmetrically negotiate above 431 if (h264Params.level_asymmetry_allowed) { 432 SetSaneH264Level(GetSaneH264Level(h264Params.profile_level_id), 433 &mProfileLevelId); 434 } 435 } else { 436 // TODO(bug 1143709): max-recv-level support 437 } 438 } else if (mName == "red") { 439 SdpFmtpAttributeList::RedParameters redParams( 440 GetRedParameters(mDefaultPt, remoteMsection)); 441 mRedundantEncodings = redParams.encodings; 442 } else if (mName == "VP8" || mName == "VP9") { 443 if (mDirection == sdp::kSend) { 444 SdpFmtpAttributeList::VP8Parameters vp8Params( 445 GetVP8Parameters(mDefaultPt, remoteMsection)); 446 447 mConstraints.maxFs = vp8Params.max_fs; 448 mConstraints.maxFps = vp8Params.max_fr; 449 } 450 } 451 452 NegotiateRtcpFb(remoteMsection); 453 return true; 454 } 455 456 // Maps the not-so-sane encoding of H264 level into something that is 457 // ordered in the way one would expect 458 // 1b is 0xAB, everything else is the level left-shifted one half-byte 459 // (eg; 1.0 is 0xA0, 1.1 is 0xB0, 3.1 is 0x1F0) GetSaneH264Level(uint32_t profileLevelId)460 static uint32_t GetSaneH264Level(uint32_t profileLevelId) { 461 uint32_t profileIdc = (profileLevelId >> 16); 462 463 if (profileIdc == 0x42 || profileIdc == 0x4D || profileIdc == 0x58) { 464 if ((profileLevelId & 0x10FF) == 0x100B) { 465 // Level 1b 466 return 0xAB; 467 } 468 } 469 470 uint32_t level = profileLevelId & 0xFF; 471 472 if (level == 0x09) { 473 // Another way to encode level 1b 474 return 0xAB; 475 } 476 477 return level << 4; 478 } 479 SetSaneH264Level(uint32_t level,uint32_t * profileLevelId)480 static void SetSaneH264Level(uint32_t level, uint32_t* profileLevelId) { 481 uint32_t profileIdc = (*profileLevelId >> 16); 482 uint32_t levelMask = 0xFF; 483 484 if (profileIdc == 0x42 || profileIdc == 0x4d || profileIdc == 0x58) { 485 levelMask = 0x10FF; 486 if (level == 0xAB) { 487 // Level 1b 488 level = 0x100B; 489 } else { 490 // Not 1b, just shift 491 level = level >> 4; 492 } 493 } else if (level == 0xAB) { 494 // Another way to encode 1b 495 level = 0x09; 496 } else { 497 // Not 1b, just shift 498 level = level >> 4; 499 } 500 501 *profileLevelId = (*profileLevelId & ~levelMask) | level; 502 } 503 504 enum Subprofile { 505 kH264ConstrainedBaseline, 506 kH264Baseline, 507 kH264Main, 508 kH264Extended, 509 kH264High, 510 kH264High10, 511 kH264High42, 512 kH264High44, 513 kH264High10I, 514 kH264High42I, 515 kH264High44I, 516 kH264CALVC44, 517 kH264UnknownSubprofile 518 }; 519 GetSubprofile(uint32_t profileLevelId)520 static Subprofile GetSubprofile(uint32_t profileLevelId) { 521 // Based on Table 5 from RFC 6184: 522 // Profile profile_idc profile-iop 523 // (hexadecimal) (binary) 524 525 // CB 42 (B) x1xx0000 526 // same as: 4D (M) 1xxx0000 527 // same as: 58 (E) 11xx0000 528 // B 42 (B) x0xx0000 529 // same as: 58 (E) 10xx0000 530 // M 4D (M) 0x0x0000 531 // E 58 00xx0000 532 // H 64 00000000 533 // H10 6E 00000000 534 // H42 7A 00000000 535 // H44 F4 00000000 536 // H10I 6E 00010000 537 // H42I 7A 00010000 538 // H44I F4 00010000 539 // C44I 2C 00010000 540 541 if ((profileLevelId & 0xFF4F00) == 0x424000) { 542 // 01001111 (mask, 0x4F) 543 // x1xx0000 (from table) 544 // 01000000 (expected value, 0x40) 545 return kH264ConstrainedBaseline; 546 } 547 548 if ((profileLevelId & 0xFF8F00) == 0x4D8000) { 549 // 10001111 (mask, 0x8F) 550 // 1xxx0000 (from table) 551 // 10000000 (expected value, 0x80) 552 return kH264ConstrainedBaseline; 553 } 554 555 if ((profileLevelId & 0xFFCF00) == 0x58C000) { 556 // 11001111 (mask, 0xCF) 557 // 11xx0000 (from table) 558 // 11000000 (expected value, 0xC0) 559 return kH264ConstrainedBaseline; 560 } 561 562 if ((profileLevelId & 0xFF4F00) == 0x420000) { 563 // 01001111 (mask, 0x4F) 564 // x0xx0000 (from table) 565 // 00000000 (expected value) 566 return kH264Baseline; 567 } 568 569 if ((profileLevelId & 0xFFCF00) == 0x588000) { 570 // 11001111 (mask, 0xCF) 571 // 10xx0000 (from table) 572 // 10000000 (expected value, 0x80) 573 return kH264Baseline; 574 } 575 576 if ((profileLevelId & 0xFFAF00) == 0x4D0000) { 577 // 10101111 (mask, 0xAF) 578 // 0x0x0000 (from table) 579 // 00000000 (expected value) 580 return kH264Main; 581 } 582 583 if ((profileLevelId & 0xFF0000) == 0x580000) { 584 // 11001111 (mask, 0xCF) 585 // 00xx0000 (from table) 586 // 00000000 (expected value) 587 return kH264Extended; 588 } 589 590 if ((profileLevelId & 0xFFFF00) == 0x640000) { 591 return kH264High; 592 } 593 594 if ((profileLevelId & 0xFFFF00) == 0x6E0000) { 595 return kH264High10; 596 } 597 598 if ((profileLevelId & 0xFFFF00) == 0x7A0000) { 599 return kH264High42; 600 } 601 602 if ((profileLevelId & 0xFFFF00) == 0xF40000) { 603 return kH264High44; 604 } 605 606 if ((profileLevelId & 0xFFFF00) == 0x6E1000) { 607 return kH264High10I; 608 } 609 610 if ((profileLevelId & 0xFFFF00) == 0x7A1000) { 611 return kH264High42I; 612 } 613 614 if ((profileLevelId & 0xFFFF00) == 0xF41000) { 615 return kH264High44I; 616 } 617 618 if ((profileLevelId & 0xFFFF00) == 0x2C1000) { 619 return kH264CALVC44; 620 } 621 622 return kH264UnknownSubprofile; 623 } 624 ParametersMatch(const std::string & fmt,const SdpMediaSection & remoteMsection)625 virtual bool ParametersMatch( 626 const std::string& fmt, 627 const SdpMediaSection& remoteMsection) const override { 628 if (mName == "H264") { 629 SdpFmtpAttributeList::H264Parameters h264Params( 630 GetH264Parameters(fmt, remoteMsection)); 631 632 if (h264Params.packetization_mode != mPacketizationMode) { 633 return false; 634 } 635 636 if (GetSubprofile(h264Params.profile_level_id) != 637 GetSubprofile(mProfileLevelId)) { 638 return false; 639 } 640 } 641 642 return true; 643 } 644 RtcpFbRembIsSet()645 virtual bool RtcpFbRembIsSet() const { 646 for (const auto& fb : mOtherFbTypes) { 647 if (fb.type == SdpRtcpFbAttributeList::kRemb) { 648 return true; 649 } 650 } 651 return false; 652 } 653 UpdateRedundantEncodings(std::vector<JsepCodecDescription * > codecs)654 virtual void UpdateRedundantEncodings( 655 std::vector<JsepCodecDescription*> codecs) { 656 for (const auto codec : codecs) { 657 if (codec->mType == SdpMediaSection::kVideo && codec->mEnabled && 658 codec->mName != "red") { 659 uint16_t pt; 660 if (!SdpHelper::GetPtAsInt(codec->mDefaultPt, &pt)) { 661 continue; 662 } 663 mRedundantEncodings.push_back(pt); 664 } 665 } 666 } 667 668 JSEP_CODEC_CLONE(JsepVideoCodecDescription) 669 670 std::vector<std::string> mAckFbTypes; 671 std::vector<std::string> mNackFbTypes; 672 std::vector<std::string> mCcmFbTypes; 673 std::vector<SdpRtcpFbAttributeList::Feedback> mOtherFbTypes; 674 bool mTmmbrEnabled; 675 bool mRembEnabled; 676 bool mFECEnabled; 677 uint8_t mREDPayloadType; 678 uint8_t mULPFECPayloadType; 679 std::vector<uint8_t> mRedundantEncodings; 680 681 // H264-specific stuff 682 uint32_t mProfileLevelId; 683 uint32_t mPacketizationMode; 684 std::string mSpropParameterSets; 685 }; 686 687 class JsepApplicationCodecDescription : public JsepCodecDescription { 688 // This is the new draft-21 implementation 689 public: 690 JsepApplicationCodecDescription(const std::string& name, uint16_t channels, 691 uint16_t localPort, 692 uint32_t localMaxMessageSize, 693 bool enabled = true) 694 : JsepCodecDescription(mozilla::SdpMediaSection::kApplication, "", name, 695 0, channels, enabled), 696 mLocalPort(localPort), 697 mLocalMaxMessageSize(localMaxMessageSize), 698 mRemotePort(0), 699 mRemoteMaxMessageSize(0) {} 700 JSEP_CODEC_CLONE(JsepApplicationCodecDescription)701 JSEP_CODEC_CLONE(JsepApplicationCodecDescription) 702 703 // Override, uses sctpport or sctpmap instead of rtpmap 704 virtual bool Matches(const std::string& fmt, 705 const SdpMediaSection& remoteMsection) const override { 706 if (mType != remoteMsection.GetMediaType()) { 707 return false; 708 } 709 710 int sctp_port = remoteMsection.GetSctpPort(); 711 bool fmt_matches = 712 nsCRT::strcasecmp(mName.c_str(), 713 remoteMsection.GetFormats()[0].c_str()) == 0; 714 if (sctp_port && fmt_matches) { 715 // New sctp draft 21 format 716 return true; 717 } 718 719 const SdpSctpmapAttributeList::Sctpmap* sctp_map( 720 remoteMsection.GetSctpmap()); 721 if (sctp_map) { 722 // Old sctp draft 05 format 723 return nsCRT::strcasecmp(mName.c_str(), sctp_map->name.c_str()) == 0; 724 } 725 726 return false; 727 } 728 AddToMediaSection(SdpMediaSection & msection)729 virtual void AddToMediaSection(SdpMediaSection& msection) const override { 730 if (mEnabled && msection.GetMediaType() == mType) { 731 if (msection.GetFormats().empty()) { 732 msection.AddDataChannel(mName, mLocalPort, mChannels, 733 mLocalMaxMessageSize); 734 } 735 736 AddParametersToMSection(msection); 737 } 738 } 739 Negotiate(const std::string & pt,const SdpMediaSection & remoteMsection)740 bool Negotiate(const std::string& pt, 741 const SdpMediaSection& remoteMsection) override { 742 JsepCodecDescription::Negotiate(pt, remoteMsection); 743 744 uint32_t message_size; 745 mRemoteMMSSet = remoteMsection.GetMaxMessageSize(&message_size); 746 if (mRemoteMMSSet) { 747 mRemoteMaxMessageSize = message_size; 748 } else { 749 mRemoteMaxMessageSize = 750 WEBRTC_DATACHANNEL_MAX_MESSAGE_SIZE_REMOTE_DEFAULT; 751 } 752 753 int sctp_port = remoteMsection.GetSctpPort(); 754 if (sctp_port) { 755 mRemotePort = sctp_port; 756 return true; 757 } 758 759 const SdpSctpmapAttributeList::Sctpmap* sctp_map( 760 remoteMsection.GetSctpmap()); 761 if (sctp_map) { 762 mRemotePort = std::stoi(sctp_map->pt); 763 return true; 764 } 765 766 return false; 767 } 768 769 uint16_t mLocalPort; 770 uint32_t mLocalMaxMessageSize; 771 uint16_t mRemotePort; 772 uint32_t mRemoteMaxMessageSize; 773 bool mRemoteMMSSet; 774 }; 775 776 } // namespace mozilla 777 778 #endif 779