зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1401592: Add a config option to imitate the old setParameters behavior. r=jib,chutten,webidl,smaug
When the compat mode is used, we log warnings to the JS console instead of throwing. We also add a bunch of Glean metrics for tracking how often we see these warnings (or failures) in the field. Differential Revision: https://phabricator.services.mozilla.com/D161523
This commit is contained in:
Родитель
4d5c35000c
Коммит
e1da52d829
|
@ -477,6 +477,11 @@ nsresult PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
|
|||
// Initialize the media object.
|
||||
mForceProxy = ShouldForceProxy();
|
||||
|
||||
// We put this here, in case we later want to set this based on a non-standard
|
||||
// param in RTCConfiguration.
|
||||
mAllowOldSetParameters = Preferences::GetBool(
|
||||
"media.peerconnection.allow_old_setParameters", false);
|
||||
|
||||
// setup the stun local addresses IPC async call
|
||||
InitLocalAddrs();
|
||||
|
||||
|
@ -2079,6 +2084,12 @@ void PeerConnectionImpl::StampTimecard(const char* aEvent) {
|
|||
STAMP_TIMECARD(mTimeCard, aEvent);
|
||||
}
|
||||
|
||||
void PeerConnectionImpl::SendWarningToConsole(const nsCString& aWarning) {
|
||||
nsAutoString msg = NS_ConvertASCIItoUTF16(aWarning);
|
||||
nsContentUtils::ReportToConsoleByWindowID(msg, nsIScriptError::warningFlag,
|
||||
"WebRTC"_ns, mWindow->WindowID());
|
||||
}
|
||||
|
||||
nsresult PeerConnectionImpl::CalculateFingerprint(
|
||||
const std::string& algorithm, std::vector<uint8_t>* fingerprint) const {
|
||||
DtlsDigest digest(algorithm);
|
||||
|
@ -2372,6 +2383,7 @@ nsresult PeerConnectionImpl::SetConfiguration(
|
|||
|
||||
// Store the configuration for about:webrtc
|
||||
StoreConfigurationForAboutWebrtc(aConfiguration);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -519,6 +519,10 @@ class PeerConnectionImpl final
|
|||
return NS_ConvertUTF8toUTF16(result.c_str());
|
||||
}
|
||||
|
||||
bool ShouldAllowOldSetParameters() const { return mAllowOldSetParameters; }
|
||||
|
||||
void SendWarningToConsole(const nsCString& aWarning);
|
||||
|
||||
private:
|
||||
virtual ~PeerConnectionImpl();
|
||||
PeerConnectionImpl(const PeerConnectionImpl& rhs);
|
||||
|
@ -821,6 +825,9 @@ class PeerConnectionImpl final
|
|||
// Used to store the mDNS hostnames that we have registered
|
||||
std::set<std::string> mRegisteredMDNSHostnames;
|
||||
|
||||
// web-compat stopgap
|
||||
bool mAllowOldSetParameters = false;
|
||||
|
||||
// Used to store the mDNS hostnames that we have queried
|
||||
struct PendingIceCandidate {
|
||||
std::vector<std::string> mTokenizedCandidate;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "transport/logging.h"
|
||||
#include "mozilla/dom/MediaStreamTrack.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/glean/GleanMetrics.h"
|
||||
#include "transportbridge/MediaPipeline.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsString.h"
|
||||
|
@ -78,10 +79,18 @@ RTCRtpSender::RTCRtpSender(nsPIDOMWindowInner* aWindow, PeerConnectionImpl* aPc,
|
|||
}
|
||||
mPipeline->SetTrack(mSenderTrack);
|
||||
|
||||
mozilla::glean::rtcrtpsender::count.Add(1);
|
||||
|
||||
if (mPc->ShouldAllowOldSetParameters()) {
|
||||
mAllowOldSetParameters = true;
|
||||
mozilla::glean::rtcrtpsender::count_setparameters_compat.Add(1);
|
||||
}
|
||||
|
||||
if (aEncodings.Length()) {
|
||||
// This sender was created by addTransceiver with sendEncodings.
|
||||
mParameters.mEncodings = aEncodings;
|
||||
SetJsepRids(mParameters);
|
||||
mozilla::glean::rtcrtpsender::used_sendencodings.AddToNumerator(1);
|
||||
} else {
|
||||
// This sender was created by addTrack, sRD(offer), or addTransceiver
|
||||
// without sendEncodings.
|
||||
|
@ -419,6 +428,16 @@ nsTArray<RefPtr<dom::RTCStatsPromise>> RTCRtpSender::GetStatsInternal() {
|
|||
return promises;
|
||||
}
|
||||
|
||||
void RTCRtpSender::WarnAboutBadSetParameters(const nsCString& aError) {
|
||||
nsCString warning(
|
||||
"WARNING! Invalid setParameters call detected! The good news? Firefox "
|
||||
"supports sendEncodings in addTransceiver now, so we ask that you switch "
|
||||
"over to using the parameters code you use for other browsers. Thank you "
|
||||
"for your patience and support. The specific error was: ");
|
||||
warning += aError;
|
||||
mPc->SendWarningToConsole(warning);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> RTCRtpSender::SetParameters(
|
||||
const dom::RTCRtpSendParameters& aParameters, ErrorResult& aError) {
|
||||
dom::RTCRtpSendParameters paramsCopy(aParameters);
|
||||
|
@ -449,11 +468,47 @@ already_AddRefed<Promise> RTCRtpSender::SetParameters(
|
|||
// If sender.[[LastReturnedParameters]] is null, return a promise rejected
|
||||
// with a newly created InvalidStateError.
|
||||
if (!mLastReturnedParameters.isSome()) {
|
||||
p->MaybeRejectWithInvalidStateError(
|
||||
nsCString error(
|
||||
"Cannot call setParameters without first calling getParameters");
|
||||
return p.forget();
|
||||
if (mAllowOldSetParameters) {
|
||||
if (!mHaveWarnedBecauseNoGetParameters) {
|
||||
mHaveWarnedBecauseNoGetParameters = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::warn_no_getparameters
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
WarnAboutBadSetParameters(error);
|
||||
} else {
|
||||
if (!mHaveFailedBecauseNoGetParameters) {
|
||||
mHaveFailedBecauseNoGetParameters = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::fail_no_getparameters
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
p->MaybeRejectWithInvalidStateError(error);
|
||||
return p.forget();
|
||||
}
|
||||
}
|
||||
|
||||
// According to the spec, our consistency checking is based on
|
||||
// [[LastReturnedParameters]], but if we're letting
|
||||
// [[LastReturnedParameters]]==null slide, we still want to do
|
||||
// consistency checking on _something_ so we can warn implementers if they
|
||||
// are messing that up also. Just find something, _anything_, to do that
|
||||
// checking with.
|
||||
// TODO(bug 1803388): Remove this stuff once it is no longer needed.
|
||||
// TODO(bug 1803389): Remove the glean errors once they are no longer needed.
|
||||
Maybe<RTCRtpSendParameters> oldParams;
|
||||
if (mAllowOldSetParameters) {
|
||||
if (mPendingParameters.isSome()) {
|
||||
oldParams = mPendingParameters;
|
||||
} else {
|
||||
oldParams = Some(mParameters);
|
||||
}
|
||||
MOZ_ASSERT(oldParams.isSome());
|
||||
} else {
|
||||
oldParams = mLastReturnedParameters;
|
||||
}
|
||||
MOZ_ASSERT(oldParams.isSome());
|
||||
|
||||
// Validate parameters by running the following steps:
|
||||
// Let encodings be parameters.encodings.
|
||||
// Let codecs be parameters.codecs.
|
||||
|
@ -463,32 +518,104 @@ already_AddRefed<Promise> RTCRtpSender::SetParameters(
|
|||
// return a promise rejected with a newly created InvalidModificationError:
|
||||
|
||||
// encodings.length is different from N.
|
||||
if (paramsCopy.mEncodings.Length() !=
|
||||
mLastReturnedParameters->mEncodings.Length()) {
|
||||
p->MaybeRejectWithInvalidModificationError(
|
||||
"Cannot change the number of encodings with setParameters");
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
// encodings has been re-ordered.
|
||||
for (size_t i = 0; i < paramsCopy.mEncodings.Length(); ++i) {
|
||||
const auto& oldEncoding = mLastReturnedParameters->mEncodings[i];
|
||||
const auto& newEncoding = paramsCopy.mEncodings[i];
|
||||
if (oldEncoding.mRid != newEncoding.mRid) {
|
||||
p->MaybeRejectWithInvalidModificationError(
|
||||
"Cannot change rid, or reorder encodings");
|
||||
if (paramsCopy.mEncodings.Length() != oldParams->mEncodings.Length()) {
|
||||
nsCString error("Cannot change the number of encodings with setParameters");
|
||||
if (!mAllowOldSetParameters) {
|
||||
if (!mHaveFailedBecauseEncodingCountChange) {
|
||||
mHaveFailedBecauseEncodingCountChange = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::fail_length_changed
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
p->MaybeRejectWithInvalidModificationError(error);
|
||||
return p.forget();
|
||||
}
|
||||
if (!mHaveWarnedBecauseEncodingCountChange) {
|
||||
mHaveWarnedBecauseEncodingCountChange = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::warn_length_changed
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
WarnAboutBadSetParameters(error);
|
||||
} else {
|
||||
// encodings has been re-ordered.
|
||||
for (size_t i = 0; i < paramsCopy.mEncodings.Length(); ++i) {
|
||||
const auto& oldEncoding = oldParams->mEncodings[i];
|
||||
const auto& newEncoding = paramsCopy.mEncodings[i];
|
||||
if (oldEncoding.mRid != newEncoding.mRid) {
|
||||
nsCString error("Cannot change rid, or reorder encodings");
|
||||
if (!mAllowOldSetParameters) {
|
||||
if (!mHaveFailedBecauseRidChange) {
|
||||
mHaveFailedBecauseRidChange = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::fail_rid_changed
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
p->MaybeRejectWithInvalidModificationError(error);
|
||||
return p.forget();
|
||||
}
|
||||
if (!mHaveWarnedBecauseRidChange) {
|
||||
mHaveWarnedBecauseRidChange = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::warn_rid_changed
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
WarnAboutBadSetParameters(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Any parameter in parameters is marked as a Read-only parameter (such as
|
||||
// RID) and has a value that is different from the corresponding parameter
|
||||
// value in sender.[[LastReturnedParameters]]. Note that this also applies to
|
||||
// transactionId.
|
||||
if (mLastReturnedParameters->mTransactionId != paramsCopy.mTransactionId) {
|
||||
p->MaybeRejectWithInvalidModificationError(
|
||||
// TODO(bug 1803388): Handle this in webidl, once we stop allowing the old
|
||||
// setParameters style.
|
||||
if (!paramsCopy.mTransactionId.WasPassed()) {
|
||||
nsCString error("transactionId is not set!");
|
||||
if (!mAllowOldSetParameters) {
|
||||
if (!mHaveFailedBecauseNoTransactionId) {
|
||||
mHaveFailedBecauseNoTransactionId = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::fail_no_transactionid
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
p->MaybeRejectWithTypeError(error);
|
||||
return p.forget();
|
||||
}
|
||||
if (!mHaveWarnedBecauseNoTransactionId) {
|
||||
mHaveWarnedBecauseNoTransactionId = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::warn_no_transactionid
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
WarnAboutBadSetParameters(error);
|
||||
} else if (oldParams->mTransactionId != paramsCopy.mTransactionId) {
|
||||
// Any parameter in parameters is marked as a Read-only parameter (such as
|
||||
// RID) and has a value that is different from the corresponding parameter
|
||||
// value in sender.[[LastReturnedParameters]]. Note that this also applies
|
||||
// to transactionId.
|
||||
nsCString error(
|
||||
"Cannot change transaction id: call getParameters, modify the result, "
|
||||
"and then call setParameters");
|
||||
if (!mAllowOldSetParameters) {
|
||||
if (!mHaveFailedBecauseStaleTransactionId) {
|
||||
mHaveFailedBecauseStaleTransactionId = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::fail_stale_transactionid
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
p->MaybeRejectWithInvalidModificationError(error);
|
||||
return p.forget();
|
||||
}
|
||||
if (!mHaveWarnedBecauseStaleTransactionId) {
|
||||
mHaveWarnedBecauseStaleTransactionId = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::warn_stale_transactionid
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
WarnAboutBadSetParameters(error);
|
||||
}
|
||||
|
||||
// This could conceivably happen if we are allowing the old setParameters
|
||||
// behavior.
|
||||
if (!paramsCopy.mEncodings.Length()) {
|
||||
if (!mHaveFailedBecauseNoEncodings) {
|
||||
mHaveFailedBecauseNoEncodings = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::fail_no_encodings
|
||||
.AddToNumerator(1);
|
||||
}
|
||||
|
||||
p->MaybeRejectWithInvalidModificationError(
|
||||
"Cannot set an empty encodings array");
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
|
@ -512,6 +639,10 @@ already_AddRefed<Promise> RTCRtpSender::SetParameters(
|
|||
ErrorResult rv;
|
||||
CheckAndRectifyEncodings(paramsCopy.mEncodings, mTransceiver->IsVideo(), rv);
|
||||
if (rv.Failed()) {
|
||||
if (!mHaveFailedBecauseOtherError) {
|
||||
mHaveFailedBecauseOtherError = true;
|
||||
mozilla::glean::rtcrtpsender_setparameters::fail_other.AddToNumerator(1);
|
||||
}
|
||||
p->MaybeReject(std::move(rv));
|
||||
return p.forget();
|
||||
}
|
||||
|
@ -541,6 +672,10 @@ already_AddRefed<Promise> RTCRtpSender::SetParameters(
|
|||
uint32_t serialNumber = ++mNumSetParametersCalls;
|
||||
MaybeUpdateConduit();
|
||||
|
||||
if (mAllowOldSetParameters) {
|
||||
SetJsepRids(paramsCopy);
|
||||
}
|
||||
|
||||
// If the media stack is successfully configured with parameters,
|
||||
// queue a task to run the following steps:
|
||||
GetMainThreadEventTarget()->Dispatch(NS_NewRunnableFunction(
|
||||
|
@ -676,7 +811,7 @@ void RTCRtpSender::GetParameters(RTCRtpSendParameters& aParameters) {
|
|||
// Let result be a new RTCRtpSendParameters dictionary constructed as follows:
|
||||
|
||||
// transactionId is set to a new unique identifier
|
||||
aParameters.mTransactionId = mPc->GenerateUUID();
|
||||
aParameters.mTransactionId.Construct(mPc->GenerateUUID());
|
||||
|
||||
// encodings is set to the value of the [[SendEncodings]] internal slot.
|
||||
aParameters.mEncodings = mParameters.mEncodings;
|
||||
|
@ -693,9 +828,11 @@ void RTCRtpSender::GetParameters(RTCRtpSendParameters& aParameters) {
|
|||
// rtcp.reducedSize is set to true if reduced-size RTCP has been negotiated
|
||||
// for sending, and false otherwise.
|
||||
// TODO(bug 1765852): We do not support this yet
|
||||
// aParameters.mRtcp.Construct();
|
||||
aParameters.mRtcp.mCname.Construct();
|
||||
aParameters.mRtcp.mReducedSize.Construct(false);
|
||||
aParameters.mRtcp.Construct();
|
||||
aParameters.mRtcp.Value().mCname.Construct();
|
||||
aParameters.mRtcp.Value().mReducedSize.Construct(false);
|
||||
aParameters.mHeaderExtensions.Construct();
|
||||
aParameters.mCodecs.Construct();
|
||||
|
||||
// Set sender.[[LastReturnedParameters]] to result.
|
||||
mLastReturnedParameters = Some(aParameters);
|
||||
|
@ -786,8 +923,7 @@ Sequence<RTCRtpEncodingParameters> RTCRtpSender::ToSendEncodings(
|
|||
|
||||
void RTCRtpSender::MaybeGetJsepRids() {
|
||||
MOZ_ASSERT(!mSimulcastEnvelopeSet);
|
||||
MOZ_ASSERT(mParameters.mEncodings.Length() == 1);
|
||||
MOZ_ASSERT(!mParameters.mEncodings[0].mRid.WasPassed());
|
||||
MOZ_ASSERT(mParameters.mEncodings.Length());
|
||||
|
||||
auto jsepRids = GetJsepTransceiver().mSendTrack.GetRids();
|
||||
if (!jsepRids.empty()) {
|
||||
|
@ -796,7 +932,6 @@ void RTCRtpSender::MaybeGetJsepRids() {
|
|||
// JSEP is using at least one rid. Stomp our single ridless encoding
|
||||
mParameters.mEncodings = ToSendEncodings(jsepRids);
|
||||
}
|
||||
GetJsepTransceiver().mSendTrack.SetMaxEncodings(jsepRids.size());
|
||||
mSimulcastEnvelopeSet = true;
|
||||
}
|
||||
}
|
||||
|
@ -805,7 +940,27 @@ Sequence<RTCRtpEncodingParameters> RTCRtpSender::GetMatchingEncodings(
|
|||
const std::vector<std::string>& aRids) const {
|
||||
Sequence<RTCRtpEncodingParameters> result;
|
||||
|
||||
if (aRids.empty() || (aRids.size() == 1 && aRids[0].empty())) {
|
||||
if (!aRids.empty() && !aRids[0].empty()) {
|
||||
// Simulcast, or unicast with rid
|
||||
for (const auto& encoding : mParameters.mEncodings) {
|
||||
for (const auto& rid : aRids) {
|
||||
auto utf16Rid = NS_ConvertUTF8toUTF16(rid.c_str());
|
||||
if (!encoding.mRid.WasPassed() || (utf16Rid == encoding.mRid.Value())) {
|
||||
auto encodingCopy(encoding);
|
||||
if (!encodingCopy.mRid.WasPassed()) {
|
||||
encodingCopy.mRid.Construct(NS_ConvertUTF8toUTF16(rid.c_str()));
|
||||
}
|
||||
Unused << result.AppendElement(encodingCopy, fallible);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're allowing the old setParameters behavior, we _might_ be able to
|
||||
// get into this situation even if there were rids above. Be extra careful.
|
||||
// Under normal circumstances, this just handles the ridless case.
|
||||
if (!result.Length()) {
|
||||
// Unicast with no specified rid. Restore mUnicastEncoding, if
|
||||
// it exists, otherwise pick the first encoding.
|
||||
if (mUnicastEncoding.isSome()) {
|
||||
|
@ -813,22 +968,6 @@ Sequence<RTCRtpEncodingParameters> RTCRtpSender::GetMatchingEncodings(
|
|||
} else {
|
||||
Unused << result.AppendElement(mParameters.mEncodings[0], fallible);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const auto& encoding : mParameters.mEncodings) {
|
||||
for (const auto& rid : aRids) {
|
||||
MOZ_ASSERT(!rid.empty());
|
||||
auto utf16Rid = NS_ConvertUTF8toUTF16(rid.c_str());
|
||||
if (!encoding.mRid.WasPassed() || (utf16Rid == encoding.mRid.Value())) {
|
||||
auto encodingCopy(encoding);
|
||||
if (!encodingCopy.mRid.WasPassed()) {
|
||||
encodingCopy.mRid.Construct(NS_ConvertUTF8toUTF16(rid.c_str()));
|
||||
}
|
||||
Unused << result.AppendElement(encodingCopy, fallible);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -147,6 +147,8 @@ class RTCRtpSender : public nsISupports, public nsWrapperCache {
|
|||
const std::vector<std::string>& aRids) const;
|
||||
void MaybeGetJsepRids();
|
||||
|
||||
void WarnAboutBadSetParameters(const nsCString& aError);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
RefPtr<PeerConnectionImpl> mPc;
|
||||
RefPtr<dom::MediaStreamTrack> mSenderTrack;
|
||||
|
@ -163,6 +165,23 @@ class RTCRtpSender : public nsISupports, public nsWrapperCache {
|
|||
RefPtr<RTCRtpTransceiver> mTransceiver;
|
||||
nsTArray<RefPtr<DOMMediaStream>> mStreams;
|
||||
bool mHaveSetupTransport = false;
|
||||
// TODO(bug 1803388): Remove this stuff once it is no longer needed.
|
||||
bool mAllowOldSetParameters = false;
|
||||
|
||||
// TODO(bug 1803388): Remove the glean warnings once they are no longer needed
|
||||
bool mHaveWarnedBecauseNoGetParameters = false;
|
||||
bool mHaveWarnedBecauseEncodingCountChange = false;
|
||||
bool mHaveWarnedBecauseRidChange = false;
|
||||
bool mHaveWarnedBecauseNoTransactionId = false;
|
||||
bool mHaveWarnedBecauseStaleTransactionId = false;
|
||||
// TODO(bug 1803389): Remove the glean errors once they are no longer needed.
|
||||
bool mHaveFailedBecauseNoGetParameters = false;
|
||||
bool mHaveFailedBecauseEncodingCountChange = false;
|
||||
bool mHaveFailedBecauseRidChange = false;
|
||||
bool mHaveFailedBecauseNoTransactionId = false;
|
||||
bool mHaveFailedBecauseStaleTransactionId = false;
|
||||
bool mHaveFailedBecauseNoEncodings = false;
|
||||
bool mHaveFailedBecauseOtherError = false;
|
||||
|
||||
RefPtr<dom::RTCDTMFSender> mDtmf;
|
||||
|
||||
|
|
|
@ -109,8 +109,9 @@ void JsepTrack::AddToAnswer(const SdpMediaSection& offer,
|
|||
|
||||
void JsepTrack::SetRids(const std::vector<std::string>& aRids) {
|
||||
MOZ_ASSERT(!aRids.empty());
|
||||
MOZ_ASSERT(mRids.empty());
|
||||
MOZ_ASSERT(aRids.size() <= mMaxEncodings);
|
||||
if (!mRids.empty()) {
|
||||
return;
|
||||
}
|
||||
mRids = aRids;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
# 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/.
|
||||
|
||||
# Adding a new metric? We have docs for that!
|
||||
# https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/new_definitions_file.html
|
||||
|
||||
---
|
||||
$schema: moz://mozilla.org/schemas/glean/metrics/2-0-0
|
||||
$tags:
|
||||
- 'Core :: WebRTC'
|
||||
|
||||
rtcrtpsender:
|
||||
count:
|
||||
type: counter
|
||||
description: >
|
||||
The number of RTCRtpSenders created.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
count_setparameters_compat:
|
||||
type: counter
|
||||
description: >
|
||||
The number of RTCRtpSenders created that use the compatibility mode for
|
||||
setParameters.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
used_sendencodings:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders that were created by an addTransceivers
|
||||
call that was passed a sendEncodings.
|
||||
denominator_metric: rtcrtpsender.count
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
rtcrtpsender.setparameters:
|
||||
warn_no_getparameters:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders configured with the setParameters compat
|
||||
mode that have warned at least once about a setParameters call because
|
||||
[[LastReturnedParameters]] was not set. (ie; there was not a recent
|
||||
enough call to getParameters)
|
||||
denominator_metric: rtcrtpsender.count_setparameters_compat
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
warn_length_changed:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders configured with the setParameters compat
|
||||
mode that have warned at least once about a setParameters call that
|
||||
attempted to change the number of encodings.
|
||||
denominator_metric: rtcrtpsender.count_setparameters_compat
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
warn_rid_changed:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders configured with the setParameters compat
|
||||
mode that have warned at least once about a setParameters call that
|
||||
attempted to change the rid on an encoding (note that we only check this
|
||||
if the encoding count did not change, see warn_length_changed).
|
||||
denominator_metric: rtcrtpsender.count_setparameters_compat
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
warn_no_transactionid:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders configured with the setParameters compat
|
||||
mode that have warned at least once about a setParameters call that did
|
||||
not set the transactionId field.
|
||||
denominator_metric: rtcrtpsender.count_setparameters_compat
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
warn_stale_transactionid:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders configured with the setParameters compat
|
||||
mode that have warned at least once about a setParameters call that used
|
||||
a stale transaction id.
|
||||
denominator_metric: rtcrtpsender.count_setparameters_compat
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
fail_length_changed:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders that have thrown an error at least once
|
||||
about a setParameters call that attempted to change the number of
|
||||
encodings.
|
||||
denominator_metric: rtcrtpsender.count
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
fail_rid_changed:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders that have thrown an error at least once
|
||||
about a setParameters call that attempted to change the rid on an
|
||||
encoding (note that we only check this if the encoding count did not
|
||||
change, see fail_length_changed).
|
||||
denominator_metric: rtcrtpsender.count
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
fail_no_getparameters:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders that have thrown an error at least once
|
||||
about a setParameters call because [[LastReturnedParameters]] was not set.
|
||||
(ie; there was not a recent enough call to getParameters)
|
||||
denominator_metric: rtcrtpsender.count
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
fail_no_transactionid:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders that have thrown an error at least once
|
||||
about a setParameters call that did not set the transactionId field.
|
||||
denominator_metric: rtcrtpsender.count
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
fail_stale_transactionid:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders that have thrown an error at least once
|
||||
about a setParameters call that used a stale transaction id.
|
||||
denominator_metric: rtcrtpsender.count
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
fail_no_encodings:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders configured with the setParameters compat
|
||||
mode that have thrown an error at least once about a setParameters call
|
||||
that had no encodings (we do not measure this against the general
|
||||
population of RTCRtpSenders, since without the compat mode this failure
|
||||
is never observed, because it fails the length change check).
|
||||
denominator_metric: rtcrtpsender.count_setparameters_compat
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
||||
|
||||
fail_other:
|
||||
type: rate
|
||||
description: >
|
||||
The proportion of RTCRtpSenders that have thrown an error at least once
|
||||
about a setParameters call that had no encodings.
|
||||
denominator_metric: rtcrtpsender.count
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1401592
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- webrtc-telemetry-alerts@mozilla.com
|
||||
expires: 116
|
|
@ -991,6 +991,38 @@ const getTurnHostname = turnUrl => {
|
|||
return hostAndMaybePort.split(":")[0];
|
||||
};
|
||||
|
||||
// Yo dawg I heard you like Proxies
|
||||
// Example: let value = await GleanTest.category.metric.testGetValue();
|
||||
const GleanTest = new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, categoryName, receiver) {
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, metricName, receiver) {
|
||||
return {
|
||||
// The only API we actually implement right now.
|
||||
async testGetValue() {
|
||||
return SpecialPowers.spawnChrome(
|
||||
[categoryName, metricName],
|
||||
async (categoryName, metricName) => {
|
||||
await Services.fog.testFlushAllChildren();
|
||||
const window = this.browsingContext.topChromeWindow;
|
||||
return window.Glean[categoryName][
|
||||
metricName
|
||||
].testGetValue();
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* This class executes a series of functions in a continuous sequence.
|
||||
* Promise-bearing functions are executed after the previous promise completes.
|
||||
|
|
|
@ -280,3 +280,21 @@ scheme=http
|
|||
fail-if = 1
|
||||
[test_peerConnection_telephoneEventFirst.html]
|
||||
[test_peerConnection_rtcp_rsize.html]
|
||||
|
||||
[test_peerConnection_scaleResolution_oldSetParameters.html]
|
||||
[test_peerConnection_setParameters_maxFramerate_oldSetParameters.html]
|
||||
[test_peerConnection_setParameters_oldSetParameters.html]
|
||||
[test_peerConnection_setParameters_scaleResolutionDownBy_oldSetParameters.html]
|
||||
skip-if = (os == 'win' && processor == 'aarch64') # aarch64 due to bug 1537567
|
||||
[test_peerConnection_simulcastAnswer_lowResFirst_oldSetParameters.html]
|
||||
skip-if = toolkit == 'android' # no simulcast support on android
|
||||
[test_peerConnection_simulcastAnswer_oldSetParameters.html]
|
||||
skip-if = toolkit == 'android' # no simulcast support on android
|
||||
[test_peerConnection_simulcastOddResolution_oldSetParameters.html]
|
||||
skip-if = toolkit == 'android' # no simulcast support on android
|
||||
[test_peerConnection_simulcastOffer_lowResFirst_oldSetParameters.html]
|
||||
skip-if = toolkit == 'android' # no simulcast support on android
|
||||
[test_peerConnection_simulcastOffer_oldSetParameters.html]
|
||||
skip-if = toolkit == 'android' # no simulcast support on android
|
||||
[test_peerConnection_glean.html]
|
||||
|
||||
|
|
|
@ -0,0 +1,370 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1401592",
|
||||
title: "Test that glean is recording stats as expected",
|
||||
visible: true
|
||||
});
|
||||
|
||||
const tests = [
|
||||
async function checkRTCRtpSenderCount() {
|
||||
const pc = new RTCPeerConnection();
|
||||
const oldCount = await GleanTest.rtcrtpsender.count.testGetValue() ?? 0;
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
const countDiff = await GleanTest.rtcrtpsender.count.testGetValue() - oldCount;
|
||||
is(countDiff, 1, "Glean should have recorded the creation of a single RTCRtpSender");
|
||||
},
|
||||
|
||||
async function checkRTCRtpSenderSetParametersCompatCount() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", true]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const oldCount = await GleanTest.rtcrtpsender.countSetparametersCompat.testGetValue() ?? 0;
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
const countDiff = await GleanTest.rtcrtpsender.countSetparametersCompat.testGetValue() - oldCount;
|
||||
is(countDiff, 1, "Glean should have recorded the creation of a single RTCRtpSender that uses the setParameters compat mode");
|
||||
},
|
||||
|
||||
async function checkSendEncodings() {
|
||||
const pc = new RTCPeerConnection();
|
||||
const oldRate = await GleanTest.rtcrtpsender.usedSendencodings.testGetValue();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
const newRate = await GleanTest.rtcrtpsender.usedSendencodings.testGetValue();
|
||||
is(newRate.denominator, oldRate.denominator + 1, "Glean should have recorded the creation of a single RTCRtpSender");
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded the use of sendEncodings");
|
||||
},
|
||||
|
||||
async function checkAddTransceiverNoSendEncodings() {
|
||||
const pc = new RTCPeerConnection();
|
||||
const oldRate = await GleanTest.rtcrtpsender.usedSendencodings.testGetValue();
|
||||
const {sender} = pc.addTransceiver('video');
|
||||
const newRate = await GleanTest.rtcrtpsender.usedSendencodings.testGetValue();
|
||||
is(newRate.denominator, oldRate.denominator + 1, "Glean should have recorded the creation of a single RTCRtpSender");
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded a use of sendEncodings");
|
||||
},
|
||||
|
||||
async function checkAddTrack() {
|
||||
const pc = new RTCPeerConnection();
|
||||
const oldRate = await GleanTest.rtcrtpsender.usedSendencodings.testGetValue();
|
||||
const stream = await navigator.mediaDevices.getUserMedia({video: true});
|
||||
const sender = pc.addTrack(stream.getTracks()[0]);
|
||||
const newRate = await GleanTest.rtcrtpsender.usedSendencodings.testGetValue();
|
||||
is(newRate.denominator, oldRate.denominator + 1, "Glean should have recorded the creation of a single RTCRtpSender");
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded a use of sendEncodings");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersNoGetParametersWarning() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", true]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.warnNoGetparameters.testGetValue();
|
||||
await sender.setParameters({encodings: [{rid: "0"},{rid: "1"},{rid: "2"}]});
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.warnNoGetparameters.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded a warning in setParameters due to lack of a getParameters call");
|
||||
|
||||
// Glean should only record the warning once per sender!
|
||||
oldRate = newRate;
|
||||
await sender.setParameters({encodings: [{rid: "0"},{rid: "1"},{rid: "2"}]});
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.warnNoGetparameters.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another warning in setParameters due to lack of a getParameters call");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersLengthChangedWarning() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", true]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.warnLengthChanged.testGetValue();
|
||||
let params = sender.getParameters();
|
||||
params.encodings.pop();
|
||||
await sender.setParameters(params);
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.warnLengthChanged.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded a warning due to a length change in encodings");
|
||||
|
||||
// Glean should only record the warning once per sender!
|
||||
params = sender.getParameters();
|
||||
params.encodings.pop();
|
||||
oldRate = newRate;
|
||||
await sender.setParameters(params);
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.warnLengthChanged.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another warning due to a length change in encodings");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersRidChangedWarning() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", true]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.warnRidChanged.testGetValue();
|
||||
let params = sender.getParameters();
|
||||
params.encodings[1].rid = "foo";
|
||||
await sender.setParameters(params);
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.warnRidChanged.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded a warning due to a rid change in encodings");
|
||||
|
||||
// Glean should only record the warning once per sender!
|
||||
params = sender.getParameters();
|
||||
params.encodings[1].rid = "bar";
|
||||
oldRate = newRate;
|
||||
await sender.setParameters(params);
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.warnRidChanged.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another warning due to a rid change in encodings");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersNoTransactionIdWarning() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", true]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.warnNoTransactionid.testGetValue();
|
||||
await sender.setParameters({encodings: [{rid: "0"},{rid: "1"},{rid: "2"}]});
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.warnNoTransactionid.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded a warning due to missing transactionId in setParameters");
|
||||
|
||||
// Glean should only record the warning once per sender!
|
||||
oldRate = newRate;
|
||||
await sender.setParameters({encodings: [{rid: "0"},{rid: "1"},{rid: "2"}]});
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.warnNoTransactionid.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another warning due to missing transactionId in setParameters");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersStaleTransactionIdWarning() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", true]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.warnStaleTransactionid.testGetValue();
|
||||
let params = sender.getParameters();
|
||||
// Cause transactionId to be stale
|
||||
await pc.createOffer();
|
||||
// ...but make sure there is a recent getParameters call
|
||||
sender.getParameters();
|
||||
await sender.setParameters(params);
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.warnStaleTransactionid.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded a warning due to stale transactionId in setParameters");
|
||||
|
||||
// Glean should only record the warning once per sender!
|
||||
oldRate = newRate;
|
||||
params = sender.getParameters();
|
||||
// Cause transactionId to be stale
|
||||
await pc.createOffer();
|
||||
// ...but make sure there is a recent getParameters call
|
||||
sender.getParameters();
|
||||
await sender.setParameters(params);
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.warnStaleTransactionid.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another warning due to stale transactionId in setParameters");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersLengthChangedError() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", false]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.failLengthChanged.testGetValue();
|
||||
let params = sender.getParameters();
|
||||
params.encodings.pop();
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch(e) {
|
||||
}
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.failLengthChanged.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded an error due to a length change in encodings");
|
||||
|
||||
// Glean should only record the error once per sender!
|
||||
params = sender.getParameters();
|
||||
params.encodings.pop();
|
||||
oldRate = newRate;
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.failLengthChanged.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another error due to a length change in encodings");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersRidChangedError() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", false]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.failRidChanged.testGetValue();
|
||||
let params = sender.getParameters();
|
||||
params.encodings[1].rid = "foo";
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.failRidChanged.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded an error due to a rid change in encodings");
|
||||
|
||||
// Glean should only record the error once per sender!
|
||||
params = sender.getParameters();
|
||||
params.encodings[1].rid = "bar";
|
||||
oldRate = newRate;
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.failRidChanged.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another error due to a rid change in encodings");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersNoGetParametersError() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", false]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.failNoGetparameters.testGetValue();
|
||||
try {
|
||||
await sender.setParameters({encodings: [{rid: "0"},{rid: "1"},{rid: "2"}]});
|
||||
} catch (e) {
|
||||
}
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.failNoGetparameters.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded an error in setParameters due to lack of a getParameters call");
|
||||
|
||||
// Glean should only record the error once per sender!
|
||||
oldRate = newRate;
|
||||
try {
|
||||
await sender.setParameters({encodings: [{rid: "0"},{rid: "1"},{rid: "2"}]});
|
||||
} catch (e) {
|
||||
}
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.failNoGetparameters.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another error in setParameters due to lack of a getParameters call");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersStaleTransactionIdError() {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", false]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.failStaleTransactionid.testGetValue();
|
||||
let params = sender.getParameters();
|
||||
// Cause transactionId to be stale
|
||||
await pc.createOffer();
|
||||
// ...but make sure there is a recent getParameters call
|
||||
sender.getParameters();
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.failStaleTransactionid.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded an error due to stale transactionId in setParameters");
|
||||
|
||||
// Glean should only record the error once per sender!
|
||||
oldRate = newRate;
|
||||
params = sender.getParameters();
|
||||
// Cause transactionId to be stale
|
||||
await pc.createOffer();
|
||||
// ...but make sure there is a recent getParameters call
|
||||
sender.getParameters();
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.failStaleTransactionid.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another error due to stale transactionId in setParameters");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersNoEncodingsError() {
|
||||
// If we do not allow the old setParameters, this will fail the length check
|
||||
// instead.
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", true]);
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.failNoEncodings.testGetValue();
|
||||
let params = sender.getParameters();
|
||||
params.encodings = [];
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.failNoEncodings.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded an error due to stale transactionId in setParameters");
|
||||
|
||||
// Glean should only record the error once per sender!
|
||||
oldRate = newRate;
|
||||
params = sender.getParameters();
|
||||
params.encodings = [];
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.failNoEncodings.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another error due to stale transactionId in setParameters");
|
||||
},
|
||||
|
||||
async function checkBadSetParametersOtherError() {
|
||||
const pc = new RTCPeerConnection();
|
||||
const {sender} = pc.addTransceiver('video', {
|
||||
sendEncodings: [{rid: "0"},{rid: "1"},{rid: "2"}]
|
||||
});
|
||||
let oldRate = await GleanTest.rtcrtpsenderSetparameters.failOther.testGetValue();
|
||||
let params = sender.getParameters();
|
||||
params.encodings[0].scaleResolutionDownBy = 0.5;
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
let newRate = await GleanTest.rtcrtpsenderSetparameters.failOther.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator + 1, "Glean should have recorded an error due to some other failure");
|
||||
|
||||
// Glean should only record the error once per sender!
|
||||
oldRate = newRate;
|
||||
params = sender.getParameters();
|
||||
params.encodings[0].scaleResolutionDownBy = 0.5;
|
||||
try {
|
||||
await sender.setParameters(params);
|
||||
} catch (e) {
|
||||
}
|
||||
newRate = await GleanTest.rtcrtpsenderSetparameters.failOther.testGetValue();
|
||||
is(newRate.numerator, oldRate.numerator, "Glean should not have recorded another error due to some other failure");
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
runNetworkTest(async () => {
|
||||
for (const test of tests) {
|
||||
info(`Running test: ${test.name}`);
|
||||
await test();
|
||||
info(`Done running test: ${test.name}`);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,101 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1244913",
|
||||
title: "Scale resolution down on a PeerConnection",
|
||||
visible: true
|
||||
});
|
||||
|
||||
var mustRejectWith = (msg, reason, f) =>
|
||||
f().then(() => ok(false, msg),
|
||||
e => is(e.name, reason, msg));
|
||||
|
||||
async function testScale(codec) {
|
||||
var pc1 = new RTCPeerConnection();
|
||||
var pc2 = new RTCPeerConnection();
|
||||
|
||||
var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
|
||||
pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback());
|
||||
pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback());
|
||||
|
||||
info("testing scaling with " + codec);
|
||||
|
||||
let stream = await navigator.mediaDevices.getUserMedia({ video: true });
|
||||
|
||||
var v1 = createMediaElement('video', 'v1');
|
||||
var v2 = createMediaElement('video', 'v2');
|
||||
|
||||
var ontrackfired = new Promise(resolve => pc2.ontrack = e => resolve(e));
|
||||
var v2loadedmetadata = new Promise(resolve => v2.onloadedmetadata = resolve);
|
||||
|
||||
is(v2.currentTime, 0, "v2.currentTime is zero at outset");
|
||||
|
||||
v1.srcObject = stream;
|
||||
var sender = pc1.addTrack(stream.getVideoTracks()[0], stream);
|
||||
|
||||
const otherErrorStart = await GleanTest.rtcrtpsenderSetparameters.failOther.testGetValue();
|
||||
const noTransactionIdWarningStart = await GleanTest.rtcrtpsenderSetparameters.warnNoTransactionid.testGetValue();
|
||||
|
||||
await mustRejectWith(
|
||||
"Invalid scaleResolutionDownBy must reject", "RangeError",
|
||||
() => sender.setParameters(
|
||||
{ encodings:[{ scaleResolutionDownBy: 0.5 } ] })
|
||||
);
|
||||
|
||||
const otherErrorEnd = await GleanTest.rtcrtpsenderSetparameters.failOther.testGetValue();
|
||||
const noTransactionIdWarningEnd = await GleanTest.rtcrtpsenderSetparameters.warnNoTransactionid.testGetValue();
|
||||
|
||||
// Make sure Glean is recording these statistics
|
||||
is(otherErrorEnd.denominator, otherErrorStart.denominator, "No new RTCRtpSenders were created during this time");
|
||||
is(otherErrorEnd.numerator, otherErrorStart.numerator + 1, "RTCRtpSender.setParameters reported a failure via Glean");
|
||||
is(noTransactionIdWarningEnd.denominator, noTransactionIdWarningStart.denominator, "No new RTCRtpSenders were created during this time");
|
||||
is(noTransactionIdWarningEnd.numerator, noTransactionIdWarningStart.numerator + 1, "Glean should have recorded a warning due to missing transactionId");
|
||||
|
||||
await sender.setParameters({ encodings: [{ maxBitrate: 60000,
|
||||
scaleResolutionDownBy: 2 }] });
|
||||
|
||||
let offer = await pc1.createOffer();
|
||||
if (codec == "VP8") {
|
||||
offer.sdp = sdputils.removeAllButPayloadType(offer.sdp, 126);
|
||||
}
|
||||
await pc1.setLocalDescription(offer);
|
||||
await pc2.setRemoteDescription(pc1.localDescription);
|
||||
|
||||
let answer = await pc2.createAnswer();
|
||||
await pc2.setLocalDescription(answer);
|
||||
await pc1.setRemoteDescription(pc2.localDescription);
|
||||
let trackevent = await ontrackfired;
|
||||
|
||||
v2.srcObject = trackevent.streams[0];
|
||||
|
||||
await v2loadedmetadata;
|
||||
|
||||
await waitUntil(() => v2.currentTime > 0);
|
||||
ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")");
|
||||
|
||||
ok(v1.videoWidth > 0, "source width is positive");
|
||||
ok(v1.videoHeight > 0, "source height is positive");
|
||||
is(v2.videoWidth, v1.videoWidth / 2, "sink is half the width of source");
|
||||
is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source");
|
||||
stream.getTracks().forEach(track => track.stop());
|
||||
v1.srcObject = v2.srcObject = null;
|
||||
pc1.close()
|
||||
pc2.close()
|
||||
}
|
||||
|
||||
runNetworkTest(async () => {
|
||||
await matchPlatformH264CodecPrefs();
|
||||
await pushPrefs(['media.peerconnection.video.lock_scaling', true]);
|
||||
await testScale("VP8");
|
||||
await testScale("H264");
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -157,6 +157,8 @@ const tests = [
|
|||
];
|
||||
|
||||
runNetworkTest(async () => {
|
||||
await pushPrefs(
|
||||
["media.peerconnection.allow_old_setParameters", false]);
|
||||
for (const test of tests) {
|
||||
info(`Running test: ${test.name}`);
|
||||
await test();
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1611957",
|
||||
title: "Live-updating maxFramerate"
|
||||
});
|
||||
|
||||
let sender, receiver;
|
||||
|
||||
async function checkMaxFrameRate(rate) {
|
||||
sender.setParameters({ encodings: [{ maxFramerate: rate }] });
|
||||
await wait(2000);
|
||||
const stats = Array.from((await receiver.getStats()).values());
|
||||
const inboundRtp = stats.find(stat => stat.type == "inbound-rtp");
|
||||
info(`inbound-rtp stats: ${JSON.stringify(inboundRtp)}`);
|
||||
const fps = inboundRtp.framesPerSecond;
|
||||
ok(fps <= (rate * 1.1) + 1, `fps is an appropriate value (${fps}) for rate (${rate})`);
|
||||
}
|
||||
|
||||
runNetworkTest(async function (options) {
|
||||
let test = new PeerConnectionTest(options);
|
||||
test.setMediaConstraints([{video: true}], []);
|
||||
test.chain.append([
|
||||
function CHECK_PRECONDITIONS() {
|
||||
is(test.pcLocal._pc.getSenders().length, 1,
|
||||
"Should have 1 local sender");
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"Should have 1 remote receiver");
|
||||
|
||||
sender = test.pcLocal._pc.getSenders()[0];
|
||||
receiver = test.pcRemote._pc.getReceivers()[0];
|
||||
},
|
||||
function PC_LOCAL_SET_MAX_FRAMERATE_2() {
|
||||
return checkMaxFrameRate(2);
|
||||
},
|
||||
function PC_LOCAL_SET_MAX_FRAMERATE_4() {
|
||||
return checkMaxFrameRate(4);
|
||||
},
|
||||
function PC_LOCAL_SET_MAX_FRAMERATE_15() {
|
||||
return checkMaxFrameRate(15);
|
||||
},
|
||||
function PC_LOCAL_SET_MAX_FRAMERATE_8() {
|
||||
return checkMaxFrameRate(8);
|
||||
},
|
||||
function PC_LOCAL_SET_MAX_FRAMERATE_1() {
|
||||
return checkMaxFrameRate(1);
|
||||
},
|
||||
]);
|
||||
await test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,86 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1230184",
|
||||
title: "Set parameters on sender",
|
||||
visible: true
|
||||
});
|
||||
|
||||
function parameterstest(pc) {
|
||||
ok(pc.getSenders().length, "have senders");
|
||||
var sender = pc.getSenders()[0];
|
||||
|
||||
var testParameters = (params, errorName, errorMsg) => {
|
||||
info("Trying to set " + JSON.stringify(params));
|
||||
|
||||
var validateParameters = (a, b) => {
|
||||
var validateEncoding = (a, b) => {
|
||||
is(a.rid, b.rid, "same rid");
|
||||
is(a.maxBitrate, b.maxBitrate, "same maxBitrate");
|
||||
is(a.maxFramerate, b.maxFramerate, "same maxFramerate");
|
||||
is(a.scaleResolutionDownBy, b.scaleResolutionDownBy,
|
||||
"same scaleResolutionDownBy");
|
||||
};
|
||||
is(a.encodings.length, (b.encodings || []).length, "same encodings");
|
||||
a.encodings.forEach((en, i) => validateEncoding(en, b.encodings[i]));
|
||||
};
|
||||
|
||||
var before = JSON.stringify(sender.getParameters());
|
||||
isnot(JSON.stringify(params), before, "starting condition");
|
||||
|
||||
var p = sender.setParameters(params)
|
||||
.then(() => {
|
||||
isnot(JSON.stringify(sender.getParameters()), before, "parameters changed");
|
||||
validateParameters(sender.getParameters(), params);
|
||||
is(null, errorName || null, "is success expected");
|
||||
}, e => {
|
||||
is(e.name, errorName, "correct error name");
|
||||
is(e.message, errorMsg, "correct error message");
|
||||
});
|
||||
is(JSON.stringify(sender.getParameters()), before, "parameters not set yet");
|
||||
return p;
|
||||
};
|
||||
|
||||
return [
|
||||
[{ encodings: [ { rid: "foo", maxBitrate: 40000, scaleResolutionDownBy: 2 },
|
||||
{ rid: "bar", maxBitrate: 10000, scaleResolutionDownBy: 4 }]
|
||||
}],
|
||||
[{ encodings: [{ maxBitrate: 10000, scaleResolutionDownBy: 4 }]}],
|
||||
[{ encodings: [{ maxFramerate: 0.0, scaleResolutionDownBy: 1 }]}],
|
||||
[{ encodings: [{ maxFramerate: 30.5, scaleResolutionDownBy: 1 }]}],
|
||||
[{ encodings: [{ maxFramerate: -1, scaleResolutionDownBy: 1 }]}, "RangeError", "maxFramerate must be non-negative"],
|
||||
[{ encodings: [{ maxBitrate: 40000 },
|
||||
{ rid: "bar", maxBitrate: 10000 }] }, "TypeError", "Missing rid"],
|
||||
[{ encodings: [{ rid: "foo", maxBitrate: 40000 },
|
||||
{ rid: "bar", maxBitrate: 10000 },
|
||||
{ rid: "bar", maxBitrate: 20000 }] }, "TypeError", "Duplicate rid"],
|
||||
[{}, "TypeError", `RTCRtpSender.setParameters: Missing required 'encodings' member of RTCRtpSendParameters.`]
|
||||
].reduce((p, args) => p.then(() => testParameters.apply(this, args)),
|
||||
Promise.resolve());
|
||||
}
|
||||
|
||||
runNetworkTest(() => {
|
||||
const test = new PeerConnectionTest();
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.chain.removeAfter("PC_REMOTE_WAIT_FOR_MEDIA_FLOW");
|
||||
|
||||
// Test sender parameters.
|
||||
test.chain.append([
|
||||
function PC_LOCAL_SET_PARAMETERS(test) {
|
||||
return parameterstest(test.pcLocal._pc);
|
||||
}
|
||||
]);
|
||||
|
||||
return test.run();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1253499",
|
||||
title: "Live-updating scaleResolutionDownBy"
|
||||
});
|
||||
|
||||
let sender, localElem, remoteElem;
|
||||
let originalWidth, originalHeight;
|
||||
|
||||
async function checkScaleDownBy(scale) {
|
||||
sender.setParameters({ encodings: [{ scaleResolutionDownBy: scale }] });
|
||||
await haveEvent(remoteElem, "resize", wait(5000, new Error("Timeout")));
|
||||
|
||||
// Find the expected resolution. Internally we pick the closest lower
|
||||
// resolution with an identical aspect ratio.
|
||||
let expectedWidth = Math.floor(originalWidth / scale);
|
||||
let expectedHeight = Math.floor(originalHeight / scale);
|
||||
|
||||
is(remoteElem.videoWidth, expectedWidth,
|
||||
`Width should have scaled down by ${scale}`);
|
||||
is(remoteElem.videoHeight, expectedHeight,
|
||||
`Height should have scaled down by ${scale}`);
|
||||
}
|
||||
|
||||
runNetworkTest(async function (options) {
|
||||
await pushPrefs(['media.peerconnection.video.lock_scaling', true]);
|
||||
// [TODO] re-enable HW decoder after bug 1526207 is fixed.
|
||||
if (navigator.userAgent.includes("Android")) {
|
||||
await pushPrefs(["media.navigator.mediadatadecoder_vpx_enabled", false],
|
||||
["media.webrtc.hw.h264.enabled", false]);
|
||||
}
|
||||
|
||||
let test = new PeerConnectionTest(options);
|
||||
test.setMediaConstraints([{video: true}], []);
|
||||
test.chain.append([
|
||||
function CHECK_PRECONDITIONS() {
|
||||
is(test.pcLocal._pc.getSenders().length, 1,
|
||||
"Should have 1 local sender");
|
||||
is(test.pcLocal.localMediaElements.length, 1,
|
||||
"Should have 1 local sending media element");
|
||||
is(test.pcRemote.remoteMediaElements.length, 1,
|
||||
"Should have 1 remote media element");
|
||||
|
||||
sender = test.pcLocal._pc.getSenders()[0];
|
||||
localElem = test.pcLocal.localMediaElements[0];
|
||||
remoteElem = test.pcRemote.remoteMediaElements[0];
|
||||
|
||||
remoteElem.addEventListener("resize", () =>
|
||||
info(`Video resized to ${remoteElem.videoWidth}x${remoteElem.videoHeight}`));
|
||||
|
||||
originalWidth = localElem.videoWidth;
|
||||
originalHeight = localElem.videoHeight;
|
||||
info(`Original width is ${originalWidth}`);
|
||||
},
|
||||
function PC_LOCAL_SCALEDOWNBY_2() {
|
||||
return checkScaleDownBy(2);
|
||||
},
|
||||
function PC_LOCAL_SCALEDOWNBY_4() {
|
||||
return checkScaleDownBy(4);
|
||||
},
|
||||
function PC_LOCAL_SCALEDOWNBY_15() {
|
||||
return checkScaleDownBy(15);
|
||||
},
|
||||
function PC_LOCAL_SCALEDOWNBY_8() {
|
||||
return checkScaleDownBy(8);
|
||||
},
|
||||
function PC_LOCAL_SCALEDOWNBY_1() {
|
||||
return checkScaleDownBy(1);
|
||||
},
|
||||
]);
|
||||
await test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,115 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
<script type="application/javascript" src="helpers_from_wpt/sdp.js"></script>
|
||||
<script type="application/javascript" src="simulcast.js"></script>
|
||||
<script type="application/javascript" src="stats.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1231507",
|
||||
title: "Basic video-only peer connection with Simulcast answer, first rid has lowest resolution",
|
||||
visible: true
|
||||
});
|
||||
|
||||
runNetworkTest(async () => {
|
||||
await pushPrefs(
|
||||
['media.peerconnection.simulcast', true],
|
||||
// 180Kbps was determined empirically, set well-higher than
|
||||
// the 80Kbps+overhead needed for the two simulcast streams.
|
||||
// 100Kbps was apparently too low.
|
||||
['media.peerconnection.video.min_bitrate_estimate', 180*1000]);
|
||||
|
||||
|
||||
const offerer = new RTCPeerConnection();
|
||||
const answerer = new RTCPeerConnection();
|
||||
|
||||
const add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
|
||||
offerer.onicecandidate = e => add(answerer, e.candidate, generateErrorCallback());
|
||||
answerer.onicecandidate = e => add(offerer, e.candidate, generateErrorCallback());
|
||||
|
||||
const metadataToBeLoaded = [];
|
||||
offerer.ontrack = (e) => {
|
||||
metadataToBeLoaded.push(getPlaybackWithLoadedMetadata(e.track));
|
||||
};
|
||||
|
||||
// Two recv transceivers, one for each simulcast stream
|
||||
offerer.addTransceiver('video', { direction: 'recvonly' });
|
||||
offerer.addTransceiver('video', { direction: 'recvonly' });
|
||||
|
||||
// One send transceiver, that will be used to send both simulcast streams
|
||||
const emitter = new VideoFrameEmitter();
|
||||
const videoStream = emitter.stream();
|
||||
answerer.addTrack(videoStream.getVideoTracks()[0], videoStream);
|
||||
emitter.start();
|
||||
|
||||
const offer = await offerer.createOffer();
|
||||
|
||||
const mungedOffer = midToRid(offer);
|
||||
info(`Transformed recv offer to simulcast: ${offer.sdp} to ${mungedOffer}`);
|
||||
|
||||
await answerer.setRemoteDescription({type: "offer", sdp: mungedOffer});
|
||||
await offerer.setLocalDescription(offer);
|
||||
|
||||
const rids = offerer.getTransceivers().map(t => t.mid);
|
||||
is(rids.length, 2, 'Should have 2 mids in offer');
|
||||
ok(rids[0] != '', 'First mid should be non-empty');
|
||||
ok(rids[1] != '', 'Second mid should be non-empty');
|
||||
info(`rids: ${JSON.stringify(rids)}`);
|
||||
|
||||
const sender = answerer.getSenders()[0];
|
||||
sender.setParameters({
|
||||
encodings: [
|
||||
{ rid: rids[0], maxBitrate: 40000, scaleResolutionDownBy: 2 },
|
||||
{ rid: rids[1], maxBitrate: 40000 }
|
||||
]
|
||||
});
|
||||
|
||||
const answer = await answerer.createAnswer();
|
||||
|
||||
const mungedAnswer = ridToMid(answer);
|
||||
info(`Transformed send simulcast answer to multiple m-sections: ${answer.sdp} to ${mungedAnswer}`);
|
||||
await offerer.setRemoteDescription({type: "answer", sdp: mungedAnswer});
|
||||
await answerer.setLocalDescription(answer);
|
||||
|
||||
is(metadataToBeLoaded.length, 2, 'Offerer should have gotten 2 ontrack events');
|
||||
info('Waiting for 2 loadedmetadata events');
|
||||
const videoElems = await Promise.all(metadataToBeLoaded);
|
||||
|
||||
const statsReady =
|
||||
Promise.all([waitForSyncedRtcp(offerer), waitForSyncedRtcp(answerer)]);
|
||||
|
||||
const helper = new VideoStreamHelper();
|
||||
info('Waiting for first video element to start playing');
|
||||
await helper.checkVideoPlaying(videoElems[0]);
|
||||
info('Waiting for second video element to start playing');
|
||||
await helper.checkVideoPlaying(videoElems[1]);
|
||||
|
||||
is(videoElems[1].videoWidth, 50,
|
||||
"sink is same width as source, modulo our cropping algorithm");
|
||||
is(videoElems[1].videoHeight, 50,
|
||||
"sink is same height as source, modulo our cropping algorithm");
|
||||
is(videoElems[0].videoWidth, 25,
|
||||
"sink is 1/2 width of source, modulo our cropping algorithm");
|
||||
is(videoElems[0].videoHeight, 25,
|
||||
"sink is 1/2 height of source, modulo our cropping algorithm");
|
||||
|
||||
await statsReady;
|
||||
const senderStats = await sender.getStats();
|
||||
checkSenderStats(senderStats, 2);
|
||||
checkExpectedFields(senderStats);
|
||||
pedanticChecks(senderStats);
|
||||
|
||||
emitter.stop();
|
||||
videoStream.getVideoTracks()[0].stop();
|
||||
offerer.close();
|
||||
answerer.close();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,115 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
<script type="application/javascript" src="helpers_from_wpt/sdp.js"></script>
|
||||
<script type="application/javascript" src="simulcast.js"></script>
|
||||
<script type="application/javascript" src="stats.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1231507",
|
||||
title: "Basic video-only peer connection with Simulcast answer",
|
||||
visible: true
|
||||
});
|
||||
|
||||
runNetworkTest(async () => {
|
||||
await pushPrefs(
|
||||
['media.peerconnection.simulcast', true],
|
||||
// 180Kbps was determined empirically, set well-higher than
|
||||
// the 80Kbps+overhead needed for the two simulcast streams.
|
||||
// 100Kbps was apparently too low.
|
||||
['media.peerconnection.video.min_bitrate_estimate', 180*1000]);
|
||||
|
||||
|
||||
const offerer = new RTCPeerConnection();
|
||||
const answerer = new RTCPeerConnection();
|
||||
|
||||
const add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
|
||||
offerer.onicecandidate = e => add(answerer, e.candidate, generateErrorCallback());
|
||||
answerer.onicecandidate = e => add(offerer, e.candidate, generateErrorCallback());
|
||||
|
||||
const metadataToBeLoaded = [];
|
||||
offerer.ontrack = (e) => {
|
||||
metadataToBeLoaded.push(getPlaybackWithLoadedMetadata(e.track));
|
||||
};
|
||||
|
||||
// Two recv transceivers, one for each simulcast stream
|
||||
offerer.addTransceiver('video', { direction: 'recvonly' });
|
||||
offerer.addTransceiver('video', { direction: 'recvonly' });
|
||||
|
||||
// One send transceiver, that will be used to send both simulcast streams
|
||||
const emitter = new VideoFrameEmitter();
|
||||
const videoStream = emitter.stream();
|
||||
answerer.addTrack(videoStream.getVideoTracks()[0], videoStream);
|
||||
emitter.start();
|
||||
|
||||
const offer = await offerer.createOffer();
|
||||
|
||||
const mungedOffer = midToRid(offer);
|
||||
info(`Transformed recv offer to simulcast: ${offer.sdp} to ${mungedOffer}`);
|
||||
|
||||
await answerer.setRemoteDescription({type: "offer", sdp: mungedOffer});
|
||||
await offerer.setLocalDescription(offer);
|
||||
|
||||
const rids = offerer.getTransceivers().map(t => t.mid);
|
||||
is(rids.length, 2, 'Should have 2 mids in offer');
|
||||
ok(rids[0] != '', 'First mid should be non-empty');
|
||||
ok(rids[1] != '', 'Second mid should be non-empty');
|
||||
info(`rids: ${JSON.stringify(rids)}`);
|
||||
|
||||
const sender = answerer.getSenders()[0];
|
||||
await sender.setParameters({
|
||||
encodings: [
|
||||
{ rid: rids[0], maxBitrate: 40000 },
|
||||
{ rid: rids[1], maxBitrate: 40000, scaleResolutionDownBy: 2 }
|
||||
]
|
||||
});
|
||||
|
||||
const answer = await answerer.createAnswer();
|
||||
|
||||
const mungedAnswer = ridToMid(answer);
|
||||
info(`Transformed send simulcast answer to multiple m-sections: ${answer.sdp} to ${mungedAnswer}`);
|
||||
await offerer.setRemoteDescription({type: "answer", sdp: mungedAnswer});
|
||||
await answerer.setLocalDescription(answer);
|
||||
|
||||
is(metadataToBeLoaded.length, 2, 'Offerer should have gotten 2 ontrack events');
|
||||
info('Waiting for 2 loadedmetadata events');
|
||||
const videoElems = await Promise.all(metadataToBeLoaded);
|
||||
|
||||
const statsReady =
|
||||
Promise.all([waitForSyncedRtcp(offerer), waitForSyncedRtcp(answerer)]);
|
||||
|
||||
const helper = new VideoStreamHelper();
|
||||
info('Waiting for first video element to start playing');
|
||||
await helper.checkVideoPlaying(videoElems[0]);
|
||||
info('Waiting for second video element to start playing');
|
||||
await helper.checkVideoPlaying(videoElems[1]);
|
||||
|
||||
is(videoElems[0].videoWidth, 50,
|
||||
"sink is same width as source, modulo our cropping algorithm");
|
||||
is(videoElems[0].videoHeight, 50,
|
||||
"sink is same height as source, modulo our cropping algorithm");
|
||||
is(videoElems[1].videoWidth, 25,
|
||||
"sink is 1/2 width of source, modulo our cropping algorithm");
|
||||
is(videoElems[1].videoHeight, 25,
|
||||
"sink is 1/2 height of source, modulo our cropping algorithm");
|
||||
|
||||
await statsReady;
|
||||
const senderStats = await sender.getStats();
|
||||
checkSenderStats(senderStats, 2);
|
||||
checkExpectedFields(senderStats);
|
||||
pedanticChecks(senderStats);
|
||||
|
||||
emitter.stop();
|
||||
videoStream.getVideoTracks()[0].stop();
|
||||
offerer.close();
|
||||
answerer.close();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,172 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
<script type="application/javascript" src="helpers_from_wpt/sdp.js"></script>
|
||||
<script type="application/javascript" src="simulcast.js"></script>
|
||||
<script type="application/javascript" src="stats.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1432793",
|
||||
title: "Simulcast with odd resolution",
|
||||
visible: true
|
||||
});
|
||||
|
||||
runNetworkTest(async () => {
|
||||
const helper = new VideoStreamHelper();
|
||||
const emitter = new VideoFrameEmitter(helper.green, helper.red, 705, 528);
|
||||
|
||||
async function checkVideoElement(senderElement, receiverElement, encoding) {
|
||||
info(`Waiting for receiver video element ${encoding.rid} to start playing`);
|
||||
await helper.checkVideoPlaying(receiverElement);
|
||||
const srcWidth = senderElement.videoWidth;
|
||||
const srcHeight = senderElement.videoHeight;
|
||||
info(`Source resolution is ${srcWidth}x${srcHeight}`);
|
||||
|
||||
const scaleDownBy = encoding.scaleResolutionDownBy;
|
||||
const expectedWidth = srcWidth / scaleDownBy;
|
||||
const expectedHeight = srcHeight / scaleDownBy;
|
||||
const margin = srcWidth * 0.1;
|
||||
const width = receiverElement.videoWidth;
|
||||
const height = receiverElement.videoHeight;
|
||||
const rid = encoding.rid;
|
||||
ok(width >= expectedWidth - margin && width <= expectedWidth + margin,
|
||||
`Width ${width} should be within 10% of ${expectedWidth} for rid '${rid}'`);
|
||||
ok(height >= expectedHeight - margin && height <= expectedHeight + margin,
|
||||
`Height ${height} should be within 10% of ${expectedHeight} for rid '${rid}'`);
|
||||
}
|
||||
|
||||
async function checkVideoElements(senderElement, receiverElements, encodings) {
|
||||
is(receiverElements.length, encodings.length, 'Number of video elements should match number of encodings');
|
||||
info('Waiting for sender video element to start playing');
|
||||
await helper.checkVideoPlaying(senderElement);
|
||||
for (let i = 0; i < encodings.length; i++) {
|
||||
await checkVideoElement(senderElement, receiverElements[i], encodings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkSenderStats(sender) {
|
||||
const senderStats = await sender.getStats();
|
||||
checkSenderStats(senderStats, encodings.length);
|
||||
checkExpectedFields(senderStats);
|
||||
pedanticChecks(senderStats);
|
||||
}
|
||||
|
||||
async function waitForResizeEvents(elements) {
|
||||
return Promise.all(elements.map(elem => haveEvent(elem, 'resize')));
|
||||
}
|
||||
|
||||
const encodings = [{ rid: "0", maxBitrate: 40000, scaleResolutionDownBy: 1.9 },
|
||||
{ rid: "1", maxBitrate: 40000, scaleResolutionDownBy: 3.5 },
|
||||
{ rid: "2", maxBitrate: 40000, scaleResolutionDownBy: 17.8 }];
|
||||
|
||||
await pushPrefs(
|
||||
['media.peerconnection.simulcast', true],
|
||||
// 180Kbps was determined empirically, set well-higher than
|
||||
// the 80Kbps+overhead needed for the two simulcast streams.
|
||||
// 100Kbps was apparently too low.
|
||||
['media.peerconnection.video.min_bitrate_estimate', 180*1000]);
|
||||
|
||||
|
||||
const offerer = new RTCPeerConnection();
|
||||
const answerer = new RTCPeerConnection();
|
||||
|
||||
const add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
|
||||
offerer.onicecandidate = e => add(answerer, e.candidate, generateErrorCallback());
|
||||
answerer.onicecandidate = e => add(offerer, e.candidate, generateErrorCallback());
|
||||
|
||||
const metadataToBeLoaded = [];
|
||||
answerer.ontrack = (e) => {
|
||||
metadataToBeLoaded.push(getPlaybackWithLoadedMetadata(e.track));
|
||||
};
|
||||
|
||||
// One send transceiver, that will be used to send both simulcast streams
|
||||
const videoStream = emitter.stream();
|
||||
offerer.addTrack(videoStream.getVideoTracks()[0], videoStream);
|
||||
const senderElement = document.createElement('video');
|
||||
senderElement.autoplay = true;
|
||||
senderElement.srcObject = videoStream;
|
||||
senderElement.id = videoStream.id
|
||||
|
||||
const sender = offerer.getSenders()[0];
|
||||
sender.setParameters({encodings});
|
||||
|
||||
const offer = await offerer.createOffer();
|
||||
|
||||
const mungedOffer = ridToMid(offer);
|
||||
info(`Transformed send simulcast offer to multiple m-sections: ${offer.sdp} to ${mungedOffer}`);
|
||||
|
||||
await answerer.setRemoteDescription({type: "offer", sdp: mungedOffer});
|
||||
await offerer.setLocalDescription(offer);
|
||||
|
||||
const rids = answerer.getTransceivers().map(t => t.mid);
|
||||
is(rids.length, 3, 'Should have 3 mids in offer');
|
||||
ok(rids[0], 'First mid should be non-empty');
|
||||
ok(rids[1], 'Second mid should be non-empty');
|
||||
ok(rids[2], 'Third mid should be non-empty');
|
||||
info(`rids: ${JSON.stringify(rids)}`);
|
||||
|
||||
const answer = await answerer.createAnswer();
|
||||
|
||||
const mungedAnswer = midToRid(answer);
|
||||
info(`Transformed recv answer to simulcast: ${answer.sdp} to ${mungedAnswer}`);
|
||||
await offerer.setRemoteDescription({type: "answer", sdp: mungedAnswer});
|
||||
await answerer.setLocalDescription(answer);
|
||||
|
||||
is(metadataToBeLoaded.length, 3, 'Offerer should have gotten 3 ontrack events');
|
||||
emitter.start();
|
||||
info('Waiting for 3 loadedmetadata events');
|
||||
const videoElems = await Promise.all(metadataToBeLoaded);
|
||||
await checkVideoElements(senderElement, videoElems, encodings);
|
||||
emitter.stop();
|
||||
|
||||
await Promise.all([waitForSyncedRtcp(offerer), waitForSyncedRtcp(answerer)]);
|
||||
|
||||
info(`Changing source resolution to 1280x720`);
|
||||
emitter.size(1280, 720);
|
||||
emitter.start();
|
||||
await waitForResizeEvents([senderElement, ...videoElems]);
|
||||
await checkVideoElements(senderElement, videoElems, encodings);
|
||||
await checkSenderStats(sender);
|
||||
|
||||
encodings[0].scaleResolutionDownBy = 1;
|
||||
encodings[1].scaleResolutionDownBy = 2;
|
||||
encodings[2].scaleResolutionDownBy = 3;
|
||||
info(`Changing encodings to ${JSON.stringify(encodings)}`);
|
||||
await sender.setParameters({encodings});
|
||||
await waitForResizeEvents(videoElems);
|
||||
await checkVideoElements(senderElement, videoElems, encodings);
|
||||
await checkSenderStats(sender);
|
||||
|
||||
encodings[0].scaleResolutionDownBy = 6;
|
||||
encodings[1].scaleResolutionDownBy = 5;
|
||||
encodings[2].scaleResolutionDownBy = 4;
|
||||
info(`Changing encodings to ${JSON.stringify(encodings)}`);
|
||||
await sender.setParameters({encodings});
|
||||
await waitForResizeEvents(videoElems);
|
||||
await checkVideoElements(senderElement, videoElems, encodings);
|
||||
await checkSenderStats(sender);
|
||||
|
||||
encodings[0].scaleResolutionDownBy = 4;
|
||||
encodings[1].scaleResolutionDownBy = 1;
|
||||
encodings[2].scaleResolutionDownBy = 2;
|
||||
info(`Changing encodings to ${JSON.stringify(encodings)}`);
|
||||
await sender.setParameters({encodings});
|
||||
await waitForResizeEvents(videoElems);
|
||||
await checkVideoElements(senderElement, videoElems, encodings);
|
||||
await checkSenderStats(sender);
|
||||
|
||||
emitter.stop();
|
||||
videoStream.getVideoTracks()[0].stop();
|
||||
offerer.close();
|
||||
answerer.close();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,112 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="parser_rtp.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
<script type="application/javascript" src="helpers_from_wpt/sdp.js"></script>
|
||||
<script type="application/javascript" src="simulcast.js"></script>
|
||||
<script type="application/javascript" src="stats.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1231507",
|
||||
title: "Basic video-only peer connection with Simulcast offer, first rid has lowest resolution",
|
||||
visible: true
|
||||
});
|
||||
|
||||
runNetworkTest(async () => {
|
||||
await pushPrefs(
|
||||
['media.peerconnection.simulcast', true],
|
||||
// 180Kbps was determined empirically, set well-higher than
|
||||
// the 80Kbps+overhead needed for the two simulcast streams.
|
||||
// 100Kbps was apparently too low.
|
||||
['media.peerconnection.video.min_bitrate_estimate', 180*1000]);
|
||||
|
||||
|
||||
const offerer = new RTCPeerConnection();
|
||||
const answerer = new RTCPeerConnection();
|
||||
|
||||
const add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
|
||||
offerer.onicecandidate = e => add(answerer, e.candidate, generateErrorCallback());
|
||||
answerer.onicecandidate = e => add(offerer, e.candidate, generateErrorCallback());
|
||||
|
||||
const metadataToBeLoaded = [];
|
||||
answerer.ontrack = (e) => {
|
||||
metadataToBeLoaded.push(getPlaybackWithLoadedMetadata(e.track));
|
||||
};
|
||||
|
||||
// One send transceiver, that will be used to send both simulcast streams
|
||||
const emitter = new VideoFrameEmitter();
|
||||
const videoStream = emitter.stream();
|
||||
offerer.addTrack(videoStream.getVideoTracks()[0], videoStream);
|
||||
emitter.start();
|
||||
|
||||
const sender = offerer.getSenders()[0];
|
||||
sender.setParameters({
|
||||
encodings: [
|
||||
{ rid: '0', maxBitrate: 40000, scaleResolutionDownBy: 2 },
|
||||
{ rid: '1', maxBitrate: 40000 }
|
||||
]
|
||||
});
|
||||
|
||||
const offer = await offerer.createOffer();
|
||||
|
||||
const mungedOffer = ridToMid(offer);
|
||||
info(`Transformed send simulcast offer to multiple m-sections: ${offer.sdp} to ${mungedOffer}`);
|
||||
|
||||
await answerer.setRemoteDescription({type: 'offer', sdp: mungedOffer});
|
||||
await offerer.setLocalDescription(offer);
|
||||
|
||||
const rids = answerer.getTransceivers().map(t => t.mid);
|
||||
is(rids.length, 2, 'Should have 2 mids in offer');
|
||||
ok(rids[0] != '', 'First mid should be non-empty');
|
||||
ok(rids[1] != '', 'Second mid should be non-empty');
|
||||
info(`rids: ${JSON.stringify(rids)}`);
|
||||
|
||||
const answer = await answerer.createAnswer();
|
||||
|
||||
const mungedAnswer = midToRid(answer);
|
||||
info(`Transformed recv answer to simulcast: ${answer.sdp} to ${mungedAnswer}`);
|
||||
await offerer.setRemoteDescription({type: 'answer', sdp: mungedAnswer});
|
||||
await answerer.setLocalDescription(answer);
|
||||
|
||||
is(metadataToBeLoaded.length, 2, 'Offerer should have gotten 2 ontrack events');
|
||||
info('Waiting for 2 loadedmetadata events');
|
||||
const videoElems = await Promise.all(metadataToBeLoaded);
|
||||
|
||||
const statsReady =
|
||||
Promise.all([waitForSyncedRtcp(offerer), waitForSyncedRtcp(answerer)]);
|
||||
|
||||
const helper = new VideoStreamHelper();
|
||||
info('Waiting for first video element to start playing');
|
||||
await helper.checkVideoPlaying(videoElems[0]);
|
||||
info('Waiting for second video element to start playing');
|
||||
await helper.checkVideoPlaying(videoElems[1]);
|
||||
|
||||
is(videoElems[1].videoWidth, 50,
|
||||
"sink is same width as source, modulo our cropping algorithm");
|
||||
is(videoElems[1].videoHeight, 50,
|
||||
"sink is same height as source, modulo our cropping algorithm");
|
||||
is(videoElems[0].videoWidth, 25,
|
||||
"sink is 1/2 width of source, modulo our cropping algorithm");
|
||||
is(videoElems[0].videoHeight, 25,
|
||||
"sink is 1/2 height of source, modulo our cropping algorithm");
|
||||
|
||||
await statsReady;
|
||||
const senderStats = await sender.getStats();
|
||||
checkSenderStats(senderStats, 2);
|
||||
checkExpectedFields(senderStats);
|
||||
pedanticChecks(senderStats);
|
||||
|
||||
emitter.stop();
|
||||
videoStream.getVideoTracks()[0].stop();
|
||||
offerer.close();
|
||||
answerer.close();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,112 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="parser_rtp.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
<script type="application/javascript" src="helpers_from_wpt/sdp.js"></script>
|
||||
<script type="application/javascript" src="simulcast.js"></script>
|
||||
<script type="application/javascript" src="stats.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1231507",
|
||||
title: "Basic video-only peer connection with Simulcast offer",
|
||||
visible: true
|
||||
});
|
||||
|
||||
runNetworkTest(async () => {
|
||||
await pushPrefs(
|
||||
['media.peerconnection.simulcast', true],
|
||||
// 180Kbps was determined empirically, set well-higher than
|
||||
// the 80Kbps+overhead needed for the two simulcast streams.
|
||||
// 100Kbps was apparently too low.
|
||||
['media.peerconnection.video.min_bitrate_estimate', 180*1000]);
|
||||
|
||||
|
||||
const offerer = new RTCPeerConnection();
|
||||
const answerer = new RTCPeerConnection();
|
||||
|
||||
const add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
|
||||
offerer.onicecandidate = e => add(answerer, e.candidate, generateErrorCallback());
|
||||
answerer.onicecandidate = e => add(offerer, e.candidate, generateErrorCallback());
|
||||
|
||||
const metadataToBeLoaded = [];
|
||||
answerer.ontrack = (e) => {
|
||||
metadataToBeLoaded.push(getPlaybackWithLoadedMetadata(e.track));
|
||||
};
|
||||
|
||||
// One send transceiver, that will be used to send both simulcast streams
|
||||
const emitter = new VideoFrameEmitter();
|
||||
const videoStream = emitter.stream();
|
||||
offerer.addTrack(videoStream.getVideoTracks()[0], videoStream);
|
||||
emitter.start();
|
||||
|
||||
const sender = offerer.getSenders()[0];
|
||||
sender.setParameters({
|
||||
encodings: [
|
||||
{ rid: '0', maxBitrate: 40000 },
|
||||
{ rid: '1', maxBitrate: 40000, scaleResolutionDownBy: 2 }
|
||||
]
|
||||
});
|
||||
|
||||
const offer = await offerer.createOffer();
|
||||
|
||||
const mungedOffer = ridToMid(offer);
|
||||
info(`Transformed send simulcast offer to multiple m-sections: ${offer.sdp} to ${mungedOffer}`);
|
||||
|
||||
await answerer.setRemoteDescription({type: "offer", sdp: mungedOffer});
|
||||
await offerer.setLocalDescription(offer);
|
||||
|
||||
const rids = answerer.getTransceivers().map(t => t.mid);
|
||||
is(rids.length, 2, 'Should have 2 mids in offer');
|
||||
ok(rids[0] != '', 'First mid should be non-empty');
|
||||
ok(rids[1] != '', 'Second mid should be non-empty');
|
||||
info(`rids: ${JSON.stringify(rids)}`);
|
||||
|
||||
const answer = await answerer.createAnswer();
|
||||
|
||||
const mungedAnswer = midToRid(answer);
|
||||
info(`Transformed recv answer to simulcast: ${answer.sdp} to ${mungedAnswer}`);
|
||||
await offerer.setRemoteDescription({type: "answer", sdp: mungedAnswer});
|
||||
await answerer.setLocalDescription(answer);
|
||||
|
||||
is(metadataToBeLoaded.length, 2, 'Offerer should have gotten 2 ontrack events');
|
||||
info('Waiting for 2 loadedmetadata events');
|
||||
const videoElems = await Promise.all(metadataToBeLoaded);
|
||||
|
||||
const statsReady =
|
||||
Promise.all([waitForSyncedRtcp(offerer), waitForSyncedRtcp(answerer)]);
|
||||
|
||||
const helper = new VideoStreamHelper();
|
||||
info('Waiting for first video element to start playing');
|
||||
await helper.checkVideoPlaying(videoElems[0]);
|
||||
info('Waiting for second video element to start playing');
|
||||
await helper.checkVideoPlaying(videoElems[1]);
|
||||
|
||||
is(videoElems[0].videoWidth, 50,
|
||||
"sink is same width as source, modulo our cropping algorithm");
|
||||
is(videoElems[0].videoHeight, 50,
|
||||
"sink is same height as source, modulo our cropping algorithm");
|
||||
is(videoElems[1].videoWidth, 25,
|
||||
"sink is 1/2 width of source, modulo our cropping algorithm");
|
||||
is(videoElems[1].videoHeight, 25,
|
||||
"sink is 1/2 height of source, modulo our cropping algorithm");
|
||||
|
||||
await statsReady;
|
||||
const senderStats = await sender.getStats();
|
||||
checkSenderStats(senderStats, 2);
|
||||
checkExpectedFields(senderStats);
|
||||
pedanticChecks(senderStats);
|
||||
|
||||
emitter.stop();
|
||||
videoStream.getVideoTracks()[0].stop();
|
||||
offerer.close();
|
||||
answerer.close();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -65,12 +65,12 @@ dictionary RTCRtpParameters {
|
|||
// We do not support these, but every wpt test involving parameters insists
|
||||
// that these be present, regardless of whether the test-case has anything to
|
||||
// do with these in particular (see validateRtpParameters).
|
||||
required sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
|
||||
required RTCRtcpParameters rtcp;
|
||||
required sequence<RTCRtpCodecParameters> codecs;
|
||||
sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
|
||||
RTCRtcpParameters rtcp;
|
||||
sequence<RTCRtpCodecParameters> codecs;
|
||||
};
|
||||
|
||||
dictionary RTCRtpSendParameters : RTCRtpParameters {
|
||||
required DOMString transactionId;
|
||||
DOMString transactionId;
|
||||
required sequence<RTCRtpEncodingParameters> encodings;
|
||||
};
|
||||
|
|
|
@ -353,6 +353,7 @@ pref("media.videocontrols.keyboard-tab-to-all-controls", true);
|
|||
pref("media.navigator.permission.disabled", false);
|
||||
pref("media.navigator.streams.fake", false);
|
||||
pref("media.peerconnection.default_iceservers", "[]");
|
||||
pref("media.peerconnection.allow_old_setParameters", true);
|
||||
pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
|
||||
pref("media.peerconnection.ice.tcp", true);
|
||||
pref("media.peerconnection.ice.tcp_so_sock_count", 0); // Disable SO gathering
|
||||
|
|
|
@ -59,6 +59,8 @@ function androidStartup() {
|
|||
|
||||
windowTracker.init();
|
||||
}
|
||||
|
||||
Services.fog.initializeFOG();
|
||||
}
|
||||
|
||||
// ///// Desktop ///////
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
prefs: [media.navigator.permission.disabled:true, media.navigator.streams.fake:true, privacy.resistFingerprinting.reduceTimerPrecision.jitter:false, privacy.reduceTimerPrecision:false, media.peerconnection.ice.trickle_grace_period:10000, media.peerconnection.ice.obfuscate_host_addresses:false]
|
||||
prefs: [media.navigator.permission.disabled:true, media.navigator.streams.fake:true, privacy.resistFingerprinting.reduceTimerPrecision.jitter:false, privacy.reduceTimerPrecision:false, media.peerconnection.ice.trickle_grace_period:10000, media.peerconnection.ice.obfuscate_host_addresses:false, media.peerconnection.allow_old_setParameters:false]
|
||||
lsan-allowed: [Alloc, MakeAndAddRef, Malloc, NS_NewDOMDataChannel, NS_NewRunnableFunction, PR_Realloc, ParentContentActorCreateFunc, allocate, mozilla::DataChannelConnection::Create, mozilla::DataChannelConnection::HandleOpenRequestMessage, mozilla::DataChannelConnection::Open, mozilla::MediaPacket::Copy, mozilla::MediaPipeline::MediaPipeline, mozilla::WeakPtr, mozilla::dom::DocGroup::Create, mozilla::dom::DocGroup::DocGroup, mozilla::runnable_args_func, nsRefPtrDeque, sctp_add_vtag_to_timewait, sctp_hashinit_flags]
|
||||
leak-threshold: [default:3020800, rdd:51200, tab:51200]
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
gecko_metrics = [
|
||||
"browser/base/content/metrics.yaml",
|
||||
"dom/media/metrics.yaml",
|
||||
"dom/media/webrtc/metrics.yaml",
|
||||
"dom/metrics.yaml",
|
||||
"gfx/metrics.yaml",
|
||||
"netwerk/metrics.yaml",
|
||||
|
|
Загрузка…
Ссылка в новой задаче