зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1170683: Do a better job in copying previous transport parameters into new offers/answers. r=mt
--HG-- extra : rebase_source : f263b9ad0bce2928a13584f374018d94cd6144ba extra : amend_source : 8476404611746d25e7f1bbf34c6c1ec5077f9af6
This commit is contained in:
Родитель
64babb721b
Коммит
63565e6168
|
@ -533,19 +533,18 @@ JsepSessionImpl::SetupBundle(Sdp* sdp) const
|
|||
}
|
||||
|
||||
nsresult
|
||||
JsepSessionImpl::FinalizeTransportAttributes(Sdp* offer)
|
||||
JsepSessionImpl::SetupTransportAttributes(const Sdp& newOffer, Sdp* local)
|
||||
{
|
||||
const Sdp* oldAnswer = GetAnswer();
|
||||
|
||||
if (oldAnswer) {
|
||||
// Renegotiation, we might have transport attributes to copy over
|
||||
for (size_t i = 0; i < oldAnswer->GetMediaSectionCount(); ++i) {
|
||||
if (!MsectionIsDisabled(offer->GetMediaSection(i)) &&
|
||||
!MsectionIsDisabled(oldAnswer->GetMediaSection(i)) &&
|
||||
!IsBundleSlave(*oldAnswer, i)) {
|
||||
if (!MsectionIsDisabled(local->GetMediaSection(i)) &&
|
||||
AreOldTransportParamsValid(*oldAnswer, newOffer, i)) {
|
||||
nsresult rv = CopyTransportParams(
|
||||
mCurrentLocalDescription->GetMediaSection(i),
|
||||
&offer->GetMediaSection(i));
|
||||
&local->GetMediaSection(i));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
@ -769,7 +768,7 @@ JsepSessionImpl::CreateOffer(const JsepOfferOptions& options,
|
|||
|
||||
SetupBundle(sdp.get());
|
||||
|
||||
rv = FinalizeTransportAttributes(sdp.get());
|
||||
rv = SetupTransportAttributes(*sdp, sdp.get());
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
*offer = sdp->ToString();
|
||||
|
@ -1022,6 +1021,9 @@ JsepSessionImpl::CreateAnswer(const JsepAnswerOptions& options,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = SetupTransportAttributes(offer, sdp.get());
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
*answer = sdp->ToString();
|
||||
mGeneratedLocalDescription = Move(sdp);
|
||||
|
||||
|
@ -1416,6 +1418,7 @@ JsepSessionImpl::SetLocalDescriptionAnswer(JsepSdpType type,
|
|||
|
||||
mCurrentRemoteDescription = Move(mPendingRemoteDescription);
|
||||
mCurrentLocalDescription = Move(mPendingLocalDescription);
|
||||
mWasOffererLastTime = mIsOfferer;
|
||||
|
||||
SetState(kJsepStateStable);
|
||||
return NS_OK;
|
||||
|
@ -1865,6 +1868,37 @@ JsepSessionImpl::FinalizeTransport(const SdpAttributeList& remote,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
JsepSessionImpl::AreOldTransportParamsValid(const Sdp& oldAnswer,
|
||||
const Sdp& newOffer,
|
||||
size_t level)
|
||||
{
|
||||
if (MsectionIsDisabled(oldAnswer.GetMediaSection(level)) ||
|
||||
MsectionIsDisabled(newOffer.GetMediaSection(level))) {
|
||||
// Obvious
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsBundleSlave(oldAnswer, level)) {
|
||||
// The transport attributes on this m-section were thrown away, because it
|
||||
// was bundled.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newOffer.GetMediaSection(level).GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kBundleOnlyAttribute) &&
|
||||
IsBundleSlave(newOffer, level)) {
|
||||
// It never makes sense to put transport attributes in a bundle-only
|
||||
// m-section
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(bug 906986): Check for ICE restart (will need to pass the offerer's
|
||||
// old SDP to compare it against |newOffer|)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
JsepSessionImpl::AddTransportAttributes(SdpMediaSection* msection,
|
||||
SdpSetupAttribute::Role dtlsRole)
|
||||
|
@ -1886,33 +1920,43 @@ JsepSessionImpl::AddTransportAttributes(SdpMediaSection* msection,
|
|||
}
|
||||
|
||||
nsresult
|
||||
JsepSessionImpl::CopyTransportParams(const SdpMediaSection& source,
|
||||
SdpMediaSection* dest)
|
||||
JsepSessionImpl::CopyTransportParams(const SdpMediaSection& oldLocal,
|
||||
SdpMediaSection* newLocal)
|
||||
{
|
||||
// Copy over m-section details
|
||||
dest->SetPort(source.GetPort());
|
||||
dest->GetConnection() = source.GetConnection();
|
||||
newLocal->SetPort(oldLocal.GetPort());
|
||||
newLocal->GetConnection() = oldLocal.GetConnection();
|
||||
|
||||
auto& sourceAttrs = source.GetAttributeList();
|
||||
auto& destAttrs = dest->GetAttributeList();
|
||||
const SdpAttributeList& oldLocalAttrs = oldLocal.GetAttributeList();
|
||||
SdpAttributeList& newLocalAttrs = newLocal->GetAttributeList();
|
||||
|
||||
// If newLocal is an offer, this will be the number of components we used
|
||||
// last time, and if it is an answer, this will be the number of components
|
||||
// we know we're using now.
|
||||
size_t components = mTransports[oldLocal.GetLevel()]->mComponents;
|
||||
|
||||
// Now we copy over attributes that won't be added by the usual logic
|
||||
if (sourceAttrs.HasAttribute(SdpAttribute::kCandidateAttribute)) {
|
||||
auto* candidateAttrs =
|
||||
new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute);
|
||||
candidateAttrs->mValues = sourceAttrs.GetCandidate();
|
||||
destAttrs.SetAttribute(candidateAttrs);
|
||||
if (oldLocalAttrs.HasAttribute(SdpAttribute::kCandidateAttribute) &&
|
||||
components) {
|
||||
UniquePtr<SdpMultiStringAttribute> candidateAttrs(
|
||||
new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute));
|
||||
for (const std::string& candidate : oldLocalAttrs.GetCandidate()) {
|
||||
size_t component;
|
||||
nsresult rv = GetComponent(candidate, &component);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (components >= component) {
|
||||
candidateAttrs->mValues.push_back(candidate);
|
||||
}
|
||||
}
|
||||
if (candidateAttrs->mValues.size()) {
|
||||
newLocalAttrs.SetAttribute(candidateAttrs.release());
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceAttrs.HasAttribute(SdpAttribute::kEndOfCandidatesAttribute)) {
|
||||
destAttrs.SetAttribute(
|
||||
new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
|
||||
}
|
||||
|
||||
if (!destAttrs.HasAttribute(SdpAttribute::kRtcpMuxAttribute) &&
|
||||
sourceAttrs.HasAttribute(SdpAttribute::kRtcpAttribute)) {
|
||||
// copy rtcp attribute
|
||||
destAttrs.SetAttribute(new SdpRtcpAttribute(sourceAttrs.GetRtcp()));
|
||||
if (components == 2 &&
|
||||
oldLocalAttrs.HasAttribute(SdpAttribute::kRtcpAttribute)) {
|
||||
// copy rtcp attribute if we had one that we are using
|
||||
newLocalAttrs.SetAttribute(new SdpRtcpAttribute(oldLocalAttrs.GetRtcp()));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2075,6 +2119,7 @@ JsepSessionImpl::SetRemoteDescriptionAnswer(JsepSdpType type,
|
|||
|
||||
mCurrentRemoteDescription = Move(mPendingRemoteDescription);
|
||||
mCurrentLocalDescription = Move(mPendingLocalDescription);
|
||||
mWasOffererLastTime = mIsOfferer;
|
||||
|
||||
SetState(kJsepStateStable);
|
||||
return NS_OK;
|
||||
|
@ -2567,6 +2612,21 @@ JsepSessionImpl::AddCandidateToSdp(Sdp* sdp,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// TODO(bug 1142105): Move this into an SDP helper class. Ideally, we'd like
|
||||
// to have real parse code and a useful representation of candidate attrs.
|
||||
nsresult
|
||||
JsepSessionImpl::GetComponent(const std::string& candidate, size_t* component)
|
||||
{
|
||||
unsigned int temp;
|
||||
int32_t result = PR_sscanf(candidate.c_str(), "%*s %u", &temp);
|
||||
if (result == 1) {
|
||||
*component = temp;
|
||||
return NS_OK;
|
||||
}
|
||||
JSEP_SET_ERROR("Malformed local ICE candidate: " << candidate);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult
|
||||
JsepSessionImpl::AddRemoteIceCandidate(const std::string& candidate,
|
||||
const std::string& mid,
|
||||
|
@ -2636,6 +2696,7 @@ static void SetDefaultAddresses(const std::string& defaultCandidateAddr,
|
|||
{
|
||||
msection->GetConnection().SetAddress(defaultCandidateAddr);
|
||||
msection->SetPort(defaultCandidatePort);
|
||||
|
||||
if (!defaultRtcpCandidateAddr.empty()) {
|
||||
sdp::AddrType ipVersion = sdp::kIPv4;
|
||||
if (defaultRtcpCandidateAddr.find(':') != std::string::npos) {
|
||||
|
@ -2669,17 +2730,30 @@ JsepSessionImpl::EndOfLocalCandidates(const std::string& defaultCandidateAddr,
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
std::set<std::string> bundleMids;
|
||||
const SdpMediaSection* bundleMsection;
|
||||
nsresult rv = GetNegotiatedBundleInfo(&bundleMids, &bundleMsection);
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_ASSERT(false);
|
||||
mLastError += " (This should have been caught sooner!)";
|
||||
return NS_ERROR_FAILURE;
|
||||
if (level >= sdp->GetMediaSectionCount()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (level < sdp->GetMediaSectionCount()) {
|
||||
SdpMediaSection& msection = sdp->GetMediaSection(level);
|
||||
std::string defaultRtcpCandidateAddrCopy(defaultRtcpCandidateAddr);
|
||||
if (mState == kJsepStateStable && mTransports[level]->mComponents == 1) {
|
||||
// We know we're doing rtcp-mux by now. Don't create an rtcp attr.
|
||||
defaultRtcpCandidateAddrCopy = "";
|
||||
defaultRtcpCandidatePort = 0;
|
||||
}
|
||||
|
||||
SdpMediaSection& msection = sdp->GetMediaSection(level);
|
||||
|
||||
if (mState == kJsepStateStable) {
|
||||
// offer/answer is done. Do we actually incorporate these defaults?
|
||||
const Sdp* answer(GetAnswer());
|
||||
std::set<std::string> bundleMids;
|
||||
const SdpMediaSection* bundleMsection;
|
||||
nsresult rv = GetBundleInfo(*answer, &bundleMids, &bundleMsection);
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_ASSERT(false);
|
||||
mLastError += " (This should have been caught sooner!)";
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (msection.GetAttributeList().HasAttribute(SdpAttribute::kMidAttribute) &&
|
||||
bundleMids.count(msection.GetAttributeList().GetMid())) {
|
||||
|
@ -2698,26 +2772,26 @@ JsepSessionImpl::EndOfLocalCandidates(const std::string& defaultCandidateAddr,
|
|||
}
|
||||
SetDefaultAddresses(defaultCandidateAddr,
|
||||
defaultCandidatePort,
|
||||
defaultRtcpCandidateAddr,
|
||||
defaultRtcpCandidateAddrCopy,
|
||||
defaultRtcpCandidatePort,
|
||||
bundledMsection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetDefaultAddresses(defaultCandidateAddr,
|
||||
defaultCandidatePort,
|
||||
defaultRtcpCandidateAddr,
|
||||
defaultRtcpCandidatePort,
|
||||
&msection);
|
||||
SetDefaultAddresses(defaultCandidateAddr,
|
||||
defaultCandidatePort,
|
||||
defaultRtcpCandidateAddrCopy,
|
||||
defaultRtcpCandidatePort,
|
||||
&msection);
|
||||
|
||||
// TODO(bug 1095793): Will this have an mid someday?
|
||||
// TODO(bug 1095793): Will this have an mid someday?
|
||||
|
||||
SdpAttributeList& attrs = msection.GetAttributeList();
|
||||
attrs.SetAttribute(
|
||||
new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
|
||||
if (!mIsOfferer) {
|
||||
attrs.RemoveAttribute(SdpAttribute::kIceOptionsAttribute);
|
||||
}
|
||||
SdpAttributeList& attrs = msection.GetAttributeList();
|
||||
attrs.SetAttribute(
|
||||
new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
|
||||
if (!mIsOfferer) {
|
||||
attrs.RemoveAttribute(SdpAttribute::kIceOptionsAttribute);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -3039,10 +3113,8 @@ JsepSessionImpl::MsectionIsDisabled(const SdpMediaSection& msection) const
|
|||
const Sdp*
|
||||
JsepSessionImpl::GetAnswer() const
|
||||
{
|
||||
MOZ_ASSERT(mState == kJsepStateStable);
|
||||
|
||||
return mIsOfferer ? mCurrentRemoteDescription.get()
|
||||
: mCurrentLocalDescription.get();
|
||||
return mWasOffererLastTime ? mCurrentRemoteDescription.get()
|
||||
: mCurrentLocalDescription.get();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
JsepSessionImpl(const std::string& name, UniquePtr<JsepUuidGenerator> uuidgen)
|
||||
: JsepSession(name),
|
||||
mIsOfferer(false),
|
||||
mWasOffererLastTime(false),
|
||||
mIceControlling(false),
|
||||
mRemoteIsIceLite(false),
|
||||
mSessionId(0),
|
||||
|
@ -240,7 +241,7 @@ private:
|
|||
const Sdp& oldAnswer,
|
||||
Sdp* newSdp);
|
||||
void SetupBundle(Sdp* sdp) const;
|
||||
nsresult FinalizeTransportAttributes(Sdp* sdp);
|
||||
nsresult SetupTransportAttributes(const Sdp& newOffer, Sdp* local);
|
||||
void SetupMsidSemantic(const std::vector<std::string>& msids, Sdp* sdp) const;
|
||||
nsresult GetIdsFromMsid(const Sdp& sdp,
|
||||
const SdpMediaSection& msection,
|
||||
|
@ -286,11 +287,15 @@ private:
|
|||
nsresult FinalizeTransport(const SdpAttributeList& remote,
|
||||
const SdpAttributeList& answer,
|
||||
const RefPtr<JsepTransport>& transport);
|
||||
bool AreOldTransportParamsValid(const Sdp& oldAnswer,
|
||||
const Sdp& newOffer,
|
||||
size_t level);
|
||||
|
||||
nsresult AddCandidateToSdp(Sdp* sdp,
|
||||
const std::string& candidate,
|
||||
const std::string& mid,
|
||||
uint16_t level);
|
||||
nsresult GetComponent(const std::string& candidate, size_t* component);
|
||||
|
||||
SdpMediaSection* FindMsectionByMid(Sdp& sdp,
|
||||
const std::string& mid) const;
|
||||
|
@ -330,6 +335,7 @@ private:
|
|||
std::vector<JsepTrackPair> mNegotiatedTrackPairs;
|
||||
|
||||
bool mIsOfferer;
|
||||
bool mWasOffererLastTime;
|
||||
bool mIceControlling;
|
||||
std::string mIceUfrag;
|
||||
std::string mIcePwd;
|
||||
|
|
|
@ -31,27 +31,8 @@
|
|||
#include "mtransport_test_utils.h"
|
||||
|
||||
namespace mozilla {
|
||||
static const char* kCandidates[] = {
|
||||
"0 1 UDP 9999 192.168.0.1 2000 typ host",
|
||||
"0 1 UDP 9999 192.168.0.1 2001 typ host",
|
||||
"0 1 UDP 9999 192.168.0.2 2002 typ srflx raddr 10.252.34.97 rport 53594",
|
||||
// Mix up order
|
||||
"0 1 UDP 9999 192.168.1.2 2012 typ srflx raddr 10.252.34.97 rport 53595",
|
||||
"0 1 UDP 9999 192.168.1.1 2010 typ host",
|
||||
"0 1 UDP 9999 192.168.1.1 2011 typ host"
|
||||
};
|
||||
|
||||
static const char* kRtcpCandidates[] = {
|
||||
"0 2 UDP 9999 192.168.0.1 3000 typ host",
|
||||
"0 2 UDP 9999 192.168.0.1 3001 typ host",
|
||||
"0 2 UDP 9999 192.168.0.2 3002 typ srflx raddr 10.252.34.97 rport 53596",
|
||||
// Mix up order
|
||||
"0 2 UDP 9999 192.168.1.2 3012 typ srflx raddr 10.252.34.97 rport 53597",
|
||||
"0 2 UDP 9999 192.168.1.1 3010 typ host",
|
||||
"0 2 UDP 9999 192.168.1.1 3011 typ host"
|
||||
};
|
||||
|
||||
static std::string kAEqualsCandidate("a=candidate:");
|
||||
const static size_t kNumCandidatesPerComponent = 3;
|
||||
|
||||
class JsepSessionTestBase : public ::testing::Test
|
||||
{
|
||||
|
@ -372,8 +353,7 @@ protected:
|
|||
}
|
||||
|
||||
UniquePtr<Sdp> GetParsedLocalDescription(const JsepSessionImpl& side) const {
|
||||
SipccSdpParser parser;
|
||||
return mozilla::Move(parser.Parse(side.GetLocalDescription()));
|
||||
return Parse(side.GetLocalDescription());
|
||||
}
|
||||
|
||||
SdpMediaSection* GetMsection(Sdp& sdp,
|
||||
|
@ -591,62 +571,203 @@ protected:
|
|||
DumpTrackPairs(mSessionAns);
|
||||
}
|
||||
|
||||
void
|
||||
GatherCandidates(JsepSession& session)
|
||||
{
|
||||
bool skipped;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
session.AddLocalIceCandidate(
|
||||
kAEqualsCandidate + kCandidates[i], "", 0, &skipped);
|
||||
session.AddLocalIceCandidate(
|
||||
kAEqualsCandidate + kRtcpCandidates[i], "", 0, &skipped);
|
||||
}
|
||||
session.EndOfLocalCandidates("192.168.0.2", 2002, "192.168.0.2", 3002, 0);
|
||||
typedef enum {
|
||||
RTP = 1,
|
||||
RTCP = 2
|
||||
} ComponentType;
|
||||
|
||||
for (size_t i = 3; i < 6; ++i) {
|
||||
session.AddLocalIceCandidate(
|
||||
kAEqualsCandidate + kCandidates[i], "", 1, &skipped);
|
||||
session.AddLocalIceCandidate(
|
||||
kAEqualsCandidate + kRtcpCandidates[i], "", 1, &skipped);
|
||||
}
|
||||
session.EndOfLocalCandidates("192.168.1.2", 2012, "192.168.1.2", 3012, 1);
|
||||
class CandidateSet {
|
||||
public:
|
||||
CandidateSet() {}
|
||||
|
||||
std::cerr << "local SDP after candidates: "
|
||||
<< session.GetLocalDescription();
|
||||
}
|
||||
void Gather(JsepSession& session,
|
||||
const std::vector<SdpMediaSection::MediaType>& types,
|
||||
ComponentType maxComponent = RTCP)
|
||||
{
|
||||
for (size_t level = 0; level < types.size(); ++level) {
|
||||
Gather(session, level, RTP);
|
||||
if (types[level] != SdpMediaSection::kApplication &&
|
||||
maxComponent == RTCP) {
|
||||
Gather(session, level, RTCP);
|
||||
}
|
||||
}
|
||||
FinishGathering(session);
|
||||
}
|
||||
|
||||
void
|
||||
TrickleCandidates(JsepSession& session)
|
||||
{
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
session.AddRemoteIceCandidate(
|
||||
kAEqualsCandidate + kCandidates[i], "", 0);
|
||||
session.AddRemoteIceCandidate(
|
||||
kAEqualsCandidate + kRtcpCandidates[i], "", 0);
|
||||
}
|
||||
void Gather(JsepSession& session, size_t level, ComponentType component)
|
||||
{
|
||||
static uint16_t port = 1000;
|
||||
std::vector<std::string> candidates;
|
||||
for (size_t i = 0; i < kNumCandidatesPerComponent; ++i) {
|
||||
++port;
|
||||
std::ostringstream candidate;
|
||||
candidate << "0 " << static_cast<uint16_t>(component)
|
||||
<< " UDP 9999 192.168.0.1 " << port << " typ host";
|
||||
bool skipped;
|
||||
session.AddLocalIceCandidate(kAEqualsCandidate + candidate.str(),
|
||||
"", level, &skipped);
|
||||
if (!skipped) {
|
||||
mCandidatesToTrickle.push_back(
|
||||
std::pair<uint16_t, std::string>(
|
||||
level, kAEqualsCandidate + candidate.str()));
|
||||
candidates.push_back(candidate.str());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 3; i < 6; ++i) {
|
||||
session.AddRemoteIceCandidate(
|
||||
kAEqualsCandidate + kCandidates[i], "", 1);
|
||||
session.AddRemoteIceCandidate(
|
||||
kAEqualsCandidate + kRtcpCandidates[i], "", 1);
|
||||
}
|
||||
// Stomp existing candidates
|
||||
mCandidates[level][component] = candidates;
|
||||
|
||||
std::cerr << "remote SDP after candidates: "
|
||||
<< session.GetRemoteDescription();
|
||||
}
|
||||
// Stomp existing defaults
|
||||
mDefaultCandidates[level][component] =
|
||||
std::make_pair("192.168.0.1", port);
|
||||
}
|
||||
|
||||
void
|
||||
GatherOffererCandidates()
|
||||
{
|
||||
GatherCandidates(mSessionOff);
|
||||
}
|
||||
void FinishGathering(JsepSession& session) const
|
||||
{
|
||||
// Copy so we can be terse and use []
|
||||
for (auto levelAndCandidates : mDefaultCandidates) {
|
||||
ASSERT_EQ(1U, levelAndCandidates.second.count(RTP));
|
||||
session.EndOfLocalCandidates(
|
||||
levelAndCandidates.second[RTP].first,
|
||||
levelAndCandidates.second[RTP].second,
|
||||
// Will be empty string if not present, which is how we indicate
|
||||
// that there is no default for RTCP
|
||||
levelAndCandidates.second[RTCP].first,
|
||||
levelAndCandidates.second[RTCP].second,
|
||||
levelAndCandidates.first);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TrickleOffererCandidates()
|
||||
{
|
||||
TrickleCandidates(mSessionAns);
|
||||
}
|
||||
void Trickle(JsepSession& session)
|
||||
{
|
||||
for (const auto& levelAndCandidate : mCandidatesToTrickle) {
|
||||
session.AddRemoteIceCandidate(levelAndCandidate.second,
|
||||
"",
|
||||
levelAndCandidate.first);
|
||||
}
|
||||
mCandidatesToTrickle.clear();
|
||||
}
|
||||
|
||||
void CheckRtpCandidates(bool expectRtpCandidates,
|
||||
const SdpMediaSection& msection,
|
||||
size_t transportLevel,
|
||||
const std::string& context) const
|
||||
{
|
||||
auto& attrs = msection.GetAttributeList();
|
||||
|
||||
ASSERT_EQ(expectRtpCandidates,
|
||||
attrs.HasAttribute(SdpAttribute::kCandidateAttribute))
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
|
||||
if (expectRtpCandidates) {
|
||||
// Copy so we can be terse and use []
|
||||
auto expectedCandidates = mCandidates;
|
||||
ASSERT_LE(kNumCandidatesPerComponent,
|
||||
expectedCandidates[transportLevel][RTP].size());
|
||||
|
||||
auto& candidates = attrs.GetCandidate();
|
||||
ASSERT_LE(kNumCandidatesPerComponent, candidates.size())
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
for (size_t i = 0; i < kNumCandidatesPerComponent; ++i) {
|
||||
ASSERT_EQ(expectedCandidates[transportLevel][RTP][i], candidates[i])
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckRtcpCandidates(bool expectRtcpCandidates,
|
||||
const SdpMediaSection& msection,
|
||||
size_t transportLevel,
|
||||
const std::string& context) const
|
||||
{
|
||||
auto& attrs = msection.GetAttributeList();
|
||||
|
||||
if (expectRtcpCandidates) {
|
||||
// Copy so we can be terse and use []
|
||||
auto expectedCandidates = mCandidates;
|
||||
ASSERT_LE(kNumCandidatesPerComponent,
|
||||
expectedCandidates[transportLevel][RTCP].size());
|
||||
|
||||
ASSERT_TRUE(attrs.HasAttribute(SdpAttribute::kCandidateAttribute))
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
auto& candidates = attrs.GetCandidate();
|
||||
ASSERT_EQ(kNumCandidatesPerComponent * 2, candidates.size())
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
for (size_t i = 0; i < kNumCandidatesPerComponent; ++i) {
|
||||
ASSERT_EQ(expectedCandidates[transportLevel][RTCP][i],
|
||||
candidates[i + kNumCandidatesPerComponent])
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckDefaultRtpCandidate(bool expectDefault,
|
||||
const SdpMediaSection& msection,
|
||||
size_t transportLevel,
|
||||
const std::string& context) const
|
||||
{
|
||||
if (expectDefault) {
|
||||
// Copy so we can be terse and use []
|
||||
auto defaultCandidates = mDefaultCandidates;
|
||||
ASSERT_EQ(defaultCandidates[transportLevel][RTP].first,
|
||||
msection.GetConnection().GetAddress())
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
ASSERT_EQ(defaultCandidates[transportLevel][RTP].second,
|
||||
msection.GetPort())
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
} else {
|
||||
ASSERT_EQ("0.0.0.0", msection.GetConnection().GetAddress())
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
ASSERT_EQ(9U, msection.GetPort())
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void CheckDefaultRtcpCandidate(bool expectDefault,
|
||||
const SdpMediaSection& msection,
|
||||
size_t transportLevel,
|
||||
const std::string& context) const
|
||||
{
|
||||
if (expectDefault) {
|
||||
// Copy so we can be terse and use []
|
||||
auto defaultCandidates = mDefaultCandidates;
|
||||
ASSERT_TRUE(msection.GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kRtcpAttribute))
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
auto& rtcpAttr = msection.GetAttributeList().GetRtcp();
|
||||
ASSERT_EQ(defaultCandidates[transportLevel][RTCP].second,
|
||||
rtcpAttr.mPort)
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
ASSERT_EQ(sdp::kInternet, rtcpAttr.mNetType)
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
ASSERT_EQ(sdp::kIPv4, rtcpAttr.mAddrType)
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
ASSERT_EQ(defaultCandidates[transportLevel][RTCP].first,
|
||||
rtcpAttr.mAddress)
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
} else {
|
||||
ASSERT_FALSE(msection.GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kRtcpAttribute))
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef size_t Level;
|
||||
typedef std::string Candidate;
|
||||
typedef std::string Address;
|
||||
typedef uint16_t Port;
|
||||
// Default candidates are put into the m-line, c-line, and rtcp
|
||||
// attribute for endpoints that don't support ICE.
|
||||
std::map<Level,
|
||||
std::map<ComponentType,
|
||||
std::pair<Address, Port>>> mDefaultCandidates;
|
||||
std::map<Level,
|
||||
std::map<ComponentType,
|
||||
std::vector<Candidate>>> mCandidates;
|
||||
// Level/candidate pairs that need to be trickled
|
||||
std::vector<std::pair<Level, Candidate>> mCandidatesToTrickle;
|
||||
};
|
||||
|
||||
// For streaming parse errors
|
||||
std::string
|
||||
|
@ -661,85 +782,19 @@ protected:
|
|||
return output.str();
|
||||
}
|
||||
|
||||
void
|
||||
ValidateCandidates(JsepSession& session, bool local)
|
||||
void CheckEndOfCandidates(bool expectEoc,
|
||||
const SdpMediaSection& msection,
|
||||
const std::string& context)
|
||||
{
|
||||
std::string sdp =
|
||||
local ? session.GetLocalDescription() : session.GetRemoteDescription();
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> parsed = parser.Parse(sdp);
|
||||
ASSERT_TRUE(!!parsed) << "Parse failed on " << std::endl << sdp << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
ASSERT_LT(0U, parsed->GetMediaSectionCount());
|
||||
|
||||
auto& msection_0 = parsed->GetMediaSection(0);
|
||||
|
||||
// We should not be doing things like setting the c-line on remote SDP
|
||||
if (local) {
|
||||
ASSERT_EQ("192.168.0.2", msection_0.GetConnection().GetAddress());
|
||||
ASSERT_EQ(2002U, msection_0.GetPort());
|
||||
ASSERT_TRUE(msection_0.GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kRtcpAttribute));
|
||||
auto& rtcpAttr = msection_0.GetAttributeList().GetRtcp();
|
||||
ASSERT_EQ(3002U, rtcpAttr.mPort);
|
||||
ASSERT_EQ(sdp::kInternet, rtcpAttr.mNetType);
|
||||
ASSERT_EQ(sdp::kIPv4, rtcpAttr.mAddrType);
|
||||
ASSERT_EQ("192.168.0.2", rtcpAttr.mAddress);
|
||||
ASSERT_TRUE(msection_0.GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kEndOfCandidatesAttribute));
|
||||
if (expectEoc) {
|
||||
ASSERT_TRUE(msection.GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kEndOfCandidatesAttribute))
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
} else {
|
||||
ASSERT_FALSE(msection.GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kEndOfCandidatesAttribute))
|
||||
<< context << " (level " << msection.GetLevel() << ")";
|
||||
}
|
||||
|
||||
auto& attrs_0 = msection_0.GetAttributeList();
|
||||
ASSERT_TRUE(attrs_0.HasAttribute(SdpAttribute::kCandidateAttribute));
|
||||
|
||||
auto& candidates_0 = attrs_0.GetCandidate();
|
||||
ASSERT_EQ(6U, candidates_0.size());
|
||||
ASSERT_EQ(kCandidates[0], candidates_0[0]);
|
||||
ASSERT_EQ(kRtcpCandidates[0], candidates_0[1]);
|
||||
ASSERT_EQ(kCandidates[1], candidates_0[2]);
|
||||
ASSERT_EQ(kRtcpCandidates[1], candidates_0[3]);
|
||||
ASSERT_EQ(kCandidates[2], candidates_0[4]);
|
||||
ASSERT_EQ(kRtcpCandidates[2], candidates_0[5]);
|
||||
|
||||
if (parsed->GetMediaSectionCount() > 1) {
|
||||
auto& msection_1 = parsed->GetMediaSection(1);
|
||||
|
||||
if (local) {
|
||||
ASSERT_EQ("192.168.1.2", msection_1.GetConnection().GetAddress());
|
||||
ASSERT_EQ(2012U, msection_1.GetPort());
|
||||
auto& rtcpAttr = msection_1.GetAttributeList().GetRtcp();
|
||||
ASSERT_EQ(3012U, rtcpAttr.mPort);
|
||||
ASSERT_EQ(sdp::kInternet, rtcpAttr.mNetType);
|
||||
ASSERT_EQ(sdp::kIPv4, rtcpAttr.mAddrType);
|
||||
ASSERT_EQ("192.168.1.2", rtcpAttr.mAddress);
|
||||
ASSERT_TRUE(msection_0.GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kEndOfCandidatesAttribute));
|
||||
}
|
||||
|
||||
auto& attrs_1 = msection_1.GetAttributeList();
|
||||
ASSERT_TRUE(attrs_1.HasAttribute(SdpAttribute::kCandidateAttribute));
|
||||
|
||||
auto& candidates_1 = attrs_1.GetCandidate();
|
||||
ASSERT_EQ(6U, candidates_1.size());
|
||||
ASSERT_EQ(kCandidates[3], candidates_1[0]);
|
||||
ASSERT_EQ(kRtcpCandidates[3], candidates_1[1]);
|
||||
ASSERT_EQ(kCandidates[4], candidates_1[2]);
|
||||
ASSERT_EQ(kRtcpCandidates[4], candidates_1[3]);
|
||||
ASSERT_EQ(kCandidates[5], candidates_1[4]);
|
||||
ASSERT_EQ(kRtcpCandidates[5], candidates_1[5]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ValidateOffererCandidates()
|
||||
{
|
||||
ValidateCandidates(mSessionOff, true);
|
||||
}
|
||||
|
||||
void
|
||||
ValidateAnswererCandidates()
|
||||
{
|
||||
ValidateCandidates(mSessionAns, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -758,8 +813,7 @@ protected:
|
|||
|
||||
void
|
||||
DisableMsection(std::string* sdp, size_t level) const {
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> parsed = parser.Parse(*sdp);
|
||||
UniquePtr<Sdp> parsed(Parse(*sdp));
|
||||
ASSERT_TRUE(parsed.get());
|
||||
ASSERT_LT(level, parsed->GetMediaSectionCount());
|
||||
parsed->GetMediaSection(level).SetPort(0);
|
||||
|
@ -813,18 +867,29 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
UniquePtr<Sdp>
|
||||
Parse(const std::string& sdp) const
|
||||
{
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> parsed = parser.Parse(sdp);
|
||||
EXPECT_TRUE(parsed.get()) << "Should have valid SDP" << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
JsepSessionImpl mSessionOff;
|
||||
CandidateSet mOffCandidates;
|
||||
JsepSessionImpl mSessionAns;
|
||||
CandidateSet mAnsCandidates;
|
||||
std::vector<SdpMediaSection::MediaType> types;
|
||||
std::vector<std::pair<std::string, uint16_t>> mGatheredCandidates;
|
||||
|
||||
private:
|
||||
void
|
||||
ValidateTransport(TransportData& source, const std::string& sdp_str)
|
||||
{
|
||||
SipccSdpParser parser;
|
||||
auto sdp = parser.Parse(sdp_str);
|
||||
ASSERT_TRUE(!!sdp) << "Should have valid SDP" << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
UniquePtr<Sdp> sdp(Parse(sdp_str));
|
||||
ASSERT_TRUE(!!sdp);
|
||||
size_t num_m_sections = sdp->GetMediaSectionCount();
|
||||
for (size_t i = 0; i < num_m_sections; ++i) {
|
||||
auto& msection = sdp->GetMediaSection(i);
|
||||
|
@ -1993,17 +2058,289 @@ TEST_P(JsepSessionTest, FullCallWithCandidates)
|
|||
AddTracks(mSessionOff);
|
||||
std::string offer = CreateOffer();
|
||||
SetLocalOffer(offer);
|
||||
GatherOffererCandidates();
|
||||
ValidateOffererCandidates();
|
||||
mOffCandidates.Gather(mSessionOff, types);
|
||||
|
||||
UniquePtr<Sdp> localOffer(Parse(mSessionOff.GetLocalDescription()));
|
||||
for (size_t i = 0; i < localOffer->GetMediaSectionCount(); ++i) {
|
||||
mOffCandidates.CheckRtpCandidates(
|
||||
true, localOffer->GetMediaSection(i), i,
|
||||
"Local offer after gathering should have RTP candidates.");
|
||||
mOffCandidates.CheckDefaultRtpCandidate(
|
||||
true, localOffer->GetMediaSection(i), i,
|
||||
"Local offer after gathering should have a default RTP candidate.");
|
||||
mOffCandidates.CheckRtcpCandidates(
|
||||
types[i] != SdpMediaSection::kApplication,
|
||||
localOffer->GetMediaSection(i), i,
|
||||
"Local offer after gathering should have RTCP candidates "
|
||||
"(unless m=application)");
|
||||
mOffCandidates.CheckDefaultRtcpCandidate(
|
||||
types[i] != SdpMediaSection::kApplication,
|
||||
localOffer->GetMediaSection(i), i,
|
||||
"Local offer after gathering should have a default RTCP candidate "
|
||||
"(unless m=application)");
|
||||
CheckEndOfCandidates(true, localOffer->GetMediaSection(i),
|
||||
"Local offer after gathering should have an end-of-candidates.");
|
||||
}
|
||||
|
||||
SetRemoteOffer(offer);
|
||||
TrickleOffererCandidates();
|
||||
ValidateAnswererCandidates();
|
||||
mOffCandidates.Trickle(mSessionAns);
|
||||
|
||||
UniquePtr<Sdp> remoteOffer(Parse(mSessionAns.GetRemoteDescription()));
|
||||
for (size_t i = 0; i < remoteOffer->GetMediaSectionCount(); ++i) {
|
||||
mOffCandidates.CheckRtpCandidates(
|
||||
true, remoteOffer->GetMediaSection(i), i,
|
||||
"Remote offer after trickle should have RTP candidates.");
|
||||
mOffCandidates.CheckDefaultRtpCandidate(
|
||||
false, remoteOffer->GetMediaSection(i), i,
|
||||
"Initial remote offer should not have a default RTP candidate.");
|
||||
mOffCandidates.CheckRtcpCandidates(
|
||||
types[i] != SdpMediaSection::kApplication,
|
||||
remoteOffer->GetMediaSection(i), i,
|
||||
"Remote offer after trickle should have RTCP candidates "
|
||||
"(unless m=application)");
|
||||
mOffCandidates.CheckDefaultRtcpCandidate(
|
||||
false, remoteOffer->GetMediaSection(i), i,
|
||||
"Initial remote offer should not have a default RTCP candidate.");
|
||||
CheckEndOfCandidates(false, remoteOffer->GetMediaSection(i),
|
||||
"Initial remote offer should not have an end-of-candidates.");
|
||||
}
|
||||
|
||||
AddTracks(mSessionAns);
|
||||
std::string answer = CreateAnswer();
|
||||
SetLocalAnswer(answer);
|
||||
// This will gather candidates that mSessionAns knows it doesn't need.
|
||||
// They should not be present in the SDP.
|
||||
mAnsCandidates.Gather(mSessionAns, types);
|
||||
|
||||
UniquePtr<Sdp> localAnswer(Parse(mSessionAns.GetLocalDescription()));
|
||||
for (size_t i = 0; i < localAnswer->GetMediaSectionCount(); ++i) {
|
||||
mAnsCandidates.CheckRtpCandidates(
|
||||
i == 0, localAnswer->GetMediaSection(i), i,
|
||||
"Local answer after gathering should have RTP candidates on level 0.");
|
||||
mAnsCandidates.CheckDefaultRtpCandidate(
|
||||
true, localAnswer->GetMediaSection(i), 0,
|
||||
"Local answer after gathering should have a default RTP candidate "
|
||||
"on all levels that matches transport level 0.");
|
||||
mAnsCandidates.CheckRtcpCandidates(
|
||||
false, localAnswer->GetMediaSection(i), i,
|
||||
"Local answer after gathering should not have RTCP candidates "
|
||||
"(because we're answering with rtcp-mux)");
|
||||
mAnsCandidates.CheckDefaultRtcpCandidate(
|
||||
false, localAnswer->GetMediaSection(i), i,
|
||||
"Local answer after gathering should not have a default RTCP candidate "
|
||||
"(because we're answering with rtcp-mux)");
|
||||
CheckEndOfCandidates(i == 0, localAnswer->GetMediaSection(i),
|
||||
"Local answer after gathering should have an end-of-candidates only for"
|
||||
" level 0.");
|
||||
}
|
||||
|
||||
SetRemoteAnswer(answer);
|
||||
mAnsCandidates.Trickle(mSessionOff);
|
||||
|
||||
UniquePtr<Sdp> remoteAnswer(Parse(mSessionOff.GetRemoteDescription()));
|
||||
for (size_t i = 0; i < remoteAnswer->GetMediaSectionCount(); ++i) {
|
||||
mAnsCandidates.CheckRtpCandidates(
|
||||
i == 0, remoteAnswer->GetMediaSection(i), i,
|
||||
"Remote answer after trickle should have RTP candidates on level 0.");
|
||||
mAnsCandidates.CheckDefaultRtpCandidate(
|
||||
false, remoteAnswer->GetMediaSection(i), i,
|
||||
"Remote answer after trickle should not have a default RTP candidate.");
|
||||
mAnsCandidates.CheckRtcpCandidates(
|
||||
false, remoteAnswer->GetMediaSection(i), i,
|
||||
"Remote answer after trickle should not have RTCP candidates "
|
||||
"(because we're answering with rtcp-mux)");
|
||||
mAnsCandidates.CheckDefaultRtcpCandidate(
|
||||
false, remoteAnswer->GetMediaSection(i), i,
|
||||
"Remote answer after trickle should not have a default RTCP "
|
||||
"candidate.");
|
||||
CheckEndOfCandidates(false, remoteAnswer->GetMediaSection(i),
|
||||
"Remote answer after trickle should not have an end-of-candidates.");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(JsepSessionTest, RenegotiationWithCandidates)
|
||||
{
|
||||
AddTracks(mSessionOff);
|
||||
std::string offer = CreateOffer();
|
||||
SetLocalOffer(offer);
|
||||
mOffCandidates.Gather(mSessionOff, types);
|
||||
SetRemoteOffer(offer);
|
||||
mOffCandidates.Trickle(mSessionAns);
|
||||
AddTracks(mSessionAns);
|
||||
std::string answer = CreateAnswer();
|
||||
SetLocalAnswer(answer);
|
||||
mAnsCandidates.Gather(mSessionAns, types);
|
||||
SetRemoteAnswer(answer);
|
||||
mAnsCandidates.Trickle(mSessionOff);
|
||||
|
||||
offer = CreateOffer();
|
||||
SetLocalOffer(offer);
|
||||
|
||||
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||
for (size_t i = 0; i < parsedOffer->GetMediaSectionCount(); ++i) {
|
||||
mOffCandidates.CheckRtpCandidates(
|
||||
i == 0, parsedOffer->GetMediaSection(i), i,
|
||||
"Local reoffer before gathering should have RTP candidates on level 0"
|
||||
" only.");
|
||||
mOffCandidates.CheckDefaultRtpCandidate(
|
||||
i == 0, parsedOffer->GetMediaSection(i), 0,
|
||||
"Local reoffer before gathering should have a default RTP candidate "
|
||||
"on level 0 only.");
|
||||
mOffCandidates.CheckRtcpCandidates(
|
||||
false, parsedOffer->GetMediaSection(i), i,
|
||||
"Local reoffer before gathering should not have RTCP candidates.");
|
||||
mOffCandidates.CheckDefaultRtcpCandidate(
|
||||
false, parsedOffer->GetMediaSection(i), i,
|
||||
"Local reoffer before gathering should not have a default RTCP "
|
||||
"candidate.");
|
||||
CheckEndOfCandidates(false, parsedOffer->GetMediaSection(i),
|
||||
"Local reoffer before gathering should not have an end-of-candidates.");
|
||||
}
|
||||
|
||||
// mSessionAns should generate a reoffer that is similar
|
||||
std::string otherOffer;
|
||||
JsepOfferOptions defaultOptions;
|
||||
nsresult rv = mSessionAns.CreateOffer(defaultOptions, &otherOffer);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
parsedOffer = Parse(otherOffer);
|
||||
for (size_t i = 0; i < parsedOffer->GetMediaSectionCount(); ++i) {
|
||||
mAnsCandidates.CheckRtpCandidates(
|
||||
i == 0, parsedOffer->GetMediaSection(i), i,
|
||||
"Local reoffer before gathering should have RTP candidates on level 0"
|
||||
" only. (previous answerer)");
|
||||
mAnsCandidates.CheckDefaultRtpCandidate(
|
||||
i == 0, parsedOffer->GetMediaSection(i), 0,
|
||||
"Local reoffer before gathering should have a default RTP candidate "
|
||||
"on level 0 only. (previous answerer)");
|
||||
mAnsCandidates.CheckRtcpCandidates(
|
||||
false, parsedOffer->GetMediaSection(i), i,
|
||||
"Local reoffer before gathering should not have RTCP candidates."
|
||||
" (previous answerer)");
|
||||
mAnsCandidates.CheckDefaultRtcpCandidate(
|
||||
false, parsedOffer->GetMediaSection(i), i,
|
||||
"Local reoffer before gathering should not have a default RTCP "
|
||||
"candidate. (previous answerer)");
|
||||
CheckEndOfCandidates(false, parsedOffer->GetMediaSection(i),
|
||||
"Local reoffer before gathering should not have an end-of-candidates. "
|
||||
"(previous answerer)");
|
||||
}
|
||||
|
||||
// Ok, let's continue with the renegotiation
|
||||
SetRemoteOffer(offer);
|
||||
|
||||
// PeerConnection will not re-gather for RTP, but it will for RTCP in case
|
||||
// the answerer decides to turn off rtcp-mux.
|
||||
if (types[0] != SdpMediaSection::kApplication) {
|
||||
mOffCandidates.Gather(mSessionOff, 0, RTCP);
|
||||
}
|
||||
|
||||
// Since the remaining levels were bundled, PeerConnection will re-gather for
|
||||
// both RTP and RTCP, in case the answerer rejects bundle.
|
||||
for (size_t level = 1; level < types.size(); ++level) {
|
||||
mOffCandidates.Gather(mSessionOff, level, RTP);
|
||||
if (types[level] != SdpMediaSection::kApplication) {
|
||||
mOffCandidates.Gather(mSessionOff, level, RTCP);
|
||||
}
|
||||
}
|
||||
mOffCandidates.FinishGathering(mSessionOff);
|
||||
|
||||
mOffCandidates.Trickle(mSessionAns);
|
||||
|
||||
UniquePtr<Sdp> localOffer(Parse(mSessionOff.GetLocalDescription()));
|
||||
for (size_t i = 0; i < localOffer->GetMediaSectionCount(); ++i) {
|
||||
mOffCandidates.CheckRtpCandidates(
|
||||
true, localOffer->GetMediaSection(i), i,
|
||||
"Local reoffer after gathering should have RTP candidates.");
|
||||
mOffCandidates.CheckDefaultRtpCandidate(
|
||||
true, localOffer->GetMediaSection(i), i,
|
||||
"Local reoffer after gathering should have a default RTP candidate.");
|
||||
mOffCandidates.CheckRtcpCandidates(
|
||||
types[i] != SdpMediaSection::kApplication,
|
||||
localOffer->GetMediaSection(i), i,
|
||||
"Local reoffer after gathering should have RTCP candidates "
|
||||
"(unless m=application)");
|
||||
mOffCandidates.CheckDefaultRtcpCandidate(
|
||||
types[i] != SdpMediaSection::kApplication,
|
||||
localOffer->GetMediaSection(i), i,
|
||||
"Local reoffer after gathering should have a default RTCP candidate "
|
||||
"(unless m=application)");
|
||||
CheckEndOfCandidates(true, localOffer->GetMediaSection(i),
|
||||
"Local reoffer after gathering should have an end-of-candidates.");
|
||||
}
|
||||
|
||||
UniquePtr<Sdp> remoteOffer(Parse(mSessionAns.GetRemoteDescription()));
|
||||
for (size_t i = 0; i < remoteOffer->GetMediaSectionCount(); ++i) {
|
||||
mOffCandidates.CheckRtpCandidates(
|
||||
true, remoteOffer->GetMediaSection(i), i,
|
||||
"Remote reoffer after trickle should have RTP candidates.");
|
||||
mOffCandidates.CheckDefaultRtpCandidate(
|
||||
i == 0, remoteOffer->GetMediaSection(i), i,
|
||||
"Remote reoffer should have a default RTP candidate on level 0 "
|
||||
"(because it was gathered last offer/answer).");
|
||||
mOffCandidates.CheckRtcpCandidates(
|
||||
types[i] != SdpMediaSection::kApplication,
|
||||
remoteOffer->GetMediaSection(i), i,
|
||||
"Remote reoffer after trickle should have RTCP candidates.");
|
||||
mOffCandidates.CheckDefaultRtcpCandidate(
|
||||
false, remoteOffer->GetMediaSection(i), i,
|
||||
"Remote reoffer should not have a default RTCP candidate.");
|
||||
CheckEndOfCandidates(false, remoteOffer->GetMediaSection(i),
|
||||
"Remote reoffer should not have an end-of-candidates.");
|
||||
}
|
||||
|
||||
answer = CreateAnswer();
|
||||
SetLocalAnswer(answer);
|
||||
SetRemoteAnswer(answer);
|
||||
// No candidates should be gathered at the answerer, but default candidates
|
||||
// should be set.
|
||||
mAnsCandidates.FinishGathering(mSessionAns);
|
||||
|
||||
UniquePtr<Sdp> localAnswer(Parse(mSessionAns.GetLocalDescription()));
|
||||
for (size_t i = 0; i < localAnswer->GetMediaSectionCount(); ++i) {
|
||||
mAnsCandidates.CheckRtpCandidates(
|
||||
i == 0, localAnswer->GetMediaSection(i), i,
|
||||
"Local reanswer after gathering should have RTP candidates on level "
|
||||
"0.");
|
||||
mAnsCandidates.CheckDefaultRtpCandidate(
|
||||
true, localAnswer->GetMediaSection(i), 0,
|
||||
"Local reanswer after gathering should have a default RTP candidate "
|
||||
"on all levels that matches transport level 0.");
|
||||
mAnsCandidates.CheckRtcpCandidates(
|
||||
false, localAnswer->GetMediaSection(i), i,
|
||||
"Local reanswer after gathering should not have RTCP candidates "
|
||||
"(because we're reanswering with rtcp-mux)");
|
||||
mAnsCandidates.CheckDefaultRtcpCandidate(
|
||||
false, localAnswer->GetMediaSection(i), i,
|
||||
"Local reanswer after gathering should not have a default RTCP "
|
||||
"candidate (because we're reanswering with rtcp-mux)");
|
||||
CheckEndOfCandidates(i == 0, localAnswer->GetMediaSection(i),
|
||||
"Local reanswer after gathering should have an end-of-candidates only "
|
||||
"for level 0.");
|
||||
}
|
||||
|
||||
UniquePtr<Sdp> remoteAnswer(Parse(mSessionOff.GetRemoteDescription()));
|
||||
for (size_t i = 0; i < localAnswer->GetMediaSectionCount(); ++i) {
|
||||
mAnsCandidates.CheckRtpCandidates(
|
||||
i == 0, remoteAnswer->GetMediaSection(i), i,
|
||||
"Remote reanswer after trickle should have RTP candidates on level 0.");
|
||||
mAnsCandidates.CheckDefaultRtpCandidate(
|
||||
i == 0, remoteAnswer->GetMediaSection(i), i,
|
||||
"Remote reanswer should have a default RTP candidate on level 0 "
|
||||
"(because it was gathered last offer/answer).");
|
||||
mAnsCandidates.CheckRtcpCandidates(
|
||||
false, remoteAnswer->GetMediaSection(i), i,
|
||||
"Remote reanswer after trickle should not have RTCP candidates "
|
||||
"(because we're reanswering with rtcp-mux)");
|
||||
mAnsCandidates.CheckDefaultRtcpCandidate(
|
||||
false, remoteAnswer->GetMediaSection(i), i,
|
||||
"Remote reanswer after trickle should not have a default RTCP "
|
||||
"candidate.");
|
||||
CheckEndOfCandidates(false, remoteAnswer->GetMediaSection(i),
|
||||
"Remote reanswer after trickle should not have an end-of-candidates.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Variants,
|
||||
JsepSessionTest,
|
||||
|
@ -2039,10 +2376,8 @@ TEST_F(JsepSessionTest, OfferAnswerRecvOnlyLines)
|
|||
options.mDontOfferDataChannel = Some(true);
|
||||
std::string offer = CreateOffer(Some(options));
|
||||
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> parsedOffer = parser.Parse(offer);
|
||||
ASSERT_TRUE(!!parsedOffer) << "Should have valid SDP" << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||
ASSERT_TRUE(!!parsedOffer);
|
||||
|
||||
ASSERT_EQ(3U, parsedOffer->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||
|
@ -2079,7 +2414,7 @@ TEST_F(JsepSessionTest, OfferAnswerRecvOnlyLines)
|
|||
SetRemoteOffer(offer, CHECK_SUCCESS);
|
||||
|
||||
std::string answer = CreateAnswer();
|
||||
UniquePtr<Sdp> parsedAnswer = parser.Parse(answer);
|
||||
UniquePtr<Sdp> parsedAnswer(Parse(answer));
|
||||
|
||||
ASSERT_EQ(3U, parsedAnswer->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||
|
@ -2118,10 +2453,8 @@ TEST_F(JsepSessionTest, OfferAnswerSendOnlyLines)
|
|||
options.mDontOfferDataChannel = Some(true);
|
||||
std::string offer = CreateOffer(Some(options));
|
||||
|
||||
SipccSdpParser parser;
|
||||
auto outputSdp = parser.Parse(offer);
|
||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
UniquePtr<Sdp> outputSdp(Parse(offer));
|
||||
ASSERT_TRUE(!!outputSdp);
|
||||
|
||||
ASSERT_EQ(3U, outputSdp->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||
|
@ -2150,7 +2483,7 @@ TEST_F(JsepSessionTest, OfferAnswerSendOnlyLines)
|
|||
SetRemoteOffer(offer, CHECK_SUCCESS);
|
||||
|
||||
std::string answer = CreateAnswer();
|
||||
outputSdp = parser.Parse(answer);
|
||||
outputSdp = Parse(answer);
|
||||
|
||||
ASSERT_EQ(3U, outputSdp->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||
|
@ -2174,8 +2507,7 @@ TEST_F(JsepSessionTest, OfferToReceiveAudioNotUsed)
|
|||
|
||||
OfferAnswer(CHECK_SUCCESS, Some(options));
|
||||
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> offer(parser.Parse(mSessionOff.GetLocalDescription()));
|
||||
UniquePtr<Sdp> offer(Parse(mSessionOff.GetLocalDescription()));
|
||||
ASSERT_TRUE(offer.get());
|
||||
ASSERT_EQ(1U, offer->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||
|
@ -2183,7 +2515,7 @@ TEST_F(JsepSessionTest, OfferToReceiveAudioNotUsed)
|
|||
ASSERT_EQ(SdpDirectionAttribute::kRecvonly,
|
||||
offer->GetMediaSection(0).GetAttributeList().GetDirection());
|
||||
|
||||
UniquePtr<Sdp> answer(parser.Parse(mSessionAns.GetLocalDescription()));
|
||||
UniquePtr<Sdp> answer(Parse(mSessionAns.GetLocalDescription()));
|
||||
ASSERT_TRUE(answer.get());
|
||||
ASSERT_EQ(1U, answer->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||
|
@ -2199,8 +2531,7 @@ TEST_F(JsepSessionTest, OfferToReceiveVideoNotUsed)
|
|||
|
||||
OfferAnswer(CHECK_SUCCESS, Some(options));
|
||||
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> offer(parser.Parse(mSessionOff.GetLocalDescription()));
|
||||
UniquePtr<Sdp> offer(Parse(mSessionOff.GetLocalDescription()));
|
||||
ASSERT_TRUE(offer.get());
|
||||
ASSERT_EQ(1U, offer->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kVideo,
|
||||
|
@ -2208,7 +2539,7 @@ TEST_F(JsepSessionTest, OfferToReceiveVideoNotUsed)
|
|||
ASSERT_EQ(SdpDirectionAttribute::kRecvonly,
|
||||
offer->GetMediaSection(0).GetAttributeList().GetDirection());
|
||||
|
||||
UniquePtr<Sdp> answer(parser.Parse(mSessionAns.GetLocalDescription()));
|
||||
UniquePtr<Sdp> answer(Parse(mSessionAns.GetLocalDescription()));
|
||||
ASSERT_TRUE(answer.get());
|
||||
ASSERT_EQ(1U, answer->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kVideo,
|
||||
|
@ -2229,10 +2560,8 @@ TEST_F(JsepSessionTest, CreateOfferNoDatachannelDefault)
|
|||
|
||||
std::string offer = CreateOffer();
|
||||
|
||||
SipccSdpParser parser;
|
||||
auto outputSdp = parser.Parse(offer);
|
||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
UniquePtr<Sdp> outputSdp(Parse(offer));
|
||||
ASSERT_TRUE(!!outputSdp);
|
||||
|
||||
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||
|
@ -2255,10 +2584,8 @@ TEST_F(JsepSessionTest, ValidateOfferedCodecParams)
|
|||
|
||||
std::string offer = CreateOffer();
|
||||
|
||||
SipccSdpParser parser;
|
||||
auto outputSdp = parser.Parse(offer);
|
||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
UniquePtr<Sdp> outputSdp(Parse(offer));
|
||||
ASSERT_TRUE(!!outputSdp);
|
||||
|
||||
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
||||
auto& video_section = outputSdp->GetMediaSection(1);
|
||||
|
@ -2389,10 +2716,8 @@ TEST_F(JsepSessionTest, ValidateAnsweredCodecParams)
|
|||
|
||||
std::string answer = CreateAnswer();
|
||||
|
||||
SipccSdpParser parser;
|
||||
auto outputSdp = parser.Parse(answer);
|
||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
UniquePtr<Sdp> outputSdp(Parse(answer));
|
||||
ASSERT_TRUE(!!outputSdp);
|
||||
|
||||
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
||||
auto& video_section = outputSdp->GetMediaSection(1);
|
||||
|
@ -2889,10 +3214,8 @@ TEST_P(JsepSessionTest, TestRejectMline)
|
|||
|
||||
std::string answer = CreateAnswer();
|
||||
|
||||
SipccSdpParser parser;
|
||||
auto outputSdp = parser.Parse(answer);
|
||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
||||
<< "Errors were: " << GetParseErrors(parser);
|
||||
UniquePtr<Sdp> outputSdp(Parse(answer));
|
||||
ASSERT_TRUE(!!outputSdp);
|
||||
|
||||
ASSERT_NE(0U, outputSdp->GetMediaSectionCount());
|
||||
SdpMediaSection* failed_section = nullptr;
|
||||
|
@ -2942,8 +3265,7 @@ TEST_F(JsepSessionTest, TestIceLite)
|
|||
std::string offer = CreateOffer();
|
||||
SetLocalOffer(offer, CHECK_SUCCESS);
|
||||
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> parsedOffer = parser.Parse(offer);
|
||||
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||
parsedOffer->GetAttributeList().SetAttribute(
|
||||
new SdpFlagAttribute(SdpAttribute::kIceLiteAttribute));
|
||||
|
||||
|
@ -2988,8 +3310,7 @@ TEST_F(JsepSessionTest, TestExtmap)
|
|||
SetLocalAnswer(answer, CHECK_SUCCESS);
|
||||
SetRemoteAnswer(answer, CHECK_SUCCESS);
|
||||
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> parsedOffer = parser.Parse(offer);
|
||||
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||
ASSERT_EQ(1U, parsedOffer->GetMediaSectionCount());
|
||||
|
||||
auto& offerMediaAttrs = parsedOffer->GetMediaSection(0).GetAttributeList();
|
||||
|
@ -3004,7 +3325,7 @@ TEST_F(JsepSessionTest, TestExtmap)
|
|||
ASSERT_EQ("bar", offerExtmap[2].extensionname);
|
||||
ASSERT_EQ(3U, offerExtmap[2].entry);
|
||||
|
||||
UniquePtr<Sdp> parsedAnswer = parser.Parse(answer);
|
||||
UniquePtr<Sdp> parsedAnswer(Parse(answer));
|
||||
ASSERT_EQ(1U, parsedAnswer->GetMediaSectionCount());
|
||||
|
||||
auto& answerMediaAttrs = parsedAnswer->GetMediaSection(0).GetAttributeList();
|
||||
|
@ -3026,8 +3347,7 @@ TEST_F(JsepSessionTest, TestRtcpFbStar)
|
|||
|
||||
std::string offer = CreateOffer();
|
||||
|
||||
SipccSdpParser parser;
|
||||
UniquePtr<Sdp> parsedOffer = parser.Parse(offer);
|
||||
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||
auto* rtcpfbs = new SdpRtcpFbAttributeList;
|
||||
rtcpfbs->PushEntry("*", SdpRtcpFbAttributeList::kNack);
|
||||
parsedOffer->GetMediaSection(0).GetAttributeList().SetAttribute(rtcpfbs);
|
||||
|
|
Загрузка…
Ссылка в новой задаче