mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1192390 - Part 2: Simulcast and RID negotiation. r=mt
--HG-- extra : transplant_source : %D1%CAj%05%C7%7B%92%D9%CDV%24j%FF%CB%24B%D4%03%92%5E
This commit is contained in:
parent
dac8417d25
commit
bc30932b74
@ -103,6 +103,9 @@ void
|
|||||||
JsepTrack::AddToOffer(SdpMediaSection* offer) const
|
JsepTrack::AddToOffer(SdpMediaSection* offer) const
|
||||||
{
|
{
|
||||||
AddToMsection(mPrototypeCodecs.values, offer);
|
AddToMsection(mPrototypeCodecs.values, offer);
|
||||||
|
if (mDirection == sdp::kSend) {
|
||||||
|
AddToMsection(mJsEncodeConstraints, sdp::kSend, offer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -119,6 +122,14 @@ JsepTrack::AddToAnswer(const SdpMediaSection& offer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
AddToMsection(codecs.values, answer);
|
AddToMsection(codecs.values, answer);
|
||||||
|
|
||||||
|
if (mDirection == sdp::kSend) {
|
||||||
|
std::vector<JsConstraints> constraints;
|
||||||
|
std::vector<SdpRidAttributeList::Rid> rids;
|
||||||
|
GetRids(offer, sdp::kRecv, &rids);
|
||||||
|
NegotiateRids(rids, &constraints);
|
||||||
|
AddToMsection(constraints, sdp::kSend, answer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -143,59 +154,143 @@ JsepTrack::AddToMsection(const std::vector<JsepCodecDescription*>& codecs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates the |id| values in |constraintsList| with the rid values in |rids|,
|
||||||
|
// where necessary.
|
||||||
void
|
void
|
||||||
JsepTrack::GetRids(const SdpMediaSection& msection,
|
JsepTrack::NegotiateRids(const std::vector<SdpRidAttributeList::Rid>& rids,
|
||||||
std::vector<SdpRidAttributeList::Rid>* rids) const
|
std::vector<JsConstraints>* constraintsList) const
|
||||||
{
|
{
|
||||||
// TODO(bug 1192390): Get list of rids from |answer|; first rid from each
|
for (const SdpRidAttributeList::Rid& rid : rids) {
|
||||||
// simulcast version.
|
if (!FindConstraints(rid.id, *constraintsList)) {
|
||||||
|
// Pair up the first JsConstraints with an empty id, if it exists.
|
||||||
|
JsConstraints* constraints = FindConstraints("", *constraintsList);
|
||||||
|
if (constraints) {
|
||||||
|
constraints->rid = rid.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
void
|
||||||
|
JsepTrack::AddToMsection(const std::vector<JsConstraints>& constraintsList,
|
||||||
|
sdp::Direction direction,
|
||||||
|
SdpMediaSection* msection)
|
||||||
|
{
|
||||||
|
UniquePtr<SdpSimulcastAttribute> simulcast(new SdpSimulcastAttribute);
|
||||||
|
UniquePtr<SdpRidAttributeList> rids(new SdpRidAttributeList);
|
||||||
|
for (const JsConstraints& constraints : constraintsList) {
|
||||||
|
if (!constraints.rid.empty()) {
|
||||||
|
SdpRidAttributeList::Rid rid;
|
||||||
|
rid.id = constraints.rid;
|
||||||
|
rid.direction = direction;
|
||||||
|
rids->mRids.push_back(rid);
|
||||||
|
|
||||||
|
SdpSimulcastAttribute::Version version;
|
||||||
|
version.choices.push_back(constraints.rid);
|
||||||
|
if (direction == sdp::kSend) {
|
||||||
|
simulcast->sendVersions.push_back(version);
|
||||||
|
} else {
|
||||||
|
simulcast->recvVersions.push_back(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rids->mRids.empty()) {
|
||||||
|
msection->GetAttributeList().SetAttribute(simulcast.release());
|
||||||
|
msection->GetAttributeList().SetAttribute(rids.release());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JsepTrack::UpdateRidsFromAnswer(
|
JsepTrack::GetRids(const SdpMediaSection& msection,
|
||||||
const std::vector<SdpRidAttributeList::Rid>& rids)
|
sdp::Direction direction,
|
||||||
|
std::vector<SdpRidAttributeList::Rid>* rids) const
|
||||||
{
|
{
|
||||||
// TODO(bug 1192390): For each rid, try to pair it with something in
|
rids->clear();
|
||||||
// mEncodingParameters (either by matching rid, or just matching by index).
|
if (!msection.GetAttributeList().HasAttribute(
|
||||||
// Once these are paired up, update the ids in mEncodingParameters to match.
|
SdpAttribute::kSimulcastAttribute)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SdpSimulcastAttribute& simulcast(
|
||||||
|
msection.GetAttributeList().GetSimulcast());
|
||||||
|
|
||||||
|
const SdpSimulcastAttribute::Versions* versions = nullptr;
|
||||||
|
switch (direction) {
|
||||||
|
case sdp::kSend:
|
||||||
|
versions = &simulcast.sendVersions;
|
||||||
|
break;
|
||||||
|
case sdp::kRecv:
|
||||||
|
versions = &simulcast.recvVersions;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!versions->IsSet()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (versions->type != SdpSimulcastAttribute::Versions::kRid) {
|
||||||
|
// No support for PT-based simulcast, yet.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const SdpSimulcastAttribute::Version& version : *versions) {
|
||||||
|
if (!version.choices.empty()) {
|
||||||
|
// We validate that rids are present (and sane) elsewhere.
|
||||||
|
rids->push_back(*msection.FindRid(version.choices[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsepTrack::JsConstraints*
|
||||||
|
JsepTrack::FindConstraints(const std::string& id,
|
||||||
|
std::vector<JsConstraints>& constraintsList) const
|
||||||
|
{
|
||||||
|
for (JsConstraints& constraints : constraintsList) {
|
||||||
|
if (constraints.rid == id) {
|
||||||
|
return &constraints;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JsepTrack::CreateEncodings(
|
JsepTrack::CreateEncodings(
|
||||||
const SdpMediaSection& answer,
|
const SdpMediaSection& remote,
|
||||||
const std::vector<JsepCodecDescription*>& negotiatedCodecs,
|
const std::vector<JsepCodecDescription*>& negotiatedCodecs,
|
||||||
JsepTrackNegotiatedDetails* negotiatedDetails)
|
JsepTrackNegotiatedDetails* negotiatedDetails)
|
||||||
{
|
{
|
||||||
std::vector<SdpRidAttributeList::Rid> answerRids;
|
std::vector<SdpRidAttributeList::Rid> rids;
|
||||||
GetRids(answer, &answerRids);
|
GetRids(remote, sdp::kRecv, &rids); // Get rids we will send
|
||||||
UpdateRidsFromAnswer(answerRids);
|
NegotiateRids(rids, &mJsEncodeConstraints);
|
||||||
if (answerRids.empty()) {
|
if (rids.empty()) {
|
||||||
// Add dummy value with an empty id to make sure we get a single unicast
|
// Add dummy value with an empty id to make sure we get a single unicast
|
||||||
// stream.
|
// stream.
|
||||||
answerRids.push_back(SdpRidAttributeList::Rid());
|
rids.push_back(SdpRidAttributeList::Rid());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each rid in the answer, make sure we have an encoding, and configure
|
// For each rid in the remote, make sure we have an encoding, and configure
|
||||||
// that encoding appropriately.
|
// that encoding appropriately.
|
||||||
for (size_t i = 0; i < answerRids.size(); ++i) {
|
for (size_t i = 0; i < rids.size(); ++i) {
|
||||||
if (i >= negotiatedDetails->mEncodings.values.size()) {
|
if (i == negotiatedDetails->mEncodings.values.size()) {
|
||||||
negotiatedDetails->mEncodings.values.push_back(new JsepTrackEncoding);
|
negotiatedDetails->mEncodings.values.push_back(new JsepTrackEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsepTrackEncoding* encoding = negotiatedDetails->mEncodings.values[i];
|
JsepTrackEncoding* encoding = negotiatedDetails->mEncodings.values[i];
|
||||||
|
|
||||||
for (const JsepCodecDescription* codec : negotiatedCodecs) {
|
for (const JsepCodecDescription* codec : negotiatedCodecs) {
|
||||||
if (answerRids[i].HasFormat(codec->mDefaultPt)) {
|
if (rids[i].HasFormat(codec->mDefaultPt)) {
|
||||||
encoding->AddCodec(*codec);
|
encoding->AddCodec(*codec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
encoding->mRid = answerRids[i].id;
|
encoding->mRid = rids[i].id;
|
||||||
// If we end up supporting params for rid, we would handle that here.
|
// If we end up supporting params for rid, we would handle that here.
|
||||||
|
|
||||||
// Incorporate the corresponding JS encoding constraints, if they exist
|
// Incorporate the corresponding JS encoding constraints, if they exist
|
||||||
for (const JsConstraints& jsConstraints : mJsEncodeConstraints) {
|
for (const JsConstraints& jsConstraints : mJsEncodeConstraints) {
|
||||||
if (jsConstraints.id == answerRids[i].id) {
|
if (jsConstraints.rid == rids[i].id) {
|
||||||
encoding->mConstraints = jsConstraints.constraints;
|
encoding->mConstraints = jsConstraints.constraints;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,7 +399,7 @@ JsepTrack::Negotiate(const SdpMediaSection& answer,
|
|||||||
UniquePtr<JsepTrackNegotiatedDetails> negotiatedDetails =
|
UniquePtr<JsepTrackNegotiatedDetails> negotiatedDetails =
|
||||||
MakeUnique<JsepTrackNegotiatedDetails>();
|
MakeUnique<JsepTrackNegotiatedDetails>();
|
||||||
|
|
||||||
CreateEncodings(answer, negotiatedCodecs.values, negotiatedDetails.get());
|
CreateEncodings(remote, negotiatedCodecs.values, negotiatedDetails.get());
|
||||||
|
|
||||||
if (answer.GetAttributeList().HasAttribute(SdpAttribute::kExtmapAttribute)) {
|
if (answer.GetAttributeList().HasAttribute(SdpAttribute::kExtmapAttribute)) {
|
||||||
for (auto& extmapAttr : answer.GetAttributeList().GetExtmap().mExtmaps) {
|
for (auto& extmapAttr : answer.GetAttributeList().GetExtmap().mExtmaps) {
|
||||||
|
@ -174,6 +174,21 @@ public:
|
|||||||
|
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(JsepTrack);
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(JsepTrack);
|
||||||
|
|
||||||
|
struct JsConstraints
|
||||||
|
{
|
||||||
|
std::string rid;
|
||||||
|
EncodingConstraints constraints;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetJsConstraints(const std::vector<JsConstraints>& constraintsList)
|
||||||
|
{
|
||||||
|
mJsEncodeConstraints = constraintsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddToMsection(const std::vector<JsConstraints>& constraintsList,
|
||||||
|
sdp::Direction direction,
|
||||||
|
SdpMediaSection* msection);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~JsepTrack() {}
|
virtual ~JsepTrack() {}
|
||||||
|
|
||||||
@ -189,10 +204,10 @@ private:
|
|||||||
void AddToMsection(const std::vector<JsepCodecDescription*>& codecs,
|
void AddToMsection(const std::vector<JsepCodecDescription*>& codecs,
|
||||||
SdpMediaSection* msection) const;
|
SdpMediaSection* msection) const;
|
||||||
void GetRids(const SdpMediaSection& msection,
|
void GetRids(const SdpMediaSection& msection,
|
||||||
|
sdp::Direction direction,
|
||||||
std::vector<SdpRidAttributeList::Rid>* rids) const;
|
std::vector<SdpRidAttributeList::Rid>* rids) const;
|
||||||
void UpdateRidsFromAnswer(const std::vector<SdpRidAttributeList::Rid>& rids);
|
|
||||||
void CreateEncodings(
|
void CreateEncodings(
|
||||||
const SdpMediaSection& answer,
|
const SdpMediaSection& remote,
|
||||||
const std::vector<JsepCodecDescription*>& negotiatedCodecs,
|
const std::vector<JsepCodecDescription*>& negotiatedCodecs,
|
||||||
JsepTrackNegotiatedDetails* details);
|
JsepTrackNegotiatedDetails* details);
|
||||||
|
|
||||||
@ -207,17 +222,18 @@ private:
|
|||||||
const SdpMediaSection* answer = nullptr,
|
const SdpMediaSection* answer = nullptr,
|
||||||
std::map<std::string, std::string>* formatChanges = nullptr) const;
|
std::map<std::string, std::string>* formatChanges = nullptr) const;
|
||||||
|
|
||||||
|
JsConstraints* FindConstraints(
|
||||||
|
const std::string& rid,
|
||||||
|
std::vector<JsConstraints>& constraintsList) const;
|
||||||
|
void NegotiateRids(const std::vector<SdpRidAttributeList::Rid>& rids,
|
||||||
|
std::vector<JsConstraints>* constraints) const;
|
||||||
|
|
||||||
const mozilla::SdpMediaSection::MediaType mType;
|
const mozilla::SdpMediaSection::MediaType mType;
|
||||||
std::string mStreamId;
|
std::string mStreamId;
|
||||||
std::string mTrackId;
|
std::string mTrackId;
|
||||||
std::string mCNAME;
|
std::string mCNAME;
|
||||||
const sdp::Direction mDirection;
|
const sdp::Direction mDirection;
|
||||||
PtrVector<JsepCodecDescription> mPrototypeCodecs;
|
PtrVector<JsepCodecDescription> mPrototypeCodecs;
|
||||||
struct JsConstraints
|
|
||||||
{
|
|
||||||
std::string id;
|
|
||||||
EncodingConstraints constraints;
|
|
||||||
};
|
|
||||||
// Holds encoding params/constraints from JS. Simulcast happens when there are
|
// Holds encoding params/constraints from JS. Simulcast happens when there are
|
||||||
// multiple of these. If there are none, we assume unconstrained unicast with
|
// multiple of these. If there are none, we assume unconstrained unicast with
|
||||||
// no rid.
|
// no rid.
|
||||||
|
@ -104,7 +104,7 @@ class SdpHelper {
|
|||||||
nsresult CopyStickyParams(const SdpMediaSection& source,
|
nsresult CopyStickyParams(const SdpMediaSection& source,
|
||||||
SdpMediaSection* dest);
|
SdpMediaSection* dest);
|
||||||
bool HasRtcp(SdpMediaSection::Protocol proto) const;
|
bool HasRtcp(SdpMediaSection::Protocol proto) const;
|
||||||
SdpMediaSection::Protocol GetProtocolForMediaType(
|
static SdpMediaSection::Protocol GetProtocolForMediaType(
|
||||||
SdpMediaSection::MediaType type);
|
SdpMediaSection::MediaType type);
|
||||||
void appendSdpParseErrors(
|
void appendSdpParseErrors(
|
||||||
const std::vector<std::pair<size_t, std::string> >& aErrors,
|
const std::vector<std::pair<size_t, std::string> >& aErrors,
|
||||||
|
@ -156,5 +156,21 @@ SdpMediaSection::AddMsid(const std::string& id, const std::string& appdata)
|
|||||||
GetAttributeList().SetAttribute(msids.release());
|
GetAttributeList().SetAttribute(msids.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SdpRidAttributeList::Rid*
|
||||||
|
SdpMediaSection::FindRid(const std::string& id) const
|
||||||
|
{
|
||||||
|
if (!GetAttributeList().HasAttribute(SdpAttribute::kRidAttribute)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& rid : GetAttributeList().GetRid().mRids) {
|
||||||
|
if (rid.id == id) {
|
||||||
|
return &rid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
@ -169,6 +169,7 @@ public:
|
|||||||
void SetSsrcs(const std::vector<uint32_t>& ssrcs,
|
void SetSsrcs(const std::vector<uint32_t>& ssrcs,
|
||||||
const std::string& cname);
|
const std::string& cname);
|
||||||
void AddMsid(const std::string& id, const std::string& appdata);
|
void AddMsid(const std::string& id, const std::string& appdata);
|
||||||
|
const SdpRidAttributeList::Rid* FindRid(const std::string& id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t mLevel;
|
size_t mLevel;
|
||||||
|
@ -136,6 +136,10 @@ SipccSdpMediaSection::Load(sdp_t* sdp, uint16_t level,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ValidateSimulcast(sdp, level, errorHolder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mBandwidths.Load(sdp, level, errorHolder)) {
|
if (!mBandwidths.Load(sdp, level, errorHolder)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -223,6 +227,68 @@ SipccSdpMediaSection::LoadFormats(sdp_t* sdp,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SipccSdpMediaSection::ValidateSimulcast(sdp_t* sdp, uint16_t level,
|
||||||
|
SdpErrorHolder& errorHolder) const
|
||||||
|
{
|
||||||
|
if (!GetAttributeList().HasAttribute(SdpAttribute::kSimulcastAttribute)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SdpSimulcastAttribute& simulcast(GetAttributeList().GetSimulcast());
|
||||||
|
if (!ValidateSimulcastVersions(
|
||||||
|
sdp, level, simulcast.sendVersions, sdp::kSend, errorHolder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ValidateSimulcastVersions(
|
||||||
|
sdp, level, simulcast.recvVersions, sdp::kRecv, errorHolder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SipccSdpMediaSection::ValidateSimulcastVersions(
|
||||||
|
sdp_t* sdp,
|
||||||
|
uint16_t level,
|
||||||
|
const SdpSimulcastAttribute::Versions& versions,
|
||||||
|
sdp::Direction direction,
|
||||||
|
SdpErrorHolder& errorHolder) const
|
||||||
|
{
|
||||||
|
if (versions.IsSet() && !(direction & GetDirectionAttribute().mValue)) {
|
||||||
|
errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
|
||||||
|
"simulcast attribute has a direction that is "
|
||||||
|
"inconsistent with the direction of this media "
|
||||||
|
"section.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const SdpSimulcastAttribute::Version& version : versions) {
|
||||||
|
for (const std::string& id : version.choices) {
|
||||||
|
if (versions.type == SdpSimulcastAttribute::Versions::kRid) {
|
||||||
|
const SdpRidAttributeList::Rid* ridAttr = FindRid(id);
|
||||||
|
if (!ridAttr || (ridAttr->direction != direction)) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "No rid attribute for \'" << id << "\'";
|
||||||
|
errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
|
||||||
|
os.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (versions.type == SdpSimulcastAttribute::Versions::kPt) {
|
||||||
|
if (std::find(mFormats.begin(), mFormats.end(), id)
|
||||||
|
== mFormats.end()) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "No pt for \'" << id << "\'";
|
||||||
|
errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
|
||||||
|
os.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SipccSdpMediaSection::LoadConnection(sdp_t* sdp, uint16_t level,
|
SipccSdpMediaSection::LoadConnection(sdp_t* sdp, uint16_t level,
|
||||||
SdpErrorHolder& errorHolder)
|
SdpErrorHolder& errorHolder)
|
||||||
|
@ -76,6 +76,14 @@ private:
|
|||||||
bool LoadConnection(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
bool LoadConnection(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
||||||
bool LoadProtocol(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
bool LoadProtocol(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
||||||
bool LoadFormats(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
bool LoadFormats(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
||||||
|
bool ValidateSimulcast(sdp_t* sdp, uint16_t level,
|
||||||
|
SdpErrorHolder& errorHolder) const;
|
||||||
|
bool ValidateSimulcastVersions(
|
||||||
|
sdp_t* sdp,
|
||||||
|
uint16_t level,
|
||||||
|
const SdpSimulcastAttribute::Versions& versions,
|
||||||
|
sdp::Direction direction,
|
||||||
|
SdpErrorHolder& errorHolder) const;
|
||||||
|
|
||||||
// the following values are cached on first get
|
// the following values are cached on first get
|
||||||
MediaType mMediaType;
|
MediaType mMediaType;
|
||||||
|
475
media/webrtc/signaling/test/jsep_track_unittest.cpp
Normal file
475
media/webrtc/signaling/test/jsep_track_unittest.cpp
Normal file
@ -0,0 +1,475 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#define GTEST_HAS_RTTI 0
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "gtest_utils.h"
|
||||||
|
|
||||||
|
// Magic linker includes :(
|
||||||
|
#include "FakeMediaStreams.h"
|
||||||
|
#include "FakeMediaStreamsImpl.h"
|
||||||
|
|
||||||
|
#include "signaling/src/jsep/JsepTrack.h"
|
||||||
|
#include "signaling/src/sdp/SipccSdp.h"
|
||||||
|
#include "signaling/src/sdp/SdpHelper.h"
|
||||||
|
|
||||||
|
#include "mtransport_test_utils.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
class JsepTrackTest : public ::testing::Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JsepTrackTest() {}
|
||||||
|
|
||||||
|
std::vector<JsepCodecDescription*>
|
||||||
|
MakeCodecs() const
|
||||||
|
{
|
||||||
|
std::vector<JsepCodecDescription*> results;
|
||||||
|
results.push_back(
|
||||||
|
new JsepAudioCodecDescription("1", "opus", 48000, 2, 960, 40000));
|
||||||
|
results.push_back(
|
||||||
|
new JsepAudioCodecDescription("9", "G722", 8000, 1, 320, 64000));
|
||||||
|
|
||||||
|
JsepVideoCodecDescription* vp8 =
|
||||||
|
new JsepVideoCodecDescription("120", "VP8", 90000);
|
||||||
|
vp8->mConstraints.maxFs = 12288;
|
||||||
|
vp8->mConstraints.maxFps = 60;
|
||||||
|
results.push_back(vp8);
|
||||||
|
|
||||||
|
JsepVideoCodecDescription* h264 =
|
||||||
|
new JsepVideoCodecDescription("126", "H264", 90000);
|
||||||
|
h264->mPacketizationMode = 1;
|
||||||
|
h264->mProfileLevelId = 0x42E00D;
|
||||||
|
results.push_back(h264);
|
||||||
|
|
||||||
|
results.push_back(
|
||||||
|
new JsepApplicationCodecDescription(
|
||||||
|
"5000",
|
||||||
|
"webrtc-datachannel",
|
||||||
|
16
|
||||||
|
));
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init(SdpMediaSection::MediaType type) {
|
||||||
|
InitCodecs();
|
||||||
|
InitTracks(type);
|
||||||
|
InitSdp(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitCodecs() {
|
||||||
|
mOffCodecs.values = MakeCodecs();
|
||||||
|
mAnsCodecs.values = MakeCodecs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitTracks(SdpMediaSection::MediaType type)
|
||||||
|
{
|
||||||
|
mSendOff = new JsepTrack(type, "stream_id", "track_id", sdp::kSend);
|
||||||
|
mRecvOff = new JsepTrack(type, "stream_id", "track_id", sdp::kRecv);
|
||||||
|
mSendOff->PopulateCodecs(mOffCodecs.values);
|
||||||
|
mRecvOff->PopulateCodecs(mOffCodecs.values);
|
||||||
|
|
||||||
|
mSendAns = new JsepTrack(type, "stream_id", "track_id", sdp::kSend);
|
||||||
|
mRecvAns = new JsepTrack(type, "stream_id", "track_id", sdp::kRecv);
|
||||||
|
mSendAns->PopulateCodecs(mAnsCodecs.values);
|
||||||
|
mRecvAns->PopulateCodecs(mAnsCodecs.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitSdp(SdpMediaSection::MediaType type)
|
||||||
|
{
|
||||||
|
mOffer.reset(new SipccSdp(SdpOrigin("", 0, 0, sdp::kIPv4, "")));
|
||||||
|
mOffer->AddMediaSection(
|
||||||
|
type,
|
||||||
|
SdpDirectionAttribute::kInactive,
|
||||||
|
0,
|
||||||
|
SdpHelper::GetProtocolForMediaType(type),
|
||||||
|
sdp::kIPv4,
|
||||||
|
"0.0.0.0");
|
||||||
|
mAnswer.reset(new SipccSdp(SdpOrigin("", 0, 0, sdp::kIPv4, "")));
|
||||||
|
mAnswer->AddMediaSection(
|
||||||
|
type,
|
||||||
|
SdpDirectionAttribute::kInactive,
|
||||||
|
0,
|
||||||
|
SdpHelper::GetProtocolForMediaType(type),
|
||||||
|
sdp::kIPv4,
|
||||||
|
"0.0.0.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
SdpMediaSection& GetOffer()
|
||||||
|
{
|
||||||
|
return mOffer->GetMediaSection(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SdpMediaSection& GetAnswer()
|
||||||
|
{
|
||||||
|
return mAnswer->GetMediaSection(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateOffer()
|
||||||
|
{
|
||||||
|
if (mSendOff) {
|
||||||
|
mSendOff->AddToOffer(&GetOffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRecvOff) {
|
||||||
|
mRecvOff->AddToOffer(&GetOffer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateAnswer()
|
||||||
|
{
|
||||||
|
if (mSendAns && GetOffer().IsReceiving()) {
|
||||||
|
mSendAns->AddToAnswer(GetOffer(), &GetAnswer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRecvAns && GetOffer().IsSending()) {
|
||||||
|
mRecvAns->AddToAnswer(GetOffer(), &GetAnswer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Negotiate()
|
||||||
|
{
|
||||||
|
std::cerr << "Offer SDP: " << std::endl;
|
||||||
|
mOffer->Serialize(std::cerr);
|
||||||
|
|
||||||
|
std::cerr << "Answer SDP: " << std::endl;
|
||||||
|
mAnswer->Serialize(std::cerr);
|
||||||
|
|
||||||
|
if (mSendAns && GetAnswer().IsSending()) {
|
||||||
|
mSendAns->Negotiate(GetAnswer(), GetOffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRecvAns && GetAnswer().IsReceiving()) {
|
||||||
|
mRecvAns->Negotiate(GetAnswer(), GetOffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSendOff && GetAnswer().IsReceiving()) {
|
||||||
|
mSendOff->Negotiate(GetAnswer(), GetAnswer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRecvOff && GetAnswer().IsSending()) {
|
||||||
|
mRecvOff->Negotiate(GetAnswer(), GetAnswer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OfferAnswer()
|
||||||
|
{
|
||||||
|
CreateOffer();
|
||||||
|
CreateAnswer();
|
||||||
|
Negotiate();
|
||||||
|
SanityCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t EncodingCount(const RefPtr<JsepTrack>& track)
|
||||||
|
{
|
||||||
|
return track->GetNegotiatedDetails()->GetEncodingCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Look into writing a macro that wraps an ASSERT_ and returns false
|
||||||
|
// if it fails (probably requires writing a bool-returning function that
|
||||||
|
// takes a void-returning lambda with a bool outparam, which will in turn
|
||||||
|
// invokes the ASSERT_)
|
||||||
|
static void CheckEncodingCount(size_t expected,
|
||||||
|
const RefPtr<JsepTrack>& send,
|
||||||
|
const RefPtr<JsepTrack>& recv)
|
||||||
|
{
|
||||||
|
if (expected) {
|
||||||
|
ASSERT_TRUE(!!send);
|
||||||
|
ASSERT_TRUE(send->GetNegotiatedDetails());
|
||||||
|
ASSERT_TRUE(!!recv);
|
||||||
|
ASSERT_TRUE(recv->GetNegotiatedDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send && send->GetNegotiatedDetails()) {
|
||||||
|
ASSERT_EQ(expected, send->GetNegotiatedDetails()->GetEncodingCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recv && recv->GetNegotiatedDetails()) {
|
||||||
|
ASSERT_EQ(expected, recv->GetNegotiatedDetails()->GetEncodingCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckOffEncodingCount(size_t expected) const
|
||||||
|
{
|
||||||
|
CheckEncodingCount(expected, mSendOff, mRecvAns);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckAnsEncodingCount(size_t expected) const
|
||||||
|
{
|
||||||
|
CheckEncodingCount(expected, mSendAns, mRecvOff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SanityCheckCodecs(const JsepCodecDescription& a,
|
||||||
|
const JsepCodecDescription& b) const
|
||||||
|
{
|
||||||
|
ASSERT_EQ(a.mType, b.mType);
|
||||||
|
ASSERT_EQ(a.mDefaultPt, b.mDefaultPt);
|
||||||
|
ASSERT_EQ(a.mName, b.mName);
|
||||||
|
ASSERT_EQ(a.mClock, b.mClock);
|
||||||
|
ASSERT_EQ(a.mChannels, b.mChannels);
|
||||||
|
ASSERT_NE(a.mDirection, b.mDirection);
|
||||||
|
// These constraints are for fmtp and rid, which _are_ signaled
|
||||||
|
ASSERT_EQ(a.mConstraints, b.mConstraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SanityCheckEncodings(const JsepTrackEncoding& a,
|
||||||
|
const JsepTrackEncoding& b) const
|
||||||
|
{
|
||||||
|
ASSERT_EQ(a.GetCodecs().size(), b.GetCodecs().size());
|
||||||
|
for (size_t i = 0; i < a.GetCodecs().size(); ++i) {
|
||||||
|
SanityCheckCodecs(*a.GetCodecs()[i], *b.GetCodecs()[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(a.mRid, b.mRid);
|
||||||
|
// mConstraints will probably differ, since they are not signaled to the
|
||||||
|
// other side.
|
||||||
|
}
|
||||||
|
|
||||||
|
void SanityCheckNegotiatedDetails(const JsepTrackNegotiatedDetails& a,
|
||||||
|
const JsepTrackNegotiatedDetails& b) const
|
||||||
|
{
|
||||||
|
ASSERT_EQ(a.GetEncodingCount(), b.GetEncodingCount());
|
||||||
|
for (size_t i = 0; i < a.GetEncodingCount(); ++i) {
|
||||||
|
SanityCheckEncodings(a.GetEncoding(i), b.GetEncoding(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(a.GetUniquePayloadTypes().size(),
|
||||||
|
b.GetUniquePayloadTypes().size());
|
||||||
|
for (size_t i = 0; i < a.GetUniquePayloadTypes().size(); ++i) {
|
||||||
|
ASSERT_EQ(a.GetUniquePayloadTypes()[i], b.GetUniquePayloadTypes()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SanityCheckTracks(const JsepTrack& a, const JsepTrack& b) const
|
||||||
|
{
|
||||||
|
if (!a.GetNegotiatedDetails()) {
|
||||||
|
ASSERT_FALSE(!!b.GetNegotiatedDetails());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_TRUE(!!a.GetNegotiatedDetails());
|
||||||
|
ASSERT_TRUE(!!b.GetNegotiatedDetails());
|
||||||
|
ASSERT_EQ(a.GetMediaType(), b.GetMediaType());
|
||||||
|
ASSERT_EQ(a.GetStreamId(), b.GetStreamId());
|
||||||
|
ASSERT_EQ(a.GetTrackId(), b.GetTrackId());
|
||||||
|
ASSERT_EQ(a.GetCNAME(), b.GetCNAME());
|
||||||
|
ASSERT_NE(a.GetDirection(), b.GetDirection());
|
||||||
|
ASSERT_EQ(a.GetSsrcs().size(), b.GetSsrcs().size());
|
||||||
|
for (size_t i = 0; i < a.GetSsrcs().size(); ++i) {
|
||||||
|
ASSERT_EQ(a.GetSsrcs()[i], b.GetSsrcs()[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SanityCheckNegotiatedDetails(*a.GetNegotiatedDetails(),
|
||||||
|
*b.GetNegotiatedDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SanityCheck() const
|
||||||
|
{
|
||||||
|
if (mSendOff && mRecvAns) {
|
||||||
|
SanityCheckTracks(*mSendOff, *mRecvAns);
|
||||||
|
}
|
||||||
|
if (mRecvOff && mSendAns) {
|
||||||
|
SanityCheckTracks(*mRecvOff, *mSendAns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RefPtr<JsepTrack> mSendOff;
|
||||||
|
RefPtr<JsepTrack> mRecvOff;
|
||||||
|
RefPtr<JsepTrack> mSendAns;
|
||||||
|
RefPtr<JsepTrack> mRecvAns;
|
||||||
|
PtrVector<JsepCodecDescription> mOffCodecs;
|
||||||
|
PtrVector<JsepCodecDescription> mAnsCodecs;
|
||||||
|
UniquePtr<Sdp> mOffer;
|
||||||
|
UniquePtr<Sdp> mAnswer;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, CreateDestroy)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kAudio);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, AudioNegotiation)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kAudio);
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(1);
|
||||||
|
CheckAnsEncodingCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, VideoNegotiation)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(1);
|
||||||
|
CheckAnsEncodingCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, AudioOffSendonlyAnsRecvonly)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kAudio);
|
||||||
|
mRecvOff = nullptr;
|
||||||
|
mSendAns = nullptr;
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(1);
|
||||||
|
CheckAnsEncodingCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, VideoOffSendonlyAnsRecvonly)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
mRecvOff = nullptr;
|
||||||
|
mSendAns = nullptr;
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(1);
|
||||||
|
CheckAnsEncodingCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, AudioOffSendrecvAnsRecvonly)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kAudio);
|
||||||
|
mSendAns = nullptr;
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(1);
|
||||||
|
CheckAnsEncodingCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, VideoOffSendrecvAnsRecvonly)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
mSendAns = nullptr;
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(1);
|
||||||
|
CheckAnsEncodingCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, AudioOffRecvonlyAnsSendrecv)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kAudio);
|
||||||
|
mSendOff = nullptr;
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(0);
|
||||||
|
CheckAnsEncodingCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, VideoOffRecvonlyAnsSendrecv)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
mSendOff = nullptr;
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(0);
|
||||||
|
CheckAnsEncodingCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, AudioOffSendrecvAnsSendonly)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kAudio);
|
||||||
|
mRecvAns = nullptr;
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(0);
|
||||||
|
CheckAnsEncodingCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, VideoOffSendrecvAnsSendonly)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
mRecvAns = nullptr;
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(0);
|
||||||
|
CheckAnsEncodingCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JsepTrack::JsConstraints
|
||||||
|
MakeConstraints(const std::string& rid, uint32_t maxBitrate)
|
||||||
|
{
|
||||||
|
JsepTrack::JsConstraints constraints;
|
||||||
|
constraints.rid = rid;
|
||||||
|
constraints.constraints.maxBr = maxBitrate;
|
||||||
|
return constraints;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, SimulcastRejected)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
std::vector<JsepTrack::JsConstraints> constraints;
|
||||||
|
constraints.push_back(MakeConstraints("foo", 40000));
|
||||||
|
constraints.push_back(MakeConstraints("bar", 10000));
|
||||||
|
mSendOff->SetJsConstraints(constraints);
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(1);
|
||||||
|
CheckAnsEncodingCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, SimulcastPrevented)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
std::vector<JsepTrack::JsConstraints> constraints;
|
||||||
|
constraints.push_back(MakeConstraints("foo", 40000));
|
||||||
|
constraints.push_back(MakeConstraints("bar", 10000));
|
||||||
|
mSendAns->SetJsConstraints(constraints);
|
||||||
|
OfferAnswer();
|
||||||
|
CheckOffEncodingCount(1);
|
||||||
|
CheckAnsEncodingCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, SimulcastOfferer)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
std::vector<JsepTrack::JsConstraints> constraints;
|
||||||
|
constraints.push_back(MakeConstraints("foo", 40000));
|
||||||
|
constraints.push_back(MakeConstraints("bar", 10000));
|
||||||
|
mSendOff->SetJsConstraints(constraints);
|
||||||
|
CreateOffer();
|
||||||
|
CreateAnswer();
|
||||||
|
// Add simulcast/rid to answer
|
||||||
|
JsepTrack::AddToMsection(constraints, sdp::kRecv, &GetAnswer());
|
||||||
|
Negotiate();
|
||||||
|
ASSERT_TRUE(mSendOff->GetNegotiatedDetails());
|
||||||
|
ASSERT_EQ(2U, mSendOff->GetNegotiatedDetails()->GetEncodingCount());
|
||||||
|
ASSERT_EQ("foo", mSendOff->GetNegotiatedDetails()->GetEncoding(0).mRid);
|
||||||
|
ASSERT_EQ(40000U,
|
||||||
|
mSendOff->GetNegotiatedDetails()->GetEncoding(0).mConstraints.maxBr);
|
||||||
|
ASSERT_EQ("bar", mSendOff->GetNegotiatedDetails()->GetEncoding(1).mRid);
|
||||||
|
ASSERT_EQ(10000U,
|
||||||
|
mSendOff->GetNegotiatedDetails()->GetEncoding(1).mConstraints.maxBr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsepTrackTest, SimulcastAnswerer)
|
||||||
|
{
|
||||||
|
Init(SdpMediaSection::kVideo);
|
||||||
|
std::vector<JsepTrack::JsConstraints> constraints;
|
||||||
|
constraints.push_back(MakeConstraints("foo", 40000));
|
||||||
|
constraints.push_back(MakeConstraints("bar", 10000));
|
||||||
|
mSendAns->SetJsConstraints(constraints);
|
||||||
|
CreateOffer();
|
||||||
|
// Add simulcast/rid to offer
|
||||||
|
JsepTrack::AddToMsection(constraints, sdp::kRecv, &GetOffer());
|
||||||
|
CreateAnswer();
|
||||||
|
Negotiate();
|
||||||
|
ASSERT_TRUE(mSendAns->GetNegotiatedDetails());
|
||||||
|
ASSERT_EQ(2U, mSendAns->GetNegotiatedDetails()->GetEncodingCount());
|
||||||
|
ASSERT_EQ("foo", mSendAns->GetNegotiatedDetails()->GetEncoding(0).mRid);
|
||||||
|
ASSERT_EQ(40000U,
|
||||||
|
mSendAns->GetNegotiatedDetails()->GetEncoding(0).mConstraints.maxBr);
|
||||||
|
ASSERT_EQ("bar", mSendAns->GetNegotiatedDetails()->GetEncoding(1).mRid);
|
||||||
|
ASSERT_EQ(10000U,
|
||||||
|
mSendAns->GetNegotiatedDetails()->GetEncoding(1).mConstraints.maxBr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
// Prevents some log spew
|
||||||
|
ScopedXPCOM xpcom("jsep_track_unittest");
|
||||||
|
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@
|
|||||||
if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'uikit':
|
if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'uikit':
|
||||||
GeckoCppUnitTests([
|
GeckoCppUnitTests([
|
||||||
'jsep_session_unittest',
|
'jsep_session_unittest',
|
||||||
|
'jsep_track_unittest',
|
||||||
'mediaconduit_unittests',
|
'mediaconduit_unittests',
|
||||||
'mediapipeline_unittest',
|
'mediapipeline_unittest',
|
||||||
'sdp_file_parser',
|
'sdp_file_parser',
|
||||||
|
@ -1195,8 +1195,7 @@ const std::string kBasicAudioVideoOffer =
|
|||||||
"a=ssrc:1111 foo:bar" CRLF
|
"a=ssrc:1111 foo:bar" CRLF
|
||||||
"a=imageattr:120 send * recv *" CRLF
|
"a=imageattr:120 send * recv *" CRLF
|
||||||
"a=imageattr:121 send [x=640,y=480] recv [x=640,y=480]" CRLF
|
"a=imageattr:121 send [x=640,y=480] recv [x=640,y=480]" CRLF
|
||||||
"a=simulcast:send pt=120;121" CRLF
|
"a=simulcast:recv pt=120;121" CRLF
|
||||||
"a=rid:foo send" CRLF
|
|
||||||
"a=rid:bar recv pt=96;max-width=800;max-height=600" CRLF
|
"a=rid:bar recv pt=96;max-width=800;max-height=600" CRLF
|
||||||
"m=audio 9 RTP/SAVPF 0" CRLF
|
"m=audio 9 RTP/SAVPF 0" CRLF
|
||||||
"a=mid:third" CRLF
|
"a=mid:third" CRLF
|
||||||
@ -1778,16 +1777,13 @@ TEST_P(NewSdpTest, CheckRid)
|
|||||||
const SdpRidAttributeList& rids =
|
const SdpRidAttributeList& rids =
|
||||||
mSdp->GetMediaSection(1).GetAttributeList().GetRid();
|
mSdp->GetMediaSection(1).GetAttributeList().GetRid();
|
||||||
|
|
||||||
ASSERT_EQ(2U, rids.mRids.size());
|
ASSERT_EQ(1U, rids.mRids.size());
|
||||||
ASSERT_EQ("foo", rids.mRids[0].id);
|
ASSERT_EQ("bar", rids.mRids[0].id);
|
||||||
ASSERT_EQ(sdp::kSend, rids.mRids[0].direction);
|
ASSERT_EQ(sdp::kRecv, rids.mRids[0].direction);
|
||||||
ASSERT_EQ(0U, rids.mRids[0].formats.size());
|
ASSERT_EQ(1U, rids.mRids[0].formats.size());
|
||||||
ASSERT_EQ("bar", rids.mRids[1].id);
|
ASSERT_EQ(96U, rids.mRids[0].formats[0]);
|
||||||
ASSERT_EQ(sdp::kRecv, rids.mRids[1].direction);
|
ASSERT_EQ(800U, rids.mRids[0].constraints.maxWidth);
|
||||||
ASSERT_EQ(1U, rids.mRids[1].formats.size());
|
ASSERT_EQ(600U, rids.mRids[0].constraints.maxHeight);
|
||||||
ASSERT_EQ(96U, rids.mRids[1].formats[0]);
|
|
||||||
ASSERT_EQ(800U, rids.mRids[1].constraints.maxWidth);
|
|
||||||
ASSERT_EQ(600U, rids.mRids[1].constraints.maxHeight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(NewSdpTest, CheckMediaLevelIceUfrag) {
|
TEST_P(NewSdpTest, CheckMediaLevelIceUfrag) {
|
||||||
@ -2099,14 +2095,14 @@ TEST_P(NewSdpTest, CheckSimulcast)
|
|||||||
const SdpSimulcastAttribute& simulcast =
|
const SdpSimulcastAttribute& simulcast =
|
||||||
mSdp->GetMediaSection(1).GetAttributeList().GetSimulcast();
|
mSdp->GetMediaSection(1).GetAttributeList().GetSimulcast();
|
||||||
|
|
||||||
ASSERT_EQ(0U, simulcast.recvVersions.size());
|
ASSERT_EQ(2U, simulcast.recvVersions.size());
|
||||||
ASSERT_EQ(2U, simulcast.sendVersions.size());
|
ASSERT_EQ(0U, simulcast.sendVersions.size());
|
||||||
ASSERT_EQ(1U, simulcast.sendVersions[0].choices.size());
|
ASSERT_EQ(1U, simulcast.recvVersions[0].choices.size());
|
||||||
ASSERT_EQ("120", simulcast.sendVersions[0].choices[0]);
|
ASSERT_EQ("120", simulcast.recvVersions[0].choices[0]);
|
||||||
ASSERT_EQ(1U, simulcast.sendVersions[1].choices.size());
|
ASSERT_EQ(1U, simulcast.recvVersions[1].choices.size());
|
||||||
ASSERT_EQ("121", simulcast.sendVersions[1].choices[0]);
|
ASSERT_EQ("121", simulcast.recvVersions[1].choices[0]);
|
||||||
ASSERT_EQ(SdpSimulcastAttribute::Versions::kPt,
|
ASSERT_EQ(SdpSimulcastAttribute::Versions::kPt,
|
||||||
simulcast.sendVersions.type);
|
simulcast.recvVersions.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(NewSdpTest, CheckSctpmap) {
|
TEST_P(NewSdpTest, CheckSctpmap) {
|
||||||
@ -2613,6 +2609,81 @@ TEST_P(NewSdpTest, CheckMalformedImageattr)
|
|||||||
ASSERT_NE("", GetParseErrors());
|
ASSERT_NE("", GetParseErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(NewSdpTest, ParseInvalidSimulcastNoSuchSendRid) {
|
||||||
|
ParseSdp("v=0" CRLF
|
||||||
|
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
|
||||||
|
"s=SIP Call" CRLF
|
||||||
|
"c=IN IP4 198.51.100.7" CRLF
|
||||||
|
"b=CT:5000" CRLF
|
||||||
|
"t=0 0" CRLF
|
||||||
|
"m=video 56436 RTP/SAVPF 120" CRLF
|
||||||
|
"a=rtpmap:120 VP8/90000" CRLF
|
||||||
|
"a=sendrecv" CRLF
|
||||||
|
"a=simulcast: send rid=9" CRLF,
|
||||||
|
false);
|
||||||
|
ASSERT_NE("", GetParseErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(NewSdpTest, ParseInvalidSimulcastNoSuchRecvRid) {
|
||||||
|
ParseSdp("v=0" CRLF
|
||||||
|
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
|
||||||
|
"s=SIP Call" CRLF
|
||||||
|
"c=IN IP4 198.51.100.7" CRLF
|
||||||
|
"b=CT:5000" CRLF
|
||||||
|
"t=0 0" CRLF
|
||||||
|
"m=video 56436 RTP/SAVPF 120" CRLF
|
||||||
|
"a=rtpmap:120 VP8/90000" CRLF
|
||||||
|
"a=sendrecv" CRLF
|
||||||
|
"a=simulcast: recv rid=9" CRLF,
|
||||||
|
false);
|
||||||
|
ASSERT_NE("", GetParseErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(NewSdpTest, ParseInvalidSimulcastNoSuchPt) {
|
||||||
|
ParseSdp("v=0" CRLF
|
||||||
|
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
|
||||||
|
"s=SIP Call" CRLF
|
||||||
|
"c=IN IP4 198.51.100.7" CRLF
|
||||||
|
"b=CT:5000" CRLF
|
||||||
|
"t=0 0" CRLF
|
||||||
|
"m=video 56436 RTP/SAVPF 120" CRLF
|
||||||
|
"a=rtpmap:120 VP8/90000" CRLF
|
||||||
|
"a=sendrecv" CRLF
|
||||||
|
"a=simulcast: send pt=9" CRLF,
|
||||||
|
false);
|
||||||
|
ASSERT_NE("", GetParseErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(NewSdpTest, ParseInvalidSimulcastNotSending) {
|
||||||
|
ParseSdp("v=0" CRLF
|
||||||
|
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
|
||||||
|
"s=SIP Call" CRLF
|
||||||
|
"c=IN IP4 198.51.100.7" CRLF
|
||||||
|
"b=CT:5000" CRLF
|
||||||
|
"t=0 0" CRLF
|
||||||
|
"m=video 56436 RTP/SAVPF 120" CRLF
|
||||||
|
"a=rtpmap:120 VP8/90000" CRLF
|
||||||
|
"a=recvonly" CRLF
|
||||||
|
"a=simulcast: send pt=120" CRLF,
|
||||||
|
false);
|
||||||
|
ASSERT_NE("", GetParseErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(NewSdpTest, ParseInvalidSimulcastNotReceiving) {
|
||||||
|
ParseSdp("v=0" CRLF
|
||||||
|
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
|
||||||
|
"s=SIP Call" CRLF
|
||||||
|
"c=IN IP4 198.51.100.7" CRLF
|
||||||
|
"b=CT:5000" CRLF
|
||||||
|
"t=0 0" CRLF
|
||||||
|
"m=video 56436 RTP/SAVPF 120" CRLF
|
||||||
|
"a=rtpmap:120 VP8/90000" CRLF
|
||||||
|
"a=sendonly" CRLF
|
||||||
|
"a=simulcast: recv pt=120" CRLF,
|
||||||
|
false);
|
||||||
|
ASSERT_NE("", GetParseErrors());
|
||||||
|
}
|
||||||
|
|
||||||
const std::string kNoAttributes =
|
const std::string kNoAttributes =
|
||||||
"v=0" CRLF
|
"v=0" CRLF
|
||||||
"o=Mozilla-SIPUA-35.0a1 5184 0 IN IP4 0.0.0.0" CRLF
|
"o=Mozilla-SIPUA-35.0a1 5184 0 IN IP4 0.0.0.0" CRLF
|
||||||
|
@ -101,6 +101,7 @@ skip-if = os == 'b2g' || os == 'android' # Bug 919646
|
|||||||
[rlogringbuffer_unittest]
|
[rlogringbuffer_unittest]
|
||||||
[runnable_utils_unittest]
|
[runnable_utils_unittest]
|
||||||
[sctp_unittest]
|
[sctp_unittest]
|
||||||
|
[jsep_track_unittest]
|
||||||
[jsep_session_unittest]
|
[jsep_session_unittest]
|
||||||
skip-if = os == 'android' # Bug 1147631
|
skip-if = os == 'android' # Bug 1147631
|
||||||
[sdp_unittests]
|
[sdp_unittests]
|
||||||
|
Loading…
Reference in New Issue
Block a user