sdp: answer with spec msid when msid support is unknown
this removes the reliance on the no-longer-spec a=msid-semantic lines
in case the offer did not signal any msid. Endpoints not supporting
msid should silently ignore the resulting a=msid: line. This also changes behavior such that a "legacy" offer without msid-semantic
line will be responded to with both msid-semantic and msid for any tracks present.
Plan-B ssrc-specific msid attributes are not signalled in that case.
See https://datatracker.ietf.org/doc/html/rfc8829#section-5.3.1
which includes it in the answer depending on the transceiver direction
but not if and only if the offer signalled a msid.
This also avoids recreating the stream and changing the SSRC
which could happen if the answer object was serialized to SDP
(which most unit tests do not do)
BUG=chromium:328522463
Change-Id: Id2f890b7756721d7c50460359950826d392483ae
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/346741
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@meta.com>
Cr-Commit-Position: refs/heads/main@{#42237}
diff --git a/pc/sdp_offer_answer_unittest.cc b/pc/sdp_offer_answer_unittest.cc
index 536c712..3a6f510 100644
--- a/pc/sdp_offer_answer_unittest.cc
+++ b/pc/sdp_offer_answer_unittest.cc
@@ -1052,6 +1052,64 @@
EXPECT_NE(std::string::npos, sdp.find("a=msid:- audio_track\r\n"));
}
+// Regression test for crbug.com/328522463
+// where the stream parameters got recreated which changed the ssrc.
+TEST_F(SdpOfferAnswerTest, MsidSignalingUnknownRespondsWithMsidAndKeepsSsrc) {
+ auto pc = CreatePeerConnection();
+ pc->AddAudioTrack("audio_track", {"default"});
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=group:BUNDLE 0\r\n"
+ // "a=msid-semantic: WMS *\r\n"
+ "a=ice-ufrag:ETEn\r\n"
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
+ "a=fingerprint:sha-1 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
+ "a=setup:actpass\r\n"
+ "m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp:9 IN IP4 0.0.0.0\r\n"
+ "a=recvonly\r\n"
+ "a=rtcp-mux\r\n"
+ "a=mid:0\r\n"
+ "a=rtpmap:111 opus/48000/2\r\n";
+
+ auto offer = CreateSessionDescription(SdpType::kOffer, sdp);
+ EXPECT_TRUE(pc->SetRemoteDescription(std::move(offer)));
+ auto first_transceiver = pc->pc()->GetTransceivers()[0];
+ EXPECT_TRUE(first_transceiver
+ ->SetDirectionWithError(RtpTransceiverDirection::kSendOnly)
+ .ok());
+ // Check the generated *serialized* SDP.
+ auto answer = pc->CreateAnswer();
+ const auto& answer_contents = answer->description()->contents();
+ ASSERT_EQ(answer_contents.size(), 1u);
+ auto answer_streams = answer_contents[0].media_description()->streams();
+ ASSERT_EQ(answer_streams.size(), 1u);
+ std::string first_stream_serialized = answer_streams[0].ToString();
+ uint32_t first_ssrc = answer_contents[0].media_description()->first_ssrc();
+
+ answer->ToString(&sdp);
+ EXPECT_TRUE(
+ pc->SetLocalDescription(CreateSessionDescription(SdpType::kAnswer, sdp)));
+
+ auto reoffer = pc->CreateOffer();
+ const auto& offer_contents = reoffer->description()->contents();
+ ASSERT_EQ(offer_contents.size(), 1u);
+
+ auto offer_streams = offer_contents[0].media_description()->streams();
+ ASSERT_EQ(offer_streams.size(), 1u);
+ std::string second_stream_serialized = offer_streams[0].ToString();
+ uint32_t second_ssrc = offer_contents[0].media_description()->first_ssrc();
+
+ EXPECT_EQ(first_ssrc, second_ssrc);
+ EXPECT_EQ(first_stream_serialized, second_stream_serialized);
+ EXPECT_TRUE(pc->SetLocalDescription(std::move(reoffer)));
+}
+
// Test variant with boolean order for audio-video and video-audio.
class SdpOfferAnswerShuffleMediaTypes
: public SdpOfferAnswerTest,
@@ -1182,39 +1240,6 @@
EXPECT_EQ(answer_contents[1].rejected, true);
}
-TEST_F(SdpOfferAnswerTest,
- OfferWithNoMsidSemanticYieldsAnswerWithoutMsidSemantic) {
- auto pc = CreatePeerConnection();
- // An offer with no msid-semantic line. The answer should not add one.
- std::string sdp =
- "v=0\r\n"
- "o=- 0 3 IN IP4 127.0.0.1\r\n"
- "s=-\r\n"
- "t=0 0\r\n"
- "a=fingerprint:sha-1 "
- "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
- "a=setup:actpass\r\n"
- "a=ice-ufrag:ETEn\r\n"
- "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
- "m=audio 9 RTP/SAVPF 111\r\n"
- "c=IN IP4 0.0.0.0\r\n"
- "a=sendrecv\r\n"
- "a=rtpmap:111 opus/48000/2\r\n"
- "a=rtcp-mux\r\n";
-
- auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
- ASSERT_NE(desc, nullptr);
- EXPECT_EQ(desc->description()->msid_signaling(),
- cricket::kMsidSignalingNotUsed);
- RTCError error;
- pc->SetRemoteDescription(std::move(desc), &error);
- EXPECT_TRUE(error.ok());
-
- auto answer = pc->CreateAnswer();
- EXPECT_EQ(answer->description()->msid_signaling(),
- cricket::kMsidSignalingNotUsed);
-}
-
TEST_F(SdpOfferAnswerTest, OfferWithRejectedMlineWithoutFingerprintIsAccepted) {
auto pc = CreatePeerConnection();
// A rejected m-line without fingerprint.