diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/third_party/webrtc/test | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/webrtc/test')
69 files changed, 2898 insertions, 1261 deletions
diff --git a/chromium/third_party/webrtc/test/BUILD.gn b/chromium/third_party/webrtc/test/BUILD.gn index 34da8894f74..9215b679cea 100644 --- a/chromium/third_party/webrtc/test/BUILD.gn +++ b/chromium/third_party/webrtc/test/BUILD.gn @@ -22,13 +22,13 @@ group("test") { ":test_renderer", ":test_support", ":video_test_common", - "pc/e2e", ] if (rtc_include_tests) { deps += [ ":test_main", ":test_support_unittests", + "pc/e2e", ] } } @@ -70,8 +70,8 @@ rtc_library("frame_generator_impl") { "../rtc_base/synchronization:sequence_checker", "../rtc_base/system:file_wrapper", "../system_wrappers", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("frame_utils") { @@ -127,8 +127,8 @@ rtc_library("video_test_common") { "../rtc_base:timeutils", "../rtc_base/task_utils:repeating_task", "../system_wrappers", - "//third_party/abseil-cpp/absl/strings", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } if (!build_with_chromium) { @@ -160,10 +160,8 @@ if (!build_with_chromium) { "platform_video_capturer.cc", "platform_video_capturer.h", ] - deps = [ - ":video_test_common", - "//third_party/abseil-cpp/absl/memory", - ] + deps = [ ":video_test_common" ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] if (is_mac || is_ios) { deps += [ ":video_test_mac" ] } else { @@ -218,6 +216,20 @@ rtc_library("field_trial") { deps = [ "../system_wrappers:field_trial" ] } +rtc_library("explicit_key_value_config") { + sources = [ + "explicit_key_value_config.cc", + "explicit_key_value_config.h", + ] + + deps = [ + "../api/transport:webrtc_key_value_config", + "../rtc_base:checks", + "../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings:strings" ] +} + rtc_library("perf_test") { visibility = [ "*" ] testonly = true @@ -235,9 +247,8 @@ rtc_library("perf_test") { "../rtc_base:criticalsection", "../rtc_base:logging", "../rtc_base:rtc_numerics", - "//third_party/abseil-cpp/absl/flags:flag", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] if (rtc_enable_protobuf) { sources += [ "testsupport/perf_test_histogram_writer.cc" ] deps += [ @@ -262,8 +273,8 @@ if (is_ios) { deps = [ ":perf_test", "../sdk:helpers_objc", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] configs += [ ":test_support_objc_config" ] } @@ -359,8 +370,8 @@ rtc_library("video_test_support") { "../rtc_base:rtc_event", "../rtc_base/synchronization:sequence_checker", "../rtc_base/system:file_wrapper", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] if (!is_ios) { deps += [ "//third_party:jpeg" ] @@ -375,6 +386,16 @@ rtc_library("video_test_support") { } if (rtc_include_tests) { + rtc_library("resources_dir_flag") { + testonly = true + visibility = [ "*" ] + sources = [ + "testsupport/resources_dir_flag.cc", + "testsupport/resources_dir_flag.h", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag" ] + } + rtc_library("test_main_lib") { visibility = [ "*" ] testonly = true @@ -394,9 +415,12 @@ if (rtc_include_tests) { "../rtc_base:rtc_base_approved", "../system_wrappers:field_trial", "../system_wrappers:metrics", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings:strings", "//third_party/abseil-cpp/absl/types:optional", ] } @@ -406,13 +430,20 @@ if (rtc_include_tests) { testonly = true sources = [ "test_main.cc" ] - deps = [ - ":test_main_lib", + deps = [ ":test_main_lib" ] + absl_deps = [ "//third_party/abseil-cpp/absl/debugging:failure_signal_handler", "//third_party/abseil-cpp/absl/debugging:symbolize", ] } + rtc_library("benchmark_main") { + testonly = true + sources = [ "benchmark_main.cc" ] + + deps = [ "//third_party/google_benchmark" ] + } + rtc_library("test_support_test_artifacts") { testonly = true sources = [ @@ -423,6 +454,8 @@ if (rtc_include_tests) { ":fileutils", "../rtc_base:logging", "../rtc_base/system:file_wrapper", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", ] @@ -586,8 +619,8 @@ rtc_library("fileutils") { ":fileutils_override_impl", "../rtc_base:checks", "../rtc_base:stringutils", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] if (is_ios) { deps += [ ":fileutils_ios_objc" ] } @@ -599,16 +632,6 @@ rtc_library("fileutils") { } } -rtc_library("resources_dir_flag") { - testonly = true - visibility = [ "*" ] - sources = [ - "testsupport/resources_dir_flag.cc", - "testsupport/resources_dir_flag.h", - ] - deps = [ "//third_party/abseil-cpp/absl/flags:flag" ] -} - # We separate header into own target to make it possible for downstream # projects to override implementation. rtc_source_set("fileutils_override_api") { @@ -625,8 +648,8 @@ rtc_library("fileutils_override_impl") { "../rtc_base:checks", "../rtc_base:macromagic", "../rtc_base:stringutils", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] if (is_ios) { deps += [ ":fileutils_ios_objc" ] } @@ -676,8 +699,8 @@ rtc_library("fileutils_unittests") { ":fileutils", ":test_support", "../rtc_base:checks", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("direct_transport") { @@ -699,8 +722,8 @@ rtc_library("direct_transport") { "../rtc_base:timeutils", "../rtc_base/synchronization:sequence_checker", "../rtc_base/task_utils:repeating_task", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] public_deps = # no-presubmit-check TODO(webrtc:8603) [ "../call:fake_network" ] } @@ -742,8 +765,8 @@ rtc_library("fake_video_codecs") { "../rtc_base:timeutils", "../rtc_base/synchronization:sequence_checker", "../system_wrappers", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("null_transport") { @@ -839,8 +862,8 @@ rtc_library("test_common") { "../rtc_base/task_utils:to_queued_task", "../system_wrappers", "../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] if (!is_android && !build_with_chromium) { deps += [ "../modules/video_capture:video_capture_internal_impl" ] } @@ -986,8 +1009,8 @@ rtc_library("audio_codec_mocks") { "../api/audio_codecs:builtin_audio_decoder_factory", "../rtc_base:checks", "../rtc_base:refcount", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_library("copy_to_file_audio_capturer") { @@ -1001,8 +1024,8 @@ rtc_library("copy_to_file_audio_capturer") { "../common_audio", "../modules/audio_device:audio_device_impl", "../rtc_base:rtc_base_approved", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("copy_to_file_audio_capturer_unittest") { diff --git a/chromium/third_party/webrtc/test/DEPS b/chromium/third_party/webrtc/test/DEPS index 62fd6d3ff77..170c4086d74 100644 --- a/chromium/third_party/webrtc/test/DEPS +++ b/chromium/third_party/webrtc/test/DEPS @@ -72,5 +72,8 @@ specific_include_rules = { ], ".*test_video_capturer_video_track_source.h": [ "+pc", + ], + "benchmark_main\.cc": [ + "+benchmark", ] } diff --git a/chromium/third_party/webrtc/test/benchmark_main.cc b/chromium/third_party/webrtc/test/benchmark_main.cc new file mode 100644 index 00000000000..1a79c249133 --- /dev/null +++ b/chromium/third_party/webrtc/test/benchmark_main.cc @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 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 "benchmark/benchmark.h" + +int main(int argc, char* argv[]) { + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + return 0; +} diff --git a/chromium/third_party/webrtc/test/explicit_key_value_config.cc b/chromium/third_party/webrtc/test/explicit_key_value_config.cc new file mode 100644 index 00000000000..69f725a9e24 --- /dev/null +++ b/chromium/third_party/webrtc/test/explicit_key_value_config.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 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/explicit_key_value_config.h" + +#include "api/transport/webrtc_key_value_config.h" +#include "rtc_base/checks.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +namespace test { + +ExplicitKeyValueConfig::ExplicitKeyValueConfig(const std::string& s) { + std::string::size_type field_start = 0; + while (field_start < s.size()) { + std::string::size_type separator_pos = s.find('/', field_start); + RTC_CHECK_NE(separator_pos, std::string::npos) + << "Missing separator '/' after field trial key."; + RTC_CHECK_GT(separator_pos, field_start) + << "Field trial key cannot be empty."; + std::string key = s.substr(field_start, separator_pos - field_start); + field_start = separator_pos + 1; + + RTC_CHECK_LT(field_start, s.size()) + << "Missing value after field trial key. String ended."; + separator_pos = s.find('/', field_start); + RTC_CHECK_NE(separator_pos, std::string::npos) + << "Missing terminating '/' in field trial string."; + RTC_CHECK_GT(separator_pos, field_start) + << "Field trial value cannot be empty."; + std::string value = s.substr(field_start, separator_pos - field_start); + field_start = separator_pos + 1; + + key_value_map_[key] = value; + } + // This check is technically redundant due to earlier checks. + // We nevertheless keep the check to make it clear that the entire + // string has been processed, and without indexing past the end. + RTC_CHECK_EQ(field_start, s.size()); +} + +std::string ExplicitKeyValueConfig::Lookup(absl::string_view key) const { + auto it = key_value_map_.find(std::string(key)); + if (it != key_value_map_.end()) + return it->second; + return ""; +} + +} // namespace test +} // namespace webrtc diff --git a/chromium/third_party/webrtc/test/explicit_key_value_config.h b/chromium/third_party/webrtc/test/explicit_key_value_config.h new file mode 100644 index 00000000000..9a3bc84f606 --- /dev/null +++ b/chromium/third_party/webrtc/test/explicit_key_value_config.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 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_EXPLICIT_KEY_VALUE_CONFIG_H_ +#define TEST_EXPLICIT_KEY_VALUE_CONFIG_H_ + +#include <map> +#include <string> + +#include "absl/strings/string_view.h" +#include "api/transport/webrtc_key_value_config.h" + +namespace webrtc { +namespace test { + +class ExplicitKeyValueConfig : public WebRtcKeyValueConfig { + public: + explicit ExplicitKeyValueConfig(const std::string& s); + std::string Lookup(absl::string_view key) const override; + + private: + std::map<std::string, std::string> key_value_map_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_EXPLICIT_KEY_VALUE_CONFIG_H_ diff --git a/chromium/third_party/webrtc/test/fake_encoder.cc b/chromium/third_party/webrtc/test/fake_encoder.cc index 64b4a4e9ff8..2959559910e 100644 --- a/chromium/third_party/webrtc/test/fake_encoder.cc +++ b/chromium/third_party/webrtc/test/fake_encoder.cc @@ -69,7 +69,7 @@ void FakeEncoder::SetMaxBitrate(int max_kbps) { RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it. rtc::CritScope cs(&crit_sect_); max_target_bitrate_kbps_ = max_kbps; - SetRates(current_rate_settings_); + SetRatesLocked(current_rate_settings_); } void FakeEncoder::SetQp(int qp) { @@ -243,6 +243,10 @@ int32_t FakeEncoder::Release() { void FakeEncoder::SetRates(const RateControlParameters& parameters) { rtc::CritScope cs(&crit_sect_); + SetRatesLocked(parameters); +} + +void FakeEncoder::SetRatesLocked(const RateControlParameters& parameters) { current_rate_settings_ = parameters; int allocated_bitrate_kbps = parameters.bitrate.get_sum_kbps(); diff --git a/chromium/third_party/webrtc/test/fake_encoder.h b/chromium/third_party/webrtc/test/fake_encoder.h index 39838d16f14..ade0e35560c 100644 --- a/chromium/third_party/webrtc/test/fake_encoder.h +++ b/chromium/third_party/webrtc/test/fake_encoder.h @@ -40,21 +40,23 @@ class FakeEncoder : public VideoEncoder { virtual ~FakeEncoder() = default; // Sets max bitrate. Not thread-safe, call before registering the encoder. - void SetMaxBitrate(int max_kbps); - void SetQp(int qp); + void SetMaxBitrate(int max_kbps) RTC_LOCKS_EXCLUDED(crit_sect_); + void SetQp(int qp) RTC_LOCKS_EXCLUDED(crit_sect_); void SetFecControllerOverride( FecControllerOverride* fec_controller_override) override; - int32_t InitEncode(const VideoCodec* config, - const Settings& settings) override; + int32_t InitEncode(const VideoCodec* config, const Settings& settings) + RTC_LOCKS_EXCLUDED(crit_sect_) override; int32_t Encode(const VideoFrame& input_image, - const std::vector<VideoFrameType>* frame_types) override; - int32_t RegisterEncodeCompleteCallback( - EncodedImageCallback* callback) override; + const std::vector<VideoFrameType>* frame_types) + RTC_LOCKS_EXCLUDED(crit_sect_) override; + int32_t RegisterEncodeCompleteCallback(EncodedImageCallback* callback) + RTC_LOCKS_EXCLUDED(crit_sect_) override; int32_t Release() override; - void SetRates(const RateControlParameters& parameters) override; - int GetConfiguredInputFramerate() const; + void SetRates(const RateControlParameters& parameters) + RTC_LOCKS_EXCLUDED(crit_sect_) override; + int GetConfiguredInputFramerate() const RTC_LOCKS_EXCLUDED(crit_sect_); EncoderInfo GetEncoderInfo() const override; static const char* kImplementationName; @@ -79,7 +81,7 @@ class FakeEncoder : public VideoEncoder { uint8_t num_simulcast_streams, const VideoBitrateAllocation& target_bitrate, SimulcastStream simulcast_streams[kMaxSimulcastStreams], - int framerate); + int framerate) RTC_LOCKS_EXCLUDED(crit_sect_); // Called before the frame is passed to callback_->OnEncodedImage, to let // subclasses fill out codec_specific, possibly modify encodedImage. @@ -88,6 +90,9 @@ class FakeEncoder : public VideoEncoder { EncodedImage* encoded_image, CodecSpecificInfo* codec_specific); + void SetRatesLocked(const RateControlParameters& parameters) + RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); + FrameInfo last_frame_info_ RTC_GUARDED_BY(crit_sect_); Clock* const clock_; diff --git a/chromium/third_party/webrtc/test/frame_forwarder.cc b/chromium/third_party/webrtc/test/frame_forwarder.cc index d1a2ddb1c29..d8ec4b5060e 100644 --- a/chromium/third_party/webrtc/test/frame_forwarder.cc +++ b/chromium/third_party/webrtc/test/frame_forwarder.cc @@ -26,6 +26,12 @@ void FrameForwarder::IncomingCapturedFrame(const VideoFrame& video_frame) { void FrameForwarder::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, const rtc::VideoSinkWants& wants) { rtc::CritScope lock(&crit_); + AddOrUpdateSinkLocked(sink, wants); +} + +void FrameForwarder::AddOrUpdateSinkLocked( + rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) { RTC_DCHECK(!sink_ || sink_ == sink); sink_ = sink; sink_wants_ = wants; @@ -42,6 +48,10 @@ rtc::VideoSinkWants FrameForwarder::sink_wants() const { return sink_wants_; } +rtc::VideoSinkWants FrameForwarder::sink_wants_locked() const { + return sink_wants_; +} + bool FrameForwarder::has_sinks() const { rtc::CritScope lock(&crit_); return sink_ != nullptr; diff --git a/chromium/third_party/webrtc/test/frame_forwarder.h b/chromium/third_party/webrtc/test/frame_forwarder.h index cf29f5f0743..d391160fab0 100644 --- a/chromium/third_party/webrtc/test/frame_forwarder.h +++ b/chromium/third_party/webrtc/test/frame_forwarder.h @@ -26,14 +26,22 @@ class FrameForwarder : public rtc::VideoSourceInterface<VideoFrame> { FrameForwarder(); ~FrameForwarder() override; // Forwards |video_frame| to the registered |sink_|. - virtual void IncomingCapturedFrame(const VideoFrame& video_frame); - rtc::VideoSinkWants sink_wants() const; - bool has_sinks() const; + virtual void IncomingCapturedFrame(const VideoFrame& video_frame) + RTC_LOCKS_EXCLUDED(crit_); + rtc::VideoSinkWants sink_wants() const RTC_LOCKS_EXCLUDED(crit_); + bool has_sinks() const RTC_LOCKS_EXCLUDED(crit_); protected: + rtc::VideoSinkWants sink_wants_locked() const + RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, - const rtc::VideoSinkWants& wants) override; - void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override; + const rtc::VideoSinkWants& wants) + RTC_LOCKS_EXCLUDED(crit_) override; + void AddOrUpdateSinkLocked(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) + RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); + void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) + RTC_LOCKS_EXCLUDED(crit_) override; rtc::CriticalSection crit_; rtc::VideoSinkInterface<VideoFrame>* sink_ RTC_GUARDED_BY(crit_); diff --git a/chromium/third_party/webrtc/test/frame_generator_capturer_unittest.cc b/chromium/third_party/webrtc/test/frame_generator_capturer_unittest.cc index 7400bbb79bd..a76cb95d443 100644 --- a/chromium/third_party/webrtc/test/frame_generator_capturer_unittest.cc +++ b/chromium/third_party/webrtc/test/frame_generator_capturer_unittest.cc @@ -22,8 +22,8 @@ using ::testing::Property; class MockVideoSinkInterfaceVideoFrame : public rtc::VideoSinkInterface<VideoFrame> { public: - MOCK_METHOD1(OnFrame, void(const VideoFrame& frame)); - MOCK_METHOD0(OnDiscardedFrame, void()); + MOCK_METHOD(void, OnFrame, (const VideoFrame& frame), (override)); + MOCK_METHOD(void, OnDiscardedFrame, (), (override)); }; } // namespace TEST(FrameGeneratorCapturerTest, CreateFromConfig) { diff --git a/chromium/third_party/webrtc/test/fuzzers/BUILD.gn b/chromium/third_party/webrtc/test/fuzzers/BUILD.gn index 96376a2e839..203490f417c 100644 --- a/chromium/third_party/webrtc/test/fuzzers/BUILD.gn +++ b/chromium/third_party/webrtc/test/fuzzers/BUILD.gn @@ -40,6 +40,10 @@ rtc_library("fuzz_data_helper") { visibility = [ ":*" ] # Only targets in this file can depend on this. } +set_defaults("webrtc_fuzzer_test") { + absl_deps = [] +} + template("webrtc_fuzzer_test") { fuzzer_test(target_name) { forward_variables_from(invoker, "*") @@ -47,6 +51,21 @@ template("webrtc_fuzzer_test") { ":fuzz_data_helper", ":webrtc_fuzzer_main", ] + + # If absl_deps is [], no action is needed. If not [], then it needs to be + # converted to //third_party/abseil-cpp:absl when build_with_chromium=true + # otherwise it just needs to be added to deps. + if (absl_deps != []) { + if (!defined(deps)) { + deps = [] + } + if (build_with_chromium) { + deps += [ "//third_party/abseil-cpp:absl" ] + } else { + deps += absl_deps + } + } + if (!build_with_chromium && is_clang) { suppressed_configs = [ "//build/config/clang:find_bad_constructs" ] } @@ -194,10 +213,8 @@ webrtc_fuzzer_test("rtcp_receiver_fuzzer") { webrtc_fuzzer_test("rtp_packet_fuzzer") { sources = [ "rtp_packet_fuzzer.cc" ] - deps = [ - "../../modules/rtp_rtcp:rtp_rtcp_format", - "//third_party/abseil-cpp/absl/types:optional", - ] + deps = [ "../../modules/rtp_rtcp:rtp_rtcp_format" ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] seed_corpus = "corpora/rtp-corpus" } @@ -240,8 +257,8 @@ rtc_library("audio_decoder_fuzzer") { "../../modules/rtp_rtcp:rtp_rtcp_format", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } webrtc_fuzzer_test("audio_decoder_ilbc_fuzzer") { @@ -318,7 +335,7 @@ webrtc_fuzzer_test("audio_encoder_opus_fuzzer") { } webrtc_fuzzer_test("audio_encoder_isac_fixed_fuzzer") { - sources = [ "audio_encoder_isax_fixed_fuzzer.cc" ] + sources = [ "audio_encoder_isac_fixed_fuzzer.cc" ] deps = [ ":audio_encoder_fuzzer", "../../api/audio_codecs/isac:audio_encoder_isac_fix", @@ -327,7 +344,7 @@ webrtc_fuzzer_test("audio_encoder_isac_fixed_fuzzer") { } webrtc_fuzzer_test("audio_encoder_isac_float_fuzzer") { - sources = [ "audio_encoder_isax_float_fuzzer.cc" ] + sources = [ "audio_encoder_isac_float_fuzzer.cc" ] deps = [ ":audio_encoder_fuzzer", "../../api/audio_codecs/isac:audio_encoder_isac_float", @@ -439,8 +456,8 @@ rtc_library("audio_processing_fuzzer_helper") { "../../modules/audio_processing:audio_frame_proxies", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } webrtc_fuzzer_test("audio_processing_fuzzer") { @@ -461,8 +478,8 @@ webrtc_fuzzer_test("audio_processing_fuzzer") { "../../rtc_base:rtc_task_queue", "../../rtc_base:safe_minmax", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] seed_corpus = "corpora/audio_processing-corpus" } diff --git a/chromium/third_party/webrtc/test/logging/BUILD.gn b/chromium/third_party/webrtc/test/logging/BUILD.gn index db2a5447ac9..1af2ecfdac2 100644 --- a/chromium/third_party/webrtc/test/logging/BUILD.gn +++ b/chromium/third_party/webrtc/test/logging/BUILD.gn @@ -27,6 +27,6 @@ rtc_library("log_writer") { "../../rtc_base:rtc_base_tests_utils", "../../rtc_base:stringutils", "../../test:fileutils", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } diff --git a/chromium/third_party/webrtc/test/mock_audio_decoder.h b/chromium/third_party/webrtc/test/mock_audio_decoder.h index 7c6db5acc22..8f44bf891d5 100644 --- a/chromium/third_party/webrtc/test/mock_audio_decoder.h +++ b/chromium/third_party/webrtc/test/mock_audio_decoder.h @@ -20,16 +20,18 @@ class MockAudioDecoder : public AudioDecoder { public: MockAudioDecoder(); ~MockAudioDecoder(); - MOCK_METHOD0(Die, void()); - MOCK_METHOD5(DecodeInternal, - int(const uint8_t*, size_t, int, int16_t*, SpeechType*)); - MOCK_CONST_METHOD0(HasDecodePlc, bool()); - MOCK_METHOD2(DecodePlc, size_t(size_t, int16_t*)); - MOCK_METHOD0(Reset, void()); - MOCK_METHOD0(ErrorCode, int()); - MOCK_CONST_METHOD2(PacketDuration, int(const uint8_t*, size_t)); - MOCK_CONST_METHOD0(Channels, size_t()); - MOCK_CONST_METHOD0(SampleRateHz, int()); + MOCK_METHOD(void, Die, ()); + MOCK_METHOD(int, + DecodeInternal, + (const uint8_t*, size_t, int, int16_t*, SpeechType*), + (override)); + MOCK_METHOD(bool, HasDecodePlc, (), (const, override)); + MOCK_METHOD(size_t, DecodePlc, (size_t, int16_t*), (override)); + MOCK_METHOD(void, Reset, (), (override)); + MOCK_METHOD(int, ErrorCode, (), (override)); + MOCK_METHOD(int, PacketDuration, (const uint8_t*, size_t), (const, override)); + MOCK_METHOD(size_t, Channels, (), (const, override)); + MOCK_METHOD(int, SampleRateHz, (), (const, override)); }; } // namespace webrtc diff --git a/chromium/third_party/webrtc/test/mock_audio_decoder_factory.h b/chromium/third_party/webrtc/test/mock_audio_decoder_factory.h index cdf29195433..cdb03d3f380 100644 --- a/chromium/third_party/webrtc/test/mock_audio_decoder_factory.h +++ b/chromium/third_party/webrtc/test/mock_audio_decoder_factory.h @@ -24,19 +24,23 @@ namespace webrtc { class MockAudioDecoderFactory : public AudioDecoderFactory { public: - MOCK_METHOD0(GetSupportedDecoders, std::vector<AudioCodecSpec>()); - MOCK_METHOD1(IsSupportedDecoder, bool(const SdpAudioFormat&)); + MOCK_METHOD(std::vector<AudioCodecSpec>, + GetSupportedDecoders, + (), + (override)); + MOCK_METHOD(bool, IsSupportedDecoder, (const SdpAudioFormat&), (override)); std::unique_ptr<AudioDecoder> MakeAudioDecoder( const SdpAudioFormat& format, - absl::optional<AudioCodecPairId> codec_pair_id) { + absl::optional<AudioCodecPairId> codec_pair_id) override { std::unique_ptr<AudioDecoder> return_value; MakeAudioDecoderMock(format, codec_pair_id, &return_value); return return_value; } - MOCK_METHOD3(MakeAudioDecoderMock, - void(const SdpAudioFormat& format, - absl::optional<AudioCodecPairId> codec_pair_id, - std::unique_ptr<AudioDecoder>* return_value)); + MOCK_METHOD(void, + MakeAudioDecoderMock, + (const SdpAudioFormat& format, + absl::optional<AudioCodecPairId> codec_pair_id, + std::unique_ptr<AudioDecoder>*)); // Creates a MockAudioDecoderFactory with no formats and that may not be // invoked to create a codec - useful for initializing a voice engine, for diff --git a/chromium/third_party/webrtc/test/mock_audio_encoder.h b/chromium/third_party/webrtc/test/mock_audio_encoder.h index 2dfd15ca981..9d9db0d66cd 100644 --- a/chromium/third_party/webrtc/test/mock_audio_encoder.h +++ b/chromium/third_party/webrtc/test/mock_audio_encoder.h @@ -27,37 +27,44 @@ class MockAudioEncoder : public AudioEncoder { // http://crbug.com/428099. MockAudioEncoder(); ~MockAudioEncoder(); - MOCK_METHOD1(Mark, void(std::string desc)); - MOCK_CONST_METHOD0(SampleRateHz, int()); - MOCK_CONST_METHOD0(NumChannels, size_t()); - MOCK_CONST_METHOD0(RtpTimestampRateHz, int()); - MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, size_t()); - MOCK_CONST_METHOD0(Max10MsFramesInAPacket, size_t()); - MOCK_CONST_METHOD0(GetTargetBitrate, int()); - MOCK_CONST_METHOD0(GetFrameLengthRange, - absl::optional<std::pair<TimeDelta, TimeDelta>>()); - - MOCK_METHOD0(Reset, void()); - MOCK_METHOD1(SetFec, bool(bool enable)); - MOCK_METHOD1(SetDtx, bool(bool enable)); - MOCK_METHOD1(SetApplication, bool(Application application)); - MOCK_METHOD1(SetMaxPlaybackRate, void(int frequency_hz)); - MOCK_METHOD1(SetMaxBitrate, void(int max_bps)); - MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes)); - MOCK_METHOD2(OnReceivedUplinkBandwidth, - void(int target_audio_bitrate_bps, - absl::optional<int64_t> probing_interval_ms)); - MOCK_METHOD1(OnReceivedUplinkPacketLossFraction, - void(float uplink_packet_loss_fraction)); - - MOCK_METHOD2(EnableAudioNetworkAdaptor, - bool(const std::string& config_string, RtcEventLog* event_log)); + MOCK_METHOD(int, SampleRateHz, (), (const, override)); + MOCK_METHOD(size_t, NumChannels, (), (const, override)); + MOCK_METHOD(int, RtpTimestampRateHz, (), (const, override)); + MOCK_METHOD(size_t, Num10MsFramesInNextPacket, (), (const, override)); + MOCK_METHOD(size_t, Max10MsFramesInAPacket, (), (const, override)); + MOCK_METHOD(int, GetTargetBitrate, (), (const, override)); + MOCK_METHOD((absl::optional<std::pair<TimeDelta, TimeDelta>>), + GetFrameLengthRange, + (), + (const, override)); + + MOCK_METHOD(void, Reset, (), (override)); + MOCK_METHOD(bool, SetFec, (bool enable), (override)); + MOCK_METHOD(bool, SetDtx, (bool enable), (override)); + MOCK_METHOD(bool, SetApplication, (Application application), (override)); + MOCK_METHOD(void, SetMaxPlaybackRate, (int frequency_hz), (override)); + MOCK_METHOD(void, + OnReceivedUplinkBandwidth, + (int target_audio_bitrate_bps, + absl::optional<int64_t> probing_interval_ms), + (override)); + MOCK_METHOD(void, + OnReceivedUplinkPacketLossFraction, + (float uplink_packet_loss_fraction), + (override)); + + MOCK_METHOD(bool, + EnableAudioNetworkAdaptor, + (const std::string& config_string, RtcEventLog*), + (override)); // Note, we explicitly chose not to create a mock for the Encode method. - MOCK_METHOD3(EncodeImpl, - EncodedInfo(uint32_t timestamp, - rtc::ArrayView<const int16_t> audio, - rtc::Buffer* encoded)); + MOCK_METHOD(EncodedInfo, + EncodeImpl, + (uint32_t timestamp, + rtc::ArrayView<const int16_t> audio, + rtc::Buffer*), + (override)); class FakeEncoding { public: diff --git a/chromium/third_party/webrtc/test/mock_audio_encoder_factory.h b/chromium/third_party/webrtc/test/mock_audio_encoder_factory.h index 3e774a39e9d..392a4c11e2e 100644 --- a/chromium/third_party/webrtc/test/mock_audio_encoder_factory.h +++ b/chromium/third_party/webrtc/test/mock_audio_encoder_factory.h @@ -24,23 +24,29 @@ namespace webrtc { class MockAudioEncoderFactory : public ::testing::NiceMock<AudioEncoderFactory> { public: - MOCK_METHOD0(GetSupportedEncoders, std::vector<AudioCodecSpec>()); - MOCK_METHOD1(QueryAudioEncoder, - absl::optional<AudioCodecInfo>(const SdpAudioFormat& format)); + MOCK_METHOD(std::vector<AudioCodecSpec>, + GetSupportedEncoders, + (), + (override)); + MOCK_METHOD(absl::optional<AudioCodecInfo>, + QueryAudioEncoder, + (const SdpAudioFormat& format), + (override)); std::unique_ptr<AudioEncoder> MakeAudioEncoder( int payload_type, const SdpAudioFormat& format, - absl::optional<AudioCodecPairId> codec_pair_id) { + absl::optional<AudioCodecPairId> codec_pair_id) override { std::unique_ptr<AudioEncoder> return_value; MakeAudioEncoderMock(payload_type, format, codec_pair_id, &return_value); return return_value; } - MOCK_METHOD4(MakeAudioEncoderMock, - void(int payload_type, - const SdpAudioFormat& format, - absl::optional<AudioCodecPairId> codec_pair_id, - std::unique_ptr<AudioEncoder>* return_value)); + MOCK_METHOD(void, + MakeAudioEncoderMock, + (int payload_type, + const SdpAudioFormat& format, + absl::optional<AudioCodecPairId> codec_pair_id, + std::unique_ptr<AudioEncoder>*)); // Creates a MockAudioEncoderFactory with no formats and that may not be // invoked to create a codec - useful for initializing a voice engine, for diff --git a/chromium/third_party/webrtc/test/mock_transport.h b/chromium/third_party/webrtc/test/mock_transport.h index 5ffc10425b6..9c4dc4bf8dc 100644 --- a/chromium/third_party/webrtc/test/mock_transport.h +++ b/chromium/third_party/webrtc/test/mock_transport.h @@ -25,7 +25,7 @@ class MockTransport : public Transport { SendRtp, (const uint8_t*, size_t, const PacketOptions&), (override)); - MOCK_METHOD(bool, SendRtcp, (const uint8_t* data, size_t len), (override)); + MOCK_METHOD(bool, SendRtcp, (const uint8_t*, size_t len), (override)); }; } // namespace webrtc diff --git a/chromium/third_party/webrtc/test/network/BUILD.gn b/chromium/third_party/webrtc/test/network/BUILD.gn index 4b01479c9b6..9e810bfc530 100644 --- a/chromium/third_party/webrtc/test/network/BUILD.gn +++ b/chromium/third_party/webrtc/test/network/BUILD.gn @@ -54,6 +54,8 @@ rtc_library("emulated_network") { "../../system_wrappers", "../scenario:column_printer", "../time_controller", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/types:optional", @@ -114,8 +116,8 @@ rtc_library("cross_traffic_unittest") { "../../rtc_base:logging", "../../rtc_base:rtc_event", "//test/time_controller:time_controller", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_library("feedback_generator") { @@ -130,8 +132,8 @@ rtc_library("feedback_generator") { "../../call:simulated_network", "../../rtc_base:checks", "../time_controller", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_library("feedback_generator_unittest") { diff --git a/chromium/third_party/webrtc/test/network/cross_traffic.cc b/chromium/third_party/webrtc/test/network/cross_traffic.cc index be0c3d32863..56e7635142e 100644 --- a/chromium/third_party/webrtc/test/network/cross_traffic.cc +++ b/chromium/third_party/webrtc/test/network/cross_traffic.cc @@ -144,15 +144,16 @@ void TcpMessageRouteImpl::SendMessage(size_t size, cwnd_ = 10; ssthresh_ = INFINITY; } - size_t data_left = size; - size_t kMaxPacketSize = 1200; - size_t kMinPacketSize = 4; + int64_t data_left = static_cast<int64_t>(size); + int64_t kMaxPacketSize = 1200; + int64_t kMinPacketSize = 4; Message message{std::move(handler)}; while (data_left > 0) { - size_t packet_size = - std::max(kMinPacketSize, std::min(data_left, kMaxPacketSize)); + int64_t packet_size = std::min(data_left, kMaxPacketSize); int fragment_id = next_fragment_id_++; - pending_.push_back(MessageFragment{fragment_id, packet_size}); + pending_.push_back(MessageFragment{ + fragment_id, + static_cast<size_t>(std::max(kMinPacketSize, packet_size))}); message.pending_fragment_ids.insert(fragment_id); data_left -= packet_size; } diff --git a/chromium/third_party/webrtc/test/network/network_emulation_unittest.cc b/chromium/third_party/webrtc/test/network/network_emulation_unittest.cc index 58346abb93c..9e630de9cb9 100644 --- a/chromium/third_party/webrtc/test/network/network_emulation_unittest.cc +++ b/chromium/third_party/webrtc/test/network/network_emulation_unittest.cc @@ -70,7 +70,7 @@ class SocketReader : public sigslot::has_slots<> { class MockReceiver : public EmulatedNetworkReceiverInterface { public: - MOCK_METHOD1(OnPacketReceived, void(EmulatedIpPacket packet)); + MOCK_METHOD(void, OnPacketReceived, (EmulatedIpPacket packet), (override)); }; class NetworkEmulationManagerThreeNodesRoutingTest : public ::testing::Test { diff --git a/chromium/third_party/webrtc/test/pc/e2e/BUILD.gn b/chromium/third_party/webrtc/test/pc/e2e/BUILD.gn index d340f1a00cc..fea59bcb87e 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/BUILD.gn +++ b/chromium/third_party/webrtc/test/pc/e2e/BUILD.gn @@ -8,632 +8,681 @@ import("../../../webrtc.gni") -group("e2e") { - testonly = true - - deps = [ - ":default_encoded_image_data_injector", - ":encoded_image_data_injector_api", - ":example_video_quality_analyzer", - ":id_generator", - ":quality_analyzing_video_decoder", - ":quality_analyzing_video_encoder", - ":single_process_encoded_image_data_injector", - ] - if (rtc_include_tests) { - deps += [ - ":peerconnection_quality_test", - ":test_peer", - ":video_quality_analyzer_injection_helper", - ] - } -} - -if (rtc_include_tests) { - group("e2e_unittests") { +if (!build_with_chromium) { + group("e2e") { testonly = true deps = [ - ":default_encoded_image_data_injector_unittest", - ":default_video_quality_analyzer_test", - ":peer_connection_e2e_smoke_test", - ":single_process_encoded_image_data_injector_unittest", + ":default_encoded_image_data_injector", + ":encoded_image_data_injector_api", + ":example_video_quality_analyzer", + ":id_generator", + ":quality_analyzing_video_decoder", + ":quality_analyzing_video_encoder", + ":single_process_encoded_image_data_injector", ] + if (rtc_include_tests) { + deps += [ + ":peerconnection_quality_test", + ":test_peer", + ":video_quality_analyzer_injection_helper", + ] + } } -} - -rtc_library("peer_connection_quality_test_params") { - visibility = [ "*" ] - testonly = true - sources = [ "peer_connection_quality_test_params.h" ] - - deps = [ - "../../../api:callfactory_api", - "../../../api:fec_controller_api", - "../../../api:libjingle_peerconnection_api", - "../../../api:packet_socket_factory", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../api/rtc_event_log", - "../../../api/task_queue", - "../../../api/transport:network_control", - "../../../api/transport/media:media_transport_interface", - "../../../api/video_codecs:video_codecs_api", - "../../../rtc_base", - ] -} - -rtc_library("encoded_image_data_injector_api") { - visibility = [ "*" ] - testonly = true - sources = [ "analyzer/video/encoded_image_data_injector.h" ] - - deps = [ "../../../api/video:encoded_image" ] -} -rtc_library("default_encoded_image_data_injector") { - visibility = [ "*" ] - testonly = true - sources = [ - "analyzer/video/default_encoded_image_data_injector.cc", - "analyzer/video/default_encoded_image_data_injector.h", - ] - - deps = [ - ":encoded_image_data_injector_api", - "../../../api/video:encoded_image", - "../../../rtc_base:checks", - "../../../rtc_base:criticalsection", - "//third_party/abseil-cpp/absl/memory", - ] -} + if (rtc_include_tests) { + group("e2e_unittests") { + testonly = true -rtc_library("single_process_encoded_image_data_injector") { - visibility = [ "*" ] - testonly = true - sources = [ - "analyzer/video/single_process_encoded_image_data_injector.cc", - "analyzer/video/single_process_encoded_image_data_injector.h", - ] - - deps = [ - ":encoded_image_data_injector_api", - "../../../api/video:encoded_image", - "../../../rtc_base:checks", - "../../../rtc_base:criticalsection", - "//third_party/abseil-cpp/absl/memory", - ] -} + deps = [ + ":default_encoded_image_data_injector_unittest", + ":default_video_quality_analyzer_test", + ":multi_head_queue_test", + ":peer_connection_e2e_smoke_test", + ":single_process_encoded_image_data_injector_unittest", + ] + } + } -rtc_library("id_generator") { - visibility = [ "*" ] - testonly = true - sources = [ - "analyzer/video/id_generator.cc", - "analyzer/video/id_generator.h", - ] - deps = [] -} + rtc_library("peer_connection_quality_test_params") { + visibility = [ "*" ] + testonly = true + sources = [ "peer_connection_quality_test_params.h" ] -rtc_library("simulcast_dummy_buffer_helper") { - visibility = [ "*" ] - testonly = true - sources = [ - "analyzer/video/simulcast_dummy_buffer_helper.cc", - "analyzer/video/simulcast_dummy_buffer_helper.h", - ] - deps = [ - "../../../api/video:video_frame", - "../../../api/video:video_frame_i420", - ] -} + deps = [ + "../../../api:callfactory_api", + "../../../api:fec_controller_api", + "../../../api:libjingle_peerconnection_api", + "../../../api:packet_socket_factory", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api/rtc_event_log", + "../../../api/task_queue", + "../../../api/transport:network_control", + "../../../api/video_codecs:video_codecs_api", + "../../../rtc_base", + ] + } -rtc_library("quality_analyzing_video_decoder") { - visibility = [ "*" ] - testonly = true - sources = [ - "analyzer/video/quality_analyzing_video_decoder.cc", - "analyzer/video/quality_analyzing_video_decoder.h", - ] - deps = [ - ":encoded_image_data_injector_api", - ":id_generator", - ":simulcast_dummy_buffer_helper", - "../../../api:video_quality_analyzer_api", - "../../../api/video:encoded_image", - "../../../api/video:video_frame", - "../../../api/video:video_frame_i420", - "../../../api/video:video_rtp_headers", - "../../../api/video_codecs:video_codecs_api", - "../../../modules/video_coding:video_codec_interface", - "../../../rtc_base:criticalsection", - "../../../rtc_base:logging", - "//third_party/abseil-cpp/absl/types:optional", - ] -} + rtc_library("encoded_image_data_injector_api") { + visibility = [ "*" ] + testonly = true + sources = [ "analyzer/video/encoded_image_data_injector.h" ] -rtc_library("quality_analyzing_video_encoder") { - visibility = [ "*" ] - testonly = true - sources = [ - "analyzer/video/quality_analyzing_video_encoder.cc", - "analyzer/video/quality_analyzing_video_encoder.h", - ] - deps = [ - ":encoded_image_data_injector_api", - ":id_generator", - "../../../api:video_quality_analyzer_api", - "../../../api/video:encoded_image", - "../../../api/video:video_frame", - "../../../api/video:video_rtp_headers", - "../../../api/video_codecs:video_codecs_api", - "../../../modules/video_coding:video_codec_interface", - "../../../rtc_base:criticalsection", - "../../../rtc_base:logging", - ] -} + deps = [ "../../../api/video:encoded_image" ] + } -if (rtc_include_tests) { - rtc_library("video_quality_analyzer_injection_helper") { + rtc_library("default_encoded_image_data_injector") { visibility = [ "*" ] testonly = true sources = [ - "analyzer/video/video_quality_analyzer_injection_helper.cc", - "analyzer/video/video_quality_analyzer_injection_helper.h", + "analyzer/video/default_encoded_image_data_injector.cc", + "analyzer/video/default_encoded_image_data_injector.h", ] + deps = [ ":encoded_image_data_injector_api", - ":id_generator", - ":quality_analyzing_video_decoder", - ":quality_analyzing_video_encoder", - ":simulcast_dummy_buffer_helper", - "../..:test_renderer", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../api:stats_observer_interface", - "../../../api:video_quality_analyzer_api", - "../../../api/video:video_frame", - "../../../api/video:video_rtp_headers", - "../../../api/video_codecs:video_codecs_api", + "../../../api/video:encoded_image", + "../../../rtc_base:checks", "../../../rtc_base:criticalsection", - "../../../test:video_test_common", - "../../../test:video_test_support", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } - rtc_library("echo_emulation") { + rtc_library("single_process_encoded_image_data_injector") { visibility = [ "*" ] testonly = true sources = [ - "echo/echo_emulation.cc", - "echo/echo_emulation.h", + "analyzer/video/single_process_encoded_image_data_injector.cc", + "analyzer/video/single_process_encoded_image_data_injector.h", ] + deps = [ - "../../../api:peer_connection_quality_test_fixture_api", - "../../../modules/audio_device:audio_device_impl", - "../../../rtc_base:rtc_base_approved", + ":encoded_image_data_injector_api", + "../../../api/video:encoded_image", + "../../../rtc_base:checks", + "../../../rtc_base:criticalsection", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } - rtc_library("test_peer") { + rtc_library("id_generator") { visibility = [ "*" ] testonly = true sources = [ - "test_peer.cc", - "test_peer.h", + "analyzer/video/id_generator.cc", + "analyzer/video/id_generator.h", + ] + deps = [] + } + + rtc_library("simulcast_dummy_buffer_helper") { + visibility = [ "*" ] + testonly = true + sources = [ + "analyzer/video/simulcast_dummy_buffer_helper.cc", + "analyzer/video/simulcast_dummy_buffer_helper.h", ] deps = [ - ":peer_configurer", - ":peer_connection_quality_test_params", - "../../../api:frame_generator_api", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../api:scoped_refptr", - "../../../modules/audio_processing:api", - "../../../pc:peerconnection_wrapper", - "//third_party/abseil-cpp/absl/memory", - "//third_party/abseil-cpp/absl/types:variant", + "../../../api/video:video_frame", + "../../../api/video:video_frame_i420", ] } - rtc_library("test_peer_factory") { + rtc_library("quality_analyzing_video_decoder") { visibility = [ "*" ] testonly = true sources = [ - "test_peer_factory.cc", - "test_peer_factory.h", + "analyzer/video/quality_analyzing_video_decoder.cc", + "analyzer/video/quality_analyzing_video_decoder.h", ] deps = [ - ":echo_emulation", - ":peer_configurer", - ":peer_connection_quality_test_params", - ":quality_analyzing_video_encoder", - ":test_peer", - ":video_quality_analyzer_injection_helper", - "../..:copy_to_file_audio_capturer", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../api/rtc_event_log:rtc_event_log_factory", - "../../../api/task_queue:default_task_queue_factory", - "../../../api/video_codecs:builtin_video_decoder_factory", - "../../../api/video_codecs:builtin_video_encoder_factory", - "../../../media:rtc_audio_video", - "../../../media:rtc_media_engine_defaults", - "../../../modules/audio_device:audio_device_impl", - "../../../modules/audio_processing/aec_dump", - "../../../p2p:rtc_p2p", - "../../../rtc_base:rtc_task_queue", - "//third_party/abseil-cpp/absl/memory", + ":encoded_image_data_injector_api", + ":id_generator", + ":simulcast_dummy_buffer_helper", + "../../../api:video_quality_analyzer_api", + "../../../api/video:encoded_image", + "../../../api/video:video_frame", + "../../../api/video:video_frame_i420", + "../../../api/video:video_rtp_headers", + "../../../api/video_codecs:video_codecs_api", + "../../../modules/video_coding:video_codec_interface", + "../../../rtc_base:criticalsection", + "../../../rtc_base:logging", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", ] } - rtc_library("media_helper") { + rtc_library("quality_analyzing_video_encoder") { visibility = [ "*" ] testonly = true sources = [ - "media/media_helper.cc", - "media/media_helper.h", - "media/test_video_capturer_video_track_source.h", + "analyzer/video/quality_analyzing_video_encoder.cc", + "analyzer/video/quality_analyzing_video_encoder.h", ] deps = [ - ":peer_configurer", - ":test_peer", - ":video_quality_analyzer_injection_helper", - "../..:fileutils", - "../..:platform_video_capturer", - "../..:video_test_common", - "../../../api:create_frame_generator", - "../../../api:frame_generator_api", - "../../../api:media_stream_interface", - "../../../api:peer_connection_quality_test_fixture_api", + ":encoded_image_data_injector_api", + ":id_generator", + "../../../api:video_quality_analyzer_api", + "../../../api/video:encoded_image", "../../../api/video:video_frame", - "../../../pc:peerconnection", - "//third_party/abseil-cpp/absl/types:variant", + "../../../api/video:video_rtp_headers", + "../../../api/video_codecs:video_codecs_api", + "../../../modules/video_coding:video_codec_interface", + "../../../rtc_base:criticalsection", + "../../../rtc_base:logging", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + } + + if (rtc_include_tests) { + rtc_library("video_quality_analyzer_injection_helper") { + visibility = [ "*" ] + testonly = true + sources = [ + "analyzer/video/video_quality_analyzer_injection_helper.cc", + "analyzer/video/video_quality_analyzer_injection_helper.h", + ] + deps = [ + ":encoded_image_data_injector_api", + ":id_generator", + ":quality_analyzing_video_decoder", + ":quality_analyzing_video_encoder", + ":simulcast_dummy_buffer_helper", + "../..:test_renderer", + "../../../api:array_view", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api:stats_observer_interface", + "../../../api:video_quality_analyzer_api", + "../../../api/video:video_frame", + "../../../api/video:video_rtp_headers", + "../../../api/video_codecs:video_codecs_api", + "../../../rtc_base:criticalsection", + "../../../test:video_test_common", + "../../../test:video_test_support", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + ] + } + + rtc_library("echo_emulation") { + visibility = [ "*" ] + testonly = true + sources = [ + "echo/echo_emulation.cc", + "echo/echo_emulation.h", + ] + deps = [ + "../../../api:peer_connection_quality_test_fixture_api", + "../../../modules/audio_device:audio_device_impl", + "../../../rtc_base:rtc_base_approved", + ] + } + + rtc_library("test_peer") { + visibility = [ "*" ] + testonly = true + sources = [ + "test_peer.cc", + "test_peer.h", + ] + deps = [ + ":peer_configurer", + ":peer_connection_quality_test_params", + "../../../api:frame_generator_api", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api:scoped_refptr", + "../../../modules/audio_processing:api", + "../../../pc:peerconnection_wrapper", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/types:variant", + ] + } + + rtc_library("test_peer_factory") { + visibility = [ "*" ] + testonly = true + sources = [ + "test_peer_factory.cc", + "test_peer_factory.h", + ] + deps = [ + ":echo_emulation", + ":peer_configurer", + ":peer_connection_quality_test_params", + ":quality_analyzing_video_encoder", + ":test_peer", + ":video_quality_analyzer_injection_helper", + "../..:copy_to_file_audio_capturer", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api/rtc_event_log:rtc_event_log_factory", + "../../../api/task_queue:default_task_queue_factory", + "../../../api/video_codecs:builtin_video_decoder_factory", + "../../../api/video_codecs:builtin_video_encoder_factory", + "../../../media:rtc_audio_video", + "../../../media:rtc_media_engine_defaults", + "../../../modules/audio_device:audio_device_impl", + "../../../modules/audio_processing/aec_dump", + "../../../p2p:rtc_p2p", + "../../../rtc_base:rtc_task_queue", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + ] + } + + rtc_library("media_helper") { + visibility = [ "*" ] + testonly = true + sources = [ + "media/media_helper.cc", + "media/media_helper.h", + "media/test_video_capturer_video_track_source.h", + ] + deps = [ + ":peer_configurer", + ":test_peer", + ":video_quality_analyzer_injection_helper", + "../..:fileutils", + "../..:platform_video_capturer", + "../..:video_test_common", + "../../../api:create_frame_generator", + "../../../api:frame_generator_api", + "../../../api:media_stream_interface", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api/video:video_frame", + "../../../pc:peerconnection", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:variant" ] + } + + rtc_library("peer_configurer") { + visibility = [ "*" ] + testonly = true + sources = [ + "peer_configurer.cc", + "peer_configurer.h", + ] + deps = [ + ":peer_connection_quality_test_params", + "../..:fileutils", + "../../../api:callfactory_api", + "../../../api:create_peer_connection_quality_test_frame_generator", + "../../../api:fec_controller_api", + "../../../api:packet_socket_factory", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api/rtc_event_log", + "../../../api/task_queue", + "../../../api/transport:network_control", + "../../../api/video_codecs:video_codecs_api", + "../../../rtc_base", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + } + + rtc_library("test_activities_executor") { + visibility = [ "*" ] + testonly = true + sources = [ + "test_activities_executor.cc", + "test_activities_executor.h", + ] + deps = [ + "../../../api/units:time_delta", + "../../../api/units:timestamp", + "../../../rtc_base:checks", + "../../../rtc_base:criticalsection", + "../../../rtc_base:logging", + "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:task_queue_for_test", + "../../../rtc_base/task_utils:repeating_task", + "../../../system_wrappers", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/types:optional", + ] + } + + rtc_library("peerconnection_quality_test") { + visibility = [ "*" ] + testonly = true + + sources = [ + "peer_connection_quality_test.cc", + "peer_connection_quality_test.h", + ] + deps = [ + ":analyzer_helper", + ":default_audio_quality_analyzer", + ":default_video_quality_analyzer", + ":media_helper", + ":peer_configurer", + ":peer_connection_quality_test_params", + ":sdp_changer", + ":single_process_encoded_image_data_injector", + ":stats_poller", + ":test_activities_executor", + ":test_peer", + ":test_peer_factory", + ":video_quality_analyzer_injection_helper", + ":video_quality_metrics_reporter", + "../..:field_trial", + "../..:fileutils", + "../..:perf_test", + "../../../api:audio_quality_analyzer_api", + "../../../api:libjingle_peerconnection_api", + "../../../api:media_stream_interface", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api:rtc_event_log_output_file", + "../../../api:scoped_refptr", + "../../../api:video_quality_analyzer_api", + "../../../api/rtc_event_log", + "../../../api/task_queue", + "../../../api/task_queue:default_task_queue_factory", + "../../../api/units:time_delta", + "../../../api/units:timestamp", + "../../../pc:pc_test_utils", + "../../../pc:peerconnection", + "../../../rtc_base", + "../../../rtc_base:gunit_helpers", + "../../../rtc_base:macromagic", + "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", + "../../../rtc_base:task_queue_for_test", + "../../../system_wrappers", + "../../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + } + + rtc_library("single_process_encoded_image_data_injector_unittest") { + testonly = true + sources = [ + "analyzer/video/single_process_encoded_image_data_injector_unittest.cc", + ] + deps = [ + ":single_process_encoded_image_data_injector", + "../../../api/video:encoded_image", + "../../../rtc_base:rtc_base_approved", + "../../../test:test_support", + ] + } + + rtc_library("default_encoded_image_data_injector_unittest") { + testonly = true + sources = + [ "analyzer/video/default_encoded_image_data_injector_unittest.cc" ] + deps = [ + ":default_encoded_image_data_injector", + "../../../api/video:encoded_image", + "../../../rtc_base:rtc_base_approved", + "../../../test:test_support", + ] + } + + peer_connection_e2e_smoke_test_resources = [ + "../../../resources/pc_quality_smoke_test_alice_source.wav", + "../../../resources/pc_quality_smoke_test_bob_source.wav", ] + if (is_ios) { + bundle_data("peer_connection_e2e_smoke_test_resources_bundle_data") { + testonly = true + sources = peer_connection_e2e_smoke_test_resources + outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] + } + } + + rtc_library("peer_connection_e2e_smoke_test") { + testonly = true + + sources = [ "peer_connection_e2e_smoke_test.cc" ] + deps = [ + ":default_audio_quality_analyzer", + ":default_video_quality_analyzer", + ":network_quality_metrics_reporter", + "../../../api:callfactory_api", + "../../../api:create_network_emulation_manager", + "../../../api:create_peer_connection_quality_test_frame_generator", + "../../../api:create_peerconnection_quality_test_fixture", + "../../../api:libjingle_peerconnection_api", + "../../../api:media_stream_interface", + "../../../api:network_emulation_manager_api", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api:scoped_refptr", + "../../../api:simulated_network_api", + "../../../api/audio_codecs:builtin_audio_decoder_factory", + "../../../api/audio_codecs:builtin_audio_encoder_factory", + "../../../api/video_codecs:builtin_video_decoder_factory", + "../../../api/video_codecs:builtin_video_encoder_factory", + "../../../call:simulated_network", + "../../../media:rtc_audio_video", + "../../../modules/audio_device:audio_device_impl", + "../../../p2p:rtc_p2p", + "../../../pc:pc_test_utils", + "../../../pc:peerconnection_wrapper", + "../../../rtc_base", + "../../../rtc_base:gunit_helpers", + "../../../rtc_base:logging", + "../../../rtc_base:rtc_event", + "../../../system_wrappers:field_trial", + "../../../test:field_trial", + "../../../test:fileutils", + "../../../test:test_support", + ] + data = peer_connection_e2e_smoke_test_resources + if (is_ios) { + deps += [ ":peer_connection_e2e_smoke_test_resources_bundle_data" ] + } + } + + rtc_library("stats_poller") { + visibility = [ "*" ] + testonly = true + sources = [ + "stats_poller.cc", + "stats_poller.h", + ] + deps = [ + ":test_peer", + "../../../api:libjingle_peerconnection_api", + "../../../api:rtc_stats_api", + "../../../api:stats_observer_interface", + "../../../rtc_base:logging", + ] + } + + rtc_library("default_video_quality_analyzer_test") { + testonly = true + sources = [ "analyzer/video/default_video_quality_analyzer_test.cc" ] + deps = [ + ":default_video_quality_analyzer", + "../..:test_support", + "../../../api:create_frame_generator", + "../../../api:rtp_packet_info", + "../../../api/video:encoded_image", + "../../../api/video:video_frame", + "../../../api/video:video_frame_i420", + "../../../modules/rtp_rtcp:rtp_rtcp_format", + "../../../rtc_base:stringutils", + "../../../system_wrappers", + ] + } + + rtc_library("multi_head_queue_test") { + testonly = true + sources = [ "analyzer/video/multi_head_queue_test.cc" ] + deps = [ + ":multi_head_queue", + "../../../test:test_support", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + } } - rtc_library("peer_configurer") { + rtc_library("analyzer_helper") { visibility = [ "*" ] - testonly = true sources = [ - "peer_configurer.cc", - "peer_configurer.h", + "analyzer_helper.cc", + "analyzer_helper.h", ] deps = [ - ":peer_connection_quality_test_params", - "../..:fileutils", - "../../../api:callfactory_api", - "../../../api:create_peer_connection_quality_test_frame_generator", - "../../../api:fec_controller_api", - "../../../api:packet_socket_factory", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../api/rtc_event_log", - "../../../api/task_queue", - "../../../api/transport:network_control", - "../../../api/transport/media:media_transport_interface", - "../../../api/video_codecs:video_codecs_api", - "../../../rtc_base", - "//third_party/abseil-cpp/absl/strings", + "../../../api:track_id_stream_label_map", + "../../../rtc_base:macromagic", + "../../../rtc_base/synchronization:sequence_checker", ] } - rtc_library("test_activities_executor") { + rtc_library("default_audio_quality_analyzer") { visibility = [ "*" ] testonly = true sources = [ - "test_activities_executor.cc", - "test_activities_executor.h", + "analyzer/audio/default_audio_quality_analyzer.cc", + "analyzer/audio/default_audio_quality_analyzer.h", ] + deps = [ + "../..:perf_test", + "../../../api:audio_quality_analyzer_api", + "../../../api:rtc_stats_api", + "../../../api:stats_observer_interface", + "../../../api:track_id_stream_label_map", "../../../api/units:time_delta", "../../../api/units:timestamp", - "../../../rtc_base:checks", "../../../rtc_base:criticalsection", "../../../rtc_base:logging", - "../../../rtc_base:rtc_base_approved", - "../../../rtc_base:task_queue_for_test", - "../../../rtc_base/task_utils:repeating_task", - "../../../system_wrappers", - "//third_party/abseil-cpp/absl/memory", - "//third_party/abseil-cpp/absl/types:optional", + "../../../rtc_base:rtc_numerics", ] } - rtc_library("peerconnection_quality_test") { + rtc_library("example_video_quality_analyzer") { visibility = [ "*" ] testonly = true - sources = [ - "peer_connection_quality_test.cc", - "peer_connection_quality_test.h", + "analyzer/video/example_video_quality_analyzer.cc", + "analyzer/video/example_video_quality_analyzer.h", ] + deps = [ - ":analyzer_helper", - ":default_audio_quality_analyzer", - ":default_video_quality_analyzer", - ":media_helper", - ":peer_configurer", - ":peer_connection_quality_test_params", - ":sdp_changer", - ":single_process_encoded_image_data_injector", - ":stats_poller", - ":test_activities_executor", - ":test_peer", - ":test_peer_factory", - ":video_quality_analyzer_injection_helper", - ":video_quality_metrics_reporter", - "../..:field_trial", - "../..:fileutils", - "../..:perf_test", - "../../../api:audio_quality_analyzer_api", - "../../../api:libjingle_peerconnection_api", - "../../../api:media_stream_interface", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../api:rtc_event_log_output_file", - "../../../api:scoped_refptr", + "../../../api:array_view", "../../../api:video_quality_analyzer_api", - "../../../api/rtc_event_log", - "../../../api/task_queue", - "../../../api/task_queue:default_task_queue_factory", - "../../../api/units:time_delta", - "../../../api/units:timestamp", - "../../../pc:pc_test_utils", - "../../../pc:peerconnection", - "../../../rtc_base", - "../../../rtc_base:gunit_helpers", - "../../../rtc_base:macromagic", - "../../../rtc_base:rtc_base_approved", - "../../../rtc_base:safe_conversions", - "../../../rtc_base:task_queue_for_test", - "../../../system_wrappers", - "../../../system_wrappers:field_trial", + "../../../api/video:encoded_image", + "../../../api/video:video_frame", + "../../../api/video:video_rtp_headers", + "../../../rtc_base:criticalsection", + "../../../rtc_base:logging", ] } - rtc_library("single_process_encoded_image_data_injector_unittest") { + rtc_library("video_quality_metrics_reporter") { + visibility = [ "*" ] + testonly = true sources = [ - "analyzer/video/single_process_encoded_image_data_injector_unittest.cc", + "analyzer/video/video_quality_metrics_reporter.cc", + "analyzer/video/video_quality_metrics_reporter.h", ] deps = [ - ":single_process_encoded_image_data_injector", - "../../../api/video:encoded_image", - "../../../rtc_base:rtc_base_approved", - "../../../test:test_support", + "../..:perf_test", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api:rtc_stats_api", + "../../../api/units:data_rate", + "../../../api/units:data_size", + "../../../api/units:time_delta", + "../../../api/units:timestamp", + "../../../rtc_base:criticalsection", + "../../../rtc_base:rtc_numerics", ] } - rtc_library("default_encoded_image_data_injector_unittest") { + rtc_library("default_video_quality_analyzer") { + visibility = [ "*" ] + testonly = true - sources = - [ "analyzer/video/default_encoded_image_data_injector_unittest.cc" ] + sources = [ + "analyzer/video/default_video_quality_analyzer.cc", + "analyzer/video/default_video_quality_analyzer.h", + ] + deps = [ - ":default_encoded_image_data_injector", + ":multi_head_queue", + "../..:perf_test", + "../../../api:array_view", + "../../../api:video_quality_analyzer_api", + "../../../api/units:time_delta", + "../../../api/units:timestamp", "../../../api/video:encoded_image", + "../../../api/video:video_frame", + "../../../api/video:video_frame_i420", + "../../../api/video:video_rtp_headers", + "../../../common_video", + "../../../rtc_base:criticalsection", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", - "../../../test:test_support", + "../../../rtc_base:rtc_base_tests_utils", + "../../../rtc_base:rtc_event", + "../../../rtc_base:rtc_numerics", + "../../../rtc_base:timeutils", + "../../../system_wrappers", ] } - peer_connection_e2e_smoke_test_resources = [ - "../../../resources/pc_quality_smoke_test_alice_source.wav", - "../../../resources/pc_quality_smoke_test_bob_source.wav", - ] - if (is_ios) { - bundle_data("peer_connection_e2e_smoke_test_resources_bundle_data") { - testonly = true - sources = peer_connection_e2e_smoke_test_resources - outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] - } - } - - rtc_library("peer_connection_e2e_smoke_test") { + rtc_library("network_quality_metrics_reporter") { + visibility = [ "*" ] testonly = true - - sources = [ "peer_connection_e2e_smoke_test.cc" ] + sources = [ + "network_quality_metrics_reporter.cc", + "network_quality_metrics_reporter.h", + ] deps = [ - ":default_audio_quality_analyzer", - ":default_video_quality_analyzer", - ":network_quality_metrics_reporter", - "../../../api:callfactory_api", - "../../../api:create_network_emulation_manager", - "../../../api:create_peer_connection_quality_test_frame_generator", - "../../../api:create_peerconnection_quality_test_fixture", - "../../../api:libjingle_peerconnection_api", - "../../../api:media_stream_interface", + "../..:perf_test", "../../../api:network_emulation_manager_api", "../../../api:peer_connection_quality_test_fixture_api", - "../../../api:scoped_refptr", - "../../../api:simulated_network_api", - "../../../api/audio_codecs:builtin_audio_decoder_factory", - "../../../api/audio_codecs:builtin_audio_encoder_factory", - "../../../api/video_codecs:builtin_video_decoder_factory", - "../../../api/video_codecs:builtin_video_encoder_factory", - "../../../call:simulated_network", - "../../../media:rtc_audio_video", - "../../../modules/audio_device:audio_device_impl", - "../../../p2p:rtc_p2p", - "../../../pc:pc_test_utils", - "../../../pc:peerconnection_wrapper", - "../../../rtc_base", - "../../../rtc_base:gunit_helpers", - "../../../rtc_base:logging", + "../../../api:rtc_stats_api", + "../../../api/units:data_size", + "../../../rtc_base:criticalsection", "../../../rtc_base:rtc_event", "../../../system_wrappers:field_trial", - "../../../test:field_trial", - "../../../test:fileutils", - "../../../test:test_support", ] - data = peer_connection_e2e_smoke_test_resources - if (is_ios) { - deps += [ ":peer_connection_e2e_smoke_test_resources_bundle_data" ] - } } - rtc_library("stats_poller") { + rtc_library("sdp_changer") { visibility = [ "*" ] testonly = true sources = [ - "stats_poller.cc", - "stats_poller.h", + "sdp/sdp_changer.cc", + "sdp/sdp_changer.h", ] deps = [ - ":test_peer", + "../../../api:array_view", "../../../api:libjingle_peerconnection_api", - "../../../api:stats_observer_interface", - "../../../rtc_base:logging", + "../../../api:peer_connection_quality_test_fixture_api", + "../../../api:rtp_parameters", + "../../../media:rtc_media_base", + "../../../p2p:rtc_p2p", + "../../../pc:peerconnection", + "../../../pc:rtc_pc_base", + "../../../rtc_base:stringutils", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings:strings", + "//third_party/abseil-cpp/absl/types:optional", ] } - rtc_library("default_video_quality_analyzer_test") { + rtc_library("multi_head_queue") { + visibility = [ "*" ] testonly = true - sources = [ "analyzer/video/default_video_quality_analyzer_test.cc" ] - deps = [ - ":default_video_quality_analyzer", - "../..:test_support", - "../../../api:create_frame_generator", - "../../../api:rtp_packet_info", - "../../../api/video:encoded_image", - "../../../api/video:video_frame", - "../../../api/video:video_frame_i420", - "../../../modules/rtp_rtcp:rtp_rtcp_format", - "../../../system_wrappers", - ] + sources = [ "analyzer/video/multi_head_queue.h" ] + deps = [ "../../../rtc_base:checks" ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } } - -rtc_library("analyzer_helper") { - visibility = [ "*" ] - sources = [ - "analyzer_helper.cc", - "analyzer_helper.h", - ] - deps = [ - "../../../api:track_id_stream_label_map", - "../../../rtc_base:macromagic", - "../../../rtc_base/synchronization:sequence_checker", - ] -} - -rtc_library("default_audio_quality_analyzer") { - visibility = [ "*" ] - testonly = true - sources = [ - "analyzer/audio/default_audio_quality_analyzer.cc", - "analyzer/audio/default_audio_quality_analyzer.h", - ] - - deps = [ - "../..:perf_test", - "../../../api:audio_quality_analyzer_api", - "../../../api:libjingle_peerconnection_api", - "../../../api:stats_observer_interface", - "../../../api:track_id_stream_label_map", - "../../../rtc_base:criticalsection", - "../../../rtc_base:logging", - "../../../rtc_base:rtc_numerics", - ] -} - -rtc_library("example_video_quality_analyzer") { - visibility = [ "*" ] - testonly = true - sources = [ - "analyzer/video/example_video_quality_analyzer.cc", - "analyzer/video/example_video_quality_analyzer.h", - ] - - deps = [ - "../../../api:video_quality_analyzer_api", - "../../../api/video:encoded_image", - "../../../api/video:video_frame", - "../../../api/video:video_rtp_headers", - "../../../rtc_base:criticalsection", - "../../../rtc_base:logging", - ] -} - -rtc_library("video_quality_metrics_reporter") { - visibility = [ "*" ] - - testonly = true - sources = [ - "analyzer/video/video_quality_metrics_reporter.cc", - "analyzer/video/video_quality_metrics_reporter.h", - ] - deps = [ - "../..:perf_test", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../rtc_base:criticalsection", - "../../../rtc_base:rtc_numerics", - ] -} - -rtc_library("default_video_quality_analyzer") { - visibility = [ "*" ] - - testonly = true - sources = [ - "analyzer/video/default_video_quality_analyzer.cc", - "analyzer/video/default_video_quality_analyzer.h", - ] - - deps = [ - "../..:perf_test", - "../../../api:video_quality_analyzer_api", - "../../../api/units:time_delta", - "../../../api/units:timestamp", - "../../../api/video:encoded_image", - "../../../api/video:video_frame", - "../../../api/video:video_frame_i420", - "../../../api/video:video_rtp_headers", - "../../../common_video", - "../../../rtc_base:criticalsection", - "../../../rtc_base:logging", - "../../../rtc_base:rtc_base_approved", - "../../../rtc_base:rtc_base_tests_utils", - "../../../rtc_base:rtc_event", - "../../../rtc_base:rtc_numerics", - "../../../rtc_base:timeutils", - "../../../system_wrappers", - ] -} - -rtc_library("network_quality_metrics_reporter") { - visibility = [ "*" ] - testonly = true - sources = [ - "network_quality_metrics_reporter.cc", - "network_quality_metrics_reporter.h", - ] - deps = [ - "../..:perf_test", - "../../../api:libjingle_peerconnection_api", - "../../../api:network_emulation_manager_api", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../rtc_base:criticalsection", - "../../../rtc_base:rtc_event", - "../../../system_wrappers:field_trial", - ] -} - -rtc_library("sdp_changer") { - visibility = [ "*" ] - testonly = true - sources = [ - "sdp/sdp_changer.cc", - "sdp/sdp_changer.h", - ] - deps = [ - "../../../api:array_view", - "../../../api:libjingle_peerconnection_api", - "../../../api:peer_connection_quality_test_fixture_api", - "../../../api:rtp_parameters", - "../../../media:rtc_media_base", - "../../../p2p:rtc_p2p", - "../../../pc:peerconnection", - "../../../pc:rtc_pc_base", - "../../../rtc_base:stringutils", - "//third_party/abseil-cpp/absl/memory", - "//third_party/abseil-cpp/absl/strings:strings", - "//third_party/abseil-cpp/absl/types:optional", - ] -} diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.cc index b8f1740e46d..b8902335213 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.cc @@ -10,16 +10,12 @@ #include "test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h" -#include "api/stats_types.h" +#include "api/stats/rtc_stats.h" +#include "api/stats/rtcstats_objects.h" #include "rtc_base/logging.h" namespace webrtc { namespace webrtc_pc_e2e { -namespace { - -static const char kStatsAudioMediaType[] = "audio"; - -} // namespace void DefaultAudioQualityAnalyzer::Start( std::string test_case_name, @@ -29,68 +25,82 @@ void DefaultAudioQualityAnalyzer::Start( } void DefaultAudioQualityAnalyzer::OnStatsReports( - const std::string& pc_label, - const StatsReports& stats_reports) { - for (const StatsReport* stats_report : stats_reports) { - // NetEq stats are only present in kStatsReportTypeSsrc reports, so all - // other reports are just ignored. - if (stats_report->type() != StatsReport::StatsType::kStatsReportTypeSsrc) { - continue; - } - // Ignoring stats reports of "video" SSRC. - const webrtc::StatsReport::Value* media_type = stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNameMediaType); - RTC_CHECK(media_type); - if (strcmp(media_type->static_string_val(), kStatsAudioMediaType) != 0) { - continue; - } - if (stats_report->FindValue( - webrtc::StatsReport::kStatsValueNameBytesSent)) { - // If kStatsValueNameBytesSent is present, it means it's a send stream, - // but we need audio metrics for receive stream, so skip it. + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) { + // TODO(https://crbug.com/webrtc/11683): use "inbound-rtp" instead of "track" + // stats when required audio metrics moved there + auto stats = report->GetStatsOfType<RTCMediaStreamTrackStats>(); + + for (auto& stat : stats) { + if (!stat->kind.is_defined() || + !(*stat->kind == RTCMediaStreamTrackKind::kAudio) || + !*stat->remote_source) { continue; } - const webrtc::StatsReport::Value* expand_rate = stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNameExpandRate); - const webrtc::StatsReport::Value* accelerate_rate = stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNameAccelerateRate); - const webrtc::StatsReport::Value* preemptive_rate = stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNamePreemptiveExpandRate); - const webrtc::StatsReport::Value* speech_expand_rate = - stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNameSpeechExpandRate); - const webrtc::StatsReport::Value* preferred_buffer_size_ms = - stats_report->FindValue(StatsReport::StatsValueName:: - kStatsValueNamePreferredJitterBufferMs); - RTC_CHECK(expand_rate); - RTC_CHECK(accelerate_rate); - RTC_CHECK(preemptive_rate); - RTC_CHECK(speech_expand_rate); - RTC_CHECK(preferred_buffer_size_ms); + StatsSample sample; + sample.total_samples_received = + stat->total_samples_received.ValueOrDefault(0ul); + sample.concealed_samples = stat->concealed_samples.ValueOrDefault(0ul); + sample.removed_samples_for_acceleration = + stat->removed_samples_for_acceleration.ValueOrDefault(0ul); + sample.inserted_samples_for_deceleration = + stat->inserted_samples_for_deceleration.ValueOrDefault(0ul); + sample.silent_concealed_samples = + stat->silent_concealed_samples.ValueOrDefault(0ul); + sample.jitter_buffer_target_delay = + TimeDelta::Seconds(stat->jitter_buffer_target_delay.ValueOrDefault(0.)); + sample.jitter_buffer_emitted_count = + stat->jitter_buffer_emitted_count.ValueOrDefault(0ul); const std::string& stream_label = - GetStreamLabelFromStatsReport(stats_report); + analyzer_helper_->GetStreamLabelFromTrackId(*stat->track_identifier); rtc::CritScope crit(&lock_); + StatsSample prev_sample = last_stats_sample_[stream_label]; + RTC_CHECK_GE(sample.total_samples_received, + prev_sample.total_samples_received); + double total_samples_diff = static_cast<double>( + sample.total_samples_received - prev_sample.total_samples_received); + if (total_samples_diff == 0) { + return; + } + AudioStreamStats& audio_stream_stats = streams_stats_[stream_label]; - audio_stream_stats.expand_rate.AddSample(expand_rate->float_val()); - audio_stream_stats.accelerate_rate.AddSample(accelerate_rate->float_val()); - audio_stream_stats.preemptive_rate.AddSample(preemptive_rate->float_val()); + audio_stream_stats.expand_rate.AddSample( + (sample.concealed_samples - prev_sample.concealed_samples) / + total_samples_diff); + audio_stream_stats.accelerate_rate.AddSample( + (sample.removed_samples_for_acceleration - + prev_sample.removed_samples_for_acceleration) / + total_samples_diff); + audio_stream_stats.preemptive_rate.AddSample( + (sample.inserted_samples_for_deceleration - + prev_sample.inserted_samples_for_deceleration) / + total_samples_diff); + + int64_t speech_concealed_samples = + sample.concealed_samples - sample.silent_concealed_samples; + int64_t prev_speech_concealed_samples = + prev_sample.concealed_samples - prev_sample.silent_concealed_samples; audio_stream_stats.speech_expand_rate.AddSample( - speech_expand_rate->float_val()); - audio_stream_stats.preferred_buffer_size_ms.AddSample( - preferred_buffer_size_ms->int_val()); - } -} + (speech_concealed_samples - prev_speech_concealed_samples) / + total_samples_diff); + + int64_t jitter_buffer_emitted_count_diff = + sample.jitter_buffer_emitted_count - + prev_sample.jitter_buffer_emitted_count; + if (jitter_buffer_emitted_count_diff > 0) { + TimeDelta jitter_buffer_target_delay_diff = + sample.jitter_buffer_target_delay - + prev_sample.jitter_buffer_target_delay; + audio_stream_stats.preferred_buffer_size_ms.AddSample( + jitter_buffer_target_delay_diff.ms<double>() / + jitter_buffer_emitted_count_diff); + } -const std::string& DefaultAudioQualityAnalyzer::GetStreamLabelFromStatsReport( - const StatsReport* stats_report) const { - const webrtc::StatsReport::Value* report_track_id = stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNameTrackId); - RTC_CHECK(report_track_id); - return analyzer_helper_->GetStreamLabelFromTrackId( - report_track_id->string_val()); + last_stats_sample_[stream_label] = sample; + } } std::string DefaultAudioQualityAnalyzer::GetTestCaseName( diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h index 33aaefd4c3f..c990e4f357f 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h @@ -14,9 +14,9 @@ #include <map> #include <string> -#include "api/stats_types.h" #include "api/test/audio_quality_analyzer_interface.h" #include "api/test/track_id_stream_label_map.h" +#include "api/units/time_delta.h" #include "rtc_base/critical_section.h" #include "rtc_base/numerics/samples_stats_counter.h" #include "test/testsupport/perf_test.h" @@ -32,22 +32,29 @@ struct AudioStreamStats { SamplesStatsCounter preferred_buffer_size_ms; }; -// TODO(bugs.webrtc.org/10430): Migrate to the new GetStats as soon as -// bugs.webrtc.org/10428 is fixed. class DefaultAudioQualityAnalyzer : public AudioQualityAnalyzerInterface { public: void Start(std::string test_case_name, TrackIdStreamLabelMap* analyzer_helper) override; - void OnStatsReports(const std::string& pc_label, - const StatsReports& stats_reports) override; + void OnStatsReports( + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) override; void Stop() override; // Returns audio quality stats per stream label. std::map<std::string, AudioStreamStats> GetAudioStreamsStats() const; private: - const std::string& GetStreamLabelFromStatsReport( - const StatsReport* stats_report) const; + struct StatsSample { + uint64_t total_samples_received = 0; + uint64_t concealed_samples = 0; + uint64_t removed_samples_for_acceleration = 0; + uint64_t inserted_samples_for_deceleration = 0; + uint64_t silent_concealed_samples = 0; + TimeDelta jitter_buffer_target_delay = TimeDelta::Zero(); + uint64_t jitter_buffer_emitted_count = 0; + }; + std::string GetTestCaseName(const std::string& stream_label) const; void ReportResult(const std::string& metric_name, const std::string& stream_label, @@ -60,6 +67,7 @@ class DefaultAudioQualityAnalyzer : public AudioQualityAnalyzerInterface { rtc::CriticalSection lock_; std::map<std::string, AudioStreamStats> streams_stats_ RTC_GUARDED_BY(lock_); + std::map<std::string, StatsSample> last_stats_sample_ RTC_GUARDED_BY(lock_); }; } // namespace webrtc_pc_e2e diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc index 786509ddb7e..851238f1e74 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc @@ -14,11 +14,13 @@ #include <memory> #include <utility> +#include "api/array_view.h" #include "api/units/time_delta.h" #include "api/video/i420_buffer.h" #include "common_video/libyuv/include/webrtc_libyuv.h" #include "rtc_base/cpu_time.h" #include "rtc_base/logging.h" +#include "rtc_base/strings/string_builder.h" #include "rtc_base/time_utils.h" namespace webrtc { @@ -35,6 +37,7 @@ void LogFrameCounters(const std::string& name, const FrameCounters& counters) { RTC_LOG(INFO) << "[" << name << "] Pre encoded : " << counters.pre_encoded; RTC_LOG(INFO) << "[" << name << "] Encoded : " << counters.encoded; RTC_LOG(INFO) << "[" << name << "] Received : " << counters.received; + RTC_LOG(INFO) << "[" << name << "] Decoded : " << counters.decoded; RTC_LOG(INFO) << "[" << name << "] Rendered : " << counters.rendered; RTC_LOG(INFO) << "[" << name << "] Dropped : " << counters.dropped; } @@ -46,6 +49,15 @@ void LogStreamInternalStats(const std::string& name, const StreamStats& stats) { << stats.dropped_before_encoder; } +template <typename T> +absl::optional<T> MaybeGetValue(const std::map<size_t, T>& map, size_t key) { + auto it = map.find(key); + if (it == map.end()) { + return absl::nullopt; + } + return it->second; +} + } // namespace void RateCounter::AddEvent(Timestamp event_time) { @@ -65,9 +77,52 @@ double RateCounter::GetEventsPerSecond() const { (event_last_time_ - event_first_time_).us() * kMicrosPerSecond; } +std::string StatsKey::ToString() const { + rtc::StringBuilder out; + out << stream_label << "_" << sender << "_" << receiver; + return out.str(); +} + +bool operator<(const StatsKey& a, const StatsKey& b) { + if (a.stream_label != b.stream_label) { + return a.stream_label < b.stream_label; + } + if (a.sender != b.sender) { + return a.sender < b.sender; + } + return a.receiver < b.receiver; +} + +bool operator==(const StatsKey& a, const StatsKey& b) { + return a.stream_label == b.stream_label && a.sender == b.sender && + a.receiver == b.receiver; +} + +std::string InternalStatsKey::ToString() const { + rtc::StringBuilder out; + out << "stream=" << stream << "_sender=" << sender + << "_receiver=" << receiver; + return out.str(); +} + +bool operator<(const InternalStatsKey& a, const InternalStatsKey& b) { + if (a.stream != b.stream) { + return a.stream < b.stream; + } + if (a.sender != b.sender) { + return a.sender < b.sender; + } + return a.receiver < b.receiver; +} + +bool operator==(const InternalStatsKey& a, const InternalStatsKey& b) { + return a.stream == b.stream && a.sender == b.sender && + a.receiver == b.receiver; +} + DefaultVideoQualityAnalyzer::DefaultVideoQualityAnalyzer( bool heavy_metrics_computation_enabled, - int max_frames_in_flight_per_stream_count) + size_t max_frames_in_flight_per_stream_count) : heavy_metrics_computation_enabled_(heavy_metrics_computation_enabled), max_frames_in_flight_per_stream_count_( max_frames_in_flight_per_stream_count), @@ -76,9 +131,12 @@ DefaultVideoQualityAnalyzer::~DefaultVideoQualityAnalyzer() { Stop(); } -void DefaultVideoQualityAnalyzer::Start(std::string test_case_name, - int max_threads_count) { +void DefaultVideoQualityAnalyzer::Start( + std::string test_case_name, + rtc::ArrayView<const std::string> peer_names, + int max_threads_count) { test_label_ = std::move(test_case_name); + peers_ = std::make_unique<NamesCollection>(peer_names); for (int i = 0; i < max_threads_count; i++) { auto thread = std::make_unique<rtc::PlatformThread>( &DefaultVideoQualityAnalyzer::ProcessComparisonsThread, this, @@ -98,73 +156,115 @@ void DefaultVideoQualityAnalyzer::Start(std::string test_case_name, } uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured( + absl::string_view peer_name, const std::string& stream_label, const webrtc::VideoFrame& frame) { // |next_frame_id| is atomic, so we needn't lock here. uint16_t frame_id = next_frame_id_++; Timestamp start_time = Timestamp::MinusInfinity(); + size_t peer_index = peers_->index(peer_name); + size_t stream_index; { rtc::CritScope crit(&lock_); - // Create a local copy of start_time_ to access it under |comparison_lock_| - // without holding a |lock_| + // Create a local copy of start_time_ to access it under + // |comparison_lock_| without holding a |lock_| start_time = start_time_; + stream_index = streams_.AddIfAbsent(stream_label); } { // Ensure stats for this stream exists. rtc::CritScope crit(&comparison_lock_); - if (stream_stats_.find(stream_label) == stream_stats_.end()) { - stream_stats_.insert({stream_label, StreamStats()}); - // Assume that the first freeze was before first stream frame captured. - // This way time before the first freeze would be counted as time between - // freezes. - stream_last_freeze_end_time_.insert({stream_label, start_time}); + for (size_t i = 0; i < peers_->size(); ++i) { + if (i == peer_index) { + continue; + } + InternalStatsKey stats_key(stream_index, peer_index, i); + if (stream_stats_.find(stats_key) == stream_stats_.end()) { + stream_stats_.insert({stats_key, StreamStats()}); + // Assume that the first freeze was before first stream frame captured. + // This way time before the first freeze would be counted as time + // between freezes. + stream_last_freeze_end_time_.insert({stats_key, start_time}); + } else { + // When we see some |stream_label| for the first time we need to create + // stream stats object for it and set up some states, but we need to do + // it only once and for all receivers, so on the next frame on the same + // |stream_label| we can be sure, that it's already done and we needn't + // to scan though all peers again. + break; + } } } { rtc::CritScope crit(&lock_); + stream_to_sender_[stream_index] = peer_index; frame_counters_.captured++; - stream_frame_counters_[stream_label].captured++; + for (size_t i = 0; i < peers_->size(); ++i) { + if (i != peer_index) { + InternalStatsKey key(stream_index, peer_index, i); + stream_frame_counters_[key].captured++; + } + } - StreamState* state = &stream_states_[stream_label]; + auto state_it = stream_states_.find(stream_index); + if (state_it == stream_states_.end()) { + stream_states_.emplace(stream_index, + StreamState(peer_index, peers_->size())); + } + StreamState* state = &stream_states_.at(stream_index); state->PushBack(frame_id); // Update frames in flight info. auto it = captured_frames_in_flight_.find(frame_id); if (it != captured_frames_in_flight_.end()) { - // We overflow uint16_t and hit previous frame id and this frame is still - // in flight. It means that this stream wasn't rendered for long time and - // we need to process existing frame as dropped. - auto stats_it = frame_stats_.find(frame_id); - RTC_DCHECK(stats_it != frame_stats_.end()); - - uint16_t oldest_frame_id = state->PopFront(); - RTC_DCHECK_EQ(frame_id, oldest_frame_id); - frame_counters_.dropped++; - stream_frame_counters_[stream_label].dropped++; - AddComparison(it->second, absl::nullopt, true, stats_it->second); + // If we overflow uint16_t and hit previous frame id and this frame is + // still in flight, it means that this stream wasn't rendered for long + // time and we need to process existing frame as dropped. + for (size_t i = 0; i < peers_->size(); ++i) { + if (i == peer_index) { + continue; + } + + uint16_t oldest_frame_id = state->PopFront(i); + RTC_DCHECK_EQ(frame_id, oldest_frame_id); + frame_counters_.dropped++; + InternalStatsKey key(stream_index, peer_index, i); + stream_frame_counters_.at(key).dropped++; + + rtc::CritScope crit1(&comparison_lock_); + analyzer_stats_.frames_in_flight_left_count.AddSample( + captured_frames_in_flight_.size()); + AddComparison(InternalStatsKey(stream_index, peer_index, i), + it->second.frame(), absl::nullopt, true, + it->second.GetStatsForPeer(i)); + } captured_frames_in_flight_.erase(it); - frame_stats_.erase(stats_it); } - captured_frames_in_flight_.insert( - std::pair<uint16_t, VideoFrame>(frame_id, frame)); + captured_frames_in_flight_.emplace( + frame_id, + FrameInFlight(stream_index, frame, + /*captured_time=*/Now(), peer_index, peers_->size())); // Set frame id on local copy of the frame - captured_frames_in_flight_.at(frame_id).set_id(frame_id); - frame_stats_.insert(std::pair<uint16_t, FrameStats>( - frame_id, FrameStats(stream_label, /*captured_time=*/Now()))); + captured_frames_in_flight_.at(frame_id).SetFrameId(frame_id); // Update history stream<->frame mapping for (auto it = stream_to_frame_id_history_.begin(); it != stream_to_frame_id_history_.end(); ++it) { it->second.erase(frame_id); } - stream_to_frame_id_history_[stream_label].insert(frame_id); + stream_to_frame_id_history_[stream_index].insert(frame_id); // If state has too many frames that are in flight => remove the oldest // queued frame in order to avoid to use too much memory. if (state->GetAliveFramesCount() > max_frames_in_flight_per_stream_count_) { uint16_t frame_id_to_remove = state->MarkNextAliveFrameAsDead(); - auto removed_count = captured_frames_in_flight_.erase(frame_id_to_remove); - RTC_DCHECK_EQ(removed_count, 1) + auto it = captured_frames_in_flight_.find(frame_id_to_remove); + RTC_CHECK(it != captured_frames_in_flight_.end()) + << "Frame with ID " << frame_id_to_remove + << " is expected to be in flight, but hasn't been found in " + << "|captured_frames_in_flight_|"; + bool is_removed = it->second.RemoveFrame(); + RTC_DCHECK(is_removed) << "Invalid stream state: alive frame is removed already"; } } @@ -172,52 +272,76 @@ uint16_t DefaultVideoQualityAnalyzer::OnFrameCaptured( } void DefaultVideoQualityAnalyzer::OnFramePreEncode( + absl::string_view peer_name, const webrtc::VideoFrame& frame) { rtc::CritScope crit(&lock_); - auto it = frame_stats_.find(frame.id()); - RTC_DCHECK(it != frame_stats_.end()) + auto it = captured_frames_in_flight_.find(frame.id()); + RTC_DCHECK(it != captured_frames_in_flight_.end()) << "Frame id=" << frame.id() << " not found"; frame_counters_.pre_encoded++; - stream_frame_counters_[it->second.stream_label].pre_encoded++; - it->second.pre_encode_time = Now(); + size_t peer_index = peers_->index(peer_name); + for (size_t i = 0; i < peers_->size(); ++i) { + if (i != peer_index) { + InternalStatsKey key(it->second.stream(), peer_index, i); + stream_frame_counters_.at(key).pre_encoded++; + } + } + it->second.SetPreEncodeTime(Now()); } void DefaultVideoQualityAnalyzer::OnFrameEncoded( + absl::string_view peer_name, uint16_t frame_id, const webrtc::EncodedImage& encoded_image, const EncoderStats& stats) { rtc::CritScope crit(&lock_); - auto it = frame_stats_.find(frame_id); - RTC_DCHECK(it != frame_stats_.end()); + auto it = captured_frames_in_flight_.find(frame_id); + RTC_DCHECK(it != captured_frames_in_flight_.end()); // For SVC we can receive multiple encoded images for one frame, so to cover // all cases we have to pick the last encode time. - if (it->second.encoded_time.IsInfinite()) { + if (!it->second.HasEncodedTime()) { // Increase counters only when we meet this frame first time. frame_counters_.encoded++; - stream_frame_counters_[it->second.stream_label].encoded++; + size_t peer_index = peers_->index(peer_name); + for (size_t i = 0; i < peers_->size(); ++i) { + if (i != peer_index) { + InternalStatsKey key(it->second.stream(), peer_index, i); + stream_frame_counters_.at(key).encoded++; + } + } } - it->second.encoded_time = Now(); - it->second.encoded_image_size = encoded_image.size(); - it->second.target_encode_bitrate += stats.target_encode_bitrate; + it->second.OnFrameEncoded(Now(), encoded_image.size(), + stats.target_encode_bitrate); } void DefaultVideoQualityAnalyzer::OnFrameDropped( + absl::string_view peer_name, webrtc::EncodedImageCallback::DropReason reason) { // Here we do nothing, because we will see this drop on renderer side. } void DefaultVideoQualityAnalyzer::OnFramePreDecode( + absl::string_view peer_name, uint16_t frame_id, const webrtc::EncodedImage& input_image) { rtc::CritScope crit(&lock_); - auto it = frame_stats_.find(frame_id); - RTC_DCHECK(it != frame_stats_.end()); - RTC_DCHECK(it->second.received_time.IsInfinite()) - << "Received multiple spatial layers for stream_label=" - << it->second.stream_label; + size_t peer_index = peers_->index(peer_name); + + auto it = captured_frames_in_flight_.find(frame_id); + if (it == captured_frames_in_flight_.end() || + it->second.HasReceivedTime(peer_index)) { + // It means this frame was predecoded before, so we can skip it. It may + // happen when we have multiple simulcast streams in one track and received + // the same picture from two different streams because SFU can't reliably + // correlate two simulcast streams and started relaying the second stream + // from the same frame it has relayed right before for the first stream. + return; + } + frame_counters_.received++; - stream_frame_counters_[it->second.stream_label].received++; - it->second.decode_start_time = Now(); + InternalStatsKey key(it->second.stream(), + stream_to_sender_.at(it->second.stream()), peer_index); + stream_frame_counters_.at(key).received++; // Determine the time of the last received packet of this video frame. RTC_DCHECK(!input_image.PacketInfos().empty()); int64_t last_receive_time = @@ -227,112 +351,145 @@ void DefaultVideoQualityAnalyzer::OnFramePreDecode( return a.receive_time_ms() < b.receive_time_ms(); }) ->receive_time_ms(); - it->second.received_time = Timestamp::Millis(last_receive_time); + it->second.OnFramePreDecode( + peer_index, + /*received_time=*/Timestamp::Millis(last_receive_time), + /*decode_start_time=*/Now()); } void DefaultVideoQualityAnalyzer::OnFrameDecoded( + absl::string_view peer_name, const webrtc::VideoFrame& frame, const DecoderStats& stats) { rtc::CritScope crit(&lock_); - auto it = frame_stats_.find(frame.id()); - RTC_DCHECK(it != frame_stats_.end()); + size_t peer_index = peers_->index(peer_name); + + auto it = captured_frames_in_flight_.find(frame.id()); + if (it == captured_frames_in_flight_.end() || + it->second.HasDecodeEndTime(peer_index)) { + // It means this frame was decoded before, so we can skip it. It may happen + // when we have multiple simulcast streams in one track and received + // the same picture from two different streams because SFU can't reliably + // correlate two simulcast streams and started relaying the second stream + // from the same frame it has relayed right before for the first stream. + return; + } frame_counters_.decoded++; - stream_frame_counters_[it->second.stream_label].decoded++; - it->second.decode_end_time = Now(); + InternalStatsKey key(it->second.stream(), + stream_to_sender_.at(it->second.stream()), peer_index); + stream_frame_counters_.at(key).decoded++; + it->second.SetDecodeEndTime(peer_index, Now()); } void DefaultVideoQualityAnalyzer::OnFrameRendered( + absl::string_view peer_name, const webrtc::VideoFrame& raw_frame) { + rtc::CritScope crit(&lock_); + size_t peer_index = peers_->index(peer_name); + + auto frame_it = captured_frames_in_flight_.find(raw_frame.id()); + if (frame_it == captured_frames_in_flight_.end() || + frame_it->second.HasRenderedTime(peer_index)) { + // It means this frame was rendered before, so we can skip it. It may happen + // when we have multiple simulcast streams in one track and received + // the same picture from two different streams because SFU can't reliably + // correlate two simulcast streams and started relaying the second stream + // from the same frame it has relayed right before for the first stream. + return; + } + // Copy entire video frame including video buffer to ensure that analyzer // won't hold any WebRTC internal buffers. VideoFrame frame = raw_frame; frame.set_video_frame_buffer( I420Buffer::Copy(*raw_frame.video_frame_buffer()->ToI420())); - rtc::CritScope crit(&lock_); - auto stats_it = frame_stats_.find(frame.id()); - RTC_DCHECK(stats_it != frame_stats_.end()); - FrameStats* frame_stats = &stats_it->second; + // Find corresponding captured frame. + FrameInFlight* frame_in_flight = &frame_it->second; + absl::optional<VideoFrame> captured_frame = frame_in_flight->frame(); + + const size_t stream_index = frame_in_flight->stream(); + StreamState* state = &stream_states_.at(stream_index); + const InternalStatsKey stats_key(stream_index, state->owner(), peer_index); + // Update frames counters. frame_counters_.rendered++; - stream_frame_counters_[frame_stats->stream_label].rendered++; + stream_frame_counters_.at(stats_key).rendered++; // Update current frame stats. - frame_stats->rendered_time = Now(); - frame_stats->rendered_frame_width = frame.width(); - frame_stats->rendered_frame_height = frame.height(); - - // Find corresponding captured frame. - auto frame_it = captured_frames_in_flight_.find(frame.id()); - absl::optional<VideoFrame> captured_frame = - frame_it != captured_frames_in_flight_.end() - ? absl::optional<VideoFrame>(frame_it->second) - : absl::nullopt; + frame_in_flight->OnFrameRendered(peer_index, Now(), frame.width(), + frame.height()); // After we received frame here we need to check if there are any dropped // frames between this one and last one, that was rendered for this video // stream. - - const std::string& stream_label = frame_stats->stream_label; - StreamState* state = &stream_states_[stream_label]; int dropped_count = 0; - while (!state->Empty() && state->Front() != frame.id()) { + while (!state->IsEmpty(peer_index) && + state->Front(peer_index) != frame.id()) { dropped_count++; - uint16_t dropped_frame_id = state->PopFront(); + uint16_t dropped_frame_id = state->PopFront(peer_index); // Frame with id |dropped_frame_id| was dropped. We need: // 1. Update global and stream frame counters // 2. Extract corresponding frame from |captured_frames_in_flight_| - // 3. Extract corresponding frame stats from |frame_stats_| - // 4. Send extracted frame to comparison with dropped=true - // 5. Cleanup dropped frame + // 3. Send extracted frame to comparison with dropped=true + // 4. Cleanup dropped frame frame_counters_.dropped++; - stream_frame_counters_[stream_label].dropped++; + stream_frame_counters_.at(stats_key).dropped++; - auto dropped_frame_stats_it = frame_stats_.find(dropped_frame_id); - RTC_DCHECK(dropped_frame_stats_it != frame_stats_.end()); auto dropped_frame_it = captured_frames_in_flight_.find(dropped_frame_id); - absl::optional<VideoFrame> dropped_frame = - dropped_frame_it != captured_frames_in_flight_.end() - ? absl::optional<VideoFrame>(dropped_frame_it->second) - : absl::nullopt; + RTC_DCHECK(dropped_frame_it != captured_frames_in_flight_.end()); + absl::optional<VideoFrame> dropped_frame = dropped_frame_it->second.frame(); + dropped_frame_it->second.MarkDropped(peer_index); - AddComparison(dropped_frame, absl::nullopt, true, - dropped_frame_stats_it->second); + { + rtc::CritScope crit1(&comparison_lock_); + analyzer_stats_.frames_in_flight_left_count.AddSample( + captured_frames_in_flight_.size()); + AddComparison(stats_key, dropped_frame, absl::nullopt, true, + dropped_frame_it->second.GetStatsForPeer(peer_index)); + } - frame_stats_.erase(dropped_frame_stats_it); - if (dropped_frame_it != captured_frames_in_flight_.end()) { + if (dropped_frame_it->second.HaveAllPeersReceived()) { captured_frames_in_flight_.erase(dropped_frame_it); } } - RTC_DCHECK(!state->Empty()); - state->PopFront(); + RTC_DCHECK(!state->IsEmpty(peer_index)); + state->PopFront(peer_index); - if (state->last_rendered_frame_time()) { - frame_stats->prev_frame_rendered_time = - state->last_rendered_frame_time().value(); + if (state->last_rendered_frame_time(peer_index)) { + frame_in_flight->SetPrevFrameRenderedTime( + peer_index, state->last_rendered_frame_time(peer_index).value()); } - state->set_last_rendered_frame_time(frame_stats->rendered_time); + state->SetLastRenderedFrameTime(peer_index, + frame_in_flight->rendered_time(peer_index)); { rtc::CritScope cr(&comparison_lock_); - stream_stats_[stream_label].skipped_between_rendered.AddSample( - dropped_count); + stream_stats_[stats_key].skipped_between_rendered.AddSample(dropped_count); } - AddComparison(captured_frame, frame, false, *frame_stats); - if (frame_it != captured_frames_in_flight_.end()) { + { + rtc::CritScope crit(&comparison_lock_); + analyzer_stats_.frames_in_flight_left_count.AddSample( + captured_frames_in_flight_.size()); + AddComparison(stats_key, captured_frame, frame, false, + frame_in_flight->GetStatsForPeer(peer_index)); + } + + if (frame_it->second.HaveAllPeersReceived()) { captured_frames_in_flight_.erase(frame_it); } - frame_stats_.erase(stats_it); } void DefaultVideoQualityAnalyzer::OnEncoderError( + absl::string_view peer_name, const webrtc::VideoFrame& frame, int32_t error_code) { RTC_LOG(LS_ERROR) << "Encoder error for frame.id=" << frame.id() << ", code=" << error_code; } -void DefaultVideoQualityAnalyzer::OnDecoderError(uint16_t frame_id, +void DefaultVideoQualityAnalyzer::OnDecoderError(absl::string_view peer_name, + uint16_t frame_id, int32_t error_code) { RTC_LOG(LS_ERROR) << "Decoder error for frame_id=" << frame_id << ", code=" << error_code; @@ -362,46 +519,58 @@ void DefaultVideoQualityAnalyzer::Stop() { // between freezes. rtc::CritScope crit1(&lock_); rtc::CritScope crit2(&comparison_lock_); - for (auto& item : stream_stats_) { - const StreamState& state = stream_states_[item.first]; - // If there are no freezes in the call we have to report - // time_between_freezes_ms as call duration and in such case - // |stream_last_freeze_end_time_| for this stream will be |start_time_|. - // If there is freeze, then we need add time from last rendered frame - // to last freeze end as time between freezes. - if (state.last_rendered_frame_time()) { - item.second.time_between_freezes_ms.AddSample( - (state.last_rendered_frame_time().value() - - stream_last_freeze_end_time_.at(item.first)) - .ms()); + for (auto& state_entry : stream_states_) { + const size_t stream_index = state_entry.first; + const StreamState& stream_state = state_entry.second; + for (size_t i = 0; i < peers_->size(); ++i) { + if (i == static_cast<size_t>(stream_state.owner())) { + continue; + } + + InternalStatsKey stats_key(stream_index, stream_state.owner(), i); + + // If there are no freezes in the call we have to report + // time_between_freezes_ms as call duration and in such case + // |stream_last_freeze_end_time_| for this stream will be |start_time_|. + // If there is freeze, then we need add time from last rendered frame + // to last freeze end as time between freezes. + if (stream_state.last_rendered_frame_time(i)) { + stream_stats_[stats_key].time_between_freezes_ms.AddSample( + stream_state.last_rendered_frame_time(i).value().ms() - + stream_last_freeze_end_time_.at(stats_key).ms()); + } } } + analyzer_stats_.frames_in_flight_left_count.AddSample( + captured_frames_in_flight_.size()); } ReportResults(); } std::string DefaultVideoQualityAnalyzer::GetStreamLabel(uint16_t frame_id) { rtc::CritScope crit1(&lock_); - auto it = frame_stats_.find(frame_id); - if (it != frame_stats_.end()) { - return it->second.stream_label; + auto it = captured_frames_in_flight_.find(frame_id); + if (it != captured_frames_in_flight_.end()) { + return streams_.name(it->second.stream()); } for (auto hist_it = stream_to_frame_id_history_.begin(); hist_it != stream_to_frame_id_history_.end(); ++hist_it) { auto hist_set_it = hist_it->second.find(frame_id); if (hist_set_it != hist_it->second.end()) { - return hist_it->first; + return streams_.name(hist_it->first); } } RTC_CHECK(false) << "Unknown frame_id=" << frame_id; } -std::set<std::string> DefaultVideoQualityAnalyzer::GetKnownVideoStreams() - const { +std::set<StatsKey> DefaultVideoQualityAnalyzer::GetKnownVideoStreams() const { + rtc::CritScope crit1(&lock_); rtc::CritScope crit2(&comparison_lock_); - std::set<std::string> out; + std::set<StatsKey> out; for (auto& item : stream_stats_) { - out.insert(item.first); + RTC_LOG(INFO) << item.first.ToString() << " ==> " + << ToStatsKey(item.first).ToString(); + out.insert(ToStatsKey(item.first)); } return out; } @@ -411,16 +580,24 @@ const FrameCounters& DefaultVideoQualityAnalyzer::GetGlobalCounters() const { return frame_counters_; } -const std::map<std::string, FrameCounters>& +std::map<StatsKey, FrameCounters> DefaultVideoQualityAnalyzer::GetPerStreamCounters() const { rtc::CritScope crit(&lock_); - return stream_frame_counters_; + std::map<StatsKey, FrameCounters> out; + for (auto& item : stream_frame_counters_) { + out.emplace(ToStatsKey(item.first), item.second); + } + return out; } -std::map<std::string, StreamStats> DefaultVideoQualityAnalyzer::GetStats() - const { - rtc::CritScope cri(&comparison_lock_); - return stream_stats_; +std::map<StatsKey, StreamStats> DefaultVideoQualityAnalyzer::GetStats() const { + rtc::CritScope crit1(&lock_); + rtc::CritScope crit2(&comparison_lock_); + std::map<StatsKey, StreamStats> out; + for (auto& item : stream_stats_) { + out.emplace(ToStatsKey(item.first), item.second); + } + return out; } AnalyzerStats DefaultVideoQualityAnalyzer::GetAnalyzerStats() const { @@ -429,25 +606,27 @@ AnalyzerStats DefaultVideoQualityAnalyzer::GetAnalyzerStats() const { } void DefaultVideoQualityAnalyzer::AddComparison( + InternalStatsKey stats_key, absl::optional<VideoFrame> captured, absl::optional<VideoFrame> rendered, bool dropped, FrameStats frame_stats) { StartExcludingCpuThreadTime(); - rtc::CritScope crit(&comparison_lock_); analyzer_stats_.comparisons_queue_size.AddSample(comparisons_.size()); // If there too many computations waiting in the queue, we won't provide // frames itself to make future computations lighter. if (comparisons_.size() >= kMaxActiveComparisons) { - comparisons_.emplace_back(absl::nullopt, absl::nullopt, dropped, - frame_stats, OverloadReason::kCpu); + comparisons_.emplace_back(std::move(stats_key), absl::nullopt, + absl::nullopt, dropped, std::move(frame_stats), + OverloadReason::kCpu); } else { OverloadReason overload_reason = OverloadReason::kNone; if (!captured && !dropped) { overload_reason = OverloadReason::kMemory; } - comparisons_.emplace_back(std::move(captured), std::move(rendered), dropped, - frame_stats, overload_reason); + comparisons_.emplace_back(std::move(stats_key), std::move(captured), + std::move(rendered), dropped, + std::move(frame_stats), overload_reason); } comparison_available_event_.Set(); StopExcludingCpuThreadTime(); @@ -507,8 +686,8 @@ void DefaultVideoQualityAnalyzer::ProcessComparison( const FrameStats& frame_stats = comparison.frame_stats; rtc::CritScope crit(&comparison_lock_); - auto stats_it = stream_stats_.find(frame_stats.stream_label); - RTC_CHECK(stats_it != stream_stats_.end()); + auto stats_it = stream_stats_.find(comparison.stats_key); + RTC_CHECK(stats_it != stream_stats_.end()) << comparison.stats_key.ToString(); StreamStats* stats = &stats_it->second; analyzer_stats_.comparisons_done++; if (comparison.overload_reason == OverloadReason::kCpu) { @@ -561,7 +740,7 @@ void DefaultVideoQualityAnalyzer::ProcessComparison( 3 * average_time_between_rendered_frames_ms)) { stats->freeze_time_ms.AddSample(time_between_rendered_frames.ms()); auto freeze_end_it = - stream_last_freeze_end_time_.find(frame_stats.stream_label); + stream_last_freeze_end_time_.find(comparison.stats_key); RTC_DCHECK(freeze_end_it != stream_last_freeze_end_time_.end()); stats->time_between_freezes_ms.AddSample( (frame_stats.prev_frame_rendered_time - freeze_end_it->second) @@ -578,15 +757,16 @@ void DefaultVideoQualityAnalyzer::ReportResults() { rtc::CritScope crit1(&lock_); rtc::CritScope crit2(&comparison_lock_); for (auto& item : stream_stats_) { - ReportResults(GetTestCaseName(item.first), item.second, - stream_frame_counters_.at(item.first)); + ReportResults(GetTestCaseName(StatsKeyToMetricName(ToStatsKey(item.first))), + item.second, stream_frame_counters_.at(item.first)); } test::PrintResult("cpu_usage", "", test_label_.c_str(), GetCpuUsagePercent(), "%", false, ImproveDirection::kSmallerIsBetter); LogFrameCounters("Global", frame_counters_); for (auto& item : stream_stats_) { - LogFrameCounters(item.first, stream_frame_counters_.at(item.first)); - LogStreamInternalStats(item.first, item.second); + LogFrameCounters(ToStatsKey(item.first).ToString(), + stream_frame_counters_.at(item.first)); + LogStreamInternalStats(ToStatsKey(item.first).ToString(), item.second); } if (!analyzer_stats_.comparisons_queue_size.IsEmpty()) { RTC_LOG(INFO) << "comparisons_queue_size min=" @@ -714,6 +894,20 @@ Timestamp DefaultVideoQualityAnalyzer::Now() { return clock_->CurrentTime(); } +StatsKey DefaultVideoQualityAnalyzer::ToStatsKey( + const InternalStatsKey& key) const { + return StatsKey(streams_.name(key.stream), peers_->name(key.sender), + peers_->name(key.receiver)); +} + +std::string DefaultVideoQualityAnalyzer::StatsKeyToMetricName( + const StatsKey& key) { + if (peers_->size() <= 2) { + return key.stream_label; + } + return key.ToString(); +} + void DefaultVideoQualityAnalyzer::StartMeasuringCpuProcessTime() { rtc::CritScope lock(&cpu_measurement_lock_); cpu_time_ -= rtc::GetProcessCpuTimeNanos(); @@ -741,35 +935,208 @@ double DefaultVideoQualityAnalyzer::GetCpuUsagePercent() { return static_cast<double>(cpu_time_) / wallclock_time_ * 100.0; } -DefaultVideoQualityAnalyzer::FrameStats::FrameStats(std::string stream_label, - Timestamp captured_time) - : stream_label(std::move(stream_label)), captured_time(captured_time) {} - DefaultVideoQualityAnalyzer::FrameComparison::FrameComparison( + InternalStatsKey stats_key, absl::optional<VideoFrame> captured, absl::optional<VideoFrame> rendered, bool dropped, FrameStats frame_stats, OverloadReason overload_reason) - : captured(std::move(captured)), + : stats_key(std::move(stats_key)), + captured(std::move(captured)), rendered(std::move(rendered)), dropped(dropped), frame_stats(std::move(frame_stats)), overload_reason(overload_reason) {} -uint16_t DefaultVideoQualityAnalyzer::StreamState::PopFront() { - uint16_t frame_id = frame_ids_.front(); - frame_ids_.pop_front(); - if (dead_frames_count_ > 0) { - dead_frames_count_--; +uint16_t DefaultVideoQualityAnalyzer::StreamState::PopFront(size_t peer) { + absl::optional<uint16_t> frame_id = frame_ids_.PopFront(peer); + RTC_DCHECK(frame_id.has_value()); + + // If alive's frame queue is longer than all others, than also pop frame from + // it, because that frame is received by all receivers. + size_t owner_size = frame_ids_.size(owner_); + size_t other_size = 0; + for (size_t i = 0; i < frame_ids_.readers_count(); ++i) { + size_t cur_size = frame_ids_.size(i); + if (i != owner_ && cur_size > other_size) { + other_size = cur_size; + } } - return frame_id; + if (owner_size > other_size) { + absl::optional<uint16_t> alive_frame_id = frame_ids_.PopFront(owner_); + RTC_DCHECK(alive_frame_id.has_value()); + RTC_DCHECK_EQ(frame_id.value(), alive_frame_id.value()); + } + + return frame_id.value(); } uint16_t DefaultVideoQualityAnalyzer::StreamState::MarkNextAliveFrameAsDead() { - uint16_t frame_id = frame_ids_[dead_frames_count_]; - dead_frames_count_++; - return frame_id; + absl::optional<uint16_t> frame_id = frame_ids_.PopFront(owner_); + RTC_DCHECK(frame_id.has_value()); + return frame_id.value(); +} + +void DefaultVideoQualityAnalyzer::StreamState::SetLastRenderedFrameTime( + size_t peer, + Timestamp time) { + auto it = last_rendered_frame_time_.find(peer); + if (it == last_rendered_frame_time_.end()) { + last_rendered_frame_time_.insert({peer, time}); + } else { + it->second = time; + } +} + +absl::optional<Timestamp> +DefaultVideoQualityAnalyzer::StreamState::last_rendered_frame_time( + size_t peer) const { + return MaybeGetValue(last_rendered_frame_time_, peer); +} + +bool DefaultVideoQualityAnalyzer::FrameInFlight::RemoveFrame() { + if (!frame_) { + return false; + } + frame_ = absl::nullopt; + return true; +} + +void DefaultVideoQualityAnalyzer::FrameInFlight::SetFrameId(uint16_t id) { + if (frame_) { + frame_->set_id(id); + } +} + +std::vector<size_t> +DefaultVideoQualityAnalyzer::FrameInFlight::GetPeersWhichDidntReceive() const { + std::vector<size_t> out; + for (size_t i = 0; i < peers_count_; ++i) { + auto it = receiver_stats_.find(i); + if (i != owner_ && it != receiver_stats_.end() && + it->second.rendered_time.IsInfinite()) { + out.push_back(i); + } + } + return out; +} + +bool DefaultVideoQualityAnalyzer::FrameInFlight::HaveAllPeersReceived() const { + for (size_t i = 0; i < peers_count_; ++i) { + if (i == owner_) { + continue; + } + + auto it = receiver_stats_.find(i); + if (it == receiver_stats_.end()) { + return false; + } + + if (!it->second.dropped && it->second.rendered_time.IsInfinite()) { + return false; + } + } + return true; +} + +void DefaultVideoQualityAnalyzer::FrameInFlight::OnFrameEncoded( + webrtc::Timestamp time, + int64_t encoded_image_size, + uint32_t target_encode_bitrate) { + encoded_time_ = time; + encoded_image_size_ = encoded_image_size; + target_encode_bitrate_ += target_encode_bitrate; +} + +void DefaultVideoQualityAnalyzer::FrameInFlight::OnFramePreDecode( + size_t peer, + webrtc::Timestamp received_time, + webrtc::Timestamp decode_start_time) { + receiver_stats_[peer].received_time = received_time; + receiver_stats_[peer].decode_start_time = decode_start_time; +} + +bool DefaultVideoQualityAnalyzer::FrameInFlight::HasReceivedTime( + size_t peer) const { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end()) { + return false; + } + return it->second.received_time.IsFinite(); +} + +bool DefaultVideoQualityAnalyzer::FrameInFlight::HasDecodeEndTime( + size_t peer) const { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end()) { + return false; + } + return it->second.decode_end_time.IsFinite(); +} + +void DefaultVideoQualityAnalyzer::FrameInFlight::OnFrameRendered( + size_t peer, + webrtc::Timestamp time, + int width, + int height) { + receiver_stats_[peer].rendered_time = time; + receiver_stats_[peer].rendered_frame_width = width; + receiver_stats_[peer].rendered_frame_height = height; +} + +bool DefaultVideoQualityAnalyzer::FrameInFlight::HasRenderedTime( + size_t peer) const { + auto it = receiver_stats_.find(peer); + if (it == receiver_stats_.end()) { + return false; + } + return it->second.rendered_time.IsFinite(); +} + +DefaultVideoQualityAnalyzer::FrameStats +DefaultVideoQualityAnalyzer::FrameInFlight::GetStatsForPeer(size_t peer) const { + FrameStats stats(captured_time_); + stats.pre_encode_time = pre_encode_time_; + stats.encoded_time = encoded_time_; + stats.target_encode_bitrate = target_encode_bitrate_; + stats.encoded_image_size = encoded_image_size_; + + absl::optional<ReceiverFrameStats> receiver_stats = + MaybeGetValue<ReceiverFrameStats>(receiver_stats_, peer); + if (receiver_stats.has_value()) { + stats.received_time = receiver_stats->received_time; + stats.decode_start_time = receiver_stats->decode_start_time; + stats.decode_end_time = receiver_stats->decode_end_time; + stats.rendered_time = receiver_stats->rendered_time; + stats.prev_frame_rendered_time = receiver_stats->prev_frame_rendered_time; + stats.rendered_frame_width = receiver_stats->rendered_frame_width; + stats.rendered_frame_height = receiver_stats->rendered_frame_height; + } + return stats; +} + +size_t DefaultVideoQualityAnalyzer::NamesCollection::AddIfAbsent( + absl::string_view name) { + auto it = index_.find(name); + if (it != index_.end()) { + return it->second; + } + size_t out = names_.size(); + size_t old_capacity = names_.capacity(); + names_.emplace_back(name); + size_t new_capacity = names_.capacity(); + + if (old_capacity == new_capacity) { + index_.emplace(names_[out], out); + } else { + // Reallocation happened in the vector, so we need to rebuild |index_| + index_.clear(); + for (size_t i = 0; i < names_.size(); ++i) { + index_.emplace(names_[i], i); + } + } + return out; } } // namespace webrtc_pc_e2e diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h index 6bebb0f02b2..95049b10548 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h @@ -19,6 +19,7 @@ #include <string> #include <vector> +#include "api/array_view.h" #include "api/test/video_quality_analyzer_interface.h" #include "api/units/timestamp.h" #include "api/video/encoded_image.h" @@ -28,6 +29,7 @@ #include "rtc_base/numerics/samples_stats_counter.h" #include "rtc_base/platform_thread.h" #include "system_wrappers/include/clock.h" +#include "test/pc/e2e/analyzer/video/multi_head_queue.h" #include "test/testsupport/perf_test.h" namespace webrtc { @@ -36,7 +38,7 @@ namespace webrtc_pc_e2e { // WebRTC will request a key frame after 3 seconds if no frames were received. // We assume max frame rate ~60 fps, so 270 frames will cover max freeze without // key frame request. -constexpr int kDefaultMaxFramesInFlightPerStream = 270; +constexpr size_t kDefaultMaxFramesInFlightPerStream = 270; class RateCounter { public: @@ -124,52 +126,102 @@ struct AnalyzerStats { // it is queued when its captured frame was already removed due to high memory // usage for that video stream. int64_t memory_overloaded_comparisons_done = 0; + // Count of frames in flight in analyzer measured when new comparison is added + // and after analyzer was stopped. + SamplesStatsCounter frames_in_flight_left_count; }; +struct StatsKey { + StatsKey(std::string stream_label, std::string sender, std::string receiver) + : stream_label(std::move(stream_label)), + sender(std::move(sender)), + receiver(std::move(receiver)) {} + + std::string ToString() const; + + // Label of video stream to which stats belongs to. + std::string stream_label; + // Name of the peer which send this stream. + std::string sender; + // Name of the peer on which stream was received. + std::string receiver; +}; + +// Required to use StatsKey as std::map key. +bool operator<(const StatsKey& a, const StatsKey& b); +bool operator==(const StatsKey& a, const StatsKey& b); + +struct InternalStatsKey { + InternalStatsKey(size_t stream, size_t sender, size_t receiver) + : stream(stream), sender(sender), receiver(receiver) {} + + std::string ToString() const; + + size_t stream; + size_t sender; + size_t receiver; +}; + +// Required to use InternalStatsKey as std::map key. +bool operator<(const InternalStatsKey& a, const InternalStatsKey& b); +bool operator==(const InternalStatsKey& a, const InternalStatsKey& b); + class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { public: explicit DefaultVideoQualityAnalyzer( bool heavy_metrics_computation_enabled = true, - int max_frames_in_flight_per_stream_count = + size_t max_frames_in_flight_per_stream_count = kDefaultMaxFramesInFlightPerStream); ~DefaultVideoQualityAnalyzer() override; - void Start(std::string test_case_name, int max_threads_count) override; - uint16_t OnFrameCaptured(const std::string& stream_label, + void Start(std::string test_case_name, + rtc::ArrayView<const std::string> peer_names, + int max_threads_count) override; + uint16_t OnFrameCaptured(absl::string_view peer_name, + const std::string& stream_label, const VideoFrame& frame) override; - void OnFramePreEncode(const VideoFrame& frame) override; - void OnFrameEncoded(uint16_t frame_id, + void OnFramePreEncode(absl::string_view peer_name, + const VideoFrame& frame) override; + void OnFrameEncoded(absl::string_view peer_name, + uint16_t frame_id, const EncodedImage& encoded_image, const EncoderStats& stats) override; - void OnFrameDropped(EncodedImageCallback::DropReason reason) override; - void OnFramePreDecode(uint16_t frame_id, + void OnFrameDropped(absl::string_view peer_name, + EncodedImageCallback::DropReason reason) override; + void OnFramePreDecode(absl::string_view peer_name, + uint16_t frame_id, const EncodedImage& input_image) override; - void OnFrameDecoded(const VideoFrame& frame, + void OnFrameDecoded(absl::string_view peer_name, + const VideoFrame& frame, const DecoderStats& stats) override; - void OnFrameRendered(const VideoFrame& frame) override; - void OnEncoderError(const VideoFrame& frame, int32_t error_code) override; - void OnDecoderError(uint16_t frame_id, int32_t error_code) override; + void OnFrameRendered(absl::string_view peer_name, + const VideoFrame& frame) override; + void OnEncoderError(absl::string_view peer_name, + const VideoFrame& frame, + int32_t error_code) override; + void OnDecoderError(absl::string_view peer_name, + uint16_t frame_id, + int32_t error_code) override; void Stop() override; std::string GetStreamLabel(uint16_t frame_id) override; - void OnStatsReports(const std::string& pc_label, - const StatsReports& stats_reports) override {} + void OnStatsReports( + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) override {} // Returns set of stream labels, that were met during test call. - std::set<std::string> GetKnownVideoStreams() const; + std::set<StatsKey> GetKnownVideoStreams() const; const FrameCounters& GetGlobalCounters() const; // Returns frame counter per stream label. Valid stream labels can be obtained // by calling GetKnownVideoStreams() - const std::map<std::string, FrameCounters>& GetPerStreamCounters() const; + std::map<StatsKey, FrameCounters> GetPerStreamCounters() const; // Returns video quality stats per stream label. Valid stream labels can be // obtained by calling GetKnownVideoStreams() - std::map<std::string, StreamStats> GetStats() const; + std::map<StatsKey, StreamStats> GetStats() const; AnalyzerStats GetAnalyzerStats() const; private: struct FrameStats { - FrameStats(std::string stream_label, Timestamp captured_time); - - std::string stream_label; + FrameStats(Timestamp captured_time) : captured_time(captured_time) {} // Frame events timestamp. Timestamp captured_time; @@ -182,12 +234,11 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { Timestamp rendered_time = Timestamp::MinusInfinity(); Timestamp prev_frame_rendered_time = Timestamp::MinusInfinity(); + int64_t encoded_image_size = 0; uint32_t target_encode_bitrate = 0; absl::optional<int> rendered_frame_width = absl::nullopt; absl::optional<int> rendered_frame_height = absl::nullopt; - - int64_t encoded_image_size = 0; }; // Describes why comparison was done in overloaded mode (without calculating @@ -209,12 +260,14 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { // because there were too many comparisons in the queue. |dropped| can be // true or false showing was frame dropped or not. struct FrameComparison { - FrameComparison(absl::optional<VideoFrame> captured, + FrameComparison(InternalStatsKey stats_key, + absl::optional<VideoFrame> captured, absl::optional<VideoFrame> rendered, bool dropped, FrameStats frame_stats, OverloadReason overload_reason); + InternalStatsKey stats_key; // Frames can be omitted if there too many computations waiting in the // queue. absl::optional<VideoFrame> captured; @@ -230,49 +283,175 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { // Represents a current state of video stream. class StreamState { public: - void PushBack(uint16_t frame_id) { frame_ids_.emplace_back(frame_id); } - - uint16_t PopFront(); - - bool Empty() { return frame_ids_.empty(); } + StreamState(size_t owner, size_t peers_count) + : owner_(owner), frame_ids_(peers_count) {} - uint16_t Front() { return frame_ids_.front(); } + size_t owner() const { return owner_; } - int GetAliveFramesCount() { return frame_ids_.size() - dead_frames_count_; } + void PushBack(uint16_t frame_id) { frame_ids_.PushBack(frame_id); } + // Crash if state is empty. + uint16_t PopFront(size_t peer); + bool IsEmpty(size_t peer) const { return frame_ids_.IsEmpty(peer); } + // Crash if state is empty. + uint16_t Front(size_t peer) const { return frame_ids_.Front(peer).value(); } + size_t GetAliveFramesCount() { return frame_ids_.size(owner_); } uint16_t MarkNextAliveFrameAsDead(); - void set_last_rendered_frame_time(Timestamp time) { - last_rendered_frame_time_ = time; - } - absl::optional<Timestamp> last_rendered_frame_time() const { - return last_rendered_frame_time_; - } + void SetLastRenderedFrameTime(size_t peer, Timestamp time); + absl::optional<Timestamp> last_rendered_frame_time(size_t peer) const; private: + // Index of the owner. Owner's queue in |frame_ids_| will keep alive frames. + const size_t owner_; // To correctly determine dropped frames we have to know sequence of frames // in each stream so we will keep a list of frame ids inside the stream. - // When the frame is rendered, we will pop ids from the list for until id - // will match with rendered one. All ids before matched one can be - // considered as dropped: + // This list is represented by multi head queue of frame ids with separate + // head for each receiver. When the frame is rendered, we will pop ids from + // the corresponding head until id will match with rendered one. All ids + // before matched one can be considered as dropped: // // | frame_id1 |->| frame_id2 |->| frame_id3 |->| frame_id4 | // // If we received frame with id frame_id3, then we will pop frame_id1 and // frame_id2 and consider that frames as dropped and then compare received // frame with the one from |captured_frames_in_flight_| with id frame_id3. - std::deque<uint16_t> frame_ids_; - // Count of dead frames in the beginning of the deque. - int dead_frames_count_; - absl::optional<Timestamp> last_rendered_frame_time_ = absl::nullopt; + // + // To track alive frames (frames that contains frame's payload in + // |captured_frames_in_flight_|) the head which corresponds to |owner_| will + // be used. So that head will point to the first alive frame in frames list. + MultiHeadQueue<uint16_t> frame_ids_; + std::map<size_t, Timestamp> last_rendered_frame_time_; }; enum State { kNew, kActive, kStopped }; - void AddComparison(absl::optional<VideoFrame> captured, + struct ReceiverFrameStats { + // Time when last packet of a frame was received. + Timestamp received_time = Timestamp::MinusInfinity(); + Timestamp decode_start_time = Timestamp::MinusInfinity(); + Timestamp decode_end_time = Timestamp::MinusInfinity(); + Timestamp rendered_time = Timestamp::MinusInfinity(); + Timestamp prev_frame_rendered_time = Timestamp::MinusInfinity(); + + absl::optional<int> rendered_frame_width = absl::nullopt; + absl::optional<int> rendered_frame_height = absl::nullopt; + + bool dropped = false; + }; + + class FrameInFlight { + public: + FrameInFlight(size_t stream, + VideoFrame frame, + Timestamp captured_time, + size_t owner, + size_t peers_count) + : stream_(stream), + owner_(owner), + peers_count_(peers_count), + frame_(std::move(frame)), + captured_time_(captured_time) {} + + size_t stream() const { return stream_; } + const absl::optional<VideoFrame>& frame() const { return frame_; } + // Returns was frame removed or not. + bool RemoveFrame(); + void SetFrameId(uint16_t id); + + std::vector<size_t> GetPeersWhichDidntReceive() const; + bool HaveAllPeersReceived() const; + + void SetPreEncodeTime(webrtc::Timestamp time) { pre_encode_time_ = time; } + + void OnFrameEncoded(webrtc::Timestamp time, + int64_t encoded_image_size, + uint32_t target_encode_bitrate); + + bool HasEncodedTime() const { return encoded_time_.IsFinite(); } + + void OnFramePreDecode(size_t peer, + webrtc::Timestamp received_time, + webrtc::Timestamp decode_start_time); + + bool HasReceivedTime(size_t peer) const; + + void SetDecodeEndTime(size_t peer, webrtc::Timestamp time) { + receiver_stats_[peer].decode_end_time = time; + } + + bool HasDecodeEndTime(size_t peer) const; + + void OnFrameRendered(size_t peer, + webrtc::Timestamp time, + int width, + int height); + + bool HasRenderedTime(size_t peer) const; + + // Crash if rendered time is not set for specified |peer|. + webrtc::Timestamp rendered_time(size_t peer) const { + return receiver_stats_.at(peer).rendered_time; + } + + void MarkDropped(size_t peer) { receiver_stats_[peer].dropped = true; } + + void SetPrevFrameRenderedTime(size_t peer, webrtc::Timestamp time) { + receiver_stats_[peer].prev_frame_rendered_time = time; + } + + FrameStats GetStatsForPeer(size_t peer) const; + + private: + const size_t stream_; + const size_t owner_; + const size_t peers_count_; + absl::optional<VideoFrame> frame_; + + // Frame events timestamp. + Timestamp captured_time_; + Timestamp pre_encode_time_ = Timestamp::MinusInfinity(); + Timestamp encoded_time_ = Timestamp::MinusInfinity(); + int64_t encoded_image_size_ = 0; + uint32_t target_encode_bitrate_ = 0; + std::map<size_t, ReceiverFrameStats> receiver_stats_; + }; + + class NamesCollection { + public: + NamesCollection() = default; + explicit NamesCollection(rtc::ArrayView<const std::string> names) { + names_ = std::vector<std::string>(names.begin(), names.end()); + for (size_t i = 0; i < names_.size(); ++i) { + index_.emplace(names_[i], i); + } + } + + size_t size() const { return names_.size(); } + + size_t index(absl::string_view name) const { return index_.at(name); } + + const std::string& name(size_t index) const { return names_[index]; } + + bool HasName(absl::string_view name) const { + return index_.find(name) != index_.end(); + } + + // Add specified |name| to the collection if it isn't presented. + // Returns index which corresponds to specified |name|. + size_t AddIfAbsent(absl::string_view name); + + private: + std::vector<std::string> names_; + std::map<absl::string_view, size_t> index_; + }; + + void AddComparison(InternalStatsKey stats_key, + absl::optional<VideoFrame> captured, absl::optional<VideoFrame> rendered, bool dropped, - FrameStats frame_stats); + FrameStats frame_stats) + RTC_EXCLUSIVE_LOCKS_REQUIRED(comparison_lock_); static void ProcessComparisonsThread(void* obj); void ProcessComparisons(); void ProcessComparison(const FrameComparison& comparison); @@ -292,6 +471,11 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { // Returns name of current test case for reporting. std::string GetTestCaseName(const std::string& stream_label) const; Timestamp Now(); + StatsKey ToStatsKey(const InternalStatsKey& key) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); + // Returns string representation of stats key for metrics naming. Used for + // backward compatibility by metrics naming for 2 peers cases. + std::string StatsKeyToMetricName(const StatsKey& key); void StartMeasuringCpuProcessTime(); void StopMeasuringCpuProcessTime(); @@ -300,15 +484,19 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { double GetCpuUsagePercent(); const bool heavy_metrics_computation_enabled_; - const int max_frames_in_flight_per_stream_count_; + const size_t max_frames_in_flight_per_stream_count_; webrtc::Clock* const clock_; std::atomic<uint16_t> next_frame_id_{0}; std::string test_label_; + std::unique_ptr<NamesCollection> peers_; rtc::CriticalSection lock_; State state_ RTC_GUARDED_BY(lock_) = State::kNew; Timestamp start_time_ RTC_GUARDED_BY(lock_) = Timestamp::MinusInfinity(); + // Mapping from stream label to unique size_t value to use in stats and avoid + // extra string copying. + NamesCollection streams_ RTC_GUARDED_BY(lock_); // Frames that were captured by all streams and still aren't rendered by any // stream or deemed dropped. Frame with id X can be removed from this map if: // 1. The frame with id X was received in OnFrameRendered @@ -316,27 +504,29 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { // 3. Next available frame id for newly captured frame is X // 4. There too many frames in flight for current video stream and X is the // oldest frame id in this stream. - std::map<uint16_t, VideoFrame> captured_frames_in_flight_ + std::map<uint16_t, FrameInFlight> captured_frames_in_flight_ RTC_GUARDED_BY(lock_); // Global frames count for all video streams. FrameCounters frame_counters_ RTC_GUARDED_BY(lock_); - // Frame counters per each stream. - std::map<std::string, FrameCounters> stream_frame_counters_ + // Frame counters per each stream per each receiver. + std::map<InternalStatsKey, FrameCounters> stream_frame_counters_ RTC_GUARDED_BY(lock_); - std::map<uint16_t, FrameStats> frame_stats_ RTC_GUARDED_BY(lock_); - std::map<std::string, StreamState> stream_states_ RTC_GUARDED_BY(lock_); - - // Stores history mapping between stream labels and frame ids. Updated when - // frame id overlap. It required to properly return stream label after 1st - // frame from simulcast streams was already rendered and last is still - // encoding. - std::map<std::string, std::set<uint16_t>> stream_to_frame_id_history_ + // Map from stream index in |streams_| to its StreamState. + std::map<size_t, StreamState> stream_states_ RTC_GUARDED_BY(lock_); + // Map from stream index in |streams_| to sender peer index in |peers_|. + std::map<size_t, size_t> stream_to_sender_ RTC_GUARDED_BY(lock_); + + // Stores history mapping between stream index in |streams_| and frame ids. + // Updated when frame id overlap. It required to properly return stream label + // after 1st frame from simulcast streams was already rendered and last is + // still encoding. + std::map<size_t, std::set<uint16_t>> stream_to_frame_id_history_ RTC_GUARDED_BY(lock_); rtc::CriticalSection comparison_lock_; - std::map<std::string, StreamStats> stream_stats_ + std::map<InternalStatsKey, StreamStats> stream_stats_ RTC_GUARDED_BY(comparison_lock_); - std::map<std::string, Timestamp> stream_last_freeze_end_time_ + std::map<InternalStatsKey, Timestamp> stream_last_freeze_end_time_ RTC_GUARDED_BY(comparison_lock_); std::deque<FrameComparison> comparisons_ RTC_GUARDED_BY(comparison_lock_); AnalyzerStats analyzer_stats_ RTC_GUARDED_BY(comparison_lock_); diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc index 1bc29c5f091..55cc438b9d0 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc @@ -18,6 +18,7 @@ #include "api/video/encoded_image.h" #include "api/video/i420_buffer.h" #include "api/video/video_frame.h" +#include "rtc_base/strings/string_builder.h" #include "system_wrappers/include/sleep.h" #include "test/gtest.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer.h" @@ -26,11 +27,15 @@ namespace webrtc { namespace webrtc_pc_e2e { namespace { +using StatsSample = ::webrtc::SamplesStatsCounter::StatsSample; + constexpr int kAnalyzerMaxThreadsCount = 1; constexpr int kMaxFramesInFlightPerStream = 10; constexpr int kFrameWidth = 320; constexpr int kFrameHeight = 240; constexpr char kStreamLabel[] = "video-stream"; +constexpr char kSenderPeerName[] = "alice"; +constexpr char kReceiverPeerName[] = "bob"; VideoFrame NextFrame(test::FrameGeneratorInterface* frame_generator, int64_t timestamp_us) { @@ -64,6 +69,24 @@ VideoFrame DeepCopy(const VideoFrame& frame) { return copy; } +std::vector<StatsSample> GetSortedSamples(const SamplesStatsCounter& counter) { + rtc::ArrayView<const StatsSample> view = counter.GetTimedSamples(); + std::vector<StatsSample> out(view.begin(), view.end()); + std::sort(out.begin(), out.end(), + [](const StatsSample& a, const StatsSample& b) { + return a.time < b.time; + }); + return out; +} + +std::string ToString(const std::vector<StatsSample>& values) { + rtc::StringBuilder out; + for (const auto& v : values) { + out << "{ time_ms=" << v.time.ms() << "; value=" << v.value << "}, "; + } + return out.str(); +} + TEST(DefaultVideoQualityAnalyzerTest, MemoryOverloadedAndThenAllFramesReceived) { std::unique_ptr<test::FrameGeneratorInterface> frame_generator = @@ -73,26 +96,30 @@ TEST(DefaultVideoQualityAnalyzerTest, DefaultVideoQualityAnalyzer analyzer( /*heavy_metrics_computation_enabled=*/false, kMaxFramesInFlightPerStream); - analyzer.Start("test_case", kAnalyzerMaxThreadsCount); + analyzer.Start("test_case", + std::vector<std::string>{kSenderPeerName, kReceiverPeerName}, + kAnalyzerMaxThreadsCount); std::map<uint16_t, VideoFrame> captured_frames; std::vector<uint16_t> frames_order; for (int i = 0; i < kMaxFramesInFlightPerStream * 2; ++i) { VideoFrame frame = NextFrame(frame_generator.get(), i); - frame.set_id(analyzer.OnFrameCaptured(kStreamLabel, frame)); + frame.set_id( + analyzer.OnFrameCaptured(kSenderPeerName, kStreamLabel, frame)); frames_order.push_back(frame.id()); captured_frames.insert({frame.id(), frame}); - analyzer.OnFramePreEncode(frame); - analyzer.OnFrameEncoded(frame.id(), FakeEncode(frame), + analyzer.OnFramePreEncode(kSenderPeerName, frame); + analyzer.OnFrameEncoded(kSenderPeerName, frame.id(), FakeEncode(frame), VideoQualityAnalyzerInterface::EncoderStats()); } for (const uint16_t& frame_id : frames_order) { VideoFrame received_frame = DeepCopy(captured_frames.at(frame_id)); - analyzer.OnFramePreDecode(received_frame.id(), FakeEncode(received_frame)); - analyzer.OnFrameDecoded(received_frame, + analyzer.OnFramePreDecode(kReceiverPeerName, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kReceiverPeerName, received_frame, VideoQualityAnalyzerInterface::DecoderStats()); - analyzer.OnFrameRendered(received_frame); + analyzer.OnFrameRendered(kReceiverPeerName, received_frame); } // Give analyzer some time to process frames on async thread. The computations @@ -112,6 +139,87 @@ TEST(DefaultVideoQualityAnalyzerTest, } TEST(DefaultVideoQualityAnalyzerTest, + FillMaxMemoryReceiveAllMemoryOverloadedAndThenAllFramesReceived) { + std::unique_ptr<test::FrameGeneratorInterface> frame_generator = + test::CreateSquareFrameGenerator(kFrameWidth, kFrameHeight, + /*type=*/absl::nullopt, + /*num_squares=*/absl::nullopt); + + DefaultVideoQualityAnalyzer analyzer( + /*heavy_metrics_computation_enabled=*/false, kMaxFramesInFlightPerStream); + analyzer.Start("test_case", + std::vector<std::string>{kSenderPeerName, kReceiverPeerName}, + kAnalyzerMaxThreadsCount); + + std::map<uint16_t, VideoFrame> captured_frames; + std::vector<uint16_t> frames_order; + // Feel analyzer's memory up to limit + for (int i = 0; i < kMaxFramesInFlightPerStream; ++i) { + VideoFrame frame = NextFrame(frame_generator.get(), i); + frame.set_id( + analyzer.OnFrameCaptured(kSenderPeerName, kStreamLabel, frame)); + frames_order.push_back(frame.id()); + captured_frames.insert({frame.id(), frame}); + analyzer.OnFramePreEncode(kSenderPeerName, frame); + analyzer.OnFrameEncoded(kSenderPeerName, frame.id(), FakeEncode(frame), + VideoQualityAnalyzerInterface::EncoderStats()); + } + + // Receive all frames. + for (const uint16_t& frame_id : frames_order) { + VideoFrame received_frame = DeepCopy(captured_frames.at(frame_id)); + analyzer.OnFramePreDecode(kReceiverPeerName, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kReceiverPeerName, received_frame, + VideoQualityAnalyzerInterface::DecoderStats()); + analyzer.OnFrameRendered(kReceiverPeerName, received_frame); + } + frames_order.clear(); + + // Give analyzer some time to process frames on async thread. The computations + // have to be fast (heavy metrics are disabled!), so if doesn't fit 100ms it + // means we have an issue! + SleepMs(100); + + // Overload analyzer's memory up to limit + for (int i = 0; i < 2 * kMaxFramesInFlightPerStream; ++i) { + VideoFrame frame = NextFrame(frame_generator.get(), i); + frame.set_id( + analyzer.OnFrameCaptured(kSenderPeerName, kStreamLabel, frame)); + frames_order.push_back(frame.id()); + captured_frames.insert({frame.id(), frame}); + analyzer.OnFramePreEncode(kSenderPeerName, frame); + analyzer.OnFrameEncoded(kSenderPeerName, frame.id(), FakeEncode(frame), + VideoQualityAnalyzerInterface::EncoderStats()); + } + + // Receive all frames. + for (const uint16_t& frame_id : frames_order) { + VideoFrame received_frame = DeepCopy(captured_frames.at(frame_id)); + analyzer.OnFramePreDecode(kReceiverPeerName, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kReceiverPeerName, received_frame, + VideoQualityAnalyzerInterface::DecoderStats()); + analyzer.OnFrameRendered(kReceiverPeerName, received_frame); + } + + // Give analyzer some time to process frames on async thread. The computations + // have to be fast (heavy metrics are disabled!), so if doesn't fit 100ms it + // means we have an issue! + SleepMs(100); + analyzer.Stop(); + + AnalyzerStats stats = analyzer.GetAnalyzerStats(); + EXPECT_EQ(stats.memory_overloaded_comparisons_done, + kMaxFramesInFlightPerStream); + EXPECT_EQ(stats.comparisons_done, kMaxFramesInFlightPerStream * 3); + FrameCounters frame_counters = analyzer.GetGlobalCounters(); + EXPECT_EQ(frame_counters.captured, kMaxFramesInFlightPerStream * 3); + EXPECT_EQ(frame_counters.rendered, kMaxFramesInFlightPerStream * 3); + EXPECT_EQ(frame_counters.dropped, 0); +} + +TEST(DefaultVideoQualityAnalyzerTest, MemoryOverloadedHalfDroppedAndThenHalfFramesReceived) { std::unique_ptr<test::FrameGeneratorInterface> frame_generator = test::CreateSquareFrameGenerator(kFrameWidth, kFrameHeight, @@ -120,27 +228,31 @@ TEST(DefaultVideoQualityAnalyzerTest, DefaultVideoQualityAnalyzer analyzer( /*heavy_metrics_computation_enabled=*/false, kMaxFramesInFlightPerStream); - analyzer.Start("test_case", kAnalyzerMaxThreadsCount); + analyzer.Start("test_case", + std::vector<std::string>{kSenderPeerName, kReceiverPeerName}, + kAnalyzerMaxThreadsCount); std::map<uint16_t, VideoFrame> captured_frames; std::vector<uint16_t> frames_order; for (int i = 0; i < kMaxFramesInFlightPerStream * 2; ++i) { VideoFrame frame = NextFrame(frame_generator.get(), i); - frame.set_id(analyzer.OnFrameCaptured(kStreamLabel, frame)); + frame.set_id( + analyzer.OnFrameCaptured(kSenderPeerName, kStreamLabel, frame)); frames_order.push_back(frame.id()); captured_frames.insert({frame.id(), frame}); - analyzer.OnFramePreEncode(frame); - analyzer.OnFrameEncoded(frame.id(), FakeEncode(frame), + analyzer.OnFramePreEncode(kSenderPeerName, frame); + analyzer.OnFrameEncoded(kSenderPeerName, frame.id(), FakeEncode(frame), VideoQualityAnalyzerInterface::EncoderStats()); } for (size_t i = kMaxFramesInFlightPerStream; i < frames_order.size(); ++i) { uint16_t frame_id = frames_order.at(i); VideoFrame received_frame = DeepCopy(captured_frames.at(frame_id)); - analyzer.OnFramePreDecode(received_frame.id(), FakeEncode(received_frame)); - analyzer.OnFrameDecoded(received_frame, + analyzer.OnFramePreDecode(kReceiverPeerName, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kReceiverPeerName, received_frame, VideoQualityAnalyzerInterface::DecoderStats()); - analyzer.OnFrameRendered(received_frame); + analyzer.OnFrameRendered(kReceiverPeerName, received_frame); } // Give analyzer some time to process frames on async thread. The computations @@ -166,27 +278,31 @@ TEST(DefaultVideoQualityAnalyzerTest, NormalScenario) { DefaultVideoQualityAnalyzer analyzer( /*heavy_metrics_computation_enabled=*/false, kMaxFramesInFlightPerStream); - analyzer.Start("test_case", kAnalyzerMaxThreadsCount); + analyzer.Start("test_case", + std::vector<std::string>{kSenderPeerName, kReceiverPeerName}, + kAnalyzerMaxThreadsCount); std::map<uint16_t, VideoFrame> captured_frames; std::vector<uint16_t> frames_order; for (int i = 0; i < kMaxFramesInFlightPerStream; ++i) { VideoFrame frame = NextFrame(frame_generator.get(), i); - frame.set_id(analyzer.OnFrameCaptured(kStreamLabel, frame)); + frame.set_id( + analyzer.OnFrameCaptured(kSenderPeerName, kStreamLabel, frame)); frames_order.push_back(frame.id()); captured_frames.insert({frame.id(), frame}); - analyzer.OnFramePreEncode(frame); - analyzer.OnFrameEncoded(frame.id(), FakeEncode(frame), + analyzer.OnFramePreEncode(kSenderPeerName, frame); + analyzer.OnFrameEncoded(kSenderPeerName, frame.id(), FakeEncode(frame), VideoQualityAnalyzerInterface::EncoderStats()); } for (size_t i = 1; i < frames_order.size(); i += 2) { uint16_t frame_id = frames_order.at(i); VideoFrame received_frame = DeepCopy(captured_frames.at(frame_id)); - analyzer.OnFramePreDecode(received_frame.id(), FakeEncode(received_frame)); - analyzer.OnFrameDecoded(received_frame, + analyzer.OnFramePreDecode(kReceiverPeerName, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kReceiverPeerName, received_frame, VideoQualityAnalyzerInterface::DecoderStats()); - analyzer.OnFrameRendered(received_frame); + analyzer.OnFrameRendered(kReceiverPeerName, received_frame); } // Give analyzer some time to process frames on async thread. The computations @@ -199,6 +315,11 @@ TEST(DefaultVideoQualityAnalyzerTest, NormalScenario) { EXPECT_EQ(stats.memory_overloaded_comparisons_done, 0); EXPECT_EQ(stats.comparisons_done, kMaxFramesInFlightPerStream); + std::vector<StatsSample> frames_in_flight_sizes = + GetSortedSamples(stats.frames_in_flight_left_count); + EXPECT_EQ(frames_in_flight_sizes.back().value, 0) + << ToString(frames_in_flight_sizes); + FrameCounters frame_counters = analyzer.GetGlobalCounters(); EXPECT_EQ(frame_counters.captured, kMaxFramesInFlightPerStream); EXPECT_EQ(frame_counters.received, kMaxFramesInFlightPerStream / 2); @@ -207,6 +328,231 @@ TEST(DefaultVideoQualityAnalyzerTest, NormalScenario) { EXPECT_EQ(frame_counters.dropped, kMaxFramesInFlightPerStream / 2); } +TEST(DefaultVideoQualityAnalyzerTest, OneFrameReceivedTwice) { + std::unique_ptr<test::FrameGeneratorInterface> frame_generator = + test::CreateSquareFrameGenerator(kFrameWidth, kFrameHeight, + /*type=*/absl::nullopt, + /*num_squares=*/absl::nullopt); + + DefaultVideoQualityAnalyzer analyzer( + /*heavy_metrics_computation_enabled=*/false, kMaxFramesInFlightPerStream); + analyzer.Start("test_case", + std::vector<std::string>{kSenderPeerName, kReceiverPeerName}, + kAnalyzerMaxThreadsCount); + + VideoFrame captured_frame = NextFrame(frame_generator.get(), 0); + captured_frame.set_id( + analyzer.OnFrameCaptured(kSenderPeerName, kStreamLabel, captured_frame)); + analyzer.OnFramePreEncode(kSenderPeerName, captured_frame); + analyzer.OnFrameEncoded(kSenderPeerName, captured_frame.id(), + FakeEncode(captured_frame), + VideoQualityAnalyzerInterface::EncoderStats()); + + VideoFrame received_frame = DeepCopy(captured_frame); + analyzer.OnFramePreDecode(kReceiverPeerName, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kReceiverPeerName, received_frame, + VideoQualityAnalyzerInterface::DecoderStats()); + analyzer.OnFrameRendered(kReceiverPeerName, received_frame); + + received_frame = DeepCopy(captured_frame); + analyzer.OnFramePreDecode(kReceiverPeerName, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kReceiverPeerName, received_frame, + VideoQualityAnalyzerInterface::DecoderStats()); + analyzer.OnFrameRendered(kReceiverPeerName, received_frame); + + // Give analyzer some time to process frames on async thread. The computations + // have to be fast (heavy metrics are disabled!), so if doesn't fit 100ms it + // means we have an issue! + SleepMs(100); + analyzer.Stop(); + + AnalyzerStats stats = analyzer.GetAnalyzerStats(); + EXPECT_EQ(stats.memory_overloaded_comparisons_done, 0); + EXPECT_EQ(stats.comparisons_done, 1); + + FrameCounters frame_counters = analyzer.GetGlobalCounters(); + EXPECT_EQ(frame_counters.captured, 1); + EXPECT_EQ(frame_counters.received, 1); + EXPECT_EQ(frame_counters.decoded, 1); + EXPECT_EQ(frame_counters.rendered, 1); + EXPECT_EQ(frame_counters.dropped, 0); +} + +TEST(DefaultVideoQualityAnalyzerTest, NormalScenario2Receivers) { + std::unique_ptr<test::FrameGeneratorInterface> frame_generator = + test::CreateSquareFrameGenerator(kFrameWidth, kFrameHeight, + /*type=*/absl::nullopt, + /*num_squares=*/absl::nullopt); + + constexpr char kAlice[] = "alice"; + constexpr char kBob[] = "bob"; + constexpr char kCharlie[] = "charlie"; + + DefaultVideoQualityAnalyzer analyzer( + /*heavy_metrics_computation_enabled=*/false, kMaxFramesInFlightPerStream); + analyzer.Start("test_case", std::vector<std::string>{kAlice, kBob, kCharlie}, + kAnalyzerMaxThreadsCount); + + std::map<uint16_t, VideoFrame> captured_frames; + std::vector<uint16_t> frames_order; + for (int i = 0; i < kMaxFramesInFlightPerStream; ++i) { + VideoFrame frame = NextFrame(frame_generator.get(), i); + frame.set_id(analyzer.OnFrameCaptured(kAlice, kStreamLabel, frame)); + frames_order.push_back(frame.id()); + captured_frames.insert({frame.id(), frame}); + analyzer.OnFramePreEncode(kAlice, frame); + SleepMs(20); + analyzer.OnFrameEncoded(kAlice, frame.id(), FakeEncode(frame), + VideoQualityAnalyzerInterface::EncoderStats()); + } + + SleepMs(50); + + for (size_t i = 1; i < frames_order.size(); i += 2) { + uint16_t frame_id = frames_order.at(i); + VideoFrame received_frame = DeepCopy(captured_frames.at(frame_id)); + analyzer.OnFramePreDecode(kBob, received_frame.id(), + FakeEncode(received_frame)); + SleepMs(30); + analyzer.OnFrameDecoded(kBob, received_frame, + VideoQualityAnalyzerInterface::DecoderStats()); + SleepMs(10); + analyzer.OnFrameRendered(kBob, received_frame); + } + + for (size_t i = 1; i < frames_order.size(); i += 2) { + uint16_t frame_id = frames_order.at(i); + VideoFrame received_frame = DeepCopy(captured_frames.at(frame_id)); + analyzer.OnFramePreDecode(kCharlie, received_frame.id(), + FakeEncode(received_frame)); + SleepMs(40); + analyzer.OnFrameDecoded(kCharlie, received_frame, + VideoQualityAnalyzerInterface::DecoderStats()); + SleepMs(5); + analyzer.OnFrameRendered(kCharlie, received_frame); + } + + // Give analyzer some time to process frames on async thread. The computations + // have to be fast (heavy metrics are disabled!), so if doesn't fit 100ms it + // means we have an issue! + SleepMs(100); + analyzer.Stop(); + + AnalyzerStats analyzer_stats = analyzer.GetAnalyzerStats(); + EXPECT_EQ(analyzer_stats.memory_overloaded_comparisons_done, 0); + EXPECT_EQ(analyzer_stats.comparisons_done, kMaxFramesInFlightPerStream * 2); + + FrameCounters frame_counters = analyzer.GetGlobalCounters(); + EXPECT_EQ(frame_counters.captured, kMaxFramesInFlightPerStream); + EXPECT_EQ(frame_counters.received, kMaxFramesInFlightPerStream); + EXPECT_EQ(frame_counters.decoded, kMaxFramesInFlightPerStream); + EXPECT_EQ(frame_counters.rendered, kMaxFramesInFlightPerStream); + EXPECT_EQ(frame_counters.dropped, kMaxFramesInFlightPerStream); + EXPECT_EQ(analyzer.GetKnownVideoStreams().size(), 2lu); + for (auto stream_key : analyzer.GetKnownVideoStreams()) { + FrameCounters stream_conters = + analyzer.GetPerStreamCounters().at(stream_key); + // On some devices the pipeline can be too slow, so we actually can't + // force real constraints here. Lets just check, that at least 1 + // frame passed whole pipeline. + EXPECT_GE(stream_conters.captured, 10); + EXPECT_GE(stream_conters.pre_encoded, 10); + EXPECT_GE(stream_conters.encoded, 10); + EXPECT_GE(stream_conters.received, 5); + EXPECT_GE(stream_conters.decoded, 5); + EXPECT_GE(stream_conters.rendered, 5); + EXPECT_GE(stream_conters.dropped, 5); + } + + std::map<StatsKey, StreamStats> stats = analyzer.GetStats(); + const StatsKey kAliceBobStats(kStreamLabel, kAlice, kBob); + const StatsKey kAliceCharlieStats(kStreamLabel, kAlice, kCharlie); + EXPECT_EQ(stats.size(), 2lu); + { + auto it = stats.find(kAliceBobStats); + EXPECT_FALSE(it == stats.end()); + ASSERT_FALSE(it->second.encode_time_ms.IsEmpty()); + EXPECT_GE(it->second.encode_time_ms.GetMin(), 20); + ASSERT_FALSE(it->second.decode_time_ms.IsEmpty()); + EXPECT_GE(it->second.decode_time_ms.GetMin(), 30); + ASSERT_FALSE(it->second.resolution_of_rendered_frame.IsEmpty()); + EXPECT_GE(it->second.resolution_of_rendered_frame.GetMin(), + kFrameWidth * kFrameHeight - 1); + EXPECT_LE(it->second.resolution_of_rendered_frame.GetMax(), + kFrameWidth * kFrameHeight + 1); + } + { + auto it = stats.find(kAliceCharlieStats); + EXPECT_FALSE(it == stats.end()); + ASSERT_FALSE(it->second.encode_time_ms.IsEmpty()); + EXPECT_GE(it->second.encode_time_ms.GetMin(), 20); + ASSERT_FALSE(it->second.decode_time_ms.IsEmpty()); + EXPECT_GE(it->second.decode_time_ms.GetMin(), 30); + ASSERT_FALSE(it->second.resolution_of_rendered_frame.IsEmpty()); + EXPECT_GE(it->second.resolution_of_rendered_frame.GetMin(), + kFrameWidth * kFrameHeight - 1); + EXPECT_LE(it->second.resolution_of_rendered_frame.GetMax(), + kFrameWidth * kFrameHeight + 1); + } +} + +TEST(DefaultVideoQualityAnalyzerTest, OneFrameReceivedTwiceWith2Receivers) { + std::unique_ptr<test::FrameGeneratorInterface> frame_generator = + test::CreateSquareFrameGenerator(kFrameWidth, kFrameHeight, + /*type=*/absl::nullopt, + /*num_squares=*/absl::nullopt); + + constexpr char kAlice[] = "alice"; + constexpr char kBob[] = "bob"; + constexpr char kCharlie[] = "charlie"; + + DefaultVideoQualityAnalyzer analyzer( + /*heavy_metrics_computation_enabled=*/false, kMaxFramesInFlightPerStream); + analyzer.Start("test_case", std::vector<std::string>{kAlice, kBob, kCharlie}, + kAnalyzerMaxThreadsCount); + + VideoFrame captured_frame = NextFrame(frame_generator.get(), 0); + captured_frame.set_id( + analyzer.OnFrameCaptured(kAlice, kStreamLabel, captured_frame)); + analyzer.OnFramePreEncode(kAlice, captured_frame); + analyzer.OnFrameEncoded(kAlice, captured_frame.id(), + FakeEncode(captured_frame), + VideoQualityAnalyzerInterface::EncoderStats()); + + VideoFrame received_frame = DeepCopy(captured_frame); + analyzer.OnFramePreDecode(kBob, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kBob, received_frame, + VideoQualityAnalyzerInterface::DecoderStats()); + analyzer.OnFrameRendered(kBob, received_frame); + + received_frame = DeepCopy(captured_frame); + analyzer.OnFramePreDecode(kBob, received_frame.id(), + FakeEncode(received_frame)); + analyzer.OnFrameDecoded(kBob, received_frame, + VideoQualityAnalyzerInterface::DecoderStats()); + analyzer.OnFrameRendered(kBob, received_frame); + + // Give analyzer some time to process frames on async thread. The computations + // have to be fast (heavy metrics are disabled!), so if doesn't fit 100ms it + // means we have an issue! + SleepMs(100); + analyzer.Stop(); + + AnalyzerStats stats = analyzer.GetAnalyzerStats(); + EXPECT_EQ(stats.memory_overloaded_comparisons_done, 0); + EXPECT_EQ(stats.comparisons_done, 1); + + FrameCounters frame_counters = analyzer.GetGlobalCounters(); + EXPECT_EQ(frame_counters.captured, 1); + EXPECT_EQ(frame_counters.received, 1); + EXPECT_EQ(frame_counters.decoded, 1); + EXPECT_EQ(frame_counters.rendered, 1); + EXPECT_EQ(frame_counters.dropped, 0); +} + } // namespace } // namespace webrtc_pc_e2e } // namespace webrtc diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc index d1d1bface7d..a980b0e9d09 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc @@ -10,6 +10,7 @@ #include "test/pc/e2e/analyzer/video/example_video_quality_analyzer.h" +#include "api/array_view.h" #include "rtc_base/logging.h" namespace webrtc { @@ -18,10 +19,13 @@ namespace webrtc_pc_e2e { ExampleVideoQualityAnalyzer::ExampleVideoQualityAnalyzer() = default; ExampleVideoQualityAnalyzer::~ExampleVideoQualityAnalyzer() = default; -void ExampleVideoQualityAnalyzer::Start(std::string test_case_name, - int max_threads_count) {} +void ExampleVideoQualityAnalyzer::Start( + std::string test_case_name, + rtc::ArrayView<const std::string> peer_names, + int max_threads_count) {} uint16_t ExampleVideoQualityAnalyzer::OnFrameCaptured( + absl::string_view peer_name, const std::string& stream_label, const webrtc::VideoFrame& frame) { rtc::CritScope crit(&lock_); @@ -45,12 +49,14 @@ uint16_t ExampleVideoQualityAnalyzer::OnFrameCaptured( } void ExampleVideoQualityAnalyzer::OnFramePreEncode( + absl::string_view peer_name, const webrtc::VideoFrame& frame) { rtc::CritScope crit(&lock_); ++frames_pre_encoded_; } void ExampleVideoQualityAnalyzer::OnFrameEncoded( + absl::string_view peer_name, uint16_t frame_id, const webrtc::EncodedImage& encoded_image, const EncoderStats& stats) { @@ -59,6 +65,7 @@ void ExampleVideoQualityAnalyzer::OnFrameEncoded( } void ExampleVideoQualityAnalyzer::OnFrameDropped( + absl::string_view peer_name, webrtc::EncodedImageCallback::DropReason reason) { RTC_LOG(INFO) << "Frame dropped by encoder"; rtc::CritScope crit(&lock_); @@ -66,6 +73,7 @@ void ExampleVideoQualityAnalyzer::OnFrameDropped( } void ExampleVideoQualityAnalyzer::OnFramePreDecode( + absl::string_view peer_name, uint16_t frame_id, const webrtc::EncodedImage& encoded_image) { rtc::CritScope crit(&lock_); @@ -73,6 +81,7 @@ void ExampleVideoQualityAnalyzer::OnFramePreDecode( } void ExampleVideoQualityAnalyzer::OnFrameDecoded( + absl::string_view peer_name, const webrtc::VideoFrame& frame, const DecoderStats& stats) { rtc::CritScope crit(&lock_); @@ -80,6 +89,7 @@ void ExampleVideoQualityAnalyzer::OnFrameDecoded( } void ExampleVideoQualityAnalyzer::OnFrameRendered( + absl::string_view peer_name, const webrtc::VideoFrame& frame) { rtc::CritScope crit(&lock_); frames_in_flight_.erase(frame.id()); @@ -87,13 +97,15 @@ void ExampleVideoQualityAnalyzer::OnFrameRendered( } void ExampleVideoQualityAnalyzer::OnEncoderError( + absl::string_view peer_name, const webrtc::VideoFrame& frame, int32_t error_code) { RTC_LOG(LS_ERROR) << "Failed to encode frame " << frame.id() << ". Code: " << error_code; } -void ExampleVideoQualityAnalyzer::OnDecoderError(uint16_t frame_id, +void ExampleVideoQualityAnalyzer::OnDecoderError(absl::string_view peer_name, + uint16_t frame_id, int32_t error_code) { RTC_LOG(LS_ERROR) << "Failed to decode frame " << frame_id << ". Code: " << error_code; diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h index 0d6169f9fa2..0126093c87a 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h @@ -16,6 +16,7 @@ #include <set> #include <string> +#include "api/array_view.h" #include "api/test/video_quality_analyzer_interface.h" #include "api/video/encoded_image.h" #include "api/video/video_frame.h" @@ -33,21 +34,34 @@ class ExampleVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { ExampleVideoQualityAnalyzer(); ~ExampleVideoQualityAnalyzer() override; - void Start(std::string test_case_name, int max_threads_count) override; - uint16_t OnFrameCaptured(const std::string& stream_label, + void Start(std::string test_case_name, + rtc::ArrayView<const std::string> peer_names, + int max_threads_count) override; + uint16_t OnFrameCaptured(absl::string_view peer_name, + const std::string& stream_label, const VideoFrame& frame) override; - void OnFramePreEncode(const VideoFrame& frame) override; - void OnFrameEncoded(uint16_t frame_id, + void OnFramePreEncode(absl::string_view peer_name, + const VideoFrame& frame) override; + void OnFrameEncoded(absl::string_view peer_name, + uint16_t frame_id, const EncodedImage& encoded_image, const EncoderStats& stats) override; - void OnFrameDropped(EncodedImageCallback::DropReason reason) override; - void OnFramePreDecode(uint16_t frame_id, + void OnFrameDropped(absl::string_view peer_name, + EncodedImageCallback::DropReason reason) override; + void OnFramePreDecode(absl::string_view peer_name, + uint16_t frame_id, const EncodedImage& encoded_image) override; - void OnFrameDecoded(const VideoFrame& frame, + void OnFrameDecoded(absl::string_view peer_name, + const VideoFrame& frame, const DecoderStats& stats) override; - void OnFrameRendered(const VideoFrame& frame) override; - void OnEncoderError(const VideoFrame& frame, int32_t error_code) override; - void OnDecoderError(uint16_t frame_id, int32_t error_code) override; + void OnFrameRendered(absl::string_view peer_name, + const VideoFrame& frame) override; + void OnEncoderError(absl::string_view peer_name, + const VideoFrame& frame, + int32_t error_code) override; + void OnDecoderError(absl::string_view peer_name, + uint16_t frame_id, + int32_t error_code) override; void Stop() override; std::string GetStreamLabel(uint16_t frame_id) override; diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/multi_head_queue.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/multi_head_queue.h new file mode 100644 index 00000000000..52314a60d54 --- /dev/null +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/multi_head_queue.h @@ -0,0 +1,99 @@ +/* + * 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_ANALYZER_VIDEO_MULTI_HEAD_QUEUE_H_ +#define TEST_PC_E2E_ANALYZER_VIDEO_MULTI_HEAD_QUEUE_H_ + +#include <deque> +#include <memory> +#include <vector> + +#include "absl/types/optional.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace webrtc_pc_e2e { + +// A queue that allows more than one reader. Readers are independent, and all +// readers will see all elements; an inserted element stays in the queue until +// all readers have extracted it. Elements are copied and copying is assumed to +// be cheap. +template <typename T> +class MultiHeadQueue { + public: + // Creates queue with exactly |readers_count| readers. + explicit MultiHeadQueue(size_t readers_count) { + for (size_t i = 0; i < readers_count; ++i) { + queues_.push_back(std::deque<T>()); + } + } + + // Add value to the end of the queue. Complexity O(readers_count). + void PushBack(T value) { + for (auto& queue : queues_) { + queue.push_back(value); + } + } + + // Extract element from specified head. Complexity O(1). + absl::optional<T> PopFront(size_t index) { + RTC_CHECK_LT(index, queues_.size()); + if (queues_[index].empty()) { + return absl::nullopt; + } + T out = queues_[index].front(); + queues_[index].pop_front(); + return out; + } + + // Returns element at specified head. Complexity O(1). + absl::optional<T> Front(size_t index) const { + RTC_CHECK_LT(index, queues_.size()); + if (queues_[index].empty()) { + return absl::nullopt; + } + return queues_[index].front(); + } + + // Returns true if for specified head there are no more elements in the queue + // or false otherwise. Complexity O(1). + bool IsEmpty(size_t index) const { + RTC_CHECK_LT(index, queues_.size()); + return queues_[index].empty(); + } + + // Returns size of the longest queue between all readers. + // Complexity O(readers_count). + size_t size() const { + size_t size = 0; + for (auto& queue : queues_) { + if (queue.size() > size) { + size = queue.size(); + } + } + return size; + } + + // Returns size of the specified queue. Complexity O(1). + size_t size(size_t index) const { + RTC_CHECK_LT(index, queues_.size()); + return queues_[index].size(); + } + + size_t readers_count() const { return queues_.size(); } + + private: + std::vector<std::deque<T>> queues_; +}; + +} // namespace webrtc_pc_e2e +} // namespace webrtc + +#endif // TEST_PC_E2E_ANALYZER_VIDEO_MULTI_HEAD_QUEUE_H_ diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/multi_head_queue_test.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/multi_head_queue_test.cc new file mode 100644 index 00000000000..3a4ab6cdbb9 --- /dev/null +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/multi_head_queue_test.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020 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/analyzer/video/multi_head_queue.h" +#include "absl/types/optional.h" +#include "test/gtest.h" + +namespace webrtc { +namespace webrtc_pc_e2e { +namespace { + +TEST(MultiHeadQueueTest, GetOnEmpty) { + MultiHeadQueue<int> queue = MultiHeadQueue<int>(10); + EXPECT_TRUE(queue.IsEmpty(0)); + for (int i = 0; i < 10; ++i) { + EXPECT_FALSE(queue.PopFront(i).has_value()); + EXPECT_FALSE(queue.Front(i).has_value()); + } +} + +TEST(MultiHeadQueueTest, SingleHeadOneAddOneRemove) { + MultiHeadQueue<int> queue = MultiHeadQueue<int>(1); + queue.PushBack(1); + EXPECT_EQ(queue.size(), 1lu); + EXPECT_TRUE(queue.Front(0).has_value()); + EXPECT_EQ(queue.Front(0).value(), 1); + absl::optional<int> value = queue.PopFront(0); + EXPECT_TRUE(value.has_value()); + EXPECT_EQ(value.value(), 1); + EXPECT_EQ(queue.size(), 0lu); + EXPECT_TRUE(queue.IsEmpty(0)); +} + +TEST(MultiHeadQueueTest, SingleHead) { + MultiHeadQueue<size_t> queue = MultiHeadQueue<size_t>(1); + for (size_t i = 0; i < 10; ++i) { + queue.PushBack(i); + EXPECT_EQ(queue.size(), i + 1); + } + for (size_t i = 0; i < 10; ++i) { + absl::optional<size_t> value = queue.PopFront(0); + EXPECT_EQ(queue.size(), 10 - i - 1); + ASSERT_TRUE(value.has_value()); + EXPECT_EQ(value.value(), i); + } +} + +TEST(MultiHeadQueueTest, ThreeHeadsAddAllRemoveAllPerHead) { + MultiHeadQueue<size_t> queue = MultiHeadQueue<size_t>(3); + for (size_t i = 0; i < 10; ++i) { + queue.PushBack(i); + EXPECT_EQ(queue.size(), i + 1); + } + for (size_t i = 0; i < 10; ++i) { + absl::optional<size_t> value = queue.PopFront(0); + EXPECT_EQ(queue.size(), 10lu); + ASSERT_TRUE(value.has_value()); + EXPECT_EQ(value.value(), i); + } + for (size_t i = 0; i < 10; ++i) { + absl::optional<size_t> value = queue.PopFront(1); + EXPECT_EQ(queue.size(), 10lu); + ASSERT_TRUE(value.has_value()); + EXPECT_EQ(value.value(), i); + } + for (size_t i = 0; i < 10; ++i) { + absl::optional<size_t> value = queue.PopFront(2); + EXPECT_EQ(queue.size(), 10 - i - 1); + ASSERT_TRUE(value.has_value()); + EXPECT_EQ(value.value(), i); + } +} + +TEST(MultiHeadQueueTest, ThreeHeadsAddAllRemoveAll) { + MultiHeadQueue<size_t> queue = MultiHeadQueue<size_t>(3); + for (size_t i = 0; i < 10; ++i) { + queue.PushBack(i); + EXPECT_EQ(queue.size(), i + 1); + } + for (size_t i = 0; i < 10; ++i) { + absl::optional<size_t> value1 = queue.PopFront(0); + absl::optional<size_t> value2 = queue.PopFront(1); + absl::optional<size_t> value3 = queue.PopFront(2); + EXPECT_EQ(queue.size(), 10 - i - 1); + ASSERT_TRUE(value1.has_value()); + ASSERT_TRUE(value2.has_value()); + ASSERT_TRUE(value3.has_value()); + EXPECT_EQ(value1.value(), i); + EXPECT_EQ(value2.value(), i); + EXPECT_EQ(value3.value(), i); + } +} + +} // namespace +} // namespace webrtc_pc_e2e +} // namespace webrtc diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.cc index 228ab8ac025..9e81c8728bd 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.cc @@ -15,6 +15,7 @@ #include <memory> #include <utility> +#include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/video/i420_buffer.h" #include "modules/video_coding/include/video_error_codes.h" @@ -26,10 +27,12 @@ namespace webrtc_pc_e2e { QualityAnalyzingVideoDecoder::QualityAnalyzingVideoDecoder( int id, + absl::string_view peer_name, std::unique_ptr<VideoDecoder> delegate, EncodedImageDataExtractor* extractor, VideoQualityAnalyzerInterface* analyzer) : id_(id), + peer_name_(peer_name), implementation_name_("AnalyzingDecoder-" + std::string(delegate->ImplementationName())), delegate_(std::move(delegate)), @@ -87,7 +90,7 @@ int32_t QualityAnalyzingVideoDecoder::Decode(const EncodedImage& input_image, // We can safely dereference |origin_image|, because it can be removed from // the map only after |delegate_| Decode method will be invoked. Image will be // removed inside DecodedImageCallback, which can be done on separate thread. - analyzer_->OnFramePreDecode(out.id, *origin_image); + analyzer_->OnFramePreDecode(peer_name_, out.id, *origin_image); int32_t result = delegate_->Decode(*origin_image, missing_frames, render_time_ms); if (result != WEBRTC_VIDEO_CODEC_OK) { @@ -97,7 +100,7 @@ int32_t QualityAnalyzingVideoDecoder::Decode(const EncodedImage& input_image, timestamp_to_frame_id_.erase(input_image.Timestamp()); decoding_images_.erase(out.id); } - analyzer_->OnDecoderError(out.id, result); + analyzer_->OnDecoderError(peer_name_, out.id, result); } return result; } @@ -224,15 +227,17 @@ void QualityAnalyzingVideoDecoder::OnFrameDecoded( frame->set_id(frame_id); VideoQualityAnalyzerInterface::DecoderStats stats; stats.decode_time_ms = decode_time_ms; - analyzer_->OnFrameDecoded(*frame, stats); + analyzer_->OnFrameDecoded(peer_name_, *frame, stats); } QualityAnalyzingVideoDecoderFactory::QualityAnalyzingVideoDecoderFactory( + absl::string_view peer_name, std::unique_ptr<VideoDecoderFactory> delegate, IdGenerator<int>* id_generator, EncodedImageDataExtractor* extractor, VideoQualityAnalyzerInterface* analyzer) - : delegate_(std::move(delegate)), + : peer_name_(peer_name), + delegate_(std::move(delegate)), id_generator_(id_generator), extractor_(extractor), analyzer_(analyzer) {} @@ -249,7 +254,8 @@ QualityAnalyzingVideoDecoderFactory::CreateVideoDecoder( const SdpVideoFormat& format) { std::unique_ptr<VideoDecoder> decoder = delegate_->CreateVideoDecoder(format); return std::make_unique<QualityAnalyzingVideoDecoder>( - id_generator_->GetNextId(), std::move(decoder), extractor_, analyzer_); + id_generator_->GetNextId(), peer_name_, std::move(decoder), extractor_, + analyzer_); } std::unique_ptr<VideoDecoder> @@ -259,7 +265,8 @@ QualityAnalyzingVideoDecoderFactory::LegacyCreateVideoDecoder( std::unique_ptr<VideoDecoder> decoder = delegate_->LegacyCreateVideoDecoder(format, receive_stream_id); return std::make_unique<QualityAnalyzingVideoDecoder>( - id_generator_->GetNextId(), std::move(decoder), extractor_, analyzer_); + id_generator_->GetNextId(), peer_name_, std::move(decoder), extractor_, + analyzer_); } } // namespace webrtc_pc_e2e diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h index 5cbc8822266..decb844bc2a 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h @@ -16,6 +16,7 @@ #include <string> #include <vector> +#include "absl/strings/string_view.h" #include "api/test/video_quality_analyzer_interface.h" #include "api/video/encoded_image.h" #include "api/video/video_frame.h" @@ -45,14 +46,15 @@ namespace webrtc_pc_e2e { // callback, where video analyzer will be called again and then decoded frame // will be passed to origin callback, provided by user. // -// Quality decoder registers its own callback in origin decoder at the same -// time, when user registers his callback in quality decoder. +// Quality decoder registers its own callback in origin decoder, at the same +// time the user registers their callback in quality decoder. class QualityAnalyzingVideoDecoder : public VideoDecoder { public: // Creates analyzing decoder. |id| is unique coding entity id, that will // be used to distinguish all encoders and decoders inside // EncodedImageDataInjector and EncodedImageIdExtracor. QualityAnalyzingVideoDecoder(int id, + absl::string_view peer_name, std::unique_ptr<VideoDecoder> delegate, EncodedImageDataExtractor* extractor, VideoQualityAnalyzerInterface* analyzer); @@ -104,6 +106,7 @@ class QualityAnalyzingVideoDecoder : public VideoDecoder { absl::optional<uint8_t> qp); const int id_; + const std::string peer_name_; const std::string implementation_name_; std::unique_ptr<VideoDecoder> delegate_; EncodedImageDataExtractor* const extractor_; @@ -129,6 +132,7 @@ class QualityAnalyzingVideoDecoder : public VideoDecoder { class QualityAnalyzingVideoDecoderFactory : public VideoDecoderFactory { public: QualityAnalyzingVideoDecoderFactory( + absl::string_view peer_name, std::unique_ptr<VideoDecoderFactory> delegate, IdGenerator<int>* id_generator, EncodedImageDataExtractor* extractor, @@ -144,6 +148,7 @@ class QualityAnalyzingVideoDecoderFactory : public VideoDecoderFactory { const std::string& receive_stream_id) override; private: + const std::string peer_name_; std::unique_ptr<VideoDecoderFactory> delegate_; IdGenerator<int>* const id_generator_; EncodedImageDataExtractor* const extractor_; diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc index 2e7b8f41529..4d04a2ccbbb 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc @@ -14,6 +14,7 @@ #include <memory> #include <utility> +#include "absl/strings/string_view.h" #include "api/video/video_codec_type.h" #include "api/video_codecs/video_encoder.h" #include "modules/video_coding/include/video_error_codes.h" @@ -54,12 +55,14 @@ std::pair<uint32_t, uint32_t> GetMinMaxBitratesBps(const VideoCodec& codec, QualityAnalyzingVideoEncoder::QualityAnalyzingVideoEncoder( int id, + absl::string_view peer_name, std::unique_ptr<VideoEncoder> delegate, double bitrate_multiplier, std::map<std::string, absl::optional<int>> stream_required_spatial_index, EncodedImageDataInjector* injector, VideoQualityAnalyzerInterface* analyzer) : id_(id), + peer_name_(peer_name), delegate_(std::move(delegate)), bitrate_multiplier_(bitrate_multiplier), stream_required_spatial_index_(std::move(stream_required_spatial_index)), @@ -134,7 +137,7 @@ int32_t QualityAnalyzingVideoEncoder::Encode( // images from encoder. So it should be a bug in setup on in the encoder. RTC_DCHECK_LT(timestamp_to_frame_id_list_.size(), kMaxFrameInPipelineCount); } - analyzer_->OnFramePreEncode(frame); + analyzer_->OnFramePreEncode(peer_name_, frame); int32_t result = delegate_->Encode(frame, frame_types); if (result != WEBRTC_VIDEO_CODEC_OK) { // If origin encoder failed, then cleanup data for this frame. @@ -152,7 +155,7 @@ int32_t QualityAnalyzingVideoEncoder::Encode( } } } - analyzer_->OnEncoderError(frame, result); + analyzer_->OnEncoderError(peer_name_, frame, result); } return result; } @@ -277,7 +280,7 @@ EncodedImageCallback::Result QualityAnalyzingVideoEncoder::OnEncodedImage( // not discarded layers have to be passed. VideoQualityAnalyzerInterface::EncoderStats stats; stats.target_encode_bitrate = target_encode_bitrate; - analyzer_->OnFrameEncoded(frame_id, encoded_image, stats); + analyzer_->OnFrameEncoded(peer_name_, frame_id, encoded_image, stats); } // Image data injector injects frame id and discard flag into provided @@ -298,7 +301,7 @@ EncodedImageCallback::Result QualityAnalyzingVideoEncoder::OnEncodedImage( void QualityAnalyzingVideoEncoder::OnDroppedFrame( EncodedImageCallback::DropReason reason) { rtc::CritScope crit(&lock_); - analyzer_->OnFrameDropped(reason); + analyzer_->OnFrameDropped(peer_name_, reason); RTC_DCHECK(delegate_callback_); delegate_callback_->OnDroppedFrame(reason); } @@ -348,13 +351,15 @@ bool QualityAnalyzingVideoEncoder::ShouldDiscard( } QualityAnalyzingVideoEncoderFactory::QualityAnalyzingVideoEncoderFactory( + absl::string_view peer_name, std::unique_ptr<VideoEncoderFactory> delegate, double bitrate_multiplier, std::map<std::string, absl::optional<int>> stream_required_spatial_index, IdGenerator<int>* id_generator, EncodedImageDataInjector* injector, VideoQualityAnalyzerInterface* analyzer) - : delegate_(std::move(delegate)), + : peer_name_(peer_name), + delegate_(std::move(delegate)), bitrate_multiplier_(bitrate_multiplier), stream_required_spatial_index_(std::move(stream_required_spatial_index)), id_generator_(id_generator), @@ -378,9 +383,9 @@ std::unique_ptr<VideoEncoder> QualityAnalyzingVideoEncoderFactory::CreateVideoEncoder( const SdpVideoFormat& format) { return std::make_unique<QualityAnalyzingVideoEncoder>( - id_generator_->GetNextId(), delegate_->CreateVideoEncoder(format), - bitrate_multiplier_, stream_required_spatial_index_, injector_, - analyzer_); + id_generator_->GetNextId(), peer_name_, + delegate_->CreateVideoEncoder(format), bitrate_multiplier_, + stream_required_spatial_index_, injector_, analyzer_); } } // namespace webrtc_pc_e2e diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.h index 3307dc73255..f6db1369b09 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.h +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.h @@ -16,6 +16,7 @@ #include <utility> #include <vector> +#include "absl/strings/string_view.h" #include "api/test/video_quality_analyzer_interface.h" #include "api/video/video_frame.h" #include "api/video_codecs/sdp_video_format.h" @@ -49,8 +50,8 @@ constexpr int kAnalyzeAnySpatialStream = -1; // injected into EncodedImage with passed EncodedImageDataInjector. Then new // EncodedImage will be passed to origin callback, provided by user. // -// Quality encoder registers its own callback in origin encoder at the same -// time, when user registers his callback in quality encoder. +// Quality encoder registers its own callback in origin encoder, at the same +// time the user registers their callback in quality encoder. class QualityAnalyzingVideoEncoder : public VideoEncoder, public EncodedImageCallback { public: @@ -59,6 +60,7 @@ class QualityAnalyzingVideoEncoder : public VideoEncoder, // EncodedImageDataInjector and EncodedImageIdExtracor. QualityAnalyzingVideoEncoder( int id, + absl::string_view peer_name, std::unique_ptr<VideoEncoder> delegate, double bitrate_multiplier, std::map<std::string, absl::optional<int>> stream_required_spatial_index, @@ -139,6 +141,7 @@ class QualityAnalyzingVideoEncoder : public VideoEncoder, RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); const int id_; + const std::string peer_name_; std::unique_ptr<VideoEncoder> delegate_; const double bitrate_multiplier_; // Contains mapping from stream label to optional spatial index. @@ -170,6 +173,7 @@ class QualityAnalyzingVideoEncoder : public VideoEncoder, class QualityAnalyzingVideoEncoderFactory : public VideoEncoderFactory { public: QualityAnalyzingVideoEncoderFactory( + absl::string_view peer_name, std::unique_ptr<VideoEncoderFactory> delegate, double bitrate_multiplier, std::map<std::string, absl::optional<int>> stream_required_spatial_index, @@ -186,6 +190,7 @@ class QualityAnalyzingVideoEncoderFactory : public VideoEncoderFactory { const SdpVideoFormat& format) override; private: + const std::string peer_name_; std::unique_ptr<VideoEncoderFactory> delegate_; const double bitrate_multiplier_; std::map<std::string, absl::optional<int>> stream_required_spatial_index_; diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.cc index ec0d26b780b..75f1265e1f4 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.cc @@ -19,13 +19,6 @@ namespace webrtc { namespace webrtc_pc_e2e { -namespace { - -// Number of bytes from the beginning of the EncodedImage buffer that will be -// used to store frame id and sub id. -constexpr size_t kUsedBufferSize = 3; - -} // namespace SingleProcessEncodedImageDataInjector::SingleProcessEncodedImageDataInjector() = default; @@ -37,13 +30,13 @@ EncodedImage SingleProcessEncodedImageDataInjector::InjectData( bool discard, const EncodedImage& source, int coding_entity_id) { - RTC_CHECK(source.size() >= kUsedBufferSize); + RTC_CHECK(source.size() >= ExtractionInfo::kUsedBufferSize); ExtractionInfo info; - info.length = source.size(); info.discard = discard; - size_t insertion_pos = source.size() - kUsedBufferSize; - memcpy(info.origin_data, &source.data()[insertion_pos], kUsedBufferSize); + size_t insertion_pos = source.size() - ExtractionInfo::kUsedBufferSize; + memcpy(info.origin_data, &source.data()[insertion_pos], + ExtractionInfo::kUsedBufferSize); { rtc::CritScope crit(&lock_); // Will create new one if missed. @@ -69,15 +62,27 @@ EncodedImageExtractionResult SingleProcessEncodedImageDataInjector::ExtractData( uint8_t* buffer = out.data(); size_t size = out.size(); - // |pos| is pointing to end of current encoded image. - size_t pos = size - 1; + std::vector<size_t> frame_sizes; + std::vector<size_t> frame_sl_index; + size_t max_spatial_index = out.SpatialIndex().value_or(0); + for (size_t i = 0; i <= max_spatial_index; ++i) { + auto frame_size = source.SpatialLayerFrameSize(i); + if (frame_size.value_or(0)) { + frame_sl_index.push_back(i); + frame_sizes.push_back(frame_size.value()); + } + } + if (frame_sizes.empty()) { + frame_sizes.push_back(size); + } + + size_t prev_frames_size = 0; absl::optional<uint16_t> id = absl::nullopt; bool discard = true; std::vector<ExtractionInfo> extraction_infos; - // Go through whole buffer and find all related extraction infos in - // order from 1st encoded image to the last. - while (true) { - size_t insertion_pos = pos - kUsedBufferSize + 1; + for (size_t frame_size : frame_sizes) { + size_t insertion_pos = + prev_frames_size + frame_size - ExtractionInfo::kUsedBufferSize; // Extract frame id from first 2 bytes starting from insertion pos. uint16_t next_id = buffer[insertion_pos] + (buffer[insertion_pos + 1] << 8); // Extract frame sub id from second 3 byte starting from insertion pos. @@ -90,6 +95,8 @@ EncodedImageExtractionResult SingleProcessEncodedImageDataInjector::ExtractData( { rtc::CritScope crit(&lock_); auto ext_vector_it = extraction_cache_.find(next_id); + // TODO(titovartem) add support for receiving single frame multiple times + // when in simulcast key frame for another spatial stream can be received. RTC_CHECK(ext_vector_it != extraction_cache_.end()) << "Unknown frame_id=" << next_id; @@ -99,41 +106,45 @@ EncodedImageExtractionResult SingleProcessEncodedImageDataInjector::ExtractData( info = info_it->second; ext_vector_it->second.infos.erase(info_it); } - extraction_infos.push_back(info); // We need to discard encoded image only if all concatenated encoded images // have to be discarded. discard = discard && info.discard; - if (pos < info.length) { - break; - } - pos -= info.length; + + extraction_infos.push_back(info); + prev_frames_size += frame_size; } RTC_CHECK(id); - std::reverse(extraction_infos.begin(), extraction_infos.end()); + if (discard) { out.set_size(0); + for (size_t i = 0; i <= max_spatial_index; ++i) { + out.SetSpatialLayerFrameSize(i, 0); + } return EncodedImageExtractionResult{*id, out, true}; } // Make a pass from begin to end to restore origin payload and erase discarded // encoded images. - pos = 0; - auto extraction_infos_it = extraction_infos.begin(); - while (pos < size) { - RTC_DCHECK(extraction_infos_it != extraction_infos.end()); - const ExtractionInfo& info = *extraction_infos_it; + size_t pos = 0; + for (size_t frame_index = 0; frame_index < frame_sizes.size(); + ++frame_index) { + RTC_CHECK(pos < size); + const size_t frame_size = frame_sizes[frame_index]; + const ExtractionInfo& info = extraction_infos[frame_index]; if (info.discard) { // If this encoded image is marked to be discarded - erase it's payload // from the buffer. - memmove(&buffer[pos], &buffer[pos + info.length], - size - pos - info.length); - size -= info.length; + memmove(&buffer[pos], &buffer[pos + frame_size], size - pos - frame_size); + RTC_CHECK_LT(frame_index, frame_sl_index.size()) + << "codec doesn't support discard option or the image, that was " + "supposed to be discarded, is lost"; + out.SetSpatialLayerFrameSize(frame_sl_index[frame_index], 0); + size -= frame_size; } else { - memcpy(&buffer[pos + info.length - kUsedBufferSize], info.origin_data, - kUsedBufferSize); - pos += info.length; + memcpy(&buffer[pos + frame_size - ExtractionInfo::kUsedBufferSize], + info.origin_data, ExtractionInfo::kUsedBufferSize); + pos += frame_size; } - ++extraction_infos_it; } out.set_size(pos); diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h index 3787cc51aac..f79532e0961 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h @@ -57,15 +57,16 @@ class SingleProcessEncodedImageDataInjector : public EncodedImageDataInjector, // Contains data required to extract frame id from EncodedImage and restore // original buffer. struct ExtractionInfo { + // Number of bytes from the beginning of the EncodedImage buffer that will + // be used to store frame id and sub id. + const static size_t kUsedBufferSize = 3; // Frame sub id to distinguish encoded images for different spatial layers. uint8_t sub_id; - // Length of the origin buffer encoded image. - size_t length; // Flag to show is this encoded images should be discarded by analyzing // decoder because of not required spatial layer/simulcast stream. bool discard; // Data from first 3 bytes of origin encoded image's payload. - uint8_t origin_data[3]; + uint8_t origin_data[ExtractionInfo::kUsedBufferSize]; }; struct ExtractionInfoVector { diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc index 67cafa75a6d..e25361e337b 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc @@ -44,6 +44,7 @@ TEST(SingleProcessEncodedImageDataInjector, InjectExtractDiscardFalse) { EXPECT_FALSE(out.discard); EXPECT_EQ(out.image.size(), 10ul); EXPECT_EQ(out.image.capacity(), 10ul); + EXPECT_EQ(out.image.SpatialLayerFrameSize(0).value_or(0), 0ul); for (int i = 0; i < 10; ++i) { EXPECT_EQ(out.image.data()[i], i + 1); } @@ -63,6 +64,60 @@ TEST(SingleProcessEncodedImageDataInjector, InjectExtractDiscardTrue) { EXPECT_TRUE(out.discard); EXPECT_EQ(out.image.size(), 0ul); EXPECT_EQ(out.image.capacity(), 10ul); + EXPECT_EQ(out.image.SpatialLayerFrameSize(0).value_or(0), 0ul); +} + +TEST(SingleProcessEncodedImageDataInjector, InjectWithUnsetSpatialLayerSizes) { + SingleProcessEncodedImageDataInjector injector; + + rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); + + EncodedImage source(buffer.data(), 10, 10); + source.SetTimestamp(123456789); + + EncodedImage intermediate = injector.InjectData(512, false, source, 1); + intermediate.SetSpatialIndex(2); + + EncodedImageExtractionResult out = injector.ExtractData(intermediate, 2); + EXPECT_EQ(out.id, 512); + EXPECT_FALSE(out.discard); + EXPECT_EQ(out.image.size(), 10ul); + EXPECT_EQ(out.image.capacity(), 10ul); + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(out.image.data()[i], i + 1); + } + EXPECT_EQ(out.image.SpatialIndex().value_or(0), 2); + for (int i = 0; i < 3; ++i) { + EXPECT_EQ(out.image.SpatialLayerFrameSize(i).value_or(0), 0ul); + } +} + +TEST(SingleProcessEncodedImageDataInjector, InjectWithZeroSpatialLayerSizes) { + SingleProcessEncodedImageDataInjector injector; + + rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); + + EncodedImage source(buffer.data(), 10, 10); + source.SetTimestamp(123456789); + + EncodedImage intermediate = injector.InjectData(512, false, source, 1); + intermediate.SetSpatialIndex(2); + intermediate.SetSpatialLayerFrameSize(0, 0); + intermediate.SetSpatialLayerFrameSize(1, 0); + intermediate.SetSpatialLayerFrameSize(2, 0); + + EncodedImageExtractionResult out = injector.ExtractData(intermediate, 2); + EXPECT_EQ(out.id, 512); + EXPECT_FALSE(out.discard); + EXPECT_EQ(out.image.size(), 10ul); + EXPECT_EQ(out.image.capacity(), 10ul); + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(out.image.data()[i], i + 1); + } + EXPECT_EQ(out.image.SpatialIndex().value_or(0), 2); + for (int i = 0; i < 3; ++i) { + EXPECT_EQ(out.image.SpatialLayerFrameSize(i).value_or(0), 0ul); + } } TEST(SingleProcessEncodedImageDataInjector, Inject3Extract3) { @@ -95,6 +150,7 @@ TEST(SingleProcessEncodedImageDataInjector, Inject3Extract3) { EXPECT_FALSE(out1.discard); EXPECT_EQ(out1.image.size(), 10ul); EXPECT_EQ(out1.image.capacity(), 10ul); + EXPECT_EQ(out1.image.SpatialLayerFrameSize(0).value_or(0), 0ul); for (int i = 0; i < 10; ++i) { EXPECT_EQ(out1.image.data()[i], i + 1); } @@ -102,10 +158,12 @@ TEST(SingleProcessEncodedImageDataInjector, Inject3Extract3) { EXPECT_TRUE(out2.discard); EXPECT_EQ(out2.image.size(), 0ul); EXPECT_EQ(out2.image.capacity(), 10ul); + EXPECT_EQ(out2.image.SpatialLayerFrameSize(0).value_or(0), 0ul); EXPECT_EQ(out3.id, 520); EXPECT_FALSE(out3.discard); EXPECT_EQ(out3.image.size(), 10ul); EXPECT_EQ(out3.image.capacity(), 10ul); + EXPECT_EQ(out3.image.SpatialLayerFrameSize(0).value_or(0), 0ul); for (int i = 0; i < 10; ++i) { EXPECT_EQ(out3.image.data()[i], i + 21); } @@ -140,6 +198,10 @@ TEST(SingleProcessEncodedImageDataInjector, InjectExtractFromConcatenated) { concatenated_buffer.AppendData(intermediate3.data(), intermediate3.size()); EncodedImage concatenated(concatenated_buffer.data(), concatenated_length, concatenated_length); + concatenated.SetSpatialIndex(2); + concatenated.SetSpatialLayerFrameSize(0, intermediate1.size()); + concatenated.SetSpatialLayerFrameSize(1, intermediate2.size()); + concatenated.SetSpatialLayerFrameSize(2, intermediate3.size()); // Extract frame id from concatenated image EncodedImageExtractionResult out = injector.ExtractData(concatenated, 2); @@ -152,6 +214,10 @@ TEST(SingleProcessEncodedImageDataInjector, InjectExtractFromConcatenated) { EXPECT_EQ(out.image.data()[i], i + 1); EXPECT_EQ(out.image.data()[i + 10], i + 21); } + EXPECT_EQ(out.image.SpatialIndex().value_or(0), 2); + EXPECT_EQ(out.image.SpatialLayerFrameSize(0).value_or(0), 10ul); + EXPECT_EQ(out.image.SpatialLayerFrameSize(1).value_or(0), 0ul); + EXPECT_EQ(out.image.SpatialLayerFrameSize(2).value_or(0), 10ul); } TEST(SingleProcessEncodedImageDataInjector, @@ -184,6 +250,10 @@ TEST(SingleProcessEncodedImageDataInjector, concatenated_buffer.AppendData(intermediate3.data(), intermediate3.size()); EncodedImage concatenated(concatenated_buffer.data(), concatenated_length, concatenated_length); + concatenated.SetSpatialIndex(2); + concatenated.SetSpatialLayerFrameSize(0, intermediate1.size()); + concatenated.SetSpatialLayerFrameSize(1, intermediate2.size()); + concatenated.SetSpatialLayerFrameSize(2, intermediate3.size()); // Extract frame id from concatenated image EncodedImageExtractionResult out = injector.ExtractData(concatenated, 2); @@ -192,6 +262,10 @@ TEST(SingleProcessEncodedImageDataInjector, EXPECT_TRUE(out.discard); EXPECT_EQ(out.image.size(), 0ul); EXPECT_EQ(out.image.capacity(), 3 * 10ul); + EXPECT_EQ(out.image.SpatialIndex().value_or(0), 2); + for (int i = 0; i < 3; ++i) { + EXPECT_EQ(out.image.SpatialLayerFrameSize(i).value_or(0), 0ul); + } } } // namespace webrtc_pc_e2e diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc index 074188439b3..19487778485 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc @@ -14,6 +14,8 @@ #include <vector> #include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "api/array_view.h" #include "test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h" #include "test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.h" #include "test/pc/e2e/analyzer/video/simulcast_dummy_buffer_helper.h" @@ -43,10 +45,12 @@ class AnalyzingFramePreprocessor : public test::TestVideoCapturer::FramePreprocessor { public: AnalyzingFramePreprocessor( - std::string stream_label, + absl::string_view peer_name, + absl::string_view stream_label, VideoQualityAnalyzerInterface* analyzer, std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks) - : stream_label_(std::move(stream_label)), + : peer_name_(peer_name), + stream_label_(stream_label), analyzer_(analyzer), sinks_(std::move(sinks)) {} ~AnalyzingFramePreprocessor() override = default; @@ -54,7 +58,8 @@ class AnalyzingFramePreprocessor VideoFrame Preprocess(const VideoFrame& source_frame) override { // Copy VideoFrame to be able to set id on it. VideoFrame frame = source_frame; - uint16_t frame_id = analyzer_->OnFrameCaptured(stream_label_, frame); + uint16_t frame_id = + analyzer_->OnFrameCaptured(peer_name_, stream_label_, frame); frame.set_id(frame_id); for (auto& sink : sinks_) { @@ -64,6 +69,7 @@ class AnalyzingFramePreprocessor } private: + const std::string peer_name_; const std::string stream_label_; VideoQualityAnalyzerInterface* const analyzer_; const std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> @@ -88,26 +94,29 @@ VideoQualityAnalyzerInjectionHelper::~VideoQualityAnalyzerInjectionHelper() = std::unique_ptr<VideoEncoderFactory> VideoQualityAnalyzerInjectionHelper::WrapVideoEncoderFactory( + absl::string_view peer_name, std::unique_ptr<VideoEncoderFactory> delegate, double bitrate_multiplier, std::map<std::string, absl::optional<int>> stream_required_spatial_index) const { return std::make_unique<QualityAnalyzingVideoEncoderFactory>( - std::move(delegate), bitrate_multiplier, + peer_name, std::move(delegate), bitrate_multiplier, std::move(stream_required_spatial_index), encoding_entities_id_generator_.get(), injector_, analyzer_.get()); } std::unique_ptr<VideoDecoderFactory> VideoQualityAnalyzerInjectionHelper::WrapVideoDecoderFactory( + absl::string_view peer_name, std::unique_ptr<VideoDecoderFactory> delegate) const { return std::make_unique<QualityAnalyzingVideoDecoderFactory>( - std::move(delegate), encoding_entities_id_generator_.get(), extractor_, - analyzer_.get()); + peer_name, std::move(delegate), encoding_entities_id_generator_.get(), + extractor_, analyzer_.get()); } std::unique_ptr<test::TestVideoCapturer::FramePreprocessor> VideoQualityAnalyzerInjectionHelper::CreateFramePreprocessor( + absl::string_view peer_name, const VideoConfig& config) { std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks; test::VideoFrameWriter* writer = @@ -125,23 +134,27 @@ VideoQualityAnalyzerInjectionHelper::CreateFramePreprocessor( known_video_configs_.insert({*config.stream_label, config}); } return std::make_unique<AnalyzingFramePreprocessor>( - std::move(*config.stream_label), analyzer_.get(), std::move(sinks)); + peer_name, std::move(*config.stream_label), analyzer_.get(), + std::move(sinks)); } std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> -VideoQualityAnalyzerInjectionHelper::CreateVideoSink() { - return std::make_unique<AnalyzingVideoSink>(this); +VideoQualityAnalyzerInjectionHelper::CreateVideoSink( + absl::string_view peer_name) { + return std::make_unique<AnalyzingVideoSink>(peer_name, this); } -void VideoQualityAnalyzerInjectionHelper::Start(std::string test_case_name, - int max_threads_count) { - analyzer_->Start(std::move(test_case_name), max_threads_count); +void VideoQualityAnalyzerInjectionHelper::Start( + std::string test_case_name, + rtc::ArrayView<const std::string> peer_names, + int max_threads_count) { + analyzer_->Start(std::move(test_case_name), peer_names, max_threads_count); } void VideoQualityAnalyzerInjectionHelper::OnStatsReports( - const std::string& pc_label, - const StatsReports& stats_reports) { - analyzer_->OnStatsReports(pc_label, stats_reports); + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) { + analyzer_->OnStatsReports(pc_label, report); } void VideoQualityAnalyzerInjectionHelper::Stop() { @@ -169,12 +182,13 @@ VideoQualityAnalyzerInjectionHelper::MaybeCreateVideoWriter( return out; } -void VideoQualityAnalyzerInjectionHelper::OnFrame(const VideoFrame& frame) { +void VideoQualityAnalyzerInjectionHelper::OnFrame(absl::string_view peer_name, + const VideoFrame& frame) { if (IsDummyFrameBuffer(frame.video_frame_buffer()->ToI420())) { // This is dummy frame, so we don't need to process it further. return; } - analyzer_->OnFrameRendered(frame); + analyzer_->OnFrameRendered(peer_name, frame); std::string stream_label = analyzer_->GetStreamLabel(frame.id()); std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>>* sinks = PopulateSinks(stream_label); diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h index a0daa9ff18a..ca5243484d4 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h @@ -14,7 +14,10 @@ #include <map> #include <memory> #include <string> +#include <vector> +#include "absl/strings/string_view.h" +#include "api/array_view.h" #include "api/test/peerconnection_quality_test_fixture.h" #include "api/test/stats_observer_interface.h" #include "api/test/video_quality_analyzer_interface.h" @@ -46,6 +49,7 @@ class VideoQualityAnalyzerInjectionHelper : public StatsObserverInterface { // Wraps video encoder factory to give video quality analyzer access to frames // before encoding and encoded images after. std::unique_ptr<VideoEncoderFactory> WrapVideoEncoderFactory( + absl::string_view peer_name, std::unique_ptr<VideoEncoderFactory> delegate, double bitrate_multiplier, std::map<std::string, absl::optional<int>> stream_required_spatial_index) @@ -53,25 +57,31 @@ class VideoQualityAnalyzerInjectionHelper : public StatsObserverInterface { // Wraps video decoder factory to give video quality analyzer access to // received encoded images and frames, that were decoded from them. std::unique_ptr<VideoDecoderFactory> WrapVideoDecoderFactory( + absl::string_view peer_name, std::unique_ptr<VideoDecoderFactory> delegate) const; // Creates VideoFrame preprocessor, that will allow video quality analyzer to // get access to the captured frames. If provided config also specifies // |input_dump_file_name|, video will be written into that file. std::unique_ptr<test::TestVideoCapturer::FramePreprocessor> - CreateFramePreprocessor(const VideoConfig& config); + CreateFramePreprocessor(absl::string_view peer_name, + const VideoConfig& config); // Creates sink, that will allow video quality analyzer to get access to // the rendered frames. If corresponding video track has // |output_dump_file_name| in its VideoConfig, then video also will be written // into that file. - std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> CreateVideoSink(); + std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> CreateVideoSink( + absl::string_view peer_name); - void Start(std::string test_case_name, int max_threads_count); + void Start(std::string test_case_name, + rtc::ArrayView<const std::string> peer_names, + int max_threads_count); // Forwards |stats_reports| for Peer Connection |pc_label| to // |analyzer_|. - void OnStatsReports(const std::string& pc_label, - const StatsReports& stats_reports) override; + void OnStatsReports( + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) override; // Stops VideoQualityAnalyzerInterface to populate final data and metrics. // Should be invoked after analyzed video tracks are disposed. @@ -80,20 +90,24 @@ class VideoQualityAnalyzerInjectionHelper : public StatsObserverInterface { private: class AnalyzingVideoSink final : public rtc::VideoSinkInterface<VideoFrame> { public: - explicit AnalyzingVideoSink(VideoQualityAnalyzerInjectionHelper* helper) - : helper_(helper) {} + explicit AnalyzingVideoSink(absl::string_view peer_name, + VideoQualityAnalyzerInjectionHelper* helper) + : peer_name_(peer_name), helper_(helper) {} ~AnalyzingVideoSink() override = default; - void OnFrame(const VideoFrame& frame) override { helper_->OnFrame(frame); } + void OnFrame(const VideoFrame& frame) override { + helper_->OnFrame(peer_name_, frame); + } private: + const std::string peer_name_; VideoQualityAnalyzerInjectionHelper* const helper_; }; test::VideoFrameWriter* MaybeCreateVideoWriter( absl::optional<std::string> file_name, const PeerConnectionE2EQualityTestFixture::VideoConfig& config); - void OnFrame(const VideoFrame& frame); + void OnFrame(absl::string_view peer_name, const VideoFrame& frame); std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>>* PopulateSinks(const std::string& stream_label); diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.cc b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.cc index 754a0a468fe..baf973f2770 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.cc @@ -10,51 +10,88 @@ #include "test/pc/e2e/analyzer/video/video_quality_metrics_reporter.h" +#include "api/stats/rtc_stats.h" +#include "api/stats/rtcstats_objects.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" + namespace webrtc { namespace webrtc_pc_e2e { -namespace { - -constexpr int kBitsInByte = 8; - -} // namespace void VideoQualityMetricsReporter::Start(absl::string_view test_case_name) { test_case_name_ = std::string(test_case_name); + start_time_ = Now(); } -// TODO(bugs.webrtc.org/10430): Migrate to the new GetStats as soon as -// bugs.webrtc.org/10428 is fixed. void VideoQualityMetricsReporter::OnStatsReports( - const std::string& pc_label, - const StatsReports& stats_reports) { - for (const StatsReport* stats_report : stats_reports) { - // The only stats collected by this analyzer are present in - // kStatsReportTypeBwe reports, so all other reports are just ignored. - if (stats_report->type() != StatsReport::StatsType::kStatsReportTypeBwe) { + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) { + RTC_CHECK(start_time_) + << "Please invoke Start(...) method before calling OnStatsReports(...)"; + + auto transport_stats = report->GetStatsOfType<RTCTransportStats>(); + if (transport_stats.size() == 0u || + !transport_stats[0]->selected_candidate_pair_id.is_defined()) { + return; + } + RTC_DCHECK_EQ(transport_stats.size(), 1); + std::string selected_ice_id = + transport_stats[0]->selected_candidate_pair_id.ValueToString(); + // Use the selected ICE candidate pair ID to get the appropriate ICE stats. + const RTCIceCandidatePairStats ice_candidate_pair_stats = + report->Get(selected_ice_id)->cast_to<const RTCIceCandidatePairStats>(); + + auto outbound_rtp_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>(); + StatsSample sample; + for (auto& s : outbound_rtp_stats) { + if (!s->media_type.is_defined()) { + continue; + } + if (!(*s->media_type == RTCMediaStreamTrackKind::kVideo)) { continue; } - const webrtc::StatsReport::Value* available_send_bandwidth = - stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNameAvailableSendBandwidth); - const webrtc::StatsReport::Value* retransmission_bitrate = - stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNameRetransmitBitrate); - const webrtc::StatsReport::Value* transmission_bitrate = - stats_report->FindValue( - StatsReport::StatsValueName::kStatsValueNameTransmitBitrate); - RTC_CHECK(available_send_bandwidth); - RTC_CHECK(retransmission_bitrate); - RTC_CHECK(transmission_bitrate); - - rtc::CritScope crit(&video_bwe_stats_lock_); - VideoBweStats& video_bwe_stats = video_bwe_stats_[pc_label]; + if (s->timestamp_us() > sample.sample_time.us()) { + sample.sample_time = Timestamp::Micros(s->timestamp_us()); + } + sample.retransmitted_bytes_sent += + DataSize::Bytes(s->retransmitted_bytes_sent.ValueOrDefault(0ul)); + sample.bytes_sent += DataSize::Bytes(s->bytes_sent.ValueOrDefault(0ul)); + sample.header_bytes_sent += + DataSize::Bytes(s->header_bytes_sent.ValueOrDefault(0ul)); + } + + rtc::CritScope crit(&video_bwe_stats_lock_); + VideoBweStats& video_bwe_stats = video_bwe_stats_[std::string(pc_label)]; + if (ice_candidate_pair_stats.available_outgoing_bitrate.is_defined()) { video_bwe_stats.available_send_bandwidth.AddSample( - available_send_bandwidth->int_val()); - video_bwe_stats.transmission_bitrate.AddSample( - transmission_bitrate->int_val()); - video_bwe_stats.retransmission_bitrate.AddSample( - retransmission_bitrate->int_val()); + DataRate::BitsPerSec( + *ice_candidate_pair_stats.available_outgoing_bitrate) + .bytes_per_sec()); + } + + StatsSample prev_sample = last_stats_sample_[std::string(pc_label)]; + if (prev_sample.sample_time.IsZero()) { + prev_sample.sample_time = start_time_.value(); + } + last_stats_sample_[std::string(pc_label)] = sample; + + TimeDelta time_between_samples = sample.sample_time - prev_sample.sample_time; + if (time_between_samples.IsZero()) { + return; } + + DataRate retransmission_bitrate = + (sample.retransmitted_bytes_sent - prev_sample.retransmitted_bytes_sent) / + time_between_samples; + video_bwe_stats.retransmission_bitrate.AddSample( + retransmission_bitrate.bytes_per_sec()); + DataRate transmission_bitrate = + (sample.bytes_sent + sample.header_bytes_sent - prev_sample.bytes_sent - + prev_sample.header_bytes_sent) / + time_between_samples; + video_bwe_stats.transmission_bitrate.AddSample( + transmission_bitrate.bytes_per_sec()); } void VideoQualityMetricsReporter::StopAndReportResults() { @@ -73,14 +110,11 @@ void VideoQualityMetricsReporter::ReportVideoBweResults( const std::string& test_case_name, const VideoBweStats& video_bwe_stats) { ReportResult("available_send_bandwidth", test_case_name, - video_bwe_stats.available_send_bandwidth / kBitsInByte, - "bytesPerSecond"); + video_bwe_stats.available_send_bandwidth, "bytesPerSecond"); ReportResult("transmission_bitrate", test_case_name, - video_bwe_stats.transmission_bitrate / kBitsInByte, - "bytesPerSecond"); + video_bwe_stats.transmission_bitrate, "bytesPerSecond"); ReportResult("retransmission_bitrate", test_case_name, - video_bwe_stats.retransmission_bitrate / kBitsInByte, - "bytesPerSecond"); + video_bwe_stats.retransmission_bitrate, "bytesPerSecond"); } void VideoQualityMetricsReporter::ReportResult( diff --git a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.h b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.h index 1688a7b6fcf..a6ac9b4fa18 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.h +++ b/chromium/third_party/webrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.h @@ -15,6 +15,8 @@ #include <string> #include "api/test/peerconnection_quality_test_fixture.h" +#include "api/units/data_size.h" +#include "api/units/timestamp.h" #include "rtc_base/critical_section.h" #include "rtc_base/numerics/samples_stats_counter.h" #include "test/testsupport/perf_test.h" @@ -31,15 +33,24 @@ struct VideoBweStats { class VideoQualityMetricsReporter : public PeerConnectionE2EQualityTestFixture::QualityMetricsReporter { public: - VideoQualityMetricsReporter() = default; + VideoQualityMetricsReporter(Clock* const clock) : clock_(clock) {} ~VideoQualityMetricsReporter() override = default; void Start(absl::string_view test_case_name) override; - void OnStatsReports(const std::string& pc_label, - const StatsReports& reports) override; + void OnStatsReports( + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) override; void StopAndReportResults() override; private: + struct StatsSample { + DataSize bytes_sent = DataSize::Zero(); + DataSize header_bytes_sent = DataSize::Zero(); + DataSize retransmitted_bytes_sent = DataSize::Zero(); + + Timestamp sample_time = Timestamp::Zero(); + }; + std::string GetTestCaseName(const std::string& stream_label) const; static void ReportVideoBweResults(const std::string& test_case_name, const VideoBweStats& video_bwe_stats); @@ -50,14 +61,20 @@ class VideoQualityMetricsReporter const std::string& unit, webrtc::test::ImproveDirection improve_direction = webrtc::test::ImproveDirection::kNone); + Timestamp Now() const { return clock_->CurrentTime(); } + + Clock* const clock_; std::string test_case_name_; + absl::optional<Timestamp> start_time_; rtc::CriticalSection video_bwe_stats_lock_; // Map between a peer connection label (provided by the framework) and // its video BWE stats. std::map<std::string, VideoBweStats> video_bwe_stats_ RTC_GUARDED_BY(video_bwe_stats_lock_); + std::map<std::string, StatsSample> last_stats_sample_ + RTC_GUARDED_BY(video_bwe_stats_lock_); }; } // namespace webrtc_pc_e2e diff --git a/chromium/third_party/webrtc/test/pc/e2e/echo/echo_emulation.cc b/chromium/third_party/webrtc/test/pc/e2e/echo/echo_emulation.cc index 2beaa34cbd8..230e8e3eca9 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/echo/echo_emulation.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/echo/echo_emulation.cc @@ -57,17 +57,7 @@ void EchoEmulatingCapturer::OnAudioRendered( } queue_input_.assign(data.begin(), data.end()); if (!renderer_queue_.Insert(&queue_input_)) { - // Test audio device works too slow with sanitizers and on some platforms - // and can't properly process audio, so when capturer will be stopped - // renderer will quickly overfill the queue. - // TODO(crbug.com/webrtc/10850) remove it when test ADM will be fast enough. -#if defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER) || \ - defined(ADDRESS_SANITIZER) || defined(WEBRTC_ANDROID) || \ - (defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)) RTC_LOG(WARNING) << "Echo queue is full"; -#else - RTC_CHECK(false) << "Echo queue is full"; -#endif } } diff --git a/chromium/third_party/webrtc/test/pc/e2e/media/media_helper.cc b/chromium/third_party/webrtc/test/pc/e2e/media/media_helper.cc index d3fa6ffe039..d1c27838a6e 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/media/media_helper.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/media/media_helper.cc @@ -58,7 +58,7 @@ MediaHelper::MaybeAddVideo(TestPeer* peer) { std::unique_ptr<test::TestVideoCapturer> capturer = CreateVideoCapturer( video_config, peer->ReleaseVideoSource(i), video_quality_analyzer_injection_helper_->CreateFramePreprocessor( - video_config)); + params->name.value(), video_config)); bool is_screencast = video_config.content_hint == VideoTrackInterface::ContentHint::kText || video_config.content_hint == diff --git a/chromium/third_party/webrtc/test/pc/e2e/network_quality_metrics_reporter.cc b/chromium/third_party/webrtc/test/pc/e2e/network_quality_metrics_reporter.cc index 56f0337037c..3b232fdc710 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/network_quality_metrics_reporter.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/network_quality_metrics_reporter.cc @@ -11,7 +11,8 @@ #include <utility> -#include "api/stats_types.h" +#include "api/stats/rtc_stats.h" +#include "api/stats/rtcstats_objects.h" #include "rtc_base/event.h" #include "system_wrappers/include/field_trial.h" #include "test/testsupport/perf_test.h" @@ -40,28 +41,29 @@ void NetworkQualityMetricsReporter::Start(absl::string_view test_case_name) { } void NetworkQualityMetricsReporter::OnStatsReports( - const std::string& pc_label, - const StatsReports& reports) { - rtc::CritScope cs(&lock_); - int64_t payload_bytes_received = 0; - int64_t payload_bytes_sent = 0; - for (const StatsReport* report : reports) { - if (report->type() == StatsReport::kStatsReportTypeSsrc) { - const auto* received = - report->FindValue(StatsReport::kStatsValueNameBytesReceived); - if (received) { - payload_bytes_received += received->int64_val(); - } - const auto* sent = - report->FindValue(StatsReport::kStatsValueNameBytesSent); - if (sent) { - payload_bytes_sent += sent->int64_val(); - } - } + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) { + DataSize payload_received = DataSize::Zero(); + DataSize payload_sent = DataSize::Zero(); + + auto inbound_stats = report->GetStatsOfType<RTCInboundRTPStreamStats>(); + for (const auto& stat : inbound_stats) { + payload_received += + DataSize::Bytes(stat->bytes_received.ValueOrDefault(0ul) + + stat->header_bytes_received.ValueOrDefault(0ul)); + } + + auto outbound_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>(); + for (const auto& stat : outbound_stats) { + payload_sent += + DataSize::Bytes(stat->bytes_sent.ValueOrDefault(0ul) + + stat->header_bytes_sent.ValueOrDefault(0ul)); } - PCStats& stats = pc_stats_[pc_label]; - stats.payload_bytes_received = payload_bytes_received; - stats.payload_bytes_sent = payload_bytes_sent; + + rtc::CritScope cs(&lock_); + PCStats& stats = pc_stats_[std::string(pc_label)]; + stats.payload_received = payload_received; + stats.payload_sent = payload_sent; } void NetworkQualityMetricsReporter::StopAndReportResults() { @@ -125,9 +127,9 @@ void NetworkQualityMetricsReporter::ReportStats( void NetworkQualityMetricsReporter::ReportPCStats(const std::string& pc_label, const PCStats& stats) { - ReportResult("payload_bytes_received", pc_label, stats.payload_bytes_received, - "sizeInBytes"); - ReportResult("payload_bytes_sent", pc_label, stats.payload_bytes_sent, + ReportResult("payload_bytes_received", pc_label, + stats.payload_received.bytes(), "sizeInBytes"); + ReportResult("payload_bytes_sent", pc_label, stats.payload_sent.bytes(), "sizeInBytes"); } diff --git a/chromium/third_party/webrtc/test/pc/e2e/network_quality_metrics_reporter.h b/chromium/third_party/webrtc/test/pc/e2e/network_quality_metrics_reporter.h index 6454f175260..932e03140be 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/network_quality_metrics_reporter.h +++ b/chromium/third_party/webrtc/test/pc/e2e/network_quality_metrics_reporter.h @@ -15,6 +15,7 @@ #include "api/test/network_emulation_manager.h" #include "api/test/peerconnection_quality_test_fixture.h" +#include "api/units/data_size.h" #include "rtc_base/critical_section.h" namespace webrtc { @@ -30,16 +31,17 @@ class NetworkQualityMetricsReporter // Network stats must be empty when this method will be invoked. void Start(absl::string_view test_case_name) override; - void OnStatsReports(const std::string& pc_label, - const StatsReports& reports) override; + void OnStatsReports( + absl::string_view pc_label, + const rtc::scoped_refptr<const RTCStatsReport>& report) override; void StopAndReportResults() override; private: struct PCStats { // TODO(nisse): Separate audio and video counters. Depends on standard stat // counters, enabled by field trial "WebRTC-UseStandardBytesStats". - int64_t payload_bytes_received = 0; - int64_t payload_bytes_sent = 0; + DataSize payload_received = DataSize::Zero(); + DataSize payload_sent = DataSize::Zero(); }; static EmulatedNetworkStats PopulateStats( diff --git a/chromium/third_party/webrtc/test/pc/e2e/peer_configurer.h b/chromium/third_party/webrtc/test/pc/e2e/peer_configurer.h index 010ddcee82c..7da547bdc31 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/peer_configurer.h +++ b/chromium/third_party/webrtc/test/pc/e2e/peer_configurer.h @@ -23,7 +23,6 @@ #include "api/task_queue/task_queue_factory.h" #include "api/test/create_peer_connection_quality_test_frame_generator.h" #include "api/test/peerconnection_quality_test_fixture.h" -#include "api/transport/media/media_transport_interface.h" #include "api/transport/network_control.h" #include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_encoder_factory.h" @@ -86,12 +85,6 @@ class PeerConfigurerImpl final std::move(network_controller_factory); return this; } - PeerConfigurer* SetMediaTransportFactory( - std::unique_ptr<MediaTransportFactory> media_transport_factory) override { - components_->pcf_dependencies->media_transport_factory = - std::move(media_transport_factory); - return this; - } PeerConfigurer* SetVideoEncoderFactory( std::unique_ptr<VideoEncoderFactory> video_encoder_factory) override { components_->pcf_dependencies->video_encoder_factory = @@ -172,7 +165,15 @@ class PeerConfigurerImpl final } PeerConfigurer* SetBitrateParameters( PeerConnectionInterface::BitrateParameters bitrate_params) override { - params_->bitrate_params = bitrate_params; + BitrateSettings bitrate_settings; + bitrate_settings.min_bitrate_bps = bitrate_params.min_bitrate_bps; + bitrate_settings.start_bitrate_bps = bitrate_params.current_bitrate_bps; + bitrate_settings.max_bitrate_bps = bitrate_params.max_bitrate_bps; + return SetBitrateSettings(bitrate_settings); + } + PeerConfigurer* SetBitrateSettings( + BitrateSettings bitrate_settings) override { + params_->bitrate_settings = bitrate_settings; return this; } diff --git a/chromium/third_party/webrtc/test/pc/e2e/peer_connection_e2e_smoke_test.cc b/chromium/third_party/webrtc/test/pc/e2e/peer_connection_e2e_smoke_test.cc index 8080d4bb0a5..ab6aaa07313 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/peer_connection_e2e_smoke_test.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/peer_connection_e2e_smoke_test.cc @@ -83,7 +83,7 @@ class PeerConnectionE2EQualityTestSmokeTest : public ::testing::Test { auto fixture = CreatePeerConnectionE2EQualityTestFixture( test_case_name, /*audio_quality_analyzer=*/nullptr, std::move(video_quality_analyzer)); - fixture->ExecuteAt(TimeDelta::Seconds(2), + fixture->ExecuteAt(TimeDelta::Seconds(1), [alice_network_behavior_ptr](TimeDelta) { BuiltInNetworkBehaviorConfig config; config.loss_percent = 5; @@ -110,19 +110,20 @@ class PeerConnectionE2EQualityTestSmokeTest : public ::testing::Test { fixture->Run(run_params); EXPECT_GE(fixture->GetRealTestDuration(), run_params.run_duration); - for (auto stream_label : video_analyzer_ptr->GetKnownVideoStreams()) { + for (auto stream_key : video_analyzer_ptr->GetKnownVideoStreams()) { FrameCounters stream_conters = - video_analyzer_ptr->GetPerStreamCounters().at(stream_label); + video_analyzer_ptr->GetPerStreamCounters().at(stream_key); // On some devices the pipeline can be too slow, so we actually can't // force real constraints here. Lets just check, that at least 1 // frame passed whole pipeline. - int64_t expected_min_fps = run_params.run_duration.seconds() * 30; - EXPECT_GE(stream_conters.captured, expected_min_fps); - EXPECT_GE(stream_conters.pre_encoded, 1); - EXPECT_GE(stream_conters.encoded, 1); - EXPECT_GE(stream_conters.received, 1); - EXPECT_GE(stream_conters.decoded, 1); - EXPECT_GE(stream_conters.rendered, 1); + int64_t expected_min_fps = run_params.run_duration.seconds() * 15; + EXPECT_GE(stream_conters.captured, expected_min_fps) + << stream_key.ToString(); + EXPECT_GE(stream_conters.pre_encoded, 1) << stream_key.ToString(); + EXPECT_GE(stream_conters.encoded, 1) << stream_key.ToString(); + EXPECT_GE(stream_conters.received, 1) << stream_key.ToString(); + EXPECT_GE(stream_conters.decoded, 1) << stream_key.ToString(); + EXPECT_GE(stream_conters.rendered, 1) << stream_key.ToString(); } } }; @@ -148,7 +149,7 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_Smoke) { RunTest( "smoke", run_params, [](PeerConfigurer* alice) { - VideoConfig video(640, 360, 30); + VideoConfig video(160, 120, 15); video.stream_label = "alice-video"; video.sync_group = "alice-media"; alice->AddVideoConfig(std::move(video)); @@ -164,23 +165,11 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_Smoke) { }, [](PeerConfigurer* charlie) { charlie->SetName("charlie"); - VideoConfig video(640, 360, 30); + VideoConfig video(160, 120, 15); video.stream_label = "charlie-video"; video.temporal_layers_count = 2; charlie->AddVideoConfig(std::move(video)); - VideoConfig screenshare(640, 360, 30); - screenshare.stream_label = "charlie-screenshare"; - screenshare.content_hint = VideoTrackInterface::ContentHint::kText; - ScreenShareConfig screen_share_config = - ScreenShareConfig(TimeDelta::Seconds(2)); - screen_share_config.scrolling_params = ScrollingParams( - TimeDelta::Millis(1800), kDefaultSlidesWidth, kDefaultSlidesHeight); - auto screen_share_frame_generator = - CreateScreenShareFrameGenerator(screenshare, screen_share_config); - charlie->AddVideoConfig(std::move(screenshare), - std::move(screen_share_frame_generator)); - AudioConfig audio; audio.stream_label = "charlie-audio"; audio.mode = AudioConfig::Mode::kFile; @@ -192,6 +181,35 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_Smoke) { // IOS debug builds can be quite slow, disabling to avoid issues with timeouts. #if defined(WEBRTC_IOS) && defined(WEBRTC_ARCH_ARM64) && !defined(NDEBUG) +#define MAYBE_Screenshare DISABLED_Screenshare +#else +#define MAYBE_Screenshare Screenshare +#endif +TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_Screenshare) { + RunParams run_params(TimeDelta::Seconds(2)); + test::ScopedFieldTrials field_trials( + std::string(field_trial::GetFieldTrialString()) + + "WebRTC-UseStandardBytesStats/Enabled/"); + RunTest( + "screenshare", run_params, + [](PeerConfigurer* alice) { + VideoConfig screenshare(320, 180, 30); + screenshare.stream_label = "alice-screenshare"; + screenshare.content_hint = VideoTrackInterface::ContentHint::kText; + ScreenShareConfig screen_share_config = + ScreenShareConfig(TimeDelta::Seconds(2)); + screen_share_config.scrolling_params = ScrollingParams( + TimeDelta::Millis(1800), kDefaultSlidesWidth, kDefaultSlidesHeight); + auto screen_share_frame_generator = + CreateScreenShareFrameGenerator(screenshare, screen_share_config); + alice->AddVideoConfig(std::move(screenshare), + std::move(screen_share_frame_generator)); + }, + [](PeerConfigurer* charlie) {}); +} + +// IOS debug builds can be quite slow, disabling to avoid issues with timeouts. +#if defined(WEBRTC_IOS) && defined(WEBRTC_ARCH_ARM64) && !defined(NDEBUG) #define MAYBE_Echo DISABLED_Echo #else #define MAYBE_Echo Echo @@ -232,9 +250,9 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_Simulcast) { RunTest( "simulcast", run_params, [](PeerConfigurer* alice) { - VideoConfig simulcast(1280, 720, 30); + VideoConfig simulcast(1280, 720, 15); simulcast.stream_label = "alice-simulcast"; - simulcast.simulcast_config = VideoSimulcastConfig(3, 0); + simulcast.simulcast_config = VideoSimulcastConfig(2, 0); alice->AddVideoConfig(std::move(simulcast)); AudioConfig audio; @@ -244,18 +262,7 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_Simulcast) { test::ResourcePath("pc_quality_smoke_test_alice_source", "wav"); alice->SetAudioConfig(std::move(audio)); }, - [](PeerConfigurer* bob) { - VideoConfig video(640, 360, 30); - video.stream_label = "bob-video"; - bob->AddVideoConfig(std::move(video)); - - AudioConfig audio; - audio.stream_label = "bob-audio"; - audio.mode = AudioConfig::Mode::kFile; - audio.input_file_name = - test::ResourcePath("pc_quality_smoke_test_bob_source", "wav"); - bob->SetAudioConfig(std::move(audio)); - }); + [](PeerConfigurer* bob) {}); } // IOS debug builds can be quite slow, disabling to avoid issues with timeouts. @@ -270,11 +277,11 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_Svc) { RunTest( "simulcast", run_params, [](PeerConfigurer* alice) { - VideoConfig simulcast(1280, 720, 30); + VideoConfig simulcast(1280, 720, 15); simulcast.stream_label = "alice-svc"; // Because we have network with packets loss we can analyze only the // highest spatial layer in SVC mode. - simulcast.simulcast_config = VideoSimulcastConfig(3, 2); + simulcast.simulcast_config = VideoSimulcastConfig(2, 1); alice->AddVideoConfig(std::move(simulcast)); AudioConfig audio; @@ -284,18 +291,7 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_Svc) { test::ResourcePath("pc_quality_smoke_test_alice_source", "wav"); alice->SetAudioConfig(std::move(audio)); }, - [](PeerConfigurer* bob) { - VideoConfig video(640, 360, 30); - video.stream_label = "bob-video"; - bob->AddVideoConfig(std::move(video)); - - AudioConfig audio; - audio.stream_label = "bob-audio"; - audio.mode = AudioConfig::Mode::kFile; - audio.input_file_name = - test::ResourcePath("pc_quality_smoke_test_bob_source", "wav"); - bob->SetAudioConfig(std::move(audio)); - }); + [](PeerConfigurer* bob) {}); } // IOS debug builds can be quite slow, disabling to avoid issues with timeouts. @@ -312,11 +308,11 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_HighBitrate) { RunTest( "smoke", run_params, [](PeerConfigurer* alice) { - PeerConnectionInterface::BitrateParameters bitrate_params; - bitrate_params.current_bitrate_bps = 3'000'000; - bitrate_params.max_bitrate_bps = 3'000'000; - alice->SetBitrateParameters(bitrate_params); - VideoConfig video(800, 600, 30); + BitrateSettings bitrate_settings; + bitrate_settings.start_bitrate_bps = 3'000'000; + bitrate_settings.max_bitrate_bps = 3'000'000; + alice->SetBitrateSettings(bitrate_settings); + VideoConfig video(800, 600, 15); video.stream_label = "alice-video"; video.min_encode_bitrate_bps = 500'000; video.max_encode_bitrate_bps = 3'000'000; @@ -330,24 +326,7 @@ TEST_F(PeerConnectionE2EQualityTestSmokeTest, MAYBE_HighBitrate) { audio.sampling_frequency_in_hz = 48000; alice->SetAudioConfig(std::move(audio)); }, - [](PeerConfigurer* bob) { - PeerConnectionInterface::BitrateParameters bitrate_params; - bitrate_params.current_bitrate_bps = 3'000'000; - bitrate_params.max_bitrate_bps = 3'000'000; - bob->SetBitrateParameters(bitrate_params); - VideoConfig video(800, 600, 30); - video.stream_label = "bob-video"; - video.min_encode_bitrate_bps = 500'000; - video.max_encode_bitrate_bps = 3'000'000; - bob->AddVideoConfig(std::move(video)); - - AudioConfig audio; - audio.stream_label = "bob-audio"; - audio.mode = AudioConfig::Mode::kFile; - audio.input_file_name = - test::ResourcePath("pc_quality_smoke_test_bob_source", "wav"); - bob->SetAudioConfig(std::move(audio)); - }); + [](PeerConfigurer* bob) {}); } } // namespace webrtc_pc_e2e diff --git a/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test.cc b/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test.cc index 17104a90aa2..a23d2248f3c 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test.cc @@ -14,6 +14,7 @@ #include <set> #include <utility> +#include "absl/strings/string_view.h" #include "api/jsep.h" #include "api/media_stream_interface.h" #include "api/peer_connection_interface.h" @@ -205,18 +206,21 @@ void PeerConnectionE2EQualityTest::Run(RunParams run_params) { RemotePeerAudioConfig::Create(bob_configurer->params()->audio_config); absl::optional<RemotePeerAudioConfig> bob_remote_audio_config = RemotePeerAudioConfig::Create(alice_configurer->params()->audio_config); - // Copy Alice and Bob video configs to correctly pass them into lambdas. + // Copy Alice and Bob video configs and names to correctly pass them into + // lambdas. std::vector<VideoConfig> alice_video_configs = alice_configurer->params()->video_configs; + std::string alice_name = alice_configurer->params()->name.value(); std::vector<VideoConfig> bob_video_configs = bob_configurer->params()->video_configs; + std::string bob_name = bob_configurer->params()->name.value(); alice_ = TestPeerFactory::CreateTestPeer( std::move(alice_configurer), std::make_unique<FixturePeerConnectionObserver>( - [this, bob_video_configs]( + [this, bob_video_configs, alice_name]( rtc::scoped_refptr<RtpTransceiverInterface> transceiver) { - OnTrackCallback(transceiver, bob_video_configs); + OnTrackCallback(alice_name, transceiver, bob_video_configs); }, [this]() { StartVideo(alice_video_sources_); }), video_quality_analyzer_injection_helper_.get(), signaling_thread.get(), @@ -225,9 +229,9 @@ void PeerConnectionE2EQualityTest::Run(RunParams run_params) { bob_ = TestPeerFactory::CreateTestPeer( std::move(bob_configurer), std::make_unique<FixturePeerConnectionObserver>( - [this, alice_video_configs]( - rtc::scoped_refptr<RtpTransceiverInterface> transceiver) { - OnTrackCallback(transceiver, alice_video_configs); + [this, alice_video_configs, + bob_name](rtc::scoped_refptr<RtpTransceiverInterface> transceiver) { + OnTrackCallback(bob_name, transceiver, alice_video_configs); }, [this]() { StartVideo(bob_video_sources_); }), video_quality_analyzer_injection_helper_.get(), signaling_thread.get(), @@ -246,10 +250,13 @@ void PeerConnectionE2EQualityTest::Run(RunParams run_params) { std::min(video_analyzer_threads, kMaxVideoAnalyzerThreads); RTC_LOG(INFO) << "video_analyzer_threads=" << video_analyzer_threads; quality_metrics_reporters_.push_back( - std::make_unique<VideoQualityMetricsReporter>()); + std::make_unique<VideoQualityMetricsReporter>(clock_)); - video_quality_analyzer_injection_helper_->Start(test_case_name_, - video_analyzer_threads); + video_quality_analyzer_injection_helper_->Start( + test_case_name_, + std::vector<std::string>{alice_->params()->name.value(), + bob_->params()->name.value()}, + video_analyzer_threads); audio_quality_analyzer_->Start(test_case_name_, &analyzer_helper_); for (auto& reporter : quality_metrics_reporters_) { reporter->Start(test_case_name_); @@ -371,6 +378,7 @@ void PeerConnectionE2EQualityTest::SetupRequiredFieldTrials( } void PeerConnectionE2EQualityTest::OnTrackCallback( + absl::string_view peer_name, rtc::scoped_refptr<RtpTransceiverInterface> transceiver, std::vector<VideoConfig> remote_video_configs) { const rtc::scoped_refptr<MediaStreamTrackInterface>& track = @@ -387,7 +395,7 @@ void PeerConnectionE2EQualityTest::OnTrackCallback( // track->kind() is kVideoKind. auto* video_track = static_cast<VideoTrackInterface*>(track.get()); std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> video_sink = - video_quality_analyzer_injection_helper_->CreateVideoSink(); + video_quality_analyzer_injection_helper_->CreateVideoSink(peer_name); video_track->AddOrUpdateSink(video_sink.get(), rtc::VideoSinkWants()); output_video_sinks_.push_back(std::move(video_sink)); } diff --git a/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test.h b/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test.h index 2eb7e708c6f..b302e5c51b5 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test.h +++ b/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test.h @@ -15,6 +15,7 @@ #include <string> #include <vector> +#include "absl/strings/string_view.h" #include "api/task_queue/task_queue_factory.h" #include "api/test/audio_quality_analyzer_interface.h" #include "api/test/peerconnection_quality_test_fixture.h" @@ -80,7 +81,8 @@ class PeerConnectionE2EQualityTest // For some functionality some field trials have to be enabled, so we will // enable them here. void SetupRequiredFieldTrials(const RunParams& run_params); - void OnTrackCallback(rtc::scoped_refptr<RtpTransceiverInterface> transceiver, + void OnTrackCallback(absl::string_view peer_name, + rtc::scoped_refptr<RtpTransceiverInterface> transceiver, std::vector<VideoConfig> remote_video_configs); // Have to be run on the signaling thread. void SetupCallOnSignalingThread(const RunParams& run_params); diff --git a/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test_params.h b/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test_params.h index ccb53492c3a..edefc7a0084 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test_params.h +++ b/chromium/third_party/webrtc/test/pc/e2e/peer_connection_quality_test_params.h @@ -20,7 +20,6 @@ #include "api/rtc_event_log/rtc_event_log_factory_interface.h" #include "api/task_queue/task_queue_factory.h" #include "api/test/peerconnection_quality_test_fixture.h" -#include "api/transport/media/media_transport_interface.h" #include "api/transport/network_control.h" #include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_encoder_factory.h" @@ -47,7 +46,6 @@ struct PeerConnectionFactoryComponents { std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory; std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory; std::unique_ptr<NetworkControllerFactoryInterface> network_controller_factory; - std::unique_ptr<MediaTransportFactory> media_transport_factory; std::unique_ptr<NetEqFactory> neteq_factory; // Will be passed to MediaEngineInterface, that will be used in @@ -114,7 +112,7 @@ struct Params { absl::optional<std::string> aec_dump_path; PeerConnectionInterface::RTCConfiguration rtc_configuration; - PeerConnectionInterface::BitrateParameters bitrate_params; + BitrateSettings bitrate_settings; }; } // namespace webrtc_pc_e2e diff --git a/chromium/third_party/webrtc/test/pc/e2e/stats_poller.cc b/chromium/third_party/webrtc/test/pc/e2e/stats_poller.cc index 987f26e7e80..e6973e6af19 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/stats_poller.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/stats_poller.cc @@ -18,14 +18,13 @@ namespace webrtc { namespace webrtc_pc_e2e { void InternalStatsObserver::PollStats() { - peer_->pc()->GetStats(this, nullptr, - webrtc::PeerConnectionInterface::StatsOutputLevel:: - kStatsOutputLevelStandard); + peer_->pc()->GetStats(this); } -void InternalStatsObserver::OnComplete(const StatsReports& reports) { +void InternalStatsObserver::OnStatsDelivered( + const rtc::scoped_refptr<const RTCStatsReport>& report) { for (auto* observer : observers_) { - observer->OnStatsReports(pc_label_, reports); + observer->OnStatsReports(pc_label_, report); } } diff --git a/chromium/third_party/webrtc/test/pc/e2e/stats_poller.h b/chromium/third_party/webrtc/test/pc/e2e/stats_poller.h index 3d0c2d68013..157a1478349 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/stats_poller.h +++ b/chromium/third_party/webrtc/test/pc/e2e/stats_poller.h @@ -17,6 +17,7 @@ #include <vector> #include "api/peer_connection_interface.h" +#include "api/stats/rtc_stats_collector_callback.h" #include "api/test/stats_observer_interface.h" #include "test/pc/e2e/test_peer.h" @@ -25,7 +26,7 @@ namespace webrtc_pc_e2e { // Helper class that will notify all the webrtc::test::StatsObserverInterface // objects subscribed. -class InternalStatsObserver : public StatsObserver { +class InternalStatsObserver : public RTCStatsCollectorCallback { public: InternalStatsObserver(std::string pc_label, TestPeer* peer, @@ -36,7 +37,8 @@ class InternalStatsObserver : public StatsObserver { void PollStats(); - void OnComplete(const StatsReports& reports) override; + void OnStatsDelivered( + const rtc::scoped_refptr<const RTCStatsReport>& report) override; private: std::string pc_label_; diff --git a/chromium/third_party/webrtc/test/pc/e2e/test_peer_factory.cc b/chromium/third_party/webrtc/test/pc/e2e/test_peer_factory.cc index 455337ef3a3..f700f1cb787 100644 --- a/chromium/third_party/webrtc/test/pc/e2e/test_peer_factory.cc +++ b/chromium/third_party/webrtc/test/pc/e2e/test_peer_factory.cc @@ -12,6 +12,7 @@ #include <utility> #include "absl/memory/memory.h" +#include "absl/strings/string_view.h" #include "api/task_queue/default_task_queue_factory.h" #include "api/video_codecs/builtin_video_decoder_factory.h" #include "api/video_codecs/builtin_video_encoder_factory.h" @@ -172,6 +173,7 @@ std::unique_ptr<cricket::MediaEngineInterface> CreateMediaEngine( } void WrapVideoEncoderFactory( + absl::string_view peer_name, double bitrate_multiplier, std::map<std::string, absl::optional<int>> stream_required_spatial_index, PeerConnectionFactoryComponents* pcf_dependencies, @@ -184,11 +186,12 @@ void WrapVideoEncoderFactory( } pcf_dependencies->video_encoder_factory = video_analyzer_helper->WrapVideoEncoderFactory( - std::move(video_encoder_factory), bitrate_multiplier, + peer_name, std::move(video_encoder_factory), bitrate_multiplier, std::move(stream_required_spatial_index)); } void WrapVideoDecoderFactory( + absl::string_view peer_name, PeerConnectionFactoryComponents* pcf_dependencies, VideoQualityAnalyzerInjectionHelper* video_analyzer_helper) { std::unique_ptr<VideoDecoderFactory> video_decoder_factory; @@ -199,7 +202,7 @@ void WrapVideoDecoderFactory( } pcf_dependencies->video_decoder_factory = video_analyzer_helper->WrapVideoDecoderFactory( - std::move(video_decoder_factory)); + peer_name, std::move(video_decoder_factory)); } // Creates PeerConnectionFactoryDependencies objects, providing entities @@ -226,10 +229,6 @@ PeerConnectionFactoryDependencies CreatePCFDependencies( pcf_deps.network_controller_factory = std::move(pcf_dependencies->network_controller_factory); } - if (pcf_dependencies->media_transport_factory != nullptr) { - pcf_deps.media_transport_factory = - std::move(pcf_dependencies->media_transport_factory); - } if (pcf_dependencies->neteq_factory != nullptr) { pcf_deps.neteq_factory = std::move(pcf_dependencies->neteq_factory); } @@ -309,10 +308,11 @@ std::unique_ptr<TestPeer> TestPeerFactory::CreateTestPeer( params->audio_config, remote_audio_config, echo_emulation_config, components->pcf_dependencies->task_queue_factory.get()); WrapVideoEncoderFactory( - bitrate_multiplier, + params->name.value(), bitrate_multiplier, CalculateRequiredSpatialIndexPerStream(params->video_configs), components->pcf_dependencies.get(), video_analyzer_helper); - WrapVideoDecoderFactory(components->pcf_dependencies.get(), + WrapVideoDecoderFactory(params->name.value(), + components->pcf_dependencies.get(), video_analyzer_helper); std::unique_ptr<cricket::MediaEngineInterface> media_engine = CreateMediaEngine(components->pcf_dependencies.get(), audio_device_module, @@ -329,7 +329,7 @@ std::unique_ptr<TestPeer> TestPeerFactory::CreateTestPeer( rtc::scoped_refptr<PeerConnectionInterface> peer_connection = peer_connection_factory->CreatePeerConnection(params->rtc_configuration, std::move(pc_deps)); - peer_connection->SetBitrate(params->bitrate_params); + peer_connection->SetBitrate(params->bitrate_settings); return absl::WrapUnique(new TestPeer( peer_connection_factory, peer_connection, std::move(observer), diff --git a/chromium/third_party/webrtc/test/peer_scenario/BUILD.gn b/chromium/third_party/webrtc/test/peer_scenario/BUILD.gn index d702cf539f2..bdc77b70c8d 100644 --- a/chromium/third_party/webrtc/test/peer_scenario/BUILD.gn +++ b/chromium/third_party/webrtc/test/peer_scenario/BUILD.gn @@ -52,6 +52,8 @@ if (rtc_include_tests) { "../network:emulated_network", "../scenario", "../time_controller", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/memory", ] diff --git a/chromium/third_party/webrtc/test/run_loop_unittest.cc b/chromium/third_party/webrtc/test/run_loop_unittest.cc index a356cc265a5..160aba0716a 100644 --- a/chromium/third_party/webrtc/test/run_loop_unittest.cc +++ b/chromium/third_party/webrtc/test/run_loop_unittest.cc @@ -17,7 +17,6 @@ namespace webrtc { TEST(RunLoopTest, TaskQueueOnThread) { - EXPECT_EQ(TaskQueueBase::Current(), nullptr); test::RunLoop loop; EXPECT_EQ(TaskQueueBase::Current(), loop.task_queue()); EXPECT_TRUE(loop.task_queue()->IsCurrent()); diff --git a/chromium/third_party/webrtc/test/scenario/BUILD.gn b/chromium/third_party/webrtc/test/scenario/BUILD.gn index e2e5f8cef22..33c68a8211d 100644 --- a/chromium/third_party/webrtc/test/scenario/BUILD.gn +++ b/chromium/third_party/webrtc/test/scenario/BUILD.gn @@ -141,6 +141,8 @@ if (rtc_include_tests) { "../logging:log_writer", "../network:emulated_network", "../time_controller", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", "//third_party/abseil-cpp/absl/memory", diff --git a/chromium/third_party/webrtc/test/scenario/call_client.cc b/chromium/third_party/webrtc/test/scenario/call_client.cc index fb888df6946..0107497252d 100644 --- a/chromium/third_party/webrtc/test/scenario/call_client.cc +++ b/chromium/third_party/webrtc/test/scenario/call_client.cc @@ -54,7 +54,8 @@ Call* CreateCall(TimeController* time_controller, RtcEventLog* event_log, CallClientConfig config, LoggingNetworkControllerFactory* network_controller_factory, - rtc::scoped_refptr<AudioState> audio_state) { + rtc::scoped_refptr<AudioState> audio_state, + rtc::scoped_refptr<SharedModuleThread> call_thread) { CallConfig call_config(event_log); call_config.bitrate_config.max_bitrate_bps = config.transport.rates.max_rate.bps_or(-1); @@ -67,7 +68,7 @@ Call* CreateCall(TimeController* time_controller, call_config.audio_state = audio_state; call_config.trials = config.field_trials; return Call::Create(call_config, time_controller->GetClock(), - time_controller->CreateProcessThread("CallModules"), + std::move(call_thread), time_controller->CreateProcessThread("Pacer")); } @@ -213,9 +214,14 @@ CallClient::CallClient( event_log_ = CreateEventLog(time_controller_->GetTaskQueueFactory(), log_writer_factory_.get()); fake_audio_setup_ = InitAudio(time_controller_); + RTC_DCHECK(!module_thread_); + module_thread_ = SharedModuleThread::Create( + time_controller_->CreateProcessThread("CallThread"), + [this]() { module_thread_ = nullptr; }); + call_.reset(CreateCall(time_controller_, event_log_.get(), config, &network_controller_factory_, - fake_audio_setup_.audio_state)); + fake_audio_setup_.audio_state, module_thread_)); transport_ = std::make_unique<NetworkNodeTransport>(clock_, call_.get()); }); } @@ -223,6 +229,7 @@ CallClient::CallClient( CallClient::~CallClient() { SendTask([&] { call_.reset(); + RTC_DCHECK(!module_thread_); // Should be set to null in the lambda above. fake_audio_setup_ = {}; rtc::Event done; event_log_->StopLogging([&done] { done.Set(); }); diff --git a/chromium/third_party/webrtc/test/scenario/call_client.h b/chromium/third_party/webrtc/test/scenario/call_client.h index 33fa2765cb5..80814eb1b3b 100644 --- a/chromium/third_party/webrtc/test/scenario/call_client.h +++ b/chromium/third_party/webrtc/test/scenario/call_client.h @@ -157,6 +157,8 @@ class CallClient : public EmulatedNetworkReceiverInterface { // Defined last so it's destroyed first. TaskQueueForTest task_queue_; + rtc::scoped_refptr<SharedModuleThread> module_thread_; + const FieldTrialBasedConfig field_trials_; }; diff --git a/chromium/third_party/webrtc/test/scenario/scenario_unittest.cc b/chromium/third_party/webrtc/test/scenario/scenario_unittest.cc index 839e6a375e5..f74c1a5bdf3 100644 --- a/chromium/third_party/webrtc/test/scenario/scenario_unittest.cc +++ b/chromium/third_party/webrtc/test/scenario/scenario_unittest.cc @@ -119,7 +119,8 @@ TEST(ScenarioTest, MAYBE_RealTimeEncoding) { } // Regression tests based on previous runs. EXPECT_LT(analyzer.stats().lost_count, 2); - EXPECT_NEAR(analyzer.stats().psnr_with_freeze.Mean(), 38, 10); + // This far below expected but ensures that we get something. + EXPECT_GT(analyzer.stats().psnr_with_freeze.Mean(), 10); } TEST(ScenarioTest, SimTimeFakeing) { diff --git a/chromium/third_party/webrtc/test/test_main.cc b/chromium/third_party/webrtc/test/test_main.cc index 8555d5e6dae..50469795486 100644 --- a/chromium/third_party/webrtc/test/test_main.cc +++ b/chromium/third_party/webrtc/test/test_main.cc @@ -16,11 +16,10 @@ int main(int argc, char* argv[]) { // Initialize the symbolizer to get a human-readable stack trace - // TODO(crbug.com/1050976): Breaks iossim tests, re-enable when fixed. - // absl::InitializeSymbolizer(argv[0]); + absl::InitializeSymbolizer(argv[0]); - // absl::FailureSignalHandlerOptions options; - // absl::InstallFailureSignalHandler(options); + absl::FailureSignalHandlerOptions options; + absl::InstallFailureSignalHandler(options); std::unique_ptr<webrtc::TestMain> main = webrtc::TestMain::Create(); int err_code = main->Init(&argc, argv); diff --git a/chromium/third_party/webrtc/test/test_main_lib.cc b/chromium/third_party/webrtc/test/test_main_lib.cc index 15318b49e15..f5e02341f3f 100644 --- a/chromium/third_party/webrtc/test/test_main_lib.cc +++ b/chromium/third_party/webrtc/test/test_main_lib.cc @@ -17,6 +17,7 @@ #include "absl/flags/flag.h" #include "absl/flags/parse.h" #include "absl/memory/memory.h" +#include "absl/strings/match.h" #include "absl/types/optional.h" #include "rtc_base/checks.h" #include "rtc_base/event_tracer.h" @@ -100,6 +101,62 @@ namespace { class TestMainImpl : public TestMain { public: + // In order to set up a fresh rtc::Thread state for each test and avoid + // accidentally carrying over pending tasks that might be sent from one test + // and executed while another test is running, we inject a TestListener + // that sets up a new rtc::Thread instance for the main thread, per test. + class TestListener : public ::testing::EmptyTestEventListener { + public: + TestListener() = default; + + private: + bool IsDeathTest(const char* test_case_name, const char* test_name) { + // Workaround to avoid wrapping the main thread when we run death tests. + // The approach we take for detecting death tests is essentially the same + // as gtest does internally. Gtest does this: + // + // static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + // ::testing::internal::UnitTestOptions::MatchesFilter( + // test_case_name, kDeathTestCaseFilter); + // + // Our approach is a little more straight forward. + if (absl::EndsWith(test_case_name, "DeathTest")) + return true; + + return absl::EndsWith(test_name, "DeathTest"); + } + + void OnTestStart(const ::testing::TestInfo& test_info) override { + if (!IsDeathTest(test_info.test_suite_name(), test_info.name())) { + // Ensure that main thread gets wrapped as an rtc::Thread. + // TODO(bugs.webrtc.org/9714): It might be better to avoid wrapping the + // main thread, or leave it to individual tests that need it. But as + // long as we have automatic thread wrapping, we need this to avoid that + // some other random thread (which one depending on which tests are run) + // gets automatically wrapped. + thread_ = rtc::Thread::CreateWithSocketServer(); + thread_->WrapCurrent(); + RTC_DCHECK_EQ(rtc::Thread::Current(), thread_.get()); + } else { + RTC_LOG(LS_INFO) << "No thread auto wrap for death test."; + } + } + + void OnTestEnd(const ::testing::TestInfo& test_info) override { + // Terminate the message loop. Note that if the test failed to clean + // up pending messages, this may execute part of the test. Ideally we + // should print a warning message here, or even fail the test if it leaks. + if (thread_) { + thread_->Quit(); // Signal quit. + thread_->Run(); // Flush + process Quit signal. + thread_->UnwrapCurrent(); + thread_ = nullptr; + } + } + + std::unique_ptr<rtc::Thread> thread_; + }; + int Init(int* argc, char* argv[]) override { ::testing::InitGoogleMock(argc, argv); absl::ParseCommandLine(*argc, argv); @@ -134,14 +191,7 @@ class TestMainImpl : public TestMain { rtc::InitializeSSL(); rtc::SSLStreamAdapter::EnableTimeCallbackForTesting(); - // Ensure that main thread gets wrapped as an rtc::Thread. - // TODO(bugs.webrt.org/9714): It might be better to avoid wrapping the main - // thread, or leave it to individual tests that need it. But as long as we - // have automatic thread wrapping, we need this to avoid that some other - // random thread (which one depending on which tests are run) gets - // automatically wrapped. - rtc::ThreadManager::Instance()->WrapCurrentThread(); - RTC_CHECK(rtc::Thread::Current()); + ::testing::UnitTest::GetInstance()->listeners().Append(new TestListener()); return 0; } diff --git a/chromium/third_party/webrtc/test/testsupport/mock/mock_frame_reader.h b/chromium/third_party/webrtc/test/testsupport/mock/mock_frame_reader.h index 8da3695d23b..bda6b1ad2dc 100644 --- a/chromium/third_party/webrtc/test/testsupport/mock/mock_frame_reader.h +++ b/chromium/third_party/webrtc/test/testsupport/mock/mock_frame_reader.h @@ -19,11 +19,11 @@ namespace test { class MockFrameReader : public FrameReader { public: - MOCK_METHOD0(Init, bool()); - MOCK_METHOD0(ReadFrame, rtc::scoped_refptr<I420Buffer>()); - MOCK_METHOD0(Close, void()); - MOCK_METHOD0(FrameLength, size_t()); - MOCK_METHOD0(NumberOfFrames, int()); + MOCK_METHOD(bool, Init, (), (override)); + MOCK_METHOD(rtc::scoped_refptr<I420Buffer>, ReadFrame, (), (override)); + MOCK_METHOD(void, Close, (), (override)); + MOCK_METHOD(size_t, FrameLength, (), (override)); + MOCK_METHOD(int, NumberOfFrames, (), (override)); }; } // namespace test diff --git a/chromium/third_party/webrtc/test/testsupport/perf_test.h b/chromium/third_party/webrtc/test/testsupport/perf_test.h index b0a5607d20a..4bb6773336c 100644 --- a/chromium/third_party/webrtc/test/testsupport/perf_test.h +++ b/chromium/third_party/webrtc/test/testsupport/perf_test.h @@ -15,7 +15,6 @@ #include <string> #include <vector> -#include "absl/flags/flag.h" #include "api/array_view.h" #include "rtc_base/numerics/samples_stats_counter.h" diff --git a/chromium/third_party/webrtc/test/testsupport/resources_dir_flag.cc b/chromium/third_party/webrtc/test/testsupport/resources_dir_flag.cc index a6ab3b537be..87a449a401d 100644 --- a/chromium/third_party/webrtc/test/testsupport/resources_dir_flag.cc +++ b/chromium/third_party/webrtc/test/testsupport/resources_dir_flag.cc @@ -10,6 +10,8 @@ #include "test/testsupport/resources_dir_flag.h" +#include "absl/flags/flag.h" + ABSL_FLAG(std::string, resources_dir, "", diff --git a/chromium/third_party/webrtc/test/testsupport/resources_dir_flag.h b/chromium/third_party/webrtc/test/testsupport/resources_dir_flag.h index 055cc825467..7d6f192d9bd 100644 --- a/chromium/third_party/webrtc/test/testsupport/resources_dir_flag.h +++ b/chromium/third_party/webrtc/test/testsupport/resources_dir_flag.h @@ -13,7 +13,7 @@ #ifndef TEST_TESTSUPPORT_RESOURCES_DIR_FLAG_H__ #define TEST_TESTSUPPORT_RESOURCES_DIR_FLAG_H__ -#include "absl/flags/flag.h" +#include "absl/flags/declare.h" ABSL_DECLARE_FLAG(std::string, resources_dir); diff --git a/chromium/third_party/webrtc/test/testsupport/test_artifacts_unittest.cc b/chromium/third_party/webrtc/test/testsupport/test_artifacts_unittest.cc index 98de9e4bb83..fb577610fbb 100644 --- a/chromium/third_party/webrtc/test/testsupport/test_artifacts_unittest.cc +++ b/chromium/third_party/webrtc/test/testsupport/test_artifacts_unittest.cc @@ -14,6 +14,7 @@ #include <string> +#include "absl/flags/declare.h" #include "absl/flags/flag.h" #include "rtc_base/system/file_wrapper.h" #include "test/gtest.h" diff --git a/chromium/third_party/webrtc/test/time_controller/BUILD.gn b/chromium/third_party/webrtc/test/time_controller/BUILD.gn index 7f77f0afec7..c3d5dc9031b 100644 --- a/chromium/third_party/webrtc/test/time_controller/BUILD.gn +++ b/chromium/third_party/webrtc/test/time_controller/BUILD.gn @@ -41,8 +41,8 @@ rtc_library("time_controller") { "../../rtc_base/synchronization:yield_policy", "../../rtc_base/task_utils:to_queued_task", "../../system_wrappers", - "//third_party/abseil-cpp/absl/strings", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } if (rtc_include_tests) { diff --git a/chromium/third_party/webrtc/test/time_controller/simulated_time_controller.cc b/chromium/third_party/webrtc/test/time_controller/simulated_time_controller.cc index a81083b4fb9..769be3ff782 100644 --- a/chromium/third_party/webrtc/test/time_controller/simulated_time_controller.cc +++ b/chromium/third_party/webrtc/test/time_controller/simulated_time_controller.cc @@ -57,7 +57,6 @@ SimulatedTimeControllerImpl::CreateTaskQueue( std::unique_ptr<ProcessThread> SimulatedTimeControllerImpl::CreateProcessThread( const char* thread_name) { - rtc::CritScope lock(&lock_); auto process_thread = std::make_unique<SimulatedProcessThread>(this, thread_name); Register(process_thread.get()); @@ -117,10 +116,12 @@ void SimulatedTimeControllerImpl::RunReadyRunners() { while (!ready_runners_.empty()) { auto* runner = ready_runners_.front(); ready_runners_.pop_front(); + lock_.Leave(); // Note that the RunReady function might indirectly cause a call to - // Unregister() which will recursively grab |lock_| again to remove items - // from |ready_runners_|. + // Unregister() which will grab |lock_| again to remove items from + // |ready_runners_|. runner->RunReady(current_time); + lock_.Enter(); } } } @@ -169,6 +170,7 @@ void SimulatedTimeControllerImpl::StartYield(TaskQueueBase* yielding_from) { void SimulatedTimeControllerImpl::StopYield(TaskQueueBase* yielding_from) { yielded_.erase(yielding_from); } + } // namespace sim_time_impl GlobalSimulatedTimeController::GlobalSimulatedTimeController( diff --git a/chromium/third_party/webrtc/test/time_controller/simulated_time_controller.h b/chromium/third_party/webrtc/test/time_controller/simulated_time_controller.h index 758f90989e8..48112b3a318 100644 --- a/chromium/third_party/webrtc/test/time_controller/simulated_time_controller.h +++ b/chromium/third_party/webrtc/test/time_controller/simulated_time_controller.h @@ -52,32 +52,34 @@ class SimulatedTimeControllerImpl : public TaskQueueFactory, std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue( absl::string_view name, - Priority priority) const override; + Priority priority) const RTC_LOCKS_EXCLUDED(time_lock_) override; // Implements the YieldInterface by running ready tasks on all task queues, // except that if this method is called from a task, the task queue running // that task is skipped. - void YieldExecution() override; + void YieldExecution() RTC_LOCKS_EXCLUDED(time_lock_, lock_) override; // Create process thread with the name |thread_name|. - std::unique_ptr<ProcessThread> CreateProcessThread(const char* thread_name); + std::unique_ptr<ProcessThread> CreateProcessThread(const char* thread_name) + RTC_LOCKS_EXCLUDED(time_lock_, lock_); // Create thread using provided |socket_server|. std::unique_ptr<rtc::Thread> CreateThread( const std::string& name, - std::unique_ptr<rtc::SocketServer> socket_server); + std::unique_ptr<rtc::SocketServer> socket_server) + RTC_LOCKS_EXCLUDED(time_lock_, lock_); // Runs all runners in |runners_| that has tasks or modules ready for // execution. - void RunReadyRunners(); + void RunReadyRunners() RTC_LOCKS_EXCLUDED(time_lock_, lock_); // Return |current_time_|. - Timestamp CurrentTime() const; + Timestamp CurrentTime() const RTC_LOCKS_EXCLUDED(time_lock_); // Return min of runner->GetNextRunTime() for runner in |runners_|. - Timestamp NextRunTime() const; + Timestamp NextRunTime() const RTC_LOCKS_EXCLUDED(lock_); // Set |current_time_| to |target_time|. - void AdvanceTime(Timestamp target_time); + void AdvanceTime(Timestamp target_time) RTC_LOCKS_EXCLUDED(time_lock_); // Adds |runner| to |runners_|. - void Register(SimulatedSequenceRunner* runner); + void Register(SimulatedSequenceRunner* runner) RTC_LOCKS_EXCLUDED(lock_); // Removes |runner| from |runners_|. - void Unregister(SimulatedSequenceRunner* runner); + void Unregister(SimulatedSequenceRunner* runner) RTC_LOCKS_EXCLUDED(lock_); // Indicates that |yielding_from| is not ready to run. void StartYield(TaskQueueBase* yielding_from); |