diff --git a/api/BUILD.gn b/api/BUILD.gn index 0b86f196e5..510fe4f557 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -268,6 +268,7 @@ rtc_source_set("peer_connection_quality_test_fixture_api") { ":simulated_network_api", ":video_quality_analyzer_api", "../logging:rtc_event_log_api", + "../media:rtc_media_base", "../rtc_base:rtc_base", "transport:network_control", "units:time_delta", diff --git a/api/test/DEPS b/api/test/DEPS index e49fdb42dd..f54fe1cacf 100644 --- a/api/test/DEPS +++ b/api/test/DEPS @@ -24,5 +24,6 @@ specific_include_rules = { "+rtc_base/rtc_certificate_generator.h", "+rtc_base/ssl_certificate.h", "+rtc_base/thread.h", + "+media/base/media_constants.h", ], } diff --git a/api/test/peerconnection_quality_test_fixture.h b/api/test/peerconnection_quality_test_fixture.h index 9f8d7ea2f2..76de3d0d6a 100644 --- a/api/test/peerconnection_quality_test_fixture.h +++ b/api/test/peerconnection_quality_test_fixture.h @@ -10,6 +10,7 @@ #ifndef API_TEST_PEERCONNECTION_QUALITY_TEST_FIXTURE_H_ #define API_TEST_PEERCONNECTION_QUALITY_TEST_FIXTURE_H_ +#include #include #include #include @@ -30,6 +31,7 @@ #include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder_factory.h" #include "logging/rtc_event_log/rtc_event_log_factory_interface.h" +#include "media/base/media_constants.h" #include "rtc_base/network.h" #include "rtc_base/rtc_certificate_generator.h" #include "rtc_base/ssl_certificate.h" @@ -184,6 +186,21 @@ class PeerConnectionE2EQualityTestFixture { // it will be shut downed. TimeDelta run_duration; + // Next two fields are used to specify concrete video codec, that should be + // used in the test. Video code will be negotiated in SDP during offer/ + // answer exchange. + // Video codec name. You can find valid names in + // media/base/media_constants.h + std::string video_codec_name = cricket::kVp8CodecName; + // Map of parameters, that have to be specified on SDP codec. Each parameter + // is described by key and value. Codec parameters will match the specified + // map if and only if for each key from |video_codec_required_params| there + // will be a parameter with name equal to this key and parameter value will + // be equal to the value from |video_codec_required_params| for this key. + // If empty then only name will be used to match the codec. + std::map video_codec_required_params; + bool use_ulp_fec = false; + bool use_flex_fec = false; // Specifies how much video encoder target bitrate should be different than // target bitrate, provided by WebRTC stack. Must be greater then 0. Can be // used to emulate overshooting of video encoders. This multiplier will diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn index f7c90b98c3..0d98206997 100644 --- a/test/pc/e2e/BUILD.gn +++ b/test/pc/e2e/BUILD.gn @@ -249,6 +249,7 @@ if (rtc_include_tests) { ":default_audio_quality_analyzer", ":default_video_quality_analyzer", ":peer_connection_quality_test_params", + ":sdp_changer", ":single_process_encoded_image_data_injector", ":stats_poller", ":test_peer", @@ -265,6 +266,7 @@ if (rtc_include_tests) { "../../../logging:rtc_event_log_api", "../../../logging:rtc_event_log_impl_output", "../../../pc:pc_test_utils", + "../../../pc:peerconnection", "../../../rtc_base", "../../../rtc_base:gunit_helpers", "../../../rtc_base:rtc_base_approved", @@ -476,3 +478,17 @@ rtc_source_set("network_quality_metrics_reporter") { "../../../rtc_base:rtc_event", ] } + +rtc_source_set("sdp_changer") { + testonly = true + sources = [ + "sdp/sdp_changer.cc", + "sdp/sdp_changer.h", + ] + deps = [ + "../../../api:libjingle_peerconnection_api", + "../../../media:rtc_media_base", + "../../../rtc_base:stringutils", + "//third_party/abseil-cpp/absl/strings:strings", + ] +} diff --git a/test/pc/e2e/peer_connection_e2e_smoke_test.cc b/test/pc/e2e/peer_connection_e2e_smoke_test.cc index 95f45c4166..f29746f68b 100644 --- a/test/pc/e2e/peer_connection_e2e_smoke_test.cc +++ b/test/pc/e2e/peer_connection_e2e_smoke_test.cc @@ -119,6 +119,10 @@ TEST(PeerConnectionE2EQualityTestSmokeTest, MAYBE_RunWithEmulatedNetwork) { bob_network)); RunParams run_params(TimeDelta::seconds(7)); + run_params.video_codec_name = cricket::kVp9CodecName; + run_params.video_codec_required_params = {{"profile-id", "0"}}; + run_params.use_flex_fec = true; + run_params.use_ulp_fec = true; run_params.video_encoder_bitrate_multiplier = 1.1; fixture->Run(run_params); diff --git a/test/pc/e2e/peer_connection_quality_test.cc b/test/pc/e2e/peer_connection_quality_test.cc index e6dca51529..4653c7c812 100644 --- a/test/pc/e2e/peer_connection_quality_test.cc +++ b/test/pc/e2e/peer_connection_quality_test.cc @@ -22,6 +22,7 @@ #include "api/units/time_delta.h" #include "logging/rtc_event_log/output/rtc_event_log_output_file.h" #include "logging/rtc_event_log/rtc_event_log.h" +#include "pc/sdp_utils.h" #include "pc/test/mock_peer_connection_observers.h" #include "rtc_base/bind.h" #include "rtc_base/gunit.h" @@ -29,6 +30,7 @@ #include "system_wrappers/include/cpu_info.h" #include "test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer.h" +#include "test/pc/e2e/sdp/sdp_changer.h" #include "test/pc/e2e/stats_poller.h" #include "test/testsupport/file_utils.h" @@ -318,8 +320,8 @@ void PeerConnectionE2EQualityTest::Run( // Setup call. signaling_thread->Invoke( RTC_FROM_HERE, - rtc::Bind(&PeerConnectionE2EQualityTest::SetupCallOnSignalingThread, - this)); + rtc::Bind(&PeerConnectionE2EQualityTest::SetupCallOnSignalingThread, this, + run_params)); { rtc::CritScope crit(&lock_); start_time_ = Now(); @@ -513,7 +515,8 @@ void PeerConnectionE2EQualityTest::OnTrackCallback( output_video_sinks_.push_back(std::move(video_sink)); } -void PeerConnectionE2EQualityTest::SetupCallOnSignalingThread() { +void PeerConnectionE2EQualityTest::SetupCallOnSignalingThread( + const RunParams& run_params) { // We need receive-only transceivers for Bob's media stream, so there will // be media section in SDP for that streams in Alice's offer, because it is // forbidden to add new media sections in answer in Unified Plan. @@ -534,6 +537,9 @@ void PeerConnectionE2EQualityTest::SetupCallOnSignalingThread() { alice_video_sources_ = MaybeAddMedia(alice_.get()); bob_video_sources_ = MaybeAddMedia(bob_.get()); + SetPeerCodecPreferences(alice_.get(), run_params); + SetPeerCodecPreferences(bob_.get(), run_params); + SetupCall(); } @@ -631,6 +637,24 @@ void PeerConnectionE2EQualityTest::MaybeAddAudio(TestPeer* peer) { peer->AddTrack(track, {*audio_config.stream_label}); } +void PeerConnectionE2EQualityTest::SetPeerCodecPreferences( + TestPeer* peer, + const RunParams& run_params) { + std::vector video_capabilities = FilterCodecCapabilities( + run_params.video_codec_name, run_params.video_codec_required_params, + run_params.use_ulp_fec, run_params.use_flex_fec, + peer->pc_factory() + ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO) + .codecs); + + // Set codecs for transceivers + for (auto transceiver : peer->pc()->GetTransceivers()) { + if (transceiver->media_type() == cricket::MediaType::MEDIA_TYPE_VIDEO) { + transceiver->SetCodecPreferences(video_capabilities); + } + } +} + void PeerConnectionE2EQualityTest::SetupCall() { // Connect peers. ASSERT_TRUE(alice_->ExchangeOfferAnswerWith(bob_.get())); diff --git a/test/pc/e2e/peer_connection_quality_test.h b/test/pc/e2e/peer_connection_quality_test.h index 93afd3cf4e..3b39916198 100644 --- a/test/pc/e2e/peer_connection_quality_test.h +++ b/test/pc/e2e/peer_connection_quality_test.h @@ -211,7 +211,7 @@ class PeerConnectionE2EQualityTest void OnTrackCallback(rtc::scoped_refptr transceiver, std::vector remote_video_configs); // Have to be run on the signaling thread. - void SetupCallOnSignalingThread(); + void SetupCallOnSignalingThread(const RunParams& run_params); void TearDownCallOnSignalingThread(); std::vector> MaybeAddMedia(TestPeer* peer); @@ -220,6 +220,7 @@ class PeerConnectionE2EQualityTest std::unique_ptr CreateFrameGenerator( const VideoConfig& video_config); void MaybeAddAudio(TestPeer* peer); + void SetPeerCodecPreferences(TestPeer* peer, const RunParams& run_params); void SetupCall(); void StartVideo( const std::vector< diff --git a/test/pc/e2e/sdp/sdp_changer.cc b/test/pc/e2e/sdp/sdp_changer.cc new file mode 100644 index 0000000000..2c7dc3c434 --- /dev/null +++ b/test/pc/e2e/sdp/sdp_changer.cc @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 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 "test/pc/e2e/sdp/sdp_changer.h" + +#include + +#include "media/base/media_constants.h" +#include "rtc_base/strings/string_builder.h" + +namespace webrtc { +namespace webrtc_pc_e2e { +namespace { + +std::string CodecRequiredParamsToString( + const std::map& codec_required_params) { + rtc::StringBuilder out; + for (auto entry : codec_required_params) { + out << entry.first << "=" << entry.second << ";"; + } + return out.str(); +} + +} // namespace + +std::vector FilterCodecCapabilities( + absl::string_view codec_name, + const std::map& codec_required_params, + bool ulpfec, + bool flexfec, + std::vector supported_codecs) { + std::vector output_codecs; + // Find main requested codecs among supported and add them to output. + for (auto& codec : supported_codecs) { + if (codec.name != codec_name) { + continue; + } + bool parameters_matched = true; + for (auto item : codec_required_params) { + auto it = codec.parameters.find(item.first); + if (it == codec.parameters.end()) { + parameters_matched = false; + break; + } + if (item.second != it->second) { + parameters_matched = false; + break; + } + } + if (parameters_matched) { + output_codecs.push_back(codec); + } + } + + RTC_CHECK_GT(output_codecs.size(), 0) + << "Codec with name=" << codec_name << " and params {" + << CodecRequiredParamsToString(codec_required_params) + << "} is unsupported for this peer connection"; + + // Add required FEC and RTX codecs to output. + for (auto& codec : supported_codecs) { + if (codec.name == cricket::kRtxCodecName) { + output_codecs.push_back(codec); + } else if (codec.name == cricket::kFlexfecCodecName && flexfec) { + output_codecs.push_back(codec); + } else if ((codec.name == cricket::kRedCodecName || + codec.name == cricket::kUlpfecCodecName) && + ulpfec) { + // Red and ulpfec should be enabled or disabled together. + output_codecs.push_back(codec); + } + } + return output_codecs; +} + +} // namespace webrtc_pc_e2e +} // namespace webrtc diff --git a/test/pc/e2e/sdp/sdp_changer.h b/test/pc/e2e/sdp/sdp_changer.h new file mode 100644 index 0000000000..dbc76b3667 --- /dev/null +++ b/test/pc/e2e/sdp/sdp_changer.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 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. + */ + +#ifndef TEST_PC_E2E_SDP_SDP_CHANGER_H_ +#define TEST_PC_E2E_SDP_SDP_CHANGER_H_ + +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "api/rtp_parameters.h" + +namespace webrtc { +namespace webrtc_pc_e2e { + +// Creates list of capabilities, which can be set on RtpTransceiverInterface via +// RtpTransceiverInterface::SetCodecPreferences(...) to negotiate use of codec +// from list of |supported_codecs| with specified |codec_name| and parameters, +// which contains all of |codec_required_params|. If flags |ulpfec| or |flexfec| +// set to true corresponding FEC codec will be added. FEC and RTX codecs will be +// added after required codecs. +// +// All codecs will be added only if they exists in the list of +// |supported_codecs|. If multiple codecs from this list will have |codec_name| +// and |codec_required_params|, then all of them will be added to the output +// vector and they will be added in the same order, as they were in +// |supported_codecs|. +std::vector FilterCodecCapabilities( + absl::string_view codec_name, + const std::map& codec_required_params, + bool ulpfec, + bool flexfec, + std::vector supported_codecs); + +} // namespace webrtc_pc_e2e +} // namespace webrtc + +#endif // TEST_PC_E2E_SDP_SDP_CHANGER_H_