jsep_track_unittest.cpp (84934B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "nss.h" 8 #include "ssl.h" 9 10 #define GTEST_HAS_RTTI 0 11 #include "gmock/gmock.h" 12 #include "gtest/gtest.h" 13 14 #include "MockJsepCodecPreferences.h" 15 #include "jsapi/DefaultCodecPreferences.h" 16 #include "jsep/JsepTrack.h" 17 #include "sdp/SipccSdp.h" 18 #include "sdp/SipccSdpParser.h" 19 #include "sdp/SdpHelper.h" 20 21 using testing::UnorderedElementsAre; 22 23 namespace mozilla { 24 25 class JsepTrackTestBase : public ::testing::Test { 26 public: 27 static void SetUpTestCase() { 28 NSS_NoDB_Init(nullptr); 29 NSS_SetDomesticPolicy(); 30 } 31 }; 32 33 struct CodecOverrides { 34 bool addFecCodecs = false; 35 bool preferRed = false; 36 bool addDtmfCodec = false; 37 bool enableRemb = true; 38 bool enableTransportCC = true; 39 void ApplyToPrefs(MockJsepCodecPreferences& aPrefs) const { 40 aPrefs.mUseRemb = enableRemb; 41 aPrefs.mUseTransportCC = enableTransportCC; 42 } 43 }; 44 45 class JsepTrackTest : public JsepTrackTestBase { 46 public: 47 JsepTrackTest() 48 : mSendOff(SdpMediaSection::kAudio, sdp::kSend), 49 mRecvOff(SdpMediaSection::kAudio, sdp::kRecv), 50 mSendAns(SdpMediaSection::kAudio, sdp::kSend), 51 mRecvAns(SdpMediaSection::kAudio, sdp::kRecv) {} 52 53 void TearDown() override { 54 if (::testing::UnitTest::GetInstance() 55 ->current_test_info() 56 ->result() 57 ->Failed()) { 58 if (mOffer) { 59 std::cerr << "Offer SDP: \n"; 60 mOffer->Serialize(std::cerr); 61 } 62 63 if (mAnswer) { 64 std::cerr << "Answer SDP: \n"; 65 mAnswer->Serialize(std::cerr); 66 } 67 } 68 } 69 70 std::vector<UniquePtr<JsepCodecDescription>> MakeCodecs( 71 const CodecOverrides overrides) const { 72 MockJsepCodecPreferences prefs; 73 overrides.ApplyToPrefs(prefs); 74 75 prefs.mUseRemb = overrides.enableRemb; 76 prefs.mUseTransportCC = overrides.enableTransportCC; 77 JsepCodecPreferences& prefsRef = prefs; 78 std::cout << "CodecPrefrences: " << prefsRef << "\n"; 79 std::vector<UniquePtr<JsepCodecDescription>> results; 80 results.emplace_back(JsepAudioCodecDescription::CreateDefaultOpus(prefs)); 81 results.emplace_back(JsepAudioCodecDescription::CreateDefaultG722()); 82 if (overrides.addDtmfCodec) { 83 results.emplace_back( 84 JsepAudioCodecDescription::CreateDefaultTelephoneEvent()); 85 } 86 87 if (overrides.addFecCodecs && overrides.preferRed) { 88 results.emplace_back(JsepVideoCodecDescription::CreateDefaultRed(prefs)); 89 } 90 results.emplace_back(JsepVideoCodecDescription::CreateDefaultVP8(prefs)); 91 results.emplace_back(JsepVideoCodecDescription::CreateDefaultH264_1(prefs)); 92 results.emplace_back(JsepVideoCodecDescription::CreateDefaultAV1(prefs)); 93 94 if (overrides.addFecCodecs) { 95 if (!overrides.preferRed) { 96 results.emplace_back( 97 JsepVideoCodecDescription::CreateDefaultRed(prefs)); 98 } 99 results.emplace_back( 100 JsepVideoCodecDescription::CreateDefaultUlpFec(prefs)); 101 } 102 103 results.emplace_back(new JsepApplicationCodecDescription( 104 "webrtc-datachannel", 256, 5999, 499)); 105 106 return results; 107 } 108 109 void Init(SdpMediaSection::MediaType type) { 110 InitCodecs(CodecOverrides{}); 111 InitTracks(type); 112 InitSdp(type); 113 } 114 115 struct SplitOverrides { 116 CodecOverrides offer = {}; 117 CodecOverrides answer = {}; 118 }; 119 120 void InitCodecs(const CodecOverrides& overrides) { 121 mOffCodecs = MakeCodecs(overrides); 122 mAnsCodecs = MakeCodecs(overrides); 123 } 124 void InitCodecs(const SplitOverrides& overrides) { 125 mOffCodecs = MakeCodecs(overrides.offer); 126 mAnsCodecs = MakeCodecs(overrides.answer); 127 } 128 129 void InitTracks(SdpMediaSection::MediaType type) { 130 mSendOff = JsepTrack(type, sdp::kSend); 131 if (type != SdpMediaSection::MediaType::kApplication) { 132 mSendOff.UpdateStreamIds(std::vector<std::string>(1, "stream_id")); 133 } 134 mRecvOff = JsepTrack(type, sdp::kRecv); 135 mSendOff.PopulateCodecs(mOffCodecs); 136 mRecvOff.PopulateCodecs(mOffCodecs); 137 138 mSendAns = JsepTrack(type, sdp::kSend); 139 if (type != SdpMediaSection::MediaType::kApplication) { 140 mSendAns.UpdateStreamIds(std::vector<std::string>(1, "stream_id")); 141 } 142 mRecvAns = JsepTrack(type, sdp::kRecv); 143 mSendAns.PopulateCodecs(mAnsCodecs); 144 mRecvAns.PopulateCodecs(mAnsCodecs); 145 } 146 147 void InitSdp(SdpMediaSection::MediaType type) { 148 std::vector<std::string> msids(1, "*"); 149 std::string error; 150 SdpHelper helper(&error); 151 152 mOffer.reset(new SipccSdp(SdpOrigin("", 0, 0, sdp::kIPv4, ""))); 153 mOffer->AddMediaSection(type, SdpDirectionAttribute::kSendrecv, 0, 154 SdpHelper::GetProtocolForMediaType(type), 155 sdp::kIPv4, "0.0.0.0"); 156 // JsepTrack doesn't set msid-semantic 157 helper.SetupMsidSemantic(msids, mOffer.get()); 158 159 mAnswer.reset(new SipccSdp(SdpOrigin("", 0, 0, sdp::kIPv4, ""))); 160 mAnswer->AddMediaSection(type, SdpDirectionAttribute::kSendrecv, 0, 161 SdpHelper::GetProtocolForMediaType(type), 162 sdp::kIPv4, "0.0.0.0"); 163 // JsepTrack doesn't set msid-semantic 164 helper.SetupMsidSemantic(msids, mAnswer.get()); 165 } 166 167 SdpMediaSection& GetOffer() { return mOffer->GetMediaSection(0); } 168 169 SdpMediaSection& GetAnswer() { return mAnswer->GetMediaSection(0); } 170 171 void CreateOffer() { 172 mSendOff.AddToOffer(mSsrcGenerator, &GetOffer()); 173 mRecvOff.AddToOffer(mSsrcGenerator, &GetOffer()); 174 } 175 176 void CreateAnswer() { 177 if (mRecvAns.GetMediaType() != SdpMediaSection::MediaType::kApplication) { 178 mRecvAns.RecvTrackSetRemote(*mOffer, GetOffer()); 179 mSendAns.SendTrackSetRemote(mSsrcGenerator, GetOffer()); 180 } 181 182 mSendAns.AddToAnswer(GetOffer(), mSsrcGenerator, &GetAnswer()); 183 mRecvAns.AddToAnswer(GetOffer(), mSsrcGenerator, &GetAnswer()); 184 } 185 186 void Negotiate() { 187 if (mRecvOff.GetMediaType() != SdpMediaSection::MediaType::kApplication) { 188 mRecvOff.RecvTrackSetRemote(*mAnswer, GetAnswer()); 189 mSendOff.SendTrackSetRemote(mSsrcGenerator, GetAnswer()); 190 } 191 192 if (GetAnswer().IsSending()) { 193 mSendAns.Negotiate(GetAnswer(), GetOffer(), GetAnswer()); 194 mRecvOff.Negotiate(GetAnswer(), GetAnswer(), GetOffer()); 195 } 196 197 if (GetAnswer().IsReceiving()) { 198 mRecvAns.Negotiate(GetAnswer(), GetOffer(), GetAnswer()); 199 mSendOff.Negotiate(GetAnswer(), GetAnswer(), GetOffer()); 200 } 201 } 202 203 void OfferAnswer(bool offerCodecsMatchAnswer = true) { 204 CreateOffer(); 205 CreateAnswer(); 206 Negotiate(); 207 SanityCheck(offerCodecsMatchAnswer); 208 } 209 210 // TODO: Look into writing a macro that wraps an ASSERT_ and returns false 211 // if it fails (probably requires writing a bool-returning function that 212 // takes a void-returning lambda with a bool outparam, which will in turn 213 // invokes the ASSERT_) 214 static void CheckEncodingCount(size_t expected, const JsepTrack& send, 215 const JsepTrack& recv) { 216 if (expected) { 217 ASSERT_TRUE(send.GetNegotiatedDetails()); 218 ASSERT_TRUE(recv.GetNegotiatedDetails()); 219 } 220 221 if (!send.GetStreamIds().empty() && send.GetNegotiatedDetails()) { 222 ASSERT_EQ(expected, send.GetNegotiatedDetails()->GetEncodingCount()); 223 } 224 225 if (!recv.GetStreamIds().empty() && recv.GetNegotiatedDetails()) { 226 ASSERT_EQ(expected, recv.GetNegotiatedDetails()->GetEncodingCount()); 227 } 228 } 229 230 void CheckOffEncodingCount(size_t expected) const { 231 CheckEncodingCount(expected, mSendOff, mRecvAns); 232 } 233 234 void CheckAnsEncodingCount(size_t expected) const { 235 CheckEncodingCount(expected, mSendAns, mRecvOff); 236 } 237 238 UniquePtr<JsepCodecDescription> GetCodec(const JsepTrack& track, 239 SdpMediaSection::MediaType type, 240 size_t expectedSize, 241 size_t codecIndex) const { 242 if (!track.GetNegotiatedDetails() || 243 track.GetNegotiatedDetails()->GetEncodingCount() != 1U || 244 track.GetMediaType() != type) { 245 return nullptr; 246 } 247 const auto& codecs = 248 track.GetNegotiatedDetails()->GetEncoding(0).GetCodecs(); 249 // it should not be possible for codecs to have a different type 250 // than the track, but we'll check the codec here just in case. 251 if (codecs.size() != expectedSize || codecIndex >= expectedSize || 252 codecs[codecIndex]->Type() != type) { 253 return nullptr; 254 } 255 return UniquePtr<JsepCodecDescription>(codecs[codecIndex]->Clone()); 256 } 257 258 UniquePtr<JsepVideoCodecDescription> GetVideoCodec( 259 const JsepTrack& track, size_t expectedSize = 1, 260 size_t codecIndex = 0) const { 261 auto codec = 262 GetCodec(track, SdpMediaSection::kVideo, expectedSize, codecIndex); 263 return UniquePtr<JsepVideoCodecDescription>( 264 static_cast<JsepVideoCodecDescription*>(codec.release())); 265 } 266 267 UniquePtr<JsepAudioCodecDescription> GetAudioCodec( 268 const JsepTrack& track, size_t expectedSize = 1, 269 size_t codecIndex = 0) const { 270 auto codec = 271 GetCodec(track, SdpMediaSection::kAudio, expectedSize, codecIndex); 272 return UniquePtr<JsepAudioCodecDescription>( 273 static_cast<JsepAudioCodecDescription*>(codec.release())); 274 } 275 276 void CheckOtherFbExists(const JsepVideoCodecDescription& videoCodec, 277 SdpRtcpFbAttributeList::Type type) const { 278 for (const auto& fb : videoCodec.mOtherFbTypes) { 279 if (fb.type == type) { 280 return; // found the RtcpFb type, so stop looking 281 } 282 } 283 FAIL(); // RtcpFb type not found 284 } 285 286 void SanityCheckRtcpFbs(const JsepVideoCodecDescription& a, 287 const JsepVideoCodecDescription& b) const { 288 ASSERT_EQ(a.mNackFbTypes.size(), b.mNackFbTypes.size()); 289 ASSERT_EQ(a.mAckFbTypes.size(), b.mAckFbTypes.size()); 290 ASSERT_EQ(a.mCcmFbTypes.size(), b.mCcmFbTypes.size()); 291 ASSERT_EQ(a.mOtherFbTypes.size(), b.mOtherFbTypes.size()); 292 } 293 294 void SanityCheckCodecs(const JsepCodecDescription& a, 295 const JsepCodecDescription& b) const { 296 #define MSG \ 297 "For codecs " << a.mName << " (" << a.mDirection << ") and " << b.mName \ 298 << " (" << b.mDirection << ")" 299 ASSERT_EQ(a.Type(), b.Type()) << MSG; 300 if (a.Type() != SdpMediaSection::kApplication) { 301 ASSERT_EQ(a.mDefaultPt, b.mDefaultPt) << MSG; 302 } 303 ASSERT_EQ(a.mName, b.mName); 304 if (!mExpectDifferingFmtp) { 305 ASSERT_EQ(a.mSdpFmtpLine, b.mSdpFmtpLine) << MSG; 306 } 307 ASSERT_EQ(a.mClock, b.mClock) << MSG; 308 ASSERT_EQ(a.mChannels, b.mChannels) << MSG; 309 ASSERT_NE(a.mDirection, b.mDirection) << MSG; 310 // These constraints are for fmtp and rid, which _are_ signaled 311 ASSERT_EQ(a.mConstraints, b.mConstraints) << MSG; 312 #undef MSG 313 314 if (a.Type() == SdpMediaSection::kVideo) { 315 SanityCheckRtcpFbs(static_cast<const JsepVideoCodecDescription&>(a), 316 static_cast<const JsepVideoCodecDescription&>(b)); 317 } 318 } 319 320 void SanityCheckEncodings(const JsepTrackEncoding& a, 321 const JsepTrackEncoding& b) const { 322 ASSERT_EQ(a.GetCodecs().size(), b.GetCodecs().size()); 323 for (size_t i = 0; i < a.GetCodecs().size(); ++i) { 324 SanityCheckCodecs(*a.GetCodecs()[i], *b.GetCodecs()[i]); 325 } 326 327 ASSERT_EQ(a.mRid, b.mRid); 328 // mConstraints will probably differ, since they are not signaled to the 329 // other side. 330 } 331 332 void SanityCheckNegotiatedDetails(const JsepTrack& aTrack, 333 const JsepTrack& bTrack, 334 bool codecsMustMatch) const { 335 const auto aDetails = *aTrack.GetNegotiatedDetails(); 336 const auto bDetails = *bTrack.GetNegotiatedDetails(); 337 ASSERT_EQ(aDetails.GetEncodingCount(), bDetails.GetEncodingCount()); 338 if (codecsMustMatch) { 339 for (size_t i = 0; i < aDetails.GetEncodingCount(); ++i) { 340 SanityCheckEncodings(aDetails.GetEncoding(i), bDetails.GetEncoding(i)); 341 } 342 } 343 344 ASSERT_EQ(aTrack.GetUniqueReceivePayloadTypes().size(), 345 bTrack.GetUniqueReceivePayloadTypes().size()); 346 for (size_t i = 0; i < aTrack.GetUniqueReceivePayloadTypes().size(); ++i) { 347 ASSERT_EQ(aTrack.GetUniqueReceivePayloadTypes()[i], 348 bTrack.GetUniqueReceivePayloadTypes()[i]); 349 } 350 } 351 352 void SanityCheckTracks(const JsepTrack& a, const JsepTrack& b, 353 bool codecsMustMatch) const { 354 if (!a.GetNegotiatedDetails()) { 355 ASSERT_FALSE(!!b.GetNegotiatedDetails()); 356 return; 357 } 358 359 ASSERT_TRUE(!!a.GetNegotiatedDetails()); 360 ASSERT_TRUE(!!b.GetNegotiatedDetails()); 361 ASSERT_EQ(a.GetMediaType(), b.GetMediaType()); 362 ASSERT_EQ(a.GetStreamIds(), b.GetStreamIds()); 363 ASSERT_EQ(a.GetCNAME(), b.GetCNAME()); 364 ASSERT_NE(a.GetDirection(), b.GetDirection()); 365 ASSERT_EQ(a.GetSsrcs().size(), b.GetSsrcs().size()); 366 for (size_t i = 0; i < a.GetSsrcs().size(); ++i) { 367 ASSERT_EQ(a.GetSsrcs()[i], b.GetSsrcs()[i]); 368 } 369 370 SanityCheckNegotiatedDetails(a, b, codecsMustMatch); 371 } 372 373 void SanityCheck(bool offerCodecsMatchAnswer = true) const { 374 SanityCheckTracks(mSendOff, mRecvAns, true); 375 SanityCheckTracks(mRecvOff, mSendAns, offerCodecsMatchAnswer); 376 } 377 378 protected: 379 JsepTrack mSendOff; 380 JsepTrack mRecvOff; 381 JsepTrack mSendAns; 382 JsepTrack mRecvAns; 383 std::vector<UniquePtr<JsepCodecDescription>> mOffCodecs; 384 std::vector<UniquePtr<JsepCodecDescription>> mAnsCodecs; 385 UniquePtr<Sdp> mOffer; 386 UniquePtr<Sdp> mAnswer; 387 SsrcGenerator mSsrcGenerator; 388 bool mExpectDifferingFmtp = false; 389 }; 390 391 TEST_F(JsepTrackTestBase, CreateDestroy) {} 392 393 TEST_F(JsepTrackTest, CreateDestroy) { Init(SdpMediaSection::kAudio); } 394 395 TEST_F(JsepTrackTest, AudioNegotiation) { 396 Init(SdpMediaSection::kAudio); 397 OfferAnswer(); 398 CheckOffEncodingCount(1); 399 CheckAnsEncodingCount(1); 400 } 401 402 TEST_F(JsepTrackTest, VideoNegotiation) { 403 Init(SdpMediaSection::kVideo); 404 OfferAnswer(); 405 CheckOffEncodingCount(1); 406 CheckAnsEncodingCount(1); 407 } 408 409 class CheckForCodecType { 410 public: 411 explicit CheckForCodecType(SdpMediaSection::MediaType type, bool* result) 412 : mResult(result), mType(type) {} 413 414 void operator()(const UniquePtr<JsepCodecDescription>& codec) { 415 if (codec->Type() == mType) { 416 *mResult = true; 417 } 418 } 419 420 private: 421 bool* mResult; 422 SdpMediaSection::MediaType mType; 423 }; 424 425 TEST_F(JsepTrackTest, CheckForAnsweringWithExtmapAllowMixedWhenNotOffered) { 426 Init(SdpMediaSection::kAudio); 427 428 CreateOffer(); 429 mOffer->GetMediaSection(0).GetAttributeList().RemoveAttribute( 430 SdpAttribute::kExtmapAllowMixedAttribute); 431 CreateAnswer(); 432 433 ASSERT_FALSE(mAnswer->GetMediaSection(0).GetAttributeList().HasAttribute( 434 SdpAttribute::kExtmapAllowMixedAttribute)); 435 Negotiate(); 436 SanityCheck(); 437 } 438 439 TEST_F(JsepTrackTest, CheckForMismatchedAudioCodecAndVideoTrack) { 440 std::vector<UniquePtr<JsepCodecDescription>> offerCodecs; 441 442 // make codecs including telephone-event (an audio codec) 443 offerCodecs = MakeCodecs({.addDtmfCodec = true}); 444 JsepTrack videoTrack(SdpMediaSection::kVideo, sdp::kSend); 445 videoTrack.UpdateStreamIds(std::vector<std::string>(1, "stream_id")); 446 // populate codecs and then make sure we don't have any audio codecs 447 // in the video track 448 videoTrack.PopulateCodecs(offerCodecs); 449 450 bool found = false; 451 videoTrack.ForEachCodec(CheckForCodecType(SdpMediaSection::kAudio, &found)); 452 ASSERT_FALSE(found); 453 454 found = false; 455 videoTrack.ForEachCodec(CheckForCodecType(SdpMediaSection::kVideo, &found)); 456 ASSERT_TRUE(found); // for sanity, make sure we did find video codecs 457 } 458 459 TEST_F(JsepTrackTest, CheckVideoTrackWithHackedDtmfSdp) { 460 Init(SdpMediaSection::kVideo); 461 CreateOffer(); 462 // make sure we don't find sdp containing telephone-event in video track 463 ASSERT_EQ(mOffer->ToString().find("a=rtpmap:101 telephone-event"), 464 std::string::npos); 465 // force audio codec telephone-event into video m= section of offer 466 GetOffer().AddCodec("101", "telephone-event", 8000, 1); 467 // make sure we _do_ find sdp containing telephone-event in video track 468 ASSERT_NE(mOffer->ToString().find("a=rtpmap:101 telephone-event"), 469 std::string::npos); 470 471 CreateAnswer(); 472 // make sure we don't find sdp containing telephone-event in video track 473 ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:101 telephone-event"), 474 std::string::npos); 475 // force audio codec telephone-event into video m= section of answer 476 GetAnswer().AddCodec("101", "telephone-event", 8000, 1); 477 // make sure we _do_ find sdp containing telephone-event in video track 478 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:101 telephone-event"), 479 std::string::npos); 480 481 Negotiate(); 482 SanityCheck(); 483 484 CheckOffEncodingCount(1); 485 CheckAnsEncodingCount(1); 486 487 // make sure we still don't find any audio codecs in the video track after 488 // hacking the sdp 489 bool found = false; 490 mSendOff.ForEachCodec(CheckForCodecType(SdpMediaSection::kAudio, &found)); 491 ASSERT_FALSE(found); 492 mRecvOff.ForEachCodec(CheckForCodecType(SdpMediaSection::kAudio, &found)); 493 ASSERT_FALSE(found); 494 mSendAns.ForEachCodec(CheckForCodecType(SdpMediaSection::kAudio, &found)); 495 ASSERT_FALSE(found); 496 mRecvAns.ForEachCodec(CheckForCodecType(SdpMediaSection::kAudio, &found)); 497 ASSERT_FALSE(found); 498 } 499 500 TEST_F(JsepTrackTest, AudioNegotiationOffererDtmf) { 501 InitCodecs( 502 {.offer = {.addDtmfCodec = true}, .answer = {.addDtmfCodec = false}}); 503 504 InitTracks(SdpMediaSection::kAudio); 505 InitSdp(SdpMediaSection::kAudio); 506 OfferAnswer(false); 507 508 CheckOffEncodingCount(1); 509 CheckAnsEncodingCount(1); 510 511 ASSERT_NE(mOffer->ToString().find("a=rtpmap:101 telephone-event"), 512 std::string::npos); 513 ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:101 telephone-event"), 514 std::string::npos); 515 516 ASSERT_NE(mOffer->ToString().find("a=fmtp:101 0-15"), std::string::npos); 517 ASSERT_EQ(mAnswer->ToString().find("a=fmtp:101"), std::string::npos); 518 519 UniquePtr<JsepAudioCodecDescription> track; 520 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 2, 0))); 521 ASSERT_EQ("109", track->mDefaultPt); 522 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 0))); 523 ASSERT_EQ("109", track->mDefaultPt); 524 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 2, 0))); 525 ASSERT_EQ("109", track->mDefaultPt); 526 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 2, 0))); 527 ASSERT_EQ("109", track->mDefaultPt); 528 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 2, 1))); 529 ASSERT_EQ("9", track->mDefaultPt); 530 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 1))); 531 ASSERT_EQ("9", track->mDefaultPt); 532 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 2, 1))); 533 ASSERT_EQ("9", track->mDefaultPt); 534 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 2, 1))); 535 ASSERT_EQ("9", track->mDefaultPt); 536 } 537 538 TEST_F(JsepTrackTest, AudioNegotiationAnswererDtmf) { 539 InitCodecs( 540 {.offer = {.addDtmfCodec = false}, .answer = {.addDtmfCodec = true}}); 541 542 InitTracks(SdpMediaSection::kAudio); 543 InitSdp(SdpMediaSection::kAudio); 544 OfferAnswer(); 545 546 CheckOffEncodingCount(1); 547 CheckAnsEncodingCount(1); 548 549 ASSERT_EQ(mOffer->ToString().find("a=rtpmap:101 telephone-event"), 550 std::string::npos); 551 ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:101 telephone-event"), 552 std::string::npos); 553 554 ASSERT_EQ(mOffer->ToString().find("a=fmtp:101 0-15"), std::string::npos); 555 ASSERT_EQ(mAnswer->ToString().find("a=fmtp:101"), std::string::npos); 556 557 UniquePtr<JsepAudioCodecDescription> track; 558 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 2, 0))); 559 ASSERT_EQ("109", track->mDefaultPt); 560 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 2, 0))); 561 ASSERT_EQ("109", track->mDefaultPt); 562 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 2, 0))); 563 ASSERT_EQ("109", track->mDefaultPt); 564 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 2, 0))); 565 ASSERT_EQ("109", track->mDefaultPt); 566 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 2, 1))); 567 ASSERT_EQ("9", track->mDefaultPt); 568 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 2, 1))); 569 ASSERT_EQ("9", track->mDefaultPt); 570 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 2, 1))); 571 ASSERT_EQ("9", track->mDefaultPt); 572 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 2, 1))); 573 ASSERT_EQ("9", track->mDefaultPt); 574 } 575 576 TEST_F(JsepTrackTest, AudioNegotiationOffererAnswererDtmf) { 577 InitCodecs( 578 {.offer = {.addDtmfCodec = true}, .answer = {.addDtmfCodec = true}}); 579 580 InitTracks(SdpMediaSection::kAudio); 581 InitSdp(SdpMediaSection::kAudio); 582 OfferAnswer(); 583 584 CheckOffEncodingCount(1); 585 CheckAnsEncodingCount(1); 586 587 ASSERT_NE(mOffer->ToString().find("a=rtpmap:101 telephone-event"), 588 std::string::npos); 589 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:101 telephone-event"), 590 std::string::npos); 591 592 ASSERT_NE(mOffer->ToString().find("a=fmtp:101 0-15"), std::string::npos); 593 ASSERT_NE(mAnswer->ToString().find("a=fmtp:101 0-15"), std::string::npos); 594 595 UniquePtr<JsepAudioCodecDescription> track; 596 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 0))); 597 ASSERT_EQ("109", track->mDefaultPt); 598 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 0))); 599 ASSERT_EQ("109", track->mDefaultPt); 600 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 0))); 601 ASSERT_EQ("109", track->mDefaultPt); 602 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 0))); 603 ASSERT_EQ("109", track->mDefaultPt); 604 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 1))); 605 ASSERT_EQ("9", track->mDefaultPt); 606 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 1))); 607 ASSERT_EQ("9", track->mDefaultPt); 608 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 1))); 609 ASSERT_EQ("9", track->mDefaultPt); 610 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 1))); 611 ASSERT_EQ("9", track->mDefaultPt); 612 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 2))); 613 ASSERT_EQ("101", track->mDefaultPt); 614 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 2))); 615 ASSERT_EQ("101", track->mDefaultPt); 616 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 2))); 617 ASSERT_EQ("101", track->mDefaultPt); 618 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 2))); 619 ASSERT_EQ("101", track->mDefaultPt); 620 } 621 622 TEST_F(JsepTrackTest, AudioNegotiationDtmfOffererNoFmtpAnswererFmtp) { 623 InitCodecs( 624 {.offer = {.addDtmfCodec = true}, .answer = {.addDtmfCodec = true}}); 625 626 mExpectDifferingFmtp = true; 627 628 InitTracks(SdpMediaSection::kAudio); 629 InitSdp(SdpMediaSection::kAudio); 630 631 CreateOffer(); 632 GetOffer().RemoveFmtp("101"); 633 634 CreateAnswer(); 635 636 Negotiate(); 637 SanityCheck(); 638 639 CheckOffEncodingCount(1); 640 CheckAnsEncodingCount(1); 641 642 ASSERT_NE(mOffer->ToString().find("a=rtpmap:101 telephone-event"), 643 std::string::npos); 644 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:101 telephone-event"), 645 std::string::npos); 646 647 ASSERT_EQ(mOffer->ToString().find("a=fmtp:101"), std::string::npos); 648 ASSERT_NE(mAnswer->ToString().find("a=fmtp:101 0-15"), std::string::npos); 649 650 UniquePtr<JsepAudioCodecDescription> track; 651 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 0))); 652 ASSERT_EQ("109", track->mDefaultPt); 653 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 0))); 654 ASSERT_EQ("109", track->mDefaultPt); 655 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 0))); 656 ASSERT_EQ("109", track->mDefaultPt); 657 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 0))); 658 ASSERT_EQ("109", track->mDefaultPt); 659 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 1))); 660 ASSERT_EQ("9", track->mDefaultPt); 661 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 1))); 662 ASSERT_EQ("9", track->mDefaultPt); 663 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 1))); 664 ASSERT_EQ("9", track->mDefaultPt); 665 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 1))); 666 ASSERT_EQ("9", track->mDefaultPt); 667 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 2))); 668 ASSERT_EQ("101", track->mDefaultPt); 669 ASSERT_EQ("0-15", track->mSdpFmtpLine.valueOr("nothing")); 670 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 2))); 671 ASSERT_EQ("101", track->mDefaultPt); 672 ASSERT_EQ("nothing", track->mSdpFmtpLine.valueOr("nothing")); 673 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 2))); 674 ASSERT_EQ("101", track->mDefaultPt); 675 ASSERT_EQ("nothing", track->mSdpFmtpLine.valueOr("nothing")); 676 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 2))); 677 ASSERT_EQ("101", track->mDefaultPt); 678 ASSERT_EQ("0-15", track->mSdpFmtpLine.valueOr("nothing")); 679 } 680 681 TEST_F(JsepTrackTest, AudioNegotiationDtmfOffererFmtpAnswererNoFmtp) { 682 InitCodecs( 683 {.offer = {.addDtmfCodec = true}, .answer = {.addDtmfCodec = true}}); 684 685 mExpectDifferingFmtp = true; 686 687 InitTracks(SdpMediaSection::kAudio); 688 InitSdp(SdpMediaSection::kAudio); 689 690 CreateOffer(); 691 692 CreateAnswer(); 693 GetAnswer().RemoveFmtp("101"); 694 695 Negotiate(); 696 SanityCheck(); 697 698 CheckOffEncodingCount(1); 699 CheckAnsEncodingCount(1); 700 701 ASSERT_NE(mOffer->ToString().find("a=rtpmap:101 telephone-event"), 702 std::string::npos); 703 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:101 telephone-event"), 704 std::string::npos); 705 706 ASSERT_NE(mOffer->ToString().find("a=fmtp:101 0-15"), std::string::npos); 707 ASSERT_EQ(mAnswer->ToString().find("a=fmtp:101"), std::string::npos); 708 709 UniquePtr<JsepAudioCodecDescription> track; 710 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 0))); 711 ASSERT_EQ("109", track->mDefaultPt); 712 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 0))); 713 ASSERT_EQ("109", track->mDefaultPt); 714 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 0))); 715 ASSERT_EQ("109", track->mDefaultPt); 716 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 0))); 717 ASSERT_EQ("109", track->mDefaultPt); 718 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 1))); 719 ASSERT_EQ("9", track->mDefaultPt); 720 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 1))); 721 ASSERT_EQ("9", track->mDefaultPt); 722 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 1))); 723 ASSERT_EQ("9", track->mDefaultPt); 724 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 1))); 725 ASSERT_EQ("9", track->mDefaultPt); 726 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 2))); 727 ASSERT_EQ("101", track->mDefaultPt); 728 ASSERT_EQ("nothing", track->mSdpFmtpLine.valueOr("nothing")); 729 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 2))); 730 ASSERT_EQ("101", track->mDefaultPt); 731 ASSERT_EQ("0-15", track->mSdpFmtpLine.valueOr("nothing")); 732 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 2))); 733 ASSERT_EQ("101", track->mDefaultPt); 734 ASSERT_EQ("0-15", track->mSdpFmtpLine.valueOr("nothing")); 735 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 2))); 736 ASSERT_EQ("101", track->mDefaultPt); 737 ASSERT_EQ("nothing", track->mSdpFmtpLine.valueOr("nothing")); 738 } 739 740 TEST_F(JsepTrackTest, AudioNegotiationDtmfOffererNoFmtpAnswererNoFmtp) { 741 InitCodecs( 742 {.offer = {.addDtmfCodec = true}, .answer = {.addDtmfCodec = true}}); 743 744 mExpectDifferingFmtp = true; 745 746 InitTracks(SdpMediaSection::kAudio); 747 InitSdp(SdpMediaSection::kAudio); 748 749 CreateOffer(); 750 GetOffer().RemoveFmtp("101"); 751 752 CreateAnswer(); 753 GetAnswer().RemoveFmtp("101"); 754 755 Negotiate(); 756 SanityCheck(); 757 758 CheckOffEncodingCount(1); 759 CheckAnsEncodingCount(1); 760 761 ASSERT_NE(mOffer->ToString().find("a=rtpmap:101 telephone-event"), 762 std::string::npos); 763 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:101 telephone-event"), 764 std::string::npos); 765 766 ASSERT_EQ(mOffer->ToString().find("a=fmtp:101"), std::string::npos); 767 ASSERT_EQ(mAnswer->ToString().find("a=fmtp:101"), std::string::npos); 768 769 UniquePtr<JsepAudioCodecDescription> track; 770 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 0))); 771 ASSERT_EQ("109", track->mDefaultPt); 772 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 0))); 773 ASSERT_EQ("109", track->mDefaultPt); 774 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 0))); 775 ASSERT_EQ("109", track->mDefaultPt); 776 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 0))); 777 ASSERT_EQ("109", track->mDefaultPt); 778 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 1))); 779 ASSERT_EQ("9", track->mDefaultPt); 780 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 1))); 781 ASSERT_EQ("9", track->mDefaultPt); 782 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 1))); 783 ASSERT_EQ("9", track->mDefaultPt); 784 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 1))); 785 ASSERT_EQ("9", track->mDefaultPt); 786 ASSERT_TRUE((track = GetAudioCodec(mSendOff, 3, 2))); 787 ASSERT_EQ("101", track->mDefaultPt); 788 ASSERT_EQ("nothing", track->mSdpFmtpLine.valueOr("nothing")); 789 ASSERT_TRUE((track = GetAudioCodec(mRecvOff, 3, 2))); 790 ASSERT_EQ("101", track->mDefaultPt); 791 ASSERT_EQ("nothing", track->mSdpFmtpLine.valueOr("nothing")); 792 ASSERT_TRUE((track = GetAudioCodec(mSendAns, 3, 2))); 793 ASSERT_EQ("101", track->mDefaultPt); 794 ASSERT_EQ("nothing", track->mSdpFmtpLine.valueOr("nothing")); 795 ASSERT_TRUE((track = GetAudioCodec(mRecvAns, 3, 2))); 796 ASSERT_EQ("101", track->mDefaultPt); 797 ASSERT_EQ("nothing", track->mSdpFmtpLine.valueOr("nothing")); 798 } 799 800 TEST_F(JsepTrackTest, VideoNegotationOffererFEC) { 801 InitCodecs( 802 {.offer = {.addFecCodecs = true}, .answer = {.addFecCodecs = false}}); 803 804 InitTracks(SdpMediaSection::kVideo); 805 InitSdp(SdpMediaSection::kVideo); 806 OfferAnswer(false); 807 808 CheckOffEncodingCount(1); 809 CheckAnsEncodingCount(1); 810 811 ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos); 812 ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 813 ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos); 814 ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 815 816 UniquePtr<JsepVideoCodecDescription> track; 817 ASSERT_TRUE((track = GetVideoCodec(mSendOff, 3, 0))); 818 ASSERT_EQ("120", track->mDefaultPt); 819 ASSERT_TRUE((track = GetVideoCodec(mRecvOff, 5, 0))); 820 ASSERT_EQ("120", track->mDefaultPt); 821 ASSERT_TRUE((track = GetVideoCodec(mSendAns, 3, 0))); 822 ASSERT_EQ("120", track->mDefaultPt); 823 ASSERT_TRUE((track = GetVideoCodec(mRecvAns, 3, 0))); 824 ASSERT_EQ("120", track->mDefaultPt); 825 ASSERT_TRUE((track = GetVideoCodec(mSendOff, 3, 1))); 826 ASSERT_EQ("126", track->mDefaultPt); 827 ASSERT_TRUE((track = GetVideoCodec(mRecvOff, 5, 1))); 828 ASSERT_EQ("126", track->mDefaultPt); 829 ASSERT_TRUE((track = GetVideoCodec(mSendAns, 3, 1))); 830 ASSERT_EQ("126", track->mDefaultPt); 831 ASSERT_TRUE((track = GetVideoCodec(mRecvAns, 3, 1))); 832 ASSERT_EQ("126", track->mDefaultPt); 833 } 834 835 TEST_F(JsepTrackTest, VideoNegotationAnswererFEC) { 836 InitCodecs( 837 {.offer = {.addFecCodecs = false}, .answer = {.addFecCodecs = true}}); 838 839 InitTracks(SdpMediaSection::kVideo); 840 InitSdp(SdpMediaSection::kVideo); 841 OfferAnswer(); 842 843 CheckOffEncodingCount(1); 844 CheckAnsEncodingCount(1); 845 846 ASSERT_EQ(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos); 847 ASSERT_EQ(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 848 ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos); 849 ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 850 851 UniquePtr<JsepVideoCodecDescription> track; 852 ASSERT_TRUE((track = GetVideoCodec(mSendOff, 3, 0))); 853 ASSERT_EQ("120", track->mDefaultPt); 854 ASSERT_TRUE((track = GetVideoCodec(mRecvOff, 3, 0))); 855 ASSERT_EQ("120", track->mDefaultPt); 856 ASSERT_TRUE((track = GetVideoCodec(mSendAns, 3, 0))); 857 ASSERT_EQ("120", track->mDefaultPt); 858 ASSERT_TRUE((track = GetVideoCodec(mRecvAns, 3, 0))); 859 ASSERT_EQ("120", track->mDefaultPt); 860 ASSERT_TRUE((track = GetVideoCodec(mSendOff, 3, 1))); 861 ASSERT_EQ("126", track->mDefaultPt); 862 ASSERT_TRUE((track = GetVideoCodec(mRecvOff, 3, 1))); 863 ASSERT_EQ("126", track->mDefaultPt); 864 ASSERT_TRUE((track = GetVideoCodec(mSendAns, 3, 1))); 865 ASSERT_EQ("126", track->mDefaultPt); 866 ASSERT_TRUE((track = GetVideoCodec(mRecvAns, 3, 1))); 867 ASSERT_EQ("126", track->mDefaultPt); 868 } 869 870 TEST_F(JsepTrackTest, VideoNegotationOffererAnswererFEC) { 871 InitCodecs( 872 {.offer = {.addFecCodecs = true}, .answer = {.addFecCodecs = true}}); 873 874 InitTracks(SdpMediaSection::kVideo); 875 InitSdp(SdpMediaSection::kVideo); 876 OfferAnswer(); 877 878 CheckOffEncodingCount(1); 879 CheckAnsEncodingCount(1); 880 881 ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos); 882 ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 883 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos); 884 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 885 886 UniquePtr<JsepVideoCodecDescription> track; 887 ASSERT_TRUE((track = GetVideoCodec(mSendOff, 5))); 888 ASSERT_EQ("120", track->mDefaultPt); 889 ASSERT_TRUE((track = GetVideoCodec(mRecvOff, 5))); 890 ASSERT_EQ("120", track->mDefaultPt); 891 ASSERT_TRUE((track = GetVideoCodec(mSendAns, 5))); 892 ASSERT_EQ("120", track->mDefaultPt); 893 ASSERT_TRUE((track = GetVideoCodec(mRecvAns, 5))); 894 ASSERT_EQ("120", track->mDefaultPt); 895 } 896 897 TEST_F(JsepTrackTest, VideoNegotationOffererAnswererFECPreferred) { 898 InitCodecs({.offer = {.addFecCodecs = true, .preferRed = true}, 899 .answer = {.addFecCodecs = true}}); 900 901 InitTracks(SdpMediaSection::kVideo); 902 InitSdp(SdpMediaSection::kVideo); 903 OfferAnswer(); 904 905 CheckOffEncodingCount(1); 906 CheckAnsEncodingCount(1); 907 908 ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos); 909 ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 910 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos); 911 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 912 913 UniquePtr<JsepVideoCodecDescription> track; 914 // We should have 4 codecs, the first of which is VP8, because having a 915 // pseudo codec come first is silly. 916 ASSERT_TRUE((track = GetVideoCodec(mSendOff, 5))); 917 ASSERT_EQ("120", track->mDefaultPt); 918 ASSERT_TRUE((track = GetVideoCodec(mRecvOff, 5))); 919 ASSERT_EQ("120", track->mDefaultPt); 920 ASSERT_TRUE((track = GetVideoCodec(mSendAns, 5))); 921 ASSERT_EQ("120", track->mDefaultPt); 922 ASSERT_TRUE((track = GetVideoCodec(mRecvAns, 5))); 923 ASSERT_EQ("120", track->mDefaultPt); 924 } 925 926 // Make sure we only put the right things in the fmtp:122 120/.... line 927 TEST_F(JsepTrackTest, VideoNegotationOffererAnswererFECMismatch) { 928 InitCodecs({.offer = {.addFecCodecs = true, .preferRed = true}, 929 .answer = {.addFecCodecs = true}}); 930 // remove h264 & AV1 from answer codecs 931 ASSERT_EQ("H264", mAnsCodecs[3]->mName); 932 ASSERT_EQ("AV1", mAnsCodecs[4]->mName); 933 mAnsCodecs.erase(mAnsCodecs.begin() + 4); 934 mAnsCodecs.erase(mAnsCodecs.begin() + 3); 935 936 InitTracks(SdpMediaSection::kVideo); 937 InitSdp(SdpMediaSection::kVideo); 938 OfferAnswer(false); 939 940 CheckOffEncodingCount(1); 941 CheckAnsEncodingCount(1); 942 943 ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos); 944 ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 945 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos); 946 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 947 948 // We should have 3 codecs, the first of which is VP8, because having a 949 // pseudo codec come first is silly. 950 UniquePtr<JsepVideoCodecDescription> track; 951 ASSERT_TRUE((track = GetVideoCodec(mSendOff, 3))); 952 ASSERT_EQ("120", track->mDefaultPt); 953 ASSERT_TRUE((track = GetVideoCodec(mRecvOff, 5))); 954 ASSERT_EQ("120", track->mDefaultPt); 955 ASSERT_TRUE((track = GetVideoCodec(mSendAns, 3))); 956 ASSERT_EQ("120", track->mDefaultPt); 957 ASSERT_TRUE((track = GetVideoCodec(mRecvAns, 3))); 958 ASSERT_EQ("120", track->mDefaultPt); 959 } 960 961 TEST_F(JsepTrackTest, VideoNegotationOffererAnswererFECZeroVP9Codec) { 962 MockJsepCodecPreferences prefs; 963 mOffCodecs = MakeCodecs({.addFecCodecs = true}); 964 auto vp9 = JsepVideoCodecDescription::CreateDefaultVP9(prefs); 965 vp9->mDefaultPt = "0"; 966 mOffCodecs.push_back(std::move(vp9)); 967 968 ASSERT_EQ(9U, mOffCodecs.size()); 969 JsepVideoCodecDescription& red = 970 static_cast<JsepVideoCodecDescription&>(*mOffCodecs[5]); 971 ASSERT_EQ("red", red.mName); 972 973 mAnsCodecs = MakeCodecs({.addFecCodecs = true}); 974 975 InitTracks(SdpMediaSection::kVideo); 976 InitSdp(SdpMediaSection::kVideo); 977 OfferAnswer(); 978 979 CheckOffEncodingCount(1); 980 CheckAnsEncodingCount(1); 981 982 ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos); 983 ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 984 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos); 985 ASSERT_NE(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos); 986 } 987 988 TEST_F(JsepTrackTest, VideoNegotiationOfferRemb) { 989 // enable remb on the offer codecs 990 InitCodecs({.offer = {.enableRemb = true, .enableTransportCC = false}, 991 .answer = {.enableRemb = false, .enableTransportCC = false}}); 992 InitTracks(SdpMediaSection::kVideo); 993 InitSdp(SdpMediaSection::kVideo); 994 OfferAnswer(); 995 996 // make sure REMB is on offer and not on answer 997 ASSERT_NE(mOffer->ToString().find("a=rtcp-fb:120 goog-remb"), 998 std::string::npos); 999 ASSERT_EQ(mAnswer->ToString().find("a=rtcp-fb:120 goog-remb"), 1000 std::string::npos); 1001 CheckOffEncodingCount(1); 1002 CheckAnsEncodingCount(1); 1003 1004 UniquePtr<JsepVideoCodecDescription> codec; 1005 ASSERT_TRUE((codec = GetVideoCodec(mSendOff, 3, 0))); 1006 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1007 1008 ASSERT_TRUE((codec = GetVideoCodec(mRecvAns, 3, 0))); 1009 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1010 ASSERT_TRUE((codec = GetVideoCodec(mSendAns, 3, 0))); 1011 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1012 ASSERT_TRUE((codec = GetVideoCodec(mRecvOff, 3, 0))); 1013 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1014 } 1015 1016 TEST_F(JsepTrackTest, VideoNegotiationAnswerRemb) { 1017 InitCodecs({.offer = {.enableRemb = false, .enableTransportCC = false}, 1018 .answer = {.enableRemb = true, .enableTransportCC = false}}); 1019 // enable remb on the answer codecs 1020 ((JsepVideoCodecDescription&)*mAnsCodecs[2]).EnableRemb(); 1021 InitTracks(SdpMediaSection::kVideo); 1022 InitSdp(SdpMediaSection::kVideo); 1023 OfferAnswer(); 1024 1025 // make sure REMB is not on offer and not on answer 1026 ASSERT_EQ(mOffer->ToString().find("a=rtcp-fb:120 goog-remb"), 1027 std::string::npos); 1028 ASSERT_EQ(mAnswer->ToString().find("a=rtcp-fb:120 goog-remb"), 1029 std::string::npos); 1030 CheckOffEncodingCount(1); 1031 CheckAnsEncodingCount(1); 1032 1033 UniquePtr<JsepVideoCodecDescription> codec; 1034 ASSERT_TRUE((codec = GetVideoCodec(mSendOff, 3, 0))); 1035 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1036 ASSERT_TRUE((codec = GetVideoCodec(mRecvAns, 3, 0))); 1037 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1038 ASSERT_TRUE((codec = GetVideoCodec(mSendAns, 3, 0))); 1039 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1040 ASSERT_TRUE((codec = GetVideoCodec(mRecvOff, 3, 0))); 1041 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1042 } 1043 1044 TEST_F(JsepTrackTest, VideoNegotiationOfferAnswerRemb) { 1045 InitCodecs({.offer = {.enableRemb = true, .enableTransportCC = false}, 1046 .answer = {.enableRemb = true, .enableTransportCC = false}}); 1047 // enable remb on the offer and answer codecs 1048 ((JsepVideoCodecDescription&)*mOffCodecs[2]).EnableRemb(); 1049 ((JsepVideoCodecDescription&)*mAnsCodecs[2]).EnableRemb(); 1050 InitTracks(SdpMediaSection::kVideo); 1051 InitSdp(SdpMediaSection::kVideo); 1052 OfferAnswer(); 1053 1054 // make sure REMB is on offer and on answer 1055 ASSERT_NE(mOffer->ToString().find("a=rtcp-fb:120 goog-remb"), 1056 std::string::npos); 1057 ASSERT_NE(mAnswer->ToString().find("a=rtcp-fb:120 goog-remb"), 1058 std::string::npos); 1059 CheckOffEncodingCount(1); 1060 CheckAnsEncodingCount(1); 1061 1062 UniquePtr<JsepVideoCodecDescription> codec; 1063 ASSERT_TRUE((codec = GetVideoCodec(mSendOff, 3, 0))); 1064 ASSERT_EQ(codec->mOtherFbTypes.size(), 1U); 1065 CheckOtherFbExists(*codec, SdpRtcpFbAttributeList::kRemb); 1066 ASSERT_TRUE((codec = GetVideoCodec(mRecvAns, 3, 0))); 1067 ASSERT_EQ(codec->mOtherFbTypes.size(), 1U); 1068 CheckOtherFbExists(*codec, SdpRtcpFbAttributeList::kRemb); 1069 ASSERT_TRUE((codec = GetVideoCodec(mSendAns, 3, 0))); 1070 ASSERT_EQ(codec->mOtherFbTypes.size(), 1U); 1071 CheckOtherFbExists(*codec, SdpRtcpFbAttributeList::kRemb); 1072 ASSERT_TRUE((codec = GetVideoCodec(mRecvOff, 3, 0))); 1073 ASSERT_EQ(codec->mOtherFbTypes.size(), 1U); 1074 CheckOtherFbExists(*codec, SdpRtcpFbAttributeList::kRemb); 1075 } 1076 1077 TEST_F(JsepTrackTest, VideoNegotiationOfferTransportCC) { 1078 InitCodecs({.offer = {.enableRemb = false, .enableTransportCC = true}, 1079 .answer = {.enableRemb = false, .enableTransportCC = false}}); 1080 // enable TransportCC on the offer codecs 1081 ((JsepVideoCodecDescription&)*mOffCodecs[2]).EnableTransportCC(); 1082 InitTracks(SdpMediaSection::kVideo); 1083 InitSdp(SdpMediaSection::kVideo); 1084 OfferAnswer(); 1085 1086 // make sure TransportCC is on offer and not on answer 1087 ASSERT_NE(mOffer->ToString().find("a=rtcp-fb:120 transport-cc"), 1088 std::string::npos); 1089 ASSERT_EQ(mAnswer->ToString().find("a=rtcp-fb:120 transport-cc"), 1090 std::string::npos); 1091 CheckOffEncodingCount(1); 1092 CheckAnsEncodingCount(1); 1093 1094 UniquePtr<JsepVideoCodecDescription> codec; 1095 ASSERT_TRUE((codec = GetVideoCodec(mSendOff, 3, 0))); 1096 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1097 ASSERT_TRUE((codec = GetVideoCodec(mRecvAns, 3, 0))); 1098 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1099 ASSERT_TRUE((codec = GetVideoCodec(mSendAns, 3, 0))); 1100 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1101 ASSERT_TRUE((codec = GetVideoCodec(mRecvOff, 3, 0))); 1102 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1103 } 1104 1105 TEST_F(JsepTrackTest, VideoNegotiationAnswerTransportCC) { 1106 InitCodecs({.offer = {.enableRemb = false, .enableTransportCC = false}, 1107 .answer = {.enableRemb = false, .enableTransportCC = true}}); 1108 // enable TransportCC on the answer codecs 1109 ((JsepVideoCodecDescription&)*mAnsCodecs[2]).EnableTransportCC(); 1110 InitTracks(SdpMediaSection::kVideo); 1111 InitSdp(SdpMediaSection::kVideo); 1112 OfferAnswer(); 1113 1114 // make sure TransportCC is not on offer and not on answer 1115 ASSERT_EQ(mOffer->ToString().find("a=rtcp-fb:120 transport-cc"), 1116 std::string::npos); 1117 ASSERT_EQ(mAnswer->ToString().find("a=rtcp-fb:120 transport-cc"), 1118 std::string::npos); 1119 CheckOffEncodingCount(1); 1120 CheckAnsEncodingCount(1); 1121 1122 UniquePtr<JsepVideoCodecDescription> codec; 1123 ASSERT_TRUE((codec = GetVideoCodec(mSendOff, 3, 0))); 1124 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1125 ASSERT_TRUE((codec = GetVideoCodec(mRecvAns, 3, 0))); 1126 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1127 ASSERT_TRUE((codec = GetVideoCodec(mSendAns, 3, 0))); 1128 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1129 ASSERT_TRUE((codec = GetVideoCodec(mRecvOff, 3, 0))); 1130 ASSERT_EQ(codec->mOtherFbTypes.size(), 0U); 1131 } 1132 1133 TEST_F(JsepTrackTest, VideoNegotiationOfferAnswerTransportCC) { 1134 InitCodecs({.enableRemb = false, .enableTransportCC = true}); 1135 // enable TransportCC on the offer and answer codecs 1136 ((JsepVideoCodecDescription&)*mOffCodecs[2]).EnableTransportCC(); 1137 ((JsepVideoCodecDescription&)*mAnsCodecs[2]).EnableTransportCC(); 1138 InitTracks(SdpMediaSection::kVideo); 1139 InitSdp(SdpMediaSection::kVideo); 1140 OfferAnswer(); 1141 1142 // make sure TransportCC is on offer and on answer 1143 ASSERT_NE(mOffer->ToString().find("a=rtcp-fb:120 transport-cc"), 1144 std::string::npos); 1145 ASSERT_NE(mAnswer->ToString().find("a=rtcp-fb:120 transport-cc"), 1146 std::string::npos); 1147 CheckOffEncodingCount(1); 1148 CheckAnsEncodingCount(1); 1149 1150 UniquePtr<JsepVideoCodecDescription> codec; 1151 ASSERT_TRUE((codec = GetVideoCodec(mSendOff, 3, 0))); 1152 ASSERT_EQ(codec->mOtherFbTypes.size(), 1U); 1153 CheckOtherFbExists(*codec, SdpRtcpFbAttributeList::kTransportCC); 1154 ASSERT_TRUE((codec = GetVideoCodec(mRecvAns, 3, 0))); 1155 ASSERT_EQ(codec->mOtherFbTypes.size(), 1U); 1156 CheckOtherFbExists(*codec, SdpRtcpFbAttributeList::kTransportCC); 1157 ASSERT_TRUE((codec = GetVideoCodec(mSendAns, 3, 0))); 1158 ASSERT_EQ(codec->mOtherFbTypes.size(), 1U); 1159 CheckOtherFbExists(*codec, SdpRtcpFbAttributeList::kTransportCC); 1160 ASSERT_TRUE((codec = GetVideoCodec(mRecvOff, 3, 0))); 1161 ASSERT_EQ(codec->mOtherFbTypes.size(), 1U); 1162 CheckOtherFbExists(*codec, SdpRtcpFbAttributeList::kTransportCC); 1163 } 1164 1165 TEST_F(JsepTrackTest, AudioOffSendonlyAnsRecvonly) { 1166 Init(SdpMediaSection::kAudio); 1167 GetOffer().SetDirection(SdpDirectionAttribute::kSendonly); 1168 GetAnswer().SetDirection(SdpDirectionAttribute::kRecvonly); 1169 OfferAnswer(); 1170 CheckOffEncodingCount(1); 1171 CheckAnsEncodingCount(0); 1172 } 1173 1174 TEST_F(JsepTrackTest, VideoOffSendonlyAnsRecvonly) { 1175 Init(SdpMediaSection::kVideo); 1176 GetOffer().SetDirection(SdpDirectionAttribute::kSendonly); 1177 GetAnswer().SetDirection(SdpDirectionAttribute::kRecvonly); 1178 OfferAnswer(); 1179 CheckOffEncodingCount(1); 1180 CheckAnsEncodingCount(0); 1181 } 1182 1183 TEST_F(JsepTrackTest, AudioOffSendrecvAnsRecvonly) { 1184 Init(SdpMediaSection::kAudio); 1185 GetAnswer().SetDirection(SdpDirectionAttribute::kRecvonly); 1186 OfferAnswer(); 1187 CheckOffEncodingCount(1); 1188 CheckAnsEncodingCount(0); 1189 } 1190 1191 TEST_F(JsepTrackTest, VideoOffSendrecvAnsRecvonly) { 1192 Init(SdpMediaSection::kVideo); 1193 GetAnswer().SetDirection(SdpDirectionAttribute::kRecvonly); 1194 OfferAnswer(); 1195 CheckOffEncodingCount(1); 1196 CheckAnsEncodingCount(0); 1197 } 1198 1199 TEST_F(JsepTrackTest, AudioOffRecvonlyAnsSendonly) { 1200 Init(SdpMediaSection::kAudio); 1201 GetOffer().SetDirection(SdpDirectionAttribute::kRecvonly); 1202 GetAnswer().SetDirection(SdpDirectionAttribute::kSendonly); 1203 OfferAnswer(); 1204 CheckOffEncodingCount(0); 1205 CheckAnsEncodingCount(1); 1206 } 1207 1208 TEST_F(JsepTrackTest, VideoOffRecvonlyAnsSendonly) { 1209 Init(SdpMediaSection::kVideo); 1210 GetOffer().SetDirection(SdpDirectionAttribute::kRecvonly); 1211 GetAnswer().SetDirection(SdpDirectionAttribute::kSendonly); 1212 OfferAnswer(); 1213 CheckOffEncodingCount(0); 1214 CheckAnsEncodingCount(1); 1215 } 1216 1217 TEST_F(JsepTrackTest, AudioOffSendrecvAnsSendonly) { 1218 Init(SdpMediaSection::kAudio); 1219 GetAnswer().SetDirection(SdpDirectionAttribute::kSendonly); 1220 OfferAnswer(); 1221 CheckOffEncodingCount(0); 1222 CheckAnsEncodingCount(1); 1223 } 1224 1225 TEST_F(JsepTrackTest, VideoOffSendrecvAnsSendonly) { 1226 Init(SdpMediaSection::kVideo); 1227 GetAnswer().SetDirection(SdpDirectionAttribute::kSendonly); 1228 OfferAnswer(); 1229 CheckOffEncodingCount(0); 1230 CheckAnsEncodingCount(1); 1231 } 1232 1233 TEST_F(JsepTrackTest, DataChannelDraft05) { 1234 InitCodecs(CodecOverrides{}); 1235 InitTracks(SdpMediaSection::kApplication); 1236 1237 mOffer.reset(new SipccSdp(SdpOrigin("", 0, 0, sdp::kIPv4, ""))); 1238 mOffer->AddMediaSection(SdpMediaSection::kApplication, 1239 SdpDirectionAttribute::kSendrecv, 0, 1240 SdpMediaSection::kDtlsSctp, sdp::kIPv4, "0.0.0.0"); 1241 mAnswer.reset(new SipccSdp(SdpOrigin("", 0, 0, sdp::kIPv4, ""))); 1242 mAnswer->AddMediaSection(SdpMediaSection::kApplication, 1243 SdpDirectionAttribute::kSendrecv, 0, 1244 SdpMediaSection::kDtlsSctp, sdp::kIPv4, "0.0.0.0"); 1245 1246 OfferAnswer(); 1247 CheckOffEncodingCount(1); 1248 CheckAnsEncodingCount(1); 1249 1250 ASSERT_NE(std::string::npos, 1251 mOffer->ToString().find("a=sctpmap:5999 webrtc-datachannel 256")); 1252 ASSERT_NE(std::string::npos, 1253 mAnswer->ToString().find("a=sctpmap:5999 webrtc-datachannel 256")); 1254 // Note: this is testing for a workaround, see bug 1335262 for details 1255 ASSERT_NE(std::string::npos, 1256 mOffer->ToString().find("a=max-message-size:499")); 1257 ASSERT_NE(std::string::npos, 1258 mAnswer->ToString().find("a=max-message-size:499")); 1259 ASSERT_EQ(std::string::npos, mOffer->ToString().find("a=sctp-port")); 1260 ASSERT_EQ(std::string::npos, mAnswer->ToString().find("a=sctp-port")); 1261 } 1262 1263 TEST_F(JsepTrackTest, DataChannelDraft21) { 1264 Init(SdpMediaSection::kApplication); 1265 OfferAnswer(); 1266 CheckOffEncodingCount(1); 1267 CheckAnsEncodingCount(1); 1268 1269 ASSERT_NE(std::string::npos, mOffer->ToString().find("a=sctp-port:5999")); 1270 ASSERT_NE(std::string::npos, mAnswer->ToString().find("a=sctp-port:5999")); 1271 ASSERT_NE(std::string::npos, 1272 mOffer->ToString().find("a=max-message-size:499")); 1273 ASSERT_NE(std::string::npos, 1274 mAnswer->ToString().find("a=max-message-size:499")); 1275 ASSERT_EQ(std::string::npos, mOffer->ToString().find("a=sctpmap")); 1276 ASSERT_EQ(std::string::npos, mAnswer->ToString().find("a=sctpmap")); 1277 } 1278 1279 TEST_F(JsepTrackTest, DataChannelDraft21AnswerWithDifferentPort) { 1280 InitCodecs(CodecOverrides{}); 1281 1282 mOffCodecs.pop_back(); 1283 mOffCodecs.emplace_back(new JsepApplicationCodecDescription( 1284 "webrtc-datachannel", 256, 4555, 10544)); 1285 1286 InitTracks(SdpMediaSection::kApplication); 1287 InitSdp(SdpMediaSection::kApplication); 1288 1289 OfferAnswer(); 1290 CheckOffEncodingCount(1); 1291 CheckAnsEncodingCount(1); 1292 1293 ASSERT_NE(std::string::npos, mOffer->ToString().find("a=sctp-port:4555")); 1294 ASSERT_NE(std::string::npos, mAnswer->ToString().find("a=sctp-port:5999")); 1295 ASSERT_NE(std::string::npos, 1296 mOffer->ToString().find("a=max-message-size:10544")); 1297 ASSERT_NE(std::string::npos, 1298 mAnswer->ToString().find("a=max-message-size:499")); 1299 ASSERT_EQ(std::string::npos, mOffer->ToString().find("a=sctpmap")); 1300 ASSERT_EQ(std::string::npos, mAnswer->ToString().find("a=sctpmap")); 1301 } 1302 1303 TEST_F(JsepTrackTest, SimulcastRejected) { 1304 Init(SdpMediaSection::kVideo); 1305 std::vector<std::string> rids; 1306 rids.push_back("foo"); 1307 rids.push_back("bar"); 1308 mSendOff.SetRids(rids); 1309 OfferAnswer(); 1310 CheckOffEncodingCount(1); 1311 CheckAnsEncodingCount(1); 1312 } 1313 1314 TEST_F(JsepTrackTest, SimulcastPrevented) { 1315 Init(SdpMediaSection::kVideo); 1316 std::vector<std::string> rids; 1317 rids.push_back("foo"); 1318 rids.push_back("bar"); 1319 mSendAns.SetRids(rids); 1320 OfferAnswer(); 1321 CheckOffEncodingCount(1); 1322 CheckAnsEncodingCount(1); 1323 } 1324 1325 TEST_F(JsepTrackTest, SimulcastOfferer) { 1326 Init(SdpMediaSection::kVideo); 1327 std::vector<std::string> rids; 1328 rids.push_back("foo"); 1329 rids.push_back("bar"); 1330 mSendOff.SetRids(rids); 1331 CreateOffer(); 1332 CreateAnswer(); 1333 // Add simulcast/rid to answer 1334 mRecvAns.AddToMsection(rids, sdp::kRecv, mSsrcGenerator, false, &GetAnswer()); 1335 Negotiate(); 1336 ASSERT_TRUE(mSendOff.GetNegotiatedDetails()); 1337 ASSERT_EQ(2U, mSendOff.GetNegotiatedDetails()->GetEncodingCount()); 1338 ASSERT_EQ("foo", mSendOff.GetNegotiatedDetails()->GetEncoding(0).mRid); 1339 ASSERT_EQ("bar", mSendOff.GetNegotiatedDetails()->GetEncoding(1).mRid); 1340 ASSERT_NE(std::string::npos, 1341 mOffer->ToString().find("a=simulcast:send foo;bar")); 1342 ASSERT_NE(std::string::npos, 1343 mAnswer->ToString().find("a=simulcast:recv foo;bar")); 1344 ASSERT_NE(std::string::npos, mOffer->ToString().find("a=rid:foo send")); 1345 ASSERT_NE(std::string::npos, mOffer->ToString().find("a=rid:bar send")); 1346 ASSERT_NE(std::string::npos, mAnswer->ToString().find("a=rid:foo recv")); 1347 ASSERT_NE(std::string::npos, mAnswer->ToString().find("a=rid:bar recv")); 1348 } 1349 1350 TEST_F(JsepTrackTest, SimulcastOffererWithRtx) { 1351 Init(SdpMediaSection::kVideo); 1352 std::vector<std::string> rids; 1353 rids.push_back("foo"); 1354 rids.push_back("bar"); 1355 rids.push_back("pop"); 1356 mSendOff.SetRids(rids); 1357 mSendOff.AddToMsection(rids, sdp::kSend, mSsrcGenerator, true, &GetOffer()); 1358 mRecvOff.AddToMsection(rids, sdp::kSend, mSsrcGenerator, true, &GetOffer()); 1359 CreateAnswer(); 1360 // Add simulcast/rid to answer 1361 mRecvAns.AddToMsection(rids, sdp::kRecv, mSsrcGenerator, false, &GetAnswer()); 1362 Negotiate(); 1363 1364 ASSERT_EQ(3U, mSendOff.GetSsrcs().size()); 1365 const auto posSsrc0 = 1366 mOffer->ToString().find(std::to_string(mSendOff.GetSsrcs()[0])); 1367 const auto posSsrc1 = 1368 mOffer->ToString().find(std::to_string(mSendOff.GetSsrcs()[1])); 1369 const auto posSsrc2 = 1370 mOffer->ToString().find(std::to_string(mSendOff.GetSsrcs()[2])); 1371 ASSERT_NE(std::string::npos, posSsrc0); 1372 ASSERT_NE(std::string::npos, posSsrc1); 1373 ASSERT_NE(std::string::npos, posSsrc2); 1374 ASSERT_GT(posSsrc1, posSsrc0); 1375 ASSERT_GT(posSsrc2, posSsrc0); 1376 ASSERT_GT(posSsrc2, posSsrc1); 1377 1378 ASSERT_EQ(3U, mSendOff.GetRtxSsrcs().size()); 1379 const auto posRtxSsrc0 = 1380 mOffer->ToString().find(std::to_string(mSendOff.GetRtxSsrcs()[0])); 1381 const auto posRtxSsrc1 = 1382 mOffer->ToString().find(std::to_string(mSendOff.GetRtxSsrcs()[1])); 1383 const auto posRtxSsrc2 = 1384 mOffer->ToString().find(std::to_string(mSendOff.GetRtxSsrcs()[2])); 1385 ASSERT_NE(std::string::npos, posRtxSsrc0); 1386 ASSERT_NE(std::string::npos, posRtxSsrc1); 1387 ASSERT_NE(std::string::npos, posRtxSsrc2); 1388 ASSERT_GT(posRtxSsrc1, posRtxSsrc0); 1389 ASSERT_GT(posRtxSsrc2, posRtxSsrc0); 1390 ASSERT_GT(posRtxSsrc2, posRtxSsrc1); 1391 } 1392 1393 TEST_F(JsepTrackTest, SimulcastAnswerer) { 1394 Init(SdpMediaSection::kVideo); 1395 std::vector<std::string> rids; 1396 rids.push_back("foo"); 1397 rids.push_back("bar"); 1398 mSendAns.SetRids(rids); 1399 CreateOffer(); 1400 // Add simulcast/rid to offer 1401 mRecvOff.AddToMsection(rids, sdp::kRecv, mSsrcGenerator, false, &GetOffer()); 1402 CreateAnswer(); 1403 Negotiate(); 1404 ASSERT_TRUE(mSendAns.GetNegotiatedDetails()); 1405 ASSERT_EQ(2U, mSendAns.GetNegotiatedDetails()->GetEncodingCount()); 1406 ASSERT_EQ("foo", mSendAns.GetNegotiatedDetails()->GetEncoding(0).mRid); 1407 ASSERT_EQ("bar", mSendAns.GetNegotiatedDetails()->GetEncoding(1).mRid); 1408 ASSERT_NE(std::string::npos, 1409 mOffer->ToString().find("a=simulcast:recv foo;bar")); 1410 ASSERT_NE(std::string::npos, 1411 mAnswer->ToString().find("a=simulcast:send foo;bar")); 1412 ASSERT_NE(std::string::npos, mOffer->ToString().find("a=rid:foo recv")); 1413 ASSERT_NE(std::string::npos, mOffer->ToString().find("a=rid:bar recv")); 1414 ASSERT_NE(std::string::npos, mAnswer->ToString().find("a=rid:foo send")); 1415 ASSERT_NE(std::string::npos, mAnswer->ToString().find("a=rid:bar send")); 1416 } 1417 1418 #define VERIFY_OPUS_MAX_PLAYBACK_RATE(track, expectedRate) \ 1419 { \ 1420 JsepTrack& copy(track); \ 1421 ASSERT_TRUE(copy.GetNegotiatedDetails()); \ 1422 ASSERT_TRUE(copy.GetNegotiatedDetails()->GetEncodingCount()); \ 1423 for (const auto& codec : \ 1424 copy.GetNegotiatedDetails()->GetEncoding(0).GetCodecs()) { \ 1425 if (codec->mName == "opus") { \ 1426 JsepAudioCodecDescription& audioCodec = \ 1427 static_cast<JsepAudioCodecDescription&>(*codec); \ 1428 ASSERT_EQ((expectedRate), audioCodec.mMaxPlaybackRate); \ 1429 } \ 1430 }; \ 1431 } 1432 1433 #define VERIFY_OPUS_FORCE_MONO(track, expected) \ 1434 { \ 1435 JsepTrack& copy(track); \ 1436 ASSERT_TRUE(copy.GetNegotiatedDetails()); \ 1437 ASSERT_TRUE(copy.GetNegotiatedDetails()->GetEncodingCount()); \ 1438 for (const auto& codec : \ 1439 copy.GetNegotiatedDetails()->GetEncoding(0).GetCodecs()) { \ 1440 if (codec->mName == "opus") { \ 1441 JsepAudioCodecDescription& audioCodec = \ 1442 static_cast<JsepAudioCodecDescription&>(*codec); \ 1443 /* gtest has some compiler warnings when using ASSERT_EQ with \ 1444 * booleans. */ \ 1445 ASSERT_EQ((int)(expected), (int)audioCodec.mForceMono); \ 1446 } \ 1447 }; \ 1448 } 1449 1450 TEST_F(JsepTrackTest, DefaultOpusParameters) { 1451 Init(SdpMediaSection::kAudio); 1452 OfferAnswer(); 1453 1454 VERIFY_OPUS_MAX_PLAYBACK_RATE( 1455 mSendOff, SdpFmtpAttributeList::OpusParameters::kDefaultMaxPlaybackRate); 1456 VERIFY_OPUS_MAX_PLAYBACK_RATE( 1457 mSendAns, SdpFmtpAttributeList::OpusParameters::kDefaultMaxPlaybackRate); 1458 VERIFY_OPUS_MAX_PLAYBACK_RATE(mRecvOff, 0U); 1459 VERIFY_OPUS_FORCE_MONO(mRecvOff, false); 1460 VERIFY_OPUS_MAX_PLAYBACK_RATE(mRecvAns, 0U); 1461 VERIFY_OPUS_FORCE_MONO(mRecvAns, false); 1462 } 1463 1464 TEST_F(JsepTrackTest, NonDefaultOpusParameters) { 1465 InitCodecs(CodecOverrides{}); 1466 for (auto& codec : mAnsCodecs) { 1467 if (codec->mName == "opus") { 1468 JsepAudioCodecDescription* audioCodec = 1469 static_cast<JsepAudioCodecDescription*>(codec.get()); 1470 audioCodec->mMaxPlaybackRate = 16000; 1471 audioCodec->mForceMono = true; 1472 } 1473 } 1474 InitTracks(SdpMediaSection::kAudio); 1475 InitSdp(SdpMediaSection::kAudio); 1476 OfferAnswer(); 1477 1478 VERIFY_OPUS_MAX_PLAYBACK_RATE(mSendOff, 16000U); 1479 VERIFY_OPUS_FORCE_MONO(mSendOff, true); 1480 VERIFY_OPUS_MAX_PLAYBACK_RATE( 1481 mSendAns, SdpFmtpAttributeList::OpusParameters::kDefaultMaxPlaybackRate); 1482 VERIFY_OPUS_FORCE_MONO(mSendAns, false); 1483 VERIFY_OPUS_MAX_PLAYBACK_RATE(mRecvOff, 0U); 1484 VERIFY_OPUS_FORCE_MONO(mRecvOff, false); 1485 VERIFY_OPUS_MAX_PLAYBACK_RATE(mRecvAns, 16000U); 1486 VERIFY_OPUS_FORCE_MONO(mRecvAns, true); 1487 } 1488 1489 TEST_F(JsepTrackTest, RtcpFbWithPayloadTypeAsymmetry) { 1490 std::vector<std::string> expectedAckFbTypes; 1491 std::vector<std::string> expectedNackFbTypes{"", "pli"}; 1492 std::vector<std::string> expectedCcmFbTypes{"fir"}; 1493 std::vector<SdpRtcpFbAttributeList::Feedback> expectedOtherFbTypes{ 1494 {"", SdpRtcpFbAttributeList::kRemb, "", ""}, 1495 {"", SdpRtcpFbAttributeList::kTransportCC, "", ""}}; 1496 1497 InitCodecs(CodecOverrides{}); 1498 1499 // On offerer, configure to support remb and transport-cc on video codecs 1500 for (auto& codec : mOffCodecs) { 1501 if (codec->Type() == SdpMediaSection::kVideo) { 1502 auto& videoCodec = static_cast<JsepVideoCodecDescription&>(*codec); 1503 videoCodec.EnableRemb(); 1504 videoCodec.EnableTransportCC(); 1505 } 1506 } 1507 1508 InitTracks(SdpMediaSection::kVideo); 1509 InitSdp(SdpMediaSection::kVideo); 1510 1511 CreateOffer(); 1512 // We do not bother trying to bamboozle the answerer into doing asymmetric 1513 // payload types, we just use a raw SDP. 1514 const std::string answer = 1515 "v=0\r\n" 1516 "o=- 0 0 IN IP4 127.0.0.1\r\n" 1517 "s=-\r\n" 1518 "t=0 0\r\n" 1519 "a=msid-semantic:WMS *\r\n" 1520 "m=video 0 UDP/TLS/RTP/SAVPF 136\r\n" 1521 "c=IN IP4 0.0.0.0\r\n" 1522 "a=sendrecv\r\n" 1523 "a=fmtp:136 " 1524 "profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=" 1525 "1\r\n" 1526 "a=msid:stream_id\r\n" 1527 "a=rtcp-fb:136 nack\r\n" 1528 "a=rtcp-fb:136 nack pli\r\n" 1529 "a=rtcp-fb:136 ccm fir\r\n" 1530 "a=rtcp-fb:136 goog-remb\r\n" 1531 "a=rtcp-fb:136 transport-cc\r\n" 1532 "a=rtpmap:136 H264/90000\r\n" 1533 "a=ssrc:2025549043 cname:\r\n"; 1534 1535 UniquePtr<SdpParser> parser(new SipccSdpParser); 1536 mAnswer = std::move(parser->Parse(answer)->Sdp()); 1537 ASSERT_TRUE(mAnswer); 1538 1539 mRecvOff.RecvTrackSetRemote(*mAnswer, GetAnswer()); 1540 mRecvOff.Negotiate(GetAnswer(), GetAnswer(), GetOffer()); 1541 mSendOff.Negotiate(GetAnswer(), GetAnswer(), GetOffer()); 1542 1543 ASSERT_TRUE(mSendOff.GetNegotiatedDetails()); 1544 ASSERT_TRUE(mRecvOff.GetNegotiatedDetails()); 1545 1546 UniquePtr<JsepVideoCodecDescription> codec; 1547 ASSERT_TRUE((codec = GetVideoCodec(mSendOff))); 1548 ASSERT_EQ("136", codec->mDefaultPt) 1549 << "Offerer should have seen answer asymmetry!"; 1550 ASSERT_TRUE((codec = GetVideoCodec(mRecvOff, 3, 0))); 1551 ASSERT_EQ("126", codec->mDefaultPt); 1552 ASSERT_EQ(expectedAckFbTypes, codec->mAckFbTypes); 1553 ASSERT_EQ(expectedNackFbTypes, codec->mNackFbTypes); 1554 ASSERT_EQ(expectedCcmFbTypes, codec->mCcmFbTypes); 1555 ASSERT_EQ(expectedOtherFbTypes, codec->mOtherFbTypes); 1556 } 1557 1558 TEST_F(JsepTrackTest, AudioSdpFmtpLine) { 1559 mOffCodecs = MakeCodecs( 1560 {.addFecCodecs = true, .preferRed = true, .addDtmfCodec = true}); 1561 mAnsCodecs = MakeCodecs( 1562 {.addFecCodecs = true, .preferRed = true, .addDtmfCodec = true}); 1563 InitTracks(SdpMediaSection::kAudio); 1564 InitSdp(SdpMediaSection::kAudio); 1565 OfferAnswer(); 1566 1567 // SanityCheck checks that the sdpFmtpLine for a local codec matches that of 1568 // the corresponding remote codec. 1569 UniquePtr<JsepAudioCodecDescription> codec; 1570 EXPECT_TRUE((codec = GetAudioCodec(mSendOff, 3, 0))); 1571 EXPECT_EQ("opus", codec->mName); 1572 EXPECT_EQ("maxplaybackrate=48000;stereo=1;useinbandfec=1", 1573 codec->mSdpFmtpLine.valueOr("nothing")); 1574 EXPECT_TRUE((codec = GetAudioCodec(mSendAns, 3, 0))); 1575 EXPECT_EQ("opus", codec->mName); 1576 EXPECT_EQ("maxplaybackrate=48000;stereo=1;useinbandfec=1", 1577 codec->mSdpFmtpLine.valueOr("nothing")); 1578 1579 EXPECT_TRUE((codec = GetAudioCodec(mSendOff, 3, 1))); 1580 EXPECT_EQ("G722", codec->mName); 1581 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1582 EXPECT_TRUE((codec = GetAudioCodec(mSendAns, 3, 1))); 1583 EXPECT_EQ("G722", codec->mName); 1584 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1585 1586 EXPECT_TRUE((codec = GetAudioCodec(mSendOff, 3, 2))); 1587 EXPECT_EQ("telephone-event", codec->mName); 1588 EXPECT_EQ("0-15", codec->mSdpFmtpLine.valueOr("nothing")); 1589 EXPECT_TRUE((codec = GetAudioCodec(mSendAns, 3, 2))); 1590 EXPECT_EQ("telephone-event", codec->mName); 1591 EXPECT_EQ("0-15", codec->mSdpFmtpLine.valueOr("nothing")); 1592 } 1593 1594 TEST_F(JsepTrackTest, NonDefaultAudioSdpFmtpLine) { 1595 mOffCodecs = MakeCodecs( 1596 {.addFecCodecs = true, .preferRed = true, .addDtmfCodec = true}); 1597 mAnsCodecs = MakeCodecs( 1598 {.addFecCodecs = true, .preferRed = true, .addDtmfCodec = true}); 1599 1600 for (auto& codec : mOffCodecs) { 1601 if (codec->mName == "opus") { 1602 auto* audio = static_cast<JsepAudioCodecDescription*>(codec.get()); 1603 audio->mForceMono = true; 1604 audio->mMaxPlaybackRate = 32000; 1605 } 1606 } 1607 1608 for (auto& codec : mAnsCodecs) { 1609 if (codec->mName == "opus") { 1610 auto* audio = static_cast<JsepAudioCodecDescription*>(codec.get()); 1611 audio->mFECEnabled = true; 1612 audio->mCbrEnabled = true; 1613 audio->mDTXEnabled = true; 1614 audio->mFrameSizeMs = 10; 1615 audio->mMinFrameSizeMs = 5; 1616 audio->mMaxFrameSizeMs = 20; 1617 } 1618 } 1619 1620 InitTracks(SdpMediaSection::kAudio); 1621 InitSdp(SdpMediaSection::kAudio); 1622 1623 { 1624 // telephone-event doesn't store any params in JsepAudioCodecDescription. 1625 // Set them directly in the offer sdp instead. 1626 auto params = MakeUnique<SdpFmtpAttributeList::TelephoneEventParameters>(); 1627 params->dtmfTones = "2-9"; 1628 GetOffer().SetFmtp({"101", *params}); 1629 } 1630 1631 { 1632 // telephone-event doesn't store any params in JsepAudioCodecDescription. 1633 // Set them directly in the answer sdp instead. 1634 auto params = MakeUnique<SdpFmtpAttributeList::TelephoneEventParameters>(); 1635 params->dtmfTones = "0-3,10"; 1636 GetAnswer().SetFmtp({"101", *params}); 1637 } 1638 1639 OfferAnswer(); 1640 1641 // SanityCheck checks that the sdpFmtpLine for a local codec matches that of 1642 // the corresponding remote codec. 1643 UniquePtr<JsepAudioCodecDescription> codec; 1644 EXPECT_TRUE((codec = GetAudioCodec(mSendOff, 3, 0))); 1645 EXPECT_EQ("opus", codec->mName); 1646 EXPECT_EQ( 1647 "maxplaybackrate=48000;stereo=1;useinbandfec=1;usedtx=1;ptime=10;" 1648 "minptime=5;maxptime=20;cbr=1", 1649 codec->mSdpFmtpLine.valueOr("nothing")); 1650 EXPECT_TRUE((codec = GetAudioCodec(mSendAns, 3, 0))); 1651 EXPECT_EQ("opus", codec->mName); 1652 EXPECT_EQ("maxplaybackrate=32000;stereo=0;useinbandfec=1", 1653 codec->mSdpFmtpLine.valueOr("nothing")); 1654 1655 EXPECT_TRUE((codec = GetAudioCodec(mSendOff, 3, 1))); 1656 EXPECT_EQ("G722", codec->mName); 1657 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1658 EXPECT_TRUE((codec = GetAudioCodec(mSendAns, 3, 1))); 1659 EXPECT_EQ("G722", codec->mName); 1660 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1661 1662 EXPECT_TRUE((codec = GetAudioCodec(mSendOff, 3, 2))); 1663 EXPECT_EQ("telephone-event", codec->mName); 1664 EXPECT_EQ("0-3,10", codec->mSdpFmtpLine.valueOr("nothing")); 1665 EXPECT_TRUE((codec = GetAudioCodec(mSendAns, 3, 2))); 1666 EXPECT_EQ("telephone-event", codec->mName); 1667 EXPECT_EQ("2-9", codec->mSdpFmtpLine.valueOr("nothing")); 1668 } 1669 1670 TEST_F(JsepTrackTest, VideoSdpFmtpLine) { 1671 mOffCodecs = MakeCodecs( 1672 {.addFecCodecs = true, .preferRed = true, .addDtmfCodec = true}); 1673 mAnsCodecs = MakeCodecs( 1674 {.addFecCodecs = true, .preferRed = true, .addDtmfCodec = true}); 1675 InitTracks(SdpMediaSection::kVideo); 1676 InitSdp(SdpMediaSection::kVideo); 1677 OfferAnswer(); 1678 1679 // SanityCheck checks that the sdpFmtpLine for a local codec matches that of 1680 // the corresponding remote codec. 1681 UniquePtr<JsepVideoCodecDescription> codec; 1682 EXPECT_TRUE((codec = GetVideoCodec(mSendOff, 5, 0))); 1683 EXPECT_EQ("VP8", codec->mName); 1684 EXPECT_EQ("max-fs=12288;max-fr=60", codec->mSdpFmtpLine.valueOr("nothing")); 1685 EXPECT_TRUE((codec = GetVideoCodec(mSendAns, 5, 0))); 1686 EXPECT_EQ("VP8", codec->mName); 1687 EXPECT_EQ("max-fs=12288;max-fr=60", codec->mSdpFmtpLine.valueOr("nothing")); 1688 1689 EXPECT_TRUE((codec = GetVideoCodec(mSendOff, 5, 1))); 1690 EXPECT_EQ("H264", codec->mName); 1691 EXPECT_EQ( 1692 "profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1", 1693 codec->mSdpFmtpLine.valueOr("nothing")); 1694 EXPECT_TRUE((codec = GetVideoCodec(mSendAns, 5, 1))); 1695 EXPECT_EQ("H264", codec->mName); 1696 EXPECT_EQ( 1697 "profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1", 1698 codec->mSdpFmtpLine.valueOr("nothing")); 1699 1700 EXPECT_TRUE((codec = GetVideoCodec(mSendOff, 5, 3))); 1701 EXPECT_EQ("red", codec->mName); 1702 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1703 EXPECT_TRUE((codec = GetVideoCodec(mSendAns, 5, 3))); 1704 EXPECT_EQ("red", codec->mName); 1705 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1706 1707 EXPECT_TRUE((codec = GetVideoCodec(mSendOff, 5, 4))); 1708 EXPECT_EQ("ulpfec", codec->mName); 1709 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1710 EXPECT_TRUE((codec = GetVideoCodec(mSendAns, 5, 4))); 1711 EXPECT_EQ("ulpfec", codec->mName); 1712 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1713 } 1714 1715 TEST_F(JsepTrackTest, NonDefaultVideoSdpFmtpLine) { 1716 mOffCodecs = MakeCodecs( 1717 {.addFecCodecs = true, .preferRed = true, .addDtmfCodec = true}); 1718 mAnsCodecs = MakeCodecs( 1719 {.addFecCodecs = true, .preferRed = true, .addDtmfCodec = true}); 1720 1721 for (auto& codec : mOffCodecs) { 1722 if (codec->mName == "VP8" || codec->mName == "H264") { 1723 auto* video = static_cast<JsepVideoCodecDescription*>(codec.get()); 1724 video->mConstraints.maxFs = 1200; 1725 if (codec->mName == "VP8") { 1726 video->mConstraints.maxFps = Some(15); 1727 } else { 1728 video->mConstraints.maxDpb = 6400; 1729 video->mConstraints.maxBr = 1000; 1730 JsepVideoCodecDescription::SetSaneH264Level(0x1F0, 1731 &video->mProfileLevelId); 1732 } 1733 } 1734 } 1735 1736 for (auto& codec : mAnsCodecs) { 1737 if (codec->mName == "VP8" || codec->mName == "H264") { 1738 auto* video = static_cast<JsepVideoCodecDescription*>(codec.get()); 1739 video->mConstraints.maxFs = 32400; 1740 if (codec->mName == "VP8") { 1741 video->mConstraints.maxFps = Some(60); 1742 } else { 1743 video->mConstraints.maxMbps = 1944000; 1744 video->mConstraints.maxCpb = 800000; 1745 video->mConstraints.maxDpb = 128000; 1746 JsepVideoCodecDescription::SetSaneH264Level(0xAB, 1747 &video->mProfileLevelId); 1748 video->mPacketizationMode = 1; 1749 } 1750 } 1751 } 1752 1753 InitTracks(SdpMediaSection::kVideo); 1754 InitSdp(SdpMediaSection::kVideo); 1755 OfferAnswer(); 1756 1757 // SanityCheck checks that the sdpFmtpLine for a local codec matches that of 1758 // the corresponding remote codec. 1759 UniquePtr<JsepVideoCodecDescription> codec; 1760 EXPECT_TRUE((codec = GetVideoCodec(mSendOff, 5, 0))); 1761 EXPECT_EQ("VP8", codec->mName); 1762 EXPECT_EQ("max-fs=32400;max-fr=60", codec->mSdpFmtpLine.valueOr("nothing")); 1763 EXPECT_TRUE((codec = GetVideoCodec(mSendAns, 5, 0))); 1764 EXPECT_EQ("VP8", codec->mName); 1765 EXPECT_EQ("max-fs=1200;max-fr=15", codec->mSdpFmtpLine.valueOr("nothing")); 1766 1767 EXPECT_TRUE((codec = GetVideoCodec(mSendOff, 5, 1))); 1768 EXPECT_EQ("H264", codec->mName); 1769 EXPECT_EQ( 1770 "profile-level-id=42f00b;level-asymmetry-allowed=1;packetization-mode=1;" 1771 "max-mbps=1944000;max-fs=32400;max-cpb=800000;max-dpb=128000", 1772 codec->mSdpFmtpLine.valueOr("nothing")); 1773 EXPECT_TRUE((codec = GetVideoCodec(mSendAns, 5, 1))); 1774 EXPECT_EQ("H264", codec->mName); 1775 EXPECT_EQ( 1776 "profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1;" 1777 "max-fs=1200;max-dpb=6400;max-br=1000", 1778 codec->mSdpFmtpLine.valueOr("nothing")); 1779 1780 EXPECT_TRUE((codec = GetVideoCodec(mSendOff, 5, 3))); 1781 EXPECT_EQ("red", codec->mName); 1782 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1783 EXPECT_TRUE((codec = GetVideoCodec(mSendAns, 5, 3))); 1784 EXPECT_EQ("red", codec->mName); 1785 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1786 1787 EXPECT_TRUE((codec = GetVideoCodec(mSendOff, 5, 4))); 1788 EXPECT_EQ("ulpfec", codec->mName); 1789 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1790 EXPECT_TRUE((codec = GetVideoCodec(mSendAns, 5, 4))); 1791 EXPECT_EQ("ulpfec", codec->mName); 1792 EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing")); 1793 } 1794 1795 TEST(JsepTrackRecvPayloadTypesTest, SingleTrackPTsAreUnique) 1796 { 1797 constexpr auto audio = SdpMediaSection::MediaType::kAudio; 1798 1799 std::vector<UniquePtr<JsepCodecDescription>> codecs; 1800 codecs.emplace_back( 1801 MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1)); 1802 1803 SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 1804 SdpMediaSection& offer1Msection1 = offer1.AddMediaSection( 1805 audio, SdpDirectionAttribute::kRecvonly, 0, 1806 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1807 1808 SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 1809 SdpMediaSection& answer1Msection1 = answer1.AddMediaSection( 1810 audio, SdpDirectionAttribute::kSendonly, 0, 1811 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1812 1813 for (const auto& codec : codecs) { 1814 codec->mDirection = sdp::kSend; 1815 offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 1816 codec->mChannels); 1817 auto clone = WrapUnique(codec->Clone()); 1818 clone->mDirection = sdp::kRecv; 1819 clone->AddToMediaSection(answer1Msection1); 1820 } 1821 1822 JsepTrack t1{audio, sdp::Direction::kRecv}; 1823 t1.PopulateCodecs(codecs, false); 1824 t1.RecvTrackSetLocal(offer1Msection1); 1825 t1.RecvTrackSetRemote(answer1, answer1Msection1); 1826 ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1), 1827 NS_OK); 1828 1829 std::vector tracks{&t1}; 1830 JsepTrack::SetReceivePayloadTypes(tracks); 1831 EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(1)); 1832 EXPECT_THAT(t1.GetOtherReceivePayloadTypes(), UnorderedElementsAre()); 1833 } 1834 1835 TEST(JsepTrackRecvPayloadTypesTest, DoubleTrackPTsAreUnique) 1836 { 1837 constexpr auto audio = SdpMediaSection::MediaType::kAudio; 1838 1839 std::vector<UniquePtr<JsepCodecDescription>> codecs1; 1840 codecs1.emplace_back( 1841 MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1)); 1842 1843 std::vector<UniquePtr<JsepCodecDescription>> codecs2; 1844 codecs2.emplace_back( 1845 MakeUnique<JsepAudioCodecDescription>("2", "codec1", 48000, 1)); 1846 1847 SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 1848 SdpMediaSection& offer1Msection1 = offer1.AddMediaSection( 1849 audio, SdpDirectionAttribute::kRecvonly, 0, 1850 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1851 SdpMediaSection& offer1Msection2 = offer1.AddMediaSection( 1852 audio, SdpDirectionAttribute::kRecvonly, 0, 1853 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1854 1855 SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 1856 SdpMediaSection& answer1Msection1 = answer1.AddMediaSection( 1857 audio, SdpDirectionAttribute::kSendonly, 0, 1858 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1859 SdpMediaSection& answer1Msection2 = answer1.AddMediaSection( 1860 audio, SdpDirectionAttribute::kSendonly, 0, 1861 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1862 1863 for (const auto& codec : codecs1) { 1864 codec->mDirection = sdp::kSend; 1865 offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 1866 codec->mChannels); 1867 auto clone = WrapUnique(codec->Clone()); 1868 clone->mDirection = sdp::kRecv; 1869 clone->AddToMediaSection(answer1Msection1); 1870 } 1871 1872 for (const auto& codec : codecs2) { 1873 codec->mDirection = sdp::kSend; 1874 offer1Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 1875 codec->mChannels); 1876 auto clone = WrapUnique(codec->Clone()); 1877 clone->mDirection = sdp::kRecv; 1878 clone->AddToMediaSection(answer1Msection2); 1879 } 1880 1881 JsepTrack t1{audio, sdp::Direction::kRecv}; 1882 t1.PopulateCodecs(codecs1, false); 1883 t1.RecvTrackSetLocal(offer1Msection1); 1884 t1.RecvTrackSetRemote(answer1, answer1Msection1); 1885 ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1), 1886 NS_OK); 1887 1888 JsepTrack t2{audio, sdp::Direction::kRecv}; 1889 t2.PopulateCodecs(codecs2, false); 1890 t2.RecvTrackSetLocal(offer1Msection2); 1891 t2.RecvTrackSetRemote(answer1, answer1Msection2); 1892 ASSERT_EQ(t2.Negotiate(answer1Msection2, answer1Msection2, offer1Msection2), 1893 NS_OK); 1894 1895 std::vector tracks{&t1, &t2}; 1896 JsepTrack::SetReceivePayloadTypes(tracks); 1897 EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(1)); 1898 EXPECT_THAT(t1.GetOtherReceivePayloadTypes(), UnorderedElementsAre(2)); 1899 EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(2)); 1900 EXPECT_THAT(t2.GetOtherReceivePayloadTypes(), UnorderedElementsAre(1)); 1901 } 1902 1903 TEST(JsepTrackRecvPayloadTypesTest, DoubleTrackPTsAreDuplicates) 1904 { 1905 constexpr auto audio = SdpMediaSection::MediaType::kAudio; 1906 1907 std::vector<UniquePtr<JsepCodecDescription>> codecs1; 1908 codecs1.emplace_back( 1909 MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1)); 1910 1911 std::vector<UniquePtr<JsepCodecDescription>> codecs2; 1912 codecs2.emplace_back( 1913 MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1)); 1914 1915 SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 1916 SdpMediaSection& offer1Msection1 = offer1.AddMediaSection( 1917 audio, SdpDirectionAttribute::kRecvonly, 0, 1918 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1919 SdpMediaSection& offer1Msection2 = offer1.AddMediaSection( 1920 audio, SdpDirectionAttribute::kRecvonly, 0, 1921 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1922 1923 SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 1924 SdpMediaSection& answer1Msection1 = answer1.AddMediaSection( 1925 audio, SdpDirectionAttribute::kSendonly, 0, 1926 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1927 SdpMediaSection& answer1Msection2 = answer1.AddMediaSection( 1928 audio, SdpDirectionAttribute::kSendonly, 0, 1929 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1930 1931 for (const auto& codec : codecs1) { 1932 codec->mDirection = sdp::kSend; 1933 offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 1934 codec->mChannels); 1935 auto clone = WrapUnique(codec->Clone()); 1936 clone->mDirection = sdp::kRecv; 1937 clone->AddToMediaSection(answer1Msection1); 1938 } 1939 for (const auto& codec : codecs2) { 1940 codec->mDirection = sdp::kSend; 1941 offer1Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 1942 codec->mChannels); 1943 auto clone = WrapUnique(codec->Clone()); 1944 clone->mDirection = sdp::kRecv; 1945 clone->AddToMediaSection(answer1Msection2); 1946 } 1947 1948 JsepTrack t1{audio, sdp::Direction::kRecv}; 1949 t1.PopulateCodecs(codecs1, false); 1950 t1.RecvTrackSetLocal(offer1Msection1); 1951 t1.RecvTrackSetRemote(answer1, answer1Msection1); 1952 ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1), 1953 NS_OK); 1954 1955 JsepTrack t2{audio, sdp::Direction::kRecv}; 1956 t2.PopulateCodecs(codecs2, false); 1957 t2.RecvTrackSetLocal(offer1Msection2); 1958 t2.RecvTrackSetRemote(answer1, answer1Msection2); 1959 ASSERT_EQ(t2.Negotiate(answer1Msection2, answer1Msection2, offer1Msection2), 1960 NS_OK); 1961 1962 std::vector tracks{&t1, &t2}; 1963 JsepTrack::SetReceivePayloadTypes(tracks); 1964 EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre()); 1965 EXPECT_THAT(t1.GetOtherReceivePayloadTypes(), UnorderedElementsAre(1)); 1966 EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre()); 1967 EXPECT_THAT(t2.GetOtherReceivePayloadTypes(), UnorderedElementsAre(1)); 1968 } 1969 1970 TEST(JsepTrackRecvPayloadTypesTest, DoubleTrackPTsOverlap) 1971 { 1972 constexpr auto audio = SdpMediaSection::MediaType::kAudio; 1973 1974 std::vector<UniquePtr<JsepCodecDescription>> codecs1; 1975 codecs1.emplace_back( 1976 MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1)); 1977 codecs1.emplace_back( 1978 MakeUnique<JsepAudioCodecDescription>("2", "codec2", 48000, 1)); 1979 1980 std::vector<UniquePtr<JsepCodecDescription>> codecs2; 1981 codecs2.emplace_back( 1982 MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1)); 1983 codecs2.emplace_back( 1984 MakeUnique<JsepAudioCodecDescription>("3", "codec2", 48000, 1)); 1985 1986 SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 1987 SdpMediaSection& offer1Msection1 = offer1.AddMediaSection( 1988 audio, SdpDirectionAttribute::kRecvonly, 0, 1989 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1990 SdpMediaSection& offer1Msection2 = offer1.AddMediaSection( 1991 audio, SdpDirectionAttribute::kRecvonly, 0, 1992 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1993 1994 SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 1995 SdpMediaSection& answer1Msection1 = answer1.AddMediaSection( 1996 audio, SdpDirectionAttribute::kSendonly, 0, 1997 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 1998 SdpMediaSection& answer1Msection2 = answer1.AddMediaSection( 1999 audio, SdpDirectionAttribute::kSendonly, 0, 2000 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2001 2002 for (const auto& codec : codecs1) { 2003 codec->mDirection = sdp::kSend; 2004 offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 2005 codec->mChannels); 2006 auto clone = WrapUnique(codec->Clone()); 2007 clone->mDirection = sdp::kRecv; 2008 clone->AddToMediaSection(answer1Msection1); 2009 } 2010 2011 for (const auto& codec : codecs2) { 2012 codec->mDirection = sdp::kSend; 2013 offer1Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 2014 codec->mChannels); 2015 auto clone = WrapUnique(codec->Clone()); 2016 clone->mDirection = sdp::kRecv; 2017 clone->AddToMediaSection(answer1Msection2); 2018 } 2019 2020 JsepTrack t1{audio, sdp::Direction::kRecv}; 2021 t1.PopulateCodecs(codecs1, false); 2022 t1.RecvTrackSetLocal(offer1Msection1); 2023 t1.RecvTrackSetRemote(answer1, answer1Msection1); 2024 ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1), 2025 NS_OK); 2026 2027 JsepTrack t2{audio, sdp::Direction::kRecv}; 2028 t2.PopulateCodecs(codecs2, false); 2029 t2.RecvTrackSetLocal(offer1Msection2); 2030 t2.RecvTrackSetRemote(answer1, answer1Msection2); 2031 ASSERT_EQ(t2.Negotiate(answer1Msection2, answer1Msection2, offer1Msection2), 2032 NS_OK); 2033 2034 std::vector tracks{&t1, &t2}; 2035 JsepTrack::SetReceivePayloadTypes(tracks); 2036 EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(2)); 2037 EXPECT_THAT(t1.GetOtherReceivePayloadTypes(), UnorderedElementsAre(1, 3)); 2038 EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(3)); 2039 EXPECT_THAT(t2.GetOtherReceivePayloadTypes(), UnorderedElementsAre(1, 2)); 2040 } 2041 2042 TEST(JsepTrackRecvPayloadTypesTest, DoubleTrackPTsDuplicateAfterRenegotiation) 2043 { 2044 constexpr auto audio = SdpMediaSection::MediaType::kAudio; 2045 2046 std::vector<UniquePtr<JsepCodecDescription>> codecs1; 2047 codecs1.emplace_back( 2048 MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1)); 2049 codecs1.emplace_back( 2050 MakeUnique<JsepAudioCodecDescription>("2", "codec2", 48000, 1)); 2051 2052 std::vector<UniquePtr<JsepCodecDescription>> codecs2; 2053 codecs2.emplace_back( 2054 MakeUnique<JsepAudioCodecDescription>("3", "codec1", 48000, 1)); 2055 codecs2.emplace_back( 2056 MakeUnique<JsepAudioCodecDescription>("4", "codec2", 48000, 1)); 2057 2058 // First negotiation. 2059 SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 2060 SdpMediaSection& offer1Msection1 = offer1.AddMediaSection( 2061 audio, SdpDirectionAttribute::kRecvonly, 0, 2062 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2063 SdpMediaSection& offer1Msection2 = offer1.AddMediaSection( 2064 audio, SdpDirectionAttribute::kRecvonly, 0, 2065 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2066 2067 SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 2068 SdpMediaSection& answer1Msection1 = answer1.AddMediaSection( 2069 audio, SdpDirectionAttribute::kSendonly, 0, 2070 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2071 SdpMediaSection& answer1Msection2 = answer1.AddMediaSection( 2072 audio, SdpDirectionAttribute::kSendonly, 0, 2073 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2074 2075 for (const auto& codec : codecs1) { 2076 codec->mDirection = sdp::kSend; 2077 offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 2078 codec->mChannels); 2079 auto clone = WrapUnique(codec->Clone()); 2080 clone->mDirection = sdp::kRecv; 2081 clone->AddToMediaSection(answer1Msection1); 2082 } 2083 2084 for (const auto& codec : codecs2) { 2085 codec->mDirection = sdp::kSend; 2086 offer1Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 2087 codec->mChannels); 2088 auto clone = WrapUnique(codec->Clone()); 2089 clone->mDirection = sdp::kRecv; 2090 clone->AddToMediaSection(answer1Msection2); 2091 } 2092 2093 // t1 and t2 use distinct payload types in the first negotiation. 2094 JsepTrack t1{audio, sdp::Direction::kRecv}; 2095 t1.PopulateCodecs(codecs1, false); 2096 t1.RecvTrackSetLocal(offer1Msection1); 2097 t1.RecvTrackSetRemote(answer1, answer1Msection1); 2098 ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1), 2099 NS_OK); 2100 2101 JsepTrack t2{audio, sdp::Direction::kRecv}; 2102 t2.PopulateCodecs(codecs2, false); 2103 t2.RecvTrackSetLocal(offer1Msection2); 2104 t2.RecvTrackSetRemote(answer1, answer1Msection2); 2105 ASSERT_EQ(t2.Negotiate(answer1Msection2, answer1Msection2, offer1Msection2), 2106 NS_OK); 2107 2108 std::vector tracks{&t1, &t2}; 2109 JsepTrack::SetReceivePayloadTypes(tracks); 2110 EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(1, 2)); 2111 EXPECT_THAT(t1.GetOtherReceivePayloadTypes(), UnorderedElementsAre(3, 4)); 2112 EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(3, 4)); 2113 EXPECT_THAT(t2.GetOtherReceivePayloadTypes(), UnorderedElementsAre(1, 2)); 2114 2115 // Second negotiation. 2116 SipccSdp offer2(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 2117 SdpMediaSection& offer2Msection1 = offer2.AddMediaSection( 2118 audio, SdpDirectionAttribute::kRecvonly, 0, 2119 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2120 SdpMediaSection& offer2Msection2 = offer2.AddMediaSection( 2121 audio, SdpDirectionAttribute::kRecvonly, 0, 2122 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2123 2124 SipccSdp answer2(SdpOrigin("", 0, 0, sdp::kIPv4, "")); 2125 SdpMediaSection& answer2Msection1 = answer2.AddMediaSection( 2126 audio, SdpDirectionAttribute::kSendonly, 0, 2127 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2128 SdpMediaSection& answer2Msection2 = answer2.AddMediaSection( 2129 audio, SdpDirectionAttribute::kSendonly, 0, 2130 SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0"); 2131 2132 for (const auto& codec : codecs1) { 2133 codec->mDirection = sdp::kSend; 2134 offer2Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 2135 codec->mChannels); 2136 auto clone = WrapUnique(codec->Clone()); 2137 clone->mDirection = sdp::kRecv; 2138 clone->AddToMediaSection(answer2Msection1); 2139 } 2140 2141 for (const auto& codec : codecs2) { 2142 codec->mDirection = sdp::kSend; 2143 offer2Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock, 2144 codec->mChannels); 2145 auto clone = WrapUnique(codec->Clone()); 2146 clone->mDirection = sdp::kRecv; 2147 clone->AddToMediaSection(answer2Msection2); 2148 } 2149 2150 t1.PopulateCodecs(codecs1, false); 2151 t1.RecvTrackSetLocal(offer2Msection1); 2152 t1.RecvTrackSetRemote(answer2, answer2Msection1); 2153 ASSERT_EQ(t1.Negotiate(answer2Msection1, answer2Msection1, offer2Msection1), 2154 NS_OK); 2155 2156 // Change t2 to use the same payload types as t1. Both tracks should now mark 2157 // all their payload types as duplicates. 2158 t2.PopulateCodecs(codecs1, false); 2159 t2.RecvTrackSetLocal(offer2Msection2); 2160 t2.RecvTrackSetRemote(answer2, answer2Msection2); 2161 ASSERT_EQ(t2.Negotiate(answer2Msection2, answer2Msection2, offer2Msection2), 2162 NS_OK); 2163 2164 std::vector newTracks{&t1, &t2}; 2165 JsepTrack::SetReceivePayloadTypes(newTracks); 2166 EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre()); 2167 EXPECT_THAT(t1.GetOtherReceivePayloadTypes(), UnorderedElementsAre(1, 2)); 2168 EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre()); 2169 EXPECT_THAT(t2.GetOtherReceivePayloadTypes(), UnorderedElementsAre(1, 2)); 2170 } 2171 } // namespace mozilla