sdp: make msid support parsing more robust
by also taking into account any a=msid: line in addition to
msid-semantic. Also document issues with msid-semantic generation and unify support determination by removing the msid_supported flag.
BUG=webrtc:10421
Change-Id: Icea554ebd1998f2b526846457029eff6854a772a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/329760
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41386}
diff --git a/pc/media_session.cc b/pc/media_session.cc
index e3197c4..aaa8eb9 100644
--- a/pc/media_session.cc
+++ b/pc/media_session.cc
@@ -1881,11 +1881,13 @@
// Be conservative and signal using both a=msid and a=ssrc lines. Unified
// Plan answerers will look at a=msid and Plan B answerers will look at the
// a=ssrc MSID line.
- offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
+ offer->set_msid_signaling(cricket::kMsidSignalingSemantic |
+ cricket::kMsidSignalingMediaSection |
cricket::kMsidSignalingSsrcAttribute);
} else {
// Plan B always signals MSID using a=ssrc lines.
- offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
+ offer->set_msid_signaling(cricket::kMsidSignalingSemantic |
+ cricket::kMsidSignalingSsrcAttribute);
}
offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
@@ -2058,7 +2060,9 @@
if (is_unified_plan_) {
// Unified Plan needs to look at what the offer included to find the most
// compatible answer.
- if (offer->msid_signaling() == 0) {
+ int msid_signaling = offer->msid_signaling();
+ if (msid_signaling == cricket::kMsidSignalingNotUsed ||
+ msid_signaling == cricket::kMsidSignalingSemantic) {
// We end up here in one of three cases:
// 1. An empty offer. We'll reply with an empty answer so it doesn't
// matter what we pick here.
@@ -2067,23 +2071,26 @@
// 3. Media that's either sendonly or inactive from the remote endpoint.
// We don't have any information to say whether the endpoint is Plan B
// or Unified Plan, so be conservative and send both.
- answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
+ answer->set_msid_signaling(cricket::kMsidSignalingSemantic |
+ cricket::kMsidSignalingMediaSection |
cricket::kMsidSignalingSsrcAttribute);
- } else if (offer->msid_signaling() ==
- (cricket::kMsidSignalingMediaSection |
- cricket::kMsidSignalingSsrcAttribute)) {
+ } else if (msid_signaling == (cricket::kMsidSignalingSemantic |
+ cricket::kMsidSignalingMediaSection |
+ cricket::kMsidSignalingSsrcAttribute)) {
// If both a=msid and a=ssrc MSID signaling methods were used, we're
// probably talking to a Unified Plan endpoint so respond with just
// a=msid.
- answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
+ answer->set_msid_signaling(cricket::kMsidSignalingSemantic |
+ cricket::kMsidSignalingMediaSection);
} else {
// Otherwise, it's clear which method the offerer is using so repeat that
// back to them.
- answer->set_msid_signaling(offer->msid_signaling());
+ answer->set_msid_signaling(msid_signaling);
}
} else {
// Plan B always signals MSID using a=ssrc lines.
- answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
+ answer->set_msid_signaling(cricket::kMsidSignalingSemantic |
+ cricket::kMsidSignalingSsrcAttribute);
}
return answer;
diff --git a/pc/peer_connection_interface_unittest.cc b/pc/peer_connection_interface_unittest.cc
index a1cd4b6..61794bb 100644
--- a/pc/peer_connection_interface_unittest.cc
+++ b/pc/peer_connection_interface_unittest.cc
@@ -2814,7 +2814,7 @@
// This tests that a default MediaStream is not created if a remote session
// description is updated to not have any MediaStreams.
// Don't run under Unified Plan since this behavior is Plan B specific.
-TEST_F(PeerConnectionInterfaceTestPlanB, VerifyDefaultStreamIsNotCreated) {
+TEST_F(PeerConnectionInterfaceTestPlanB, VerifyDefaultStreamIsNotRecreated) {
RTCConfiguration config;
CreatePeerConnection(config);
CreateAndSetRemoteOffer(GetSdpStringWithStream1());
@@ -2822,7 +2822,7 @@
EXPECT_TRUE(
CompareStreamCollections(observer_.remote_streams(), reference.get()));
- CreateAndSetRemoteOffer(kSdpStringWithoutStreams);
+ CreateAndSetRemoteOffer(kSdpStringWithMsidWithoutStreams);
EXPECT_EQ(0u, observer_.remote_streams()->count());
}
diff --git a/pc/peer_connection_rtp_unittest.cc b/pc/peer_connection_rtp_unittest.cc
index 1a97a4b..77c8cec 100644
--- a/pc/peer_connection_rtp_unittest.cc
+++ b/pc/peer_connection_rtp_unittest.cc
@@ -1836,14 +1836,16 @@
// Offer should have had both a=msid and a=ssrc MSID lines.
auto* offer = callee->pc()->remote_description();
- EXPECT_EQ((cricket::kMsidSignalingMediaSection |
- cricket::kMsidSignalingSsrcAttribute),
- offer->description()->msid_signaling());
+ EXPECT_EQ(
+ (cricket::kMsidSignalingSemantic | cricket::kMsidSignalingMediaSection |
+ cricket::kMsidSignalingSsrcAttribute),
+ offer->description()->msid_signaling());
// Answer should have had only a=msid lines.
auto* answer = caller->pc()->remote_description();
- EXPECT_EQ(cricket::kMsidSignalingMediaSection,
- answer->description()->msid_signaling());
+ EXPECT_EQ(
+ cricket::kMsidSignalingSemantic | cricket::kMsidSignalingMediaSection,
+ answer->description()->msid_signaling());
}
TEST_F(PeerConnectionMsidSignalingTest, PlanBOfferToUnifiedPlanAnswer) {
@@ -1856,13 +1858,15 @@
// Offer should have only a=ssrc MSID lines.
auto* offer = callee->pc()->remote_description();
- EXPECT_EQ(cricket::kMsidSignalingSsrcAttribute,
- offer->description()->msid_signaling());
+ EXPECT_EQ(
+ cricket::kMsidSignalingSemantic | cricket::kMsidSignalingSsrcAttribute,
+ offer->description()->msid_signaling());
// Answer should have only a=ssrc MSID lines to match the offer.
auto* answer = caller->pc()->remote_description();
- EXPECT_EQ(cricket::kMsidSignalingSsrcAttribute,
- answer->description()->msid_signaling());
+ EXPECT_EQ(
+ cricket::kMsidSignalingSemantic | cricket::kMsidSignalingSsrcAttribute,
+ answer->description()->msid_signaling());
}
// This tests that a Plan B endpoint appropriately sets the remote description
@@ -1884,9 +1888,10 @@
// Offer should have had both a=msid and a=ssrc MSID lines.
auto* offer = callee->pc()->remote_description();
- EXPECT_EQ((cricket::kMsidSignalingMediaSection |
- cricket::kMsidSignalingSsrcAttribute),
- offer->description()->msid_signaling());
+ EXPECT_EQ(
+ (cricket::kMsidSignalingSemantic | cricket::kMsidSignalingMediaSection |
+ cricket::kMsidSignalingSsrcAttribute),
+ offer->description()->msid_signaling());
// Callee should always have 1 stream for all of it's receivers.
const auto& track_events = callee->observer()->add_track_events_;
@@ -1907,7 +1912,8 @@
auto offer = caller->CreateOffer();
// Simulate a pure Unified Plan offerer by setting the MSID signaling to media
// section only.
- offer->description()->set_msid_signaling(cricket::kMsidSignalingMediaSection);
+ offer->description()->set_msid_signaling(cricket::kMsidSignalingSemantic |
+ cricket::kMsidSignalingMediaSection);
ASSERT_TRUE(
caller->SetLocalDescription(CloneSessionDescription(offer.get())));
@@ -1915,8 +1921,9 @@
// Answer should have only a=msid to match the offer.
auto answer = callee->CreateAnswer();
- EXPECT_EQ(cricket::kMsidSignalingMediaSection,
- answer->description()->msid_signaling());
+ EXPECT_EQ(
+ cricket::kMsidSignalingSemantic | cricket::kMsidSignalingMediaSection,
+ answer->description()->msid_signaling());
}
// Sender setups in a call.
diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc
index b61fbf5..d49506a 100644
--- a/pc/sdp_offer_answer.cc
+++ b/pc/sdp_offer_answer.cc
@@ -2078,24 +2078,16 @@
if (operation->unified_plan()) {
ApplyRemoteDescriptionUpdateTransceiverState(operation->type());
}
-
- const cricket::AudioContentDescription* audio_desc =
- GetFirstAudioContentDescription(remote_description()->description());
- const cricket::VideoContentDescription* video_desc =
- GetFirstVideoContentDescription(remote_description()->description());
-
- // Check if the descriptions include streams, just in case the peer supports
- // MSID, but doesn't indicate so with "a=msid-semantic".
- if (remote_description()->description()->msid_supported() ||
- (audio_desc && !audio_desc->streams().empty()) ||
- (video_desc && !video_desc->streams().empty())) {
- remote_peer_supports_msid_ = true;
- }
+ remote_peer_supports_msid_ =
+ remote_description()->description()->msid_signaling() !=
+ cricket::kMsidSignalingNotUsed;
if (!operation->unified_plan()) {
PlanBUpdateSendersAndReceivers(
- GetFirstAudioContent(remote_description()->description()), audio_desc,
- GetFirstVideoContent(remote_description()->description()), video_desc);
+ GetFirstAudioContent(remote_description()->description()),
+ GetFirstAudioContentDescription(remote_description()->description()),
+ GetFirstVideoContent(remote_description()->description()),
+ GetFirstVideoContentDescription(remote_description()->description()));
}
if (operation->type() == SdpType::kAnswer) {
diff --git a/pc/sdp_offer_answer_unittest.cc b/pc/sdp_offer_answer_unittest.cc
index f178e7b..8d4aa1f 100644
--- a/pc/sdp_offer_answer_unittest.cc
+++ b/pc/sdp_offer_answer_unittest.cc
@@ -1005,6 +1005,53 @@
}
}
+TEST_F(SdpOfferAnswerTest, MsidSignalingInSubsequentOfferAnswer) {
+ auto pc = CreatePeerConnection();
+ pc->AddAudioTrack("audio_track", {});
+
+ 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=msid-semantic: WMS\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 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=rtpmap:111 opus/48000/2\r\n";
+
+ auto offer = CreateSessionDescription(SdpType::kOffer, sdp);
+ EXPECT_TRUE(pc->SetRemoteDescription(std::move(offer)));
+
+ // Check the generated SDP.
+ auto answer = pc->CreateAnswer();
+ answer->ToString(&sdp);
+ EXPECT_NE(std::string::npos, sdp.find("a=msid:- audio_track\r\n"));
+
+ EXPECT_TRUE(pc->SetLocalDescription(std::move(answer)));
+
+ // Check the local description object.
+ auto local_description = pc->pc()->local_description();
+ ASSERT_EQ(local_description->description()->contents().size(), 1u);
+ auto streams = local_description->description()
+ ->contents()[0]
+ .media_description()
+ ->streams();
+ ASSERT_EQ(streams.size(), 1u);
+ EXPECT_EQ(streams[0].id, "audio_track");
+
+ // Check the serialization of the local description.
+ local_description->ToString(&sdp);
+ EXPECT_NE(std::string::npos, sdp.find("a=msid:- audio_track\r\n"));
+}
+
// Test variant with boolean order for audio-video and video-audio.
class SdpOfferAnswerShuffleMediaTypes
: public SdpOfferAnswerTest,
diff --git a/pc/session_description.h b/pc/session_description.h
index 403e465..6c2477d 100644
--- a/pc/session_description.h
+++ b/pc/session_description.h
@@ -468,13 +468,23 @@
const ContentInfo* FindContentInfoByType(const ContentInfos& contents,
const std::string& type);
-// Determines how the MSID will be signaled in the SDP. These can be used as
-// flags to indicate both or none.
+// Determines how the MSID will be signaled in the SDP.
+// These can be used as bit flags to indicate both or the special value none.
enum MsidSignaling {
- // Signal MSID with one a=msid line in the media section.
+ // MSID is not signaled. This is not a bit flag and must be compared for
+ // equality.
+ kMsidSignalingNotUsed = 0x0,
+ // Signal MSID with at least one a=msid line in the media section.
+ // This requires unified plan.
kMsidSignalingMediaSection = 0x1,
// Signal MSID with a=ssrc: msid lines in the media section.
- kMsidSignalingSsrcAttribute = 0x2
+ // This should only be used with plan-b but is signalled in
+ // offers for backward compability reasons.
+ kMsidSignalingSsrcAttribute = 0x2,
+ // Signal MSID with a=msid-semantic: WMS in the session section.
+ // This is deprecated but signalled for backward compability reasons.
+ // It is typically combined with 0x1 or 0x2.
+ kMsidSignalingSemantic = 0x4
};
// Describes a collection of contents, each with its own name and
@@ -548,9 +558,6 @@
void RemoveGroupByName(const std::string& name);
// Global attributes.
- void set_msid_supported(bool supported) { msid_supported_ = supported; }
- bool msid_supported() const { return msid_supported_; }
-
// Determines how the MSIDs were/will be signaled. Flag value composed of
// MsidSignaling bits (see enum above).
void set_msid_signaling(int msid_signaling) {
@@ -582,10 +589,9 @@
ContentInfos contents_;
TransportInfos transport_infos_;
ContentGroups content_groups_;
- bool msid_supported_ = true;
// Default to what Plan B would do.
// TODO(bugs.webrtc.org/8530): Change default to kMsidSignalingMediaSection.
- int msid_signaling_ = kMsidSignalingSsrcAttribute;
+ int msid_signaling_ = kMsidSignalingSsrcAttribute | kMsidSignalingSemantic;
bool extmap_allow_mixed_ = true;
};
diff --git a/pc/test/integration_test_helpers.cc b/pc/test/integration_test_helpers.cc
index 64d8deb..1f603ad 100644
--- a/pc/test/integration_test_helpers.cc
+++ b/pc/test/integration_test_helpers.cc
@@ -22,7 +22,6 @@
for (ContentInfo& content : desc->contents()) {
content.media_description()->mutable_streams().clear();
}
- desc->set_msid_supported(false);
desc->set_msid_signaling(0);
}
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
index 8bd8d36..fe31826 100644
--- a/pc/webrtc_sdp.cc
+++ b/pc/webrtc_sdp.cc
@@ -722,7 +722,7 @@
// This is the case with Plan B SDP msid signaling.
stream_ids.push_back(ssrc_info.stream_id);
track_id = ssrc_info.track_id;
- } else {
+ } else if (msid_signaling == cricket::kMsidSignalingNotUsed) {
// Since no media streams isn't supported with older SDP signaling, we
// use a default stream id.
stream_ids.push_back(kDefaultMsid);
@@ -924,6 +924,9 @@
InitAttrLine(kAttributeMsidSemantics, &os);
os << kSdpDelimiterColon << " " << kMediaStreamSemantic;
+ // TODO(bugs.webrtc.org/10421): this code only looks at the first audio/video
+ // content. Fixing that might result in much larger SDP and the msid-semantic
+ // line should eventually go away so this is not worth fixing.
std::set<std::string> media_stream_ids;
const ContentInfo* audio_content = GetFirstAudioContent(desc);
if (audio_content)
@@ -2131,7 +2134,7 @@
SdpParseError* error) {
absl::optional<absl::string_view> line;
- desc->set_msid_supported(false);
+ desc->set_msid_signaling(cricket::kMsidSignalingNotUsed);
desc->set_extmap_allow_mixed(false);
// RFC 4566
// v= (protocol version)
@@ -2273,8 +2276,9 @@
if (!GetValue(*aline, kAttributeMsidSemantics, &semantics, error)) {
return false;
}
- desc->set_msid_supported(
- CaseInsensitiveFind(semantics, kMediaStreamSemantic));
+ if (CaseInsensitiveFind(semantics, kMediaStreamSemantic)) {
+ desc->set_msid_signaling(cricket::kMsidSignalingSemantic);
+ }
} else if (HasAttribute(*aline, kAttributeExtmapAllowMixed)) {
desc->set_extmap_allow_mixed(true);
} else if (HasAttribute(*aline, kAttributeExtmap)) {
@@ -2694,7 +2698,7 @@
SdpParseError* error) {
RTC_DCHECK(desc != NULL);
int mline_index = -1;
- int msid_signaling = 0;
+ int msid_signaling = desc->msid_signaling();
// Zero or more media descriptions
// RFC 4566
@@ -2746,7 +2750,7 @@
std::unique_ptr<MediaContentDescription> content;
std::string content_name;
bool bundle_only = false;
- int section_msid_signaling = 0;
+ int section_msid_signaling = cricket::kMsidSignalingNotUsed;
absl::string_view media_type = fields[0];
if ((media_type == kMediaTypeVideo || media_type == kMediaTypeAudio) &&
!cricket::IsRtpProtocol(protocol)) {
diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc
index bc79d17..bbbbb57 100644
--- a/pc/webrtc_sdp_unittest.cc
+++ b/pc/webrtc_sdp_unittest.cc
@@ -1219,7 +1219,8 @@
absl::WrapUnique(video_desc_3));
desc_.AddTransportInfo(TransportInfo(
kVideoContentName3, TransportDescription(kUfragVideo3, kPwdVideo3)));
- desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
+ desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection |
+ cricket::kMsidSignalingSemantic);
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
jdesc_.session_version()));
@@ -1299,7 +1300,8 @@
absl::WrapUnique(audio_desc));
// Enable signaling a=msid lines.
- desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
+ desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection |
+ cricket::kMsidSignalingSemantic);
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
jdesc_.session_version()));
}
@@ -1508,7 +1510,7 @@
}
// global attributes
- EXPECT_EQ(desc1.msid_supported(), desc2.msid_supported());
+ EXPECT_EQ(desc1.msid_signaling(), desc2.msid_signaling());
EXPECT_EQ(desc1.extmap_allow_mixed(), desc2.extmap_allow_mixed());
}
@@ -3751,7 +3753,7 @@
// Create both msid lines for Plan B and Unified Plan support.
MakeUnifiedPlanDescriptionMultipleStreamIds(
cricket::kMsidSignalingMediaSection |
- cricket::kMsidSignalingSsrcAttribute);
+ cricket::kMsidSignalingSsrcAttribute | cricket::kMsidSignalingSemantic);
JsepSessionDescription deserialized_description(kDummyType);
EXPECT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullStringWithSpecialMsid,
@@ -3759,7 +3761,8 @@
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
EXPECT_EQ(cricket::kMsidSignalingMediaSection |
- cricket::kMsidSignalingSsrcAttribute,
+ cricket::kMsidSignalingSsrcAttribute |
+ cricket::kMsidSignalingSemantic,
deserialized_description.description()->msid_signaling());
}
@@ -3771,7 +3774,7 @@
// Create both msid lines for Plan B and Unified Plan support.
MakeUnifiedPlanDescriptionMultipleStreamIds(
cricket::kMsidSignalingMediaSection |
- cricket::kMsidSignalingSsrcAttribute);
+ cricket::kMsidSignalingSsrcAttribute | cricket::kMsidSignalingSemantic);
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
@@ -3787,7 +3790,7 @@
TEST_F(WebRtcSdpTest, UnifiedPlanDeserializeSessionDescriptionSpecialMsid) {
// Only create a=msid lines for strictly Unified Plan stream ID support.
MakeUnifiedPlanDescriptionMultipleStreamIds(
- cricket::kMsidSignalingMediaSection);
+ cricket::kMsidSignalingMediaSection | cricket::kMsidSignalingSemantic);
JsepSessionDescription deserialized_description(kDummyType);
std::string unified_plan_sdp_string =
@@ -3805,7 +3808,7 @@
TEST_F(WebRtcSdpTest, UnifiedPlanSerializeSessionDescriptionSpecialMsid) {
// Only create a=msid lines for strictly Unified Plan stream ID support.
MakeUnifiedPlanDescriptionMultipleStreamIds(
- cricket::kMsidSignalingMediaSection);
+ cricket::kMsidSignalingMediaSection | cricket::kMsidSignalingSemantic);
TestSerialize(jdesc_);
}
@@ -3837,7 +3840,8 @@
TEST_F(WebRtcSdpTest, EmptyDescriptionHasNoMsidSignaling) {
JsepSessionDescription jsep_desc(kDummyType);
ASSERT_TRUE(SdpDeserialize(kSdpSessionString, &jsep_desc));
- EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
+ EXPECT_EQ(cricket::kMsidSignalingSemantic,
+ jsep_desc.description()->msid_signaling());
}
TEST_F(WebRtcSdpTest, DataChannelOnlyHasNoMsidSignaling) {
@@ -3845,21 +3849,24 @@
std::string sdp = kSdpSessionString;
sdp += kSdpSctpDataChannelString;
ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
- EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
+ EXPECT_EQ(cricket::kMsidSignalingSemantic,
+ jsep_desc.description()->msid_signaling());
}
TEST_F(WebRtcSdpTest, PlanBHasSsrcAttributeMsidSignaling) {
JsepSessionDescription jsep_desc(kDummyType);
ASSERT_TRUE(SdpDeserialize(kPlanBSdpFullString, &jsep_desc));
- EXPECT_EQ(cricket::kMsidSignalingSsrcAttribute,
- jsep_desc.description()->msid_signaling());
+ EXPECT_EQ(
+ cricket::kMsidSignalingSsrcAttribute | cricket::kMsidSignalingSemantic,
+ jsep_desc.description()->msid_signaling());
}
TEST_F(WebRtcSdpTest, UnifiedPlanHasMediaSectionMsidSignaling) {
JsepSessionDescription jsep_desc(kDummyType);
ASSERT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullString, &jsep_desc));
- EXPECT_EQ(cricket::kMsidSignalingMediaSection,
- jsep_desc.description()->msid_signaling());
+ EXPECT_EQ(
+ cricket::kMsidSignalingMediaSection | cricket::kMsidSignalingSemantic,
+ jsep_desc.description()->msid_signaling());
}
const char kMediaSectionMsidLine[] = "a=msid:local_stream_1 audio_track_id_1";