webrtc_m130/pc/peer_connection_encodings_integrationtest.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

3428 lines
152 KiB
C++
Raw Normal View History

/*
* Copyright 2023 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "absl/algorithm/container.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
#include "api/audio_options.h"
#include "api/field_trials.h"
#include "api/jsep.h"
#include "api/make_ref_counted.h"
#include "api/media_stream_interface.h"
#include "api/media_types.h"
#include "api/rtc_error.h"
#include "api/rtp_parameters.h"
#include "api/rtp_sender_interface.h"
#include "api/rtp_transceiver_direction.h"
#include "api/rtp_transceiver_interface.h"
#include "api/scoped_refptr.h"
#include "api/stats/rtc_stats_report.h"
#include "api/stats/rtcstats_objects.h"
#include "api/test/rtc_error_matchers.h"
#include "api/units/data_rate.h"
#include "api/units/time_delta.h"
#include "media/base/codec.h"
2025-01-17 12:06:53 +01:00
#include "media/engine/fake_webrtc_video_engine.h"
#include "pc/sdp_utils.h"
#include "pc/session_description.h"
#include "pc/simulcast_description.h"
#include "pc/test/mock_peer_connection_observers.h"
#include "pc/test/peer_connection_test_wrapper.h"
#include "pc/test/simulcast_layer_util.h"
#include "rtc_base/checks.h"
#include "rtc_base/containers/flat_map.h"
#include "rtc_base/logging.h"
#include "rtc_base/physical_socket_server.h"
#include "rtc_base/thread.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/wait_until.h"
using ::testing::AllOf;
using ::testing::AnyOf;
using ::testing::Contains;
using ::testing::Each;
using ::testing::Eq;
using ::testing::Field;
using ::testing::Gt;
Add unidirectional codec support ("offer to send" use case). This CL implements allowing sendonly codecs in setCodecPreferences(), i.e. this spec PR: https://github.com/w3c/webrtc-pc/pull/3018. It also makes the setCodecPreferences() ignore level IDs in the filtering algorithm (but not in the sCP method call) as per this spec PR: https://github.com/w3c/webrtc-pc/pull/3023. In short, before this CL, setCodecPreferences() threw an exception if a codec was preferred that is not present in receiver codec capabilities. After this CL, setCodecPreferences() allows you to prefer codecs that are *either* in the sender capabilities *or* the receiver capabilities. - This allows you to "offer to send", i.e. prefer sendonly codecs on a sendonly transceiver. - The filtering on direction is handled by RtpTransceiver::filtered_codec_preferences() which is called during SDP offer/answer (sdp_offer_answer.cc). Also as per spec changes, if this filtering results in not having any codecs to offer or answer then this results in not having any codec preferences as opposed to throwing an exception (old behavior). - Two old peer_connection_media_unittest.cc tests are updated to reflect the API failing less. This CL adds both unit tests (rtp_transceiver_unittest.cc) and full stack integration tests (peer_connection_encodings_integrationtest.cc). It also makes us pass the following Web Platform Tests in Chrome: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/external/wpt/webrtc/protocol/h265-level-id.https.html Bug: chromium:381407888 Change-Id: I98a5ad1acccb56db0538e4d47975b8a725102c33 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/374520 Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Evan Shrubsole <eshr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43788}
2025-01-22 15:13:37 +01:00
using ::testing::HasSubstr;
using ::testing::IsSupersetOf;
using ::testing::IsTrue;
using ::testing::Key;
using ::testing::Le;
using ::testing::Matcher;
using ::testing::Ne;
using ::testing::NotNull;
using ::testing::Optional;
using ::testing::Pair;
using ::testing::Pointer;
using ::testing::ResultOf;
using ::testing::SizeIs;
using ::testing::StrCaseEq;
using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
namespace webrtc {
namespace {
// Most tests pass in 20-30 seconds, but some tests take longer such as AV1
// requiring additional ramp-up time (https://crbug.com/webrtc/15006) or SVC
// (LxTx_KEY) being slower than simulcast to send top spatial layer.
// TODO(https://crbug.com/webrtc/15076): Remove need for long ramp-up timeouts
// by using simulated time.
constexpr TimeDelta kLongTimeoutForRampingUp = TimeDelta::Minutes(1);
// The max bitrate 1500 kbps may be subject to change in the future. What we're
// interested in here is that all code paths that result in L1T3 result in the
// same target bitrate which does not exceed this limit.
constexpr DataRate kVp9ExpectedMaxBitrateForL1T3 =
DataRate::KilobitsPerSec(1500);
auto EncoderImplementationIs(absl::string_view impl) {
return Field("encoder_implementation",
&RTCOutboundRtpStreamStats::encoder_implementation,
Optional(StrEq(impl)));
}
template <typename M>
auto ScalabilityModeIs(M matcher) {
return Field("scalability_mode", &RTCOutboundRtpStreamStats::scalability_mode,
matcher);
}
template <typename M>
auto CodecIs(M matcher) {
return Field("codec_id", &RTCOutboundRtpStreamStats::codec_id, matcher);
}
template <typename M>
auto RidIs(M matcher) {
return Field("rid", &RTCOutboundRtpStreamStats::rid, matcher);
}
template <typename WidthMatcher, typename HeightMatcher>
auto ResolutionIs(WidthMatcher width_matcher, HeightMatcher height_matcher) {
return AllOf(Field("frame_width", &RTCOutboundRtpStreamStats::frame_width,
width_matcher),
Field("frame_height", &RTCOutboundRtpStreamStats::frame_height,
height_matcher));
}
template <typename M>
auto HeightIs(M matcher) {
return Field("frame_height", &RTCOutboundRtpStreamStats::frame_height,
matcher);
}
template <typename M>
auto BytesSentIs(M matcher) {
return Field("bytes_sent", &RTCOutboundRtpStreamStats::bytes_sent, matcher);
}
template <typename M>
auto FramesEncodedIs(M matcher) {
return Field("frames_encoded", &RTCOutboundRtpStreamStats::frames_encoded,
matcher);
}
auto Active() {
return Field("active", &RTCOutboundRtpStreamStats::active, true);
}
Matcher<scoped_refptr<const RTCStatsReport>> OutboundRtpStatsAre(
Matcher<std::vector<RTCOutboundRtpStreamStats>> matcher) {
return Pointer(ResultOf(
"outbound_rtp",
[&](const RTCStatsReport* report) {
std::vector<const RTCOutboundRtpStreamStats*> stats =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
// Copy to a new vector.
std::vector<RTCOutboundRtpStreamStats> stats_copy;
stats_copy.reserve(stats.size());
for (const auto* stat : stats) {
stats_copy.emplace_back(*stat);
}
return stats_copy;
},
matcher));
}
auto HasOutboundRtpBytesSent(size_t num_layers, size_t num_active_layers) {
return OutboundRtpStatsAre(AllOf(
SizeIs(num_layers),
testing::Contains(
Field("bytes_sent", &RTCOutboundRtpStreamStats::bytes_sent, Gt(0)))
.Times(num_active_layers)));
}
auto HasOutboundRtpBytesSent(size_t num_layers) {
return HasOutboundRtpBytesSent(num_layers, num_layers);
}
flat_map<std::string, RTCOutboundRtpStreamStats> GetOutboundRtpStreamStatsByRid(
scoped_refptr<const RTCStatsReport> report) {
flat_map<std::string, RTCOutboundRtpStreamStats> result;
auto stats = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
for (const auto* outbound_rtp : stats) {
result.emplace(
std::make_pair(outbound_rtp->rid.value_or(""), *outbound_rtp));
}
return result;
}
struct StringParamToString {
std::string operator()(const ::testing::TestParamInfo<std::string>& info) {
return info.param;
}
};
std::string GetCurrentCodecMimeType(
rtc::scoped_refptr<const RTCStatsReport> report,
const RTCOutboundRtpStreamStats& outbound_rtp) {
return outbound_rtp.codec_id.has_value()
? *report->GetAs<RTCCodecStats>(*outbound_rtp.codec_id)->mime_type
: "";
}
const RTCOutboundRtpStreamStats* FindOutboundRtpByRid(
const std::vector<const RTCOutboundRtpStreamStats*>& outbound_rtps,
const absl::string_view& rid) {
for (const auto* outbound_rtp : outbound_rtps) {
if (outbound_rtp->rid.has_value() && *outbound_rtp->rid == rid) {
return outbound_rtp;
}
}
return nullptr;
}
} // namespace
class PeerConnectionEncodingsIntegrationTest : public ::testing::Test {
public:
PeerConnectionEncodingsIntegrationTest()
: background_thread_(std::make_unique<rtc::Thread>(&pss_)) {
RTC_CHECK(background_thread_->Start());
}
scoped_refptr<PeerConnectionTestWrapper> CreatePc(
std::unique_ptr<FieldTrialsView> field_trials = nullptr) {
auto pc_wrapper = make_ref_counted<PeerConnectionTestWrapper>(
"pc", &pss_, background_thread_.get(), background_thread_.get());
pc_wrapper->CreatePc({}, CreateBuiltinAudioEncoderFactory(),
CreateBuiltinAudioDecoderFactory(),
std::move(field_trials));
return pc_wrapper;
}
rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiverWithSimulcastLayers(
rtc::scoped_refptr<PeerConnectionTestWrapper> local,
rtc::scoped_refptr<PeerConnectionTestWrapper> remote,
std::vector<cricket::SimulcastLayer> init_layers) {
rtc::scoped_refptr<MediaStreamInterface> stream = local->GetUserMedia(
/*audio=*/false, cricket::AudioOptions(), /*video=*/true,
{.width = 1280, .height = 720});
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
transceiver_or_error = local->pc()->AddTransceiver(
track, CreateTransceiverInit(init_layers));
EXPECT_TRUE(transceiver_or_error.ok());
return transceiver_or_error.value();
}
bool HasReceiverVideoCodecCapability(
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
absl::string_view codec_name) {
std::vector<RtpCodecCapability> codecs =
pc_wrapper->pc_factory()
->GetRtpReceiverCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
return std::find_if(codecs.begin(), codecs.end(),
[&codec_name](const RtpCodecCapability& codec) {
return absl::EqualsIgnoreCase(codec.name, codec_name);
}) != codecs.end();
}
std::vector<RtpCodecCapability> GetCapabilitiesAndRestrictToCodec(
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
absl::string_view codec_name) {
std::vector<RtpCodecCapability> codecs =
pc_wrapper->pc_factory()
->GetRtpReceiverCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
codecs.erase(std::remove_if(codecs.begin(), codecs.end(),
[&codec_name](const RtpCodecCapability& codec) {
return !codec.IsResiliencyCodec() &&
!absl::EqualsIgnoreCase(codec.name,
codec_name);
}),
codecs.end());
RTC_DCHECK(std::find_if(codecs.begin(), codecs.end(),
[&codec_name](const RtpCodecCapability& codec) {
return absl::EqualsIgnoreCase(codec.name,
codec_name);
}) != codecs.end());
return codecs;
}
void ExchangeIceCandidates(
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper,
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper) {
local_pc_wrapper->SignalOnIceCandidateReady.connect(
remote_pc_wrapper.get(), &PeerConnectionTestWrapper::AddIceCandidate);
remote_pc_wrapper->SignalOnIceCandidateReady.connect(
local_pc_wrapper.get(), &PeerConnectionTestWrapper::AddIceCandidate);
}
// Negotiate without any tweaks (does not work for simulcast loopback).
void Negotiate(
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper,
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper) {
std::unique_ptr<SessionDescriptionInterface> offer =
CreateOffer(local_pc_wrapper);
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p1 =
SetLocalDescription(local_pc_wrapper, offer.get());
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p2 =
SetRemoteDescription(remote_pc_wrapper, offer.get());
EXPECT_TRUE(Await({p1, p2}));
std::unique_ptr<SessionDescriptionInterface> answer =
CreateAnswer(remote_pc_wrapper);
p1 = SetLocalDescription(remote_pc_wrapper, answer.get());
p2 = SetRemoteDescription(local_pc_wrapper, answer.get());
EXPECT_TRUE(Await({p1, p2}));
}
void NegotiateWithSimulcastTweaks(
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper,
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper) {
// Create and set offer for `local_pc_wrapper`.
std::unique_ptr<SessionDescriptionInterface> offer =
CreateOffer(local_pc_wrapper);
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p1 =
SetLocalDescription(local_pc_wrapper, offer.get());
// Modify the offer before handoff because `remote_pc_wrapper` only supports
// receiving singlecast.
cricket::SimulcastDescription simulcast_description =
RemoveSimulcast(offer.get());
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p2 =
SetRemoteDescription(remote_pc_wrapper, offer.get());
EXPECT_TRUE(Await({p1, p2}));
// Create and set answer for `remote_pc_wrapper`.
std::unique_ptr<SessionDescriptionInterface> answer =
CreateAnswer(remote_pc_wrapper);
EXPECT_TRUE(answer);
p1 = SetLocalDescription(remote_pc_wrapper, answer.get());
// Modify the answer before handoff because `local_pc_wrapper` should still
// send simulcast.
cricket::MediaContentDescription* mcd_answer =
answer->description()->contents()[0].media_description();
mcd_answer->mutable_streams().clear();
std::vector<cricket::SimulcastLayer> simulcast_layers =
simulcast_description.send_layers().GetAllLayers();
cricket::SimulcastLayerList& receive_layers =
mcd_answer->simulcast_description().receive_layers();
for (const auto& layer : simulcast_layers) {
receive_layers.AddLayer(layer);
}
p2 = SetRemoteDescription(local_pc_wrapper, answer.get());
EXPECT_TRUE(Await({p1, p2}));
}
rtc::scoped_refptr<const RTCStatsReport> GetStats(
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper) {
auto callback = rtc::make_ref_counted<MockRTCStatsCollectorCallback>();
pc_wrapper->pc()->GetStats(callback.get());
RTC_CHECK(WaitUntil([&]() { return callback->called(); }, testing::IsTrue())
.ok());
return callback->report();
}
[[nodiscard]] RTCErrorOr<scoped_refptr<const RTCStatsReport>> GetStatsUntil(
scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
Matcher<scoped_refptr<const RTCStatsReport>> matcher,
WaitUntilSettings settings = {}) {
return WaitUntil([&]() { return GetStats(pc_wrapper); }, std::move(matcher),
settings);
}
protected:
std::unique_ptr<SessionDescriptionInterface> CreateOffer(
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper) {
auto observer =
rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
pc_wrapper->pc()->CreateOffer(observer.get(), {});
EXPECT_THAT(WaitUntil([&] { return observer->called(); }, IsTrue()),
IsRtcOk());
return observer->MoveDescription();
}
std::unique_ptr<SessionDescriptionInterface> CreateAnswer(
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper) {
auto observer =
rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
pc_wrapper->pc()->CreateAnswer(observer.get(), {});
EXPECT_THAT(WaitUntil([&] { return observer->called(); }, IsTrue()),
IsRtcOk());
return observer->MoveDescription();
}
rtc::scoped_refptr<MockSetSessionDescriptionObserver> SetLocalDescription(
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
SessionDescriptionInterface* sdp) {
auto observer = rtc::make_ref_counted<MockSetSessionDescriptionObserver>();
pc_wrapper->pc()->SetLocalDescription(
observer.get(), CloneSessionDescription(sdp).release());
return observer;
}
rtc::scoped_refptr<MockSetSessionDescriptionObserver> SetRemoteDescription(
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
SessionDescriptionInterface* sdp) {
auto observer = rtc::make_ref_counted<MockSetSessionDescriptionObserver>();
pc_wrapper->pc()->SetRemoteDescription(
observer.get(), CloneSessionDescription(sdp).release());
return observer;
}
// To avoid ICE candidates arriving before the remote endpoint has received
// the offer it is important to SetLocalDescription() and
// SetRemoteDescription() are kicked off without awaiting in-between. This
// helper is used to await multiple observers.
bool Await(std::vector<rtc::scoped_refptr<MockSetSessionDescriptionObserver>>
observers) {
for (auto& observer : observers) {
auto result = WaitUntil([&] { return observer->called(); }, IsTrue());
if (!result.ok() || !observer->result()) {
return false;
}
}
return true;
}
rtc::PhysicalSocketServer pss_;
std::unique_ptr<rtc::Thread> background_thread_;
};
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP8_SingleEncodingDefaultsToL1T1) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP8");
transceiver->SetCodecPreferences(codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until media is flowing.
auto stats_result =
GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(1));
ASSERT_THAT(stats_result, IsRtcOk());
EXPECT_THAT(GetOutboundRtpStreamStatsByRid(stats_result.value()),
ElementsAre(Pair("", ResolutionIs(1280, 720))));
// Verify codec and scalability mode.
rtc::scoped_refptr<const RTCStatsReport> report = stats_result.value();
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_THAT(outbound_rtps, Contains(ResolutionIs(Le(1280), Le(720))));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/VP8"));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T1"));
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP8_RejectsSvcAndDefaultsToL1T1) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
// Restricting the local receive codecs will restrict what we offer and
// hence the answer if it is a subset of our offer.
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP8");
transceiver->SetCodecPreferences(codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
// Attempt SVC (L3T3_KEY). This is not possible because only VP8 is up for
// negotiation and VP8 does not support it.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
parameters.encodings[0].scalability_mode = "L3T3_KEY";
parameters.encodings[0].scale_resolution_down_by = 1;
EXPECT_FALSE(sender->SetParameters(parameters).ok());
// `scalability_mode` remains unset because SetParameters() failed.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq(std::nullopt));
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until media is flowing.
ASSERT_THAT(GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(1)),
IsRtcOk());
// When `scalability_mode` is not set, VP8 defaults to L1T1.
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/VP8"));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T1"));
// GetParameters() confirms `scalability_mode` is still not set.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq(std::nullopt));
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersWithScalabilityModeNotSupportedBySubsequentNegotiation) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
// Restricting the local receive codecs will restrict what we offer and
// hence the answer if it is a subset of our offer.
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP8");
transceiver->SetCodecPreferences(codecs);
// Attempt SVC (L3T3_KEY). This is still possible because VP9 might be
// available from the remote end.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
parameters.encodings[0].scalability_mode = "L3T3_KEY";
parameters.encodings[0].scale_resolution_down_by = 1;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
// `scalability_mode` is set to the VP8 default since that is what was
// negotiated.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq("L1T2"));
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until media is flowing.
auto error_or_stats =
GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(1));
ASSERT_THAT(error_or_stats, IsRtcOk());
// When `scalability_mode` is not set, VP8 defaults to L1T1.
rtc::scoped_refptr<const RTCStatsReport> report = error_or_stats.value();
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/VP8"));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T2"));
// GetParameters() confirms `scalability_mode` is still not set.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq("L1T2"));
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP8_FallbackFromSvcResultsInL1T2) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
// Verify test assumption that VP8 is first in the list, but don't modify the
// codec preferences because we want the sender to think SVC is a possibility.
std::vector<RtpCodecCapability> codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
EXPECT_THAT(codecs[0].name, StrCaseEq("VP8"));
// Attempt SVC (L3T3_KEY), which is not possible with VP8, but the sender does
// not yet know which codec we'll use so the parameters will be accepted.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
parameters.encodings[0].scalability_mode = "L3T3_KEY";
parameters.encodings[0].scale_resolution_down_by = 1;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
// Verify fallback has not happened yet.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(std::string("L3T3_KEY")));
// Negotiate, this results in VP8 being picked and fallback happening.
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// `scalaiblity_mode` is assigned the fallback value "L1T2" which is different
// than the default of std::nullopt.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(std::string("L1T2")));
// Wait until media is flowing, no significant time needed because we only
// have one layer.
ASSERT_THAT(GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(1u)),
IsRtcOk());
// GetStats() confirms "L1T2" is used which is different than the "L1T1"
// default or the "L3T3_KEY" that was attempted.
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/VP8"));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T2"));
// Now that we know VP8 is used, try setting L3T3 which should fail.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
parameters.encodings[0].scalability_mode = "L3T3_KEY";
parameters.encodings[0].scale_resolution_down_by = 1;
EXPECT_FALSE(sender->SetParameters(parameters).ok());
}
// The legacy SVC path is triggered when VP9 us used, but `scalability_mode` has
// not been specified.
// TODO(https://crbug.com/webrtc/14889): When legacy VP9 SVC path has been
// deprecated and removed, update this test to assert that simulcast is used
// (i.e. VP9 is not treated differently than VP8).
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_LegacySvcWhenScalabilityModeNotSpecified) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until media is flowing. We only expect a single RTP stream.
// We expect to see bytes flowing almost immediately on the lowest layer.
ASSERT_THAT(GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(1u)),
IsRtcOk());
// Wait until scalability mode is reported and expected resolution reached.
// Ramp up time may be significant.
ASSERT_THAT(
GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(Contains(
AllOf(RidIs("f"), ScalabilityModeIs("L3T3_KEY"), HeightIs(720)))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
// Despite SVC being used on a single RTP stream, GetParameters() returns the
// three encodings that we configured earlier (this is not spec-compliant but
// it is how legacy SVC behaves).
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
std::vector<RtpEncodingParameters> encodings =
sender->GetParameters().encodings;
ASSERT_EQ(encodings.size(), 3u);
// When legacy SVC is used, `scalability_mode` is not specified.
EXPECT_FALSE(encodings[0].scalability_mode.has_value());
EXPECT_FALSE(encodings[1].scalability_mode.has_value());
EXPECT_FALSE(encodings[2].scalability_mode.has_value());
}
// The spec-compliant way to configure SVC for a single stream. The expected
// outcome is the same as for the legacy SVC case except that we only have one
// encoding in GetParameters().
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_StandardSvcWithOnlyOneEncoding) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// Configure SVC, a.k.a. "L3T3_KEY".
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
parameters.encodings[0].scalability_mode = "L3T3_KEY";
parameters.encodings[0].scale_resolution_down_by = 1;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until media is flowing. We only expect a single RTP stream.
// We expect to see bytes flowing almost immediately on the lowest layer.
auto error_or_stats =
GetStatsUntil(local_pc_wrapper,
AllOf(HasOutboundRtpBytesSent(1u),
OutboundRtpStatsAre(Contains(HeightIs(720)))),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(error_or_stats, IsRtcOk());
// Verify codec and scalability mode.
scoped_refptr<const RTCStatsReport> report = error_or_stats.value();
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_THAT(outbound_rtps[0], ResolutionIs(1280, 720));
EXPECT_THAT(outbound_rtps[0], RidIs(std::nullopt));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/VP9"));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L3T3_KEY"));
// GetParameters() is consistent with what we asked for and got.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(std::string("L3T3_KEY")));
}
// The {active,inactive,inactive} case is technically simulcast but since we
// only have one active stream, we're able to do SVC (multiple spatial layers
// is not supported if multiple encodings are active). The expected outcome is
// the same as above except we end up with two inactive RTP streams which are
// observable in GetStats().
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_StandardSvcWithSingleActiveEncoding) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// Configure SVC, a.k.a. "L3T3_KEY".
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].scalability_mode = "L3T3_KEY";
parameters.encodings[0].scale_resolution_down_by = 1;
parameters.encodings[1].active = false;
parameters.encodings[2].active = false;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Since the standard API is configuring simulcast we get three outbound-rtps,
// but only one is active.
// Wait until scalability mode is reported and expected resolution reached.
// Ramp up time is significant.
ASSERT_THAT(GetStatsUntil(local_pc_wrapper,
AllOf(HasOutboundRtpBytesSent(3, 1),
OutboundRtpStatsAre(Contains(AllOf(
RidIs("f"), ScalabilityModeIs("L3T3_KEY"),
HeightIs(720))))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
// GetParameters() is consistent with what we asked for and got.
parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(StrEq("L3T3_KEY")));
EXPECT_FALSE(parameters.encodings[1].scalability_mode.has_value());
EXPECT_FALSE(parameters.encodings[2].scalability_mode.has_value());
}
// Exercise common path where `scalability_mode` is not specified until after
// negotiation, requiring us to recreate the stream when the number of streams
// changes from 1 (legacy SVC) to 3 (standard simulcast).
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_SwitchFromLegacySvcToStandardSingleActiveEncodingSvc) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// The original negotiation triggers legacy SVC because we didn't specify
// any scalability mode.
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Switch to the standard mode. Despite only having a single active stream in
// both cases, this internally reconfigures from 1 stream to 3 streams.
// Test coverage for https://crbug.com/webrtc/15016.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].active = true;
parameters.encodings[0].scalability_mode = "L2T2_KEY";
parameters.encodings[0].scale_resolution_down_by = 2.0;
parameters.encodings[1].active = false;
parameters.encodings[1].scalability_mode = std::nullopt;
parameters.encodings[2].active = false;
parameters.encodings[2].scalability_mode = std::nullopt;
sender->SetParameters(parameters);
// Since the standard API is configuring simulcast we get three outbound-rtps,
// but only one is active.
// Wait until scalability mode is reported and expected resolution reached.
// Ramp up time may be significant.
ASSERT_THAT(GetStatsUntil(local_pc_wrapper,
AllOf(HasOutboundRtpBytesSent(3, 1),
OutboundRtpStatsAre(Contains(AllOf(
RidIs("f"), ScalabilityModeIs("L2T2_KEY"),
HeightIs(720 / 2))))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
// GetParameters() does not report any fallback.
parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(std::string("L2T2_KEY")));
EXPECT_FALSE(parameters.encodings[1].scalability_mode.has_value());
EXPECT_FALSE(parameters.encodings[2].scalability_mode.has_value());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_SimulcastDeactiveActiveLayer_StandardSvc) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
constexpr absl::string_view kCodec = "VP9";
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, kCodec);
transceiver->SetCodecPreferences(codecs);
// Switch to the standard mode. Despite only having a single active stream in
// both cases, this internally reconfigures from 1 stream to 3 streams.
// Test coverage for https://crbug.com/webrtc/15016.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].active = true;
parameters.encodings[0].scalability_mode = "L1T3";
parameters.encodings[0].scale_resolution_down_by = 4.0;
parameters.encodings[1].active = true;
parameters.encodings[1].scalability_mode = "L1T1";
parameters.encodings[1].scale_resolution_down_by = 2.0;
parameters.encodings[2].active = true;
parameters.encodings[2].scalability_mode = "L1T1";
parameters.encodings[2].scale_resolution_down_by = 1.0;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
// The original negotiation triggers legacy SVC because we didn't specify
// any scalability mode.
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Since the standard API is configuring simulcast we get three outbound-rtps,
// and two are active.
ASSERT_THAT(
WaitUntil(
[&] {
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
GetStats(local_pc_wrapper)
->GetStatsOfType<RTCOutboundRtpStreamStats>();
std::vector<size_t> bytes_sent;
bytes_sent.reserve(outbound_rtps.size());
for (const auto* outbound_rtp : outbound_rtps) {
bytes_sent.push_back(outbound_rtp->bytes_sent.value_or(0));
}
return bytes_sent;
},
AllOf(SizeIs(3), Each(Gt(0))), {.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
ASSERT_TRUE(report);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
EXPECT_THAT(outbound_rtps,
Each(EncoderImplementationIs(
"SimulcastEncoderAdapter (libvpx, libvpx, libvpx)")));
// GetParameters() does not report any fallback.
parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(StrEq("L1T3")));
EXPECT_THAT(parameters.encodings[1].scalability_mode,
Optional(StrEq("L1T1")));
EXPECT_THAT(parameters.encodings[2].scalability_mode,
Optional(StrEq("L1T1")));
EXPECT_THAT(parameters.encodings[2].scale_resolution_down_by, Eq(1.0));
EXPECT_THAT(parameters.encodings[1].scale_resolution_down_by, Eq(2.0));
EXPECT_THAT(parameters.encodings[0].scale_resolution_down_by, Eq(4.0));
// Deactivate the active layer.
parameters.encodings[2].active = false;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
ASSERT_THAT(WaitUntil(
[&]() {
return GetStats(local_pc_wrapper)
->GetStatsOfType<RTCOutboundRtpStreamStats>();
},
AllOf(Each(EncoderImplementationIs(
"SimulcastEncoderAdapter (libvpx, libvpx)")),
UnorderedElementsAre(ScalabilityModeIs("L1T3"),
ScalabilityModeIs("L1T1"),
ScalabilityModeIs(std::nullopt)))),
IsRtcOk());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_SimulcastMultiplLayersActive_StandardSvc) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// Switch to the standard mode. Despite only having a single active stream in
// both cases, this internally reconfigures from 1 stream to 3 streams.
// Test coverage for https://crbug.com/webrtc/15016.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].active = true;
parameters.encodings[0].scalability_mode = "L1T3";
parameters.encodings[0].scale_resolution_down_by = 4.0;
parameters.encodings[1].active = true;
parameters.encodings[1].scalability_mode = "L1T1";
parameters.encodings[1].scale_resolution_down_by = 2.0;
parameters.encodings[2].active = false;
parameters.encodings[2].scalability_mode = std::nullopt;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
// The original negotiation triggers legacy SVC because we didn't specify
// any scalability mode.
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Since the standard API is configuring simulcast we get three outbound-rtps,
// and two are active.
// Wait until scalability mode is reported and expected resolution reached.
// Ramp up time may be significant.
auto error_or_stats = GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(
IsSupersetOf({AllOf(RidIs("q"), ScalabilityModeIs("L1T3"),
HeightIs(720 / 4), BytesSentIs(Gt(0))),
AllOf(RidIs("h"), ScalabilityModeIs("L1T1"),
HeightIs(720 / 2), BytesSentIs(Gt(0)))})),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(error_or_stats, IsRtcOk());
rtc::scoped_refptr<const RTCStatsReport> report = error_or_stats.value();
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
EXPECT_THAT(outbound_rtps, Each(EncoderImplementationIs(
"SimulcastEncoderAdapter (libvpx, libvpx)")));
// GetParameters() does not report any fallback.
parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(StrEq("L1T3")));
EXPECT_THAT(parameters.encodings[1].scalability_mode,
Optional(StrEq("L1T1")));
EXPECT_THAT(parameters.encodings[2].scalability_mode, Eq(std::nullopt));
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_Simulcast_SwitchToLegacySvc) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// Switch to the standard mode. Despite only having a single active stream in
// both cases, this internally reconfigures from 1 stream to 3 streams.
// Test coverage for https://crbug.com/webrtc/15016.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].active = false;
parameters.encodings[1].active = true;
parameters.encodings[1].scalability_mode = "L1T1";
parameters.encodings[1].scale_resolution_down_by = 2.0;
parameters.encodings[2].active = true;
parameters.encodings[2].scalability_mode = "L1T3";
parameters.encodings[2].scale_resolution_down_by = 4.0;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
// The original negotiation triggers legacy SVC because we didn't specify
// any scalability mode.
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Since the standard API is configuring simulcast we get three outbound-rtps,
// and two are active.
// Wait until scalability mode is reported and expected resolution reached.
// Ramp up time may be significant.
auto error_or_stats = GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(UnorderedElementsAre(
AllOf(RidIs("q"), ScalabilityModeIs("L1T3"), HeightIs(720 / 4)),
AllOf(RidIs("h"), ScalabilityModeIs("L1T1"), HeightIs(720 / 2)),
AllOf(RidIs("f"), BytesSentIs(AnyOf(0, std::nullopt))))),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(error_or_stats, IsRtcOk());
// GetParameters() does not report any fallback.
parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq(std::nullopt));
EXPECT_THAT(parameters.encodings[1].scalability_mode,
Optional(StrEq("L1T1")));
EXPECT_THAT(parameters.encodings[2].scalability_mode,
Optional(StrEq("L1T3")));
// Switch to legacy SVC mode.
parameters.encodings[0].active = true;
parameters.encodings[0].scalability_mode = std::nullopt;
parameters.encodings[0].scale_resolution_down_by = std::nullopt;
parameters.encodings[1].active = true;
parameters.encodings[1].scalability_mode = std::nullopt;
parameters.encodings[1].scale_resolution_down_by = std::nullopt;
parameters.encodings[2].active = false;
parameters.encodings[2].scalability_mode = std::nullopt;
parameters.encodings[2].scale_resolution_down_by = std::nullopt;
EXPECT_TRUE(sender->SetParameters(parameters).ok());
// Ensure that we are getting VGA at L1T3 from the "f" rid.
EXPECT_THAT(
GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(Contains(AllOf(
RidIs("f"), ScalabilityModeIs("L2T3_KEY"), HeightIs(720 / 2)))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
}
TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_OneLayerActive_LegacySvc) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// Sending L1T3 with legacy SVC mode means setting 1 layer active.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].active = true;
parameters.encodings[1].active = false;
parameters.encodings[2].active = false;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Ensure that we are getting 180P at L1T3 from the "f" rid.
EXPECT_THAT(
GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(Contains(
AllOf(RidIs("f"), ScalabilityModeIs("L1T3"), HeightIs(720 / 4)))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_AllLayersInactive_LegacySvc) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// Legacy SVC mode and all layers inactive.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].active = false;
parameters.encodings[1].active = false;
parameters.encodings[2].active = false;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Ensure no media is flowing (1 second should be enough).
rtc::Thread::Current()->SleepMs(1000);
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_EQ(*outbound_rtps[0]->bytes_sent, 0u);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
VP9_AllLayersInactive_StandardSvc) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// Standard mode and all layers inactive.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].scalability_mode = "L3T3_KEY";
parameters.encodings[0].scale_resolution_down_by = 1;
parameters.encodings[0].active = false;
parameters.encodings[1].active = false;
parameters.encodings[2].active = false;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Ensure no media is flowing (1 second should be enough).
rtc::Thread::Current()->SleepMs(1000);
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(3u));
EXPECT_EQ(*outbound_rtps[0]->bytes_sent, 0u);
EXPECT_EQ(*outbound_rtps[1]->bytes_sent, 0u);
EXPECT_EQ(*outbound_rtps[2]->bytes_sent, 0u);
}
TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_LegacyL1T3) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// In legacy SVC, disabling the bottom two layers encodings is interpreted as
// disabling the bottom two spatial layers resulting in L1T3.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
parameters.encodings[0].active = false;
parameters.encodings[1].active = false;
parameters.encodings[2].active = true;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until 720p L1T3 has ramped up to 720p. It may take additional time
// for the target bitrate to reach its maximum.
ASSERT_THAT(
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(Contains(AllOf(
RidIs("f"), ScalabilityModeIs("L1T3"), HeightIs(720)))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
// The target bitrate typically reaches `kVp9ExpectedMaxBitrateForL1T3`
// in a short period of time. However to reduce risk of flakiness in bot
// environments, this test only fails if we we exceed the expected target.
rtc::Thread::Current()->SleepMs(1000);
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1));
DataRate target_bitrate =
DataRate::BitsPerSec(*outbound_rtps[0]->target_bitrate);
EXPECT_LE(target_bitrate.kbps(), kVp9ExpectedMaxBitrateForL1T3.kbps());
}
// Test coverage for https://crbug.com/1455039.
TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_StandardL1T3) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP9");
transceiver->SetCodecPreferences(codecs);
// With standard APIs, L1T3 is explicitly specified and the encodings refers
// to the RTP streams, not the spatial layers. The end result should be
// equivalent to the legacy L1T3 case.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
parameters.encodings[0].active = true;
parameters.encodings[0].scale_resolution_down_by = 1.0;
parameters.encodings[0].scalability_mode = "L1T3";
parameters.encodings[1].active = false;
parameters.encodings[2].active = false;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until 720p L1T3 has ramped up to 720p. It may take additional time
// for the target bitrate to reach its maximum.
ASSERT_THAT(
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(Contains(AllOf(
RidIs("f"), ScalabilityModeIs("L1T3"), HeightIs(720)))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
// The target bitrate typically reaches `kVp9ExpectedMaxBitrateForL1T3`
// in a short period of time. However to reduce risk of flakiness in bot
// environments, this test only fails if we we exceed the expected target.
rtc::Thread::Current()->SleepMs(1000);
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(3));
auto* outbound_rtp = FindOutboundRtpByRid(outbound_rtps, "f");
ASSERT_TRUE(outbound_rtp);
DataRate target_bitrate = DataRate::BitsPerSec(*outbound_rtp->target_bitrate);
EXPECT_LE(target_bitrate.kbps(), kVp9ExpectedMaxBitrateForL1T3.kbps());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SimulcastProducesUniqueSsrcAndRtxSsrcs) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, "VP8");
transceiver->SetCodecPreferences(codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until media is flowing on all three layers.
// Ramp up time is needed before all three layers are sending.
auto stats = GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(3u),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(stats, IsRtcOk());
// Verify SSRCs and RTX SSRCs.
rtc::scoped_refptr<const RTCStatsReport> report = stats.MoveValue();
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(3u));
std::set<uint32_t> ssrcs;
std::set<uint32_t> rtx_ssrcs;
for (const auto& outbound_rtp : outbound_rtps) {
ASSERT_TRUE(outbound_rtp->ssrc.has_value());
ASSERT_TRUE(outbound_rtp->rtx_ssrc.has_value());
ssrcs.insert(*outbound_rtp->ssrc);
rtx_ssrcs.insert(*outbound_rtp->rtx_ssrc);
}
EXPECT_EQ(ssrcs.size(), 3u);
EXPECT_EQ(rtx_ssrcs.size(), 3u);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParameterCodecIsEmptyWhenCreatedAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
EXPECT_FALSE(parameters.encodings[0].codec.has_value());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParameterCodecIsEmptyWhenCreatedVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
EXPECT_FALSE(parameters.encodings[0].codec.has_value());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParameterCodecIsSetByAddTransceiverAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
rtc::scoped_refptr<MediaStreamInterface> stream =
local_pc_wrapper->GetUserMedia(
/*audio=*/true, {}, /*video=*/false, {});
rtc::scoped_refptr<AudioTrackInterface> track = stream->GetAudioTracks()[0];
std::optional<RtpCodecCapability> pcmu =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
"pcmu");
ASSERT_TRUE(pcmu);
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.codec = pcmu;
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(track, init);
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
EXPECT_EQ(*parameters.encodings[0].codec, *pcmu);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
ASSERT_TRUE(local_pc_wrapper->WaitForConnection());
ASSERT_TRUE(remote_pc_wrapper->WaitForConnection());
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_EQ(outbound_rtps.size(), 1u);
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
EXPECT_STRCASEEQ(("audio/" + pcmu->name).c_str(), codec_name.c_str());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParameterCodecIsSetByAddTransceiverVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
rtc::scoped_refptr<MediaStreamInterface> stream =
local_pc_wrapper->GetUserMedia(
/*audio=*/false, {}, /*video=*/true, {.width = 1280, .height = 720});
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
std::optional<RtpCodecCapability> vp9 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp9");
ASSERT_TRUE(vp9);
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.codec = vp9;
encoding_parameters.scalability_mode = "L3T3";
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(track, init);
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
EXPECT_EQ(*parameters.encodings[0].codec, *vp9);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
auto error_or_stats =
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(Contains(ScalabilityModeIs("L3T3"))));
ASSERT_THAT(error_or_stats, IsRtcOk());
rtc::scoped_refptr<const RTCStatsReport> report = error_or_stats.MoveValue();
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_EQ(outbound_rtps.size(), 1u);
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
EXPECT_STRCASEEQ(("video/" + vp9->name).c_str(), codec_name.c_str());
EXPECT_EQ(outbound_rtps[0]->scalability_mode.value(), "L3T3");
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParameterCodecIsSetBySetParametersBeforeNegotiationAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
rtc::scoped_refptr<MediaStreamInterface> stream =
local_pc_wrapper->GetUserMedia(
/*audio=*/true, {}, /*video=*/false, {});
rtc::scoped_refptr<AudioTrackInterface> track = stream->GetAudioTracks()[0];
std::optional<RtpCodecCapability> pcmu =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
"pcmu");
auto transceiver_or_error = local_pc_wrapper->pc()->AddTransceiver(track);
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = pcmu;
EXPECT_TRUE(audio_transceiver->sender()->SetParameters(parameters).ok());
parameters = audio_transceiver->sender()->GetParameters();
EXPECT_EQ(parameters.encodings[0].codec, pcmu);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_EQ(outbound_rtps.size(), 1u);
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
EXPECT_STRCASEEQ(("audio/" + pcmu->name).c_str(), codec_name.c_str());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParameterCodecIsSetBySetParametersAfterNegotiationAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
rtc::scoped_refptr<MediaStreamInterface> stream =
local_pc_wrapper->GetUserMedia(
/*audio=*/true, {}, /*video=*/false, {});
rtc::scoped_refptr<AudioTrackInterface> track = stream->GetAudioTracks()[0];
std::optional<RtpCodecCapability> pcmu =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
"pcmu");
auto transceiver_or_error = local_pc_wrapper->pc()->AddTransceiver(track);
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_EQ(outbound_rtps.size(), 1u);
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
EXPECT_STRCASENE(("audio/" + pcmu->name).c_str(), codec_name.c_str());
std::string last_codec_id = outbound_rtps[0]->codec_id.value();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = pcmu;
EXPECT_TRUE(audio_transceiver->sender()->SetParameters(parameters).ok());
parameters = audio_transceiver->sender()->GetParameters();
EXPECT_EQ(parameters.encodings[0].codec, pcmu);
auto error_or_stats =
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(Contains(CodecIs(Ne(last_codec_id)))));
ASSERT_THAT(error_or_stats, IsRtcOk());
report = error_or_stats.MoveValue();
outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_EQ(outbound_rtps.size(), 1u);
codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
EXPECT_STRCASEEQ(("audio/" + pcmu->name).c_str(), codec_name.c_str());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParameterCodecIsSetBySetParametersBeforeNegotiationVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
rtc::scoped_refptr<MediaStreamInterface> stream =
local_pc_wrapper->GetUserMedia(
/*audio=*/false, {}, /*video=*/true, {.width = 1280, .height = 720});
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
std::optional<RtpCodecCapability> vp9 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp9");
auto transceiver_or_error = local_pc_wrapper->pc()->AddTransceiver(track);
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = vp9;
parameters.encodings[0].scalability_mode = "L3T3";
EXPECT_TRUE(video_transceiver->sender()->SetParameters(parameters).ok());
parameters = video_transceiver->sender()->GetParameters();
EXPECT_EQ(parameters.encodings[0].codec, vp9);
EXPECT_EQ(parameters.encodings[0].scalability_mode, "L3T3");
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
auto error_or_stats = GetStatsUntil(
local_pc_wrapper, OutboundRtpStatsAre(Contains(AllOf(
ScalabilityModeIs("L3T3"), CodecIs(Ne(""))))));
ASSERT_THAT(error_or_stats, IsRtcOk());
rtc::scoped_refptr<const RTCStatsReport> report = error_or_stats.MoveValue();
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_EQ(outbound_rtps.size(), 1u);
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
EXPECT_STRCASEEQ(("video/" + vp9->name).c_str(), codec_name.c_str());
EXPECT_EQ(outbound_rtps[0]->scalability_mode.value_or(""), "L3T3");
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParameterCodecIsSetBySetParametersAfterNegotiationVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
rtc::scoped_refptr<MediaStreamInterface> stream =
local_pc_wrapper->GetUserMedia(
/*audio=*/false, {}, /*video=*/true, {.width = 1280, .height = 720});
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
std::optional<RtpCodecCapability> vp9 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp9");
auto transceiver_or_error = local_pc_wrapper->pc()->AddTransceiver(track);
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_EQ(outbound_rtps.size(), 1u);
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
EXPECT_STRCASENE(("audio/" + vp9->name).c_str(), codec_name.c_str());
std::string last_codec_id = outbound_rtps[0]->codec_id.value();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = vp9;
parameters.encodings[0].scalability_mode = "L3T3";
EXPECT_TRUE(video_transceiver->sender()->SetParameters(parameters).ok());
parameters = video_transceiver->sender()->GetParameters();
EXPECT_EQ(parameters.encodings[0].codec, vp9);
EXPECT_EQ(parameters.encodings[0].scalability_mode, "L3T3");
auto error_or_stats = GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(Contains(
AllOf(ScalabilityModeIs("L3T3"), CodecIs(Ne(last_codec_id))))));
ASSERT_THAT(error_or_stats, IsRtcOk());
report = error_or_stats.MoveValue();
outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_EQ(outbound_rtps.size(), 1u);
codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
EXPECT_STRCASEEQ(("video/" + vp9->name).c_str(), codec_name.c_str());
EXPECT_EQ(outbound_rtps[0]->scalability_mode.value(), "L3T3");
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
AddTransceiverRejectsUnknownCodecParameterAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
RtpCodec dummy_codec;
dummy_codec.kind = cricket::MEDIA_TYPE_AUDIO;
dummy_codec.name = "FOOBAR";
dummy_codec.clock_rate = 90000;
dummy_codec.num_channels = 2;
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.codec = dummy_codec;
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
EXPECT_FALSE(transceiver_or_error.ok());
EXPECT_EQ(transceiver_or_error.error().type(),
RTCErrorType::UNSUPPORTED_OPERATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
AddTransceiverRejectsUnknownCodecParameterVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
RtpCodec dummy_codec;
dummy_codec.kind = cricket::MEDIA_TYPE_VIDEO;
dummy_codec.name = "FOOBAR";
dummy_codec.clock_rate = 90000;
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.codec = dummy_codec;
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
EXPECT_FALSE(transceiver_or_error.ok());
EXPECT_EQ(transceiver_or_error.error().type(),
RTCErrorType::UNSUPPORTED_OPERATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersRejectsUnknownCodecParameterAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
RtpCodec dummy_codec;
dummy_codec.kind = cricket::MEDIA_TYPE_AUDIO;
dummy_codec.name = "FOOBAR";
dummy_codec.clock_rate = 90000;
dummy_codec.num_channels = 2;
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = dummy_codec;
RTCError error = audio_transceiver->sender()->SetParameters(parameters);
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersRejectsUnknownCodecParameterVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
RtpCodec dummy_codec;
dummy_codec.kind = cricket::MEDIA_TYPE_VIDEO;
dummy_codec.name = "FOOBAR";
dummy_codec.clock_rate = 90000;
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = dummy_codec;
RTCError error = video_transceiver->sender()->SetParameters(parameters);
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersRejectsNonNegotiatedCodecParameterAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::optional<RtpCodecCapability> opus =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
"opus");
ASSERT_TRUE(opus);
std::vector<RtpCodecCapability> not_opus_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
.codecs;
not_opus_codecs.erase(
std::remove_if(not_opus_codecs.begin(), not_opus_codecs.end(),
[&](const auto& codec) {
return absl::EqualsIgnoreCase(codec.name, opus->name);
}),
not_opus_codecs.end());
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
ASSERT_TRUE(audio_transceiver->SetCodecPreferences(not_opus_codecs).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = opus;
RTCError error = audio_transceiver->sender()->SetParameters(parameters);
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersRejectsNonRemotelyNegotiatedCodecParameterAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::optional<RtpCodecCapability> opus =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
"opus");
ASSERT_TRUE(opus);
std::vector<RtpCodecCapability> not_opus_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
.codecs;
not_opus_codecs.erase(
std::remove_if(not_opus_codecs.begin(), not_opus_codecs.end(),
[&](const auto& codec) {
return absl::EqualsIgnoreCase(codec.name, opus->name);
}),
not_opus_codecs.end());
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
// Negotiation, create offer and apply it
std::unique_ptr<SessionDescriptionInterface> offer =
CreateOffer(local_pc_wrapper);
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p1 =
SetLocalDescription(local_pc_wrapper, offer.get());
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p2 =
SetRemoteDescription(remote_pc_wrapper, offer.get());
EXPECT_TRUE(Await({p1, p2}));
// Update the remote transceiver to reject Opus
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remote_transceivers =
remote_pc_wrapper->pc()->GetTransceivers();
ASSERT_TRUE(!remote_transceivers.empty());
rtc::scoped_refptr<RtpTransceiverInterface> remote_audio_transceiver =
remote_transceivers[0];
ASSERT_TRUE(
remote_audio_transceiver->SetCodecPreferences(not_opus_codecs).ok());
// Create answer and apply it
std::unique_ptr<SessionDescriptionInterface> answer =
CreateAnswer(remote_pc_wrapper);
p1 = SetLocalDescription(remote_pc_wrapper, answer.get());
p2 = SetRemoteDescription(local_pc_wrapper, answer.get());
EXPECT_TRUE(Await({p1, p2}));
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = opus;
RTCError error = audio_transceiver->sender()->SetParameters(parameters);
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
}
// Test coverage for https://crbug.com/webrtc/391340599.
// Some web apps add non-standard FMTP parameters to video codecs and because
// they get successfully negotiated due to being ignored by SDP rules, they show
// up in GetParameters().codecs. Using SetParameters() with such codecs should
// still work.
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersAcceptsMungedCodecFromGetParameters) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
std::unique_ptr<SessionDescriptionInterface> offer =
CreateOffer(local_pc_wrapper);
// Munge a new parameter for VP8 in the offer.
auto* mcd = offer->description()->contents()[0].media_description();
ASSERT_THAT(mcd, NotNull());
std::vector<cricket::Codec> codecs = mcd->codecs();
ASSERT_THAT(codecs, Contains(Field(&cricket::Codec::name, "VP8")));
auto vp8_codec = absl::c_find_if(
codecs, [](const cricket::Codec& codec) { return codec.name == "VP8"; });
vp8_codec->params.emplace("non-standard-param", "true");
mcd->set_codecs(codecs);
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p1 =
SetLocalDescription(local_pc_wrapper, offer.get());
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p2 =
SetRemoteDescription(remote_pc_wrapper, offer.get());
EXPECT_TRUE(Await({p1, p2}));
// Create answer and apply it
std::unique_ptr<SessionDescriptionInterface> answer =
CreateAnswer(remote_pc_wrapper);
mcd = answer->description()->contents()[0].media_description();
ASSERT_THAT(mcd, NotNull());
codecs = mcd->codecs();
ASSERT_THAT(codecs, Contains(Field(&cricket::Codec::name, "VP8")));
vp8_codec = absl::c_find_if(
codecs, [](const cricket::Codec& codec) { return codec.name == "VP8"; });
vp8_codec->params.emplace("non-standard-param", "true");
mcd->set_codecs(codecs);
p1 = SetLocalDescription(remote_pc_wrapper, answer.get());
p2 = SetRemoteDescription(local_pc_wrapper, answer.get());
EXPECT_TRUE(Await({p1, p2}));
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
auto it = absl::c_find_if(
parameters.codecs, [](const auto& codec) { return codec.name == "VP8"; });
ASSERT_NE(it, parameters.codecs.end());
RtpCodecParameters& vp8_codec_from_parameters = *it;
EXPECT_THAT(vp8_codec_from_parameters.parameters,
Contains(Pair("non-standard-param", "true")));
parameters.encodings[0].codec = vp8_codec_from_parameters;
EXPECT_THAT(video_transceiver->sender()->SetParameters(parameters),
IsRtcOk());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersRejectsNonNegotiatedCodecParameterVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::optional<RtpCodecCapability> vp8 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp8");
ASSERT_TRUE(vp8);
std::vector<RtpCodecCapability> not_vp8_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
not_vp8_codecs.erase(
std::remove_if(not_vp8_codecs.begin(), not_vp8_codecs.end(),
[&](const auto& codec) {
return absl::EqualsIgnoreCase(codec.name, vp8->name);
}),
not_vp8_codecs.end());
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
ASSERT_TRUE(video_transceiver->SetCodecPreferences(not_vp8_codecs).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = vp8;
RTCError error = video_transceiver->sender()->SetParameters(parameters);
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersRejectsNonRemotelyNegotiatedCodecParameterVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::optional<RtpCodecCapability> vp8 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp8");
ASSERT_TRUE(vp8);
std::vector<RtpCodecCapability> not_vp8_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
not_vp8_codecs.erase(
std::remove_if(not_vp8_codecs.begin(), not_vp8_codecs.end(),
[&](const auto& codec) {
return absl::EqualsIgnoreCase(codec.name, vp8->name);
}),
not_vp8_codecs.end());
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
// Negotiation, create offer and apply it
std::unique_ptr<SessionDescriptionInterface> offer =
CreateOffer(local_pc_wrapper);
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p1 =
SetLocalDescription(local_pc_wrapper, offer.get());
rtc::scoped_refptr<MockSetSessionDescriptionObserver> p2 =
SetRemoteDescription(remote_pc_wrapper, offer.get());
EXPECT_TRUE(Await({p1, p2}));
// Update the remote transceiver to reject VP8
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remote_transceivers =
remote_pc_wrapper->pc()->GetTransceivers();
ASSERT_TRUE(!remote_transceivers.empty());
rtc::scoped_refptr<RtpTransceiverInterface> remote_video_transceiver =
remote_transceivers[0];
ASSERT_TRUE(
remote_video_transceiver->SetCodecPreferences(not_vp8_codecs).ok());
// Create answer and apply it
std::unique_ptr<SessionDescriptionInterface> answer =
CreateAnswer(remote_pc_wrapper);
p1 = SetLocalDescription(remote_pc_wrapper, answer.get());
p2 = SetRemoteDescription(local_pc_wrapper, answer.get());
EXPECT_TRUE(Await({p1, p2}));
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
parameters.encodings[0].codec = vp8;
RTCError error = video_transceiver->sender()->SetParameters(parameters);
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParametersCodecRemovedAfterNegotiationAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::optional<RtpCodecCapability> opus =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
"opus");
ASSERT_TRUE(opus);
std::vector<RtpCodecCapability> not_opus_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
.codecs;
not_opus_codecs.erase(
std::remove_if(not_opus_codecs.begin(), not_opus_codecs.end(),
[&](const auto& codec) {
return absl::EqualsIgnoreCase(codec.name, opus->name);
}),
not_opus_codecs.end());
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.codec = opus;
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
EXPECT_EQ(parameters.encodings[0].codec, opus);
ASSERT_TRUE(audio_transceiver->SetCodecPreferences(not_opus_codecs).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
parameters = audio_transceiver->sender()->GetParameters();
EXPECT_FALSE(parameters.encodings[0].codec);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParametersRedEnabledBeforeNegotiationAudio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<RtpCodecCapability> send_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
.codecs;
std::optional<RtpCodecCapability> opus =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
"opus");
ASSERT_TRUE(opus);
std::optional<RtpCodecCapability> red =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
"red");
ASSERT_TRUE(red);
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.codec = opus;
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
transceiver_or_error.MoveValue();
// Preferring RED over Opus should enable RED with Opus encoding.
send_codecs[0] = red.value();
send_codecs[1] = opus.value();
ASSERT_TRUE(audio_transceiver->SetCodecPreferences(send_codecs).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
RtpParameters parameters = audio_transceiver->sender()->GetParameters();
EXPECT_EQ(parameters.encodings[0].codec, opus);
EXPECT_EQ(parameters.codecs[0].name, red->name);
// Check that it's possible to switch back to Opus without RED.
send_codecs[0] = opus.value();
send_codecs[1] = red.value();
ASSERT_TRUE(audio_transceiver->SetCodecPreferences(send_codecs).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
parameters = audio_transceiver->sender()->GetParameters();
EXPECT_EQ(parameters.encodings[0].codec, opus);
EXPECT_EQ(parameters.codecs[0].name, opus->name);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
SetParametersRejectsScalabilityModeForSelectedCodec) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
std::optional<RtpCodecCapability> vp8 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp8");
ASSERT_TRUE(vp8);
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.codec = vp8;
encoding_parameters.scalability_mode = "L1T3";
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
parameters.encodings[0].scalability_mode = "L3T3";
RTCError error = video_transceiver->sender()->SetParameters(parameters);
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
EncodingParametersCodecRemovedByNegotiationVideo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::optional<RtpCodecCapability> vp8 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp8");
ASSERT_TRUE(vp8);
std::vector<RtpCodecCapability> not_vp8_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
not_vp8_codecs.erase(
std::remove_if(not_vp8_codecs.begin(), not_vp8_codecs.end(),
[&](const auto& codec) {
return absl::EqualsIgnoreCase(codec.name, vp8->name);
}),
not_vp8_codecs.end());
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.rid = "h";
encoding_parameters.codec = vp8;
encoding_parameters.scale_resolution_down_by = 2;
init.send_encodings.push_back(encoding_parameters);
encoding_parameters.rid = "f";
encoding_parameters.scale_resolution_down_by = 1;
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
transceiver_or_error.MoveValue();
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
RtpParameters parameters = video_transceiver->sender()->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 2u);
EXPECT_EQ(parameters.encodings[0].codec, vp8);
EXPECT_EQ(parameters.encodings[1].codec, vp8);
ASSERT_TRUE(video_transceiver->SetCodecPreferences(not_vp8_codecs).ok());
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
parameters = video_transceiver->sender()->GetParameters();
EXPECT_FALSE(parameters.encodings[0].codec);
EXPECT_FALSE(parameters.encodings[1].codec);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
AddTransceiverRejectsMixedCodecSimulcast) {
// Mixed Codec Simulcast is not yet supported, so we ensure that we reject
// such parameters.
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::optional<RtpCodecCapability> vp8 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp8");
ASSERT_TRUE(vp8);
std::optional<RtpCodecCapability> vp9 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp9");
ASSERT_TRUE(vp9);
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.rid = "h";
encoding_parameters.codec = vp8;
encoding_parameters.scale_resolution_down_by = 2;
init.send_encodings.push_back(encoding_parameters);
encoding_parameters.rid = "f";
encoding_parameters.codec = vp9;
encoding_parameters.scale_resolution_down_by = 1;
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
ASSERT_FALSE(transceiver_or_error.ok());
EXPECT_EQ(transceiver_or_error.error().type(),
RTCErrorType::UNSUPPORTED_OPERATION);
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
AddTransceiverAcceptsMixedCodecSimulcast) {
// Enable WIP mixed codec simulcast support
std::string field_trials = "WebRTC-MixedCodecSimulcast/Enabled/";
scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper =
CreatePc(FieldTrials::CreateNoGlobal(field_trials));
scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper =
CreatePc(FieldTrials::CreateNoGlobal(field_trials));
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::optional<RtpCodecCapability> vp8 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp8");
ASSERT_TRUE(vp8);
std::optional<RtpCodecCapability> vp9 =
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
"vp9");
ASSERT_TRUE(vp9);
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kSendOnly;
RtpEncodingParameters encoding_parameters;
encoding_parameters.rid = "h";
encoding_parameters.codec = vp8;
encoding_parameters.scale_resolution_down_by = 2;
init.send_encodings.push_back(encoding_parameters);
encoding_parameters.rid = "f";
encoding_parameters.codec = vp9;
encoding_parameters.scale_resolution_down_by = 1;
init.send_encodings.push_back(encoding_parameters);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
ASSERT_TRUE(transceiver_or_error.ok());
}
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
TEST_F(PeerConnectionEncodingsIntegrationTest, ScaleToParameterChecking) {
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper = CreatePc();
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// AddTransceiver: If `scale_resolution_down_to` is specified on any encoding
// it must be specified on all encodings.
RtpTransceiverInit init;
RtpEncodingParameters encoding;
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
encoding.scale_resolution_down_to = std::nullopt;
init.send_encodings.push_back(encoding);
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
encoding.scale_resolution_down_to = {.width = 1280, .height = 720};
init.send_encodings.push_back(encoding);
auto transceiver_or_error =
pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
EXPECT_FALSE(transceiver_or_error.ok());
EXPECT_EQ(transceiver_or_error.error().type(),
RTCErrorType::UNSUPPORTED_OPERATION);
// AddTransceiver: Width and height must not be zero.
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
init.send_encodings[0].scale_resolution_down_to = {.width = 1280,
.height = 0};
init.send_encodings[1].scale_resolution_down_to = {.width = 0, .height = 720};
transceiver_or_error =
pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
EXPECT_FALSE(transceiver_or_error.ok());
EXPECT_EQ(transceiver_or_error.error().type(),
RTCErrorType::UNSUPPORTED_OPERATION);
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// AddTransceiver: Specifying both `scale_resolution_down_to` and
// `scale_resolution_down_by` is allowed (the latter is ignored).
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
init.send_encodings[0].scale_resolution_down_to = {.width = 640,
.height = 480};
init.send_encodings[0].scale_resolution_down_by = 1.0;
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
init.send_encodings[1].scale_resolution_down_to = {.width = 1280,
.height = 720};
init.send_encodings[1].scale_resolution_down_by = 2.0;
transceiver_or_error =
pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
ASSERT_TRUE(transceiver_or_error.ok());
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// SetParameters: If `scale_resolution_down_to` is specified on any active
// encoding it must be specified on all active encodings.
auto sender = transceiver_or_error.value()->sender();
auto parameters = sender->GetParameters();
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 640,
.height = 480};
parameters.encodings[1].scale_resolution_down_to = std::nullopt;
auto error = sender->SetParameters(parameters);
EXPECT_FALSE(error.ok());
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// But it's OK not to specify `scale_resolution_down_to` on an inactive
// encoding.
parameters = sender->GetParameters();
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 640,
.height = 480};
parameters.encodings[1].active = false;
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[1].scale_resolution_down_to = std::nullopt;
error = sender->SetParameters(parameters);
EXPECT_TRUE(error.ok());
// SetParameters: Width and height must not be zero.
sender = transceiver_or_error.value()->sender();
parameters = sender->GetParameters();
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 1280,
.height = 0};
parameters.encodings[1].active = true;
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[1].scale_resolution_down_to = {.width = 0,
.height = 720};
error = sender->SetParameters(parameters);
EXPECT_FALSE(error.ok());
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// SetParameters: Specifying both `scale_resolution_down_to` and
// `scale_resolution_down_by` is allowed (the latter is ignored).
parameters = sender->GetParameters();
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 640,
.height = 480};
parameters.encodings[0].scale_resolution_down_by = 2.0;
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[1].scale_resolution_down_to = {.width = 1280,
.height = 720};
parameters.encodings[1].scale_resolution_down_by = 1.0;
error = sender->SetParameters(parameters);
EXPECT_TRUE(error.ok());
}
TEST_F(PeerConnectionEncodingsIntegrationTest,
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
ScaleResolutionDownByIsIgnoredWhenScaleToIsSpecified) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
rtc::scoped_refptr<MediaStreamInterface> stream =
local_pc_wrapper->GetUserMedia(
/*audio=*/false, {}, /*video=*/true, {.width = 640, .height = 360});
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
// Configure contradicting scaling factors (180p vs 360p).
RtpTransceiverInit init;
RtpEncodingParameters encoding;
encoding.scale_resolution_down_by = 2.0;
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
encoding.scale_resolution_down_to = {.width = 640, .height = 360};
init.send_encodings.push_back(encoding);
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(track, init);
// Negotiate singlecast.
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
Negotiate(local_pc_wrapper, remote_pc_wrapper);
// Confirm 640x360 is sent.
// If `scale_resolution_down_by` was not ignored we would never ramp up to
// full resolution.
EXPECT_THAT(
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(ElementsAre(ResolutionIs(640, 360))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
}
// Tests that use the standard path (specifying both `scalability_mode` and
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// `scale_resolution_down_by` or `scale_resolution_down_to`) should pass for all
// codecs.
class PeerConnectionEncodingsIntegrationParameterizedTest
: public PeerConnectionEncodingsIntegrationTest,
public ::testing::WithParamInterface<std::string> {
public:
PeerConnectionEncodingsIntegrationParameterizedTest()
: codec_name_(GetParam()), mime_type_("video/" + codec_name_) {}
// Work-around for the fact that whether or not AV1 is supported is not known
// at compile-time so we have to skip tests early if missing.
// TODO(https://crbug.com/webrtc/15011): Increase availability of AV1 or make
// it possible to check support at compile-time.
bool SkipTestDueToAv1Missing(
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper) {
if (codec_name_ == "AV1" &&
!HasReceiverVideoCodecCapability(local_pc_wrapper, "AV1")) {
RTC_LOG(LS_WARNING) << "\n***\nAV1 is not available, skipping test.\n***";
return true;
}
return false;
}
protected:
const std::string codec_name_; // E.g. "VP9"
const std::string mime_type_; // E.g. "video/VP9"
};
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, AllLayersInactive) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f", "h", "q"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
// Standard mode and all layers inactive.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].scalability_mode = "L1T3";
parameters.encodings[0].scale_resolution_down_by = 1;
parameters.encodings[0].active = false;
parameters.encodings[1].active = false;
parameters.encodings[2].active = false;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Ensure no media is flowing (1 second should be enough).
rtc::Thread::Current()->SleepMs(1000);
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(3u));
EXPECT_EQ(*outbound_rtps[0]->bytes_sent, 0u);
EXPECT_EQ(*outbound_rtps[1]->bytes_sent, 0u);
EXPECT_EQ(*outbound_rtps[2]->bytes_sent, 0u);
}
// Configure 4:2:1 using `scale_resolution_down_by`.
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, Simulcast) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].scalability_mode = "L1T3";
parameters.encodings[0].scale_resolution_down_by = 4;
parameters.encodings[1].scalability_mode = "L1T3";
parameters.encodings[1].scale_resolution_down_by = 2;
parameters.encodings[2].scalability_mode = "L1T3";
parameters.encodings[2].scale_resolution_down_by = 1;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// GetParameters() does not report any fallback.
parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(std::string("L1T3")));
EXPECT_THAT(parameters.encodings[1].scalability_mode,
Optional(std::string("L1T3")));
EXPECT_THAT(parameters.encodings[2].scalability_mode,
Optional(std::string("L1T3")));
// Wait until media is flowing on all three layers.
// Ramp up time is needed before all three layers are sending.
auto error_or_report =
GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(3u),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(error_or_report, IsRtcOk());
// Verify codec and scalability mode.
rtc::scoped_refptr<const RTCStatsReport> report = error_or_report.value();
auto outbound_rtp_by_rid = GetOutboundRtpStreamStatsByRid(report);
EXPECT_THAT(outbound_rtp_by_rid,
UnorderedElementsAre(Pair("q", ResolutionIs(320, 180)),
Pair("h", ResolutionIs(640, 360)),
Pair("f", ResolutionIs(1280, 720))));
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(3u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq(mime_type_));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]),
StrCaseEq(mime_type_));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]),
StrCaseEq(mime_type_));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T3"));
EXPECT_THAT(*outbound_rtps[1]->scalability_mode, StrEq("L1T3"));
EXPECT_THAT(*outbound_rtps[2]->scalability_mode, StrEq("L1T3"));
}
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// Configure 4:2:1 using `scale_resolution_down_to`.
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
SimulcastWithScaleTo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].scalability_mode = "L1T3";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 320,
.height = 180};
parameters.encodings[1].scalability_mode = "L1T3";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[1].scale_resolution_down_to = {.width = 640,
.height = 360};
parameters.encodings[2].scalability_mode = "L1T3";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[2].scale_resolution_down_to = {.width = 1280,
.height = 720};
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// GetParameters() does not report any fallback.
parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(std::string("L1T3")));
EXPECT_THAT(parameters.encodings[1].scalability_mode,
Optional(std::string("L1T3")));
EXPECT_THAT(parameters.encodings[2].scalability_mode,
Optional(std::string("L1T3")));
// Wait until media is flowing on all three layers.
// Ramp up time is needed before all three layers are sending.
auto error_or_report =
GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(3u),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(error_or_report, IsRtcOk());
// Verify codec and scalability mode.
rtc::scoped_refptr<const RTCStatsReport> report = error_or_report.value();
auto outbound_rtp_by_rid = GetOutboundRtpStreamStatsByRid(report);
EXPECT_THAT(outbound_rtp_by_rid,
UnorderedElementsAre(Pair("q", ResolutionIs(320, 180)),
Pair("h", ResolutionIs(640, 360)),
Pair("f", ResolutionIs(1280, 720))));
// Verify codec and scalability mode.
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(3u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq(mime_type_));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]),
StrCaseEq(mime_type_));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]),
StrCaseEq(mime_type_));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T3"));
EXPECT_THAT(*outbound_rtps[1]->scalability_mode, StrEq("L1T3"));
EXPECT_THAT(*outbound_rtps[2]->scalability_mode, StrEq("L1T3"));
}
// Simulcast starting in 720p 4:2:1 then changing to {180p, 360p, 540p} using
// the `scale_resolution_down_by` API.
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
SimulcastScaleDownByNoLongerPowerOfTwo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
// Configure {180p, 360p, 720p}.
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].scalability_mode = "L1T1";
parameters.encodings[0].scale_resolution_down_by = 4.0;
parameters.encodings[1].scalability_mode = "L1T1";
parameters.encodings[1].scale_resolution_down_by = 2.0;
parameters.encodings[2].scalability_mode = "L1T1";
parameters.encodings[2].scale_resolution_down_by = 1.0;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait for media to flow on all layers.
// Needed repro step of https://crbug.com/webrtc/369654168: When the same
// LibvpxVp9Encoder instance was used to first produce simulcast and later for
// a single encoding, the previously used simulcast index (= 2) would still be
// set when producing 180p since non-simulcast config does not reset this,
// resulting in the 180p encoding freezing and the 540p encoding having double
// frame rate and toggling between 180p and 540p in resolution.
ASSERT_THAT(GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(3u),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
// Configure {180p, 360p, 540p}.
parameters = sender->GetParameters();
parameters.encodings[0].scale_resolution_down_by = 4.0;
parameters.encodings[1].scale_resolution_down_by = 2.0;
parameters.encodings[2].scale_resolution_down_by = 1.333333;
sender->SetParameters(parameters);
// Wait for the new resolutions to be produced.
auto encoding_resolutions_result =
WaitUntil([&] { return GetStats(local_pc_wrapper); },
OutboundRtpStatsAre(UnorderedElementsAre(
AllOf(RidIs("q"), ResolutionIs(320, 180)),
AllOf(RidIs("h"), ResolutionIs(640, 360)),
AllOf(RidIs("f"), ResolutionIs(960, 540)))),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(encoding_resolutions_result, IsRtcOk());
auto outbound_rtp_by_rid =
GetOutboundRtpStreamStatsByRid(encoding_resolutions_result.value());
ASSERT_THAT(outbound_rtp_by_rid,
UnorderedElementsAre(Key("q"), Key("h"), Key("f")));
// Ensure frames continue to be encoded post reconfiguration.
uint64_t frames_encoded_q =
outbound_rtp_by_rid.at("q").frames_encoded.value();
uint64_t frames_encoded_h =
outbound_rtp_by_rid.at("h").frames_encoded.value();
uint64_t frames_encoded_f =
outbound_rtp_by_rid.at("f").frames_encoded.value();
EXPECT_THAT(
GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(UnorderedElementsAre(
AllOf(RidIs("q"), FramesEncodedIs(Gt(frames_encoded_q))),
AllOf(RidIs("h"), FramesEncodedIs(Gt(frames_encoded_h))),
AllOf(RidIs("f"), FramesEncodedIs(Gt(frames_encoded_f))))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
}
// Simulcast starting in 720p 4:2:1 then changing to {180p, 360p, 540p} using
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// the `scale_resolution_down_to` API.
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
SimulcastScaleToNoLongerPowerOfTwo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
// Configure {180p, 360p, 720p}.
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].scalability_mode = "L1T1";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 320,
.height = 180};
parameters.encodings[1].scalability_mode = "L1T1";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[1].scale_resolution_down_to = {.width = 640,
.height = 360};
parameters.encodings[2].scalability_mode = "L1T1";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[2].scale_resolution_down_to = {.width = 1280,
.height = 720};
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait for media to flow on all layers.
// Needed repro step of https://crbug.com/webrtc/369654168: When the same
// LibvpxVp9Encoder instance was used to first produce simulcast and later for
// a single encoding, the previously used simulcast index (= 2) would still be
// set when producing 180p since non-simulcast config does not reset this,
// resulting in the 180p encoding freezing and the 540p encoding having double
// frame rate and toggling between 180p and 540p in resolution.
ASSERT_THAT(GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(3u),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
// Configure {180p, 360p, 540p}.
parameters = sender->GetParameters();
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 320,
.height = 180};
parameters.encodings[1].scale_resolution_down_to = {.width = 640,
.height = 360};
parameters.encodings[2].scale_resolution_down_to = {.width = 960,
.height = 540};
sender->SetParameters(parameters);
// Wait for the new resolutions to be produced.
auto error_or_stats =
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(UnorderedElementsAre(
AllOf(RidIs("q"), ResolutionIs(320, 180)),
AllOf(RidIs("h"), ResolutionIs(640, 360)),
AllOf(RidIs("f"), ResolutionIs(960, 540)))),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(error_or_stats, IsRtcOk());
auto outbound_rtp_by_rid =
GetOutboundRtpStreamStatsByRid(error_or_stats.value());
ASSERT_THAT(outbound_rtp_by_rid,
UnorderedElementsAre(Pair("q", BytesSentIs(Ne(std::nullopt))),
Pair("h", BytesSentIs(Ne(std::nullopt))),
Pair("f", BytesSentIs(Ne(std::nullopt)))));
// Ensure frames continue to be encoded post reconfiguration.
EXPECT_THAT(
GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(UnorderedElementsAre(
AllOf(RidIs("q"),
BytesSentIs(
Gt(outbound_rtp_by_rid.at("q").bytes_sent.value()))),
AllOf(RidIs("h"),
BytesSentIs(
Gt(outbound_rtp_by_rid.at("h").bytes_sent.value()))),
AllOf(RidIs("f"),
BytesSentIs(
Gt(outbound_rtp_by_rid.at("f").bytes_sent.value()))))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
}
// The code path that disables layers based on resolution size should NOT run
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
// when `scale_resolution_down_to` is specified. (It shouldn't run in any case
// but that is an existing legacy code and non-compliance problem that we don't
// have to repeat here.)
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
LowResolutionSimulcastWithScaleTo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
// Configure {20p,40p,80p} with 2:1 aspect ratio.
RtpTransceiverInit init;
RtpEncodingParameters encoding;
encoding.scalability_mode = "L1T3";
encoding.rid = "q";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
encoding.scale_resolution_down_to = {.width = 40, .height = 20};
init.send_encodings.push_back(encoding);
encoding.rid = "h";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
encoding.scale_resolution_down_to = {.width = 80, .height = 40};
init.send_encodings.push_back(encoding);
encoding.rid = "f";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
encoding.scale_resolution_down_to = {.width = 160, .height = 80};
init.send_encodings.push_back(encoding);
rtc::scoped_refptr<MediaStreamInterface> stream =
local_pc_wrapper->GetUserMedia(
/*audio=*/false, {}, /*video=*/true, {.width = 160, .height = 80});
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
auto transceiver_or_error =
local_pc_wrapper->pc()->AddTransceiver(track, init);
ASSERT_TRUE(transceiver_or_error.ok());
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
transceiver_or_error.value();
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait for media to flow on all layers.
ASSERT_THAT(GetStatsUntil(local_pc_wrapper, HasOutboundRtpBytesSent(3u)),
IsRtcOk());
// q=20p, h=40p, f=80p.
EXPECT_THAT(GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(UnorderedElementsAre(
AllOf(RidIs("q"), ResolutionIs(40, 20)),
AllOf(RidIs("h"), ResolutionIs(80, 40)),
AllOf(RidIs("f"), ResolutionIs(160, 80)))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
}
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
SimulcastEncodingStopWhenRtpEncodingChangeToInactive) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
ASSERT_EQ(parameters.encodings[0].rid, "q");
parameters.encodings[0].scalability_mode = "L1T3";
parameters.encodings[0].scale_resolution_down_by = 4;
ASSERT_EQ(parameters.encodings[1].rid, "h");
parameters.encodings[1].scalability_mode = "L1T3";
parameters.encodings[1].scale_resolution_down_by = 2;
ASSERT_EQ(parameters.encodings[2].rid, "f");
parameters.encodings[2].scalability_mode = "L1T3";
parameters.encodings[2].scale_resolution_down_by = 1;
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
ASSERT_THAT(GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(Contains(
AllOf(RidIs("f"), FramesEncodedIs(Gt(0))))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
// Switch higest layer to Inactive.
parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[2].active = false;
sender->SetParameters(parameters);
auto error_or_stats = GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(Contains(AllOf(RidIs("f"), Not(Active())))),
{.timeout = kLongTimeoutForRampingUp});
ASSERT_THAT(error_or_stats, IsRtcOk());
auto outbound_rtp_by_rid =
GetOutboundRtpStreamStatsByRid(error_or_stats.value());
int encoded_frames_f = outbound_rtp_by_rid.at("f").frames_encoded.value();
int encoded_frames_h = outbound_rtp_by_rid.at("h").frames_encoded.value();
int encoded_frames_q = outbound_rtp_by_rid.at("q").frames_encoded.value();
// Wait until the encoder has encoded another 10 frames on lower layers.
ASSERT_THAT(
GetStatsUntil(
local_pc_wrapper,
OutboundRtpStatsAre(UnorderedElementsAre(
AllOf(RidIs("q"), FramesEncodedIs(Gt(encoded_frames_q + 10))),
AllOf(RidIs("h"), FramesEncodedIs(Gt(encoded_frames_h + 10))),
AllOf(RidIs("f"), FramesEncodedIs(Le(encoded_frames_f + 2))))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
}
Fix requested_resolution bug where we get stuck with old restrictions. Normally (scaleResolutionDownBy) restrictions are applied at the source which changes the input frame size which triggers reconfiguration with appropriate scaling factors. But when requested_resolution is used, encoder settings are by definition not relative to the input frame size. In order for restrictions to have an effect, they are applied inside ReconfigureEncoder(): you get the minimum between the requested resolution and the restricted resolution. ReconfigureEncoder() happens when you SetParameters(), but the bug here is that we don't do it again once the restrictions are updated. So if restrictions are 540p when you ask for 720p, you get 540p and after restrictions change to unlimited you're still stuck in 540p. The fix is to also trigger ReconfigureEncoder() inside OnVideoSourceRestrictionsUpdated() when the restricted resolution is changing and a requested_resolution is configured. To ensure reconfiguring the encoder "on the fly" like this does not reset initial frame dropping logic, InitialFrameDropper caring about input frame size changing is made conditional on not using requested_resolution. # Slow purple bots failing but they are not affected by this change. NOTRY=True Bug: webrtc:361477261 Change-Id: I1389aa16cf408b0d14e0b5b6f68c2442db955be9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/360200 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42882}
2024-08-23 11:16:37 +02:00
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
ScaleToDownscaleAndThenUpscale) {
Fix requested_resolution bug where we get stuck with old restrictions. Normally (scaleResolutionDownBy) restrictions are applied at the source which changes the input frame size which triggers reconfiguration with appropriate scaling factors. But when requested_resolution is used, encoder settings are by definition not relative to the input frame size. In order for restrictions to have an effect, they are applied inside ReconfigureEncoder(): you get the minimum between the requested resolution and the restricted resolution. ReconfigureEncoder() happens when you SetParameters(), but the bug here is that we don't do it again once the restrictions are updated. So if restrictions are 540p when you ask for 720p, you get 540p and after restrictions change to unlimited you're still stuck in 540p. The fix is to also trigger ReconfigureEncoder() inside OnVideoSourceRestrictionsUpdated() when the restricted resolution is changing and a requested_resolution is configured. To ensure reconfiguring the encoder "on the fly" like this does not reset initial frame dropping logic, InitialFrameDropper caring about input frame size changing is made conditional on not using requested_resolution. # Slow purple bots failing but they are not affected by this change. NOTRY=True Bug: webrtc:361477261 Change-Id: I1389aa16cf408b0d14e0b5b6f68c2442db955be9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/360200 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42882}
2024-08-23 11:16:37 +02:00
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
// This transceiver receives a 1280x720 source.
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Request 640x360, which is the same as scaling down by 2.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(1));
parameters.encodings[0].scalability_mode = "L1T3";
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 640,
.height = 360};
Fix requested_resolution bug where we get stuck with old restrictions. Normally (scaleResolutionDownBy) restrictions are applied at the source which changes the input frame size which triggers reconfiguration with appropriate scaling factors. But when requested_resolution is used, encoder settings are by definition not relative to the input frame size. In order for restrictions to have an effect, they are applied inside ReconfigureEncoder(): you get the minimum between the requested resolution and the restricted resolution. ReconfigureEncoder() happens when you SetParameters(), but the bug here is that we don't do it again once the restrictions are updated. So if restrictions are 540p when you ask for 720p, you get 540p and after restrictions change to unlimited you're still stuck in 540p. The fix is to also trigger ReconfigureEncoder() inside OnVideoSourceRestrictionsUpdated() when the restricted resolution is changing and a requested_resolution is configured. To ensure reconfiguring the encoder "on the fly" like this does not reset initial frame dropping logic, InitialFrameDropper caring about input frame size changing is made conditional on not using requested_resolution. # Slow purple bots failing but they are not affected by this change. NOTRY=True Bug: webrtc:361477261 Change-Id: I1389aa16cf408b0d14e0b5b6f68c2442db955be9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/360200 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42882}
2024-08-23 11:16:37 +02:00
sender->SetParameters(parameters);
// Confirm 640x360 is sent.
ASSERT_THAT(
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(ElementsAre(ResolutionIs(640, 360))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
Fix requested_resolution bug where we get stuck with old restrictions. Normally (scaleResolutionDownBy) restrictions are applied at the source which changes the input frame size which triggers reconfiguration with appropriate scaling factors. But when requested_resolution is used, encoder settings are by definition not relative to the input frame size. In order for restrictions to have an effect, they are applied inside ReconfigureEncoder(): you get the minimum between the requested resolution and the restricted resolution. ReconfigureEncoder() happens when you SetParameters(), but the bug here is that we don't do it again once the restrictions are updated. So if restrictions are 540p when you ask for 720p, you get 540p and after restrictions change to unlimited you're still stuck in 540p. The fix is to also trigger ReconfigureEncoder() inside OnVideoSourceRestrictionsUpdated() when the restricted resolution is changing and a requested_resolution is configured. To ensure reconfiguring the encoder "on the fly" like this does not reset initial frame dropping logic, InitialFrameDropper caring about input frame size changing is made conditional on not using requested_resolution. # Slow purple bots failing but they are not affected by this change. NOTRY=True Bug: webrtc:361477261 Change-Id: I1389aa16cf408b0d14e0b5b6f68c2442db955be9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/360200 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42882}
2024-08-23 11:16:37 +02:00
// Test coverage for https://crbug.com/webrtc/361477261:
// Due initial frame dropping, OnFrameDroppedDueToSize() should have created
// some resolution restrictions by now. With 720p input frame, restriction is
// 540p which is not observable when sending 360p, but it prevents us from
// immediately sending 720p. Restrictions will be lifted after a few seconds
// (when good QP is reported by QualityScaler) and 720p should be sent. The
// bug was not reconfiguring the encoder when restrictions were updated so the
// restrictions at the time of the SetParameter() call were made indefinite.
// Request the full 1280x720 resolution.
parameters = sender->GetParameters();
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 1280,
.height = 720};
Fix requested_resolution bug where we get stuck with old restrictions. Normally (scaleResolutionDownBy) restrictions are applied at the source which changes the input frame size which triggers reconfiguration with appropriate scaling factors. But when requested_resolution is used, encoder settings are by definition not relative to the input frame size. In order for restrictions to have an effect, they are applied inside ReconfigureEncoder(): you get the minimum between the requested resolution and the restricted resolution. ReconfigureEncoder() happens when you SetParameters(), but the bug here is that we don't do it again once the restrictions are updated. So if restrictions are 540p when you ask for 720p, you get 540p and after restrictions change to unlimited you're still stuck in 540p. The fix is to also trigger ReconfigureEncoder() inside OnVideoSourceRestrictionsUpdated() when the restricted resolution is changing and a requested_resolution is configured. To ensure reconfiguring the encoder "on the fly" like this does not reset initial frame dropping logic, InitialFrameDropper caring about input frame size changing is made conditional on not using requested_resolution. # Slow purple bots failing but they are not affected by this change. NOTRY=True Bug: webrtc:361477261 Change-Id: I1389aa16cf408b0d14e0b5b6f68c2442db955be9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/360200 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42882}
2024-08-23 11:16:37 +02:00
sender->SetParameters(parameters);
// Confirm 1280x720 is sent.
EXPECT_THAT(
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(ElementsAre(ResolutionIs(1280, 720))),
{.timeout = kLongTimeoutForRampingUp}),
IsRtcOk());
Fix requested_resolution bug where we get stuck with old restrictions. Normally (scaleResolutionDownBy) restrictions are applied at the source which changes the input frame size which triggers reconfiguration with appropriate scaling factors. But when requested_resolution is used, encoder settings are by definition not relative to the input frame size. In order for restrictions to have an effect, they are applied inside ReconfigureEncoder(): you get the minimum between the requested resolution and the restricted resolution. ReconfigureEncoder() happens when you SetParameters(), but the bug here is that we don't do it again once the restrictions are updated. So if restrictions are 540p when you ask for 720p, you get 540p and after restrictions change to unlimited you're still stuck in 540p. The fix is to also trigger ReconfigureEncoder() inside OnVideoSourceRestrictionsUpdated() when the restricted resolution is changing and a requested_resolution is configured. To ensure reconfiguring the encoder "on the fly" like this does not reset initial frame dropping logic, InitialFrameDropper caring about input frame size changing is made conditional on not using requested_resolution. # Slow purple bots failing but they are not affected by this change. NOTRY=True Bug: webrtc:361477261 Change-Id: I1389aa16cf408b0d14e0b5b6f68c2442db955be9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/360200 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42882}
2024-08-23 11:16:37 +02:00
}
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
ScaleToIsOrientationAgnostic) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
// This transceiver receives a 1280x720 source.
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// 360x640 is the same as 640x360 due to orientation agnosticism.
// The orientation is determined by the frame (1280x720): landscape.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(1));
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 360,
.height = 640};
sender->SetParameters(parameters);
// Confirm 640x360 is sent.
EXPECT_THAT(
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(ElementsAre(ResolutionIs(640, 360)))),
IsRtcOk());
}
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
ScaleToMaintainsAspectRatio) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
// This transceiver receives a 1280x720 source.
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Restrict height more than width, the scaling factor needed on height should
// also be applied on the width in order to maintain the frame aspect ratio.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(1));
Reland "Rename `requested_resolution` to `scale_resolution_down_to`." This is a reland of commit 82617ac51e7825db53451818f4d1ad52b69761fd The reason for the revert was a downstream use of `rtc::VideoSinkWants::requested_resolution`, so in this reland we don't rename this field, it's fine just to rename the one in RtpEncodingParameters for now. Original change's description: > Rename `requested_resolution` to `scale_resolution_down_to`. > > This is a pure refactor/rename CL without any changes in behavior. > > This field is called scaleResolutionDownTo in the spec and JavaScript. > Let's make C++ match to avoid confusion. > > In order not to break downstream during the transition a variable with > the old name being a pure reference to the renamed attribute is added. > This means we have to add custom constructors, but we can change this > back to "= default" when the transition is completed, which should only > be a couple of CLs away. > > Bug: webrtc:375048799 > Change-Id: If755102ccd79d46020ce5b33acd3dfcc29799e47 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366560 > Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Commit-Queue: Henrik Boström <hbos@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#43300} NOTRY=True Bug: webrtc:375048799 Change-Id: Ic4ee156c1d50aa36070a8d84059870791dcbbe5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/366660 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43304}
2024-10-25 09:51:44 +02:00
parameters.encodings[0].scale_resolution_down_to = {.width = 1280,
.height = 360};
sender->SetParameters(parameters);
// Confirm 640x360 is sent.
EXPECT_THAT(
GetStatsUntil(local_pc_wrapper,
OutboundRtpStatsAre(ElementsAre(ResolutionIs(640, 360)))),
IsRtcOk());
}
INSTANTIATE_TEST_SUITE_P(StandardPath,
PeerConnectionEncodingsIntegrationParameterizedTest,
::testing::Values("VP8",
"VP9",
#if defined(WEBRTC_USE_H264)
"H264",
#endif // defined(WEBRTC_USE_H264)
"AV1"),
StringParamToString());
2025-01-17 12:06:53 +01:00
// These tests use fake encoders and decoders, allowing testing of codec
// preferences, SDP negotiation and get/setParamaters(). But because the codecs
// implementations are fake, these tests do not encode or decode any frames.
class PeerConnectionEncodingsFakeCodecsIntegrationTest
: public PeerConnectionEncodingsIntegrationTest {
public:
Add unidirectional codec support ("offer to send" use case). This CL implements allowing sendonly codecs in setCodecPreferences(), i.e. this spec PR: https://github.com/w3c/webrtc-pc/pull/3018. It also makes the setCodecPreferences() ignore level IDs in the filtering algorithm (but not in the sCP method call) as per this spec PR: https://github.com/w3c/webrtc-pc/pull/3023. In short, before this CL, setCodecPreferences() threw an exception if a codec was preferred that is not present in receiver codec capabilities. After this CL, setCodecPreferences() allows you to prefer codecs that are *either* in the sender capabilities *or* the receiver capabilities. - This allows you to "offer to send", i.e. prefer sendonly codecs on a sendonly transceiver. - The filtering on direction is handled by RtpTransceiver::filtered_codec_preferences() which is called during SDP offer/answer (sdp_offer_answer.cc). Also as per spec changes, if this filtering results in not having any codecs to offer or answer then this results in not having any codec preferences as opposed to throwing an exception (old behavior). - Two old peer_connection_media_unittest.cc tests are updated to reflect the API failing less. This CL adds both unit tests (rtp_transceiver_unittest.cc) and full stack integration tests (peer_connection_encodings_integrationtest.cc). It also makes us pass the following Web Platform Tests in Chrome: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/external/wpt/webrtc/protocol/h265-level-id.https.html Bug: chromium:381407888 Change-Id: I98a5ad1acccb56db0538e4d47975b8a725102c33 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/374520 Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Evan Shrubsole <eshr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43788}
2025-01-22 15:13:37 +01:00
#ifdef RTC_ENABLE_H265
2025-01-17 12:06:53 +01:00
scoped_refptr<PeerConnectionTestWrapper> CreatePcWithFakeH265(
std::unique_ptr<FieldTrialsView> field_trials = nullptr) {
std::unique_ptr<cricket::FakeWebRtcVideoEncoderFactory>
video_encoder_factory =
std::make_unique<cricket::FakeWebRtcVideoEncoderFactory>();
video_encoder_factory->AddSupportedVideoCodec(
SdpVideoFormat("H265",
{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "156"},
{"tx-mode", "SRST"}},
{ScalabilityMode::kL1T1}));
std::unique_ptr<cricket::FakeWebRtcVideoDecoderFactory>
video_decoder_factory =
std::make_unique<cricket::FakeWebRtcVideoDecoderFactory>();
video_decoder_factory->AddSupportedVideoCodecType("H265");
auto pc_wrapper = make_ref_counted<PeerConnectionTestWrapper>(
"pc", &pss_, background_thread_.get(), background_thread_.get());
pc_wrapper->CreatePc(
{}, CreateBuiltinAudioEncoderFactory(),
CreateBuiltinAudioDecoderFactory(), std::move(video_encoder_factory),
std::move(video_decoder_factory), std::move(field_trials));
return pc_wrapper;
}
Add unidirectional codec support ("offer to send" use case). This CL implements allowing sendonly codecs in setCodecPreferences(), i.e. this spec PR: https://github.com/w3c/webrtc-pc/pull/3018. It also makes the setCodecPreferences() ignore level IDs in the filtering algorithm (but not in the sCP method call) as per this spec PR: https://github.com/w3c/webrtc-pc/pull/3023. In short, before this CL, setCodecPreferences() threw an exception if a codec was preferred that is not present in receiver codec capabilities. After this CL, setCodecPreferences() allows you to prefer codecs that are *either* in the sender capabilities *or* the receiver capabilities. - This allows you to "offer to send", i.e. prefer sendonly codecs on a sendonly transceiver. - The filtering on direction is handled by RtpTransceiver::filtered_codec_preferences() which is called during SDP offer/answer (sdp_offer_answer.cc). Also as per spec changes, if this filtering results in not having any codecs to offer or answer then this results in not having any codec preferences as opposed to throwing an exception (old behavior). - Two old peer_connection_media_unittest.cc tests are updated to reflect the API failing less. This CL adds both unit tests (rtp_transceiver_unittest.cc) and full stack integration tests (peer_connection_encodings_integrationtest.cc). It also makes us pass the following Web Platform Tests in Chrome: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/external/wpt/webrtc/protocol/h265-level-id.https.html Bug: chromium:381407888 Change-Id: I98a5ad1acccb56db0538e4d47975b8a725102c33 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/374520 Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Evan Shrubsole <eshr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43788}
2025-01-22 15:13:37 +01:00
#endif // RTC_ENABLE_H265
// Creates a PC where we have H264 with one sendonly, one recvonly and one
// sendrecv "profile-level-id". The sendrecv one is constrained baseline.
scoped_refptr<PeerConnectionTestWrapper> CreatePcWithUnidirectionalH264(
std::unique_ptr<FieldTrialsView> field_trials = nullptr) {
std::unique_ptr<cricket::FakeWebRtcVideoEncoderFactory>
video_encoder_factory =
std::make_unique<cricket::FakeWebRtcVideoEncoderFactory>();
SdpVideoFormat h264_constrained_baseline =
SdpVideoFormat("H264",
{{"level-asymmetry-allowed", "1"},
{"packetization-mode", "1"},
{"profile-level-id", "42f00b"}}, // sendrecv
{ScalabilityMode::kL1T1});
video_encoder_factory->AddSupportedVideoCodec(h264_constrained_baseline);
video_encoder_factory->AddSupportedVideoCodec(
SdpVideoFormat("H264",
{{"level-asymmetry-allowed", "1"},
{"packetization-mode", "1"},
{"profile-level-id", "640034"}}, // sendonly
{ScalabilityMode::kL1T1}));
std::unique_ptr<cricket::FakeWebRtcVideoDecoderFactory>
video_decoder_factory =
std::make_unique<cricket::FakeWebRtcVideoDecoderFactory>();
video_decoder_factory->AddSupportedVideoCodec(h264_constrained_baseline);
video_decoder_factory->AddSupportedVideoCodec(
SdpVideoFormat("H264",
{{"level-asymmetry-allowed", "1"},
{"packetization-mode", "1"},
{"profile-level-id", "f4001f"}}, // recvonly
{ScalabilityMode::kL1T1}));
auto pc_wrapper = make_ref_counted<PeerConnectionTestWrapper>(
"pc", &pss_, background_thread_.get(), background_thread_.get());
pc_wrapper->CreatePc(
{}, CreateBuiltinAudioEncoderFactory(),
CreateBuiltinAudioDecoderFactory(), std::move(video_encoder_factory),
std::move(video_decoder_factory), std::move(field_trials));
return pc_wrapper;
}
std::string LocalDescriptionStr(PeerConnectionTestWrapper* pc_wrapper) {
const SessionDescriptionInterface* local_description =
pc_wrapper->pc()->local_description();
if (!local_description) {
return "";
}
std::string str;
if (!local_description->ToString(&str)) {
return "";
}
return str;
}
2025-01-17 12:06:53 +01:00
};
Add unidirectional codec support ("offer to send" use case). This CL implements allowing sendonly codecs in setCodecPreferences(), i.e. this spec PR: https://github.com/w3c/webrtc-pc/pull/3018. It also makes the setCodecPreferences() ignore level IDs in the filtering algorithm (but not in the sCP method call) as per this spec PR: https://github.com/w3c/webrtc-pc/pull/3023. In short, before this CL, setCodecPreferences() threw an exception if a codec was preferred that is not present in receiver codec capabilities. After this CL, setCodecPreferences() allows you to prefer codecs that are *either* in the sender capabilities *or* the receiver capabilities. - This allows you to "offer to send", i.e. prefer sendonly codecs on a sendonly transceiver. - The filtering on direction is handled by RtpTransceiver::filtered_codec_preferences() which is called during SDP offer/answer (sdp_offer_answer.cc). Also as per spec changes, if this filtering results in not having any codecs to offer or answer then this results in not having any codec preferences as opposed to throwing an exception (old behavior). - Two old peer_connection_media_unittest.cc tests are updated to reflect the API failing less. This CL adds both unit tests (rtp_transceiver_unittest.cc) and full stack integration tests (peer_connection_encodings_integrationtest.cc). It also makes us pass the following Web Platform Tests in Chrome: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/external/wpt/webrtc/protocol/h265-level-id.https.html Bug: chromium:381407888 Change-Id: I98a5ad1acccb56db0538e4d47975b8a725102c33 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/374520 Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Evan Shrubsole <eshr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43788}
2025-01-22 15:13:37 +01:00
#ifdef RTC_ENABLE_H265
2025-01-17 12:06:53 +01:00
TEST_F(PeerConnectionEncodingsFakeCodecsIntegrationTest, H265Singlecast) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper =
CreatePcWithFakeH265();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper =
CreatePcWithFakeH265();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
local_pc_wrapper->pc()
->AddTransceiver(cricket::MEDIA_TYPE_VIDEO)
.MoveValue();
std::vector<RtpCodecCapability> preferred_codecs =
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "H265");
transceiver->SetCodecPreferences(preferred_codecs);
Negotiate(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Verify codec.
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/H265"));
}
TEST_F(PeerConnectionEncodingsFakeCodecsIntegrationTest, H265Simulcast) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper =
CreatePcWithFakeH265();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper =
CreatePcWithFakeH265();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> preferred_codecs =
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "H265");
transceiver->SetCodecPreferences(preferred_codecs);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until all outbound RTPs exist.
EXPECT_THAT(
GetStatsUntil(local_pc_wrapper, OutboundRtpStatsAre(UnorderedElementsAre(
AllOf(RidIs("q")), AllOf(RidIs("h")),
AllOf(RidIs("f"))))),
IsRtcOk());
// Verify codec.
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(3u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/H265"));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]),
StrCaseEq("video/H265"));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]),
StrCaseEq("video/H265"));
}
TEST_F(PeerConnectionEncodingsFakeCodecsIntegrationTest,
H265SetParametersIgnoresLevelId) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper =
CreatePcWithFakeH265();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper =
CreatePcWithFakeH265();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> preferred_codecs =
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "H265");
transceiver->SetCodecPreferences(preferred_codecs);
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// This includes non-codecs like rtx, red and flexfec too so we need to find
// H265.
std::vector<RtpCodecCapability> sender_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
auto it = std::find_if(sender_codecs.begin(), sender_codecs.end(),
[](const RtpCodecCapability codec_capability) {
return codec_capability.name == "H265";
});
ASSERT_NE(it, sender_codecs.end());
RtpCodecCapability& h265_codec = *it;
// SetParameters() without changing level-id.
EXPECT_EQ(h265_codec.parameters["level-id"], "156");
{
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(1));
parameters.encodings[0].codec = h265_codec;
ASSERT_THAT(sender->SetParameters(parameters), IsRtcOk());
}
// SetParameters() with a lower level-id.
h265_codec.parameters["level-id"] = "30";
{
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(1));
parameters.encodings[0].codec = h265_codec;
ASSERT_THAT(sender->SetParameters(parameters), IsRtcOk());
}
// SetParameters() with a higher level-id.
h265_codec.parameters["level-id"] = "180";
{
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(1));
parameters.encodings[0].codec = h265_codec;
ASSERT_THAT(sender->SetParameters(parameters), IsRtcOk());
}
}
#endif // RTC_ENABLE_H265
Add unidirectional codec support ("offer to send" use case). This CL implements allowing sendonly codecs in setCodecPreferences(), i.e. this spec PR: https://github.com/w3c/webrtc-pc/pull/3018. It also makes the setCodecPreferences() ignore level IDs in the filtering algorithm (but not in the sCP method call) as per this spec PR: https://github.com/w3c/webrtc-pc/pull/3023. In short, before this CL, setCodecPreferences() threw an exception if a codec was preferred that is not present in receiver codec capabilities. After this CL, setCodecPreferences() allows you to prefer codecs that are *either* in the sender capabilities *or* the receiver capabilities. - This allows you to "offer to send", i.e. prefer sendonly codecs on a sendonly transceiver. - The filtering on direction is handled by RtpTransceiver::filtered_codec_preferences() which is called during SDP offer/answer (sdp_offer_answer.cc). Also as per spec changes, if this filtering results in not having any codecs to offer or answer then this results in not having any codec preferences as opposed to throwing an exception (old behavior). - Two old peer_connection_media_unittest.cc tests are updated to reflect the API failing less. This CL adds both unit tests (rtp_transceiver_unittest.cc) and full stack integration tests (peer_connection_encodings_integrationtest.cc). It also makes us pass the following Web Platform Tests in Chrome: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/external/wpt/webrtc/protocol/h265-level-id.https.html Bug: chromium:381407888 Change-Id: I98a5ad1acccb56db0538e4d47975b8a725102c33 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/374520 Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Evan Shrubsole <eshr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43788}
2025-01-22 15:13:37 +01:00
TEST_F(PeerConnectionEncodingsFakeCodecsIntegrationTest,
H264UnidirectionalNegotiation) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper =
CreatePcWithUnidirectionalH264();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper =
CreatePcWithUnidirectionalH264();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
local_pc_wrapper->pc()
->AddTransceiver(cricket::MEDIA_TYPE_VIDEO)
.MoveValue();
// Filter on codec name and assert that sender capabilities have codecs for
// {sendrecv, sendonly} and the receiver capabilities have codecs for
// {sendrecv, recvonly}.
std::vector<RtpCodecCapability> send_codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
send_codecs.erase(std::remove_if(send_codecs.begin(), send_codecs.end(),
[](const RtpCodecCapability& codec) {
return codec.name != "H264";
}),
send_codecs.end());
std::vector<RtpCodecCapability> recv_codecs =
local_pc_wrapper->pc_factory()
->GetRtpReceiverCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
recv_codecs.erase(std::remove_if(recv_codecs.begin(), recv_codecs.end(),
[](const RtpCodecCapability& codec) {
RTC_LOG(LS_ERROR) << codec.name;
return codec.name != "H264";
}),
recv_codecs.end());
ASSERT_THAT(send_codecs, SizeIs(2u));
ASSERT_THAT(recv_codecs, SizeIs(2u));
EXPECT_EQ(send_codecs[0], recv_codecs[0]);
EXPECT_NE(send_codecs[1], recv_codecs[1]);
RtpCodecCapability& sendrecv_codec = send_codecs[0];
RtpCodecCapability& sendonly_codec = send_codecs[1];
RtpCodecCapability& recvonly_codec = recv_codecs[1];
// Preferring sendonly + recvonly on a sendrecv transceiver is the same as
// not having any preferences, meaning the sendrecv codec (not listed) is the
// one being negotiated.
std::vector<RtpCodecCapability> preferred_codecs = {sendonly_codec,
recvonly_codec};
EXPECT_THAT(transceiver->SetCodecPreferences(preferred_codecs), IsRtcOk());
EXPECT_THAT(
transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv),
IsRtcOk());
Negotiate(local_pc_wrapper, remote_pc_wrapper);
std::string local_sdp = LocalDescriptionStr(local_pc_wrapper.get());
EXPECT_THAT(local_sdp,
HasSubstr(sendrecv_codec.parameters["profile-level-id"]));
EXPECT_THAT(local_sdp,
Not(HasSubstr(sendonly_codec.parameters["profile-level-id"])));
EXPECT_THAT(local_sdp,
Not(HasSubstr(recvonly_codec.parameters["profile-level-id"])));
// Prefer all codecs and expect that the SDP offer contains the relevant
// codecs after filtering. Complete O/A each time.
preferred_codecs = {sendrecv_codec, sendonly_codec, recvonly_codec};
EXPECT_THAT(transceiver->SetCodecPreferences(preferred_codecs), IsRtcOk());
// Transceiver direction: sendrecv.
EXPECT_THAT(
transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv),
IsRtcOk());
Negotiate(local_pc_wrapper, remote_pc_wrapper);
local_sdp = LocalDescriptionStr(local_pc_wrapper.get());
EXPECT_THAT(local_sdp,
HasSubstr(sendrecv_codec.parameters["profile-level-id"]));
EXPECT_THAT(local_sdp,
Not(HasSubstr(sendonly_codec.parameters["profile-level-id"])));
EXPECT_THAT(local_sdp,
Not(HasSubstr(recvonly_codec.parameters["profile-level-id"])));
// Transceiver direction: sendonly.
EXPECT_THAT(
transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendOnly),
IsRtcOk());
Negotiate(local_pc_wrapper, remote_pc_wrapper);
local_sdp = LocalDescriptionStr(local_pc_wrapper.get());
EXPECT_THAT(local_sdp,
HasSubstr(sendrecv_codec.parameters["profile-level-id"]));
EXPECT_THAT(local_sdp,
HasSubstr(sendonly_codec.parameters["profile-level-id"]));
EXPECT_THAT(local_sdp,
Not(HasSubstr(recvonly_codec.parameters["profile-level-id"])));
// Transceiver direction: recvonly.
EXPECT_THAT(
transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly),
IsRtcOk());
Negotiate(local_pc_wrapper, remote_pc_wrapper);
local_sdp = LocalDescriptionStr(local_pc_wrapper.get());
EXPECT_THAT(local_sdp,
HasSubstr(sendrecv_codec.parameters["profile-level-id"]));
EXPECT_THAT(local_sdp,
Not(HasSubstr(sendonly_codec.parameters["profile-level-id"])));
EXPECT_THAT(local_sdp,
HasSubstr(recvonly_codec.parameters["profile-level-id"]));
// Test that offering a sendonly codec on a sendonly transceiver is possible.
// - Note that we don't complete the negotiation this time because we're not
// capable of receiving the codec.
preferred_codecs = {sendonly_codec};
EXPECT_THAT(transceiver->SetCodecPreferences(preferred_codecs), IsRtcOk());
EXPECT_THAT(
transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendOnly),
IsRtcOk());
std::unique_ptr<SessionDescriptionInterface> offer =
CreateOffer(local_pc_wrapper);
EXPECT_TRUE(Await({SetLocalDescription(local_pc_wrapper, offer.get())}));
local_sdp = LocalDescriptionStr(local_pc_wrapper.get());
EXPECT_THAT(local_sdp,
Not(HasSubstr(sendrecv_codec.parameters["profile-level-id"])));
EXPECT_THAT(local_sdp,
HasSubstr(sendonly_codec.parameters["profile-level-id"]));
EXPECT_THAT(local_sdp,
Not(HasSubstr(recvonly_codec.parameters["profile-level-id"])));
// Test that offering recvonly codec on a recvonly transceiver is possible.
// - Note that we don't complete the negotiation this time because we're not
// capable of sending the codec.
preferred_codecs = {recvonly_codec};
EXPECT_THAT(transceiver->SetCodecPreferences(preferred_codecs), IsRtcOk());
EXPECT_THAT(
transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly),
IsRtcOk());
offer = CreateOffer(local_pc_wrapper);
EXPECT_TRUE(Await({SetLocalDescription(local_pc_wrapper, offer.get())}));
local_sdp = LocalDescriptionStr(local_pc_wrapper.get());
EXPECT_THAT(local_sdp,
Not(HasSubstr(sendrecv_codec.parameters["profile-level-id"])));
EXPECT_THAT(local_sdp,
Not(HasSubstr(sendonly_codec.parameters["profile-level-id"])));
EXPECT_THAT(local_sdp,
HasSubstr(recvonly_codec.parameters["profile-level-id"]));
}
} // namespace webrtc