Adds support for "-" to a=ssrc msid lines.
Currently with in Unified Plan an initial offer will include both
"a=ssrc:... msid:..." lines and "a=msid:... ..." lines. The a=ssrc line
is added in order to support signaling to a Plan B endpoint. Although if
no stream is associated to a given track it will only be signaled in the
"a=msid" line with "-". The "a=ssrc msid" line will simply put an empty
string for the msid, which does not interoperate with FF. This change
adds support so that both lines will signal a "-".
Bug: webrtc:9880
Change-Id: I73655ce3c11a924b508616d820555bf24aae1bd3
Reviewed-on: https://webrtc-review.googlesource.com/c/106605
Commit-Queue: Seth Hampson <shampson@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Seth Hampson <shampson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25241}
diff --git a/pc/webrtcsdp_unittest.cc b/pc/webrtcsdp_unittest.cc
index e3ccd06..bba10f2 100644
--- a/pc/webrtcsdp_unittest.cc
+++ b/pc/webrtcsdp_unittest.cc
@@ -623,8 +623,8 @@
"generation 2\r\n"
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
"a=mid:audio_content_name\r\n"
- "a=msid:local_stream_1 audio_track_id_1\r\n"
"a=sendrecv\r\n"
+ "a=msid:local_stream_1 audio_track_id_1\r\n"
"a=rtcp-mux\r\n"
"a=rtcp-rsize\r\n"
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
@@ -643,9 +643,9 @@
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
"a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
"a=mid:audio_content_name_2\r\n"
+ "a=sendrecv\r\n"
"a=msid:local_stream_1 audio_track_id_2\r\n"
"a=msid:local_stream_2 audio_track_id_2\r\n"
- "a=sendrecv\r\n"
"a=rtcp-mux\r\n"
"a=rtcp-rsize\r\n"
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
@@ -666,8 +666,8 @@
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
"a=ice-ufrag:ufrag_voice_3\r\na=ice-pwd:pwd_voice_3\r\n"
"a=mid:audio_content_name_3\r\n"
- "a=msid:- audio_track_id_3\r\n"
"a=sendrecv\r\n"
+ "a=msid:- audio_track_id_3\r\n"
"a=rtcp-mux\r\n"
"a=rtcp-rsize\r\n"
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
@@ -676,7 +676,10 @@
"a=rtpmap:111 opus/48000/2\r\n"
"a=rtpmap:103 ISAC/16000\r\n"
"a=rtpmap:104 ISAC/32000\r\n"
- "a=ssrc:7 cname:stream_2_cname\r\n";
+ "a=ssrc:7 cname:stream_2_cname\r\n"
+ "a=ssrc:7 msid:- audio_track_id_3\r\n"
+ "a=ssrc:7 mslabel:-\r\n"
+ "a=ssrc:7 label:audio_track_id_3\r\n";
// One candidate reference string as per W3c spec.
// candidate:<blah> not a=candidate:<blah>CRLF
@@ -1162,7 +1165,7 @@
// with 3 audio MediaContentDescriptions with special StreamParams that
// contain 0 or multiple stream ids: - audio track 1 has 1 media stream id -
// audio track 2 has 2 media stream ids - audio track 3 has 0 media stream ids
- void MakeUnifiedPlanDescriptionMultipleStreamIds() {
+ void MakeUnifiedPlanDescriptionMultipleStreamIds(const int msid_signaling) {
desc_.RemoveContentByName(kVideoContentName);
desc_.RemoveTransportInfoByName(kVideoContentName);
RemoveVideoCandidates();
@@ -1190,9 +1193,7 @@
desc_.AddContent(kAudioContentName3, MediaProtocolType::kRtp, audio_desc_3);
EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
kAudioContentName3, TransportDescription(kUfragVoice3, kPwdVoice3))));
- // Make sure to create both a=msid lines.
- desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection |
- cricket::kMsidSignalingSsrcAttribute);
+ desc_.set_msid_signaling(msid_signaling);
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(), jdesc_.session_id(),
jdesc_.session_version()));
}
@@ -1547,6 +1548,27 @@
}
}
+ // Removes all a=ssrc lines from the SDP string, except for the
+ // "a=ssrc:... cname:..." lines.
+ void RemoveSsrcMsidLinesFromSdpString(std::string* sdp_string) {
+ const char kAttributeSsrc[] = "a=ssrc";
+ const char kAttributeCname[] = "cname";
+ size_t ssrc_line_pos = sdp_string->find(kAttributeSsrc);
+ while (ssrc_line_pos != std::string::npos) {
+ size_t beg_line_pos = sdp_string->rfind('\n', ssrc_line_pos);
+ size_t end_line_pos = sdp_string->find('\n', ssrc_line_pos);
+ size_t cname_pos = sdp_string->find(kAttributeCname, ssrc_line_pos);
+ if (cname_pos == std::string::npos || cname_pos > end_line_pos) {
+ // Only erase a=ssrc lines that don't contain "cname".
+ sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
+ ssrc_line_pos = sdp_string->find(kAttributeSsrc, beg_line_pos);
+ } else {
+ // Skip the "a=ssrc:... cname" line and find the next "a=ssrc" line.
+ ssrc_line_pos = sdp_string->find(kAttributeSsrc, end_line_pos);
+ }
+ }
+ }
+
// Removes all a=ssrc lines from the SDP string.
void RemoveSsrcLinesFromSdpString(std::string* sdp_string) {
const char kAttributeSsrc[] = "a=ssrc";
@@ -3434,12 +3456,16 @@
}
// This tests deserializing a Unified Plan SDP that is compatible with both
-// Unified Plan and Plan B style SDP. It tests the case for audio/video tracks
+// Unified Plan and Plan B style SDP, meaning that it contains both "a=ssrc
+// msid" lines and "a=msid " lines. It tests the case for audio/video tracks
// with no stream ids and multiple stream ids. For parsing this, the Unified
// Plan a=msid lines should take priority, because the Plan B style a=ssrc msid
// lines do not support multiple stream ids and no stream ids.
-TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescriptionSpecialMsid) {
- MakeUnifiedPlanDescriptionMultipleStreamIds();
+TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionSpecialMsid) {
+ // Create both msid lines for Plan B and Unified Plan support.
+ MakeUnifiedPlanDescriptionMultipleStreamIds(
+ cricket::kMsidSignalingMediaSection |
+ cricket::kMsidSignalingSsrcAttribute);
JsepSessionDescription deserialized_description(kDummyType);
EXPECT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullStringWithSpecialMsid,
@@ -3448,8 +3474,50 @@
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
}
-TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescriptionSpecialMsid) {
- MakeUnifiedPlanDescriptionMultipleStreamIds();
+// Tests the serialization of a Unified Plan SDP that is compatible for both
+// Unified Plan and Plan B style SDPs, meaning that it contains both "a=ssrc
+// msid" lines and "a=msid " lines. It tests the case for no stream ids and
+// multiple stream ids.
+TEST_F(WebRtcSdpTest, SerializeSessionDescriptionSpecialMsid) {
+ // Create both msid lines for Plan B and Unified Plan support.
+ MakeUnifiedPlanDescriptionMultipleStreamIds(
+ cricket::kMsidSignalingMediaSection |
+ cricket::kMsidSignalingSsrcAttribute);
+ std::string serialized_sdp = webrtc::SdpSerialize(jdesc_);
+ // We explicitly test that the serialized SDP string is equal to the hard
+ // coded SDP string. This is necessary, because in the parser "a=msid" lines
+ // take priority over "a=ssrc msid" lines. This means if we just used
+ // TestSerialize(), it could serialize an SDP that omits "a=ssrc msid" lines,
+ // and still pass, because the deserialized version would be the same.
+ EXPECT_EQ(kUnifiedPlanSdpFullStringWithSpecialMsid, serialized_sdp);
+}
+
+// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
+// that signal stream IDs) is deserialized appropriately. It tests the case for
+// no stream ids and multiple stream ids.
+TEST_F(WebRtcSdpTest, UnifiedPlanDeserializeSessionDescriptionSpecialMsid) {
+ // Only create a=msid lines for strictly Unified Plan stream ID support.
+ MakeUnifiedPlanDescriptionMultipleStreamIds(
+ cricket::kMsidSignalingMediaSection);
+
+ JsepSessionDescription deserialized_description(kDummyType);
+ std::string unified_plan_sdp_string =
+ kUnifiedPlanSdpFullStringWithSpecialMsid;
+ RemoveSsrcMsidLinesFromSdpString(&unified_plan_sdp_string);
+ EXPECT_TRUE(
+ SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
+
+ EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
+}
+
+// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
+// that signal stream IDs) is serialized appropriately. It tests the case for no
+// stream ids and multiple stream ids.
+TEST_F(WebRtcSdpTest, UnifiedPlanSerializeSessionDescriptionSpecialMsid) {
+ // Only create a=msid lines for strictly Unified Plan stream ID support.
+ MakeUnifiedPlanDescriptionMultipleStreamIds(
+ cricket::kMsidSignalingMediaSection);
+
TestSerialize(jdesc_);
}