Reject attempts to change the media kind for a m-line with a previously used mid

which can happen if the remote end reuses a mid.

BUG=webrtc:15471

Change-Id: I38da7dced712400002bc61d616e481a1255aa896
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/319460
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40776}
This commit is contained in:
Philipp Hancke 2023-09-18 10:55:02 +02:00 committed by WebRTC LUCI CQ
parent ec8262788b
commit 5551776035
2 changed files with 82 additions and 4 deletions

View File

@ -2341,7 +2341,14 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
// recycled.
if (current_content && !current_content->rejected &&
current_content->name == media_description_options.mid) {
RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
if (!IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)) {
// TODO(bugs.webrtc.org/15471): add a unit test for this since
// it is not clear how this can happen for offers.
RTC_LOG(LS_ERROR) << "Media type for content with mid='"
<< current_content->name
<< "' does not match previous type.";
return false;
}
const AudioContentDescription* acd =
current_content->media_description()->as_audio();
for (const AudioCodec& codec : acd->codecs()) {
@ -2434,7 +2441,15 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
// recycled.
if (current_content && !current_content->rejected &&
current_content->name == media_description_options.mid) {
RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
if (!IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)) {
// TODO(bugs.webrtc.org/15471): add a unit test for this since
// it is not clear how this can happen for offers.
RTC_LOG(LS_ERROR) << "Media type for content with mid='"
<< current_content->name
<< "' does not match previous type.";
return false;
}
const VideoContentDescription* vcd =
current_content->media_description()->as_video();
for (const VideoCodec& codec : vcd->codecs()) {
@ -2645,7 +2660,13 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
// recycled.
if (current_content && !current_content->rejected &&
current_content->name == media_description_options.mid) {
RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
if (!IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)) {
// Can happen if the remote side re-uses a MID while recycling.
RTC_LOG(LS_ERROR) << "Media type for content with mid='"
<< current_content->name
<< "' does not match previous type.";
return false;
}
const AudioContentDescription* acd =
current_content->media_description()->as_audio();
for (const AudioCodec& codec : acd->codecs()) {
@ -2770,7 +2791,13 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
// recycled.
if (current_content && !current_content->rejected &&
current_content->name == media_description_options.mid) {
RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
if (!IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)) {
// Can happen if the remote side re-uses a MID while recycling.
RTC_LOG(LS_ERROR) << "Media type for content with mid='"
<< current_content->name
<< "' does not match previous type.";
return false;
}
const VideoContentDescription* vcd =
current_content->media_description()->as_video();
for (const VideoCodec& codec : vcd->codecs()) {

View File

@ -1006,4 +1006,55 @@ TEST_F(SdpOfferAnswerTest, SdpMungingWithInvalidPayloadTypeIsRejected) {
}
}
// Test variant with boolean order for audio-video and video-audio.
class SdpOfferAnswerShuffleMediaTypes
: public SdpOfferAnswerTest,
public testing::WithParamInterface<bool> {
public:
SdpOfferAnswerShuffleMediaTypes() : SdpOfferAnswerTest() {}
};
TEST_P(SdpOfferAnswerShuffleMediaTypes,
RecyclingWithDifferentKindAndSameMidFails) {
bool audio_first = GetParam();
auto pc1 = CreatePeerConnection();
auto pc2 = CreatePeerConnection();
if (audio_first) {
pc1->AddAudioTrack("audio_track", {});
pc2->AddVideoTrack("video_track", {});
} else {
pc2->AddAudioTrack("audio_track", {});
pc1->AddVideoTrack("video_track", {});
}
auto initial_offer = pc1->CreateOfferAndSetAsLocal();
ASSERT_EQ(initial_offer->description()->contents().size(), 1u);
auto mid1 = initial_offer->description()->contents()[0].mid();
std::string rejected_answer_sdp =
"v=0\r\n"
"o=- 8621259572628890423 2 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"t=0 0\r\n"
"m=" +
std::string(audio_first ? "audio" : "video") +
" 0 UDP/TLS/RTP/SAVPF 111\r\n"
"c=IN IP4 0.0.0.0\r\n";
auto rejected_answer =
CreateSessionDescription(SdpType::kAnswer, rejected_answer_sdp);
EXPECT_TRUE(pc1->SetRemoteDescription(std::move(rejected_answer)));
auto offer =
pc2->CreateOfferAndSetAsLocal(); // This will generate a mid=0 too
ASSERT_EQ(offer->description()->contents().size(), 1u);
auto mid2 = offer->description()->contents()[0].mid();
EXPECT_EQ(mid1, mid2); // Check that the mids collided.
EXPECT_TRUE(pc1->SetRemoteDescription(std::move(offer)));
auto answer = pc1->CreateAnswer();
EXPECT_FALSE(pc1->SetLocalDescription(std::move(answer)));
}
INSTANTIATE_TEST_SUITE_P(SdpOfferAnswerShuffleMediaTypes,
SdpOfferAnswerShuffleMediaTypes,
::testing::Values(true, false));
} // namespace webrtc