зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to central, a=merge
This commit is contained in:
Коммит
a9e2fe1637
|
@ -805,7 +805,11 @@ getParentCB(AtkObject *aAtkObj)
|
||||||
atkParent = GetWrapperFor(parent);
|
atkParent = GetWrapperFor(parent);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise this should be the proxy for the tab's top level document.
|
// Otherwise this should be the proxy for the tab's top level document.
|
||||||
atkParent = AccessibleWrap::GetAtkObject(proxy->OuterDocOfRemoteBrowser());
|
Accessible* outerDocParent = proxy->OuterDocOfRemoteBrowser();
|
||||||
|
NS_ASSERTION(outerDocParent, "this document should have an outerDoc as a parent");
|
||||||
|
if (outerDocParent) {
|
||||||
|
atkParent = AccessibleWrap::GetAtkObject(outerDocParent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,11 @@
|
||||||
work correctly on the menupopup. ContentSelectDropdown expects the
|
work correctly on the menupopup. ContentSelectDropdown expects the
|
||||||
popuponly menulist to be its immediate parent. -->
|
popuponly menulist to be its immediate parent. -->
|
||||||
<menulist popuponly="true" id="ContentSelectDropdown" hidden="true">
|
<menulist popuponly="true" id="ContentSelectDropdown" hidden="true">
|
||||||
<menupopup rolluponmousewheel="true"/>
|
<menupopup rolluponmousewheel="true"
|
||||||
|
#ifdef XP_WIN
|
||||||
|
consumeoutsideclicks="false"
|
||||||
|
#endif
|
||||||
|
/>
|
||||||
</menulist>
|
</menulist>
|
||||||
|
|
||||||
<!-- for invalid form error message -->
|
<!-- for invalid form error message -->
|
||||||
|
|
|
@ -73,10 +73,6 @@
|
||||||
#include "SurfaceCache.h"
|
#include "SurfaceCache.h"
|
||||||
#include "gfxPrefs.h"
|
#include "gfxPrefs.h"
|
||||||
|
|
||||||
#if defined(MOZ_CRASHREPORTER)
|
|
||||||
#include "nsExceptionHandler.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "VsyncSource.h"
|
#include "VsyncSource.h"
|
||||||
#include "DriverInitCrashDetection.h"
|
#include "DriverInitCrashDetection.h"
|
||||||
|
|
||||||
|
@ -1721,16 +1717,12 @@ bool DoesD3D11DeviceWork(ID3D11Device *device)
|
||||||
gfxWindowsPlatform::GetDLLVersion(L"dlumd32.dll", displayLinkModuleVersionString);
|
gfxWindowsPlatform::GetDLLVersion(L"dlumd32.dll", displayLinkModuleVersionString);
|
||||||
uint64_t displayLinkModuleVersion;
|
uint64_t displayLinkModuleVersion;
|
||||||
if (!ParseDriverVersion(displayLinkModuleVersionString, &displayLinkModuleVersion)) {
|
if (!ParseDriverVersion(displayLinkModuleVersionString, &displayLinkModuleVersion)) {
|
||||||
#if defined(MOZ_CRASHREPORTER)
|
gfxCriticalError() << "DisplayLink: could not parse version";
|
||||||
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: could not parse version\n"));
|
|
||||||
#endif
|
|
||||||
gANGLESupportsD3D11 = false;
|
gANGLESupportsD3D11 = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (displayLinkModuleVersion <= V(8,6,1,36484)) {
|
if (displayLinkModuleVersion <= V(8,6,1,36484)) {
|
||||||
#if defined(MOZ_CRASHREPORTER)
|
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DisplayLink: too old version";
|
||||||
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: too old version\n"));
|
|
||||||
#endif
|
|
||||||
gANGLESupportsD3D11 = false;
|
gANGLESupportsD3D11 = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1762,9 +1754,7 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma
|
||||||
gfxInfo->GetAdapterVendorID(vendorID);
|
gfxInfo->GetAdapterVendorID(vendorID);
|
||||||
gfxInfo->GetAdapterVendorID2(vendorID2);
|
gfxInfo->GetAdapterVendorID2(vendorID2);
|
||||||
if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
|
if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
|
||||||
#if defined(MOZ_CRASHREPORTER)
|
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Unexpected Intel/AMD dual-GPU setup";
|
||||||
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("Unexpected Intel/AMD dual-GPU setup\n"));
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1804,6 +1794,7 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma
|
||||||
if (FAILED(device->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource),
|
if (FAILED(device->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource),
|
||||||
getter_AddRefs(sharedResource))))
|
getter_AddRefs(sharedResource))))
|
||||||
{
|
{
|
||||||
|
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "OpenSharedResource failed for format " << format;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1817,9 +1808,7 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma
|
||||||
|
|
||||||
// This if(FAILED()) is the one that actually fails on systems affected by bug 1083071.
|
// This if(FAILED()) is the one that actually fails on systems affected by bug 1083071.
|
||||||
if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, byRef(sharedView)))) {
|
if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, byRef(sharedView)))) {
|
||||||
#if defined(MOZ_CRASHREPORTER)
|
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "CreateShaderResourceView failed for format" << format;
|
||||||
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("CreateShaderResourceView failed\n"));
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1843,13 +1832,17 @@ bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
|
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
|
||||||
if (gfxInfo) {
|
if (gfxInfo) {
|
||||||
// Disable texture sharing if we're blocking d2d since that's the only other time we use it
|
// A8 texture sharing crashes on this intel driver version (and no others)
|
||||||
// and it might be broken.
|
// so just avoid using it in that case.
|
||||||
int32_t status;
|
nsString adapterVendor;
|
||||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
|
nsString driverVersion;
|
||||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
gfxInfo->GetAdapterVendorID(adapterVendor);
|
||||||
return false;
|
gfxInfo->GetAdapterDriverVersion(driverVersion);
|
||||||
}
|
|
||||||
|
nsAString &intelVendorID = (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorIntel);
|
||||||
|
if (adapterVendor.Equals(intelVendorID, nsCaseInsensitiveStringComparator()) &&
|
||||||
|
driverVersion.Equals(NS_LITERAL_STRING("8.15.10.2086"))) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1951,6 +1944,8 @@ gfxWindowsPlatform::InitD3D11Devices()
|
||||||
featureLevels.Elements(), featureLevels.Length(),
|
featureLevels.Elements(), featureLevels.Length(),
|
||||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||||
|
gfxCriticalError() << "Crash during D3D11 device creation";
|
||||||
|
|
||||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1960,6 +1955,7 @@ gfxWindowsPlatform::InitD3D11Devices()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
|
if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
|
||||||
|
gfxCriticalError() << "D3D11 device creation failed" << hexa(hr);
|
||||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,9 @@ MacroAssembler::setFramePushed(uint32_t framePushed)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroAssembler::adjustFrame(int value)
|
MacroAssembler::adjustFrame(int32_t value)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT_IF(value < 0, framePushed_ >= uint32_t(-value));
|
||||||
setFramePushed(framePushed_ + value);
|
setFramePushed(framePushed_ + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +38,8 @@ void
|
||||||
MacroAssembler::implicitPop(uint32_t bytes)
|
MacroAssembler::implicitPop(uint32_t bytes)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(bytes % sizeof(intptr_t) == 0);
|
MOZ_ASSERT(bytes % sizeof(intptr_t) == 0);
|
||||||
adjustFrame(-bytes);
|
MOZ_ASSERT(bytes <= INT32_MAX);
|
||||||
|
adjustFrame(-int32_t(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===============================================================
|
// ===============================================================
|
||||||
|
|
|
@ -280,7 +280,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||||
|
|
||||||
inline uint32_t framePushed() const;
|
inline uint32_t framePushed() const;
|
||||||
inline void setFramePushed(uint32_t framePushed);
|
inline void setFramePushed(uint32_t framePushed);
|
||||||
inline void adjustFrame(int value);
|
inline void adjustFrame(int32_t value);
|
||||||
|
|
||||||
// Adjust the frame, to account for implicit modification of the stack
|
// Adjust the frame, to account for implicit modification of the stack
|
||||||
// pointer, such that callee can remove arguments on the behalf of the
|
// pointer, such that callee can remove arguments on the behalf of the
|
||||||
|
|
|
@ -3340,7 +3340,7 @@ bool RangeAnalysis::tryRemovingGuards()
|
||||||
MDefinitionVector guards(alloc());
|
MDefinitionVector guards(alloc());
|
||||||
|
|
||||||
for (ReversePostorderIterator block = graph_.rpoBegin(); block != graph_.rpoEnd(); block++) {
|
for (ReversePostorderIterator block = graph_.rpoBegin(); block != graph_.rpoEnd(); block++) {
|
||||||
for (MInstructionReverseIterator iter = block->rbegin(); iter != block->rend(); iter++) {
|
for (MDefinitionIterator iter(*block); iter; iter++) {
|
||||||
if (!iter->isGuardRangeBailouts())
|
if (!iter->isGuardRangeBailouts())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
|
|
||||||
|
#include "mozilla/Snprintf.h"
|
||||||
#include "mozilla/Vector.h"
|
#include "mozilla/Vector.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
@ -286,8 +287,6 @@ static bool cvt_ll(SprintfState* ss, int64_t num, int width, int prec, int radix
|
||||||
/*
|
/*
|
||||||
* Convert a double precision floating point number into its printable
|
* Convert a double precision floating point number into its printable
|
||||||
* form.
|
* form.
|
||||||
*
|
|
||||||
* XXX stop using sprintf to convert floating point
|
|
||||||
*/
|
*/
|
||||||
static bool cvt_f(SprintfState* ss, double d, const char* fmt0, const char* fmt1)
|
static bool cvt_f(SprintfState* ss, double d, const char* fmt0, const char* fmt1)
|
||||||
{
|
{
|
||||||
|
@ -303,7 +302,7 @@ static bool cvt_f(SprintfState* ss, double d, const char* fmt0, const char* fmt1
|
||||||
js_memcpy(fin, fmt0, (size_t)amount);
|
js_memcpy(fin, fmt0, (size_t)amount);
|
||||||
fin[amount] = 0;
|
fin[amount] = 0;
|
||||||
|
|
||||||
// Convert floating point using the native sprintf code
|
// Convert floating point using the native snprintf code
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
const char* p = fin;
|
const char* p = fin;
|
||||||
|
@ -313,12 +312,7 @@ static bool cvt_f(SprintfState* ss, double d, const char* fmt0, const char* fmt1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sprintf(fout, fin, d);
|
snprintf_literal(fout, fin, d);
|
||||||
|
|
||||||
// This assert will catch overflow's of fout, when building with
|
|
||||||
// debugging on. At least this way we can track down the evil piece
|
|
||||||
// of calling code and fix it!
|
|
||||||
MOZ_ASSERT(strlen(fout) < sizeof(fout));
|
|
||||||
|
|
||||||
return (*ss->stuff)(ss, fout, strlen(fout));
|
return (*ss->stuff)(ss, fout, strlen(fout));
|
||||||
}
|
}
|
||||||
|
|
|
@ -533,19 +533,18 @@ JsepSessionImpl::SetupBundle(Sdp* sdp) const
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
JsepSessionImpl::FinalizeTransportAttributes(Sdp* offer)
|
JsepSessionImpl::SetupTransportAttributes(const Sdp& newOffer, Sdp* local)
|
||||||
{
|
{
|
||||||
const Sdp* oldAnswer = GetAnswer();
|
const Sdp* oldAnswer = GetAnswer();
|
||||||
|
|
||||||
if (oldAnswer) {
|
if (oldAnswer) {
|
||||||
// Renegotiation, we might have transport attributes to copy over
|
// Renegotiation, we might have transport attributes to copy over
|
||||||
for (size_t i = 0; i < oldAnswer->GetMediaSectionCount(); ++i) {
|
for (size_t i = 0; i < oldAnswer->GetMediaSectionCount(); ++i) {
|
||||||
if (!MsectionIsDisabled(offer->GetMediaSection(i)) &&
|
if (!MsectionIsDisabled(local->GetMediaSection(i)) &&
|
||||||
!MsectionIsDisabled(oldAnswer->GetMediaSection(i)) &&
|
AreOldTransportParamsValid(*oldAnswer, newOffer, i)) {
|
||||||
!IsBundleSlave(*oldAnswer, i)) {
|
|
||||||
nsresult rv = CopyTransportParams(
|
nsresult rv = CopyTransportParams(
|
||||||
mCurrentLocalDescription->GetMediaSection(i),
|
mCurrentLocalDescription->GetMediaSection(i),
|
||||||
&offer->GetMediaSection(i));
|
&local->GetMediaSection(i));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -769,7 +768,7 @@ JsepSessionImpl::CreateOffer(const JsepOfferOptions& options,
|
||||||
|
|
||||||
SetupBundle(sdp.get());
|
SetupBundle(sdp.get());
|
||||||
|
|
||||||
rv = FinalizeTransportAttributes(sdp.get());
|
rv = SetupTransportAttributes(*sdp, sdp.get());
|
||||||
NS_ENSURE_SUCCESS(rv,rv);
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
|
||||||
*offer = sdp->ToString();
|
*offer = sdp->ToString();
|
||||||
|
@ -1022,6 +1021,9 @@ JsepSessionImpl::CreateAnswer(const JsepAnswerOptions& options,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rv = SetupTransportAttributes(offer, sdp.get());
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
|
||||||
*answer = sdp->ToString();
|
*answer = sdp->ToString();
|
||||||
mGeneratedLocalDescription = Move(sdp);
|
mGeneratedLocalDescription = Move(sdp);
|
||||||
|
|
||||||
|
@ -1416,6 +1418,7 @@ JsepSessionImpl::SetLocalDescriptionAnswer(JsepSdpType type,
|
||||||
|
|
||||||
mCurrentRemoteDescription = Move(mPendingRemoteDescription);
|
mCurrentRemoteDescription = Move(mPendingRemoteDescription);
|
||||||
mCurrentLocalDescription = Move(mPendingLocalDescription);
|
mCurrentLocalDescription = Move(mPendingLocalDescription);
|
||||||
|
mWasOffererLastTime = mIsOfferer;
|
||||||
|
|
||||||
SetState(kJsepStateStable);
|
SetState(kJsepStateStable);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -1865,6 +1868,37 @@ JsepSessionImpl::FinalizeTransport(const SdpAttributeList& remote,
|
||||||
return NS_OK;
|
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
|
nsresult
|
||||||
JsepSessionImpl::AddTransportAttributes(SdpMediaSection* msection,
|
JsepSessionImpl::AddTransportAttributes(SdpMediaSection* msection,
|
||||||
SdpSetupAttribute::Role dtlsRole)
|
SdpSetupAttribute::Role dtlsRole)
|
||||||
|
@ -1886,33 +1920,43 @@ JsepSessionImpl::AddTransportAttributes(SdpMediaSection* msection,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
JsepSessionImpl::CopyTransportParams(const SdpMediaSection& source,
|
JsepSessionImpl::CopyTransportParams(const SdpMediaSection& oldLocal,
|
||||||
SdpMediaSection* dest)
|
SdpMediaSection* newLocal)
|
||||||
{
|
{
|
||||||
// Copy over m-section details
|
// Copy over m-section details
|
||||||
dest->SetPort(source.GetPort());
|
newLocal->SetPort(oldLocal.GetPort());
|
||||||
dest->GetConnection() = source.GetConnection();
|
newLocal->GetConnection() = oldLocal.GetConnection();
|
||||||
|
|
||||||
auto& sourceAttrs = source.GetAttributeList();
|
const SdpAttributeList& oldLocalAttrs = oldLocal.GetAttributeList();
|
||||||
auto& destAttrs = dest->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
|
// Now we copy over attributes that won't be added by the usual logic
|
||||||
if (sourceAttrs.HasAttribute(SdpAttribute::kCandidateAttribute)) {
|
if (oldLocalAttrs.HasAttribute(SdpAttribute::kCandidateAttribute) &&
|
||||||
auto* candidateAttrs =
|
components) {
|
||||||
new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute);
|
UniquePtr<SdpMultiStringAttribute> candidateAttrs(
|
||||||
candidateAttrs->mValues = sourceAttrs.GetCandidate();
|
new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute));
|
||||||
destAttrs.SetAttribute(candidateAttrs);
|
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)) {
|
if (components == 2 &&
|
||||||
destAttrs.SetAttribute(
|
oldLocalAttrs.HasAttribute(SdpAttribute::kRtcpAttribute)) {
|
||||||
new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
|
// copy rtcp attribute if we had one that we are using
|
||||||
}
|
newLocalAttrs.SetAttribute(new SdpRtcpAttribute(oldLocalAttrs.GetRtcp()));
|
||||||
|
|
||||||
if (!destAttrs.HasAttribute(SdpAttribute::kRtcpMuxAttribute) &&
|
|
||||||
sourceAttrs.HasAttribute(SdpAttribute::kRtcpAttribute)) {
|
|
||||||
// copy rtcp attribute
|
|
||||||
destAttrs.SetAttribute(new SdpRtcpAttribute(sourceAttrs.GetRtcp()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -2075,6 +2119,7 @@ JsepSessionImpl::SetRemoteDescriptionAnswer(JsepSdpType type,
|
||||||
|
|
||||||
mCurrentRemoteDescription = Move(mPendingRemoteDescription);
|
mCurrentRemoteDescription = Move(mPendingRemoteDescription);
|
||||||
mCurrentLocalDescription = Move(mPendingLocalDescription);
|
mCurrentLocalDescription = Move(mPendingLocalDescription);
|
||||||
|
mWasOffererLastTime = mIsOfferer;
|
||||||
|
|
||||||
SetState(kJsepStateStable);
|
SetState(kJsepStateStable);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -2567,6 +2612,21 @@ JsepSessionImpl::AddCandidateToSdp(Sdp* sdp,
|
||||||
return NS_OK;
|
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
|
nsresult
|
||||||
JsepSessionImpl::AddRemoteIceCandidate(const std::string& candidate,
|
JsepSessionImpl::AddRemoteIceCandidate(const std::string& candidate,
|
||||||
const std::string& mid,
|
const std::string& mid,
|
||||||
|
@ -2636,6 +2696,7 @@ static void SetDefaultAddresses(const std::string& defaultCandidateAddr,
|
||||||
{
|
{
|
||||||
msection->GetConnection().SetAddress(defaultCandidateAddr);
|
msection->GetConnection().SetAddress(defaultCandidateAddr);
|
||||||
msection->SetPort(defaultCandidatePort);
|
msection->SetPort(defaultCandidatePort);
|
||||||
|
|
||||||
if (!defaultRtcpCandidateAddr.empty()) {
|
if (!defaultRtcpCandidateAddr.empty()) {
|
||||||
sdp::AddrType ipVersion = sdp::kIPv4;
|
sdp::AddrType ipVersion = sdp::kIPv4;
|
||||||
if (defaultRtcpCandidateAddr.find(':') != std::string::npos) {
|
if (defaultRtcpCandidateAddr.find(':') != std::string::npos) {
|
||||||
|
@ -2669,17 +2730,30 @@ JsepSessionImpl::EndOfLocalCandidates(const std::string& defaultCandidateAddr,
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> bundleMids;
|
if (level >= sdp->GetMediaSectionCount()) {
|
||||||
const SdpMediaSection* bundleMsection;
|
return NS_OK;
|
||||||
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()) {
|
std::string defaultRtcpCandidateAddrCopy(defaultRtcpCandidateAddr);
|
||||||
SdpMediaSection& msection = sdp->GetMediaSection(level);
|
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) &&
|
if (msection.GetAttributeList().HasAttribute(SdpAttribute::kMidAttribute) &&
|
||||||
bundleMids.count(msection.GetAttributeList().GetMid())) {
|
bundleMids.count(msection.GetAttributeList().GetMid())) {
|
||||||
|
@ -2698,26 +2772,26 @@ JsepSessionImpl::EndOfLocalCandidates(const std::string& defaultCandidateAddr,
|
||||||
}
|
}
|
||||||
SetDefaultAddresses(defaultCandidateAddr,
|
SetDefaultAddresses(defaultCandidateAddr,
|
||||||
defaultCandidatePort,
|
defaultCandidatePort,
|
||||||
defaultRtcpCandidateAddr,
|
defaultRtcpCandidateAddrCopy,
|
||||||
defaultRtcpCandidatePort,
|
defaultRtcpCandidatePort,
|
||||||
bundledMsection);
|
bundledMsection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SetDefaultAddresses(defaultCandidateAddr,
|
SetDefaultAddresses(defaultCandidateAddr,
|
||||||
defaultCandidatePort,
|
defaultCandidatePort,
|
||||||
defaultRtcpCandidateAddr,
|
defaultRtcpCandidateAddrCopy,
|
||||||
defaultRtcpCandidatePort,
|
defaultRtcpCandidatePort,
|
||||||
&msection);
|
&msection);
|
||||||
|
|
||||||
// TODO(bug 1095793): Will this have an mid someday?
|
// TODO(bug 1095793): Will this have an mid someday?
|
||||||
|
|
||||||
SdpAttributeList& attrs = msection.GetAttributeList();
|
SdpAttributeList& attrs = msection.GetAttributeList();
|
||||||
attrs.SetAttribute(
|
attrs.SetAttribute(
|
||||||
new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
|
new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
|
||||||
if (!mIsOfferer) {
|
if (!mIsOfferer) {
|
||||||
attrs.RemoveAttribute(SdpAttribute::kIceOptionsAttribute);
|
attrs.RemoveAttribute(SdpAttribute::kIceOptionsAttribute);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -3039,10 +3113,8 @@ JsepSessionImpl::MsectionIsDisabled(const SdpMediaSection& msection) const
|
||||||
const Sdp*
|
const Sdp*
|
||||||
JsepSessionImpl::GetAnswer() const
|
JsepSessionImpl::GetAnswer() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mState == kJsepStateStable);
|
return mWasOffererLastTime ? mCurrentRemoteDescription.get()
|
||||||
|
: mCurrentLocalDescription.get();
|
||||||
return mIsOfferer ? mCurrentRemoteDescription.get()
|
|
||||||
: mCurrentLocalDescription.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
JsepSessionImpl(const std::string& name, UniquePtr<JsepUuidGenerator> uuidgen)
|
JsepSessionImpl(const std::string& name, UniquePtr<JsepUuidGenerator> uuidgen)
|
||||||
: JsepSession(name),
|
: JsepSession(name),
|
||||||
mIsOfferer(false),
|
mIsOfferer(false),
|
||||||
|
mWasOffererLastTime(false),
|
||||||
mIceControlling(false),
|
mIceControlling(false),
|
||||||
mRemoteIsIceLite(false),
|
mRemoteIsIceLite(false),
|
||||||
mSessionId(0),
|
mSessionId(0),
|
||||||
|
@ -240,7 +241,7 @@ private:
|
||||||
const Sdp& oldAnswer,
|
const Sdp& oldAnswer,
|
||||||
Sdp* newSdp);
|
Sdp* newSdp);
|
||||||
void SetupBundle(Sdp* sdp) const;
|
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;
|
void SetupMsidSemantic(const std::vector<std::string>& msids, Sdp* sdp) const;
|
||||||
nsresult GetIdsFromMsid(const Sdp& sdp,
|
nsresult GetIdsFromMsid(const Sdp& sdp,
|
||||||
const SdpMediaSection& msection,
|
const SdpMediaSection& msection,
|
||||||
|
@ -286,11 +287,15 @@ private:
|
||||||
nsresult FinalizeTransport(const SdpAttributeList& remote,
|
nsresult FinalizeTransport(const SdpAttributeList& remote,
|
||||||
const SdpAttributeList& answer,
|
const SdpAttributeList& answer,
|
||||||
const RefPtr<JsepTransport>& transport);
|
const RefPtr<JsepTransport>& transport);
|
||||||
|
bool AreOldTransportParamsValid(const Sdp& oldAnswer,
|
||||||
|
const Sdp& newOffer,
|
||||||
|
size_t level);
|
||||||
|
|
||||||
nsresult AddCandidateToSdp(Sdp* sdp,
|
nsresult AddCandidateToSdp(Sdp* sdp,
|
||||||
const std::string& candidate,
|
const std::string& candidate,
|
||||||
const std::string& mid,
|
const std::string& mid,
|
||||||
uint16_t level);
|
uint16_t level);
|
||||||
|
nsresult GetComponent(const std::string& candidate, size_t* component);
|
||||||
|
|
||||||
SdpMediaSection* FindMsectionByMid(Sdp& sdp,
|
SdpMediaSection* FindMsectionByMid(Sdp& sdp,
|
||||||
const std::string& mid) const;
|
const std::string& mid) const;
|
||||||
|
@ -330,6 +335,7 @@ private:
|
||||||
std::vector<JsepTrackPair> mNegotiatedTrackPairs;
|
std::vector<JsepTrackPair> mNegotiatedTrackPairs;
|
||||||
|
|
||||||
bool mIsOfferer;
|
bool mIsOfferer;
|
||||||
|
bool mWasOffererLastTime;
|
||||||
bool mIceControlling;
|
bool mIceControlling;
|
||||||
std::string mIceUfrag;
|
std::string mIceUfrag;
|
||||||
std::string mIcePwd;
|
std::string mIcePwd;
|
||||||
|
|
|
@ -31,27 +31,8 @@
|
||||||
#include "mtransport_test_utils.h"
|
#include "mtransport_test_utils.h"
|
||||||
|
|
||||||
namespace mozilla {
|
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:");
|
static std::string kAEqualsCandidate("a=candidate:");
|
||||||
|
const static size_t kNumCandidatesPerComponent = 3;
|
||||||
|
|
||||||
class JsepSessionTestBase : public ::testing::Test
|
class JsepSessionTestBase : public ::testing::Test
|
||||||
{
|
{
|
||||||
|
@ -372,8 +353,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
UniquePtr<Sdp> GetParsedLocalDescription(const JsepSessionImpl& side) const {
|
UniquePtr<Sdp> GetParsedLocalDescription(const JsepSessionImpl& side) const {
|
||||||
SipccSdpParser parser;
|
return Parse(side.GetLocalDescription());
|
||||||
return mozilla::Move(parser.Parse(side.GetLocalDescription()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SdpMediaSection* GetMsection(Sdp& sdp,
|
SdpMediaSection* GetMsection(Sdp& sdp,
|
||||||
|
@ -591,62 +571,203 @@ protected:
|
||||||
DumpTrackPairs(mSessionAns);
|
DumpTrackPairs(mSessionAns);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
typedef enum {
|
||||||
GatherCandidates(JsepSession& session)
|
RTP = 1,
|
||||||
{
|
RTCP = 2
|
||||||
bool skipped;
|
} ComponentType;
|
||||||
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);
|
|
||||||
|
|
||||||
for (size_t i = 3; i < 6; ++i) {
|
class CandidateSet {
|
||||||
session.AddLocalIceCandidate(
|
public:
|
||||||
kAEqualsCandidate + kCandidates[i], "", 1, &skipped);
|
CandidateSet() {}
|
||||||
session.AddLocalIceCandidate(
|
|
||||||
kAEqualsCandidate + kRtcpCandidates[i], "", 1, &skipped);
|
|
||||||
}
|
|
||||||
session.EndOfLocalCandidates("192.168.1.2", 2012, "192.168.1.2", 3012, 1);
|
|
||||||
|
|
||||||
std::cerr << "local SDP after candidates: "
|
void Gather(JsepSession& session,
|
||||||
<< session.GetLocalDescription();
|
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
|
void Gather(JsepSession& session, size_t level, ComponentType component)
|
||||||
TrickleCandidates(JsepSession& session)
|
{
|
||||||
{
|
static uint16_t port = 1000;
|
||||||
for (size_t i = 0; i < 3; ++i) {
|
std::vector<std::string> candidates;
|
||||||
session.AddRemoteIceCandidate(
|
for (size_t i = 0; i < kNumCandidatesPerComponent; ++i) {
|
||||||
kAEqualsCandidate + kCandidates[i], "", 0);
|
++port;
|
||||||
session.AddRemoteIceCandidate(
|
std::ostringstream candidate;
|
||||||
kAEqualsCandidate + kRtcpCandidates[i], "", 0);
|
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) {
|
// Stomp existing candidates
|
||||||
session.AddRemoteIceCandidate(
|
mCandidates[level][component] = candidates;
|
||||||
kAEqualsCandidate + kCandidates[i], "", 1);
|
|
||||||
session.AddRemoteIceCandidate(
|
|
||||||
kAEqualsCandidate + kRtcpCandidates[i], "", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "remote SDP after candidates: "
|
// Stomp existing defaults
|
||||||
<< session.GetRemoteDescription();
|
mDefaultCandidates[level][component] =
|
||||||
}
|
std::make_pair("192.168.0.1", port);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void FinishGathering(JsepSession& session) const
|
||||||
GatherOffererCandidates()
|
{
|
||||||
{
|
// Copy so we can be terse and use []
|
||||||
GatherCandidates(mSessionOff);
|
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
|
void Trickle(JsepSession& session)
|
||||||
TrickleOffererCandidates()
|
{
|
||||||
{
|
for (const auto& levelAndCandidate : mCandidatesToTrickle) {
|
||||||
TrickleCandidates(mSessionAns);
|
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
|
// For streaming parse errors
|
||||||
std::string
|
std::string
|
||||||
|
@ -661,85 +782,19 @@ protected:
|
||||||
return output.str();
|
return output.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void CheckEndOfCandidates(bool expectEoc,
|
||||||
ValidateCandidates(JsepSession& session, bool local)
|
const SdpMediaSection& msection,
|
||||||
|
const std::string& context)
|
||||||
{
|
{
|
||||||
std::string sdp =
|
if (expectEoc) {
|
||||||
local ? session.GetLocalDescription() : session.GetRemoteDescription();
|
ASSERT_TRUE(msection.GetAttributeList().HasAttribute(
|
||||||
SipccSdpParser parser;
|
SdpAttribute::kEndOfCandidatesAttribute))
|
||||||
UniquePtr<Sdp> parsed = parser.Parse(sdp);
|
<< context << " (level " << msection.GetLevel() << ")";
|
||||||
ASSERT_TRUE(!!parsed) << "Parse failed on " << std::endl << sdp << std::endl
|
} else {
|
||||||
<< "Errors were: " << GetParseErrors(parser);
|
ASSERT_FALSE(msection.GetAttributeList().HasAttribute(
|
||||||
ASSERT_LT(0U, parsed->GetMediaSectionCount());
|
SdpAttribute::kEndOfCandidatesAttribute))
|
||||||
|
<< context << " (level " << msection.GetLevel() << ")";
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
void
|
||||||
|
@ -758,8 +813,7 @@ protected:
|
||||||
|
|
||||||
void
|
void
|
||||||
DisableMsection(std::string* sdp, size_t level) const {
|
DisableMsection(std::string* sdp, size_t level) const {
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> parsed(Parse(*sdp));
|
||||||
UniquePtr<Sdp> parsed = parser.Parse(*sdp);
|
|
||||||
ASSERT_TRUE(parsed.get());
|
ASSERT_TRUE(parsed.get());
|
||||||
ASSERT_LT(level, parsed->GetMediaSectionCount());
|
ASSERT_LT(level, parsed->GetMediaSectionCount());
|
||||||
parsed->GetMediaSection(level).SetPort(0);
|
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;
|
JsepSessionImpl mSessionOff;
|
||||||
|
CandidateSet mOffCandidates;
|
||||||
JsepSessionImpl mSessionAns;
|
JsepSessionImpl mSessionAns;
|
||||||
|
CandidateSet mAnsCandidates;
|
||||||
std::vector<SdpMediaSection::MediaType> types;
|
std::vector<SdpMediaSection::MediaType> types;
|
||||||
|
std::vector<std::pair<std::string, uint16_t>> mGatheredCandidates;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void
|
void
|
||||||
ValidateTransport(TransportData& source, const std::string& sdp_str)
|
ValidateTransport(TransportData& source, const std::string& sdp_str)
|
||||||
{
|
{
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> sdp(Parse(sdp_str));
|
||||||
auto sdp = parser.Parse(sdp_str);
|
ASSERT_TRUE(!!sdp);
|
||||||
ASSERT_TRUE(!!sdp) << "Should have valid SDP" << std::endl
|
|
||||||
<< "Errors were: " << GetParseErrors(parser);
|
|
||||||
size_t num_m_sections = sdp->GetMediaSectionCount();
|
size_t num_m_sections = sdp->GetMediaSectionCount();
|
||||||
for (size_t i = 0; i < num_m_sections; ++i) {
|
for (size_t i = 0; i < num_m_sections; ++i) {
|
||||||
auto& msection = sdp->GetMediaSection(i);
|
auto& msection = sdp->GetMediaSection(i);
|
||||||
|
@ -1993,17 +2058,289 @@ TEST_P(JsepSessionTest, FullCallWithCandidates)
|
||||||
AddTracks(mSessionOff);
|
AddTracks(mSessionOff);
|
||||||
std::string offer = CreateOffer();
|
std::string offer = CreateOffer();
|
||||||
SetLocalOffer(offer);
|
SetLocalOffer(offer);
|
||||||
GatherOffererCandidates();
|
mOffCandidates.Gather(mSessionOff, types);
|
||||||
ValidateOffererCandidates();
|
|
||||||
|
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);
|
SetRemoteOffer(offer);
|
||||||
TrickleOffererCandidates();
|
mOffCandidates.Trickle(mSessionAns);
|
||||||
ValidateAnswererCandidates();
|
|
||||||
|
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);
|
AddTracks(mSessionAns);
|
||||||
std::string answer = CreateAnswer();
|
std::string answer = CreateAnswer();
|
||||||
SetLocalAnswer(answer);
|
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);
|
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(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
Variants,
|
Variants,
|
||||||
JsepSessionTest,
|
JsepSessionTest,
|
||||||
|
@ -2039,10 +2376,8 @@ TEST_F(JsepSessionTest, OfferAnswerRecvOnlyLines)
|
||||||
options.mDontOfferDataChannel = Some(true);
|
options.mDontOfferDataChannel = Some(true);
|
||||||
std::string offer = CreateOffer(Some(options));
|
std::string offer = CreateOffer(Some(options));
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||||
UniquePtr<Sdp> parsedOffer = parser.Parse(offer);
|
ASSERT_TRUE(!!parsedOffer);
|
||||||
ASSERT_TRUE(!!parsedOffer) << "Should have valid SDP" << std::endl
|
|
||||||
<< "Errors were: " << GetParseErrors(parser);
|
|
||||||
|
|
||||||
ASSERT_EQ(3U, parsedOffer->GetMediaSectionCount());
|
ASSERT_EQ(3U, parsedOffer->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||||
|
@ -2079,7 +2414,7 @@ TEST_F(JsepSessionTest, OfferAnswerRecvOnlyLines)
|
||||||
SetRemoteOffer(offer, CHECK_SUCCESS);
|
SetRemoteOffer(offer, CHECK_SUCCESS);
|
||||||
|
|
||||||
std::string answer = CreateAnswer();
|
std::string answer = CreateAnswer();
|
||||||
UniquePtr<Sdp> parsedAnswer = parser.Parse(answer);
|
UniquePtr<Sdp> parsedAnswer(Parse(answer));
|
||||||
|
|
||||||
ASSERT_EQ(3U, parsedAnswer->GetMediaSectionCount());
|
ASSERT_EQ(3U, parsedAnswer->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||||
|
@ -2118,10 +2453,8 @@ TEST_F(JsepSessionTest, OfferAnswerSendOnlyLines)
|
||||||
options.mDontOfferDataChannel = Some(true);
|
options.mDontOfferDataChannel = Some(true);
|
||||||
std::string offer = CreateOffer(Some(options));
|
std::string offer = CreateOffer(Some(options));
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> outputSdp(Parse(offer));
|
||||||
auto outputSdp = parser.Parse(offer);
|
ASSERT_TRUE(!!outputSdp);
|
||||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
|
||||||
<< "Errors were: " << GetParseErrors(parser);
|
|
||||||
|
|
||||||
ASSERT_EQ(3U, outputSdp->GetMediaSectionCount());
|
ASSERT_EQ(3U, outputSdp->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||||
|
@ -2150,7 +2483,7 @@ TEST_F(JsepSessionTest, OfferAnswerSendOnlyLines)
|
||||||
SetRemoteOffer(offer, CHECK_SUCCESS);
|
SetRemoteOffer(offer, CHECK_SUCCESS);
|
||||||
|
|
||||||
std::string answer = CreateAnswer();
|
std::string answer = CreateAnswer();
|
||||||
outputSdp = parser.Parse(answer);
|
outputSdp = Parse(answer);
|
||||||
|
|
||||||
ASSERT_EQ(3U, outputSdp->GetMediaSectionCount());
|
ASSERT_EQ(3U, outputSdp->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||||
|
@ -2174,8 +2507,7 @@ TEST_F(JsepSessionTest, OfferToReceiveAudioNotUsed)
|
||||||
|
|
||||||
OfferAnswer(CHECK_SUCCESS, Some(options));
|
OfferAnswer(CHECK_SUCCESS, Some(options));
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> offer(Parse(mSessionOff.GetLocalDescription()));
|
||||||
UniquePtr<Sdp> offer(parser.Parse(mSessionOff.GetLocalDescription()));
|
|
||||||
ASSERT_TRUE(offer.get());
|
ASSERT_TRUE(offer.get());
|
||||||
ASSERT_EQ(1U, offer->GetMediaSectionCount());
|
ASSERT_EQ(1U, offer->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||||
|
@ -2183,7 +2515,7 @@ TEST_F(JsepSessionTest, OfferToReceiveAudioNotUsed)
|
||||||
ASSERT_EQ(SdpDirectionAttribute::kRecvonly,
|
ASSERT_EQ(SdpDirectionAttribute::kRecvonly,
|
||||||
offer->GetMediaSection(0).GetAttributeList().GetDirection());
|
offer->GetMediaSection(0).GetAttributeList().GetDirection());
|
||||||
|
|
||||||
UniquePtr<Sdp> answer(parser.Parse(mSessionAns.GetLocalDescription()));
|
UniquePtr<Sdp> answer(Parse(mSessionAns.GetLocalDescription()));
|
||||||
ASSERT_TRUE(answer.get());
|
ASSERT_TRUE(answer.get());
|
||||||
ASSERT_EQ(1U, answer->GetMediaSectionCount());
|
ASSERT_EQ(1U, answer->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||||
|
@ -2199,8 +2531,7 @@ TEST_F(JsepSessionTest, OfferToReceiveVideoNotUsed)
|
||||||
|
|
||||||
OfferAnswer(CHECK_SUCCESS, Some(options));
|
OfferAnswer(CHECK_SUCCESS, Some(options));
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> offer(Parse(mSessionOff.GetLocalDescription()));
|
||||||
UniquePtr<Sdp> offer(parser.Parse(mSessionOff.GetLocalDescription()));
|
|
||||||
ASSERT_TRUE(offer.get());
|
ASSERT_TRUE(offer.get());
|
||||||
ASSERT_EQ(1U, offer->GetMediaSectionCount());
|
ASSERT_EQ(1U, offer->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kVideo,
|
ASSERT_EQ(SdpMediaSection::kVideo,
|
||||||
|
@ -2208,7 +2539,7 @@ TEST_F(JsepSessionTest, OfferToReceiveVideoNotUsed)
|
||||||
ASSERT_EQ(SdpDirectionAttribute::kRecvonly,
|
ASSERT_EQ(SdpDirectionAttribute::kRecvonly,
|
||||||
offer->GetMediaSection(0).GetAttributeList().GetDirection());
|
offer->GetMediaSection(0).GetAttributeList().GetDirection());
|
||||||
|
|
||||||
UniquePtr<Sdp> answer(parser.Parse(mSessionAns.GetLocalDescription()));
|
UniquePtr<Sdp> answer(Parse(mSessionAns.GetLocalDescription()));
|
||||||
ASSERT_TRUE(answer.get());
|
ASSERT_TRUE(answer.get());
|
||||||
ASSERT_EQ(1U, answer->GetMediaSectionCount());
|
ASSERT_EQ(1U, answer->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kVideo,
|
ASSERT_EQ(SdpMediaSection::kVideo,
|
||||||
|
@ -2229,10 +2560,8 @@ TEST_F(JsepSessionTest, CreateOfferNoDatachannelDefault)
|
||||||
|
|
||||||
std::string offer = CreateOffer();
|
std::string offer = CreateOffer();
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> outputSdp(Parse(offer));
|
||||||
auto outputSdp = parser.Parse(offer);
|
ASSERT_TRUE(!!outputSdp);
|
||||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
|
||||||
<< "Errors were: " << GetParseErrors(parser);
|
|
||||||
|
|
||||||
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
||||||
ASSERT_EQ(SdpMediaSection::kAudio,
|
ASSERT_EQ(SdpMediaSection::kAudio,
|
||||||
|
@ -2255,10 +2584,8 @@ TEST_F(JsepSessionTest, ValidateOfferedCodecParams)
|
||||||
|
|
||||||
std::string offer = CreateOffer();
|
std::string offer = CreateOffer();
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> outputSdp(Parse(offer));
|
||||||
auto outputSdp = parser.Parse(offer);
|
ASSERT_TRUE(!!outputSdp);
|
||||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
|
||||||
<< "Errors were: " << GetParseErrors(parser);
|
|
||||||
|
|
||||||
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
||||||
auto& video_section = outputSdp->GetMediaSection(1);
|
auto& video_section = outputSdp->GetMediaSection(1);
|
||||||
|
@ -2389,10 +2716,8 @@ TEST_F(JsepSessionTest, ValidateAnsweredCodecParams)
|
||||||
|
|
||||||
std::string answer = CreateAnswer();
|
std::string answer = CreateAnswer();
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> outputSdp(Parse(answer));
|
||||||
auto outputSdp = parser.Parse(answer);
|
ASSERT_TRUE(!!outputSdp);
|
||||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
|
||||||
<< "Errors were: " << GetParseErrors(parser);
|
|
||||||
|
|
||||||
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
ASSERT_EQ(2U, outputSdp->GetMediaSectionCount());
|
||||||
auto& video_section = outputSdp->GetMediaSection(1);
|
auto& video_section = outputSdp->GetMediaSection(1);
|
||||||
|
@ -2889,10 +3214,8 @@ TEST_P(JsepSessionTest, TestRejectMline)
|
||||||
|
|
||||||
std::string answer = CreateAnswer();
|
std::string answer = CreateAnswer();
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> outputSdp(Parse(answer));
|
||||||
auto outputSdp = parser.Parse(answer);
|
ASSERT_TRUE(!!outputSdp);
|
||||||
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
|
|
||||||
<< "Errors were: " << GetParseErrors(parser);
|
|
||||||
|
|
||||||
ASSERT_NE(0U, outputSdp->GetMediaSectionCount());
|
ASSERT_NE(0U, outputSdp->GetMediaSectionCount());
|
||||||
SdpMediaSection* failed_section = nullptr;
|
SdpMediaSection* failed_section = nullptr;
|
||||||
|
@ -2942,8 +3265,7 @@ TEST_F(JsepSessionTest, TestIceLite)
|
||||||
std::string offer = CreateOffer();
|
std::string offer = CreateOffer();
|
||||||
SetLocalOffer(offer, CHECK_SUCCESS);
|
SetLocalOffer(offer, CHECK_SUCCESS);
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||||
UniquePtr<Sdp> parsedOffer = parser.Parse(offer);
|
|
||||||
parsedOffer->GetAttributeList().SetAttribute(
|
parsedOffer->GetAttributeList().SetAttribute(
|
||||||
new SdpFlagAttribute(SdpAttribute::kIceLiteAttribute));
|
new SdpFlagAttribute(SdpAttribute::kIceLiteAttribute));
|
||||||
|
|
||||||
|
@ -2988,8 +3310,7 @@ TEST_F(JsepSessionTest, TestExtmap)
|
||||||
SetLocalAnswer(answer, CHECK_SUCCESS);
|
SetLocalAnswer(answer, CHECK_SUCCESS);
|
||||||
SetRemoteAnswer(answer, CHECK_SUCCESS);
|
SetRemoteAnswer(answer, CHECK_SUCCESS);
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||||
UniquePtr<Sdp> parsedOffer = parser.Parse(offer);
|
|
||||||
ASSERT_EQ(1U, parsedOffer->GetMediaSectionCount());
|
ASSERT_EQ(1U, parsedOffer->GetMediaSectionCount());
|
||||||
|
|
||||||
auto& offerMediaAttrs = parsedOffer->GetMediaSection(0).GetAttributeList();
|
auto& offerMediaAttrs = parsedOffer->GetMediaSection(0).GetAttributeList();
|
||||||
|
@ -3004,7 +3325,7 @@ TEST_F(JsepSessionTest, TestExtmap)
|
||||||
ASSERT_EQ("bar", offerExtmap[2].extensionname);
|
ASSERT_EQ("bar", offerExtmap[2].extensionname);
|
||||||
ASSERT_EQ(3U, offerExtmap[2].entry);
|
ASSERT_EQ(3U, offerExtmap[2].entry);
|
||||||
|
|
||||||
UniquePtr<Sdp> parsedAnswer = parser.Parse(answer);
|
UniquePtr<Sdp> parsedAnswer(Parse(answer));
|
||||||
ASSERT_EQ(1U, parsedAnswer->GetMediaSectionCount());
|
ASSERT_EQ(1U, parsedAnswer->GetMediaSectionCount());
|
||||||
|
|
||||||
auto& answerMediaAttrs = parsedAnswer->GetMediaSection(0).GetAttributeList();
|
auto& answerMediaAttrs = parsedAnswer->GetMediaSection(0).GetAttributeList();
|
||||||
|
@ -3026,8 +3347,7 @@ TEST_F(JsepSessionTest, TestRtcpFbStar)
|
||||||
|
|
||||||
std::string offer = CreateOffer();
|
std::string offer = CreateOffer();
|
||||||
|
|
||||||
SipccSdpParser parser;
|
UniquePtr<Sdp> parsedOffer(Parse(offer));
|
||||||
UniquePtr<Sdp> parsedOffer = parser.Parse(offer);
|
|
||||||
auto* rtcpfbs = new SdpRtcpFbAttributeList;
|
auto* rtcpfbs = new SdpRtcpFbAttributeList;
|
||||||
rtcpfbs->PushEntry("*", SdpRtcpFbAttributeList::kNack);
|
rtcpfbs->PushEntry("*", SdpRtcpFbAttributeList::kNack);
|
||||||
parsedOffer->GetMediaSection(0).GetAttributeList().SetAttribute(rtcpfbs);
|
parsedOffer->GetMediaSection(0).GetAttributeList().SetAttribute(rtcpfbs);
|
||||||
|
|
|
@ -18,7 +18,10 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import (
|
||||||
|
Counter,
|
||||||
|
OrderedDict,
|
||||||
|
)
|
||||||
from mozbuild.util import (
|
from mozbuild.util import (
|
||||||
HierarchicalStringList,
|
HierarchicalStringList,
|
||||||
HierarchicalStringListWithFlagsFactory,
|
HierarchicalStringListWithFlagsFactory,
|
||||||
|
@ -576,6 +579,49 @@ class Files(SubContext):
|
||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def aggregate(files):
|
||||||
|
"""Given a mapping of path to Files, obtain aggregate results.
|
||||||
|
|
||||||
|
Consumers may want to extract useful information from a collection of
|
||||||
|
Files describing paths. e.g. given the files info data for N paths,
|
||||||
|
recommend a single bug component based on the most frequent one. This
|
||||||
|
function provides logic for deriving aggregate knowledge from a
|
||||||
|
collection of path File metadata.
|
||||||
|
|
||||||
|
Note: the intent of this function is to operate on the result of
|
||||||
|
:py:func:`mozbuild.frontend.reader.BuildReader.files_info`. The
|
||||||
|
:py:func:`mozbuild.frontend.context.Files` instances passed in are
|
||||||
|
thus the "collapsed" (``__iadd__``ed) results of all ``Files`` from all
|
||||||
|
moz.build files relevant to a specific path, not individual ``Files``
|
||||||
|
instances from a single moz.build file.
|
||||||
|
"""
|
||||||
|
d = {}
|
||||||
|
|
||||||
|
bug_components = Counter()
|
||||||
|
|
||||||
|
for f in files.values():
|
||||||
|
bug_component = f.get('BUG_COMPONENT')
|
||||||
|
if bug_component:
|
||||||
|
bug_components[bug_component] += 1
|
||||||
|
|
||||||
|
d['bug_component_counts'] = []
|
||||||
|
for c, count in bug_components.most_common():
|
||||||
|
component = (c.product, c.component)
|
||||||
|
d['bug_component_counts'].append((c, count))
|
||||||
|
|
||||||
|
if 'recommended_bug_component' not in d:
|
||||||
|
d['recommended_bug_component'] = component
|
||||||
|
recommended_count = count
|
||||||
|
elif count == recommended_count:
|
||||||
|
# Don't recommend a component if it doesn't have a clear lead.
|
||||||
|
d['recommended_bug_component'] = None
|
||||||
|
|
||||||
|
# In case no bug components.
|
||||||
|
d.setdefault('recommended_bug_component', None)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
# This defines functions that create sub-contexts.
|
# This defines functions that create sub-contexts.
|
||||||
#
|
#
|
||||||
|
|
|
@ -11,6 +11,7 @@ from mozbuild.frontend.context import (
|
||||||
Context,
|
Context,
|
||||||
ContextDerivedTypedList,
|
ContextDerivedTypedList,
|
||||||
ContextDerivedTypedListWithItems,
|
ContextDerivedTypedListWithItems,
|
||||||
|
Files,
|
||||||
FUNCTIONS,
|
FUNCTIONS,
|
||||||
ObjDirPath,
|
ObjDirPath,
|
||||||
Path,
|
Path,
|
||||||
|
@ -565,5 +566,64 @@ class TestPaths(unittest.TestCase):
|
||||||
self.assertEqual(l[p_str].foo, True)
|
self.assertEqual(l[p_str].foo, True)
|
||||||
self.assertEqual(l[p_path].foo, True)
|
self.assertEqual(l[p_path].foo, True)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFiles(unittest.TestCase):
|
||||||
|
def test_aggregate_empty(self):
|
||||||
|
c = Context({})
|
||||||
|
|
||||||
|
files = {'moz.build': Files(c, pattern='**')}
|
||||||
|
|
||||||
|
self.assertEqual(Files.aggregate(files), {
|
||||||
|
'bug_component_counts': [],
|
||||||
|
'recommended_bug_component': None,
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_single_bug_component(self):
|
||||||
|
c = Context({})
|
||||||
|
f = Files(c, pattern='**')
|
||||||
|
f['BUG_COMPONENT'] = (u'Product1', u'Component1')
|
||||||
|
|
||||||
|
files = {'moz.build': f}
|
||||||
|
self.assertEqual(Files.aggregate(files), {
|
||||||
|
'bug_component_counts': [((u'Product1', u'Component1'), 1)],
|
||||||
|
'recommended_bug_component': (u'Product1', u'Component1'),
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_multiple_bug_components(self):
|
||||||
|
c = Context({})
|
||||||
|
f1 = Files(c, pattern='**')
|
||||||
|
f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
|
||||||
|
|
||||||
|
f2 = Files(c, pattern='**')
|
||||||
|
f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
|
||||||
|
|
||||||
|
files = {'a': f1, 'b': f2, 'c': f1}
|
||||||
|
self.assertEqual(Files.aggregate(files), {
|
||||||
|
'bug_component_counts': [
|
||||||
|
((u'Product1', u'Component1'), 2),
|
||||||
|
((u'Product2', u'Component2'), 1),
|
||||||
|
],
|
||||||
|
'recommended_bug_component': (u'Product1', u'Component1'),
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_no_recommended_bug_component(self):
|
||||||
|
"""If there is no clear count winner, we don't recommend a bug component."""
|
||||||
|
c = Context({})
|
||||||
|
f1 = Files(c, pattern='**')
|
||||||
|
f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
|
||||||
|
|
||||||
|
f2 = Files(c, pattern='**')
|
||||||
|
f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
|
||||||
|
|
||||||
|
files = {'a': f1, 'b': f2}
|
||||||
|
self.assertEqual(Files.aggregate(files), {
|
||||||
|
'bug_component_counts': [
|
||||||
|
((u'Product1', u'Component1'), 1),
|
||||||
|
((u'Product2', u'Component2'), 1),
|
||||||
|
],
|
||||||
|
'recommended_bug_component': None,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,15 +1,29 @@
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
# 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,
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
VERSION = '0.1'
|
VERSION = '0.2'
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
author='Mozilla Foundation',
|
||||||
|
author_email='dev-builds@lists.mozilla.org',
|
||||||
name='mozbuild',
|
name='mozbuild',
|
||||||
description='Mozilla build system functionality.',
|
description='Mozilla build system functionality.',
|
||||||
license='MPL 2.0',
|
license='MPL 2.0',
|
||||||
packages=['mach', 'mozbuild', 'mozpack'],
|
packages=find_packages(),
|
||||||
version=VERSION
|
version=VERSION,
|
||||||
|
install_requires=[
|
||||||
|
'jsmin',
|
||||||
|
'mozfile',
|
||||||
|
],
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 3 - Alpha',
|
||||||
|
'Topic :: Software Development :: Build Tools',
|
||||||
|
'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Programming Language :: Python :: Implementation :: CPython',
|
||||||
|
],
|
||||||
|
keywords='mozilla build',
|
||||||
)
|
)
|
||||||
|
|
|
@ -462,16 +462,6 @@ CertErrorRunnable::CheckCertOverrides()
|
||||||
mDefaultErrorCodeToReport);
|
mDefaultErrorCodeToReport);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
|
|
||||||
NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
|
|
||||||
if (sslSocketControl &&
|
|
||||||
sslSocketControl->GetBypassAuthentication()) {
|
|
||||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
|
||||||
("[%p][%p] Bypass Auth in CheckCertOverrides\n",
|
|
||||||
mFdForLogging, this));
|
|
||||||
return new SSLServerCertVerificationResult(mInfoObject, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t port;
|
int32_t port;
|
||||||
mInfoObject->GetPort(&port);
|
mInfoObject->GetPort(&port);
|
||||||
|
|
||||||
|
@ -580,6 +570,8 @@ CertErrorRunnable::CheckCertOverrides()
|
||||||
// First, deliver the technical details of the broken SSL status.
|
// First, deliver the technical details of the broken SSL status.
|
||||||
|
|
||||||
// Try to get a nsIBadCertListener2 implementation from the socket consumer.
|
// Try to get a nsIBadCertListener2 implementation from the socket consumer.
|
||||||
|
nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
|
||||||
|
NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
|
||||||
if (sslSocketControl) {
|
if (sslSocketControl) {
|
||||||
nsCOMPtr<nsIInterfaceRequestor> cb;
|
nsCOMPtr<nsIInterfaceRequestor> cb;
|
||||||
sslSocketControl->GetNotificationCallbacks(getter_AddRefs(cb));
|
sslSocketControl->GetNotificationCallbacks(getter_AddRefs(cb));
|
||||||
|
@ -1462,6 +1454,14 @@ AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
|
||||||
if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess)
|
if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess)
|
||||||
return SECFailure;
|
return SECFailure;
|
||||||
|
|
||||||
|
nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
|
||||||
|
NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, socketInfo));
|
||||||
|
if (sslSocketControl && sslSocketControl->GetBypassAuthentication()) {
|
||||||
|
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||||
|
("[%p] Bypass Auth in AuthCertificateHook\n", fd));
|
||||||
|
return SECSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
bool onSTSThread;
|
bool onSTSThread;
|
||||||
nsresult nrv;
|
nsresult nrv;
|
||||||
nsCOMPtr<nsIEventTarget> sts
|
nsCOMPtr<nsIEventTarget> sts
|
||||||
|
|
|
@ -86,9 +86,9 @@ class SyncTestCommands(MachCommandBase):
|
||||||
'-r', '%s/components/httpd.manifest' % self.bindir,
|
'-r', '%s/components/httpd.manifest' % self.bindir,
|
||||||
'-m',
|
'-m',
|
||||||
'-s',
|
'-s',
|
||||||
|
'-e', 'const _TESTING_MODULES_DIR = "%s/_tests/modules";' % topobjdir,
|
||||||
'-f', '%s/testing/xpcshell/head.js' % topsrcdir,
|
'-f', '%s/testing/xpcshell/head.js' % topsrcdir,
|
||||||
'-e', 'const _SERVER_ADDR = "%s";' % hostname,
|
'-e', 'const _SERVER_ADDR = "%s";' % hostname,
|
||||||
'-e', 'const _TESTING_MODULES_DIR = "%s/_tests/modules";' % topobjdir,
|
|
||||||
'-e', 'const SERVER_PORT = "%s";' % port,
|
'-e', 'const SERVER_PORT = "%s";' % port,
|
||||||
'-e', 'const INCLUDE_FILES = [%s];' % ', '.join(head_paths),
|
'-e', 'const INCLUDE_FILES = [%s];' % ', '.join(head_paths),
|
||||||
'-e', '_register_protocol_handlers();',
|
'-e', '_register_protocol_handlers();',
|
||||||
|
|
|
@ -63,7 +63,8 @@ int main(int argc, char** argv)
|
||||||
#if defined(HAVE_LIBXSS) && defined(MOZ_WIDGET_GTK)
|
#if defined(HAVE_LIBXSS) && defined(MOZ_WIDGET_GTK)
|
||||||
int event_base, error_base;
|
int event_base, error_base;
|
||||||
Bool have_xscreensaver =
|
Bool have_xscreensaver =
|
||||||
XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, &error_base);
|
XScreenSaverQueryExtension(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
|
||||||
|
&event_base, &error_base);
|
||||||
|
|
||||||
if (!have_xscreensaver) {
|
if (!have_xscreensaver) {
|
||||||
fprintf(stderr, "No XScreenSaver extension on display\n");
|
fprintf(stderr, "No XScreenSaver extension on display\n");
|
||||||
|
@ -73,7 +74,8 @@ int main(int argc, char** argv)
|
||||||
fprintf(stderr, "%s: Out of memory\n", argv[0]);
|
fprintf(stderr, "%s: Out of memory\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), info);
|
XScreenSaverQueryInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
|
||||||
|
GDK_ROOT_WINDOW(), info);
|
||||||
|
|
||||||
const char* state;
|
const char* state;
|
||||||
const char* til_or_since = nullptr;
|
const char* til_or_since = nullptr;
|
||||||
|
|
|
@ -137,8 +137,19 @@ function getTempFile(aLeafName)
|
||||||
do_check_false(file.exists());
|
do_check_false(file.exists());
|
||||||
|
|
||||||
do_register_cleanup(function () {
|
do_register_cleanup(function () {
|
||||||
if (file.exists()) {
|
try {
|
||||||
file.remove(false);
|
file.remove(false)
|
||||||
|
} catch (e) {
|
||||||
|
if (!(e instanceof Components.Exception &&
|
||||||
|
(e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED ||
|
||||||
|
e.result == Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ||
|
||||||
|
e.result == Cr.NS_ERROR_FILE_NOT_FOUND))) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
// On Windows, we may get an access denied error if the file existed before,
|
||||||
|
// and was recently deleted.
|
||||||
|
// Don't bother checking file.exists() as that may also cause an access
|
||||||
|
// denied error.
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ menulist[editable="true"] > menupopup > menucaption {
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
menulist[editable="true"] > menupopup > :moz-any(menuitem, menucaption) > .menu-iconic-left
|
menulist[editable="true"] > menupopup > :-moz-any(menuitem, menucaption) > .menu-iconic-left {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,7 +239,7 @@ menulist > menupopup > menuitem[disabled="true"]:not([_moz-menuactive="true"]):-
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
menulist > menupopup > :moz-any(menuitem, menucaption):not(.menuitem-iconic) > .menu-iconic-text,
|
menulist > menupopup > :-moz-any(menuitem, menucaption):not(.menuitem-iconic) > .menu-iconic-text {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -822,13 +822,13 @@ DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
|
||||||
|
|
||||||
#ifndef MOZ_TREE_CAIRO
|
#ifndef MOZ_TREE_CAIRO
|
||||||
// Directly use the Cairo draw target to render the widget if using system Cairo everywhere.
|
// Directly use the Cairo draw target to render the widget if using system Cairo everywhere.
|
||||||
BorrowedCairoContext borrow(aDrawTarget);
|
BorrowedCairoContext borrowCairo(aDrawTarget);
|
||||||
if (borrow.mCairo) {
|
if (borrowCairo.mCairo) {
|
||||||
cairo_set_matrix(borrow.mCairo, &mat);
|
cairo_set_matrix(borrowCairo.mCairo, &mat);
|
||||||
|
|
||||||
moz_gtk_widget_paint(aGTKWidgetType, borrow.mCairo, &aGDKRect, &aState, aFlags, aDirection);
|
moz_gtk_widget_paint(aGTKWidgetType, borrowCairo.mCairo, &aGDKRect, &aState, aFlags, aDirection);
|
||||||
|
|
||||||
borrow.Finish();
|
borrowCairo.Finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Загрузка…
Ссылка в новой задаче