Add MSID signaling compatibility for Unified Plan endpoints
This is intended to ensure compatibility between Plan B and
Unified Plan endpoints for the single audio - single video case.
If Unified Plan is the offerer, it will add a=msid and a=ssrc MSID
entries to its offer.
If Unified Plan is the answerer, it will use whatever MSID
signaling mechanism was used in the offer (either a=msid or
a=ssrc).
Bug: webrtc:7600
Change-Id: I6192dec19123fbb56f5d04540d2175c7fb30b9b6
Reviewed-on: https://webrtc-review.googlesource.com/44162
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21859}
diff --git a/pc/jsepsessiondescription.cc b/pc/jsepsessiondescription.cc
index 91840e3..ecd2ee2 100644
--- a/pc/jsepsessiondescription.cc
+++ b/pc/jsepsessiondescription.cc
@@ -273,7 +273,7 @@
if (!description_ || !out) {
return false;
}
- *out = SdpSerialize(*this, false);
+ *out = SdpSerialize(*this);
return !out->empty();
}
diff --git a/pc/mediasession.cc b/pc/mediasession.cc
index 3f750d1..a2f47dc 100644
--- a/pc/mediasession.cc
+++ b/pc/mediasession.cc
@@ -1375,6 +1375,20 @@
return nullptr;
}
}
+
+ // The following determines how to signal MSIDs to ensure compatibility with
+ // older endpoints (in particular, older Plan B endpoints).
+ if (session_options.is_unified_plan) {
+ // 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 |
+ cricket::kMsidSignalingSsrcAttribute);
+ } else {
+ // Plan B always signals MSID using a=ssrc lines.
+ offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
+ }
+
return offer.release();
}
@@ -1500,6 +1514,39 @@
}
}
+ // The following determines how to signal MSIDs to ensure compatibility with
+ // older endpoints (in particular, older Plan B endpoints).
+ if (session_options.is_unified_plan) {
+ // Unified Plan needs to look at what the offer included to find the most
+ // compatible answer.
+ if (offer->msid_signaling() == 0) {
+ // 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.
+ // 2. A data channel only offer. We won't add any MSIDs to the answer so
+ // it also doesn't matter what we pick here.
+ // 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 |
+ cricket::kMsidSignalingSsrcAttribute);
+ } else if (offer->msid_signaling() ==
+ (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);
+ } else {
+ // Otherwise, it's clear which method the offerer is using so repeat that
+ // back to them.
+ answer->set_msid_signaling(offer->msid_signaling());
+ }
+ } else {
+ // Plan B always signals MSID using a=ssrc lines.
+ answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
+ }
+
return answer.release();
}
diff --git a/pc/mediasession.h b/pc/mediasession.h
index 02205c6..9b118e1 100644
--- a/pc/mediasession.h
+++ b/pc/mediasession.h
@@ -94,6 +94,7 @@
bool vad_enabled = true; // When disabled, removes all CN codecs from SDP.
bool rtcp_mux_enabled = true;
bool bundle_enabled = false;
+ bool is_unified_plan = false;
std::string rtcp_cname = kDefaultRtcpCname;
rtc::CryptoOptions crypto_options;
// List of media description options in the same order that the media
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index c361468..ca97e81 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -3199,6 +3199,7 @@
session_options->rtcp_cname = rtcp_cname_;
session_options->crypto_options = factory_->options().crypto_options;
+ session_options->is_unified_plan = IsUnifiedPlan();
}
void PeerConnection::GetOptionsForPlanBOffer(
@@ -3457,6 +3458,7 @@
session_options->rtcp_cname = rtcp_cname_;
session_options->crypto_options = factory_->options().crypto_options;
+ session_options->is_unified_plan = IsUnifiedPlan();
}
void PeerConnection::GetOptionsForPlanBAnswer(
diff --git a/pc/peerconnection_rtp_unittest.cc b/pc/peerconnection_rtp_unittest.cc
index 12e58b7..f19388f 100644
--- a/pc/peerconnection_rtp_unittest.cc
+++ b/pc/peerconnection_rtp_unittest.cc
@@ -19,6 +19,7 @@
#include "pc/mediastream.h"
#include "pc/mediastreamtrack.h"
#include "pc/peerconnectionwrapper.h"
+#include "pc/sdputils.h"
#include "pc/test/fakeaudiocapturemodule.h"
#include "pc/test/mockpeerconnectionobservers.h"
#include "rtc_base/checks.h"
@@ -74,6 +75,12 @@
return CreatePeerConnection(RTCConfiguration());
}
+ std::unique_ptr<PeerConnectionWrapper> CreatePeerConnectionWithPlanB() {
+ RTCConfiguration config;
+ config.sdp_semantics = SdpSemantics::kPlanB;
+ return CreatePeerConnection(config);
+ }
+
std::unique_ptr<PeerConnectionWrapper> CreatePeerConnectionWithUnifiedPlan() {
RTCConfiguration config;
config.sdp_semantics = SdpSemantics::kUnifiedPlan;
@@ -866,6 +873,75 @@
EXPECT_FALSE(caller->observer()->negotiation_needed());
}
+// Test MSID signaling between Unified Plan and Plan B endpoints. There are two
+// options for this kind of signaling: media section based (a=msid) and ssrc
+// based (a=ssrc MSID). While JSEP only specifies media section MSID signaling,
+// we want to ensure compatibility with older Plan B endpoints that might expect
+// ssrc based MSID signaling. Thus we test here that Unified Plan offers both
+// types but answers with the same type as the offer.
+
+class PeerConnectionMsidSignalingTest : public PeerConnectionRtpTest {};
+
+TEST_F(PeerConnectionMsidSignalingTest, UnifiedPlanTalkingToOurself) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+ caller->AddAudioTrack("caller_audio");
+ auto callee = CreatePeerConnectionWithUnifiedPlan();
+ callee->AddAudioTrack("callee_audio");
+
+ ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
+
+ // 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());
+
+ // Answer should have had only a=msid lines.
+ auto* answer = caller->pc()->remote_description();
+ EXPECT_EQ(cricket::kMsidSignalingMediaSection,
+ answer->description()->msid_signaling());
+}
+
+TEST_F(PeerConnectionMsidSignalingTest, PlanBOfferToUnifiedPlanAnswer) {
+ auto caller = CreatePeerConnectionWithPlanB();
+ caller->AddAudioTrack("caller_audio");
+ auto callee = CreatePeerConnectionWithUnifiedPlan();
+ callee->AddAudioTrack("callee_audio");
+
+ ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
+
+ // Offer should have only a=ssrc MSID lines.
+ auto* offer = callee->pc()->remote_description();
+ EXPECT_EQ(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());
+}
+
+TEST_F(PeerConnectionMsidSignalingTest, PureUnifiedPlanToUs) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+ caller->AddAudioTrack("caller_audio");
+ auto callee = CreatePeerConnectionWithUnifiedPlan();
+ callee->AddAudioTrack("callee_audio");
+
+ 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);
+
+ ASSERT_TRUE(
+ caller->SetLocalDescription(CloneSessionDescription(offer.get())));
+ ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
+
+ // Answer should have only a=msid to match the offer.
+ auto answer = callee->CreateAnswer();
+ EXPECT_EQ(cricket::kMsidSignalingMediaSection,
+ answer->description()->msid_signaling());
+}
+
// Sender setups in a call.
class PeerConnectionSenderTest : public PeerConnectionRtpTest {};
diff --git a/pc/sessiondescription.h b/pc/sessiondescription.h
index b2cdee9..645ebc5 100644
--- a/pc/sessiondescription.h
+++ b/pc/sessiondescription.h
@@ -363,6 +363,15 @@
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.
+enum MsidSignaling {
+ // Signal MSID with one a=msid line in the media section.
+ kMsidSignalingMediaSection = 0x1,
+ // Signal MSID with a=ssrc: msid lines in the media section.
+ kMsidSignalingSsrcAttribute = 0x2
+};
+
// Describes a collection of contents, each with its own name and
// type. Analogous to a <jingle> or <session> stanza. Assumes that
// contents are unique be name, but doesn't enforce that.
@@ -439,6 +448,13 @@
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) {
+ msid_signaling_ = msid_signaling;
+ }
+ int msid_signaling() const { return msid_signaling_; }
+
private:
SessionDescription(const SessionDescription&);
@@ -446,6 +462,9 @@
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;
};
// Indicates whether a session description was sent by the local client or
diff --git a/pc/webrtcsdp.cc b/pc/webrtcsdp.cc
index 56f4c99..535ed23 100644
--- a/pc/webrtcsdp.cc
+++ b/pc/webrtcsdp.cc
@@ -232,14 +232,14 @@
const TransportInfo* transport_info,
const MediaType media_type,
const std::vector<Candidate>& candidates,
- bool unified_plan_sdp,
+ int msid_signaling,
std::string* message);
static void BuildSctpContentAttributes(std::string* message,
int sctp_port,
bool use_sctpmap);
static void BuildRtpContentAttributes(const MediaContentDescription* media_desc,
const MediaType media_type,
- bool unified_plan_sdp,
+ int msid_signaling,
std::string* message);
static void BuildRtpMap(const MediaContentDescription* media_desc,
const MediaType media_type,
@@ -280,12 +280,14 @@
size_t* pos,
std::string* content_name,
bool* bundle_only,
+ int* msid_signaling,
MediaContentDescription* media_desc,
TransportDescription* transport,
std::vector<JsepIceCandidate*>* candidates,
SdpParseError* error);
static bool ParseSsrcAttribute(const std::string& line,
SsrcInfoVec* ssrc_infos,
+ int* msid_signaling,
SdpParseError* error);
static bool ParseSsrcGroupAttribute(const std::string& line,
SsrcGroupVec* ssrc_groups,
@@ -601,7 +603,7 @@
track_id = ssrc_info->label;
} else if (ssrc_info->stream_id.empty() && !msid_stream_id.empty()) {
// If there's no msid in the SSRC attributes, but there's a global one
- // (from a=msid), use that. This is the case with unified plan SDP.
+ // (from a=msid), use that. This is the case with Unified Plan SDP.
stream_id = msid_stream_id;
track_id = msid_track_id;
} else {
@@ -757,8 +759,7 @@
return port >= 0 && port <= 65535;
}
-std::string SdpSerialize(const JsepSessionDescription& jdesc,
- bool unified_plan_sdp) {
+std::string SdpSerialize(const JsepSessionDescription& jdesc) {
const cricket::SessionDescription* desc = jdesc.description();
if (!desc) {
return "";
@@ -829,7 +830,7 @@
std::vector<Candidate> candidates;
GetCandidatesByMindex(jdesc, ++mline_index, &candidates);
BuildMediaDescription(&*it, desc->GetTransportInfoByName(it->name),
- mdesc->type(), candidates, unified_plan_sdp,
+ mdesc->type(), candidates, desc->msid_signaling(),
&message);
}
return message;
@@ -1199,7 +1200,7 @@
const TransportInfo* transport_info,
const MediaType media_type,
const std::vector<Candidate>& candidates,
- bool unified_plan_sdp,
+ int msid_signaling,
std::string* message) {
RTC_DCHECK(message != NULL);
if (content_info == NULL || message == NULL) {
@@ -1405,8 +1406,7 @@
bool use_sctpmap = data_desc->use_sctpmap();
BuildSctpContentAttributes(message, sctp_port, use_sctpmap);
} else if (IsRtp(media_desc->protocol())) {
- BuildRtpContentAttributes(media_desc, media_type, unified_plan_sdp,
- message);
+ BuildRtpContentAttributes(media_desc, media_type, msid_signaling, message);
}
}
@@ -1431,10 +1431,9 @@
AddLine(os.str(), message);
}
-// If unified_plan_sdp is true, will use "a=msid".
void BuildRtpContentAttributes(const MediaContentDescription* media_desc,
const MediaType media_type,
- bool unified_plan_sdp,
+ int msid_signaling,
std::string* message) {
std::ostringstream os;
// RFC 5285
@@ -1471,19 +1470,20 @@
}
AddLine(os.str(), message);
- // draft-ietf-mmusic-msid-11
+ // Specified in https://tools.ietf.org/html/draft-ietf-mmusic-msid-16
// a=msid:<stream id> <track id>
- if (unified_plan_sdp && !media_desc->streams().empty()) {
- if (media_desc->streams().size() > 1u) {
- RTC_LOG(LS_WARNING)
- << "Trying to serialize unified plan SDP with more than "
- << "one track in a media section. Omitting 'a=msid'.";
- } else {
- auto track = media_desc->streams().begin();
- const std::string& stream_id = track->sync_label;
+ if (msid_signaling & cricket::kMsidSignalingMediaSection) {
+ const StreamParamsVec& streams = media_desc->streams();
+ if (streams.size() == 1u) {
+ const StreamParams& track = streams[0];
+ const std::string& stream_id = track.sync_label;
InitAttrLine(kAttributeMsid, &os);
- os << kSdpDelimiterColon << stream_id << kSdpDelimiterSpace << track->id;
+ os << kSdpDelimiterColon << stream_id << kSdpDelimiterSpace << track.id;
AddLine(os.str(), message);
+ } else if (streams.size() > 1u) {
+ RTC_LOG(LS_WARNING)
+ << "Trying to serialize Unified Plan SDP with more than "
+ << "one track in a media section. Omitting 'a=msid'.";
}
}
@@ -1558,25 +1558,27 @@
AddSsrcLine(ssrc, kSsrcAttributeCname,
track->cname, message);
- // draft-alvestrand-mmusic-msid-00
- // a=ssrc:<ssrc-id> msid:identifier [appdata]
- // The appdata consists of the "id" attribute of a MediaStreamTrack,
- // which corresponds to the "id" attribute of StreamParams.
- const std::string& stream_id = track->sync_label;
- InitAttrLine(kAttributeSsrc, &os);
- os << kSdpDelimiterColon << ssrc << kSdpDelimiterSpace
- << kSsrcAttributeMsid << kSdpDelimiterColon << stream_id
- << kSdpDelimiterSpace << track->id;
- AddLine(os.str(), message);
+ if (msid_signaling & cricket::kMsidSignalingSsrcAttribute) {
+ // draft-alvestrand-mmusic-msid-00
+ // a=ssrc:<ssrc-id> msid:identifier [appdata]
+ // The appdata consists of the "id" attribute of a MediaStreamTrack,
+ // which corresponds to the "id" attribute of StreamParams.
+ const std::string& stream_id = track->sync_label;
+ InitAttrLine(kAttributeSsrc, &os);
+ os << kSdpDelimiterColon << ssrc << kSdpDelimiterSpace
+ << kSsrcAttributeMsid << kSdpDelimiterColon << stream_id
+ << kSdpDelimiterSpace << track->id;
+ AddLine(os.str(), message);
- // TODO(ronghuawu): Remove below code which is for backward
- // compatibility.
- // draft-alvestrand-rtcweb-mid-01
- // a=ssrc:<ssrc-id> mslabel:<value>
- // The label isn't yet defined.
- // a=ssrc:<ssrc-id> label:<value>
- AddSsrcLine(ssrc, kSsrcAttributeMslabel, track->sync_label, message);
- AddSsrcLine(ssrc, kSSrcAttributeLabel, track->id, message);
+ // TODO(ronghuawu): Remove below code which is for backward
+ // compatibility.
+ // draft-alvestrand-rtcweb-mid-01
+ // a=ssrc:<ssrc-id> mslabel:<value>
+ // The label isn't yet defined.
+ // a=ssrc:<ssrc-id> label:<value>
+ AddSsrcLine(ssrc, kSsrcAttributeMslabel, track->sync_label, message);
+ AddSsrcLine(ssrc, kSSrcAttributeLabel, track->id, message);
+ }
}
}
}
@@ -2294,6 +2296,7 @@
size_t* pos,
std::string* content_name,
bool* bundle_only,
+ int* msid_signaling,
TransportDescription* transport,
std::vector<JsepIceCandidate*>* candidates,
webrtc::SdpParseError* error) {
@@ -2313,8 +2316,8 @@
break;
}
if (!ParseContent(message, media_type, mline_index, protocol, payload_types,
- pos, content_name, bundle_only, media_desc, transport,
- candidates, error)) {
+ pos, content_name, bundle_only, msid_signaling, media_desc,
+ transport, candidates, error)) {
delete media_desc;
return nullptr;
}
@@ -2348,6 +2351,7 @@
RTC_DCHECK(desc != NULL);
std::string line;
int mline_index = -1;
+ int msid_signaling = 0;
// Zero or more media descriptions
// RFC 4566
@@ -2405,22 +2409,23 @@
std::unique_ptr<MediaContentDescription> content;
std::string content_name;
bool bundle_only = false;
+ int section_msid_signaling = 0;
if (HasAttribute(line, kMediaTypeVideo)) {
content.reset(ParseContentDescription<VideoContentDescription>(
message, cricket::MEDIA_TYPE_VIDEO, mline_index, protocol,
- payload_types, pos, &content_name, &bundle_only, &transport,
- candidates, error));
+ payload_types, pos, &content_name, &bundle_only,
+ §ion_msid_signaling, &transport, candidates, error));
} else if (HasAttribute(line, kMediaTypeAudio)) {
content.reset(ParseContentDescription<AudioContentDescription>(
message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol,
- payload_types, pos, &content_name, &bundle_only, &transport,
- candidates, error));
+ payload_types, pos, &content_name, &bundle_only,
+ §ion_msid_signaling, &transport, candidates, error));
} else if (HasAttribute(line, kMediaTypeData)) {
DataContentDescription* data_desc =
ParseContentDescription<DataContentDescription>(
message, cricket::MEDIA_TYPE_DATA, mline_index, protocol,
- payload_types, pos, &content_name, &bundle_only, &transport,
- candidates, error);
+ payload_types, pos, &content_name, &bundle_only,
+ §ion_msid_signaling, &transport, candidates, error);
content.reset(data_desc);
if (data_desc && IsDtlsSctp(protocol)) {
@@ -2442,6 +2447,8 @@
return false;
}
+ msid_signaling |= section_msid_signaling;
+
bool content_rejected = false;
// A port of 0 is not interpreted as a rejected m= section when it's
// used along with a=bundle-only.
@@ -2500,6 +2507,8 @@
}
}
+ desc->set_msid_signaling(msid_signaling);
+
size_t end_of_message = message.size();
if (mline_index == -1 && *pos != end_of_message) {
ParseFailed(message, *pos, "Expects m line.", error);
@@ -2665,6 +2674,7 @@
size_t* pos,
std::string* content_name,
bool* bundle_only,
+ int* msid_signaling,
MediaContentDescription* media_desc,
TransportDescription* transport,
std::vector<JsepIceCandidate*>* candidates,
@@ -2839,7 +2849,7 @@
return false;
}
} else if (HasAttribute(line, kAttributeSsrc)) {
- if (!ParseSsrcAttribute(line, &ssrc_infos, error)) {
+ if (!ParseSsrcAttribute(line, &ssrc_infos, msid_signaling, error)) {
return false;
}
} else if (HasAttribute(line, kAttributeCrypto)) {
@@ -2891,6 +2901,7 @@
if (!ParseMsidAttribute(line, &stream_id, &track_id, error)) {
return false;
}
+ *msid_signaling |= cricket::kMsidSignalingMediaSection;
}
} else {
// Only parse lines that we are interested of.
@@ -2963,7 +2974,9 @@
return true;
}
-bool ParseSsrcAttribute(const std::string& line, SsrcInfoVec* ssrc_infos,
+bool ParseSsrcAttribute(const std::string& line,
+ SsrcInfoVec* ssrc_infos,
+ int* msid_signaling,
SdpParseError* error) {
RTC_DCHECK(ssrc_infos != NULL);
// RFC 5576
@@ -3029,6 +3042,7 @@
if (fields.size() == 2) {
ssrc_info->track_id = fields[1];
}
+ *msid_signaling |= cricket::kMsidSignalingSsrcAttribute;
} else if (attribute == kSsrcAttributeMslabel) {
// draft-alvestrand-rtcweb-mid-01
// mslabel:<value>
diff --git a/pc/webrtcsdp.h b/pc/webrtcsdp.h
index 83cc768..2d842a1 100644
--- a/pc/webrtcsdp.h
+++ b/pc/webrtcsdp.h
@@ -38,8 +38,7 @@
// jdesc - The JsepSessionDescription object to be serialized.
// unified_plan_sdp - If set to true, include "a=msid" lines where appropriate.
// return - SDP string serialized from the arguments.
-std::string SdpSerialize(const JsepSessionDescription& jdesc,
- bool unified_plan_sdp);
+std::string SdpSerialize(const JsepSessionDescription& jdesc);
// Serializes the passed in IceCandidateInterface to a SDP string.
// candidate - The candidate to be serialized.
diff --git a/pc/webrtcsdp_unittest.cc b/pc/webrtcsdp_unittest.cc
index 831d236..c268b04 100644
--- a/pc/webrtcsdp_unittest.cc
+++ b/pc/webrtcsdp_unittest.cc
@@ -1119,6 +1119,7 @@
desc_.AddContent(kVideoContentName3, MediaProtocolType::kRtp, video_desc_3);
EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
kVideoContentName3, TransportDescription(kUfragVideo3, kPwdVideo3))));
+ desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(), jdesc_.session_id(),
jdesc_.session_version()));
@@ -1464,7 +1465,7 @@
jdesc_.session_version())) {
return false;
}
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
EXPECT_EQ(new_sdp, message);
return true;
}
@@ -1489,7 +1490,7 @@
JsepSessionDescription jdesc_no_candidates(kDummyType);
MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
- std::string message = webrtc::SdpSerialize(jdesc_no_candidates, false);
+ std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
EXPECT_EQ(new_sdp, message);
return true;
}
@@ -1759,9 +1760,8 @@
// no order. If deserializer has already been tested, serializing then
// deserializing and comparing JsepSessionDescription will test
// the serializer sufficiently.
- void TestSerialize(const JsepSessionDescription& jdesc,
- bool unified_plan_sdp) {
- std::string message = webrtc::SdpSerialize(jdesc, unified_plan_sdp);
+ void TestSerialize(const JsepSessionDescription& jdesc) {
+ std::string message = webrtc::SdpSerialize(jdesc);
JsepSessionDescription jdesc_output_des(kDummyType);
SdpParseError error;
EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
@@ -1806,13 +1806,13 @@
TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
// SessionDescription with desc and candidates.
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
TestMismatch(std::string(kSdpFullString), message);
}
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
JsepSessionDescription jdesc_empty(kDummyType);
- EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty, false));
+ EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
}
// This tests serialization of SDP with a=crypto and a=fingerprint, as would be
@@ -1821,7 +1821,7 @@
AddFingerprint();
JsepSessionDescription jdesc_with_fingerprint(kDummyType);
MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
- std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint, false);
+ std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
std::string sdp_with_fingerprint = kSdpString;
InjectAfter(kAttributeIcePwdVoice,
@@ -1839,7 +1839,7 @@
RemoveCryptos();
JsepSessionDescription jdesc_with_fingerprint(kDummyType);
MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
- std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint, false);
+ std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
std::string sdp_with_fingerprint = kSdpString;
Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
@@ -1856,7 +1856,7 @@
// JsepSessionDescription with desc but without candidates.
JsepSessionDescription jdesc_no_candidates(kDummyType);
MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
- std::string message = webrtc::SdpSerialize(jdesc_no_candidates, false);
+ std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
EXPECT_EQ(std::string(kSdpString), message);
}
@@ -1868,7 +1868,7 @@
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
jdesc_.session_id(),
jdesc_.session_version()));
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
std::string sdp_with_bundle = kSdpFullString;
InjectAfter(kSessionTime,
"a=group:BUNDLE audio_content_name video_content_name\r\n",
@@ -1884,7 +1884,7 @@
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
jdesc_.session_id(),
jdesc_.session_version()));
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
std::string sdp_with_bandwidth = kSdpFullString;
InjectAfter("c=IN IP4 74.125.224.39\r\n",
"b=AS:100\r\n",
@@ -1907,7 +1907,7 @@
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
jdesc_.session_id(),
jdesc_.session_version()));
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
std::string sdp_with_ice_options = kSdpFullString;
InjectAfter(kAttributeIcePwdVoice,
"a=ice-options:iceoption1 iceoption3\r\n",
@@ -1947,7 +1947,7 @@
JsepSessionDescription jsep_desc(kDummyType);
MakeDescriptionWithoutCandidates(&jsep_desc);
- std::string message = webrtc::SdpSerialize(jsep_desc, false);
+ std::string message = webrtc::SdpSerialize(jsep_desc);
std::string expected_sdp = kSdpString;
expected_sdp.append(kSdpRtpDataChannelString);
@@ -1960,7 +1960,7 @@
JsepSessionDescription jsep_desc(kDummyType);
MakeDescriptionWithoutCandidates(&jsep_desc);
- std::string message = webrtc::SdpSerialize(jsep_desc, false);
+ std::string message = webrtc::SdpSerialize(jsep_desc);
std::string expected_sdp = kSdpString;
expected_sdp.append(kSdpSctpDataChannelString);
@@ -1983,7 +1983,7 @@
codec.SetParam(cricket::kCodecParamPort, kNewPort);
dcdesc->AddOrReplaceCodec(codec);
- std::string message = webrtc::SdpSerialize(jsep_desc, false);
+ std::string message = webrtc::SdpSerialize(jsep_desc);
std::string expected_sdp = kSdpString;
expected_sdp.append(kSdpSctpDataChannelString);
@@ -2005,7 +2005,7 @@
AddRtpDataChannel();
data_desc_->set_bandwidth(100*1000);
MakeDescriptionWithoutCandidates(&jsep_desc);
- std::string message = webrtc::SdpSerialize(jsep_desc, false);
+ std::string message = webrtc::SdpSerialize(jsep_desc);
std::string expected_sdp = kSdpString;
expected_sdp.append(kSdpRtpDataChannelString);
@@ -2021,7 +2021,7 @@
AddExtmap(encrypted);
JsepSessionDescription desc_with_extmap(kDummyType);
MakeDescriptionWithoutCandidates(&desc_with_extmap);
- std::string message = webrtc::SdpSerialize(desc_with_extmap, false);
+ std::string message = webrtc::SdpSerialize(desc_with_extmap);
std::string sdp_with_extmap = kSdpString;
InjectAfter("a=mid:audio_content_name\r\n",
@@ -2038,7 +2038,7 @@
JsepSessionDescription desc_with_extmap(kDummyType);
ASSERT_TRUE(desc_with_extmap.Initialize(desc_.Copy(),
kSessionId, kSessionVersion));
- TestSerialize(desc_with_extmap, false);
+ TestSerialize(desc_with_extmap);
}
TEST_F(WebRtcSdpTest, SerializeCandidates) {
@@ -2090,7 +2090,7 @@
jdesc_.Initialize(desc_.Copy(), kSessionId, kSessionVersion);
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
size_t after_pt = message.find(" H264/90000");
ASSERT_NE(after_pt, std::string::npos);
size_t before_pt = message.rfind("a=rtpmap:", after_pt);
@@ -2774,7 +2774,7 @@
// We tested deserialization already above, so just test that if we serialize
// and deserialize the flag doesn't disappear.
EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
- std::string reserialized = webrtc::SdpSerialize(jdesc, false);
+ std::string reserialized = webrtc::SdpSerialize(jdesc);
EXPECT_TRUE(SdpDeserialize(reserialized, &jdesc));
// Verify.
@@ -2912,21 +2912,21 @@
params.useinband = 1;
params.maxaveragebitrate = 128000;
TestDeserializeCodecParams(params, &jdesc_output);
- TestSerialize(jdesc_output, false);
+ TestSerialize(jdesc_output);
}
TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
const bool kUseWildcard = false;
JsepSessionDescription jdesc_output(kDummyType);
TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
- TestSerialize(jdesc_output, false);
+ TestSerialize(jdesc_output);
}
TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
const bool kUseWildcard = true;
JsepSessionDescription jdesc_output(kDummyType);
TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
- TestSerialize(jdesc_output, false);
+ TestSerialize(jdesc_output);
}
TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
@@ -3039,7 +3039,7 @@
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
jdesc_.session_id(),
jdesc_.session_version()));
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
std::string sdp_with_fmtp = kSdpFullString;
InjectAfter("a=rtpmap:111 opus/48000/2\r\n",
"a=fmtp:111 unknown-future-parameter=SomeFutureValue\r\n",
@@ -3057,7 +3057,7 @@
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
jdesc_.session_id(),
jdesc_.session_version()));
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
std::string sdp_with_fmtp = kSdpFullString;
InjectAfter("a=rtpmap:111 opus/48000/2\r\n",
"a=fmtp:111 stereo=1\r\n",
@@ -3076,7 +3076,7 @@
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
jdesc_.session_id(),
jdesc_.session_version()));
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
std::string sdp_with_fmtp = kSdpFullString;
InjectAfter("a=rtpmap:104 ISAC/32000\r\n",
"a=maxptime:120\r\n" // No comma here. String merging!
@@ -3095,7 +3095,7 @@
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
jdesc_.session_id(),
jdesc_.session_version()));
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
std::string sdp_with_fmtp = kSdpFullString;
InjectAfter("a=rtpmap:120 VP8/90000\r\n",
"a=fmtp:120 x-google-min-bitrate=10\r\n",
@@ -3135,7 +3135,7 @@
JsepSessionDescription jdesc_output(kDummyType);
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
- EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output, false));
+ EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
}
TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
@@ -3163,7 +3163,7 @@
ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
jdesc_.session_id(),
jdesc_.session_version()));
- std::string message = webrtc::SdpSerialize(jdesc_, false);
+ std::string message = webrtc::SdpSerialize(jdesc_);
std::string sdp_with_dtlssetup = kSdpFullString;
// Fingerprint attribute is necessary to add DTLS setup attribute.
@@ -3234,7 +3234,7 @@
EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
}
- std::string serialized_sdp = webrtc::SdpSerialize(jdesc, false);
+ std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
EXPECT_EQ(sdp_string, serialized_sdp);
}
}
@@ -3264,7 +3264,7 @@
TEST_F(WebRtcSdpTest, SerializeBundleOnlyAttribute) {
MakeBundleOnlyDescription();
- TestSerialize(jdesc_, false);
+ TestSerialize(jdesc_);
}
TEST_F(WebRtcSdpTest, DeserializePlanBSessionDescription) {
@@ -3278,7 +3278,7 @@
TEST_F(WebRtcSdpTest, SerializePlanBSessionDescription) {
MakePlanBDescription();
- TestSerialize(jdesc_, false);
+ TestSerialize(jdesc_);
}
// Some WebRTC endpoints include the msid in both the Plan B and Unified Plan
@@ -3307,7 +3307,66 @@
TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescription) {
MakeUnifiedPlanDescription();
- TestSerialize(jdesc_, true);
+ TestSerialize(jdesc_);
+}
+
+TEST_F(WebRtcSdpTest, EmptyDescriptionHasNoMsidSignaling) {
+ JsepSessionDescription jsep_desc(kDummyType);
+ ASSERT_TRUE(SdpDeserialize(kSdpSessionString, &jsep_desc));
+ EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
+}
+
+TEST_F(WebRtcSdpTest, DataChannelOnlyHasNoMsidSignaling) {
+ JsepSessionDescription jsep_desc(kDummyType);
+ std::string sdp = kSdpSessionString;
+ sdp += kSdpSctpDataChannelString;
+ ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
+ EXPECT_EQ(0, 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());
+}
+
+TEST_F(WebRtcSdpTest, UnifiedPlanHasMediaSectionMsidSignaling) {
+ JsepSessionDescription jsep_desc(kDummyType);
+ ASSERT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullString, &jsep_desc));
+ EXPECT_EQ(cricket::kMsidSignalingMediaSection,
+ jsep_desc.description()->msid_signaling());
+}
+
+const char kMediaSectionMsidLine[] = "a=msid:local_stream_1 audio_track_id_1";
+const char kSsrcAttributeMsidLine[] =
+ "a=ssrc:1 msid:local_stream_1 audio_track_id_1";
+
+TEST_F(WebRtcSdpTest, SerializeOnlyMediaSectionMsid) {
+ jdesc_.description()->set_msid_signaling(cricket::kMsidSignalingMediaSection);
+ std::string sdp = webrtc::SdpSerialize(jdesc_);
+
+ EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
+ EXPECT_EQ(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
+}
+
+TEST_F(WebRtcSdpTest, SerializeOnlySsrcAttributeMsid) {
+ jdesc_.description()->set_msid_signaling(
+ cricket::kMsidSignalingSsrcAttribute);
+ std::string sdp = webrtc::SdpSerialize(jdesc_);
+
+ EXPECT_EQ(std::string::npos, sdp.find(kMediaSectionMsidLine));
+ EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
+}
+
+TEST_F(WebRtcSdpTest, SerializeBothMediaSectionAndSsrcAttributeMsid) {
+ jdesc_.description()->set_msid_signaling(
+ cricket::kMsidSignalingMediaSection |
+ cricket::kMsidSignalingSsrcAttribute);
+ std::string sdp = webrtc::SdpSerialize(jdesc_);
+
+ EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
+ EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
}
// Regression test for heap overflow bug:
@@ -3559,7 +3618,7 @@
JsepSessionDescription expected_jsep(kDummyType);
MakeDescriptionWithoutCandidates(&expected_jsep);
// Serialization.
- std::string message = webrtc::SdpSerialize(expected_jsep, false);
+ std::string message = webrtc::SdpSerialize(expected_jsep);
// Deserialization.
JsepSessionDescription jdesc(kDummyType);
EXPECT_TRUE(SdpDeserialize(message, &jdesc));