diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 3478e2fc17..0f87ec68dd 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -338,6 +338,21 @@ static bool ValidateStreamParams(const StreamParams& sp) { return false; } } + for (const auto& group : sp.ssrc_groups) { + if (group.semantics != kSimSsrcGroupSemantics) + continue; + for (uint32_t group_ssrc : group.ssrcs) { + auto it = absl::c_find_if(sp.ssrcs, [&group_ssrc](uint32_t ssrc) { + return ssrc == group_ssrc; + }); + if (it == sp.ssrcs.end()) { + RTC_LOG(LS_ERROR) << "SSRC '" << group_ssrc + << "' missing from StreamParams ssrcs with semantics " + << kSimSsrcGroupSemantics << ": " << sp.ToString(); + return false; + } + } + } return true; } diff --git a/pc/sdp_offer_answer_unittest.cc b/pc/sdp_offer_answer_unittest.cc index c03c08f3b8..202b3538c8 100644 --- a/pc/sdp_offer_answer_unittest.cc +++ b/pc/sdp_offer_answer_unittest.cc @@ -808,4 +808,86 @@ TEST_F(SdpOfferAnswerTest, DuplicateSsrcsDisallowedInLocalDescription) { EXPECT_FALSE(pc->SetLocalDescription(std::move(offer))); } +TEST_F(SdpOfferAnswerTest, + DuplicateSsrcsAcrossMlinesDisallowedInLocalDescriptionTwoSsrc) { + auto pc = CreatePeerConnection(); + + pc->AddAudioTrack("audio_track", {}); + pc->AddVideoTrack("video_track", {}); + auto offer = pc->CreateOffer(); + auto& offer_contents = offer->description()->contents(); + ASSERT_EQ(offer_contents.size(), 2u); + uint32_t audio_ssrc = offer_contents[0].media_description()->first_ssrc(); + ASSERT_EQ(offer_contents[1].media_description()->streams().size(), 1u); + auto& video_stream = offer->description() + ->contents()[1] + .media_description() + ->mutable_streams()[0]; + ASSERT_EQ(video_stream.ssrcs.size(), 2u); + ASSERT_EQ(video_stream.ssrc_groups.size(), 1u); + video_stream.ssrcs[1] = audio_ssrc; + video_stream.ssrc_groups[0].ssrcs[1] = audio_ssrc; + video_stream.ssrc_groups[0].semantics = cricket::kSimSsrcGroupSemantics; + std::string sdp; + offer->ToString(&sdp); + + // Trim the last two lines which contain ssrc-specific attributes + // that we change/munge above. Guarded with expectation about what + // should be removed in case the SDP generation changes. + size_t end = sdp.rfind("\r\n"); + end = sdp.rfind("\r\n", end - 2); + end = sdp.rfind("\r\n", end - 2); + EXPECT_EQ(sdp.substr(end + 2), "a=ssrc:" + rtc::ToString(audio_ssrc) + + " cname:" + video_stream.cname + + "\r\n" + "a=ssrc:" + + rtc::ToString(audio_ssrc) + + " msid:- video_track\r\n"); + + auto modified_offer = + CreateSessionDescription(SdpType::kOffer, sdp.substr(0, end + 2)); + EXPECT_FALSE(pc->SetLocalDescription(std::move(modified_offer))); +} + +TEST_F(SdpOfferAnswerTest, + DuplicateSsrcsAcrossMlinesDisallowedInLocalDescriptionThreeSsrcs) { + auto pc = CreatePeerConnection(); + + pc->AddAudioTrack("audio_track", {}); + pc->AddVideoTrack("video_track", {}); + auto offer = pc->CreateOffer(); + auto& offer_contents = offer->description()->contents(); + ASSERT_EQ(offer_contents.size(), 2u); + uint32_t audio_ssrc = offer_contents[0].media_description()->first_ssrc(); + ASSERT_EQ(offer_contents[1].media_description()->streams().size(), 1u); + auto& video_stream = offer->description() + ->contents()[1] + .media_description() + ->mutable_streams()[0]; + ASSERT_EQ(video_stream.ssrcs.size(), 2u); + ASSERT_EQ(video_stream.ssrc_groups.size(), 1u); + video_stream.ssrcs.push_back(audio_ssrc); + video_stream.ssrc_groups[0].ssrcs.push_back(audio_ssrc); + video_stream.ssrc_groups[0].semantics = cricket::kSimSsrcGroupSemantics; + std::string sdp; + offer->ToString(&sdp); + + // Trim the last two lines which contain ssrc-specific attributes + // that we change/munge above. Guarded with expectation about what + // should be removed in case the SDP generation changes. + size_t end = sdp.rfind("\r\n"); + end = sdp.rfind("\r\n", end - 2); + end = sdp.rfind("\r\n", end - 2); + EXPECT_EQ(sdp.substr(end + 2), "a=ssrc:" + rtc::ToString(audio_ssrc) + + " cname:" + video_stream.cname + + "\r\n" + "a=ssrc:" + + rtc::ToString(audio_ssrc) + + " msid:- video_track\r\n"); + + auto modified_offer = + CreateSessionDescription(SdpType::kOffer, sdp.substr(0, end + 2)); + EXPECT_FALSE(pc->SetLocalDescription(std::move(modified_offer))); +} + } // namespace webrtc