summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/api/test
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/api/test')
-rw-r--r--third_party/libwebrtc/api/test/DEPS39
-rw-r--r--third_party/libwebrtc/api/test/OWNERS5
-rw-r--r--third_party/libwebrtc/api/test/audio_quality_analyzer_interface.h44
-rw-r--r--third_party/libwebrtc/api/test/audioproc_float.cc44
-rw-r--r--third_party/libwebrtc/api/test/audioproc_float.h71
-rw-r--r--third_party/libwebrtc/api/test/compile_all_headers.cc53
-rw-r--r--third_party/libwebrtc/api/test/create_frame_generator.cc101
-rw-r--r--third_party/libwebrtc/api/test/create_frame_generator.h85
-rw-r--r--third_party/libwebrtc/api/test/create_network_emulation_manager.cc27
-rw-r--r--third_party/libwebrtc/api/test/create_network_emulation_manager.h28
-rw-r--r--third_party/libwebrtc/api/test/create_peer_connection_quality_test_frame_generator.cc103
-rw-r--r--third_party/libwebrtc/api/test/create_peer_connection_quality_test_frame_generator.h44
-rw-r--r--third_party/libwebrtc/api/test/create_peerconnection_quality_test_fixture.cc36
-rw-r--r--third_party/libwebrtc/api/test/create_peerconnection_quality_test_fixture.h43
-rw-r--r--third_party/libwebrtc/api/test/create_simulcast_test_fixture.cc31
-rw-r--r--third_party/libwebrtc/api/test/create_simulcast_test_fixture.h32
-rw-r--r--third_party/libwebrtc/api/test/create_time_controller.cc53
-rw-r--r--third_party/libwebrtc/api/test/create_time_controller.h34
-rw-r--r--third_party/libwebrtc/api/test/create_time_controller_unittest.cc76
-rw-r--r--third_party/libwebrtc/api/test/create_video_codec_tester.cc27
-rw-r--r--third_party/libwebrtc/api/test/create_video_codec_tester.h26
-rw-r--r--third_party/libwebrtc/api/test/create_video_quality_test_fixture.cc40
-rw-r--r--third_party/libwebrtc/api/test/create_video_quality_test_fixture.h31
-rw-r--r--third_party/libwebrtc/api/test/create_videocodec_test_fixture.cc38
-rw-r--r--third_party/libwebrtc/api/test/create_videocodec_test_fixture.h34
-rw-r--r--third_party/libwebrtc/api/test/fake_frame_decryptor.cc71
-rw-r--r--third_party/libwebrtc/api/test/fake_frame_decryptor.h70
-rw-r--r--third_party/libwebrtc/api/test/fake_frame_encryptor.cc66
-rw-r--r--third_party/libwebrtc/api/test/fake_frame_encryptor.h69
-rw-r--r--third_party/libwebrtc/api/test/frame_generator_interface.cc34
-rw-r--r--third_party/libwebrtc/api/test/frame_generator_interface.h51
-rw-r--r--third_party/libwebrtc/api/test/metrics/BUILD.gn281
-rw-r--r--third_party/libwebrtc/api/test/metrics/DEPS14
-rw-r--r--third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.cc146
-rw-r--r--third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.h41
-rw-r--r--third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter_test.cc248
-rw-r--r--third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter.cc42
-rw-r--r--third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter.h32
-rw-r--r--third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter_test.cc131
-rw-r--r--third_party/libwebrtc/api/test/metrics/metric.cc48
-rw-r--r--third_party/libwebrtc/api/test/metrics/metric.h96
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_accumulator.cc132
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_accumulator.h99
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_accumulator_test.cc315
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_exporter.h33
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_logger.cc114
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_logger.h112
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_logger_test.cc326
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter.cc157
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter.h54
-rw-r--r--third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter_test.cc151
-rw-r--r--third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter.cc157
-rw-r--r--third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter.h32
-rw-r--r--third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter_test.cc177
-rw-r--r--third_party/libwebrtc/api/test/metrics/proto/metric.proto87
-rw-r--r--third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter.cc101
-rw-r--r--third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter.h41
-rw-r--r--third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter_test.cc211
-rw-r--r--third_party/libwebrtc/api/test/mock_async_dns_resolver.h62
-rw-r--r--third_party/libwebrtc/api/test/mock_audio_mixer.h29
-rw-r--r--third_party/libwebrtc/api/test/mock_audio_sink.h44
-rw-r--r--third_party/libwebrtc/api/test/mock_data_channel.h61
-rw-r--r--third_party/libwebrtc/api/test/mock_dtmf_sender.h56
-rw-r--r--third_party/libwebrtc/api/test/mock_encoder_selector.h42
-rw-r--r--third_party/libwebrtc/api/test/mock_fec_controller_override.h26
-rw-r--r--third_party/libwebrtc/api/test/mock_frame_decryptor.h40
-rw-r--r--third_party/libwebrtc/api/test/mock_frame_encryptor.h39
-rw-r--r--third_party/libwebrtc/api/test/mock_media_stream_interface.h134
-rw-r--r--third_party/libwebrtc/api/test/mock_packet_socket_factory.h49
-rw-r--r--third_party/libwebrtc/api/test/mock_peer_connection_factory_interface.h81
-rw-r--r--third_party/libwebrtc/api/test/mock_peerconnectioninterface.h213
-rw-r--r--third_party/libwebrtc/api/test/mock_rtp_transceiver.h87
-rw-r--r--third_party/libwebrtc/api/test/mock_rtpreceiver.h58
-rw-r--r--third_party/libwebrtc/api/test/mock_rtpsender.h78
-rw-r--r--third_party/libwebrtc/api/test/mock_session_description_interface.h56
-rw-r--r--third_party/libwebrtc/api/test/mock_transformable_video_frame.h42
-rw-r--r--third_party/libwebrtc/api/test/mock_video_bitrate_allocator.h28
-rw-r--r--third_party/libwebrtc/api/test/mock_video_bitrate_allocator_factory.h34
-rw-r--r--third_party/libwebrtc/api/test/mock_video_decoder.h70
-rw-r--r--third_party/libwebrtc/api/test/mock_video_decoder_factory.h40
-rw-r--r--third_party/libwebrtc/api/test/mock_video_encoder.h73
-rw-r--r--third_party/libwebrtc/api/test/mock_video_encoder_factory.h42
-rw-r--r--third_party/libwebrtc/api/test/mock_video_track.h69
-rw-r--r--third_party/libwebrtc/api/test/neteq_simulator.cc26
-rw-r--r--third_party/libwebrtc/api/test/neteq_simulator.h82
-rw-r--r--third_party/libwebrtc/api/test/neteq_simulator_factory.cc71
-rw-r--r--third_party/libwebrtc/api/test/neteq_simulator_factory.h71
-rw-r--r--third_party/libwebrtc/api/test/network_emulation/BUILD.gn52
-rw-r--r--third_party/libwebrtc/api/test/network_emulation/DEPS7
-rw-r--r--third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.cc39
-rw-r--r--third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.h37
-rw-r--r--third_party/libwebrtc/api/test/network_emulation/cross_traffic.h85
-rw-r--r--third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.cc46
-rw-r--r--third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.h311
-rw-r--r--third_party/libwebrtc/api/test/network_emulation_manager.cc122
-rw-r--r--third_party/libwebrtc/api/test/network_emulation_manager.h357
-rw-r--r--third_party/libwebrtc/api/test/pclf/BUILD.gn114
-rw-r--r--third_party/libwebrtc/api/test/pclf/DEPS13
-rw-r--r--third_party/libwebrtc/api/test/pclf/media_configuration.cc314
-rw-r--r--third_party/libwebrtc/api/test/pclf/media_configuration.h484
-rw-r--r--third_party/libwebrtc/api/test/pclf/media_quality_test_params.h189
-rw-r--r--third_party/libwebrtc/api/test/pclf/peer_configurer.cc245
-rw-r--r--third_party/libwebrtc/api/test/pclf/peer_configurer.h200
-rw-r--r--third_party/libwebrtc/api/test/peer_network_dependencies.h32
-rw-r--r--third_party/libwebrtc/api/test/peerconnection_quality_test_fixture.h142
-rw-r--r--third_party/libwebrtc/api/test/peerconnection_quality_test_fixture_unittest.cc142
-rw-r--r--third_party/libwebrtc/api/test/simulated_network.h139
-rw-r--r--third_party/libwebrtc/api/test/simulcast_test_fixture.h45
-rw-r--r--third_party/libwebrtc/api/test/stats_observer_interface.h35
-rw-r--r--third_party/libwebrtc/api/test/test_dependency_factory.cc54
-rw-r--r--third_party/libwebrtc/api/test/test_dependency_factory.h48
-rw-r--r--third_party/libwebrtc/api/test/time_controller.cc43
-rw-r--r--third_party/libwebrtc/api/test/time_controller.h89
-rw-r--r--third_party/libwebrtc/api/test/track_id_stream_info_map.h44
-rw-r--r--third_party/libwebrtc/api/test/video/BUILD.gn31
-rw-r--r--third_party/libwebrtc/api/test/video/function_video_decoder_factory.h65
-rw-r--r--third_party/libwebrtc/api/test/video/function_video_encoder_factory.h60
-rw-r--r--third_party/libwebrtc/api/test/video/video_frame_writer.h37
-rw-r--r--third_party/libwebrtc/api/test/video_codec_tester.h134
-rw-r--r--third_party/libwebrtc/api/test/video_quality_analyzer_interface.h165
-rw-r--r--third_party/libwebrtc/api/test/video_quality_test_fixture.h143
-rw-r--r--third_party/libwebrtc/api/test/videocodec_test_fixture.h177
-rw-r--r--third_party/libwebrtc/api/test/videocodec_test_stats.cc121
-rw-r--r--third_party/libwebrtc/api/test/videocodec_test_stats.h156
124 files changed, 11204 insertions, 0 deletions
diff --git a/third_party/libwebrtc/api/test/DEPS b/third_party/libwebrtc/api/test/DEPS
new file mode 100644
index 0000000000..270b274c5f
--- /dev/null
+++ b/third_party/libwebrtc/api/test/DEPS
@@ -0,0 +1,39 @@
+specific_include_rules = {
+ ".*": [
+ "+modules/video_coding",
+ ],
+ ".*": [
+ "+video"
+ ],
+ "dummy_peer_connection\.h": [
+ "+rtc_base/ref_counted_object.h",
+ ],
+ "neteq_factory_with_codecs\.h": [
+ "+system_wrappers/include/clock.h",
+ ],
+ "network_emulation_manager\.h": [
+ "+rtc_base/thread.h",
+ "+rtc_base/network.h",
+ "+rtc_base/network_constants.h",
+ ],
+ "peer_network_dependencies\.h": [
+ "+rtc_base/network.h",
+ "+rtc_base/thread.h",
+ ],
+ "peerconnection_quality_test_fixture\.h": [
+ "+logging/rtc_event_log/rtc_event_log_factory_interface.h",
+ "+rtc_base/network.h",
+ "+rtc_base/rtc_certificate_generator.h",
+ "+rtc_base/ssl_certificate.h",
+ "+rtc_base/thread.h",
+ "+media/base/media_constants.h",
+ "+modules/audio_processing/include/audio_processing.h",
+ ],
+ "time_controller\.h": [
+ "+rtc_base/synchronization/yield_policy.h",
+ "+system_wrappers/include/clock.h",
+ ],
+ "create_frame_generator\.h": [
+ "+system_wrappers/include/clock.h",
+ ],
+}
diff --git a/third_party/libwebrtc/api/test/OWNERS b/third_party/libwebrtc/api/test/OWNERS
new file mode 100644
index 0000000000..a7392abe31
--- /dev/null
+++ b/third_party/libwebrtc/api/test/OWNERS
@@ -0,0 +1,5 @@
+mbonadei@webrtc.org
+sprang@webrtc.org
+srte@webrtc.org
+titovartem@webrtc.org
+
diff --git a/third_party/libwebrtc/api/test/audio_quality_analyzer_interface.h b/third_party/libwebrtc/api/test/audio_quality_analyzer_interface.h
new file mode 100644
index 0000000000..2eb7817445
--- /dev/null
+++ b/third_party/libwebrtc/api/test/audio_quality_analyzer_interface.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_AUDIO_QUALITY_ANALYZER_INTERFACE_H_
+#define API_TEST_AUDIO_QUALITY_ANALYZER_INTERFACE_H_
+
+#include <string>
+
+#include "api/test/stats_observer_interface.h"
+#include "api/test/track_id_stream_info_map.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// API is in development. Can be changed/removed without notice.
+class AudioQualityAnalyzerInterface : public StatsObserverInterface {
+ public:
+ ~AudioQualityAnalyzerInterface() override = default;
+
+ // Will be called by the framework before the test.
+ // `test_case_name` is name of test case, that should be used to report all
+ // audio metrics.
+ // `analyzer_helper` is a pointer to a class that will allow track_id to
+ // stream_id matching. The caller is responsible for ensuring the
+ // AnalyzerHelper outlives the instance of the AudioQualityAnalyzerInterface.
+ virtual void Start(std::string test_case_name,
+ TrackIdStreamInfoMap* analyzer_helper) = 0;
+
+ // Will be called by the framework at the end of the test. The analyzer
+ // has to finalize all its stats and it should report them.
+ virtual void Stop() = 0;
+};
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_AUDIO_QUALITY_ANALYZER_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/test/audioproc_float.cc b/third_party/libwebrtc/api/test/audioproc_float.cc
new file mode 100644
index 0000000000..c8d7ff7193
--- /dev/null
+++ b/third_party/libwebrtc/api/test/audioproc_float.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 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 "api/test/audioproc_float.h"
+
+#include <utility>
+
+#include "modules/audio_processing/test/audioproc_float_impl.h"
+
+namespace webrtc {
+namespace test {
+
+int AudioprocFloat(rtc::scoped_refptr<AudioProcessing> audio_processing,
+ int argc,
+ char* argv[]) {
+ return AudioprocFloatImpl(std::move(audio_processing), argc, argv);
+}
+
+int AudioprocFloat(std::unique_ptr<AudioProcessingBuilder> ap_builder,
+ int argc,
+ char* argv[]) {
+ return AudioprocFloatImpl(std::move(ap_builder), argc, argv,
+ /*input_aecdump=*/"",
+ /*processed_capture_samples=*/nullptr);
+}
+
+int AudioprocFloat(std::unique_ptr<AudioProcessingBuilder> ap_builder,
+ int argc,
+ char* argv[],
+ absl::string_view input_aecdump,
+ std::vector<float>* processed_capture_samples) {
+ return AudioprocFloatImpl(std::move(ap_builder), argc, argv, input_aecdump,
+ processed_capture_samples);
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/audioproc_float.h b/third_party/libwebrtc/api/test/audioproc_float.h
new file mode 100644
index 0000000000..1ef1c9828f
--- /dev/null
+++ b/third_party/libwebrtc/api/test/audioproc_float.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_AUDIOPROC_FLOAT_H_
+#define API_TEST_AUDIOPROC_FLOAT_H_
+
+#include <memory>
+#include <vector>
+
+#include "modules/audio_processing/include/audio_processing.h"
+
+namespace webrtc {
+namespace test {
+
+// This is an interface for the audio processing simulation utility. This
+// utility can be used to simulate the audioprocessing module using a recording
+// (either an AEC dump or wav files), and generate the output as a wav file.
+// Any audio_processing object specified in the input is used for the
+// simulation. The optional `audio_processing` object provides the
+// AudioProcessing instance that is used during the simulation. Note that when
+// the audio_processing object is specified all functionality that relies on
+// using the AudioProcessingBuilder is deactivated, since the AudioProcessing
+// object is already created and the builder is not used in the simulation. It
+// is needed to pass the command line flags as `argc` and `argv`, so these can
+// be interpreted properly by the utility. To see a list of all supported
+// command line flags, run the executable with the '--help' flag.
+int AudioprocFloat(rtc::scoped_refptr<AudioProcessing> audio_processing,
+ int argc,
+ char* argv[]);
+
+// This is an interface for the audio processing simulation utility. This
+// utility can be used to simulate the audioprocessing module using a recording
+// (either an AEC dump or wav files), and generate the output as a wav file.
+// The `ap_builder` object will be used to create the AudioProcessing instance
+// that is used during the simulation. The `ap_builder` supports setting of
+// injectable components, which will be passed on to the created AudioProcessing
+// instance. It is needed to pass the command line flags as `argc` and `argv`,
+// so these can be interpreted properly by the utility.
+// To get a fully-working audioproc_f utility, all that is needed is to write a
+// main function, create an AudioProcessingBuilder, optionally set custom
+// processing components on it, and pass the builder together with the command
+// line arguments into this function.
+// To see a list of all supported command line flags, run the executable with
+// the '--help' flag.
+int AudioprocFloat(std::unique_ptr<AudioProcessingBuilder> ap_builder,
+ int argc,
+ char* argv[]);
+
+// Interface for the audio processing simulation utility, which is similar to
+// the one above, but which adds the option of receiving the input as a string
+// and returning the output as an array. The first three arguments fulfill the
+// same purpose as above. Pass the `input_aecdump` to provide the content of an
+// AEC dump file as a string. After the simulation is completed,
+// `processed_capture_samples` will contain the the samples processed on the
+// capture side.
+int AudioprocFloat(std::unique_ptr<AudioProcessingBuilder> ap_builder,
+ int argc,
+ char* argv[],
+ absl::string_view input_aecdump,
+ std::vector<float>* processed_capture_samples);
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_AUDIOPROC_FLOAT_H_
diff --git a/third_party/libwebrtc/api/test/compile_all_headers.cc b/third_party/libwebrtc/api/test/compile_all_headers.cc
new file mode 100644
index 0000000000..1fcf63e97b
--- /dev/null
+++ b/third_party/libwebrtc/api/test/compile_all_headers.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 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.
+ */
+
+// This file verifies that all include files in this directory can be
+// compiled without errors or other required includes.
+
+// Note: The following header files are not not tested here, as their
+// associated targets are not included in all configurations.
+// "api/test/audioproc_float.h"
+// "api/test/create_video_quality_test_fixture.h"
+// "api/test/neteq_simulator_factory.h"
+// "api/test/video_quality_test_fixture.h"
+// The following header files are also not tested:
+// "api/test/create_simulcast_test_fixture.h"
+// "api/test/create_videocodec_test_fixture.h"
+// "api/test/neteq_simulator.h"
+// "api/test/simulated_network.h"
+// "api/test/simulcast_test_fixture.h"
+// "api/test/test_dependency_factory.h"
+// "api/test/videocodec_test_fixture.h"
+// "api/test/videocodec_test_stats.h"
+
+#include "api/test/fake_frame_decryptor.h"
+#include "api/test/fake_frame_encryptor.h"
+#include "api/test/mock_async_dns_resolver.h"
+#include "api/test/mock_audio_mixer.h"
+#include "api/test/mock_audio_sink.h"
+#include "api/test/mock_data_channel.h"
+#include "api/test/mock_dtmf_sender.h"
+#include "api/test/mock_frame_decryptor.h"
+#include "api/test/mock_frame_encryptor.h"
+#include "api/test/mock_media_stream_interface.h"
+#include "api/test/mock_peer_connection_factory_interface.h"
+#include "api/test/mock_peerconnectioninterface.h"
+#include "api/test/mock_rtp_transceiver.h"
+#include "api/test/mock_rtpreceiver.h"
+#include "api/test/mock_rtpsender.h"
+#include "api/test/mock_session_description_interface.h"
+#include "api/test/mock_transformable_video_frame.h"
+#include "api/test/mock_video_bitrate_allocator.h"
+#include "api/test/mock_video_bitrate_allocator_factory.h"
+#include "api/test/mock_video_decoder.h"
+#include "api/test/mock_video_decoder_factory.h"
+#include "api/test/mock_video_encoder.h"
+#include "api/test/mock_video_encoder_factory.h"
+#include "api/test/mock_video_track.h"
diff --git a/third_party/libwebrtc/api/test/create_frame_generator.cc b/third_party/libwebrtc/api/test/create_frame_generator.cc
new file mode 100644
index 0000000000..5e6fb3228b
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_frame_generator.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/test/create_frame_generator.h"
+
+#include <cstdio>
+#include <utility>
+
+#include "rtc_base/checks.h"
+#include "test/frame_generator.h"
+#include "test/testsupport/ivf_video_frame_generator.h"
+
+namespace webrtc {
+namespace test {
+
+std::unique_ptr<FrameGeneratorInterface> CreateSquareFrameGenerator(
+ int width,
+ int height,
+ absl::optional<FrameGeneratorInterface::OutputType> type,
+ absl::optional<int> num_squares) {
+ return std::make_unique<SquareGenerator>(
+ width, height, type.value_or(FrameGeneratorInterface::OutputType::kI420),
+ num_squares.value_or(10));
+}
+
+std::unique_ptr<FrameGeneratorInterface> CreateFromYuvFileFrameGenerator(
+ std::vector<std::string> filenames,
+ size_t width,
+ size_t height,
+ int frame_repeat_count) {
+ RTC_DCHECK(!filenames.empty());
+ std::vector<FILE*> files;
+ for (const std::string& filename : filenames) {
+ FILE* file = fopen(filename.c_str(), "rb");
+ RTC_DCHECK(file != nullptr) << "Failed to open: '" << filename << "'\n";
+ files.push_back(file);
+ }
+
+ return std::make_unique<YuvFileGenerator>(files, width, height,
+ frame_repeat_count);
+}
+
+std::unique_ptr<FrameGeneratorInterface> CreateFromNV12FileFrameGenerator(
+ std::vector<std::string> filenames,
+ size_t width,
+ size_t height,
+ int frame_repeat_count) {
+ RTC_DCHECK(!filenames.empty());
+ std::vector<FILE*> files;
+ for (const std::string& filename : filenames) {
+ FILE* file = fopen(filename.c_str(), "rb");
+ RTC_DCHECK(file != nullptr) << "Failed to open: '" << filename << "'\n";
+ files.push_back(file);
+ }
+
+ return std::make_unique<NV12FileGenerator>(files, width, height,
+ frame_repeat_count);
+}
+
+std::unique_ptr<FrameGeneratorInterface> CreateFromIvfFileFrameGenerator(
+ std::string filename) {
+ return std::make_unique<IvfVideoFrameGenerator>(std::move(filename));
+}
+
+std::unique_ptr<FrameGeneratorInterface>
+CreateScrollingInputFromYuvFilesFrameGenerator(
+ Clock* clock,
+ std::vector<std::string> filenames,
+ size_t source_width,
+ size_t source_height,
+ size_t target_width,
+ size_t target_height,
+ int64_t scroll_time_ms,
+ int64_t pause_time_ms) {
+ RTC_DCHECK(!filenames.empty());
+ std::vector<FILE*> files;
+ for (const std::string& filename : filenames) {
+ FILE* file = fopen(filename.c_str(), "rb");
+ RTC_DCHECK(file != nullptr);
+ files.push_back(file);
+ }
+
+ return std::make_unique<ScrollingImageFrameGenerator>(
+ clock, files, source_width, source_height, target_width, target_height,
+ scroll_time_ms, pause_time_ms);
+}
+
+std::unique_ptr<FrameGeneratorInterface>
+CreateSlideFrameGenerator(int width, int height, int frame_repeat_count) {
+ return std::make_unique<SlideGenerator>(width, height, frame_repeat_count);
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_frame_generator.h b/third_party/libwebrtc/api/test/create_frame_generator.h
new file mode 100644
index 0000000000..70be0c4e8e
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_frame_generator.h
@@ -0,0 +1,85 @@
+/*
+ * 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 API_TEST_CREATE_FRAME_GENERATOR_H_
+#define API_TEST_CREATE_FRAME_GENERATOR_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/test/frame_generator_interface.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+namespace test {
+
+// Creates a frame generator that produces frames with small squares that
+// move randomly towards the lower right corner.
+// `type` has the default value FrameGeneratorInterface::OutputType::I420.
+// `num_squares` has the default value 10.
+std::unique_ptr<FrameGeneratorInterface> CreateSquareFrameGenerator(
+ int width,
+ int height,
+ absl::optional<FrameGeneratorInterface::OutputType> type,
+ absl::optional<int> num_squares);
+
+// Creates a frame generator that repeatedly plays a set of yuv files.
+// The frame_repeat_count determines how many times each frame is shown,
+// with 1 = show each frame once, etc.
+std::unique_ptr<FrameGeneratorInterface> CreateFromYuvFileFrameGenerator(
+ std::vector<std::string> filenames,
+ size_t width,
+ size_t height,
+ int frame_repeat_count);
+
+// Creates a frame generator that repeatedly plays a set of nv12 files.
+// The frame_repeat_count determines how many times each frame is shown,
+// with 1 = show each frame once, etc.
+std::unique_ptr<FrameGeneratorInterface> CreateFromNV12FileFrameGenerator(
+ std::vector<std::string> filenames,
+ size_t width,
+ size_t height,
+ int frame_repeat_count = 1);
+
+// Creates a frame generator that repeatedly plays an ivf file.
+std::unique_ptr<FrameGeneratorInterface> CreateFromIvfFileFrameGenerator(
+ std::string filename);
+
+// Creates a frame generator which takes a set of yuv files (wrapping a
+// frame generator created by CreateFromYuvFile() above), but outputs frames
+// that have been cropped to specified resolution: source_width/source_height
+// is the size of the source images, target_width/target_height is the size of
+// the cropped output. For each source image read, the cropped viewport will
+// be scrolled top to bottom/left to right for scroll_tim_ms milliseconds.
+// After that the image will stay in place for pause_time_ms milliseconds,
+// and then this will be repeated with the next file from the input set.
+std::unique_ptr<FrameGeneratorInterface>
+CreateScrollingInputFromYuvFilesFrameGenerator(
+ Clock* clock,
+ std::vector<std::string> filenames,
+ size_t source_width,
+ size_t source_height,
+ size_t target_width,
+ size_t target_height,
+ int64_t scroll_time_ms,
+ int64_t pause_time_ms);
+
+// Creates a frame generator that produces randomly generated slides. It fills
+// the frames with randomly sized and colored squares.
+// `frame_repeat_count` determines how many times each slide is shown.
+std::unique_ptr<FrameGeneratorInterface>
+CreateSlideFrameGenerator(int width, int height, int frame_repeat_count);
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_FRAME_GENERATOR_H_
diff --git a/third_party/libwebrtc/api/test/create_network_emulation_manager.cc b/third_party/libwebrtc/api/test/create_network_emulation_manager.cc
new file mode 100644
index 0000000000..f5d5a1bc88
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_network_emulation_manager.cc
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/test/create_network_emulation_manager.h"
+
+#include <memory>
+
+#include "test/network/network_emulation_manager.h"
+
+namespace webrtc {
+
+std::unique_ptr<NetworkEmulationManager> CreateNetworkEmulationManager(
+ TimeMode time_mode,
+ EmulatedNetworkStatsGatheringMode stats_gathering_mode) {
+ return std::make_unique<test::NetworkEmulationManagerImpl>(
+ time_mode, stats_gathering_mode);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_network_emulation_manager.h b/third_party/libwebrtc/api/test/create_network_emulation_manager.h
new file mode 100644
index 0000000000..941b2b1c52
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_network_emulation_manager.h
@@ -0,0 +1,28 @@
+/*
+ * 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 API_TEST_CREATE_NETWORK_EMULATION_MANAGER_H_
+#define API_TEST_CREATE_NETWORK_EMULATION_MANAGER_H_
+
+#include <memory>
+
+#include "api/test/network_emulation_manager.h"
+
+namespace webrtc {
+
+// Returns a non-null NetworkEmulationManager instance.
+std::unique_ptr<NetworkEmulationManager> CreateNetworkEmulationManager(
+ TimeMode time_mode = TimeMode::kRealTime,
+ EmulatedNetworkStatsGatheringMode stats_gathering_mode =
+ EmulatedNetworkStatsGatheringMode::kDefault);
+
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_NETWORK_EMULATION_MANAGER_H_
diff --git a/third_party/libwebrtc/api/test/create_peer_connection_quality_test_frame_generator.cc b/third_party/libwebrtc/api/test/create_peer_connection_quality_test_frame_generator.cc
new file mode 100644
index 0000000000..a1c53635f9
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_peer_connection_quality_test_frame_generator.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 "api/test/create_peer_connection_quality_test_frame_generator.h"
+
+#include <utility>
+#include <vector>
+
+#include "api/test/create_frame_generator.h"
+#include "api/test/pclf/media_configuration.h"
+#include "rtc_base/checks.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+void ValidateScreenShareConfig(const VideoConfig& video_config,
+ const ScreenShareConfig& screen_share_config) {
+ if (screen_share_config.slides_yuv_file_names.empty()) {
+ if (screen_share_config.scrolling_params) {
+ // If we have scrolling params, then its `source_width` and `source_heigh`
+ // will be used as width and height of video input, so we have to validate
+ // it against width and height of default input.
+ RTC_CHECK_EQ(screen_share_config.scrolling_params->source_width,
+ kDefaultSlidesWidth);
+ RTC_CHECK_EQ(screen_share_config.scrolling_params->source_height,
+ kDefaultSlidesHeight);
+ } else {
+ RTC_CHECK_EQ(video_config.width, kDefaultSlidesWidth);
+ RTC_CHECK_EQ(video_config.height, kDefaultSlidesHeight);
+ }
+ }
+ if (screen_share_config.scrolling_params) {
+ RTC_CHECK_LE(screen_share_config.scrolling_params->duration,
+ screen_share_config.slide_change_interval);
+ RTC_CHECK_GE(screen_share_config.scrolling_params->source_width,
+ video_config.width);
+ RTC_CHECK_GE(screen_share_config.scrolling_params->source_height,
+ video_config.height);
+ }
+}
+
+std::unique_ptr<test::FrameGeneratorInterface> CreateSquareFrameGenerator(
+ const VideoConfig& video_config,
+ absl::optional<test::FrameGeneratorInterface::OutputType> type) {
+ return test::CreateSquareFrameGenerator(
+ video_config.width, video_config.height, std::move(type), absl::nullopt);
+}
+
+std::unique_ptr<test::FrameGeneratorInterface> CreateFromYuvFileFrameGenerator(
+ const VideoConfig& video_config,
+ std::string filename) {
+ return test::CreateFromYuvFileFrameGenerator(
+ {std::move(filename)}, video_config.width, video_config.height,
+ /*frame_repeat_count=*/1);
+}
+
+std::unique_ptr<test::FrameGeneratorInterface> CreateScreenShareFrameGenerator(
+ const VideoConfig& video_config,
+ const ScreenShareConfig& screen_share_config) {
+ ValidateScreenShareConfig(video_config, screen_share_config);
+ if (screen_share_config.generate_slides) {
+ return test::CreateSlideFrameGenerator(
+ video_config.width, video_config.height,
+ screen_share_config.slide_change_interval.seconds() * video_config.fps);
+ }
+ std::vector<std::string> slides = screen_share_config.slides_yuv_file_names;
+ if (slides.empty()) {
+ // If slides is empty we need to add default slides as source. In such case
+ // video width and height is validated to be equal to kDefaultSlidesWidth
+ // and kDefaultSlidesHeight.
+ slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv"));
+ slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv"));
+ slides.push_back(test::ResourcePath("photo_1850_1110", "yuv"));
+ slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv"));
+ }
+ if (!screen_share_config.scrolling_params) {
+ // Cycle image every slide_change_interval seconds.
+ return test::CreateFromYuvFileFrameGenerator(
+ slides, video_config.width, video_config.height,
+ screen_share_config.slide_change_interval.seconds() * video_config.fps);
+ }
+
+ TimeDelta pause_duration = screen_share_config.slide_change_interval -
+ screen_share_config.scrolling_params->duration;
+ RTC_DCHECK(pause_duration >= TimeDelta::Zero());
+ return test::CreateScrollingInputFromYuvFilesFrameGenerator(
+ Clock::GetRealTimeClock(), slides,
+ screen_share_config.scrolling_params->source_width,
+ screen_share_config.scrolling_params->source_height, video_config.width,
+ video_config.height, screen_share_config.scrolling_params->duration.ms(),
+ pause_duration.ms());
+}
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_peer_connection_quality_test_frame_generator.h b/third_party/libwebrtc/api/test/create_peer_connection_quality_test_frame_generator.h
new file mode 100644
index 0000000000..62043d140a
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_peer_connection_quality_test_frame_generator.h
@@ -0,0 +1,44 @@
+/*
+ * 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 API_TEST_CREATE_PEER_CONNECTION_QUALITY_TEST_FRAME_GENERATOR_H_
+#define API_TEST_CREATE_PEER_CONNECTION_QUALITY_TEST_FRAME_GENERATOR_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/types/optional.h"
+#include "api/test/frame_generator_interface.h"
+#include "api/test/pclf/media_configuration.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// Creates a frame generator that produces frames with small squares that move
+// randomly towards the lower right corner. `type` has the default value
+// FrameGeneratorInterface::OutputType::I420. video_config specifies frame
+// weight and height.
+std::unique_ptr<test::FrameGeneratorInterface> CreateSquareFrameGenerator(
+ const VideoConfig& video_config,
+ absl::optional<test::FrameGeneratorInterface::OutputType> type);
+
+// Creates a frame generator that plays frames from the yuv file.
+std::unique_ptr<test::FrameGeneratorInterface> CreateFromYuvFileFrameGenerator(
+ const VideoConfig& video_config,
+ std::string filename);
+
+// Creates a proper frame generator for testing screen sharing.
+std::unique_ptr<test::FrameGeneratorInterface> CreateScreenShareFrameGenerator(
+ const VideoConfig& video_config,
+ const ScreenShareConfig& screen_share_config);
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_PEER_CONNECTION_QUALITY_TEST_FRAME_GENERATOR_H_
diff --git a/third_party/libwebrtc/api/test/create_peerconnection_quality_test_fixture.cc b/third_party/libwebrtc/api/test/create_peerconnection_quality_test_fixture.cc
new file mode 100644
index 0000000000..e156991ed4
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_peerconnection_quality_test_fixture.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/test/create_peerconnection_quality_test_fixture.h"
+
+#include <memory>
+#include <utility>
+
+#include "api/test/metrics/global_metrics_logger_and_exporter.h"
+#include "api/test/time_controller.h"
+#include "test/pc/e2e/peer_connection_quality_test.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+std::unique_ptr<PeerConnectionE2EQualityTestFixture>
+CreatePeerConnectionE2EQualityTestFixture(
+ std::string test_case_name,
+ TimeController& time_controller,
+ std::unique_ptr<AudioQualityAnalyzerInterface> audio_quality_analyzer,
+ std::unique_ptr<VideoQualityAnalyzerInterface> video_quality_analyzer) {
+ return std::make_unique<PeerConnectionE2EQualityTest>(
+ std::move(test_case_name), time_controller,
+ std::move(audio_quality_analyzer), std::move(video_quality_analyzer),
+ test::GetGlobalMetricsLogger());
+}
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_peerconnection_quality_test_fixture.h b/third_party/libwebrtc/api/test/create_peerconnection_quality_test_fixture.h
new file mode 100644
index 0000000000..a0b0d08dd4
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_peerconnection_quality_test_fixture.h
@@ -0,0 +1,43 @@
+/*
+ * 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 API_TEST_CREATE_PEERCONNECTION_QUALITY_TEST_FIXTURE_H_
+#define API_TEST_CREATE_PEERCONNECTION_QUALITY_TEST_FIXTURE_H_
+
+#include <memory>
+#include <string>
+
+#include "api/test/audio_quality_analyzer_interface.h"
+#include "api/test/peerconnection_quality_test_fixture.h"
+#include "api/test/time_controller.h"
+#include "api/test/video_quality_analyzer_interface.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// API is in development. Can be changed/removed without notice.
+
+// Create test fixture to establish test call between Alice and Bob.
+// During the test Alice will be caller and Bob will answer the call.
+// `test_case_name` is a name of test case, that will be used for all metrics
+// reporting.
+// `time_controller` is used to manage all rtc::Thread's and TaskQueue
+// instances. Instance of `time_controller` have to outlive created fixture.
+// Returns a non-null PeerConnectionE2EQualityTestFixture instance.
+std::unique_ptr<PeerConnectionE2EQualityTestFixture>
+CreatePeerConnectionE2EQualityTestFixture(
+ std::string test_case_name,
+ TimeController& time_controller,
+ std::unique_ptr<AudioQualityAnalyzerInterface> audio_quality_analyzer,
+ std::unique_ptr<VideoQualityAnalyzerInterface> video_quality_analyzer);
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_PEERCONNECTION_QUALITY_TEST_FIXTURE_H_
diff --git a/third_party/libwebrtc/api/test/create_simulcast_test_fixture.cc b/third_party/libwebrtc/api/test/create_simulcast_test_fixture.cc
new file mode 100644
index 0000000000..024145dff0
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_simulcast_test_fixture.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 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 "api/test/create_simulcast_test_fixture.h"
+
+#include <memory>
+#include <utility>
+
+#include "api/test/simulcast_test_fixture.h"
+#include "modules/video_coding/utility/simulcast_test_fixture_impl.h"
+
+namespace webrtc {
+namespace test {
+
+std::unique_ptr<SimulcastTestFixture> CreateSimulcastTestFixture(
+ std::unique_ptr<VideoEncoderFactory> encoder_factory,
+ std::unique_ptr<VideoDecoderFactory> decoder_factory,
+ SdpVideoFormat video_format) {
+ return std::make_unique<SimulcastTestFixtureImpl>(
+ std::move(encoder_factory), std::move(decoder_factory), video_format);
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_simulcast_test_fixture.h b/third_party/libwebrtc/api/test/create_simulcast_test_fixture.h
new file mode 100644
index 0000000000..87f229c009
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_simulcast_test_fixture.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_CREATE_SIMULCAST_TEST_FIXTURE_H_
+#define API_TEST_CREATE_SIMULCAST_TEST_FIXTURE_H_
+
+#include <memory>
+
+#include "api/test/simulcast_test_fixture.h"
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+
+namespace webrtc {
+namespace test {
+
+std::unique_ptr<SimulcastTestFixture> CreateSimulcastTestFixture(
+ std::unique_ptr<VideoEncoderFactory> encoder_factory,
+ std::unique_ptr<VideoDecoderFactory> decoder_factory,
+ SdpVideoFormat video_format);
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_SIMULCAST_TEST_FIXTURE_H_
diff --git a/third_party/libwebrtc/api/test/create_time_controller.cc b/third_party/libwebrtc/api/test/create_time_controller.cc
new file mode 100644
index 0000000000..d198f2b0fe
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_time_controller.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/test/create_time_controller.h"
+
+#include <memory>
+
+#include "call/call.h"
+#include "call/rtp_transport_config.h"
+#include "call/rtp_transport_controller_send_factory_interface.h"
+#include "test/time_controller/external_time_controller.h"
+#include "test/time_controller/simulated_time_controller.h"
+
+namespace webrtc {
+
+std::unique_ptr<TimeController> CreateTimeController(
+ ControlledAlarmClock* alarm) {
+ return std::make_unique<ExternalTimeController>(alarm);
+}
+
+std::unique_ptr<TimeController> CreateSimulatedTimeController() {
+ return std::make_unique<GlobalSimulatedTimeController>(
+ Timestamp::Seconds(10000));
+}
+
+std::unique_ptr<CallFactoryInterface> CreateTimeControllerBasedCallFactory(
+ TimeController* time_controller) {
+ class TimeControllerBasedCallFactory : public CallFactoryInterface {
+ public:
+ explicit TimeControllerBasedCallFactory(TimeController* time_controller)
+ : time_controller_(time_controller) {}
+ Call* CreateCall(const Call::Config& config) override {
+ RtpTransportConfig transportConfig = config.ExtractTransportConfig();
+
+ return Call::Create(config, time_controller_->GetClock(),
+ config.rtp_transport_controller_send_factory->Create(
+ transportConfig, time_controller_->GetClock()));
+ }
+
+ private:
+ TimeController* time_controller_;
+ };
+ return std::make_unique<TimeControllerBasedCallFactory>(time_controller);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_time_controller.h b/third_party/libwebrtc/api/test/create_time_controller.h
new file mode 100644
index 0000000000..e7bc9cb465
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_time_controller.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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 API_TEST_CREATE_TIME_CONTROLLER_H_
+#define API_TEST_CREATE_TIME_CONTROLLER_H_
+
+#include <memory>
+
+#include "api/call/call_factory_interface.h"
+#include "api/test/time_controller.h"
+
+namespace webrtc {
+
+// Creates a time coltroller that wraps `alarm`.
+std::unique_ptr<TimeController> CreateTimeController(
+ ControlledAlarmClock* alarm);
+
+// Creates a time controller that runs in simulated time.
+std::unique_ptr<TimeController> CreateSimulatedTimeController();
+
+// This is creates a call factory that creates Call instances that are backed by
+// a time controller.
+std::unique_ptr<CallFactoryInterface> CreateTimeControllerBasedCallFactory(
+ TimeController* time_controller);
+
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_TIME_CONTROLLER_H_
diff --git a/third_party/libwebrtc/api/test/create_time_controller_unittest.cc b/third_party/libwebrtc/api/test/create_time_controller_unittest.cc
new file mode 100644
index 0000000000..0ea868c5cc
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_time_controller_unittest.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/test/create_time_controller.h"
+
+#include "api/test/time_controller.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+class FakeAlarm : public ControlledAlarmClock {
+ public:
+ explicit FakeAlarm(Timestamp start_time);
+
+ Clock* GetClock() override;
+ bool ScheduleAlarmAt(Timestamp deadline) override;
+ void SetCallback(std::function<void()> callback) override;
+ void Sleep(TimeDelta duration) override;
+
+ private:
+ SimulatedClock clock_;
+ Timestamp deadline_;
+ std::function<void()> callback_;
+};
+
+FakeAlarm::FakeAlarm(Timestamp start_time)
+ : clock_(start_time),
+ deadline_(Timestamp::PlusInfinity()),
+ callback_([] {}) {}
+
+Clock* FakeAlarm::GetClock() {
+ return &clock_;
+}
+
+bool FakeAlarm::ScheduleAlarmAt(Timestamp deadline) {
+ if (deadline < deadline_) {
+ deadline_ = deadline;
+ return true;
+ }
+ return false;
+}
+
+void FakeAlarm::SetCallback(std::function<void()> callback) {
+ callback_ = callback;
+}
+
+void FakeAlarm::Sleep(TimeDelta duration) {
+ Timestamp end_time = clock_.CurrentTime() + duration;
+
+ while (deadline_ <= end_time) {
+ clock_.AdvanceTime(deadline_ - clock_.CurrentTime());
+ deadline_ = Timestamp::PlusInfinity();
+ callback_();
+ }
+
+ clock_.AdvanceTime(end_time - clock_.CurrentTime());
+}
+
+TEST(CreateTimeControllerTest, CreatesNonNullController) {
+ FakeAlarm alarm(Timestamp::Millis(100));
+ EXPECT_NE(CreateTimeController(&alarm), nullptr);
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_video_codec_tester.cc b/third_party/libwebrtc/api/test/create_video_codec_tester.cc
new file mode 100644
index 0000000000..a1efefdb48
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_video_codec_tester.cc
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022 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 "api/test/create_video_codec_tester.h"
+
+#include <memory>
+#include <utility>
+
+#include "api/test/video_codec_tester.h"
+#include "modules/video_coding/codecs/test/video_codec_tester_impl.h"
+
+namespace webrtc {
+namespace test {
+
+std::unique_ptr<VideoCodecTester> CreateVideoCodecTester() {
+ return std::make_unique<VideoCodecTesterImpl>();
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_video_codec_tester.h b/third_party/libwebrtc/api/test/create_video_codec_tester.h
new file mode 100644
index 0000000000..c68864ce85
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_video_codec_tester.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_CREATE_VIDEO_CODEC_TESTER_H_
+#define API_TEST_CREATE_VIDEO_CODEC_TESTER_H_
+
+#include <memory>
+
+#include "api/test/video_codec_tester.h"
+
+namespace webrtc {
+namespace test {
+
+std::unique_ptr<VideoCodecTester> CreateVideoCodecTester();
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_VIDEO_CODEC_TESTER_H_
diff --git a/third_party/libwebrtc/api/test/create_video_quality_test_fixture.cc b/third_party/libwebrtc/api/test/create_video_quality_test_fixture.cc
new file mode 100644
index 0000000000..1fa7d243cc
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_video_quality_test_fixture.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 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 "api/test/create_video_quality_test_fixture.h"
+
+#include <memory>
+#include <utility>
+
+#include "video/video_quality_test.h"
+
+namespace webrtc {
+
+std::unique_ptr<VideoQualityTestFixtureInterface>
+CreateVideoQualityTestFixture() {
+ // By default, we don't override the FEC module, so pass an empty factory.
+ return std::make_unique<VideoQualityTest>(nullptr);
+}
+
+std::unique_ptr<VideoQualityTestFixtureInterface> CreateVideoQualityTestFixture(
+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory) {
+ auto components =
+ std::make_unique<VideoQualityTestFixtureInterface::InjectionComponents>();
+ components->fec_controller_factory = std::move(fec_controller_factory);
+ return std::make_unique<VideoQualityTest>(std::move(components));
+}
+
+std::unique_ptr<VideoQualityTestFixtureInterface> CreateVideoQualityTestFixture(
+ std::unique_ptr<VideoQualityTestFixtureInterface::InjectionComponents>
+ components) {
+ return std::make_unique<VideoQualityTest>(std::move(components));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_video_quality_test_fixture.h b/third_party/libwebrtc/api/test/create_video_quality_test_fixture.h
new file mode 100644
index 0000000000..ed618fefc8
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_video_quality_test_fixture.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_CREATE_VIDEO_QUALITY_TEST_FIXTURE_H_
+#define API_TEST_CREATE_VIDEO_QUALITY_TEST_FIXTURE_H_
+
+#include <memory>
+
+#include "api/fec_controller.h"
+#include "api/test/video_quality_test_fixture.h"
+
+namespace webrtc {
+
+std::unique_ptr<VideoQualityTestFixtureInterface>
+CreateVideoQualityTestFixture();
+
+std::unique_ptr<VideoQualityTestFixtureInterface> CreateVideoQualityTestFixture(
+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory);
+
+std::unique_ptr<VideoQualityTestFixtureInterface> CreateVideoQualityTestFixture(
+ std::unique_ptr<VideoQualityTestFixtureInterface::InjectionComponents>
+ components);
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_VIDEO_QUALITY_TEST_FIXTURE_H_
diff --git a/third_party/libwebrtc/api/test/create_videocodec_test_fixture.cc b/third_party/libwebrtc/api/test/create_videocodec_test_fixture.cc
new file mode 100644
index 0000000000..1f618e5db8
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_videocodec_test_fixture.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 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 "api/test/create_videocodec_test_fixture.h"
+
+#include <memory>
+#include <utility>
+
+#include "api/test/videocodec_test_fixture.h"
+#include "modules/video_coding/codecs/test/videocodec_test_fixture_impl.h"
+
+namespace webrtc {
+namespace test {
+
+using Config = VideoCodecTestFixture::Config;
+
+std::unique_ptr<VideoCodecTestFixture> CreateVideoCodecTestFixture(
+ const Config& config) {
+ return std::make_unique<VideoCodecTestFixtureImpl>(config);
+}
+
+std::unique_ptr<VideoCodecTestFixture> CreateVideoCodecTestFixture(
+ const Config& config,
+ std::unique_ptr<VideoDecoderFactory> decoder_factory,
+ std::unique_ptr<VideoEncoderFactory> encoder_factory) {
+ return std::make_unique<VideoCodecTestFixtureImpl>(
+ config, std::move(decoder_factory), std::move(encoder_factory));
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/create_videocodec_test_fixture.h b/third_party/libwebrtc/api/test/create_videocodec_test_fixture.h
new file mode 100644
index 0000000000..7a44f6b058
--- /dev/null
+++ b/third_party/libwebrtc/api/test/create_videocodec_test_fixture.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_CREATE_VIDEOCODEC_TEST_FIXTURE_H_
+#define API_TEST_CREATE_VIDEOCODEC_TEST_FIXTURE_H_
+
+#include <memory>
+
+#include "api/test/videocodec_test_fixture.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+
+namespace webrtc {
+namespace test {
+
+std::unique_ptr<VideoCodecTestFixture> CreateVideoCodecTestFixture(
+ const VideoCodecTestFixture::Config& config);
+
+std::unique_ptr<VideoCodecTestFixture> CreateVideoCodecTestFixture(
+ const VideoCodecTestFixture::Config& config,
+ std::unique_ptr<VideoDecoderFactory> decoder_factory,
+ std::unique_ptr<VideoEncoderFactory> encoder_factory);
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_CREATE_VIDEOCODEC_TEST_FIXTURE_H_
diff --git a/third_party/libwebrtc/api/test/fake_frame_decryptor.cc b/third_party/libwebrtc/api/test/fake_frame_decryptor.cc
new file mode 100644
index 0000000000..16cb1bd3b6
--- /dev/null
+++ b/third_party/libwebrtc/api/test/fake_frame_decryptor.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018 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 "api/test/fake_frame_decryptor.h"
+
+#include <vector>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+FakeFrameDecryptor::FakeFrameDecryptor(uint8_t fake_key,
+ uint8_t expected_postfix_byte)
+ : fake_key_(fake_key), expected_postfix_byte_(expected_postfix_byte) {}
+
+FakeFrameDecryptor::Result FakeFrameDecryptor::Decrypt(
+ cricket::MediaType media_type,
+ const std::vector<uint32_t>& csrcs,
+ rtc::ArrayView<const uint8_t> additional_data,
+ rtc::ArrayView<const uint8_t> encrypted_frame,
+ rtc::ArrayView<uint8_t> frame) {
+ if (fail_decryption_) {
+ return Result(Status::kFailedToDecrypt, 0);
+ }
+
+ RTC_CHECK_EQ(frame.size() + 1, encrypted_frame.size());
+ for (size_t i = 0; i < frame.size(); i++) {
+ frame[i] = encrypted_frame[i] ^ fake_key_;
+ }
+
+ if (encrypted_frame[frame.size()] != expected_postfix_byte_) {
+ return Result(Status::kFailedToDecrypt, 0);
+ }
+
+ return Result(Status::kOk, frame.size());
+}
+
+size_t FakeFrameDecryptor::GetMaxPlaintextByteSize(
+ cricket::MediaType media_type,
+ size_t encrypted_frame_size) {
+ return encrypted_frame_size - 1;
+}
+
+void FakeFrameDecryptor::SetFakeKey(uint8_t fake_key) {
+ fake_key_ = fake_key;
+}
+
+uint8_t FakeFrameDecryptor::GetFakeKey() const {
+ return fake_key_;
+}
+
+void FakeFrameDecryptor::SetExpectedPostfixByte(uint8_t expected_postfix_byte) {
+ expected_postfix_byte_ = expected_postfix_byte;
+}
+
+uint8_t FakeFrameDecryptor::GetExpectedPostfixByte() const {
+ return expected_postfix_byte_;
+}
+
+void FakeFrameDecryptor::SetFailDecryption(bool fail_decryption) {
+ fail_decryption_ = fail_decryption;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/fake_frame_decryptor.h b/third_party/libwebrtc/api/test/fake_frame_decryptor.h
new file mode 100644
index 0000000000..783bc805c4
--- /dev/null
+++ b/third_party/libwebrtc/api/test/fake_frame_decryptor.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018 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 API_TEST_FAKE_FRAME_DECRYPTOR_H_
+#define API_TEST_FAKE_FRAME_DECRYPTOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/crypto/frame_decryptor_interface.h"
+#include "api/media_types.h"
+
+namespace webrtc {
+
+// The FakeFrameDecryptor is a TEST ONLY fake implementation of the
+// FrameDecryptorInterface. It is constructed with a simple single digit key and
+// a fixed postfix byte. This is just to validate that the core code works
+// as expected.
+class FakeFrameDecryptor : public FrameDecryptorInterface {
+ public:
+ // Provide a key (0,255) and some postfix byte (0,255) this should match the
+ // byte you expect from the FakeFrameEncryptor.
+ explicit FakeFrameDecryptor(uint8_t fake_key = 0xAA,
+ uint8_t expected_postfix_byte = 255);
+ // Fake decryption that just xors the payload with the 1 byte key and checks
+ // the postfix byte. This will always fail if fail_decryption_ is set to true.
+ Result Decrypt(cricket::MediaType media_type,
+ const std::vector<uint32_t>& csrcs,
+ rtc::ArrayView<const uint8_t> additional_data,
+ rtc::ArrayView<const uint8_t> encrypted_frame,
+ rtc::ArrayView<uint8_t> frame) override;
+ // Always returns 1 less than the size of the encrypted frame.
+ size_t GetMaxPlaintextByteSize(cricket::MediaType media_type,
+ size_t encrypted_frame_size) override;
+ // Sets the fake key to use for encryption.
+ void SetFakeKey(uint8_t fake_key);
+ // Returns the fake key used for encryption.
+ uint8_t GetFakeKey() const;
+ // Set the Postfix byte that is expected in the encrypted payload.
+ void SetExpectedPostfixByte(uint8_t expected_postfix_byte);
+ // Returns the postfix byte that will be checked for in the encrypted payload.
+ uint8_t GetExpectedPostfixByte() const;
+ // If set to true will force all encryption to fail.
+ void SetFailDecryption(bool fail_decryption);
+ // Simple error codes for tests to validate against.
+ enum class FakeDecryptStatus : int {
+ OK = 0,
+ FORCED_FAILURE = 1,
+ INVALID_POSTFIX = 2
+ };
+
+ private:
+ uint8_t fake_key_ = 0;
+ uint8_t expected_postfix_byte_ = 0;
+ bool fail_decryption_ = false;
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_FAKE_FRAME_DECRYPTOR_H_
diff --git a/third_party/libwebrtc/api/test/fake_frame_encryptor.cc b/third_party/libwebrtc/api/test/fake_frame_encryptor.cc
new file mode 100644
index 0000000000..89d14aab88
--- /dev/null
+++ b/third_party/libwebrtc/api/test/fake_frame_encryptor.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 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 "api/test/fake_frame_encryptor.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+FakeFrameEncryptor::FakeFrameEncryptor(uint8_t fake_key, uint8_t postfix_byte)
+ : fake_key_(fake_key), postfix_byte_(postfix_byte) {}
+
+// FrameEncryptorInterface implementation
+int FakeFrameEncryptor::Encrypt(cricket::MediaType media_type,
+ uint32_t ssrc,
+ rtc::ArrayView<const uint8_t> additional_data,
+ rtc::ArrayView<const uint8_t> frame,
+ rtc::ArrayView<uint8_t> encrypted_frame,
+ size_t* bytes_written) {
+ if (fail_encryption_) {
+ return static_cast<int>(FakeEncryptionStatus::FORCED_FAILURE);
+ }
+
+ RTC_CHECK_EQ(frame.size() + 1, encrypted_frame.size());
+ for (size_t i = 0; i < frame.size(); i++) {
+ encrypted_frame[i] = frame[i] ^ fake_key_;
+ }
+
+ encrypted_frame[frame.size()] = postfix_byte_;
+ *bytes_written = encrypted_frame.size();
+ return static_cast<int>(FakeEncryptionStatus::OK);
+}
+
+size_t FakeFrameEncryptor::GetMaxCiphertextByteSize(
+ cricket::MediaType media_type,
+ size_t frame_size) {
+ return frame_size + 1;
+}
+
+void FakeFrameEncryptor::SetFakeKey(uint8_t fake_key) {
+ fake_key_ = fake_key;
+}
+
+uint8_t FakeFrameEncryptor::GetFakeKey() const {
+ return fake_key_;
+}
+
+void FakeFrameEncryptor::SetPostfixByte(uint8_t postfix_byte) {
+ postfix_byte_ = postfix_byte;
+}
+
+uint8_t FakeFrameEncryptor::GetPostfixByte() const {
+ return postfix_byte_;
+}
+
+void FakeFrameEncryptor::SetFailEncryption(bool fail_encryption) {
+ fail_encryption_ = fail_encryption;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/fake_frame_encryptor.h b/third_party/libwebrtc/api/test/fake_frame_encryptor.h
new file mode 100644
index 0000000000..074981b183
--- /dev/null
+++ b/third_party/libwebrtc/api/test/fake_frame_encryptor.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 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 API_TEST_FAKE_FRAME_ENCRYPTOR_H_
+#define API_TEST_FAKE_FRAME_ENCRYPTOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "api/array_view.h"
+#include "api/crypto/frame_encryptor_interface.h"
+#include "api/media_types.h"
+#include "rtc_base/ref_counted_object.h"
+
+namespace webrtc {
+
+// The FakeFrameEncryptor is a TEST ONLY fake implementation of the
+// FrameEncryptorInterface. It is constructed with a simple single digit key and
+// a fixed postfix byte. This is just to validate that the core code works
+// as expected.
+class FakeFrameEncryptor
+ : public rtc::RefCountedObject<FrameEncryptorInterface> {
+ public:
+ // Provide a key (0,255) and some postfix byte (0,255).
+ explicit FakeFrameEncryptor(uint8_t fake_key = 0xAA,
+ uint8_t postfix_byte = 255);
+ // Simply xors each payload with the provided fake key and adds the postfix
+ // bit to the end. This will always fail if fail_encryption_ is set to true.
+ int Encrypt(cricket::MediaType media_type,
+ uint32_t ssrc,
+ rtc::ArrayView<const uint8_t> additional_data,
+ rtc::ArrayView<const uint8_t> frame,
+ rtc::ArrayView<uint8_t> encrypted_frame,
+ size_t* bytes_written) override;
+ // Always returns 1 more than the size of the frame.
+ size_t GetMaxCiphertextByteSize(cricket::MediaType media_type,
+ size_t frame_size) override;
+ // Sets the fake key to use during encryption.
+ void SetFakeKey(uint8_t fake_key);
+ // Returns the fake key used during encryption.
+ uint8_t GetFakeKey() const;
+ // Set the postfix byte to use.
+ void SetPostfixByte(uint8_t expected_postfix_byte);
+ // Return a postfix byte added to each outgoing payload.
+ uint8_t GetPostfixByte() const;
+ // Force all encryptions to fail.
+ void SetFailEncryption(bool fail_encryption);
+
+ enum class FakeEncryptionStatus : int {
+ OK = 0,
+ FORCED_FAILURE = 1,
+ };
+
+ private:
+ uint8_t fake_key_ = 0;
+ uint8_t postfix_byte_ = 0;
+ bool fail_encryption_ = false;
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_FAKE_FRAME_ENCRYPTOR_H_
diff --git a/third_party/libwebrtc/api/test/frame_generator_interface.cc b/third_party/libwebrtc/api/test/frame_generator_interface.cc
new file mode 100644
index 0000000000..fe7b1e883d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/frame_generator_interface.cc
@@ -0,0 +1,34 @@
+/*
+ * 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 "api/test/frame_generator_interface.h"
+
+namespace webrtc {
+namespace test {
+
+// static
+const char* FrameGeneratorInterface::OutputTypeToString(
+ FrameGeneratorInterface::OutputType type) {
+ switch (type) {
+ case OutputType::kI420:
+ return "I420";
+ case OutputType::kI420A:
+ return "I420A";
+ case OutputType::kI010:
+ return "I010";
+ case OutputType::kNV12:
+ return "NV12";
+ default:
+ RTC_DCHECK_NOTREACHED();
+ }
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/frame_generator_interface.h b/third_party/libwebrtc/api/test/frame_generator_interface.h
new file mode 100644
index 0000000000..90e60debac
--- /dev/null
+++ b/third_party/libwebrtc/api/test/frame_generator_interface.h
@@ -0,0 +1,51 @@
+/*
+ * 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 API_TEST_FRAME_GENERATOR_INTERFACE_H_
+#define API_TEST_FRAME_GENERATOR_INTERFACE_H_
+
+#include <utility>
+
+#include "absl/types/optional.h"
+#include "api/scoped_refptr.h"
+#include "api/video/video_frame.h"
+#include "api/video/video_frame_buffer.h"
+
+namespace webrtc {
+namespace test {
+
+class FrameGeneratorInterface {
+ public:
+ struct VideoFrameData {
+ VideoFrameData(rtc::scoped_refptr<VideoFrameBuffer> buffer,
+ absl::optional<VideoFrame::UpdateRect> update_rect)
+ : buffer(std::move(buffer)), update_rect(update_rect) {}
+
+ rtc::scoped_refptr<VideoFrameBuffer> buffer;
+ absl::optional<VideoFrame::UpdateRect> update_rect;
+ };
+
+ enum class OutputType { kI420, kI420A, kI010, kNV12 };
+ static const char* OutputTypeToString(OutputType type);
+
+ virtual ~FrameGeneratorInterface() = default;
+
+ // Returns VideoFrameBuffer and area where most of update was done to set them
+ // on the VideoFrame object.
+ virtual VideoFrameData NextFrame() = 0;
+
+ // Change the capture resolution.
+ virtual void ChangeResolution(size_t width, size_t height) = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_FRAME_GENERATOR_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/test/metrics/BUILD.gn b/third_party/libwebrtc/api/test/metrics/BUILD.gn
new file mode 100644
index 0000000000..309b699329
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/BUILD.gn
@@ -0,0 +1,281 @@
+# Copyright (c) 2022 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.
+
+import("../../../webrtc.gni")
+if (rtc_enable_protobuf) {
+ import("//third_party/protobuf/proto_library.gni")
+}
+
+group("metrics") {
+ deps = [
+ ":global_metrics_logger_and_exporter",
+ ":metric",
+ ":metrics_accumulator",
+ ":metrics_exporter",
+ ":metrics_logger",
+ ":stdout_metrics_exporter",
+ ]
+}
+
+if (rtc_include_tests) {
+ group("metrics_unittests") {
+ testonly = true
+
+ deps = [
+ ":global_metrics_logger_and_exporter_test",
+ ":metrics_accumulator_test",
+ ":metrics_logger_test",
+ ":print_result_proxy_metrics_exporter_test",
+ ":stdout_metrics_exporter_test",
+ ]
+
+ if (rtc_enable_protobuf) {
+ deps += [
+ ":chrome_perf_dashboard_metrics_exporter_test",
+ ":metrics_set_proto_file_exporter_test",
+ ]
+ }
+ }
+}
+
+rtc_library("metric") {
+ visibility = [ "*" ]
+ sources = [
+ "metric.cc",
+ "metric.h",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ deps = [ "../../../api/units:timestamp" ]
+}
+
+rtc_library("metrics_logger") {
+ visibility = [ "*" ]
+ sources = [
+ "metrics_logger.cc",
+ "metrics_logger.h",
+ ]
+ deps = [
+ ":metric",
+ ":metrics_accumulator",
+ "../..:array_view",
+ "../../../rtc_base/synchronization:mutex",
+ "../../../system_wrappers",
+ "../../numerics",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_library("metrics_accumulator") {
+ visibility = [ "*" ]
+ sources = [
+ "metrics_accumulator.cc",
+ "metrics_accumulator.h",
+ ]
+ deps = [
+ ":metric",
+ "../../../rtc_base:macromagic",
+ "../../../rtc_base/synchronization:mutex",
+ "../../numerics",
+ "../../units:timestamp",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_library("metrics_exporter") {
+ visibility = [ "*" ]
+ sources = [ "metrics_exporter.h" ]
+ deps = [
+ ":metric",
+ "../..:array_view",
+ ]
+}
+
+rtc_library("stdout_metrics_exporter") {
+ visibility = [ "*" ]
+ sources = [
+ "stdout_metrics_exporter.cc",
+ "stdout_metrics_exporter.h",
+ ]
+ deps = [
+ ":metric",
+ ":metrics_exporter",
+ "../..:array_view",
+ "../../../rtc_base:stringutils",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_library("chrome_perf_dashboard_metrics_exporter") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [
+ "chrome_perf_dashboard_metrics_exporter.cc",
+ "chrome_perf_dashboard_metrics_exporter.h",
+ ]
+ deps = [
+ ":metric",
+ ":metrics_exporter",
+ "../../../api:array_view",
+ "../../../test:fileutils",
+ "../../../test:perf_test",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+if (rtc_enable_protobuf) {
+ proto_library("metric_proto") {
+ visibility = [ "*" ]
+ sources = [ "proto/metric.proto" ]
+ proto_out_dir = "api/test/metrics/proto"
+ cc_generator_options = "lite"
+ }
+}
+
+rtc_library("metrics_set_proto_file_exporter") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [
+ "metrics_set_proto_file_exporter.cc",
+ "metrics_set_proto_file_exporter.h",
+ ]
+ deps = [
+ ":metric",
+ ":metrics_exporter",
+ "../..:array_view",
+ "../../../rtc_base:logging",
+ "../../../test:fileutils",
+ ]
+
+ if (rtc_enable_protobuf) {
+ deps += [ ":metric_proto" ]
+ }
+}
+
+rtc_library("print_result_proxy_metrics_exporter") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [
+ "print_result_proxy_metrics_exporter.cc",
+ "print_result_proxy_metrics_exporter.h",
+ ]
+ deps = [
+ ":metric",
+ ":metrics_exporter",
+ "../..:array_view",
+ "../../../test:perf_test",
+ ]
+}
+
+rtc_library("global_metrics_logger_and_exporter") {
+ visibility = [ "*" ]
+ sources = [
+ "global_metrics_logger_and_exporter.cc",
+ "global_metrics_logger_and_exporter.h",
+ ]
+ deps = [
+ ":metrics_exporter",
+ ":metrics_logger",
+ "../../../rtc_base:checks",
+ "../../../system_wrappers",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("metrics_logger_test") {
+ testonly = true
+ sources = [ "metrics_logger_test.cc" ]
+ deps = [
+ ":metric",
+ ":metrics_logger",
+ "../../../system_wrappers",
+ "../../../test:test_support",
+ "../../numerics",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ }
+
+ rtc_library("metrics_accumulator_test") {
+ testonly = true
+ sources = [ "metrics_accumulator_test.cc" ]
+ deps = [
+ ":metric",
+ ":metrics_accumulator",
+ "../../../test:test_support",
+ "../../units:timestamp",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ }
+
+ rtc_library("stdout_metrics_exporter_test") {
+ testonly = true
+ sources = [ "stdout_metrics_exporter_test.cc" ]
+ deps = [
+ ":metric",
+ ":stdout_metrics_exporter",
+ "../../../test:test_support",
+ "../../units:timestamp",
+ ]
+ }
+
+ rtc_library("print_result_proxy_metrics_exporter_test") {
+ testonly = true
+ sources = [ "print_result_proxy_metrics_exporter_test.cc" ]
+ deps = [
+ ":metric",
+ ":print_result_proxy_metrics_exporter",
+ "../../../test:test_support",
+ "../../units:timestamp",
+ ]
+ }
+
+ rtc_library("global_metrics_logger_and_exporter_test") {
+ testonly = true
+ sources = [ "global_metrics_logger_and_exporter_test.cc" ]
+ deps = [
+ ":global_metrics_logger_and_exporter",
+ ":metric",
+ ":metrics_exporter",
+ ":metrics_logger",
+ "../../../system_wrappers",
+ "../../../test:test_support",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ }
+
+ if (rtc_enable_protobuf) {
+ rtc_library("metrics_set_proto_file_exporter_test") {
+ testonly = true
+ sources = [ "metrics_set_proto_file_exporter_test.cc" ]
+ deps = [
+ ":metric",
+ ":metric_proto",
+ ":metrics_set_proto_file_exporter",
+ "../../../rtc_base:protobuf_utils",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "../../units:timestamp",
+ ]
+ }
+
+ rtc_library("chrome_perf_dashboard_metrics_exporter_test") {
+ testonly = true
+ sources = [ "chrome_perf_dashboard_metrics_exporter_test.cc" ]
+ deps = [
+ ":chrome_perf_dashboard_metrics_exporter",
+ ":metric",
+ "../../../api/units:timestamp",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "//third_party/catapult/tracing/tracing:histogram",
+ ]
+ }
+ }
+}
diff --git a/third_party/libwebrtc/api/test/metrics/DEPS b/third_party/libwebrtc/api/test/metrics/DEPS
new file mode 100644
index 0000000000..74889c61c7
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/DEPS
@@ -0,0 +1,14 @@
+specific_include_rules = {
+ "metrics_logger_and_exporter\.h": [
+ "+rtc_base/synchronization/mutex.h",
+ "+system_wrappers/include/clock.h",
+ ],
+ "metrics_logger\.h": [
+ "+rtc_base/synchronization/mutex.h",
+ "+system_wrappers/include/clock.h",
+ ],
+ "metrics_accumulator\.h": [
+ "+rtc_base/synchronization/mutex.h",
+ "+rtc_base/thread_annotations.h",
+ ],
+}
diff --git a/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.cc b/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.cc
new file mode 100644
index 0000000000..018d110b12
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/chrome_perf_dashboard_metrics_exporter.h"
+
+#include <stdio.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/test/metrics/metric.h"
+#include "test/testsupport/file_utils.h"
+#include "test/testsupport/perf_test_histogram_writer.h"
+#include "test/testsupport/perf_test_result_writer.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+std::string ToChromePerfDashboardUnit(Unit unit) {
+ switch (unit) {
+ case Unit::kMilliseconds:
+ return "msBestFitFormat";
+ case Unit::kPercent:
+ return "n%";
+ case Unit::kBytes:
+ return "sizeInBytes";
+ case Unit::kKilobitsPerSecond:
+ // Chrome Perf Dashboard doesn't have kpbs units, so we change the unit
+ // and value accordingly.
+ return "bytesPerSecond";
+ case Unit::kHertz:
+ return "Hz";
+ case Unit::kUnitless:
+ return "unitless";
+ case Unit::kCount:
+ return "count";
+ }
+}
+
+double ToChromePerfDashboardValue(double value, Unit unit) {
+ switch (unit) {
+ case Unit::kKilobitsPerSecond:
+ // Chrome Perf Dashboard doesn't have kpbs units, so we change the unit
+ // and value accordingly.
+ return value * 1000 / 8;
+ default:
+ return value;
+ }
+}
+
+ImproveDirection ToChromePerfDashboardImproveDirection(
+ ImprovementDirection direction) {
+ switch (direction) {
+ case ImprovementDirection::kBiggerIsBetter:
+ return ImproveDirection::kBiggerIsBetter;
+ case ImprovementDirection::kNeitherIsBetter:
+ return ImproveDirection::kNone;
+ case ImprovementDirection::kSmallerIsBetter:
+ return ImproveDirection::kSmallerIsBetter;
+ }
+}
+
+bool WriteMetricsToFile(const std::string& path, const std::string& data) {
+ CreateDir(DirName(path));
+ FILE* output = fopen(path.c_str(), "wb");
+ if (output == NULL) {
+ printf("Failed to write to %s.\n", path.c_str());
+ return false;
+ }
+ size_t written = fwrite(data.c_str(), sizeof(char), data.size(), output);
+ fclose(output);
+
+ if (written != data.size()) {
+ size_t expected = data.size();
+ printf("Wrote %zu, tried to write %zu\n", written, expected);
+ return false;
+ }
+ return true;
+}
+
+bool IsEmpty(const Metric::Stats& stats) {
+ return !stats.mean.has_value() && !stats.stddev.has_value() &&
+ !stats.min.has_value() && !stats.max.has_value();
+}
+
+} // namespace
+
+ChromePerfDashboardMetricsExporter::ChromePerfDashboardMetricsExporter(
+ absl::string_view export_file_path)
+ : export_file_path_(export_file_path) {}
+
+bool ChromePerfDashboardMetricsExporter::Export(
+ rtc::ArrayView<const Metric> metrics) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ absl::WrapUnique<PerfTestResultWriter>(CreateHistogramWriter());
+ for (const Metric& metric : metrics) {
+ if (metric.time_series.samples.empty() && IsEmpty(metric.stats)) {
+ // If there were no data collected for the metric it is expected that 0
+ // will be exported, so add 0 to the samples.
+ writer->LogResult(
+ metric.name, metric.test_case,
+ ToChromePerfDashboardValue(0, metric.unit),
+ ToChromePerfDashboardUnit(metric.unit),
+ /*important=*/false,
+ ToChromePerfDashboardImproveDirection(metric.improvement_direction));
+ continue;
+ }
+
+ if (metric.time_series.samples.empty()) {
+ writer->LogResultMeanAndError(
+ metric.name, metric.test_case,
+ ToChromePerfDashboardValue(*metric.stats.mean, metric.unit),
+ ToChromePerfDashboardValue(*metric.stats.stddev, metric.unit),
+ ToChromePerfDashboardUnit(metric.unit),
+ /*important=*/false,
+ ToChromePerfDashboardImproveDirection(metric.improvement_direction));
+ continue;
+ }
+
+ std::vector<double> samples(metric.time_series.samples.size());
+ for (size_t i = 0; i < metric.time_series.samples.size(); ++i) {
+ samples[i] = ToChromePerfDashboardValue(
+ metric.time_series.samples[i].value, metric.unit);
+ }
+ writer->LogResultList(
+ metric.name, metric.test_case, samples,
+ ToChromePerfDashboardUnit(metric.unit),
+ /*important=*/false,
+ ToChromePerfDashboardImproveDirection(metric.improvement_direction));
+ }
+ return WriteMetricsToFile(export_file_path_, writer->Serialize());
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.h b/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.h
new file mode 100644
index 0000000000..dda17a08c6
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_CHROME_PERF_DASHBOARD_METRICS_EXPORTER_H_
+#define API_TEST_METRICS_CHROME_PERF_DASHBOARD_METRICS_EXPORTER_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/test/metrics/metric.h"
+#include "api/test/metrics/metrics_exporter.h"
+
+namespace webrtc {
+namespace test {
+
+// Exports all collected metrics in the Chrome Perf Dashboard proto format.
+class ChromePerfDashboardMetricsExporter : public MetricsExporter {
+ public:
+ // `export_file_path` - path where the proto file will be written.
+ explicit ChromePerfDashboardMetricsExporter(
+ absl::string_view export_file_path);
+ ~ChromePerfDashboardMetricsExporter() override = default;
+
+ bool Export(rtc::ArrayView<const Metric> metrics) override;
+
+ private:
+ const std::string export_file_path_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_CHROME_PERF_DASHBOARD_METRICS_EXPORTER_H_
diff --git a/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter_test.cc b/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter_test.cc
new file mode 100644
index 0000000000..5d3136f49a
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter_test.cc
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/chrome_perf_dashboard_metrics_exporter.h"
+
+#include <fstream>
+#include <map>
+#include <vector>
+
+#include "api/test/metrics/metric.h"
+#include "api/units/timestamp.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+#include "third_party/catapult/tracing/tracing/value/histogram.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+using ::testing::DoubleNear;
+using ::testing::Eq;
+using ::testing::Test;
+
+namespace proto = ::catapult::tracing::tracing::proto;
+
+std::map<std::string, std::string> DefaultMetadata() {
+ return std::map<std::string, std::string>{{"key", "value"}};
+}
+
+Metric::TimeSeries::Sample Sample(double value) {
+ return Metric::TimeSeries::Sample{.timestamp = Timestamp::Seconds(1),
+ .value = value,
+ .sample_metadata = DefaultMetadata()};
+}
+
+std::string ReadFileAsString(const std::string& filename) {
+ std::ifstream infile(filename, std::ios_base::binary);
+ auto buffer = std::vector<char>(std::istreambuf_iterator<char>(infile),
+ std::istreambuf_iterator<char>());
+ return std::string(buffer.begin(), buffer.end());
+}
+
+class ChromePerfDashboardMetricsExporterTest : public Test {
+ protected:
+ ~ChromePerfDashboardMetricsExporterTest() override = default;
+
+ void SetUp() override {
+ temp_filename_ = webrtc::test::TempFilename(
+ webrtc::test::OutputPath(),
+ "chrome_perf_dashboard_metrics_exporter_test");
+ }
+
+ void TearDown() override {
+ ASSERT_TRUE(webrtc::test::RemoveFile(temp_filename_));
+ }
+
+ std::string temp_filename_;
+};
+
+TEST_F(ChromePerfDashboardMetricsExporterTest, ExportMetricFormatCorrect) {
+ Metric metric1{
+ .name = "test_metric1",
+ .unit = Unit::kMilliseconds,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name1",
+ .metric_metadata = DefaultMetadata(),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Sample(10), Sample(20)}},
+ .stats =
+ Metric::Stats{.mean = 15.0, .stddev = 5.0, .min = 10.0, .max = 20.0}};
+ Metric metric2{
+ .name = "test_metric2",
+ .unit = Unit::kKilobitsPerSecond,
+ .improvement_direction = ImprovementDirection::kSmallerIsBetter,
+ .test_case = "test_case_name2",
+ .metric_metadata = DefaultMetadata(),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Sample(20), Sample(40)}},
+ .stats = Metric::Stats{
+ .mean = 30.0, .stddev = 10.0, .min = 20.0, .max = 40.0}};
+
+ ChromePerfDashboardMetricsExporter exporter(temp_filename_);
+
+ ASSERT_TRUE(exporter.Export(std::vector<Metric>{metric1, metric2}));
+ proto::HistogramSet actual_histogram_set;
+ actual_histogram_set.ParseFromString(ReadFileAsString(temp_filename_));
+ EXPECT_THAT(actual_histogram_set.histograms().size(), Eq(2));
+
+ // Validate output for `metric1`
+ EXPECT_THAT(actual_histogram_set.histograms(0).name(), Eq("test_metric1"));
+ EXPECT_THAT(actual_histogram_set.histograms(0).unit().unit(),
+ Eq(proto::Unit::MS_BEST_FIT_FORMAT));
+ EXPECT_THAT(actual_histogram_set.histograms(0).unit().improvement_direction(),
+ Eq(proto::ImprovementDirection::BIGGER_IS_BETTER));
+ EXPECT_THAT(
+ actual_histogram_set.histograms(0).diagnostics().diagnostic_map().size(),
+ Eq(1lu));
+ EXPECT_THAT(actual_histogram_set.histograms(0)
+ .diagnostics()
+ .diagnostic_map()
+ .at("stories")
+ .generic_set()
+ .values(0),
+ Eq("\"test_case_name1\""));
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values().size(), Eq(2));
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values(0), Eq(10.0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values(1), Eq(20.0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().count(), Eq(2));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().max(), Eq(20));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().meanlogs(),
+ DoubleNear(2.64916, 0.1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().mean(), Eq(15));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().min(), Eq(10));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().sum(), Eq(30));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().variance(), Eq(50));
+
+ // Validate output for `metric2`
+ EXPECT_THAT(actual_histogram_set.histograms(1).name(), Eq("test_metric2"));
+ EXPECT_THAT(actual_histogram_set.histograms(1).unit().unit(),
+ Eq(proto::Unit::BYTES_PER_SECOND));
+ EXPECT_THAT(actual_histogram_set.histograms(1).unit().improvement_direction(),
+ Eq(proto::ImprovementDirection::SMALLER_IS_BETTER));
+ EXPECT_THAT(
+ actual_histogram_set.histograms(1).diagnostics().diagnostic_map().size(),
+ Eq(1lu));
+ EXPECT_THAT(actual_histogram_set.histograms(1)
+ .diagnostics()
+ .diagnostic_map()
+ .at("stories")
+ .generic_set()
+ .values(0),
+ Eq("\"test_case_name2\""));
+ EXPECT_THAT(actual_histogram_set.histograms(1).sample_values().size(), Eq(2));
+ EXPECT_THAT(actual_histogram_set.histograms(1).sample_values(0), Eq(2500.0));
+ EXPECT_THAT(actual_histogram_set.histograms(1).sample_values(1), Eq(5000.0));
+ EXPECT_THAT(actual_histogram_set.histograms(1).running().count(), Eq(2));
+ EXPECT_THAT(actual_histogram_set.histograms(1).running().max(), Eq(5000));
+ EXPECT_THAT(actual_histogram_set.histograms(1).running().meanlogs(),
+ DoubleNear(8.17062, 0.1));
+ EXPECT_THAT(actual_histogram_set.histograms(1).running().mean(), Eq(3750));
+ EXPECT_THAT(actual_histogram_set.histograms(1).running().min(), Eq(2500));
+ EXPECT_THAT(actual_histogram_set.histograms(1).running().sum(), Eq(7500));
+ EXPECT_THAT(actual_histogram_set.histograms(1).running().variance(),
+ Eq(3125000));
+}
+
+TEST_F(ChromePerfDashboardMetricsExporterTest,
+ ExportEmptyMetricExportsZeroValue) {
+ Metric metric{.name = "test_metric",
+ .unit = Unit::kMilliseconds,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = {}},
+ .stats = Metric::Stats{}};
+
+ ChromePerfDashboardMetricsExporter exporter(temp_filename_);
+
+ ASSERT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ proto::HistogramSet actual_histogram_set;
+ actual_histogram_set.ParseFromString(ReadFileAsString(temp_filename_));
+ EXPECT_THAT(actual_histogram_set.histograms().size(), Eq(1));
+
+ // Validate values for `metric`
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values().size(), Eq(1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values(0), Eq(0.0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().count(), Eq(1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().max(),
+ DoubleNear(0, 1e-6));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().meanlogs(), Eq(0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().mean(), Eq(0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().min(), Eq(0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().sum(), Eq(0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().variance(), Eq(0));
+}
+
+TEST_F(ChromePerfDashboardMetricsExporterTest,
+ ExportMetricWithOnlyStatsExportsMeanValues) {
+ Metric metric{.name = "test_metric",
+ .unit = Unit::kMilliseconds,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = {}},
+ .stats = Metric::Stats{
+ .mean = 15.0, .stddev = 5.0, .min = 10.0, .max = 20.0}};
+
+ ChromePerfDashboardMetricsExporter exporter(temp_filename_);
+
+ ASSERT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ proto::HistogramSet actual_histogram_set;
+ actual_histogram_set.ParseFromString(ReadFileAsString(temp_filename_));
+ EXPECT_THAT(actual_histogram_set.histograms().size(), Eq(1));
+
+ // Validate values for `metric`
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values().size(), Eq(1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values(0), Eq(15.0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().count(), Eq(1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().max(), Eq(15));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().meanlogs(),
+ DoubleNear(2.70805, 0.1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().mean(), Eq(15));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().min(), Eq(15));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().sum(), Eq(15));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().variance(), Eq(0));
+}
+
+TEST_F(ChromePerfDashboardMetricsExporterTest,
+ ExportMetricWithOnlyStatsConvertsMeanValuesWhenRequired) {
+ Metric metric{.name = "test_metric",
+ .unit = Unit::kKilobitsPerSecond,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = {}},
+ .stats = Metric::Stats{
+ .mean = 15.0, .stddev = 5.0, .min = 10.0, .max = 20.0}};
+
+ ChromePerfDashboardMetricsExporter exporter(temp_filename_);
+
+ ASSERT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ proto::HistogramSet actual_histogram_set;
+ actual_histogram_set.ParseFromString(ReadFileAsString(temp_filename_));
+ EXPECT_THAT(actual_histogram_set.histograms().size(), Eq(1));
+
+ // Validate values for `metric`
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values().size(), Eq(1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).sample_values(0), Eq(1875.0));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().count(), Eq(1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().max(), Eq(1875));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().meanlogs(),
+ DoubleNear(7.53636, 0.1));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().mean(), Eq(1875));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().min(), Eq(1875));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().sum(), Eq(1875));
+ EXPECT_THAT(actual_histogram_set.histograms(0).running().variance(), Eq(0));
+}
+
+} // namespace
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter.cc b/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter.cc
new file mode 100644
index 0000000000..2d42a976aa
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/global_metrics_logger_and_exporter.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "api/test/metrics/metrics_exporter.h"
+#include "api/test/metrics/metrics_logger.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+namespace test {
+
+DefaultMetricsLogger* GetGlobalMetricsLogger() {
+ static DefaultMetricsLogger* logger_ =
+ new DefaultMetricsLogger(Clock::GetRealTimeClock());
+ return logger_;
+}
+
+bool ExportPerfMetric(MetricsLogger& logger,
+ std::vector<std::unique_ptr<MetricsExporter>> exporters) {
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ bool success = true;
+ for (auto& exporter : exporters) {
+ bool export_result = exporter->Export(metrics);
+ success = success && export_result;
+ }
+ return success;
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter.h b/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter.h
new file mode 100644
index 0000000000..f77ff1c737
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_GLOBAL_METRICS_LOGGER_AND_EXPORTER_H_
+#define API_TEST_METRICS_GLOBAL_METRICS_LOGGER_AND_EXPORTER_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/test/metrics/metrics_exporter.h"
+#include "api/test/metrics/metrics_logger.h"
+
+namespace webrtc {
+namespace test {
+
+// Returns non-null global `MetricsLogger` to log metrics.
+DefaultMetricsLogger* GetGlobalMetricsLogger();
+
+bool ExportPerfMetric(MetricsLogger& logger,
+ std::vector<std::unique_ptr<MetricsExporter>> exporters);
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_GLOBAL_METRICS_LOGGER_AND_EXPORTER_H_
diff --git a/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter_test.cc b/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter_test.cc
new file mode 100644
index 0000000000..567b3da9e3
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/global_metrics_logger_and_exporter_test.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/global_metrics_logger_and_exporter.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/test/metrics/metric.h"
+#include "api/test/metrics/metrics_exporter.h"
+#include "api/test/metrics/metrics_logger.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+
+std::map<std::string, std::string> DefaultMetadata() {
+ return std::map<std::string, std::string>{{"key", "value"}};
+}
+
+struct TestMetricsExporterFactory {
+ public:
+ std::unique_ptr<MetricsExporter> CreateExporter() {
+ return std::make_unique<TestMetricsExporter>(this, /*export_result=*/true);
+ }
+
+ std::unique_ptr<MetricsExporter> CreateFailureExporter() {
+ return std::make_unique<TestMetricsExporter>(this, /*export_result=*/false);
+ }
+
+ std::vector<Metric> exported_metrics;
+
+ private:
+ class TestMetricsExporter : public MetricsExporter {
+ public:
+ TestMetricsExporter(TestMetricsExporterFactory* factory, bool export_result)
+ : factory_(factory), export_result_(export_result) {}
+ ~TestMetricsExporter() override = default;
+
+ bool Export(rtc::ArrayView<const Metric> metrics) override {
+ factory_->exported_metrics =
+ std::vector<Metric>(metrics.begin(), metrics.end());
+ return export_result_;
+ }
+
+ TestMetricsExporterFactory* factory_;
+ bool export_result_;
+ };
+};
+
+TEST(ExportPerfMetricTest, CollectedMetricsAreExporter) {
+ TestMetricsExporterFactory exporter_factory;
+
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ logger.LogSingleValueMetric(
+ "metric_name", "test_case_name",
+ /*value=*/10, Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ std::map<std::string, std::string>{{"key", "value"}});
+
+ std::vector<std::unique_ptr<MetricsExporter>> exporters;
+ exporters.push_back(exporter_factory.CreateExporter());
+ ASSERT_TRUE(ExportPerfMetric(logger, std::move(exporters)));
+
+ std::vector<Metric> metrics = exporter_factory.exported_metrics;
+ ASSERT_THAT(metrics.size(), Eq(1lu));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metric.metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key", "value"}}));
+ ASSERT_THAT(metric.time_series.samples.size(), Eq(1lu));
+ EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{}));
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.stddev, absl::nullopt);
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(10.0));
+}
+
+TEST(ExportPerfMetricTest, OneFailedExporterDoesNotPreventExportToOthers) {
+ TestMetricsExporterFactory exporter_factory1;
+ TestMetricsExporterFactory exporter_factory2;
+ TestMetricsExporterFactory exporter_factory3;
+
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ logger.LogSingleValueMetric("metric_name", "test_case_name",
+ /*value=*/10, Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+
+ std::vector<std::unique_ptr<MetricsExporter>> exporters;
+ exporters.push_back(exporter_factory1.CreateExporter());
+ exporters.push_back(exporter_factory2.CreateFailureExporter());
+ exporters.push_back(exporter_factory3.CreateExporter());
+ ASSERT_FALSE(ExportPerfMetric(logger, std::move(exporters)));
+
+ std::vector<Metric> metrics1 = exporter_factory1.exported_metrics;
+ std::vector<Metric> metrics2 = exporter_factory2.exported_metrics;
+ std::vector<Metric> metrics3 = exporter_factory3.exported_metrics;
+ ASSERT_THAT(metrics1.size(), Eq(1lu))
+ << metrics1[0].name << "; " << metrics1[1].name;
+ EXPECT_THAT(metrics1[0].name, Eq("metric_name"));
+ ASSERT_THAT(metrics2.size(), Eq(1lu));
+ EXPECT_THAT(metrics2[0].name, Eq("metric_name"));
+ ASSERT_THAT(metrics3.size(), Eq(1lu));
+ EXPECT_THAT(metrics3[0].name, Eq("metric_name"));
+}
+
+} // namespace
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/metric.cc b/third_party/libwebrtc/api/test/metrics/metric.cc
new file mode 100644
index 0000000000..3c30f36f49
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metric.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/metric.h"
+
+#include <string>
+
+namespace webrtc {
+namespace test {
+
+absl::string_view ToString(Unit unit) {
+ switch (unit) {
+ case Unit::kMilliseconds:
+ return "Milliseconds";
+ case Unit::kPercent:
+ return "Percent";
+ case Unit::kBytes:
+ return "Bytes";
+ case Unit::kKilobitsPerSecond:
+ return "KilobitsPerSecond";
+ case Unit::kHertz:
+ return "Hertz";
+ case Unit::kUnitless:
+ return "Unitless";
+ case Unit::kCount:
+ return "Count";
+ }
+}
+
+absl::string_view ToString(ImprovementDirection direction) {
+ switch (direction) {
+ case ImprovementDirection::kBiggerIsBetter:
+ return "BiggerIsBetter";
+ case ImprovementDirection::kNeitherIsBetter:
+ return "NeitherIsBetter";
+ case ImprovementDirection::kSmallerIsBetter:
+ return "SmallerIsBetter";
+ }
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/metric.h b/third_party/libwebrtc/api/test/metrics/metric.h
new file mode 100644
index 0000000000..17c1755f95
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metric.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_METRIC_H_
+#define API_TEST_METRICS_METRIC_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/units/timestamp.h"
+
+namespace webrtc {
+namespace test {
+
+enum class Unit {
+ kMilliseconds,
+ kPercent,
+ kBytes,
+ kKilobitsPerSecond,
+ kHertz,
+ // General unitless value. Can be used either for dimensionless quantities
+ // (ex ratio) or for units not presented in this enum and too specific to add
+ // to this enum.
+ kUnitless,
+ kCount
+};
+
+absl::string_view ToString(Unit unit);
+
+enum class ImprovementDirection {
+ kBiggerIsBetter,
+ kNeitherIsBetter,
+ kSmallerIsBetter
+};
+
+absl::string_view ToString(ImprovementDirection direction);
+
+struct Metric {
+ struct TimeSeries {
+ struct Sample {
+ // Timestamp in microseconds associated with a sample. For example,
+ // the timestamp when the sample was collected.
+ webrtc::Timestamp timestamp;
+ double value;
+ // Metadata associated with this particular sample.
+ std::map<std::string, std::string> sample_metadata;
+ };
+
+ // All samples collected for this metric. It can be empty if the Metric
+ // object only contains `stats`.
+ std::vector<Sample> samples;
+ };
+
+ // Contains metric's precomputed statistics based on the `time_series` or if
+ // `time_series` is omitted (has 0 samples) contains precomputed statistics
+ // provided by the metric's calculator.
+ struct Stats {
+ // Sample mean of the metric
+ // (https://en.wikipedia.org/wiki/Sample_mean_and_covariance).
+ absl::optional<double> mean;
+ // Standard deviation (https://en.wikipedia.org/wiki/Standard_deviation).
+ // Is undefined if `time_series` contains only a single value.
+ absl::optional<double> stddev;
+ absl::optional<double> min;
+ absl::optional<double> max;
+ };
+
+ // Metric name, for example PSNR, SSIM, decode_time, etc.
+ std::string name;
+ Unit unit;
+ ImprovementDirection improvement_direction;
+ // If the metric is generated by a test, this field can be used to specify
+ // this information.
+ std::string test_case;
+ // Metadata associated with the whole metric.
+ std::map<std::string, std::string> metric_metadata;
+ // Contains all samples of the metric collected during test execution.
+ // It can be empty if the user only stores precomputed statistics into
+ // `stats`.
+ TimeSeries time_series;
+ Stats stats;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_METRIC_H_
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_accumulator.cc b/third_party/libwebrtc/api/test/metrics/metrics_accumulator.cc
new file mode 100644
index 0000000000..c34396be97
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_accumulator.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/metrics_accumulator.h"
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/numerics/samples_stats_counter.h"
+#include "api/test/metrics/metric.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/synchronization/mutex.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+Metric::Stats ToStats(const SamplesStatsCounter& values) {
+ if (values.IsEmpty()) {
+ return Metric::Stats();
+ }
+ return Metric::Stats{.mean = values.GetAverage(),
+ .stddev = values.GetStandardDeviation(),
+ .min = values.GetMin(),
+ .max = values.GetMax()};
+}
+
+Metric SetTimeseries(const Metric& prototype,
+ const SamplesStatsCounter& counter) {
+ Metric output(prototype);
+ Metric::TimeSeries time_series;
+ for (const SamplesStatsCounter::StatsSample& sample :
+ counter.GetTimedSamples()) {
+ time_series.samples.push_back(
+ Metric::TimeSeries::Sample{.timestamp = sample.time,
+ .value = sample.value,
+ .sample_metadata = sample.metadata});
+ }
+ output.time_series = std::move(time_series);
+ output.stats = ToStats(counter);
+ return output;
+}
+
+} // namespace
+
+bool operator<(const MetricsAccumulator::MetricKey& a,
+ const MetricsAccumulator::MetricKey& b) {
+ if (a.test_case_name < b.test_case_name) {
+ return true;
+ } else if (a.test_case_name > b.test_case_name) {
+ return false;
+ } else {
+ return a.metric_name < b.metric_name;
+ }
+}
+
+bool MetricsAccumulator::AddSample(
+ absl::string_view metric_name,
+ absl::string_view test_case_name,
+ double value,
+ Timestamp timestamp,
+ std::map<std::string, std::string> point_metadata) {
+ MutexLock lock(&mutex_);
+ bool created;
+ MetricValue* metric_value =
+ GetOrCreateMetric(metric_name, test_case_name, &created);
+ metric_value->counter.AddSample(
+ SamplesStatsCounter::StatsSample{.value = value,
+ .time = timestamp,
+ .metadata = std::move(point_metadata)});
+ return created;
+}
+
+bool MetricsAccumulator::AddMetricMetadata(
+ absl::string_view metric_name,
+ absl::string_view test_case_name,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metric_metadata) {
+ MutexLock lock(&mutex_);
+ bool created;
+ MetricValue* metric_value =
+ GetOrCreateMetric(metric_name, test_case_name, &created);
+ metric_value->metric.unit = unit;
+ metric_value->metric.improvement_direction = improvement_direction;
+ metric_value->metric.metric_metadata = std::move(metric_metadata);
+ return created;
+}
+
+std::vector<Metric> MetricsAccumulator::GetCollectedMetrics() const {
+ MutexLock lock(&mutex_);
+ std::vector<Metric> out;
+ out.reserve(metrics_.size());
+ for (const auto& [unused_key, metric_value] : metrics_) {
+ out.push_back(SetTimeseries(metric_value.metric, metric_value.counter));
+ }
+ return out;
+}
+
+MetricsAccumulator::MetricValue* MetricsAccumulator::GetOrCreateMetric(
+ absl::string_view metric_name,
+ absl::string_view test_case_name,
+ bool* created) {
+ MetricKey key(metric_name, test_case_name);
+ auto it = metrics_.find(key);
+ if (it != metrics_.end()) {
+ *created = false;
+ return &it->second;
+ }
+ *created = true;
+
+ Metric metric{
+ .name = key.metric_name,
+ .unit = Unit::kUnitless,
+ .improvement_direction = ImprovementDirection::kNeitherIsBetter,
+ .test_case = key.test_case_name,
+ };
+ return &metrics_.emplace(key, MetricValue{.metric = std::move(metric)})
+ .first->second;
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_accumulator.h b/third_party/libwebrtc/api/test/metrics/metrics_accumulator.h
new file mode 100644
index 0000000000..c75bd9429c
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_accumulator.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_METRICS_ACCUMULATOR_H_
+#define API_TEST_METRICS_METRICS_ACCUMULATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/numerics/samples_stats_counter.h"
+#include "api/test/metrics/metric.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+namespace test {
+
+// Accumulates metrics' samples internally and provides API to get collected
+// ones.
+//
+// This object is thread safe.
+class MetricsAccumulator {
+ public:
+ MetricsAccumulator() = default;
+
+ // Adds sample for the specified `metric_name` within specified
+ // `test_case_name`. If it is the first time when this combination of
+ // `metric_name` and `test_case_name` is used, creates a new Metric to collect
+ // samples, otherwise adds a sample to the previously created Metric.
+ //
+ // By default metric will use `Unit::kUnitless` and
+ // `ImprovementDirection::kNeitherIsBetter`.
+ //
+ // `point_metadata` - the metadata to be added to the single data point that
+ // this method adds to the Metric (it is not a metric global metadata).
+ //
+ // Returns true if a new metric was created and false otherwise.
+ bool AddSample(absl::string_view metric_name,
+ absl::string_view test_case_name,
+ double value,
+ Timestamp timestamp,
+ std::map<std::string, std::string> point_metadata = {});
+
+ // Adds metadata to the metric specified by `metric_name` within specified
+ // `test_case_name`. If such a metric doesn't exist, creates a new one,
+ // otherwise overrides previously recorded values.
+ //
+ // Returns true if a new metric was created and false otherwise.
+ bool AddMetricMetadata(
+ absl::string_view metric_name,
+ absl::string_view test_case_name,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metric_metadata = {});
+
+ // Returns all metrics collected by this accumulator. No order guarantees
+ // provided.
+ std::vector<Metric> GetCollectedMetrics() const;
+
+ private:
+ struct MetricKey {
+ MetricKey(absl::string_view metric_name, absl::string_view test_case_name)
+ : metric_name(metric_name), test_case_name(test_case_name) {}
+
+ std::string metric_name;
+ std::string test_case_name;
+ };
+ friend bool operator<(const MetricKey& a, const MetricKey& b);
+
+ struct MetricValue {
+ SamplesStatsCounter counter;
+ Metric metric;
+ };
+
+ // Gets existing metrics or creates a new one. If metric was created `created`
+ // will be set to true.
+ MetricValue* GetOrCreateMetric(absl::string_view metric_name,
+ absl::string_view test_case_name,
+ bool* created)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+
+ mutable Mutex mutex_;
+ std::map<MetricKey, MetricValue> metrics_ RTC_GUARDED_BY(mutex_);
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_METRICS_ACCUMULATOR_H_
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_accumulator_test.cc b/third_party/libwebrtc/api/test/metrics/metrics_accumulator_test.cc
new file mode 100644
index 0000000000..677f523339
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_accumulator_test.cc
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/metrics_accumulator.h"
+
+#include <map>
+#include <vector>
+
+#include "api/test/metrics/metric.h"
+#include "api/units/timestamp.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::SizeIs;
+
+TEST(MetricsAccumulatorTest, AddSampleToTheNewMetricWillCreateOne) {
+ MetricsAccumulator accumulator;
+ ASSERT_TRUE(accumulator.AddSample(
+ "metric_name", "test_case_name",
+ /*value=*/10, Timestamp::Seconds(1),
+ /*point_metadata=*/std::map<std::string, std::string>{{"key", "value"}}));
+
+ std::vector<Metric> metrics = accumulator.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kUnitless));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kNeitherIsBetter));
+ EXPECT_THAT(metric.metric_metadata, IsEmpty());
+ ASSERT_THAT(metric.time_series.samples, SizeIs(1));
+ EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metric.time_series.samples[0].timestamp,
+ Eq(Timestamp::Seconds(1)));
+ EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key", "value"}}));
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.stddev, absl::optional<double>(0.0));
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(10.0));
+}
+
+TEST(MetricsAccumulatorTest, AddSamplesToExistingMetricWontCreateNewOne) {
+ MetricsAccumulator accumulator;
+ ASSERT_TRUE(accumulator.AddSample(
+ "metric_name", "test_case_name",
+ /*value=*/10, Timestamp::Seconds(1),
+ /*point_metadata=*/
+ std::map<std::string, std::string>{{"key1", "value1"}}));
+ ASSERT_FALSE(accumulator.AddSample(
+ "metric_name", "test_case_name",
+ /*value=*/20, Timestamp::Seconds(2),
+ /*point_metadata=*/
+ std::map<std::string, std::string>{{"key2", "value2"}}));
+
+ std::vector<Metric> metrics = accumulator.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kUnitless));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kNeitherIsBetter));
+ EXPECT_THAT(metric.metric_metadata, IsEmpty());
+ ASSERT_THAT(metric.time_series.samples, SizeIs(2));
+ EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metric.time_series.samples[0].timestamp,
+ Eq(Timestamp::Seconds(1)));
+ EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key1", "value1"}}));
+ EXPECT_THAT(metric.time_series.samples[1].value, Eq(20.0));
+ EXPECT_THAT(metric.time_series.samples[1].timestamp,
+ Eq(Timestamp::Seconds(2)));
+ EXPECT_THAT(metric.time_series.samples[1].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key2", "value2"}}));
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(15.0));
+ ASSERT_THAT(metric.stats.stddev, absl::optional<double>(5.0));
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(20.0));
+}
+
+TEST(MetricsAccumulatorTest, AddSampleToDifferentMetricsWillCreateBoth) {
+ MetricsAccumulator accumulator;
+ ASSERT_TRUE(accumulator.AddSample(
+ "metric_name1", "test_case_name1",
+ /*value=*/10, Timestamp::Seconds(1),
+ /*point_metadata=*/
+ std::map<std::string, std::string>{{"key1", "value1"}}));
+ ASSERT_TRUE(accumulator.AddSample(
+ "metric_name2", "test_case_name2",
+ /*value=*/20, Timestamp::Seconds(2),
+ /*point_metadata=*/
+ std::map<std::string, std::string>{{"key2", "value2"}}));
+
+ std::vector<Metric> metrics = accumulator.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(2));
+ EXPECT_THAT(metrics[0].name, Eq("metric_name1"));
+ EXPECT_THAT(metrics[0].test_case, Eq("test_case_name1"));
+ EXPECT_THAT(metrics[0].unit, Eq(Unit::kUnitless));
+ EXPECT_THAT(metrics[0].improvement_direction,
+ Eq(ImprovementDirection::kNeitherIsBetter));
+ EXPECT_THAT(metrics[0].metric_metadata, IsEmpty());
+ ASSERT_THAT(metrics[0].time_series.samples, SizeIs(1));
+ EXPECT_THAT(metrics[0].time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metrics[0].time_series.samples[0].timestamp,
+ Eq(Timestamp::Seconds(1)));
+ EXPECT_THAT(metrics[0].time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key1", "value1"}}));
+ ASSERT_THAT(metrics[0].stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metrics[0].stats.stddev, absl::optional<double>(0.0));
+ ASSERT_THAT(metrics[0].stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metrics[0].stats.max, absl::optional<double>(10.0));
+ EXPECT_THAT(metrics[1].name, Eq("metric_name2"));
+ EXPECT_THAT(metrics[1].test_case, Eq("test_case_name2"));
+ EXPECT_THAT(metrics[1].unit, Eq(Unit::kUnitless));
+ EXPECT_THAT(metrics[1].improvement_direction,
+ Eq(ImprovementDirection::kNeitherIsBetter));
+ EXPECT_THAT(metrics[1].metric_metadata, IsEmpty());
+ ASSERT_THAT(metrics[1].time_series.samples, SizeIs(1));
+ EXPECT_THAT(metrics[1].time_series.samples[0].value, Eq(20.0));
+ EXPECT_THAT(metrics[1].time_series.samples[0].timestamp,
+ Eq(Timestamp::Seconds(2)));
+ EXPECT_THAT(metrics[1].time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key2", "value2"}}));
+ ASSERT_THAT(metrics[1].stats.mean, absl::optional<double>(20.0));
+ ASSERT_THAT(metrics[1].stats.stddev, absl::optional<double>(0.0));
+ ASSERT_THAT(metrics[1].stats.min, absl::optional<double>(20.0));
+ ASSERT_THAT(metrics[1].stats.max, absl::optional<double>(20.0));
+}
+
+TEST(MetricsAccumulatorTest, AddMetadataToTheNewMetricWillCreateOne) {
+ MetricsAccumulator accumulator;
+ ASSERT_TRUE(accumulator.AddMetricMetadata(
+ "metric_name", "test_case_name", Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ /*metric_metadata=*/
+ std::map<std::string, std::string>{{"key", "value"}}));
+
+ std::vector<Metric> metrics = accumulator.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metric.metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key", "value"}}));
+ ASSERT_THAT(metric.time_series.samples, IsEmpty());
+ ASSERT_THAT(metric.stats.mean, absl::nullopt);
+ ASSERT_THAT(metric.stats.stddev, absl::nullopt);
+ ASSERT_THAT(metric.stats.min, absl::nullopt);
+ ASSERT_THAT(metric.stats.max, absl::nullopt);
+}
+
+TEST(MetricsAccumulatorTest,
+ AddMetadataToTheExistingMetricWillOverwriteValues) {
+ MetricsAccumulator accumulator;
+ ASSERT_TRUE(accumulator.AddMetricMetadata(
+ "metric_name", "test_case_name", Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ /*metric_metadata=*/
+ std::map<std::string, std::string>{{"key1", "value1"}}));
+
+ ASSERT_FALSE(accumulator.AddMetricMetadata(
+ "metric_name", "test_case_name", Unit::kBytes,
+ ImprovementDirection::kSmallerIsBetter,
+ /*metric_metadata=*/
+ std::map<std::string, std::string>{{"key2", "value2"}}));
+
+ std::vector<Metric> metrics = accumulator.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kBytes));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kSmallerIsBetter));
+ EXPECT_THAT(metric.metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key2", "value2"}}));
+ ASSERT_THAT(metric.time_series.samples, IsEmpty());
+ ASSERT_THAT(metric.stats.mean, absl::nullopt);
+ ASSERT_THAT(metric.stats.stddev, absl::nullopt);
+ ASSERT_THAT(metric.stats.min, absl::nullopt);
+ ASSERT_THAT(metric.stats.max, absl::nullopt);
+}
+
+TEST(MetricsAccumulatorTest, AddMetadataToDifferentMetricsWillCreateBoth) {
+ MetricsAccumulator accumulator;
+ ASSERT_TRUE(accumulator.AddMetricMetadata(
+ "metric_name1", "test_case_name1", Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ /*metric_metadata=*/
+ std::map<std::string, std::string>{{"key1", "value1"}}));
+
+ ASSERT_TRUE(accumulator.AddMetricMetadata(
+ "metric_name2", "test_case_name2", Unit::kBytes,
+ ImprovementDirection::kSmallerIsBetter,
+ /*metric_metadata=*/
+ std::map<std::string, std::string>{{"key2", "value2"}}));
+
+ std::vector<Metric> metrics = accumulator.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(2));
+ EXPECT_THAT(metrics[0].name, Eq("metric_name1"));
+ EXPECT_THAT(metrics[0].test_case, Eq("test_case_name1"));
+ EXPECT_THAT(metrics[0].unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metrics[0].improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metrics[0].metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key1", "value1"}}));
+ ASSERT_THAT(metrics[0].time_series.samples, IsEmpty());
+ ASSERT_THAT(metrics[0].stats.mean, absl::nullopt);
+ ASSERT_THAT(metrics[0].stats.stddev, absl::nullopt);
+ ASSERT_THAT(metrics[0].stats.min, absl::nullopt);
+ ASSERT_THAT(metrics[0].stats.max, absl::nullopt);
+ EXPECT_THAT(metrics[1].name, Eq("metric_name2"));
+ EXPECT_THAT(metrics[1].test_case, Eq("test_case_name2"));
+ EXPECT_THAT(metrics[1].unit, Eq(Unit::kBytes));
+ EXPECT_THAT(metrics[1].improvement_direction,
+ Eq(ImprovementDirection::kSmallerIsBetter));
+ EXPECT_THAT(metrics[1].metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key2", "value2"}}));
+ ASSERT_THAT(metrics[1].time_series.samples, IsEmpty());
+ ASSERT_THAT(metrics[1].stats.mean, absl::nullopt);
+ ASSERT_THAT(metrics[1].stats.stddev, absl::nullopt);
+ ASSERT_THAT(metrics[1].stats.min, absl::nullopt);
+ ASSERT_THAT(metrics[1].stats.max, absl::nullopt);
+}
+
+TEST(MetricsAccumulatorTest, AddMetadataAfterAddingSampleWontCreateNewMetric) {
+ MetricsAccumulator accumulator;
+ ASSERT_TRUE(accumulator.AddSample(
+ "metric_name", "test_case_name",
+ /*value=*/10, Timestamp::Seconds(1),
+ /*point_metadata=*/
+ std::map<std::string, std::string>{{"key_s", "value_s"}}));
+ ASSERT_FALSE(accumulator.AddMetricMetadata(
+ "metric_name", "test_case_name", Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ /*metric_metadata=*/
+ std::map<std::string, std::string>{{"key_m", "value_m"}}));
+
+ std::vector<Metric> metrics = accumulator.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metric.metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key_m", "value_m"}}));
+ ASSERT_THAT(metric.time_series.samples, SizeIs(1));
+ EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metric.time_series.samples[0].timestamp,
+ Eq(Timestamp::Seconds(1)));
+ EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key_s", "value_s"}}));
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.stddev, absl::optional<double>(0.0));
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(10.0));
+}
+
+TEST(MetricsAccumulatorTest, AddSampleAfterAddingMetadataWontCreateNewMetric) {
+ MetricsAccumulator accumulator;
+ ASSERT_TRUE(accumulator.AddMetricMetadata(
+ "metric_name", "test_case_name", Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ /*metric_metadata=*/
+ std::map<std::string, std::string>{{"key_m", "value_m"}}));
+ ASSERT_FALSE(accumulator.AddSample(
+ "metric_name", "test_case_name",
+ /*value=*/10, Timestamp::Seconds(1),
+ /*point_metadata=*/
+ std::map<std::string, std::string>{{"key_s", "value_s"}}));
+
+ std::vector<Metric> metrics = accumulator.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metric.metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key_m", "value_m"}}));
+ ASSERT_THAT(metric.time_series.samples, SizeIs(1));
+ EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metric.time_series.samples[0].timestamp,
+ Eq(Timestamp::Seconds(1)));
+ EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key_s", "value_s"}}));
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.stddev, absl::optional<double>(0.0));
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(10.0));
+}
+
+} // namespace
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_exporter.h b/third_party/libwebrtc/api/test/metrics/metrics_exporter.h
new file mode 100644
index 0000000000..23954b6b1f
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_exporter.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_METRICS_EXPORTER_H_
+#define API_TEST_METRICS_METRICS_EXPORTER_H_
+
+#include "api/array_view.h"
+#include "api/test/metrics/metric.h"
+
+namespace webrtc {
+namespace test {
+
+// Exports metrics in the requested format.
+class MetricsExporter {
+ public:
+ virtual ~MetricsExporter() = default;
+
+ // Exports specified metrics in a format that depends on the implementation.
+ // Returns true if export succeeded, false otherwise.
+ virtual bool Export(rtc::ArrayView<const Metric> metrics) = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_METRICS_EXPORTER_H_
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_logger.cc b/third_party/libwebrtc/api/test/metrics/metrics_logger.cc
new file mode 100644
index 0000000000..1e24400367
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_logger.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/metrics_logger.h"
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/numerics/samples_stats_counter.h"
+#include "api/test/metrics/metric.h"
+#include "rtc_base/synchronization/mutex.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+Metric::Stats ToStats(const SamplesStatsCounter& values) {
+ if (values.IsEmpty()) {
+ return Metric::Stats();
+ }
+ return Metric::Stats{.mean = values.GetAverage(),
+ .stddev = values.GetStandardDeviation(),
+ .min = values.GetMin(),
+ .max = values.GetMax()};
+}
+
+} // namespace
+
+void DefaultMetricsLogger::LogSingleValueMetric(
+ absl::string_view name,
+ absl::string_view test_case_name,
+ double value,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata) {
+ MutexLock lock(&mutex_);
+ metrics_.push_back(Metric{
+ .name = std::string(name),
+ .unit = unit,
+ .improvement_direction = improvement_direction,
+ .test_case = std::string(test_case_name),
+ .metric_metadata = std::move(metadata),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Metric::TimeSeries::Sample{
+ .timestamp = Now(), .value = value}}},
+ .stats = Metric::Stats{
+ .mean = value, .stddev = absl::nullopt, .min = value, .max = value}});
+}
+
+void DefaultMetricsLogger::LogMetric(
+ absl::string_view name,
+ absl::string_view test_case_name,
+ const SamplesStatsCounter& values,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata) {
+ MutexLock lock(&mutex_);
+ Metric::TimeSeries time_series;
+ for (const SamplesStatsCounter::StatsSample& sample :
+ values.GetTimedSamples()) {
+ time_series.samples.push_back(
+ Metric::TimeSeries::Sample{.timestamp = sample.time,
+ .value = sample.value,
+ .sample_metadata = sample.metadata});
+ }
+
+ metrics_.push_back(Metric{.name = std::string(name),
+ .unit = unit,
+ .improvement_direction = improvement_direction,
+ .test_case = std::string(test_case_name),
+ .metric_metadata = std::move(metadata),
+ .time_series = std::move(time_series),
+ .stats = ToStats(values)});
+}
+
+void DefaultMetricsLogger::LogMetric(
+ absl::string_view name,
+ absl::string_view test_case_name,
+ const Metric::Stats& metric_stats,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata) {
+ MutexLock lock(&mutex_);
+ metrics_.push_back(Metric{.name = std::string(name),
+ .unit = unit,
+ .improvement_direction = improvement_direction,
+ .test_case = std::string(test_case_name),
+ .metric_metadata = std::move(metadata),
+ .time_series = Metric::TimeSeries{.samples = {}},
+ .stats = std::move(metric_stats)});
+}
+
+std::vector<Metric> DefaultMetricsLogger::GetCollectedMetrics() const {
+ std::vector<Metric> out = metrics_accumulator_.GetCollectedMetrics();
+ MutexLock lock(&mutex_);
+ out.insert(out.end(), metrics_.begin(), metrics_.end());
+ return out;
+}
+
+Timestamp DefaultMetricsLogger::Now() {
+ return clock_->CurrentTime();
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_logger.h b/third_party/libwebrtc/api/test/metrics/metrics_logger.h
new file mode 100644
index 0000000000..66f9e55b95
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_logger.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_METRICS_LOGGER_H_
+#define API_TEST_METRICS_METRICS_LOGGER_H_
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/numerics/samples_stats_counter.h"
+#include "api/test/metrics/metric.h"
+#include "api/test/metrics/metrics_accumulator.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+namespace test {
+
+// Provides API to log and collect performance metrics.
+class MetricsLogger {
+ public:
+ virtual ~MetricsLogger() = default;
+
+ // Adds a metric with a single value.
+ // `metadata` - metric's level metadata to add.
+ virtual void LogSingleValueMetric(
+ absl::string_view name,
+ absl::string_view test_case_name,
+ double value,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata = {}) = 0;
+
+ // Adds metrics with a time series created based on the provided `values`.
+ // `metadata` - metric's level metadata to add.
+ virtual void LogMetric(absl::string_view name,
+ absl::string_view test_case_name,
+ const SamplesStatsCounter& values,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata = {}) = 0;
+
+ // Adds metric with a time series with only stats object and without actual
+ // collected values.
+ // `metadata` - metric's level metadata to add.
+ virtual void LogMetric(absl::string_view name,
+ absl::string_view test_case_name,
+ const Metric::Stats& metric_stats,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata = {}) = 0;
+
+ // Returns all metrics collected by this logger.
+ virtual std::vector<Metric> GetCollectedMetrics() const = 0;
+};
+
+class DefaultMetricsLogger : public MetricsLogger {
+ public:
+ explicit DefaultMetricsLogger(webrtc::Clock* clock) : clock_(clock) {}
+ ~DefaultMetricsLogger() override = default;
+
+ void LogSingleValueMetric(
+ absl::string_view name,
+ absl::string_view test_case_name,
+ double value,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata = {}) override;
+
+ void LogMetric(absl::string_view name,
+ absl::string_view test_case_name,
+ const SamplesStatsCounter& values,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata = {}) override;
+
+ void LogMetric(absl::string_view name,
+ absl::string_view test_case_name,
+ const Metric::Stats& metric_stats,
+ Unit unit,
+ ImprovementDirection improvement_direction,
+ std::map<std::string, std::string> metadata = {}) override;
+
+ // Returns all metrics collected by this logger and its `MetricsAccumulator`.
+ std::vector<Metric> GetCollectedMetrics() const override;
+
+ MetricsAccumulator* GetMetricsAccumulator() { return &metrics_accumulator_; }
+
+ private:
+ webrtc::Timestamp Now();
+
+ webrtc::Clock* const clock_;
+ MetricsAccumulator metrics_accumulator_;
+
+ mutable Mutex mutex_;
+ std::vector<Metric> metrics_ RTC_GUARDED_BY(mutex_);
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_METRICS_LOGGER_H_
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_logger_test.cc b/third_party/libwebrtc/api/test/metrics/metrics_logger_test.cc
new file mode 100644
index 0000000000..de4501ca36
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_logger_test.cc
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/metrics_logger.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/numerics/samples_stats_counter.h"
+#include "api/test/metrics/metric.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::SizeIs;
+
+std::map<std::string, std::string> DefaultMetadata() {
+ return std::map<std::string, std::string>{{"key", "value"}};
+}
+
+TEST(DefaultMetricsLoggerTest, LogSingleValueMetricRecordsMetric) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ logger.LogSingleValueMetric(
+ "metric_name", "test_case_name",
+ /*value=*/10, Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ std::map<std::string, std::string>{{"key", "value"}});
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metric.metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key", "value"}}));
+ ASSERT_THAT(metric.time_series.samples, SizeIs(1));
+ EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{}));
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.stddev, absl::nullopt);
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(10.0));
+}
+
+TEST(DefaultMetricsLoggerTest, LogMetricWithSamplesStatsCounterRecordsMetric) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+
+ SamplesStatsCounter values;
+ values.AddSample(SamplesStatsCounter::StatsSample{
+ .value = 10,
+ .time = Clock::GetRealTimeClock()->CurrentTime(),
+ .metadata =
+ std::map<std::string, std::string>{{"point_key1", "value1"}}});
+ values.AddSample(SamplesStatsCounter::StatsSample{
+ .value = 20,
+ .time = Clock::GetRealTimeClock()->CurrentTime(),
+ .metadata =
+ std::map<std::string, std::string>{{"point_key2", "value2"}}});
+ logger.LogMetric("metric_name", "test_case_name", values, Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ std::map<std::string, std::string>{{"key", "value"}});
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metric.metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key", "value"}}));
+ ASSERT_THAT(metric.time_series.samples, SizeIs(2));
+ EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"point_key1", "value1"}}));
+ EXPECT_THAT(metric.time_series.samples[1].value, Eq(20.0));
+ EXPECT_THAT(metric.time_series.samples[1].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"point_key2", "value2"}}));
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(15.0));
+ ASSERT_THAT(metric.stats.stddev, absl::optional<double>(5.0));
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(20.0));
+}
+
+TEST(DefaultMetricsLoggerTest,
+ LogMetricWithEmptySamplesStatsCounterRecordsEmptyMetric) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ SamplesStatsCounter values;
+ logger.LogMetric("metric_name", "test_case_name", values, Unit::kUnitless,
+ ImprovementDirection::kBiggerIsBetter, DefaultMetadata());
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ EXPECT_THAT(metrics[0].name, Eq("metric_name"));
+ EXPECT_THAT(metrics[0].test_case, Eq("test_case_name"));
+ EXPECT_THAT(metrics[0].time_series.samples, IsEmpty());
+ ASSERT_THAT(metrics[0].stats.mean, Eq(absl::nullopt));
+ ASSERT_THAT(metrics[0].stats.stddev, Eq(absl::nullopt));
+ ASSERT_THAT(metrics[0].stats.min, Eq(absl::nullopt));
+ ASSERT_THAT(metrics[0].stats.max, Eq(absl::nullopt));
+}
+
+TEST(DefaultMetricsLoggerTest, LogMetricWithStatsRecordsMetric) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ Metric::Stats metric_stats{.mean = 15, .stddev = 5, .min = 10, .max = 20};
+ logger.LogMetric("metric_name", "test_case_name", metric_stats,
+ Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ std::map<std::string, std::string>{{"key", "value"}});
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metric.metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key", "value"}}));
+ ASSERT_THAT(metric.time_series.samples, IsEmpty());
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(15.0));
+ ASSERT_THAT(metric.stats.stddev, absl::optional<double>(5.0));
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(20.0));
+}
+
+TEST(DefaultMetricsLoggerTest, LogSingleValueMetricRecordsMultipleMetrics) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+
+ logger.LogSingleValueMetric("metric_name1", "test_case_name1",
+ /*value=*/10, Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+ logger.LogSingleValueMetric("metric_name2", "test_case_name2",
+ /*value=*/10, Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(2));
+ EXPECT_THAT(metrics[0].name, Eq("metric_name1"));
+ EXPECT_THAT(metrics[0].test_case, Eq("test_case_name1"));
+ EXPECT_THAT(metrics[1].name, Eq("metric_name2"));
+ EXPECT_THAT(metrics[1].test_case, Eq("test_case_name2"));
+}
+
+TEST(DefaultMetricsLoggerTest,
+ LogMetricWithSamplesStatsCounterRecordsMultipleMetrics) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ SamplesStatsCounter values;
+ values.AddSample(SamplesStatsCounter::StatsSample{
+ .value = 10,
+ .time = Clock::GetRealTimeClock()->CurrentTime(),
+ .metadata = DefaultMetadata()});
+ values.AddSample(SamplesStatsCounter::StatsSample{
+ .value = 20,
+ .time = Clock::GetRealTimeClock()->CurrentTime(),
+ .metadata = DefaultMetadata()});
+
+ logger.LogMetric("metric_name1", "test_case_name1", values,
+ Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+ logger.LogMetric("metric_name2", "test_case_name2", values,
+ Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(2));
+ EXPECT_THAT(metrics[0].name, Eq("metric_name1"));
+ EXPECT_THAT(metrics[0].test_case, Eq("test_case_name1"));
+ EXPECT_THAT(metrics[1].name, Eq("metric_name2"));
+ EXPECT_THAT(metrics[1].test_case, Eq("test_case_name2"));
+}
+
+TEST(DefaultMetricsLoggerTest, LogMetricWithStatsRecordsMultipleMetrics) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ Metric::Stats metric_stats{.mean = 15, .stddev = 5, .min = 10, .max = 20};
+
+ logger.LogMetric("metric_name1", "test_case_name1", metric_stats,
+ Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+ logger.LogMetric("metric_name2", "test_case_name2", metric_stats,
+ Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(2));
+ EXPECT_THAT(metrics[0].name, Eq("metric_name1"));
+ EXPECT_THAT(metrics[0].test_case, Eq("test_case_name1"));
+ EXPECT_THAT(metrics[1].name, Eq("metric_name2"));
+ EXPECT_THAT(metrics[1].test_case, Eq("test_case_name2"));
+}
+
+TEST(DefaultMetricsLoggerTest,
+ LogMetricThroughtAllMethodsAccumulateAllMetrics) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ SamplesStatsCounter values;
+ values.AddSample(SamplesStatsCounter::StatsSample{
+ .value = 10,
+ .time = Clock::GetRealTimeClock()->CurrentTime(),
+ .metadata = DefaultMetadata()});
+ values.AddSample(SamplesStatsCounter::StatsSample{
+ .value = 20,
+ .time = Clock::GetRealTimeClock()->CurrentTime(),
+ .metadata = DefaultMetadata()});
+ Metric::Stats metric_stats{.mean = 15, .stddev = 5, .min = 10, .max = 20};
+
+ logger.LogSingleValueMetric("metric_name1", "test_case_name1",
+ /*value=*/10, Unit::kMilliseconds,
+ ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+ logger.LogMetric("metric_name2", "test_case_name2", values,
+ Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+ logger.LogMetric("metric_name3", "test_case_name3", metric_stats,
+ Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ DefaultMetadata());
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics.size(), Eq(3lu));
+ EXPECT_THAT(metrics[0].name, Eq("metric_name1"));
+ EXPECT_THAT(metrics[0].test_case, Eq("test_case_name1"));
+ EXPECT_THAT(metrics[1].name, Eq("metric_name2"));
+ EXPECT_THAT(metrics[1].test_case, Eq("test_case_name2"));
+ EXPECT_THAT(metrics[2].name, Eq("metric_name3"));
+ EXPECT_THAT(metrics[2].test_case, Eq("test_case_name3"));
+}
+
+TEST(DefaultMetricsLoggerTest, AccumulatedMetricsReturnedInCollectedMetrics) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ logger.GetMetricsAccumulator()->AddSample(
+ "metric_name", "test_case_name",
+ /*value=*/10, Timestamp::Seconds(1),
+ /*point_metadata=*/std::map<std::string, std::string>{{"key", "value"}});
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(1));
+ const Metric& metric = metrics[0];
+ EXPECT_THAT(metric.name, Eq("metric_name"));
+ EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+ EXPECT_THAT(metric.unit, Eq(Unit::kUnitless));
+ EXPECT_THAT(metric.improvement_direction,
+ Eq(ImprovementDirection::kNeitherIsBetter));
+ EXPECT_THAT(metric.metric_metadata, IsEmpty());
+ ASSERT_THAT(metric.time_series.samples, SizeIs(1));
+ EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metric.time_series.samples[0].timestamp,
+ Eq(Timestamp::Seconds(1)));
+ EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key", "value"}}));
+ ASSERT_THAT(metric.stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.stddev, absl::optional<double>(0.0));
+ ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metric.stats.max, absl::optional<double>(10.0));
+}
+
+TEST(DefaultMetricsLoggerTest,
+ AccumulatedMetricsReturnedTogetherWithLoggedMetrics) {
+ DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+ logger.LogSingleValueMetric(
+ "metric_name1", "test_case_name1",
+ /*value=*/10, Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+ std::map<std::string, std::string>{{"key_m", "value_m"}});
+ logger.GetMetricsAccumulator()->AddSample(
+ "metric_name2", "test_case_name2",
+ /*value=*/10, Timestamp::Seconds(1),
+ /*point_metadata=*/
+ std::map<std::string, std::string>{{"key_s", "value_s"}});
+
+ std::vector<Metric> metrics = logger.GetCollectedMetrics();
+ ASSERT_THAT(metrics, SizeIs(2));
+ EXPECT_THAT(metrics[0].name, Eq("metric_name2"));
+ EXPECT_THAT(metrics[0].test_case, Eq("test_case_name2"));
+ EXPECT_THAT(metrics[0].unit, Eq(Unit::kUnitless));
+ EXPECT_THAT(metrics[0].improvement_direction,
+ Eq(ImprovementDirection::kNeitherIsBetter));
+ EXPECT_THAT(metrics[0].metric_metadata, IsEmpty());
+ ASSERT_THAT(metrics[0].time_series.samples, SizeIs(1));
+ EXPECT_THAT(metrics[0].time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metrics[0].time_series.samples[0].timestamp,
+ Eq(Timestamp::Seconds(1)));
+ EXPECT_THAT(metrics[0].time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{{"key_s", "value_s"}}));
+ ASSERT_THAT(metrics[0].stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metrics[0].stats.stddev, absl::optional<double>(0.0));
+ ASSERT_THAT(metrics[0].stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metrics[0].stats.max, absl::optional<double>(10.0));
+ EXPECT_THAT(metrics[1].name, Eq("metric_name1"));
+ EXPECT_THAT(metrics[1].test_case, Eq("test_case_name1"));
+ EXPECT_THAT(metrics[1].unit, Eq(Unit::kMilliseconds));
+ EXPECT_THAT(metrics[1].improvement_direction,
+ Eq(ImprovementDirection::kBiggerIsBetter));
+ EXPECT_THAT(metrics[1].metric_metadata,
+ Eq(std::map<std::string, std::string>{{"key_m", "value_m"}}));
+ ASSERT_THAT(metrics[1].time_series.samples, SizeIs(1));
+ EXPECT_THAT(metrics[1].time_series.samples[0].value, Eq(10.0));
+ EXPECT_THAT(metrics[1].time_series.samples[0].sample_metadata,
+ Eq(std::map<std::string, std::string>{}));
+ ASSERT_THAT(metrics[1].stats.mean, absl::optional<double>(10.0));
+ ASSERT_THAT(metrics[1].stats.stddev, absl::nullopt);
+ ASSERT_THAT(metrics[1].stats.min, absl::optional<double>(10.0));
+ ASSERT_THAT(metrics[1].stats.max, absl::optional<double>(10.0));
+}
+
+} // namespace
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter.cc b/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter.cc
new file mode 100644
index 0000000000..86e6f2e136
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter.cc
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/metrics_set_proto_file_exporter.h"
+
+#include <stdio.h>
+
+#include <string>
+
+#include "api/test/metrics/metric.h"
+#include "rtc_base/logging.h"
+#include "test/testsupport/file_utils.h"
+
+#if WEBRTC_ENABLE_PROTOBUF
+#include "api/test/metrics/proto/metric.pb.h"
+#endif
+
+namespace webrtc {
+namespace test {
+namespace {
+
+#if WEBRTC_ENABLE_PROTOBUF
+webrtc::test_metrics::Unit ToProtoUnit(Unit unit) {
+ switch (unit) {
+ case Unit::kMilliseconds:
+ return webrtc::test_metrics::Unit::MILLISECONDS;
+ case Unit::kPercent:
+ return webrtc::test_metrics::Unit::PERCENT;
+ case Unit::kBytes:
+ return webrtc::test_metrics::Unit::BYTES;
+ case Unit::kKilobitsPerSecond:
+ return webrtc::test_metrics::Unit::KILOBITS_PER_SECOND;
+ case Unit::kHertz:
+ return webrtc::test_metrics::Unit::HERTZ;
+ case Unit::kUnitless:
+ return webrtc::test_metrics::Unit::UNITLESS;
+ case Unit::kCount:
+ return webrtc::test_metrics::Unit::COUNT;
+ }
+}
+
+webrtc::test_metrics::ImprovementDirection ToProtoImprovementDirection(
+ ImprovementDirection direction) {
+ switch (direction) {
+ case ImprovementDirection::kBiggerIsBetter:
+ return webrtc::test_metrics::ImprovementDirection::BIGGER_IS_BETTER;
+ case ImprovementDirection::kNeitherIsBetter:
+ return webrtc::test_metrics::ImprovementDirection::NEITHER_IS_BETTER;
+ case ImprovementDirection::kSmallerIsBetter:
+ return webrtc::test_metrics::ImprovementDirection::SMALLER_IS_BETTER;
+ }
+}
+
+void SetTimeSeries(
+ const Metric::TimeSeries& time_series,
+ webrtc::test_metrics::Metric::TimeSeries* proto_time_series) {
+ for (const Metric::TimeSeries::Sample& sample : time_series.samples) {
+ webrtc::test_metrics::Metric::TimeSeries::Sample* proto_sample =
+ proto_time_series->add_samples();
+ proto_sample->set_value(sample.value);
+ proto_sample->set_timestamp_us(sample.timestamp.us());
+ for (const auto& [key, value] : sample.sample_metadata) {
+ proto_sample->mutable_sample_metadata()->insert({key, value});
+ }
+ }
+}
+
+void SetStats(const Metric::Stats& stats,
+ webrtc::test_metrics::Metric::Stats* proto_stats) {
+ if (stats.mean.has_value()) {
+ proto_stats->set_mean(*stats.mean);
+ }
+ if (stats.stddev.has_value()) {
+ proto_stats->set_stddev(*stats.stddev);
+ }
+ if (stats.min.has_value()) {
+ proto_stats->set_min(*stats.min);
+ }
+ if (stats.max.has_value()) {
+ proto_stats->set_max(*stats.max);
+ }
+}
+
+bool WriteMetricsToFile(const std::string& path,
+ const webrtc::test_metrics::MetricsSet& metrics_set) {
+ std::string data;
+ bool ok = metrics_set.SerializeToString(&data);
+ if (!ok) {
+ RTC_LOG(LS_ERROR) << "Failed to serialize histogram set to string";
+ return false;
+ }
+
+ CreateDir(DirName(path));
+ FILE* output = fopen(path.c_str(), "wb");
+ if (output == NULL) {
+ RTC_LOG(LS_ERROR) << "Failed to write to " << path;
+ return false;
+ }
+ size_t written = fwrite(data.c_str(), sizeof(char), data.size(), output);
+ fclose(output);
+
+ if (written != data.size()) {
+ size_t expected = data.size();
+ RTC_LOG(LS_ERROR) << "Wrote " << written << ", tried to write " << expected;
+ return false;
+ }
+ return true;
+}
+#endif // WEBRTC_ENABLE_PROTOBUF
+
+} // namespace
+
+MetricsSetProtoFileExporter::Options::Options(
+ absl::string_view export_file_path)
+ : export_file_path(export_file_path) {}
+MetricsSetProtoFileExporter::Options::Options(
+ absl::string_view export_file_path,
+ bool export_whole_time_series)
+ : export_file_path(export_file_path),
+ export_whole_time_series(export_whole_time_series) {}
+
+bool MetricsSetProtoFileExporter::Export(rtc::ArrayView<const Metric> metrics) {
+#if WEBRTC_ENABLE_PROTOBUF
+ webrtc::test_metrics::MetricsSet metrics_set;
+ for (const Metric& metric : metrics) {
+ webrtc::test_metrics::Metric* metric_proto = metrics_set.add_metrics();
+ metric_proto->set_name(metric.name);
+ metric_proto->set_unit(ToProtoUnit(metric.unit));
+ metric_proto->set_improvement_direction(
+ ToProtoImprovementDirection(metric.improvement_direction));
+ metric_proto->set_test_case(metric.test_case);
+ for (const auto& [key, value] : metric.metric_metadata) {
+ metric_proto->mutable_metric_metadata()->insert({key, value});
+ }
+
+ if (options_.export_whole_time_series) {
+ SetTimeSeries(metric.time_series, metric_proto->mutable_time_series());
+ }
+ SetStats(metric.stats, metric_proto->mutable_stats());
+ }
+
+ return WriteMetricsToFile(options_.export_file_path, metrics_set);
+#else
+ RTC_LOG(LS_ERROR)
+ << "Compile with protobuf support to properly use this class";
+ return false;
+#endif
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter.h b/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter.h
new file mode 100644
index 0000000000..f996e9e7b0
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_METRICS_SET_PROTO_FILE_EXPORTER_H_
+#define API_TEST_METRICS_METRICS_SET_PROTO_FILE_EXPORTER_H_
+
+#include <string>
+
+#include "api/array_view.h"
+#include "api/test/metrics/metric.h"
+#include "api/test/metrics/metrics_exporter.h"
+
+namespace webrtc {
+namespace test {
+
+// Exports all collected metrics to the proto file using
+// `webrtc::test_metrics::MetricsSet` format.
+class MetricsSetProtoFileExporter : public MetricsExporter {
+ public:
+ struct Options {
+ explicit Options(absl::string_view export_file_path);
+ Options(absl::string_view export_file_path, bool export_whole_time_series);
+
+ // File to export proto.
+ std::string export_file_path;
+ // If true will write all time series values to the output proto file,
+ // otherwise will write stats only.
+ bool export_whole_time_series = true;
+ };
+
+ explicit MetricsSetProtoFileExporter(const Options& options)
+ : options_(options) {}
+
+ MetricsSetProtoFileExporter(const MetricsSetProtoFileExporter&) = delete;
+ MetricsSetProtoFileExporter& operator=(const MetricsSetProtoFileExporter&) =
+ delete;
+
+ bool Export(rtc::ArrayView<const Metric> metrics) override;
+
+ private:
+ const Options options_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_METRICS_SET_PROTO_FILE_EXPORTER_H_
diff --git a/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter_test.cc b/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter_test.cc
new file mode 100644
index 0000000000..eb4d483068
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/metrics_set_proto_file_exporter_test.cc
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/metrics_set_proto_file_exporter.h"
+
+#include <fstream>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "api/test/metrics/metric.h"
+#include "api/test/metrics/proto/metric.pb.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/protobuf_utils.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+using ::testing::Eq;
+using ::testing::Test;
+
+namespace proto = ::webrtc::test_metrics;
+
+std::string ReadFileAsString(const std::string& filename) {
+ std::ifstream infile(filename, std::ios_base::binary);
+ auto buffer = std::vector<char>(std::istreambuf_iterator<char>(infile),
+ std::istreambuf_iterator<char>());
+ return std::string(buffer.begin(), buffer.end());
+}
+
+std::map<std::string, std::string> DefaultMetadata() {
+ return std::map<std::string, std::string>{{"key", "value"}};
+}
+
+Metric::TimeSeries::Sample Sample(double value) {
+ return Metric::TimeSeries::Sample{.timestamp = Timestamp::Seconds(1),
+ .value = value,
+ .sample_metadata = DefaultMetadata()};
+}
+
+void AssertSamplesEqual(const proto::Metric::TimeSeries::Sample& actual_sample,
+ const Metric::TimeSeries::Sample& expected_sample) {
+ EXPECT_THAT(actual_sample.value(), Eq(expected_sample.value));
+ EXPECT_THAT(actual_sample.timestamp_us(), Eq(expected_sample.timestamp.us()));
+ EXPECT_THAT(actual_sample.sample_metadata().size(),
+ Eq(expected_sample.sample_metadata.size()));
+ for (const auto& [key, value] : expected_sample.sample_metadata) {
+ EXPECT_THAT(actual_sample.sample_metadata().at(key), Eq(value));
+ }
+}
+
+class MetricsSetProtoFileExporterTest : public Test {
+ protected:
+ ~MetricsSetProtoFileExporterTest() override = default;
+
+ void SetUp() override {
+ temp_filename_ = webrtc::test::TempFilename(
+ webrtc::test::OutputPath(), "metrics_set_proto_file_exporter_test");
+ }
+
+ void TearDown() override {
+ ASSERT_TRUE(webrtc::test::RemoveFile(temp_filename_));
+ }
+
+ std::string temp_filename_;
+};
+
+TEST_F(MetricsSetProtoFileExporterTest, MetricsAreExportedCorrectly) {
+ MetricsSetProtoFileExporter::Options options(temp_filename_);
+ MetricsSetProtoFileExporter exporter(options);
+
+ Metric metric1{
+ .name = "test_metric1",
+ .unit = Unit::kMilliseconds,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name1",
+ .metric_metadata = DefaultMetadata(),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Sample(10), Sample(20)}},
+ .stats =
+ Metric::Stats{.mean = 15.0, .stddev = 5.0, .min = 10.0, .max = 20.0}};
+ Metric metric2{
+ .name = "test_metric2",
+ .unit = Unit::kKilobitsPerSecond,
+ .improvement_direction = ImprovementDirection::kSmallerIsBetter,
+ .test_case = "test_case_name2",
+ .metric_metadata = DefaultMetadata(),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Sample(20), Sample(40)}},
+ .stats = Metric::Stats{
+ .mean = 30.0, .stddev = 10.0, .min = 20.0, .max = 40.0}};
+
+ ASSERT_TRUE(exporter.Export(std::vector<Metric>{metric1, metric2}));
+ webrtc::test_metrics::MetricsSet actual_metrics_set;
+ actual_metrics_set.ParseFromString(ReadFileAsString(temp_filename_));
+ EXPECT_THAT(actual_metrics_set.metrics().size(), Eq(2));
+
+ EXPECT_THAT(actual_metrics_set.metrics(0).name(), Eq("test_metric1"));
+ EXPECT_THAT(actual_metrics_set.metrics(0).test_case(), Eq("test_case_name1"));
+ EXPECT_THAT(actual_metrics_set.metrics(0).unit(),
+ Eq(proto::Unit::MILLISECONDS));
+ EXPECT_THAT(actual_metrics_set.metrics(0).improvement_direction(),
+ Eq(proto::ImprovementDirection::BIGGER_IS_BETTER));
+ EXPECT_THAT(actual_metrics_set.metrics(0).metric_metadata().size(), Eq(1lu));
+ EXPECT_THAT(actual_metrics_set.metrics(0).metric_metadata().at("key"),
+ Eq("value"));
+ EXPECT_THAT(actual_metrics_set.metrics(0).time_series().samples().size(),
+ Eq(2));
+ AssertSamplesEqual(actual_metrics_set.metrics(0).time_series().samples(0),
+ Sample(10.0));
+ AssertSamplesEqual(actual_metrics_set.metrics(0).time_series().samples(1),
+ Sample(20.0));
+ EXPECT_THAT(actual_metrics_set.metrics(0).stats().mean(), Eq(15.0));
+ EXPECT_THAT(actual_metrics_set.metrics(0).stats().stddev(), Eq(5.0));
+ EXPECT_THAT(actual_metrics_set.metrics(0).stats().min(), Eq(10.0));
+ EXPECT_THAT(actual_metrics_set.metrics(0).stats().max(), Eq(20.0));
+
+ EXPECT_THAT(actual_metrics_set.metrics(1).name(), Eq("test_metric2"));
+ EXPECT_THAT(actual_metrics_set.metrics(1).test_case(), Eq("test_case_name2"));
+ EXPECT_THAT(actual_metrics_set.metrics(1).unit(),
+ Eq(proto::Unit::KILOBITS_PER_SECOND));
+ EXPECT_THAT(actual_metrics_set.metrics(1).improvement_direction(),
+ Eq(proto::ImprovementDirection::SMALLER_IS_BETTER));
+ EXPECT_THAT(actual_metrics_set.metrics(1).metric_metadata().size(), Eq(1lu));
+ EXPECT_THAT(actual_metrics_set.metrics(1).metric_metadata().at("key"),
+ Eq("value"));
+ EXPECT_THAT(actual_metrics_set.metrics(1).time_series().samples().size(),
+ Eq(2));
+ AssertSamplesEqual(actual_metrics_set.metrics(1).time_series().samples(0),
+ Sample(20.0));
+ AssertSamplesEqual(actual_metrics_set.metrics(1).time_series().samples(1),
+ Sample(40.0));
+ EXPECT_THAT(actual_metrics_set.metrics(1).stats().mean(), Eq(30.0));
+ EXPECT_THAT(actual_metrics_set.metrics(1).stats().stddev(), Eq(10.0));
+ EXPECT_THAT(actual_metrics_set.metrics(1).stats().min(), Eq(20.0));
+ EXPECT_THAT(actual_metrics_set.metrics(1).stats().max(), Eq(40.0));
+}
+
+} // namespace
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter.cc b/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter.cc
new file mode 100644
index 0000000000..1ce1e63892
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter.cc
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/print_result_proxy_metrics_exporter.h"
+
+#include <string>
+#include <unordered_set>
+
+#include "api/array_view.h"
+#include "api/test/metrics/metric.h"
+#include "test/testsupport/perf_test.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+std::string ToPrintResultUnit(Unit unit) {
+ switch (unit) {
+ case Unit::kMilliseconds:
+ return "msBestFitFormat";
+ case Unit::kPercent:
+ return "n%";
+ case Unit::kBytes:
+ return "sizeInBytes";
+ case Unit::kKilobitsPerSecond:
+ // PrintResults prefer Chrome Perf Dashboard units, which doesn't have
+ // kpbs units, so we change the unit and value accordingly.
+ return "bytesPerSecond";
+ case Unit::kHertz:
+ return "Hz";
+ case Unit::kUnitless:
+ return "unitless";
+ case Unit::kCount:
+ return "count";
+ }
+}
+
+double ToPrintResultValue(double value, Unit unit) {
+ switch (unit) {
+ case Unit::kKilobitsPerSecond:
+ // PrintResults prefer Chrome Perf Dashboard units, which doesn't have
+ // kpbs units, so we change the unit and value accordingly.
+ return value * 1000 / 8;
+ default:
+ return value;
+ }
+}
+
+ImproveDirection ToPrintResultImproveDirection(ImprovementDirection direction) {
+ switch (direction) {
+ case ImprovementDirection::kBiggerIsBetter:
+ return ImproveDirection::kBiggerIsBetter;
+ case ImprovementDirection::kNeitherIsBetter:
+ return ImproveDirection::kNone;
+ case ImprovementDirection::kSmallerIsBetter:
+ return ImproveDirection::kSmallerIsBetter;
+ }
+}
+
+bool IsEmpty(const Metric::Stats& stats) {
+ return !stats.mean.has_value() && !stats.stddev.has_value() &&
+ !stats.min.has_value() && !stats.max.has_value();
+}
+
+bool NameEndsWithConnected(const std::string& name) {
+ static const std::string suffix = "_connected";
+ return name.size() >= suffix.size() &&
+ 0 == name.compare(name.size() - suffix.size(), suffix.size(), suffix);
+}
+
+} // namespace
+
+bool PrintResultProxyMetricsExporter::Export(
+ rtc::ArrayView<const Metric> metrics) {
+ static const std::unordered_set<std::string> per_call_metrics{
+ "actual_encode_bitrate",
+ "encode_frame_rate",
+ "harmonic_framerate",
+ "max_skipped",
+ "min_psnr_dB",
+ "retransmission_bitrate",
+ "sent_packets_loss",
+ "transmission_bitrate",
+ "dropped_frames",
+ "frames_in_flight",
+ "rendered_frames",
+ "average_receive_rate",
+ "average_send_rate",
+ "bytes_discarded_no_receiver",
+ "bytes_received",
+ "bytes_sent",
+ "packets_discarded_no_receiver",
+ "packets_received",
+ "packets_sent",
+ "payload_bytes_received",
+ "payload_bytes_sent",
+ "cpu_usage"};
+
+ for (const Metric& metric : metrics) {
+ if (metric.time_series.samples.empty() && IsEmpty(metric.stats)) {
+ // If there were no data collected for the metric it is expected that 0
+ // will be exported, so add 0 to the samples.
+ PrintResult(metric.name, /*modifier=*/"", metric.test_case,
+ ToPrintResultValue(0, metric.unit),
+ ToPrintResultUnit(metric.unit), /*important=*/false,
+ ToPrintResultImproveDirection(metric.improvement_direction));
+ continue;
+ }
+
+ if (metric.time_series.samples.empty()) {
+ PrintResultMeanAndError(
+ metric.name, /*modifier=*/"", metric.test_case,
+ ToPrintResultValue(*metric.stats.mean, metric.unit),
+ ToPrintResultValue(*metric.stats.stddev, metric.unit),
+ ToPrintResultUnit(metric.unit),
+ /*important=*/false,
+ ToPrintResultImproveDirection(metric.improvement_direction));
+ continue;
+ }
+
+ if (metric.time_series.samples.size() == 1lu &&
+ (per_call_metrics.count(metric.name) > 0 ||
+ NameEndsWithConnected(metric.name))) {
+ // Increase backwards compatibility for 1 value use case.
+ PrintResult(
+ metric.name, /*modifier=*/"", metric.test_case,
+ ToPrintResultValue(metric.time_series.samples[0].value, metric.unit),
+ ToPrintResultUnit(metric.unit), /*important=*/false,
+ ToPrintResultImproveDirection(metric.improvement_direction));
+ continue;
+ }
+
+ SamplesStatsCounter counter;
+ for (size_t i = 0; i < metric.time_series.samples.size(); ++i) {
+ counter.AddSample(SamplesStatsCounter::StatsSample{
+ .value = ToPrintResultValue(metric.time_series.samples[i].value,
+ metric.unit),
+ .time = metric.time_series.samples[i].timestamp,
+ .metadata = metric.time_series.samples[i].sample_metadata});
+ }
+
+ PrintResult(metric.name, /*modifier=*/"", metric.test_case, counter,
+ ToPrintResultUnit(metric.unit),
+ /*important=*/false,
+ ToPrintResultImproveDirection(metric.improvement_direction));
+ }
+ return true;
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter.h b/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter.h
new file mode 100644
index 0000000000..bad0594972
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_PRINT_RESULT_PROXY_METRICS_EXPORTER_H_
+#define API_TEST_METRICS_PRINT_RESULT_PROXY_METRICS_EXPORTER_H_
+
+#include "api/array_view.h"
+#include "api/test/metrics/metric.h"
+#include "api/test/metrics/metrics_exporter.h"
+
+namespace webrtc {
+namespace test {
+
+// Proxies all exported metrics to the `webrtc::test::PrintResult` API.
+class PrintResultProxyMetricsExporter : public MetricsExporter {
+ public:
+ ~PrintResultProxyMetricsExporter() override = default;
+
+ bool Export(rtc::ArrayView<const Metric> metrics) override;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_PRINT_RESULT_PROXY_METRICS_EXPORTER_H_
diff --git a/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter_test.cc b/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter_test.cc
new file mode 100644
index 0000000000..768c794b40
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/print_result_proxy_metrics_exporter_test.cc
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/print_result_proxy_metrics_exporter.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "api/test/metrics/metric.h"
+#include "api/units/timestamp.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+using ::testing::TestWithParam;
+
+std::map<std::string, std::string> DefaultMetadata() {
+ return std::map<std::string, std::string>{{"key", "value"}};
+}
+
+Metric::TimeSeries::Sample Sample(double value) {
+ return Metric::TimeSeries::Sample{.timestamp = Timestamp::Seconds(1),
+ .value = value,
+ .sample_metadata = DefaultMetadata()};
+}
+
+TEST(PrintResultProxyMetricsExporterTest,
+ ExportMetricsWithTimeSeriesFormatCorrect) {
+ Metric metric1{
+ .name = "test_metric1",
+ .unit = Unit::kMilliseconds,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name1",
+ .metric_metadata = DefaultMetadata(),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Sample(10), Sample(20)}},
+ .stats =
+ Metric::Stats{.mean = 15.0, .stddev = 5.0, .min = 10.0, .max = 20.0}};
+ Metric metric2{
+ .name = "test_metric2",
+ .unit = Unit::kKilobitsPerSecond,
+ .improvement_direction = ImprovementDirection::kSmallerIsBetter,
+ .test_case = "test_case_name2",
+ .metric_metadata = DefaultMetadata(),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Sample(20), Sample(40)}},
+ .stats = Metric::Stats{
+ .mean = 30.0, .stddev = 10.0, .min = 20.0, .max = 40.0}};
+
+ testing::internal::CaptureStdout();
+ PrintResultProxyMetricsExporter exporter;
+
+ std::string expected =
+ "RESULT test_metric1: test_case_name1= {15,5} "
+ "msBestFitFormat_biggerIsBetter\n"
+ "RESULT test_metric2: test_case_name2= {3750,1250} "
+ "bytesPerSecond_smallerIsBetter\n";
+
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric1, metric2}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(PrintResultProxyMetricsExporterTest,
+ ExportMetricsTimeSeriesOfSingleValueBackwardCompatibleFormat) {
+ // This should be printed as {mean, stddev} despite only being a single data
+ // point.
+ Metric metric1{
+ .name = "available_send_bandwidth",
+ .unit = Unit::kKilobitsPerSecond,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case/alice",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = std::vector{Sample(1000)}},
+ .stats = Metric::Stats{
+ .mean = 1000.0, .stddev = 0.0, .min = 1000.0, .max = 1000.0}};
+ // This is a per-call metric that shouldn't have a stddev estimate.
+ Metric metric2{
+ .name = "min_psnr_dB",
+ .unit = Unit::kUnitless,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case/alice-video",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = std::vector{Sample(10)}},
+ .stats =
+ Metric::Stats{.mean = 10.0, .stddev = 0.0, .min = 10.0, .max = 10.0}};
+ // This is a per-call metric that shouldn't have a stddev estimate.
+ Metric metric3{
+ .name = "alice_connected",
+ .unit = Unit::kUnitless,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = std::vector{Sample(1)}},
+ .stats =
+ Metric::Stats{.mean = 1.0, .stddev = 0.0, .min = 1.0, .max = 1.0}};
+
+ testing::internal::CaptureStdout();
+ PrintResultProxyMetricsExporter exporter;
+
+ std::string expected =
+ "RESULT available_send_bandwidth: test_case/alice= {125000,0} "
+ "bytesPerSecond_biggerIsBetter\n"
+ "RESULT min_psnr_dB: test_case/alice-video= 10 "
+ "unitless_biggerIsBetter\n"
+ "RESULT alice_connected: test_case= 1 "
+ "unitless_biggerIsBetter\n";
+
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric1, metric2, metric3}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(PrintResultProxyMetricsExporterTest,
+ ExportMetricsWithStatsOnlyFormatCorrect) {
+ Metric metric1{.name = "test_metric1",
+ .unit = Unit::kMilliseconds,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name1",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = {}},
+ .stats = Metric::Stats{
+ .mean = 15.0, .stddev = 5.0, .min = 10.0, .max = 20.0}};
+ Metric metric2{
+ .name = "test_metric2",
+ .unit = Unit::kKilobitsPerSecond,
+ .improvement_direction = ImprovementDirection::kSmallerIsBetter,
+ .test_case = "test_case_name2",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = {}},
+ .stats = Metric::Stats{
+ .mean = 30.0, .stddev = 10.0, .min = 20.0, .max = 40.0}};
+
+ testing::internal::CaptureStdout();
+ PrintResultProxyMetricsExporter exporter;
+
+ std::string expected =
+ "RESULT test_metric1: test_case_name1= {15,5} "
+ "msBestFitFormat_biggerIsBetter\n"
+ "RESULT test_metric2: test_case_name2= {3750,1250} "
+ "bytesPerSecond_smallerIsBetter\n";
+
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric1, metric2}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(PrintResultProxyMetricsExporterTest, ExportEmptyMetricOnlyFormatCorrect) {
+ Metric metric{.name = "test_metric",
+ .unit = Unit::kMilliseconds,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name",
+ .metric_metadata = DefaultMetadata(),
+ .time_series = Metric::TimeSeries{.samples = {}},
+ .stats = Metric::Stats{}};
+
+ testing::internal::CaptureStdout();
+ PrintResultProxyMetricsExporter exporter;
+
+ std::string expected =
+ "RESULT test_metric: test_case_name= 0 "
+ "msBestFitFormat_biggerIsBetter\n";
+
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+} // namespace
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/proto/metric.proto b/third_party/libwebrtc/api/test/metrics/proto/metric.proto
new file mode 100644
index 0000000000..cdd312589d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/proto/metric.proto
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2022 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.
+ */
+
+syntax = "proto3";
+
+package webrtc.test_metrics;
+
+// Root message of the proto file. Contains collection of all the metrics.
+message MetricsSet {
+ repeated Metric metrics = 1;
+}
+
+enum Unit {
+ // Default value that has to be defined.
+ UNDEFINED_UNIT = 0;
+ // General unitless value. Can be used either for dimensionless quantities
+ // (ex ratio) or for units not presented in this enum and too specific to add
+ // to this enum.
+ UNITLESS = 1;
+ MILLISECONDS = 2;
+ PERCENT = 3;
+ BYTES = 4;
+ KILOBITS_PER_SECOND = 5;
+ HERTZ = 6;
+ COUNT = 7;
+}
+
+enum ImprovementDirection {
+ // Default value that has to be defined.
+ UNDEFINED_IMPROVEMENT_DIRECTION = 0;
+ BIGGER_IS_BETTER = 1;
+ NEITHER_IS_BETTER = 2;
+ SMALLER_IS_BETTER = 3;
+}
+
+// Single performance metric with all related metadata.
+message Metric {
+ // Metric name, for example PSNR, SSIM, decode_time, etc.
+ string name = 1;
+ Unit unit = 2;
+ ImprovementDirection improvement_direction = 3;
+ // If the metric is generated by a test, this field can be used to specify
+ // this information.
+ string test_case = 4;
+ // Metadata associated with the whole metric.
+ map<string, string> metric_metadata = 5;
+
+ message TimeSeries {
+ message Sample {
+ // Timestamp in microseconds associated with a sample. For example,
+ // the timestamp when the sample was collected.
+ int64 timestamp_us = 1;
+ double value = 2;
+ // Metadata associated with this particular sample.
+ map<string, string> sample_metadata = 3;
+ }
+ // All samples collected for this metric. It can be empty if the Metric
+ // object only contains `stats`.
+ repeated Sample samples = 1;
+ }
+ // Contains all samples of the metric collected during test execution.
+ // It can be empty if the user only stores precomputed statistics into
+ // `stats`.
+ TimeSeries time_series = 6;
+
+ // Contains metric's precomputed statistics based on the `time_series` or if
+ // `time_series` is omitted (has 0 samples) contains precomputed statistics
+ // provided by the metric's calculator.
+ message Stats {
+ // Sample mean of the metric
+ // (https://en.wikipedia.org/wiki/Sample_mean_and_covariance).
+ optional double mean = 1;
+ // Standard deviation (https://en.wikipedia.org/wiki/Standard_deviation).
+ // Is undefined if `time_series` contains only a single sample.
+ optional double stddev = 2;
+ optional double min = 3;
+ optional double max = 4;
+ }
+ Stats stats = 7;
+}
diff --git a/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter.cc b/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter.cc
new file mode 100644
index 0000000000..22243e73e8
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/stdout_metrics_exporter.h"
+
+#include <stdio.h>
+
+#include <cmath>
+#include <string>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/test/metrics/metric.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+// Returns positive integral part of the number.
+int64_t IntegralPart(double value) {
+ return std::lround(std::floor(std::abs(value)));
+}
+
+void AppendWithPrecision(double value,
+ int digits_after_comma,
+ rtc::StringBuilder& out) {
+ int64_t multiplier = std::lround(std::pow(10, digits_after_comma));
+ int64_t integral_part = IntegralPart(value);
+ double decimal_part = std::abs(value) - integral_part;
+
+ // If decimal part has leading zeros then when it will be multiplied on
+ // `multiplier`, leading zeros will be lost. To preserve them we add "1"
+ // so then leading digit will be greater than 0 and won't be removed.
+ //
+ // During conversion to the string leading digit has to be stripped.
+ //
+ // Also due to rounding it may happen that leading digit may be incremented,
+ // like with `digits_after_comma` 3 number 1.9995 will be rounded to 2. In
+ // such case this increment has to be propagated to the `integral_part`.
+ int64_t decimal_holder = std::lround((1 + decimal_part) * multiplier);
+ if (decimal_holder >= 2 * multiplier) {
+ // Rounding incremented added leading digit, so we need to transfer 1 to
+ // integral part.
+ integral_part++;
+ decimal_holder -= multiplier;
+ }
+ // Remove trailing zeros.
+ while (decimal_holder % 10 == 0) {
+ decimal_holder /= 10;
+ }
+
+ // Print serialized number to output.
+ if (value < 0) {
+ out << "-";
+ }
+ out << integral_part;
+ if (decimal_holder != 1) {
+ out << "." << std::to_string(decimal_holder).substr(1, digits_after_comma);
+ }
+}
+
+} // namespace
+
+StdoutMetricsExporter::StdoutMetricsExporter() : output_(stdout) {}
+
+bool StdoutMetricsExporter::Export(rtc::ArrayView<const Metric> metrics) {
+ for (const Metric& metric : metrics) {
+ PrintMetric(metric);
+ }
+ return true;
+}
+
+void StdoutMetricsExporter::PrintMetric(const Metric& metric) {
+ rtc::StringBuilder value_stream;
+ value_stream << metric.test_case << " / " << metric.name << "= {mean=";
+ if (metric.stats.mean.has_value()) {
+ AppendWithPrecision(*metric.stats.mean, 8, value_stream);
+ } else {
+ value_stream << "-";
+ }
+ value_stream << ", stddev=";
+ if (metric.stats.stddev.has_value()) {
+ AppendWithPrecision(*metric.stats.stddev, 8, value_stream);
+ } else {
+ value_stream << "-";
+ }
+ value_stream << "} " << ToString(metric.unit) << " ("
+ << ToString(metric.improvement_direction) << ")";
+
+ fprintf(output_, "RESULT: %s\n", value_stream.str().c_str());
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter.h b/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter.h
new file mode 100644
index 0000000000..2c572cb2ea
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_METRICS_STDOUT_METRICS_EXPORTER_H_
+#define API_TEST_METRICS_STDOUT_METRICS_EXPORTER_H_
+
+#include "api/array_view.h"
+#include "api/test/metrics/metric.h"
+#include "api/test/metrics/metrics_exporter.h"
+
+namespace webrtc {
+namespace test {
+
+// Exports all collected metrics to stdout.
+class StdoutMetricsExporter : public MetricsExporter {
+ public:
+ StdoutMetricsExporter();
+ ~StdoutMetricsExporter() override = default;
+
+ StdoutMetricsExporter(const StdoutMetricsExporter&) = delete;
+ StdoutMetricsExporter& operator=(const StdoutMetricsExporter&) = delete;
+
+ bool Export(rtc::ArrayView<const Metric> metrics) override;
+
+ private:
+ void PrintMetric(const Metric& metric);
+
+ FILE* const output_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_METRICS_STDOUT_METRICS_EXPORTER_H_
diff --git a/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter_test.cc b/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter_test.cc
new file mode 100644
index 0000000000..91c06fac5b
--- /dev/null
+++ b/third_party/libwebrtc/api/test/metrics/stdout_metrics_exporter_test.cc
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2022 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 "api/test/metrics/stdout_metrics_exporter.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "api/test/metrics/metric.h"
+#include "api/units/timestamp.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+using ::testing::TestWithParam;
+
+std::map<std::string, std::string> DefaultMetadata() {
+ return std::map<std::string, std::string>{{"key", "value"}};
+}
+
+Metric::TimeSeries::Sample Sample(double value) {
+ return Metric::TimeSeries::Sample{.timestamp = Timestamp::Seconds(1),
+ .value = value,
+ .sample_metadata = DefaultMetadata()};
+}
+
+Metric PsnrForTestFoo(double mean, double stddev) {
+ return Metric{.name = "psnr",
+ .unit = Unit::kUnitless,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "foo",
+ .time_series = Metric::TimeSeries{},
+ .stats = Metric::Stats{.mean = mean, .stddev = stddev}};
+}
+
+TEST(StdoutMetricsExporterTest, ExportMetricFormatCorrect) {
+ Metric metric1{
+ .name = "test_metric1",
+ .unit = Unit::kMilliseconds,
+ .improvement_direction = ImprovementDirection::kBiggerIsBetter,
+ .test_case = "test_case_name1",
+ .metric_metadata = DefaultMetadata(),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Sample(10), Sample(20)}},
+ .stats =
+ Metric::Stats{.mean = 15.0, .stddev = 5.0, .min = 10.0, .max = 20.0}};
+ Metric metric2{
+ .name = "test_metric2",
+ .unit = Unit::kKilobitsPerSecond,
+ .improvement_direction = ImprovementDirection::kSmallerIsBetter,
+ .test_case = "test_case_name2",
+ .metric_metadata = DefaultMetadata(),
+ .time_series =
+ Metric::TimeSeries{.samples = std::vector{Sample(20), Sample(40)}},
+ .stats = Metric::Stats{
+ .mean = 30.0, .stddev = 10.0, .min = 20.0, .max = 40.0}};
+
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ std::string expected =
+ "RESULT: test_case_name1 / test_metric1= "
+ "{mean=15, stddev=5} Milliseconds (BiggerIsBetter)\n"
+ "RESULT: test_case_name2 / test_metric2= "
+ "{mean=30, stddev=10} KilobitsPerSecond (SmallerIsBetter)\n";
+
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric1, metric2}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest, PositiveNumberMaxPrecision) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(15.00000001, 0.00000001);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=15.00000001, stddev=0.00000001} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest,
+ PositiveNumberTrailingZeroNotAdded) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(15.12345, 0.12);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=15.12345, stddev=0.12} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest,
+ PositiveNumberTrailingZeroAreRemoved) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(15.123450000, 0.120000000);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=15.12345, stddev=0.12} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest,
+ PositiveNumberRoundsUpOnPrecisionCorrectly) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(15.000000009, 0.999999999);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=15.00000001, stddev=1} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest,
+ PositiveNumberRoundsDownOnPrecisionCorrectly) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(15.0000000049, 0.9999999949);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=15, stddev=0.99999999} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest, NegativeNumberMaxPrecision) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(-15.00000001, -0.00000001);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=-15.00000001, stddev=-0.00000001} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest,
+ NegativeNumberTrailingZeroNotAdded) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(-15.12345, -0.12);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=-15.12345, stddev=-0.12} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest,
+ NegativeNumberTrailingZeroAreRemoved) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(-15.123450000, -0.120000000);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=-15.12345, stddev=-0.12} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest,
+ NegativeNumberRoundsUpOnPrecisionCorrectly) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(-15.000000009, -0.999999999);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=-15.00000001, stddev=-1} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST(StdoutMetricsExporterNumberFormatTest,
+ NegativeNumberRoundsDownOnPrecisionCorrectly) {
+ testing::internal::CaptureStdout();
+ StdoutMetricsExporter exporter;
+
+ Metric metric = PsnrForTestFoo(-15.0000000049, -0.9999999949);
+ std::string expected =
+ "RESULT: foo / psnr= "
+ "{mean=-15, stddev=-0.99999999} Unitless (BiggerIsBetter)\n";
+ EXPECT_TRUE(exporter.Export(std::vector<Metric>{metric}));
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+} // namespace
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/mock_async_dns_resolver.h b/third_party/libwebrtc/api/test/mock_async_dns_resolver.h
new file mode 100644
index 0000000000..81132c96a5
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_async_dns_resolver.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 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 API_TEST_MOCK_ASYNC_DNS_RESOLVER_H_
+#define API_TEST_MOCK_ASYNC_DNS_RESOLVER_H_
+
+#include <functional>
+#include <memory>
+
+#include "api/async_dns_resolver.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockAsyncDnsResolverResult : public AsyncDnsResolverResult {
+ public:
+ MOCK_METHOD(bool,
+ GetResolvedAddress,
+ (int, rtc::SocketAddress*),
+ (const, override));
+ MOCK_METHOD(int, GetError, (), (const, override));
+};
+
+class MockAsyncDnsResolver : public AsyncDnsResolverInterface {
+ public:
+ MOCK_METHOD(void,
+ Start,
+ (const rtc::SocketAddress&, std::function<void()>),
+ (override));
+ MOCK_METHOD(void,
+ Start,
+ (const rtc::SocketAddress&, int family, std::function<void()>),
+ (override));
+ MOCK_METHOD(AsyncDnsResolverResult&, result, (), (const, override));
+};
+
+class MockAsyncDnsResolverFactory : public AsyncDnsResolverFactoryInterface {
+ public:
+ MOCK_METHOD(std::unique_ptr<webrtc::AsyncDnsResolverInterface>,
+ CreateAndResolve,
+ (const rtc::SocketAddress&, std::function<void()>),
+ (override));
+ MOCK_METHOD(std::unique_ptr<webrtc::AsyncDnsResolverInterface>,
+ CreateAndResolve,
+ (const rtc::SocketAddress&, int, std::function<void()>),
+ (override));
+ MOCK_METHOD(std::unique_ptr<webrtc::AsyncDnsResolverInterface>,
+ Create,
+ (),
+ (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_ASYNC_DNS_RESOLVER_H_
diff --git a/third_party/libwebrtc/api/test/mock_audio_mixer.h b/third_party/libwebrtc/api/test/mock_audio_mixer.h
new file mode 100644
index 0000000000..88dc108ca3
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_audio_mixer.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016 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 API_TEST_MOCK_AUDIO_MIXER_H_
+#define API_TEST_MOCK_AUDIO_MIXER_H_
+
+#include "api/audio/audio_mixer.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+namespace test {
+
+class MockAudioMixer : public AudioMixer {
+ public:
+ MOCK_METHOD(bool, AddSource, (Source*), (override));
+ MOCK_METHOD(void, RemoveSource, (Source*), (override));
+ MOCK_METHOD(void, Mix, (size_t number_of_channels, AudioFrame*), (override));
+};
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_AUDIO_MIXER_H_
diff --git a/third_party/libwebrtc/api/test/mock_audio_sink.h b/third_party/libwebrtc/api/test/mock_audio_sink.h
new file mode 100644
index 0000000000..88f38a3c57
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_audio_sink.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 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 API_TEST_MOCK_AUDIO_SINK_H_
+#define API_TEST_MOCK_AUDIO_SINK_H_
+
+#include "absl/types/optional.h"
+#include "api/media_stream_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockAudioSink : public webrtc::AudioTrackSinkInterface {
+ public:
+ MOCK_METHOD(void,
+ OnData,
+ (const void* audio_data,
+ int bits_per_sample,
+ int sample_rate,
+ size_t number_of_channels,
+ size_t number_of_frames),
+ (override));
+
+ MOCK_METHOD(void,
+ OnData,
+ (const void* audio_data,
+ int bits_per_sample,
+ int sample_rate,
+ size_t number_of_channels,
+ size_t number_of_frames,
+ absl::optional<int64_t> absolute_capture_timestamp_ms),
+ (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_AUDIO_SINK_H_
diff --git a/third_party/libwebrtc/api/test/mock_data_channel.h b/third_party/libwebrtc/api/test/mock_data_channel.h
new file mode 100644
index 0000000000..38730eaa51
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_data_channel.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 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 API_TEST_MOCK_DATA_CHANNEL_H_
+#define API_TEST_MOCK_DATA_CHANNEL_H_
+
+#include <string>
+
+#include "api/data_channel_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockDataChannelInterface
+ : public rtc::RefCountedObject<webrtc::DataChannelInterface> {
+ public:
+ static rtc::scoped_refptr<MockDataChannelInterface> Create() {
+ return rtc::scoped_refptr<MockDataChannelInterface>(
+ new MockDataChannelInterface());
+ }
+
+ MOCK_METHOD(void,
+ RegisterObserver,
+ (DataChannelObserver * observer),
+ (override));
+ MOCK_METHOD(void, UnregisterObserver, (), (override));
+ MOCK_METHOD(std::string, label, (), (const, override));
+ MOCK_METHOD(bool, reliable, (), (const, override));
+ MOCK_METHOD(bool, ordered, (), (const, override));
+ MOCK_METHOD(uint16_t, maxRetransmitTime, (), (const, override));
+ MOCK_METHOD(uint16_t, maxRetransmits, (), (const, override));
+ MOCK_METHOD(absl::optional<int>, maxRetransmitsOpt, (), (const, override));
+ MOCK_METHOD(absl::optional<int>, maxPacketLifeTime, (), (const, override));
+ MOCK_METHOD(std::string, protocol, (), (const, override));
+ MOCK_METHOD(bool, negotiated, (), (const, override));
+ MOCK_METHOD(int, id, (), (const, override));
+ MOCK_METHOD(Priority, priority, (), (const, override));
+ MOCK_METHOD(DataState, state, (), (const, override));
+ MOCK_METHOD(RTCError, error, (), (const, override));
+ MOCK_METHOD(uint32_t, messages_sent, (), (const, override));
+ MOCK_METHOD(uint64_t, bytes_sent, (), (const, override));
+ MOCK_METHOD(uint32_t, messages_received, (), (const, override));
+ MOCK_METHOD(uint64_t, bytes_received, (), (const, override));
+ MOCK_METHOD(uint64_t, buffered_amount, (), (const, override));
+ MOCK_METHOD(void, Close, (), (override));
+ MOCK_METHOD(bool, Send, (const DataBuffer& buffer), (override));
+
+ protected:
+ MockDataChannelInterface() = default;
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_DATA_CHANNEL_H_
diff --git a/third_party/libwebrtc/api/test/mock_dtmf_sender.h b/third_party/libwebrtc/api/test/mock_dtmf_sender.h
new file mode 100644
index 0000000000..9029195025
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_dtmf_sender.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 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 API_TEST_MOCK_DTMF_SENDER_H_
+#define API_TEST_MOCK_DTMF_SENDER_H_
+
+#include <string>
+
+#include "api/dtmf_sender_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockDtmfSenderObserver : public DtmfSenderObserverInterface {
+ public:
+ MOCK_METHOD(void,
+ OnToneChange,
+ (const std::string&, const std::string&),
+ (override));
+ MOCK_METHOD(void, OnToneChange, (const std::string&), (override));
+};
+
+static_assert(!std::is_abstract_v<MockDtmfSenderObserver>, "");
+
+class MockDtmfSender : public DtmfSenderInterface {
+ public:
+ static rtc::scoped_refptr<MockDtmfSender> Create() {
+ return rtc::make_ref_counted<MockDtmfSender>();
+ }
+
+ MOCK_METHOD(void,
+ RegisterObserver,
+ (DtmfSenderObserverInterface * observer),
+ (override));
+ MOCK_METHOD(void, UnregisterObserver, (), (override));
+ MOCK_METHOD(bool, CanInsertDtmf, (), (override));
+ MOCK_METHOD(std::string, tones, (), (const override));
+ MOCK_METHOD(int, duration, (), (const override));
+ MOCK_METHOD(int, inter_tone_gap, (), (const override));
+
+ protected:
+ MockDtmfSender() = default;
+};
+
+static_assert(!std::is_abstract_v<rtc::RefCountedObject<MockDtmfSender>>, "");
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_DTMF_SENDER_H_
diff --git a/third_party/libwebrtc/api/test/mock_encoder_selector.h b/third_party/libwebrtc/api/test/mock_encoder_selector.h
new file mode 100644
index 0000000000..2e018d57ba
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_encoder_selector.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018 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 API_TEST_MOCK_ENCODER_SELECTOR_H_
+#define API_TEST_MOCK_ENCODER_SELECTOR_H_
+
+#include "api/video_codecs/video_encoder_factory.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockEncoderSelector
+ : public VideoEncoderFactory::EncoderSelectorInterface {
+ public:
+ MOCK_METHOD(void,
+ OnCurrentEncoder,
+ (const SdpVideoFormat& format),
+ (override));
+
+ MOCK_METHOD(absl::optional<SdpVideoFormat>,
+ OnAvailableBitrate,
+ (const DataRate& rate),
+ (override));
+
+ MOCK_METHOD(absl::optional<SdpVideoFormat>,
+ OnResolutionChange,
+ (const RenderResolution& resolution),
+ (override));
+
+ MOCK_METHOD(absl::optional<SdpVideoFormat>, OnEncoderBroken, (), (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_ENCODER_SELECTOR_H_
diff --git a/third_party/libwebrtc/api/test/mock_fec_controller_override.h b/third_party/libwebrtc/api/test/mock_fec_controller_override.h
new file mode 100644
index 0000000000..8f3accbc03
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_fec_controller_override.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 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 API_TEST_MOCK_FEC_CONTROLLER_OVERRIDE_H_
+#define API_TEST_MOCK_FEC_CONTROLLER_OVERRIDE_H_
+
+#include "api/fec_controller_override.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockFecControllerOverride : public FecControllerOverride {
+ public:
+ MOCK_METHOD(void, SetFecAllowed, (bool fec_allowed), (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_FEC_CONTROLLER_OVERRIDE_H_
diff --git a/third_party/libwebrtc/api/test/mock_frame_decryptor.h b/third_party/libwebrtc/api/test/mock_frame_decryptor.h
new file mode 100644
index 0000000000..9604b96cc2
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_frame_decryptor.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 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 API_TEST_MOCK_FRAME_DECRYPTOR_H_
+#define API_TEST_MOCK_FRAME_DECRYPTOR_H_
+
+#include <vector>
+
+#include "api/crypto/frame_decryptor_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockFrameDecryptor : public FrameDecryptorInterface {
+ public:
+ MOCK_METHOD(Result,
+ Decrypt,
+ (cricket::MediaType,
+ const std::vector<uint32_t>&,
+ rtc::ArrayView<const uint8_t>,
+ rtc::ArrayView<const uint8_t>,
+ rtc::ArrayView<uint8_t>),
+ (override));
+
+ MOCK_METHOD(size_t,
+ GetMaxPlaintextByteSize,
+ (cricket::MediaType, size_t encrypted_frame_size),
+ (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_FRAME_DECRYPTOR_H_
diff --git a/third_party/libwebrtc/api/test/mock_frame_encryptor.h b/third_party/libwebrtc/api/test/mock_frame_encryptor.h
new file mode 100644
index 0000000000..e47321f801
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_frame_encryptor.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 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 API_TEST_MOCK_FRAME_ENCRYPTOR_H_
+#define API_TEST_MOCK_FRAME_ENCRYPTOR_H_
+
+#include "api/crypto/frame_encryptor_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockFrameEncryptor : public FrameEncryptorInterface {
+ public:
+ MOCK_METHOD(int,
+ Encrypt,
+ (cricket::MediaType,
+ uint32_t,
+ rtc::ArrayView<const uint8_t>,
+ rtc::ArrayView<const uint8_t>,
+ rtc::ArrayView<uint8_t>,
+ size_t*),
+ (override));
+
+ MOCK_METHOD(size_t,
+ GetMaxCiphertextByteSize,
+ (cricket::MediaType media_type, size_t frame_size),
+ (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_FRAME_ENCRYPTOR_H_
diff --git a/third_party/libwebrtc/api/test/mock_media_stream_interface.h b/third_party/libwebrtc/api/test/mock_media_stream_interface.h
new file mode 100644
index 0000000000..dfdbab35e9
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_media_stream_interface.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 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 API_TEST_MOCK_MEDIA_STREAM_INTERFACE_H_
+#define API_TEST_MOCK_MEDIA_STREAM_INTERFACE_H_
+
+#include <string>
+
+#include "api/media_stream_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockAudioSource : public rtc::RefCountedObject<AudioSourceInterface> {
+ public:
+ static rtc::scoped_refptr<MockAudioSource> Create() {
+ return rtc::scoped_refptr<MockAudioSource>(new MockAudioSource());
+ }
+
+ MOCK_METHOD(void,
+ RegisterObserver,
+ (ObserverInterface * observer),
+ (override));
+ MOCK_METHOD(void,
+ UnregisterObserver,
+ (ObserverInterface * observer),
+ (override));
+ MOCK_METHOD(SourceState, state, (), (const, override));
+ MOCK_METHOD(bool, remote, (), (const, override));
+ MOCK_METHOD(void, SetVolume, (double volume), (override));
+ MOCK_METHOD(void,
+ RegisterAudioObserver,
+ (AudioObserver * observer),
+ (override));
+ MOCK_METHOD(void,
+ UnregisterAudioObserver,
+ (AudioObserver * observer),
+ (override));
+ MOCK_METHOD(void, AddSink, (AudioTrackSinkInterface * sink), (override));
+ MOCK_METHOD(void, RemoveSink, (AudioTrackSinkInterface * sink), (override));
+ MOCK_METHOD(const cricket::AudioOptions, options, (), (const, override));
+
+ private:
+ MockAudioSource() = default;
+};
+
+class MockAudioTrack : public rtc::RefCountedObject<AudioTrackInterface> {
+ public:
+ static rtc::scoped_refptr<MockAudioTrack> Create() {
+ return rtc::scoped_refptr<MockAudioTrack>(new MockAudioTrack());
+ }
+
+ MOCK_METHOD(void,
+ RegisterObserver,
+ (ObserverInterface * observer),
+ (override));
+ MOCK_METHOD(void,
+ UnregisterObserver,
+ (ObserverInterface * observer),
+ (override));
+ MOCK_METHOD(std::string, kind, (), (const, override));
+ MOCK_METHOD(std::string, id, (), (const, override));
+ MOCK_METHOD(bool, enabled, (), (const, override));
+ MOCK_METHOD(bool, set_enabled, (bool enable), (override));
+ MOCK_METHOD(TrackState, state, (), (const, override));
+ MOCK_METHOD(AudioSourceInterface*, GetSource, (), (const, override));
+ MOCK_METHOD(void, AddSink, (AudioTrackSinkInterface * sink), (override));
+ MOCK_METHOD(void, RemoveSink, (AudioTrackSinkInterface * sink), (override));
+ MOCK_METHOD(bool, GetSignalLevel, (int* level), (override));
+ MOCK_METHOD(rtc::scoped_refptr<AudioProcessorInterface>,
+ GetAudioProcessor,
+ (),
+ (override));
+
+ private:
+ MockAudioTrack() = default;
+};
+
+class MockMediaStream : public MediaStreamInterface {
+ public:
+ MOCK_METHOD(std::string, id, (), (const override));
+ MOCK_METHOD(AudioTrackVector, GetAudioTracks, (), (override));
+ MOCK_METHOD(VideoTrackVector, GetVideoTracks, (), (override));
+ MOCK_METHOD(rtc::scoped_refptr<AudioTrackInterface>,
+ FindAudioTrack,
+ (const std::string& track_id),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<VideoTrackInterface>,
+ FindVideoTrack,
+ (const std::string& track_id),
+ (override));
+ MOCK_METHOD(bool,
+ AddTrack,
+ (rtc::scoped_refptr<AudioTrackInterface> track),
+ (override));
+ MOCK_METHOD(bool,
+ AddTrack,
+ (rtc::scoped_refptr<VideoTrackInterface> track),
+ (override));
+ MOCK_METHOD(bool,
+ RemoveTrack,
+ (rtc::scoped_refptr<AudioTrackInterface> track),
+ (override));
+ MOCK_METHOD(bool,
+ RemoveTrack,
+ (rtc::scoped_refptr<VideoTrackInterface> track),
+ (override));
+ // Old AddTrack/RemoveTrack methods - slated for removal
+ MOCK_METHOD(bool, AddTrack, (AudioTrackInterface * track), (override));
+ MOCK_METHOD(bool, AddTrack, (VideoTrackInterface * track), (override));
+ MOCK_METHOD(bool, RemoveTrack, (AudioTrackInterface * track), (override));
+ MOCK_METHOD(bool, RemoveTrack, (VideoTrackInterface * track), (override));
+ MOCK_METHOD(void,
+ RegisterObserver,
+ (ObserverInterface * observer),
+ (override));
+ MOCK_METHOD(void,
+ UnregisterObserver,
+ (ObserverInterface * observer),
+ (override));
+};
+
+static_assert(!std::is_abstract_v<rtc::RefCountedObject<MockMediaStream>>, "");
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_MEDIA_STREAM_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/test/mock_packet_socket_factory.h b/third_party/libwebrtc/api/test/mock_packet_socket_factory.h
new file mode 100644
index 0000000000..7e59556385
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_packet_socket_factory.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_MOCK_PACKET_SOCKET_FACTORY_H_
+#define API_TEST_MOCK_PACKET_SOCKET_FACTORY_H_
+
+#include <memory>
+#include <string>
+
+#include "api/packet_socket_factory.h"
+#include "test/gmock.h"
+
+namespace rtc {
+class MockPacketSocketFactory : public PacketSocketFactory {
+ public:
+ MOCK_METHOD(AsyncPacketSocket*,
+ CreateUdpSocket,
+ (const SocketAddress&, uint16_t, uint16_t),
+ (override));
+ MOCK_METHOD(AsyncListenSocket*,
+ CreateServerTcpSocket,
+ (const SocketAddress&, uint16_t, uint16_t, int opts),
+ (override));
+ MOCK_METHOD(AsyncPacketSocket*,
+ CreateClientTcpSocket,
+ (const SocketAddress& local_address,
+ const SocketAddress&,
+ const ProxyInfo&,
+ const std::string&,
+ const PacketSocketTcpOptions&),
+ (override));
+ MOCK_METHOD(std::unique_ptr<webrtc::AsyncDnsResolverInterface>,
+ CreateAsyncDnsResolver,
+ (),
+ (override));
+};
+
+static_assert(!std::is_abstract_v<MockPacketSocketFactory>, "");
+
+} // namespace rtc
+
+#endif // API_TEST_MOCK_PACKET_SOCKET_FACTORY_H_
diff --git a/third_party/libwebrtc/api/test/mock_peer_connection_factory_interface.h b/third_party/libwebrtc/api/test/mock_peer_connection_factory_interface.h
new file mode 100644
index 0000000000..ae1fbfbbb7
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_peer_connection_factory_interface.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 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 API_TEST_MOCK_PEER_CONNECTION_FACTORY_INTERFACE_H_
+#define API_TEST_MOCK_PEER_CONNECTION_FACTORY_INTERFACE_H_
+
+#include <memory>
+#include <string>
+
+#include "api/peer_connection_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockPeerConnectionFactoryInterface
+ : public rtc::RefCountedObject<webrtc::PeerConnectionFactoryInterface> {
+ public:
+ static rtc::scoped_refptr<MockPeerConnectionFactoryInterface> Create() {
+ return rtc::scoped_refptr<MockPeerConnectionFactoryInterface>(
+ new MockPeerConnectionFactoryInterface());
+ }
+
+ MOCK_METHOD(void, SetOptions, (const Options&), (override));
+ MOCK_METHOD(rtc::scoped_refptr<PeerConnectionInterface>,
+ CreatePeerConnection,
+ (const PeerConnectionInterface::RTCConfiguration&,
+ PeerConnectionDependencies),
+ (override));
+ MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<PeerConnectionInterface>>,
+ CreatePeerConnectionOrError,
+ (const PeerConnectionInterface::RTCConfiguration&,
+ PeerConnectionDependencies),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<PeerConnectionInterface>,
+ CreatePeerConnection,
+ (const PeerConnectionInterface::RTCConfiguration&,
+ std::unique_ptr<cricket::PortAllocator>,
+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface>,
+ PeerConnectionObserver*),
+ (override));
+ MOCK_METHOD(RtpCapabilities,
+ GetRtpSenderCapabilities,
+ (cricket::MediaType),
+ (const, override));
+ MOCK_METHOD(RtpCapabilities,
+ GetRtpReceiverCapabilities,
+ (cricket::MediaType),
+ (const, override));
+ MOCK_METHOD(rtc::scoped_refptr<MediaStreamInterface>,
+ CreateLocalMediaStream,
+ (const std::string&),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<AudioSourceInterface>,
+ CreateAudioSource,
+ (const cricket::AudioOptions&),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<VideoTrackInterface>,
+ CreateVideoTrack,
+ (const std::string&, VideoTrackSourceInterface*),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<AudioTrackInterface>,
+ CreateAudioTrack,
+ (const std::string&, AudioSourceInterface*),
+ (override));
+ MOCK_METHOD(bool, StartAecDump, (FILE*, int64_t), (override));
+ MOCK_METHOD(void, StopAecDump, (), (override));
+
+ protected:
+ MockPeerConnectionFactoryInterface() = default;
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_PEER_CONNECTION_FACTORY_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/test/mock_peerconnectioninterface.h b/third_party/libwebrtc/api/test/mock_peerconnectioninterface.h
new file mode 100644
index 0000000000..ccc6ce46b1
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_peerconnectioninterface.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2016 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 API_TEST_MOCK_PEERCONNECTIONINTERFACE_H_
+#define API_TEST_MOCK_PEERCONNECTIONINTERFACE_H_
+
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "api/peer_connection_interface.h"
+#include "api/scoped_refptr.h"
+#include "api/sctp_transport_interface.h"
+#include "rtc_base/ref_counted_object.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockPeerConnectionInterface : public webrtc::PeerConnectionInterface {
+ public:
+ static rtc::scoped_refptr<MockPeerConnectionInterface> Create() {
+ return rtc::make_ref_counted<MockPeerConnectionInterface>();
+ }
+
+ // PeerConnectionInterface
+ MOCK_METHOD(rtc::scoped_refptr<StreamCollectionInterface>,
+ local_streams,
+ (),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<StreamCollectionInterface>,
+ remote_streams,
+ (),
+ (override));
+ MOCK_METHOD(bool, AddStream, (MediaStreamInterface*), (override));
+ MOCK_METHOD(void, RemoveStream, (MediaStreamInterface*), (override));
+ MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
+ AddTrack,
+ (rtc::scoped_refptr<MediaStreamTrackInterface>,
+ const std::vector<std::string>&),
+ (override));
+ MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
+ AddTrack,
+ (rtc::scoped_refptr<MediaStreamTrackInterface>,
+ const std::vector<std::string>&,
+ const std::vector<RtpEncodingParameters>&),
+ (override));
+ MOCK_METHOD(RTCError,
+ RemoveTrackOrError,
+ (rtc::scoped_refptr<RtpSenderInterface>),
+ (override));
+ MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ (rtc::scoped_refptr<MediaStreamTrackInterface>),
+ (override));
+ MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ (rtc::scoped_refptr<MediaStreamTrackInterface>,
+ const RtpTransceiverInit&),
+ (override));
+ MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ (cricket::MediaType),
+ (override));
+ MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ (cricket::MediaType, const RtpTransceiverInit&),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<RtpSenderInterface>,
+ CreateSender,
+ (const std::string&, const std::string&),
+ (override));
+ MOCK_METHOD(std::vector<rtc::scoped_refptr<RtpSenderInterface>>,
+ GetSenders,
+ (),
+ (const, override));
+ MOCK_METHOD(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>,
+ GetReceivers,
+ (),
+ (const, override));
+ MOCK_METHOD(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ GetTransceivers,
+ (),
+ (const, override));
+ MOCK_METHOD(bool,
+ GetStats,
+ (StatsObserver*, MediaStreamTrackInterface*, StatsOutputLevel),
+ (override));
+ MOCK_METHOD(void, GetStats, (RTCStatsCollectorCallback*), (override));
+ MOCK_METHOD(void,
+ GetStats,
+ (rtc::scoped_refptr<RtpSenderInterface>,
+ rtc::scoped_refptr<RTCStatsCollectorCallback>),
+ (override));
+ MOCK_METHOD(void,
+ GetStats,
+ (rtc::scoped_refptr<RtpReceiverInterface>,
+ rtc::scoped_refptr<RTCStatsCollectorCallback>),
+ (override));
+ MOCK_METHOD(void, ClearStatsCache, (), (override));
+ MOCK_METHOD(rtc::scoped_refptr<SctpTransportInterface>,
+ GetSctpTransport,
+ (),
+ (const, override));
+ MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>>,
+ CreateDataChannelOrError,
+ (const std::string&, const DataChannelInit*),
+ (override));
+ MOCK_METHOD(const SessionDescriptionInterface*,
+ local_description,
+ (),
+ (const, override));
+ MOCK_METHOD(const SessionDescriptionInterface*,
+ remote_description,
+ (),
+ (const, override));
+ MOCK_METHOD(const SessionDescriptionInterface*,
+ current_local_description,
+ (),
+ (const, override));
+ MOCK_METHOD(const SessionDescriptionInterface*,
+ current_remote_description,
+ (),
+ (const, override));
+ MOCK_METHOD(const SessionDescriptionInterface*,
+ pending_local_description,
+ (),
+ (const, override));
+ MOCK_METHOD(const SessionDescriptionInterface*,
+ pending_remote_description,
+ (),
+ (const, override));
+ MOCK_METHOD(void, RestartIce, (), (override));
+ MOCK_METHOD(void,
+ CreateOffer,
+ (CreateSessionDescriptionObserver*, const RTCOfferAnswerOptions&),
+ (override));
+ MOCK_METHOD(void,
+ CreateAnswer,
+ (CreateSessionDescriptionObserver*, const RTCOfferAnswerOptions&),
+ (override));
+ MOCK_METHOD(void,
+ SetLocalDescription,
+ (SetSessionDescriptionObserver*, SessionDescriptionInterface*),
+ (override));
+ MOCK_METHOD(void,
+ SetRemoteDescription,
+ (SetSessionDescriptionObserver*, SessionDescriptionInterface*),
+ (override));
+ MOCK_METHOD(void,
+ SetRemoteDescription,
+ (std::unique_ptr<SessionDescriptionInterface>,
+ rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>),
+ (override));
+ MOCK_METHOD(PeerConnectionInterface::RTCConfiguration,
+ GetConfiguration,
+ (),
+ (override));
+ MOCK_METHOD(RTCError,
+ SetConfiguration,
+ (const PeerConnectionInterface::RTCConfiguration&),
+ (override));
+ MOCK_METHOD(bool,
+ AddIceCandidate,
+ (const IceCandidateInterface*),
+ (override));
+ MOCK_METHOD(bool,
+ RemoveIceCandidates,
+ (const std::vector<cricket::Candidate>&),
+ (override));
+ MOCK_METHOD(RTCError, SetBitrate, (const BitrateSettings&), (override));
+ MOCK_METHOD(void, SetAudioPlayout, (bool), (override));
+ MOCK_METHOD(void, SetAudioRecording, (bool), (override));
+ MOCK_METHOD(rtc::scoped_refptr<DtlsTransportInterface>,
+ LookupDtlsTransportByMid,
+ (const std::string&),
+ (override));
+ MOCK_METHOD(SignalingState, signaling_state, (), (override));
+ MOCK_METHOD(IceConnectionState, ice_connection_state, (), (override));
+ MOCK_METHOD(IceConnectionState,
+ standardized_ice_connection_state,
+ (),
+ (override));
+ MOCK_METHOD(PeerConnectionState, peer_connection_state, (), (override));
+ MOCK_METHOD(IceGatheringState, ice_gathering_state, (), (override));
+ MOCK_METHOD(absl::optional<bool>, can_trickle_ice_candidates, (), (override));
+ MOCK_METHOD(bool,
+ StartRtcEventLog,
+ (std::unique_ptr<RtcEventLogOutput>, int64_t),
+ (override));
+ MOCK_METHOD(bool,
+ StartRtcEventLog,
+ (std::unique_ptr<RtcEventLogOutput>),
+ (override));
+ MOCK_METHOD(void, StopRtcEventLog, (), (override));
+ MOCK_METHOD(void, Close, (), (override));
+};
+
+static_assert(
+ !std::is_abstract_v<rtc::RefCountedObject<MockPeerConnectionInterface>>,
+ "");
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_PEERCONNECTIONINTERFACE_H_
diff --git a/third_party/libwebrtc/api/test/mock_rtp_transceiver.h b/third_party/libwebrtc/api/test/mock_rtp_transceiver.h
new file mode 100644
index 0000000000..1d21bce5eb
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_rtp_transceiver.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 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 API_TEST_MOCK_RTP_TRANSCEIVER_H_
+#define API_TEST_MOCK_RTP_TRANSCEIVER_H_
+
+#include <string>
+#include <vector>
+
+#include "api/rtp_transceiver_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockRtpTransceiver : public RtpTransceiverInterface {
+ public:
+ MockRtpTransceiver() = default;
+
+ static rtc::scoped_refptr<MockRtpTransceiver> Create() {
+ return rtc::make_ref_counted<MockRtpTransceiver>();
+ }
+
+ MOCK_METHOD(cricket::MediaType, media_type, (), (const, override));
+ MOCK_METHOD(absl::optional<std::string>, mid, (), (const, override));
+ MOCK_METHOD(rtc::scoped_refptr<RtpSenderInterface>,
+ sender,
+ (),
+ (const, override));
+ MOCK_METHOD(rtc::scoped_refptr<RtpReceiverInterface>,
+ receiver,
+ (),
+ (const, override));
+ MOCK_METHOD(bool, stopped, (), (const, override));
+ MOCK_METHOD(bool, stopping, (), (const, override));
+ MOCK_METHOD(RtpTransceiverDirection, direction, (), (const, override));
+ MOCK_METHOD(void,
+ SetDirection,
+ (RtpTransceiverDirection new_direction),
+ (override));
+ MOCK_METHOD(RTCError,
+ SetDirectionWithError,
+ (RtpTransceiverDirection new_direction),
+ (override));
+ MOCK_METHOD(absl::optional<RtpTransceiverDirection>,
+ current_direction,
+ (),
+ (const, override));
+ MOCK_METHOD(absl::optional<RtpTransceiverDirection>,
+ fired_direction,
+ (),
+ (const, override));
+ MOCK_METHOD(RTCError, StopStandard, (), (override));
+ MOCK_METHOD(void, StopInternal, (), (override));
+ MOCK_METHOD(void, Stop, (), (override));
+ MOCK_METHOD(RTCError,
+ SetCodecPreferences,
+ (rtc::ArrayView<RtpCodecCapability> codecs),
+ (override));
+ MOCK_METHOD(std::vector<RtpCodecCapability>,
+ codec_preferences,
+ (),
+ (const, override));
+ MOCK_METHOD(std::vector<RtpHeaderExtensionCapability>,
+ HeaderExtensionsToOffer,
+ (),
+ (const, override));
+ MOCK_METHOD(std::vector<RtpHeaderExtensionCapability>,
+ HeaderExtensionsNegotiated,
+ (),
+ (const, override));
+ MOCK_METHOD(webrtc::RTCError,
+ SetOfferedRtpHeaderExtensions,
+ (rtc::ArrayView<const RtpHeaderExtensionCapability>
+ header_extensions_to_offer),
+ (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_RTP_TRANSCEIVER_H_
diff --git a/third_party/libwebrtc/api/test/mock_rtpreceiver.h b/third_party/libwebrtc/api/test/mock_rtpreceiver.h
new file mode 100644
index 0000000000..63318dc32d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_rtpreceiver.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 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 API_TEST_MOCK_RTPRECEIVER_H_
+#define API_TEST_MOCK_RTPRECEIVER_H_
+
+#include <string>
+#include <vector>
+
+#include "api/crypto/frame_decryptor_interface.h"
+#include "api/rtp_receiver_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockRtpReceiver : public rtc::RefCountedObject<RtpReceiverInterface> {
+ public:
+ MOCK_METHOD(rtc::scoped_refptr<MediaStreamTrackInterface>,
+ track,
+ (),
+ (const, override));
+ MOCK_METHOD(std::vector<rtc::scoped_refptr<MediaStreamInterface>>,
+ streams,
+ (),
+ (const, override));
+ MOCK_METHOD(cricket::MediaType, media_type, (), (const, override));
+ MOCK_METHOD(std::string, id, (), (const, override));
+ MOCK_METHOD(RtpParameters, GetParameters, (), (const, override));
+ MOCK_METHOD(bool,
+ SetParameters,
+ (const webrtc::RtpParameters& parameters),
+ (override));
+ MOCK_METHOD(void, SetObserver, (RtpReceiverObserverInterface*), (override));
+ MOCK_METHOD(void,
+ SetJitterBufferMinimumDelay,
+ (absl::optional<double>),
+ (override));
+ MOCK_METHOD(std::vector<RtpSource>, GetSources, (), (const, override));
+ MOCK_METHOD(void,
+ SetFrameDecryptor,
+ (rtc::scoped_refptr<webrtc::FrameDecryptorInterface>),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<webrtc::FrameDecryptorInterface>,
+ GetFrameDecryptor,
+ (),
+ (const, override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_RTPRECEIVER_H_
diff --git a/third_party/libwebrtc/api/test/mock_rtpsender.h b/third_party/libwebrtc/api/test/mock_rtpsender.h
new file mode 100644
index 0000000000..22113678b9
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_rtpsender.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 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 API_TEST_MOCK_RTPSENDER_H_
+#define API_TEST_MOCK_RTPSENDER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/rtp_sender_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockRtpSender : public RtpSenderInterface {
+ public:
+ static rtc::scoped_refptr<MockRtpSender> Create() {
+ return rtc::make_ref_counted<MockRtpSender>();
+ }
+
+ MOCK_METHOD(bool, SetTrack, (MediaStreamTrackInterface*), (override));
+ MOCK_METHOD(rtc::scoped_refptr<MediaStreamTrackInterface>,
+ track,
+ (),
+ (const, override));
+ MOCK_METHOD(rtc::scoped_refptr<DtlsTransportInterface>,
+ dtls_transport,
+ (),
+ (const override));
+ MOCK_METHOD(uint32_t, ssrc, (), (const, override));
+ MOCK_METHOD(cricket::MediaType, media_type, (), (const, override));
+ MOCK_METHOD(std::string, id, (), (const, override));
+ MOCK_METHOD(std::vector<std::string>, stream_ids, (), (const, override));
+ MOCK_METHOD(void, SetStreams, (const std::vector<std::string>&), (override));
+ MOCK_METHOD(std::vector<RtpEncodingParameters>,
+ init_send_encodings,
+ (),
+ (const, override));
+ MOCK_METHOD(RtpParameters, GetParameters, (), (const, override));
+ MOCK_METHOD(RTCError, SetParameters, (const RtpParameters&), (override));
+ MOCK_METHOD(void,
+ SetParametersAsync,
+ (const RtpParameters&, SetParametersCallback),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<DtmfSenderInterface>,
+ GetDtmfSender,
+ (),
+ (const, override));
+ MOCK_METHOD(void,
+ SetFrameEncryptor,
+ (rtc::scoped_refptr<FrameEncryptorInterface>),
+ (override));
+ MOCK_METHOD(rtc::scoped_refptr<FrameEncryptorInterface>,
+ GetFrameEncryptor,
+ (),
+ (const, override));
+ MOCK_METHOD(void,
+ SetEncoderToPacketizerFrameTransformer,
+ (rtc::scoped_refptr<FrameTransformerInterface>),
+ (override));
+ MOCK_METHOD(void,
+ SetEncoderSelector,
+ (std::unique_ptr<VideoEncoderFactory::EncoderSelectorInterface>),
+ (override));
+};
+
+static_assert(!std::is_abstract_v<rtc::RefCountedObject<MockRtpSender>>, "");
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_RTPSENDER_H_
diff --git a/third_party/libwebrtc/api/test/mock_session_description_interface.h b/third_party/libwebrtc/api/test/mock_session_description_interface.h
new file mode 100644
index 0000000000..f0346ceb11
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_session_description_interface.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 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 API_TEST_MOCK_SESSION_DESCRIPTION_INTERFACE_H_
+#define API_TEST_MOCK_SESSION_DESCRIPTION_INTERFACE_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "api/jsep.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockSessionDescriptionInterface : public SessionDescriptionInterface {
+ public:
+ MOCK_METHOD(std::unique_ptr<SessionDescriptionInterface>,
+ Clone,
+ (),
+ (const, override));
+ MOCK_METHOD(cricket::SessionDescription*, description, (), (override));
+ MOCK_METHOD(const cricket::SessionDescription*,
+ description,
+ (),
+ (const, override));
+ MOCK_METHOD(std::string, session_id, (), (const, override));
+ MOCK_METHOD(std::string, session_version, (), (const, override));
+ MOCK_METHOD(SdpType, GetType, (), (const, override));
+ MOCK_METHOD(std::string, type, (), (const, override));
+ MOCK_METHOD(bool, AddCandidate, (const IceCandidateInterface*), (override));
+ MOCK_METHOD(size_t,
+ RemoveCandidates,
+ (const std::vector<cricket::Candidate>&),
+ (override));
+ MOCK_METHOD(size_t, number_of_mediasections, (), (const, override));
+ MOCK_METHOD(const IceCandidateCollection*,
+ candidates,
+ (size_t),
+ (const, override));
+ MOCK_METHOD(bool, ToString, (std::string*), (const, override));
+};
+
+static_assert(!std::is_abstract_v<MockSessionDescriptionInterface>);
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_SESSION_DESCRIPTION_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/test/mock_transformable_video_frame.h b/third_party/libwebrtc/api/test/mock_transformable_video_frame.h
new file mode 100644
index 0000000000..18b3de534e
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_transformable_video_frame.h
@@ -0,0 +1,42 @@
+/*
+ * 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 API_TEST_MOCK_TRANSFORMABLE_VIDEO_FRAME_H_
+#define API_TEST_MOCK_TRANSFORMABLE_VIDEO_FRAME_H_
+
+#include <vector>
+
+#include "api/frame_transformer_interface.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockTransformableVideoFrame
+ : public webrtc::TransformableVideoFrameInterface {
+ public:
+ MOCK_METHOD(rtc::ArrayView<const uint8_t>, GetData, (), (const, override));
+ MOCK_METHOD(void, SetData, (rtc::ArrayView<const uint8_t> data), (override));
+ MOCK_METHOD(uint32_t, GetTimestamp, (), (const, override));
+ MOCK_METHOD(uint32_t, GetSsrc, (), (const, override));
+ MOCK_METHOD(bool, IsKeyFrame, (), (const, override));
+ MOCK_METHOD(std::vector<uint8_t>, GetAdditionalData, (), (const, override));
+ MOCK_METHOD(const webrtc::VideoFrameMetadata&,
+ GetMetadata,
+ (),
+ (const, override));
+ MOCK_METHOD(void,
+ SetMetadata,
+ (const webrtc::VideoFrameMetadata&),
+ (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_TRANSFORMABLE_VIDEO_FRAME_H_
diff --git a/third_party/libwebrtc/api/test/mock_video_bitrate_allocator.h b/third_party/libwebrtc/api/test/mock_video_bitrate_allocator.h
new file mode 100644
index 0000000000..76cf49e955
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_video_bitrate_allocator.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_H_
+#define API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_H_
+
+#include "api/video/video_bitrate_allocator.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockVideoBitrateAllocator : public webrtc::VideoBitrateAllocator {
+ MOCK_METHOD(VideoBitrateAllocation,
+ Allocate,
+ (VideoBitrateAllocationParameters parameters),
+ (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_H_
diff --git a/third_party/libwebrtc/api/test/mock_video_bitrate_allocator_factory.h b/third_party/libwebrtc/api/test/mock_video_bitrate_allocator_factory.h
new file mode 100644
index 0000000000..16af191970
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_video_bitrate_allocator_factory.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_FACTORY_H_
+#define API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_FACTORY_H_
+
+#include <memory>
+
+#include "api/video/video_bitrate_allocator_factory.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockVideoBitrateAllocatorFactory
+ : public webrtc::VideoBitrateAllocatorFactory {
+ public:
+ ~MockVideoBitrateAllocatorFactory() override { Die(); }
+ MOCK_METHOD(std::unique_ptr<VideoBitrateAllocator>,
+ CreateVideoBitrateAllocator,
+ (const VideoCodec&),
+ (override));
+ MOCK_METHOD(void, Die, ());
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_FACTORY_H_
diff --git a/third_party/libwebrtc/api/test/mock_video_decoder.h b/third_party/libwebrtc/api/test/mock_video_decoder.h
new file mode 100644
index 0000000000..34f732ca4d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_video_decoder.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_MOCK_VIDEO_DECODER_H_
+#define API_TEST_MOCK_VIDEO_DECODER_H_
+
+#include <utility>
+
+#include "api/video_codecs/video_decoder.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockDecodedImageCallback : public DecodedImageCallback {
+ public:
+ MOCK_METHOD(int32_t,
+ Decoded,
+ (VideoFrame & decoded_image), // NOLINT
+ (override));
+ MOCK_METHOD(int32_t,
+ Decoded,
+ (VideoFrame & decoded_image, // NOLINT
+ int64_t decode_time_ms),
+ (override));
+ MOCK_METHOD(void,
+ Decoded,
+ (VideoFrame & decoded_image, // NOLINT
+ absl::optional<int32_t> decode_time_ms,
+ absl::optional<uint8_t> qp),
+ (override));
+};
+
+class MockVideoDecoder : public VideoDecoder {
+ public:
+ MockVideoDecoder() {
+ // Make `Configure` succeed by default, so that individual tests that
+ // verify other methods wouldn't need to stub `Configure`.
+ ON_CALL(*this, Configure).WillByDefault(testing::Return(true));
+ }
+
+ ~MockVideoDecoder() override { Destruct(); }
+
+ MOCK_METHOD(bool, Configure, (const Settings& settings), (override));
+ MOCK_METHOD(int32_t,
+ Decode,
+ (const EncodedImage& input_image,
+ bool missing_frames,
+ int64_t render_time_ms),
+ (override));
+ MOCK_METHOD(int32_t,
+ RegisterDecodeCompleteCallback,
+ (DecodedImageCallback * callback),
+ (override));
+ MOCK_METHOD(int32_t, Release, (), (override));
+
+ // Special utility method that allows a test to monitor/verify when
+ // destruction of the decoder instance occurs.
+ MOCK_METHOD(void, Destruct, (), ());
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_VIDEO_DECODER_H_
diff --git a/third_party/libwebrtc/api/test/mock_video_decoder_factory.h b/third_party/libwebrtc/api/test/mock_video_decoder_factory.h
new file mode 100644
index 0000000000..6150d9f8b5
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_video_decoder_factory.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 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 API_TEST_MOCK_VIDEO_DECODER_FACTORY_H_
+#define API_TEST_MOCK_VIDEO_DECODER_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_decoder.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockVideoDecoderFactory : public webrtc::VideoDecoderFactory {
+ public:
+ ~MockVideoDecoderFactory() override { Die(); }
+
+ MOCK_METHOD(std::vector<webrtc::SdpVideoFormat>,
+ GetSupportedFormats,
+ (),
+ (const, override));
+ MOCK_METHOD(std::unique_ptr<webrtc::VideoDecoder>,
+ CreateVideoDecoder,
+ (const webrtc::SdpVideoFormat&),
+ (override));
+ MOCK_METHOD(void, Die, ());
+};
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_VIDEO_DECODER_FACTORY_H_
diff --git a/third_party/libwebrtc/api/test/mock_video_encoder.h b/third_party/libwebrtc/api/test/mock_video_encoder.h
new file mode 100644
index 0000000000..11e0f64b3f
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_video_encoder.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_MOCK_VIDEO_ENCODER_H_
+#define API_TEST_MOCK_VIDEO_ENCODER_H_
+
+#include <vector>
+
+#include "api/video_codecs/video_encoder.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockEncodedImageCallback : public EncodedImageCallback {
+ public:
+ MOCK_METHOD(Result,
+ OnEncodedImage,
+ (const EncodedImage&, const CodecSpecificInfo*),
+ (override));
+ MOCK_METHOD(void, OnDroppedFrame, (DropReason reason), (override));
+};
+
+class MockVideoEncoder : public VideoEncoder {
+ public:
+ MOCK_METHOD(void,
+ SetFecControllerOverride,
+ (FecControllerOverride*),
+ (override));
+ MOCK_METHOD(int32_t,
+ InitEncode,
+ (const VideoCodec*, int32_t numberOfCores, size_t maxPayloadSize),
+ (override));
+ MOCK_METHOD(int32_t,
+ InitEncode,
+ (const VideoCodec*, const VideoEncoder::Settings& settings),
+ (override));
+
+ MOCK_METHOD(int32_t,
+ Encode,
+ (const VideoFrame& inputImage,
+ const std::vector<VideoFrameType>*),
+ (override));
+ MOCK_METHOD(int32_t,
+ RegisterEncodeCompleteCallback,
+ (EncodedImageCallback*),
+ (override));
+ MOCK_METHOD(int32_t, Release, (), (override));
+ MOCK_METHOD(void,
+ SetRates,
+ (const RateControlParameters& parameters),
+ (override));
+ MOCK_METHOD(void,
+ OnPacketLossRateUpdate,
+ (float packet_loss_rate),
+ (override));
+ MOCK_METHOD(void, OnRttUpdate, (int64_t rtt_ms), (override));
+ MOCK_METHOD(void,
+ OnLossNotification,
+ (const LossNotification& loss_notification),
+ (override));
+ MOCK_METHOD(EncoderInfo, GetEncoderInfo, (), (const, override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_VIDEO_ENCODER_H_
diff --git a/third_party/libwebrtc/api/test/mock_video_encoder_factory.h b/third_party/libwebrtc/api/test/mock_video_encoder_factory.h
new file mode 100644
index 0000000000..02ee7aa15e
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_video_encoder_factory.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 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 API_TEST_MOCK_VIDEO_ENCODER_FACTORY_H_
+#define API_TEST_MOCK_VIDEO_ENCODER_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockVideoEncoderFactory : public webrtc::VideoEncoderFactory {
+ public:
+ ~MockVideoEncoderFactory() override { Die(); }
+
+ MOCK_METHOD(std::vector<SdpVideoFormat>,
+ GetSupportedFormats,
+ (),
+ (const, override));
+ MOCK_METHOD(std::unique_ptr<VideoEncoder>,
+ CreateVideoEncoder,
+ (const SdpVideoFormat&),
+ (override));
+
+ MOCK_METHOD(void, Die, ());
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_VIDEO_ENCODER_FACTORY_H_
diff --git a/third_party/libwebrtc/api/test/mock_video_track.h b/third_party/libwebrtc/api/test/mock_video_track.h
new file mode 100644
index 0000000000..1212a32527
--- /dev/null
+++ b/third_party/libwebrtc/api/test/mock_video_track.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021 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 API_TEST_MOCK_VIDEO_TRACK_H_
+#define API_TEST_MOCK_VIDEO_TRACK_H_
+
+#include <string>
+
+#include "api/media_stream_interface.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_counted_object.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockVideoTrack
+ : public rtc::RefCountedObject<webrtc::VideoTrackInterface> {
+ public:
+ static rtc::scoped_refptr<MockVideoTrack> Create() {
+ return rtc::scoped_refptr<MockVideoTrack>(new MockVideoTrack());
+ }
+
+ // NotifierInterface
+ MOCK_METHOD(void,
+ RegisterObserver,
+ (ObserverInterface * observer),
+ (override));
+ MOCK_METHOD(void,
+ UnregisterObserver,
+ (ObserverInterface * observer),
+ (override));
+
+ // MediaStreamTrackInterface
+ MOCK_METHOD(std::string, kind, (), (const, override));
+ MOCK_METHOD(std::string, id, (), (const, override));
+ MOCK_METHOD(bool, enabled, (), (const, override));
+ MOCK_METHOD(bool, set_enabled, (bool enable), (override));
+ MOCK_METHOD(TrackState, state, (), (const, override));
+
+ // VideoSourceInterface
+ MOCK_METHOD(void,
+ AddOrUpdateSink,
+ (rtc::VideoSinkInterface<VideoFrame> * sink,
+ const rtc::VideoSinkWants& wants),
+ (override));
+ // RemoveSink must guarantee that at the time the method returns,
+ // there is no current and no future calls to VideoSinkInterface::OnFrame.
+ MOCK_METHOD(void,
+ RemoveSink,
+ (rtc::VideoSinkInterface<VideoFrame> * sink),
+ (override));
+
+ // VideoTrackInterface
+ MOCK_METHOD(VideoTrackSourceInterface*, GetSource, (), (const, override));
+
+ MOCK_METHOD(ContentHint, content_hint, (), (const, override));
+ MOCK_METHOD(void, set_content_hint, (ContentHint hint), (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_MOCK_VIDEO_TRACK_H_
diff --git a/third_party/libwebrtc/api/test/neteq_simulator.cc b/third_party/libwebrtc/api/test/neteq_simulator.cc
new file mode 100644
index 0000000000..980db96d32
--- /dev/null
+++ b/third_party/libwebrtc/api/test/neteq_simulator.cc
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018 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 "api/test/neteq_simulator.h"
+
+namespace webrtc {
+namespace test {
+
+NetEqSimulator::SimulationStepResult::SimulationStepResult() = default;
+NetEqSimulator::SimulationStepResult::SimulationStepResult(
+ const NetEqSimulator::SimulationStepResult& other) = default;
+NetEqSimulator::SimulationStepResult::~SimulationStepResult() = default;
+
+NetEqSimulator::NetEqState::NetEqState() = default;
+NetEqSimulator::NetEqState::NetEqState(const NetEqState& other) = default;
+NetEqSimulator::NetEqState::~NetEqState() = default;
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/neteq_simulator.h b/third_party/libwebrtc/api/test/neteq_simulator.h
new file mode 100644
index 0000000000..88c7ffa681
--- /dev/null
+++ b/third_party/libwebrtc/api/test/neteq_simulator.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_NETEQ_SIMULATOR_H_
+#define API_TEST_NETEQ_SIMULATOR_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <vector>
+
+namespace webrtc {
+namespace test {
+
+class NetEqSimulator {
+ public:
+ virtual ~NetEqSimulator() = default;
+
+ enum class Action { kNormal, kExpand, kAccelerate, kPreemptiveExpand };
+
+ // The results of one simulation step.
+ struct SimulationStepResult {
+ SimulationStepResult();
+ SimulationStepResult(const SimulationStepResult& other);
+ ~SimulationStepResult();
+
+ bool is_simulation_finished = false;
+ // The amount of audio produced (in ms) with the actions in this time step.
+ std::map<Action, int> action_times_ms;
+ // The amount of wall clock time (in ms) that elapsed since the previous
+ // event. This is not necessarily equal to the sum of the values in
+ // action_times_ms.
+ int64_t simulation_step_ms = 0;
+ };
+
+ struct NetEqState {
+ NetEqState();
+ NetEqState(const NetEqState& other);
+ ~NetEqState();
+ // The sum of the packet buffer and sync buffer delay.
+ int current_delay_ms = 0;
+ // An indicator that packet loss occurred since the last GetAudio event.
+ bool packet_loss_occurred = false;
+ // An indicator that the packet buffer has been flushed since the last
+ // GetAudio event.
+ bool packet_buffer_flushed = false;
+ // Indicates if the next needed packet is available in the buffer.
+ bool next_packet_available = false;
+ // The inter-arrival times in ms of the packets that have arrived since the
+ // last GetAudio event.
+ std::vector<int> packet_iat_ms;
+ // The current packet size in ms.
+ int packet_size_ms = 0;
+ };
+
+ // Runs the simulation until the end. Returns the duration of the produced
+ // audio in ms.
+ virtual int64_t Run() = 0;
+ // Runs the simulation until we hit the next GetAudio event. If the simulation
+ // is finished, is_simulation_finished will be set to true in the returned
+ // SimulationStepResult.
+ virtual SimulationStepResult RunToNextGetAudio() = 0;
+
+ // Set the next action to be taken by NetEq. This will override any action
+ // that NetEq would normally decide to take.
+ virtual void SetNextAction(Action next_operation) = 0;
+
+ // Get the current state of NetEq.
+ virtual NetEqState GetNetEqState() = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_NETEQ_SIMULATOR_H_
diff --git a/third_party/libwebrtc/api/test/neteq_simulator_factory.cc b/third_party/libwebrtc/api/test/neteq_simulator_factory.cc
new file mode 100644
index 0000000000..82b27e546d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/neteq_simulator_factory.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 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 "api/test/neteq_simulator_factory.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "modules/audio_coding/neteq/tools/neteq_test_factory.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+NetEqTestFactory::Config convertConfig(
+ const NetEqSimulatorFactory::Config& simulation_config,
+ absl::string_view replacement_audio_filename) {
+ NetEqTestFactory::Config config;
+ config.replacement_audio_file = std::string(replacement_audio_filename);
+ config.max_nr_packets_in_buffer = simulation_config.max_nr_packets_in_buffer;
+ config.initial_dummy_packets = simulation_config.initial_dummy_packets;
+ config.skip_get_audio_events = simulation_config.skip_get_audio_events;
+ config.field_trial_string = simulation_config.field_trial_string;
+ config.output_audio_filename = simulation_config.output_audio_filename;
+ config.pythonplot = simulation_config.python_plot_filename.has_value();
+ config.plot_scripts_basename = simulation_config.python_plot_filename;
+ config.textlog = simulation_config.text_log_filename.has_value();
+ config.textlog_filename = simulation_config.text_log_filename;
+ return config;
+}
+} // namespace
+
+NetEqSimulatorFactory::NetEqSimulatorFactory()
+ : factory_(std::make_unique<NetEqTestFactory>()) {}
+
+NetEqSimulatorFactory::~NetEqSimulatorFactory() = default;
+
+std::unique_ptr<NetEqSimulator> NetEqSimulatorFactory::CreateSimulatorFromFile(
+ absl::string_view event_log_filename,
+ absl::string_view replacement_audio_filename,
+ Config simulation_config) {
+ NetEqTestFactory::Config config =
+ convertConfig(simulation_config, replacement_audio_filename);
+ return factory_->InitializeTestFromFile(
+ std::string(event_log_filename), simulation_config.neteq_factory, config);
+}
+
+std::unique_ptr<NetEqSimulator>
+NetEqSimulatorFactory::CreateSimulatorFromString(
+ absl::string_view event_log_file_contents,
+ absl::string_view replacement_audio_filename,
+ Config simulation_config) {
+ NetEqTestFactory::Config config =
+ convertConfig(simulation_config, replacement_audio_filename);
+ return factory_->InitializeTestFromString(
+ std::string(event_log_file_contents), simulation_config.neteq_factory,
+ config);
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/neteq_simulator_factory.h b/third_party/libwebrtc/api/test/neteq_simulator_factory.h
new file mode 100644
index 0000000000..2a716e665e
--- /dev/null
+++ b/third_party/libwebrtc/api/test/neteq_simulator_factory.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_NETEQ_SIMULATOR_FACTORY_H_
+#define API_TEST_NETEQ_SIMULATOR_FACTORY_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/neteq/neteq_factory.h"
+#include "api/test/neteq_simulator.h"
+
+namespace webrtc {
+namespace test {
+
+class NetEqTestFactory;
+
+class NetEqSimulatorFactory {
+ public:
+ NetEqSimulatorFactory();
+ ~NetEqSimulatorFactory();
+ struct Config {
+ // The maximum allowed number of packets in the jitter buffer.
+ int max_nr_packets_in_buffer = 0;
+ // The number of audio packets to insert at the start of the simulation.
+ // Since the simulation is done with a replacement audio file, these
+ // artificial packets will take a small piece of that replacement audio.
+ int initial_dummy_packets = 0;
+ // The number of simulation steps to skip at the start of the simulation.
+ // This removes incoming packets and GetAudio events from the start of the
+ // simulation, until the requested number of GetAudio events has been
+ // removed.
+ int skip_get_audio_events = 0;
+ // A WebRTC field trial string to be used during the simulation.
+ std::string field_trial_string;
+ // A filename for the generated output audio file.
+ absl::optional<std::string> output_audio_filename;
+ // A filename for the python plot.
+ absl::optional<std::string> python_plot_filename;
+ // A filename for the text log.
+ absl::optional<std::string> text_log_filename;
+ // A custom NetEqFactory can be used.
+ NetEqFactory* neteq_factory = nullptr;
+ };
+ std::unique_ptr<NetEqSimulator> CreateSimulatorFromFile(
+ absl::string_view event_log_filename,
+ absl::string_view replacement_audio_filename,
+ Config simulation_config);
+ // The same as above, but pass the file contents as a string.
+ std::unique_ptr<NetEqSimulator> CreateSimulatorFromString(
+ absl::string_view event_log_file_contents,
+ absl::string_view replacement_audio_file,
+ Config simulation_config);
+
+ private:
+ std::unique_ptr<NetEqTestFactory> factory_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_NETEQ_SIMULATOR_FACTORY_H_
diff --git a/third_party/libwebrtc/api/test/network_emulation/BUILD.gn b/third_party/libwebrtc/api/test/network_emulation/BUILD.gn
new file mode 100644
index 0000000000..d009d39a21
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation/BUILD.gn
@@ -0,0 +1,52 @@
+# 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.
+
+import("../../../webrtc.gni")
+
+rtc_library("network_emulation") {
+ visibility = [ "*" ]
+
+ sources = [
+ "cross_traffic.h",
+ "network_emulation_interfaces.cc",
+ "network_emulation_interfaces.h",
+ ]
+
+ deps = [
+ "../..:array_view",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:copy_on_write_buffer",
+ "../../../rtc_base:ip_address",
+ "../../../rtc_base:net_helper",
+ "../../../rtc_base:socket_address",
+ "../../numerics",
+ "../../task_queue",
+ "../../units:data_rate",
+ "../../units:data_size",
+ "../../units:time_delta",
+ "../../units:timestamp",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_library("create_cross_traffic") {
+ visibility = [ "*" ]
+ testonly = true
+
+ sources = [
+ "create_cross_traffic.cc",
+ "create_cross_traffic.h",
+ ]
+
+ deps = [
+ ":network_emulation",
+ "../..:network_emulation_manager_api",
+ "../../../rtc_base/task_utils:repeating_task",
+ "../../../test/network:emulated_network",
+ ]
+}
diff --git a/third_party/libwebrtc/api/test/network_emulation/DEPS b/third_party/libwebrtc/api/test/network_emulation/DEPS
new file mode 100644
index 0000000000..0cf128849d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation/DEPS
@@ -0,0 +1,7 @@
+specific_include_rules = {
+ ".*": [
+ "+rtc_base/socket_address.h",
+ "+rtc_base/ip_address.h",
+ "+rtc_base/copy_on_write_buffer.h",
+ ],
+}
diff --git a/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.cc b/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.cc
new file mode 100644
index 0000000000..36a535cec6
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 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 "api/test/network_emulation/create_cross_traffic.h"
+
+#include <memory>
+
+#include "rtc_base/task_utils/repeating_task.h"
+#include "test/network/cross_traffic.h"
+
+namespace webrtc {
+
+std::unique_ptr<CrossTrafficGenerator> CreateRandomWalkCrossTraffic(
+ CrossTrafficRoute* traffic_route,
+ RandomWalkConfig config) {
+ return std::make_unique<test::RandomWalkCrossTraffic>(config, traffic_route);
+}
+
+std::unique_ptr<CrossTrafficGenerator> CreatePulsedPeaksCrossTraffic(
+ CrossTrafficRoute* traffic_route,
+ PulsedPeaksConfig config) {
+ return std::make_unique<test::PulsedPeaksCrossTraffic>(config, traffic_route);
+}
+
+std::unique_ptr<CrossTrafficGenerator> CreateFakeTcpCrossTraffic(
+ EmulatedRoute* send_route,
+ EmulatedRoute* ret_route,
+ FakeTcpConfig config) {
+ return std::make_unique<test::FakeTcpCrossTraffic>(config, send_route,
+ ret_route);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.h b/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.h
new file mode 100644
index 0000000000..42fc855392
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021 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 API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_
+#define API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_
+
+#include <memory>
+
+#include "api/test/network_emulation/cross_traffic.h"
+#include "api/test/network_emulation_manager.h"
+
+namespace webrtc {
+
+// This API is still in development and can be changed without prior notice.
+
+std::unique_ptr<CrossTrafficGenerator> CreateRandomWalkCrossTraffic(
+ CrossTrafficRoute* traffic_route,
+ RandomWalkConfig config);
+
+std::unique_ptr<CrossTrafficGenerator> CreatePulsedPeaksCrossTraffic(
+ CrossTrafficRoute* traffic_route,
+ PulsedPeaksConfig config);
+
+std::unique_ptr<CrossTrafficGenerator> CreateFakeTcpCrossTraffic(
+ EmulatedRoute* send_route,
+ EmulatedRoute* ret_route,
+ FakeTcpConfig config);
+
+} // namespace webrtc
+
+#endif // API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_
diff --git a/third_party/libwebrtc/api/test/network_emulation/cross_traffic.h b/third_party/libwebrtc/api/test/network_emulation/cross_traffic.h
new file mode 100644
index 0000000000..737a93c2fd
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation/cross_traffic.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021 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 API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_
+#define API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_
+
+#include "api/task_queue/task_queue_base.h"
+#include "api/test/network_emulation/network_emulation_interfaces.h"
+#include "api/units/data_rate.h"
+#include "api/units/data_size.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+
+namespace webrtc {
+
+// This API is still in development and can be changed without prior notice.
+
+// Represents the endpoint for cross traffic that is going through the network.
+// It can be used to emulate unexpected network load.
+class CrossTrafficRoute {
+ public:
+ virtual ~CrossTrafficRoute() = default;
+
+ // Triggers sending of dummy packets with size `packet_size` bytes.
+ virtual void TriggerPacketBurst(size_t num_packets, size_t packet_size) = 0;
+ // Sends a packet over the nodes. The content of the packet is unspecified;
+ // only the size metter for the emulation purposes.
+ virtual void SendPacket(size_t packet_size) = 0;
+ // Sends a packet over the nodes and runs `action` when it has been delivered.
+ virtual void NetworkDelayedAction(size_t packet_size,
+ std::function<void()> action) = 0;
+};
+
+// Describes a way of generating cross traffic on some route. Used by
+// NetworkEmulationManager to produce cross traffic during some period of time.
+class CrossTrafficGenerator {
+ public:
+ virtual ~CrossTrafficGenerator() = default;
+
+ // Time between Process calls.
+ virtual TimeDelta GetProcessInterval() const = 0;
+
+ // Called periodically by NetworkEmulationManager. Generates traffic on the
+ // route.
+ virtual void Process(Timestamp at_time) = 0;
+};
+
+// Config of a cross traffic generator. Generated traffic rises and falls
+// randomly.
+struct RandomWalkConfig {
+ int random_seed = 1;
+ DataRate peak_rate = DataRate::KilobitsPerSec(100);
+ DataSize min_packet_size = DataSize::Bytes(200);
+ TimeDelta min_packet_interval = TimeDelta::Millis(1);
+ TimeDelta update_interval = TimeDelta::Millis(200);
+ double variance = 0.6;
+ double bias = -0.1;
+};
+
+// Config of a cross traffic generator. Generated traffic has form of periodic
+// peaks alternating with periods of silence.
+struct PulsedPeaksConfig {
+ DataRate peak_rate = DataRate::KilobitsPerSec(100);
+ DataSize min_packet_size = DataSize::Bytes(200);
+ TimeDelta min_packet_interval = TimeDelta::Millis(1);
+ TimeDelta send_duration = TimeDelta::Millis(100);
+ TimeDelta hold_duration = TimeDelta::Millis(2000);
+};
+
+struct FakeTcpConfig {
+ DataSize packet_size = DataSize::Bytes(1200);
+ DataSize send_limit = DataSize::PlusInfinity();
+ TimeDelta process_interval = TimeDelta::Millis(200);
+ TimeDelta packet_timeout = TimeDelta::Seconds(1);
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_
diff --git a/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.cc b/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.cc
new file mode 100644
index 0000000000..0f3a7f8ffd
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/test/network_emulation/network_emulation_interfaces.h"
+
+#include "rtc_base/net_helper.h"
+
+namespace webrtc {
+
+EmulatedIpPacket::EmulatedIpPacket(const rtc::SocketAddress& from,
+ const rtc::SocketAddress& to,
+ rtc::CopyOnWriteBuffer data,
+ Timestamp arrival_time,
+ uint16_t application_overhead)
+ : from(from),
+ to(to),
+ data(data),
+ headers_size(to.ipaddr().overhead() + application_overhead +
+ cricket::kUdpHeaderSize),
+ arrival_time(arrival_time) {
+ RTC_DCHECK(to.family() == AF_INET || to.family() == AF_INET6);
+}
+
+DataRate EmulatedNetworkOutgoingStats::AverageSendRate() const {
+ RTC_DCHECK_GE(packets_sent, 2);
+ RTC_DCHECK(first_packet_sent_time.IsFinite());
+ RTC_DCHECK(last_packet_sent_time.IsFinite());
+ return (bytes_sent - first_sent_packet_size) /
+ (last_packet_sent_time - first_packet_sent_time);
+}
+
+DataRate EmulatedNetworkIncomingStats::AverageReceiveRate() const {
+ RTC_DCHECK_GE(packets_received, 2);
+ RTC_DCHECK(first_packet_received_time.IsFinite());
+ RTC_DCHECK(last_packet_received_time.IsFinite());
+ return (bytes_received - first_received_packet_size) /
+ (last_packet_received_time - first_packet_received_time);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.h b/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.h
new file mode 100644
index 0000000000..7cab07b75d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.h
@@ -0,0 +1,311 @@
+/*
+ * 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 API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_
+#define API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/numerics/samples_stats_counter.h"
+#include "api/units/data_rate.h"
+#include "api/units/data_size.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/copy_on_write_buffer.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/socket_address.h"
+
+namespace webrtc {
+
+struct EmulatedIpPacket {
+ public:
+ EmulatedIpPacket(const rtc::SocketAddress& from,
+ const rtc::SocketAddress& to,
+ rtc::CopyOnWriteBuffer data,
+ Timestamp arrival_time,
+ uint16_t application_overhead = 0);
+ ~EmulatedIpPacket() = default;
+ // This object is not copyable or assignable.
+ EmulatedIpPacket(const EmulatedIpPacket&) = delete;
+ EmulatedIpPacket& operator=(const EmulatedIpPacket&) = delete;
+ // This object is only moveable.
+ EmulatedIpPacket(EmulatedIpPacket&&) = default;
+ EmulatedIpPacket& operator=(EmulatedIpPacket&&) = default;
+
+ size_t size() const { return data.size(); }
+ const uint8_t* cdata() const { return data.cdata(); }
+
+ size_t ip_packet_size() const { return size() + headers_size; }
+ rtc::SocketAddress from;
+ rtc::SocketAddress to;
+ // Holds the UDP payload.
+ rtc::CopyOnWriteBuffer data;
+ uint16_t headers_size;
+ Timestamp arrival_time;
+};
+
+// Interface for handling IP packets from an emulated network. This is used with
+// EmulatedEndpoint to receive packets on a specific port.
+class EmulatedNetworkReceiverInterface {
+ public:
+ virtual ~EmulatedNetworkReceiverInterface() = default;
+
+ virtual void OnPacketReceived(EmulatedIpPacket packet) = 0;
+};
+
+struct EmulatedNetworkOutgoingStats {
+ int64_t packets_sent = 0;
+
+ DataSize bytes_sent = DataSize::Zero();
+
+ // Sizes of all sent packets.
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ SamplesStatsCounter sent_packets_size;
+
+ DataSize first_sent_packet_size = DataSize::Zero();
+
+ // Time of the first packet sent or infinite value if no packets were sent.
+ Timestamp first_packet_sent_time = Timestamp::PlusInfinity();
+
+ // Time of the last packet sent or infinite value if no packets were sent.
+ Timestamp last_packet_sent_time = Timestamp::MinusInfinity();
+
+ // Returns average send rate. Requires that at least 2 packets were sent.
+ DataRate AverageSendRate() const;
+};
+
+struct EmulatedNetworkIncomingStats {
+ // Total amount of packets received with or without destination.
+ int64_t packets_received = 0;
+
+ // Total amount of bytes in received packets.
+ DataSize bytes_received = DataSize::Zero();
+
+ // Sizes of all received packets.
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ SamplesStatsCounter received_packets_size;
+
+ // Total amount of packets that were received, but no destination was found.
+ int64_t packets_discarded_no_receiver = 0;
+
+ // Total amount of bytes in discarded packets.
+ DataSize bytes_discarded_no_receiver = DataSize::Zero();
+
+ // Sizes of all packets that were received, but no destination was found.
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ SamplesStatsCounter packets_discarded_no_receiver_size;
+
+ DataSize first_received_packet_size = DataSize::Zero();
+
+ // Time of the first packet received or infinite value if no packets were
+ // received.
+ Timestamp first_packet_received_time = Timestamp::PlusInfinity();
+
+ // Time of the last packet received or infinite value if no packets were
+ // received.
+ Timestamp last_packet_received_time = Timestamp::MinusInfinity();
+
+ DataRate AverageReceiveRate() const;
+};
+
+struct EmulatedNetworkStats {
+ int64_t PacketsSent() const { return overall_outgoing_stats.packets_sent; }
+
+ DataSize BytesSent() const { return overall_outgoing_stats.bytes_sent; }
+
+ // Returns the timestamped sizes of all sent packets.
+ // Returned reference is valid until the next call to a non-const method.
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ const SamplesStatsCounter& SentPacketsSizeCounter() const {
+ return overall_outgoing_stats.sent_packets_size;
+ }
+
+ DataSize FirstSentPacketSize() const {
+ return overall_outgoing_stats.first_sent_packet_size;
+ }
+
+ // Returns time of the first packet sent or infinite value if no packets were
+ // sent.
+ Timestamp FirstPacketSentTime() const {
+ return overall_outgoing_stats.first_packet_sent_time;
+ }
+
+ // Returns time of the last packet sent or infinite value if no packets were
+ // sent.
+ Timestamp LastPacketSentTime() const {
+ return overall_outgoing_stats.last_packet_sent_time;
+ }
+
+ DataRate AverageSendRate() const {
+ return overall_outgoing_stats.AverageSendRate();
+ }
+
+ // Total amount of packets received regardless of the destination address.
+ int64_t PacketsReceived() const {
+ return overall_incoming_stats.packets_received;
+ }
+
+ // Total amount of bytes in received packets.
+ DataSize BytesReceived() const {
+ return overall_incoming_stats.bytes_received;
+ }
+
+ // Returns the timestamped sizes of all received packets.
+ // Returned reference is valid until the next call to a non-const method.
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ const SamplesStatsCounter& ReceivedPacketsSizeCounter() const {
+ return overall_incoming_stats.received_packets_size;
+ }
+
+ // Total amount of packets that were received, but no destination was found.
+ int64_t PacketsDiscardedNoReceiver() const {
+ return overall_incoming_stats.packets_discarded_no_receiver;
+ }
+
+ // Total amount of bytes in dropped packets.
+ DataSize BytesDiscardedNoReceiver() const {
+ return overall_incoming_stats.bytes_discarded_no_receiver;
+ }
+
+ // Returns counter with timestamped sizes of all packets that were received,
+ // but no destination was found.
+ // Returned reference is valid until the next call to a non-const method.
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ const SamplesStatsCounter& PacketsDiscardedNoReceiverSizeCounter() const {
+ return overall_incoming_stats.packets_discarded_no_receiver_size;
+ }
+
+ DataSize FirstReceivedPacketSize() const {
+ return overall_incoming_stats.first_received_packet_size;
+ }
+
+ // Returns time of the first packet received or infinite value if no packets
+ // were received.
+ Timestamp FirstPacketReceivedTime() const {
+ return overall_incoming_stats.first_packet_received_time;
+ }
+
+ // Returns time of the last packet received or infinite value if no packets
+ // were received.
+ Timestamp LastPacketReceivedTime() const {
+ return overall_incoming_stats.last_packet_received_time;
+ }
+
+ DataRate AverageReceiveRate() const {
+ return overall_incoming_stats.AverageReceiveRate();
+ }
+
+ // List of IP addresses that were used to send data considered in this stats
+ // object.
+ std::vector<rtc::IPAddress> local_addresses;
+
+ // Overall outgoing stats for all IP addresses which were requested.
+ EmulatedNetworkOutgoingStats overall_outgoing_stats;
+
+ // Overall incoming stats for all IP addresses from which data was received
+ // on requested interfaces.
+ EmulatedNetworkIncomingStats overall_incoming_stats;
+
+ std::map<rtc::IPAddress, EmulatedNetworkOutgoingStats>
+ outgoing_stats_per_destination;
+ std::map<rtc::IPAddress, EmulatedNetworkIncomingStats>
+ incoming_stats_per_source;
+
+ // Duration between packet was received on network interface and was
+ // dispatched to the network in microseconds.
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ SamplesStatsCounter sent_packets_queue_wait_time_us;
+};
+
+struct EmulatedNetworkNodeStats {
+ // Amount of time each packet spent in the emulated network node for which
+ // stats were collected.
+ //
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ SamplesStatsCounter packet_transport_time;
+
+ // For each packet contains its size divided on the amount of time which it
+ // spent in the emulated network node for which stats were collected.
+ //
+ // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled.
+ SamplesStatsCounter size_to_packet_transport_time;
+};
+
+// EmulatedEndpoint is an abstraction for network interface on device. Instances
+// of this are created by NetworkEmulationManager::CreateEndpoint and
+// thread safe.
+class EmulatedEndpoint : public EmulatedNetworkReceiverInterface {
+ public:
+ // Send packet into network.
+ // `from` will be used to set source address for the packet in destination
+ // socket.
+ // `to` will be used for routing verification and picking right socket by port
+ // on destination endpoint.
+ virtual void SendPacket(const rtc::SocketAddress& from,
+ const rtc::SocketAddress& to,
+ rtc::CopyOnWriteBuffer packet_data,
+ uint16_t application_overhead = 0) = 0;
+
+ // Binds receiver to this endpoint to send and receive data.
+ // `desired_port` is a port that should be used. If it is equal to 0,
+ // endpoint will pick the first available port starting from
+ // `kFirstEphemeralPort`.
+ //
+ // Returns the port, that should be used (it will be equals to desired, if
+ // `desired_port` != 0 and is free or will be the one, selected by endpoint)
+ // or absl::nullopt if desired_port in used. Also fails if there are no more
+ // free ports to bind to.
+ //
+ // The Bind- and Unbind-methods must not be called from within a bound
+ // receiver's OnPacketReceived method.
+ virtual absl::optional<uint16_t> BindReceiver(
+ uint16_t desired_port,
+ EmulatedNetworkReceiverInterface* receiver) = 0;
+ // Unbinds receiver from the specified port. Do nothing if no receiver was
+ // bound before. After this method returns, no more packets can be delivered
+ // to the receiver, and it is safe to destroy it.
+ virtual void UnbindReceiver(uint16_t port) = 0;
+ // Binds receiver that will accept all packets which arrived on any port
+ // for which there are no bound receiver.
+ virtual void BindDefaultReceiver(
+ EmulatedNetworkReceiverInterface* receiver) = 0;
+ // Unbinds default receiver. Do nothing if no default receiver was bound
+ // before.
+ virtual void UnbindDefaultReceiver() = 0;
+ virtual rtc::IPAddress GetPeerLocalAddress() const = 0;
+
+ private:
+ // Ensure that there can be no other subclass than EmulatedEndpointImpl. This
+ // means that it's always safe to downcast EmulatedEndpoint instances to
+ // EmulatedEndpointImpl.
+ friend class EmulatedEndpointImpl;
+ EmulatedEndpoint() = default;
+};
+
+// Simulates a TCP connection, this roughly implements the Reno algorithm. In
+// difference from TCP this only support sending messages with a fixed length,
+// no streaming. This is useful to simulate signaling and cross traffic using
+// message based protocols such as HTTP. It differs from UDP messages in that
+// they are guranteed to be delivered eventually, even on lossy networks.
+class TcpMessageRoute {
+ public:
+ // Sends a TCP message of the given `size` over the route, `on_received` is
+ // called when the message has been delivered. Note that the connection
+ // parameters are reset iff there's no currently pending message on the route.
+ virtual void SendMessage(size_t size, std::function<void()> on_received) = 0;
+
+ protected:
+ ~TcpMessageRoute() = default;
+};
+} // namespace webrtc
+
+#endif // API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_
diff --git a/third_party/libwebrtc/api/test/network_emulation_manager.cc b/third_party/libwebrtc/api/test/network_emulation_manager.cc
new file mode 100644
index 0000000000..236e2f0e17
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation_manager.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/test/network_emulation_manager.h"
+
+#include <utility>
+
+#include "call/simulated_network.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+bool AbslParseFlag(absl::string_view text, TimeMode* mode, std::string* error) {
+ if (text == "realtime") {
+ *mode = TimeMode::kRealTime;
+ return true;
+ }
+ if (text == "simulated") {
+ *mode = TimeMode::kSimulated;
+ return true;
+ }
+ *error =
+ "Unknown value for TimeMode enum. Options are 'realtime' or 'simulated'";
+ return false;
+}
+
+std::string AbslUnparseFlag(TimeMode mode) {
+ switch (mode) {
+ case TimeMode::kRealTime:
+ return "realtime";
+ case TimeMode::kSimulated:
+ return "simulated";
+ }
+ RTC_CHECK_NOTREACHED();
+ return "unknown";
+}
+
+NetworkEmulationManager::SimulatedNetworkNode::Builder&
+NetworkEmulationManager::SimulatedNetworkNode::Builder::config(
+ BuiltInNetworkBehaviorConfig config) {
+ config_ = config;
+ return *this;
+}
+
+NetworkEmulationManager::SimulatedNetworkNode::Builder&
+NetworkEmulationManager::SimulatedNetworkNode::Builder::delay_ms(
+ int queue_delay_ms) {
+ config_.queue_delay_ms = queue_delay_ms;
+ return *this;
+}
+
+NetworkEmulationManager::SimulatedNetworkNode::Builder&
+NetworkEmulationManager::SimulatedNetworkNode::Builder::capacity_kbps(
+ int link_capacity_kbps) {
+ config_.link_capacity_kbps = link_capacity_kbps;
+ return *this;
+}
+
+NetworkEmulationManager::SimulatedNetworkNode::Builder&
+NetworkEmulationManager::SimulatedNetworkNode::Builder::capacity_Mbps(
+ int link_capacity_Mbps) {
+ config_.link_capacity_kbps = link_capacity_Mbps * 1000;
+ return *this;
+}
+
+NetworkEmulationManager::SimulatedNetworkNode::Builder&
+NetworkEmulationManager::SimulatedNetworkNode::Builder::loss(double loss_rate) {
+ config_.loss_percent = std::round(loss_rate * 100);
+ return *this;
+}
+
+NetworkEmulationManager::SimulatedNetworkNode::Builder&
+NetworkEmulationManager::SimulatedNetworkNode::Builder::packet_queue_length(
+ int max_queue_length_in_packets) {
+ config_.queue_length_packets = max_queue_length_in_packets;
+ return *this;
+}
+
+NetworkEmulationManager::SimulatedNetworkNode
+NetworkEmulationManager::SimulatedNetworkNode::Builder::Build(
+ uint64_t random_seed) const {
+ RTC_CHECK(net_);
+ return Build(net_, random_seed);
+}
+
+NetworkEmulationManager::SimulatedNetworkNode
+NetworkEmulationManager::SimulatedNetworkNode::Builder::Build(
+ NetworkEmulationManager* net,
+ uint64_t random_seed) const {
+ RTC_CHECK(net);
+ RTC_CHECK(net_ == nullptr || net_ == net);
+ SimulatedNetworkNode res;
+ auto behavior = std::make_unique<SimulatedNetwork>(config_, random_seed);
+ res.simulation = behavior.get();
+ res.node = net->CreateEmulatedNode(std::move(behavior));
+ return res;
+}
+
+std::pair<EmulatedNetworkManagerInterface*, EmulatedNetworkManagerInterface*>
+NetworkEmulationManager::CreateEndpointPairWithTwoWayRoutes(
+ const BuiltInNetworkBehaviorConfig& config) {
+ auto* alice_node = CreateEmulatedNode(config);
+ auto* bob_node = CreateEmulatedNode(config);
+
+ auto* alice_endpoint = CreateEndpoint(EmulatedEndpointConfig());
+ auto* bob_endpoint = CreateEndpoint(EmulatedEndpointConfig());
+
+ CreateRoute(alice_endpoint, {alice_node}, bob_endpoint);
+ CreateRoute(bob_endpoint, {bob_node}, alice_endpoint);
+
+ return {
+ CreateEmulatedNetworkManagerInterface({alice_endpoint}),
+ CreateEmulatedNetworkManagerInterface({bob_endpoint}),
+ };
+}
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/network_emulation_manager.h b/third_party/libwebrtc/api/test/network_emulation_manager.h
new file mode 100644
index 0000000000..bc9279d306
--- /dev/null
+++ b/third_party/libwebrtc/api/test/network_emulation_manager.h
@@ -0,0 +1,357 @@
+/*
+ * 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 API_TEST_NETWORK_EMULATION_MANAGER_H_
+#define API_TEST_NETWORK_EMULATION_MANAGER_H_
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/packet_socket_factory.h"
+#include "api/test/network_emulation/cross_traffic.h"
+#include "api/test/network_emulation/network_emulation_interfaces.h"
+#include "api/test/peer_network_dependencies.h"
+#include "api/test/simulated_network.h"
+#include "api/test/time_controller.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/network.h"
+#include "rtc_base/network_constants.h"
+#include "rtc_base/thread.h"
+
+namespace webrtc {
+
+// This API is still in development and can be changed without prior notice.
+
+// These classes are forward declared here, because they used as handles, to
+// make it possible for client code to operate with these abstractions and build
+// required network configuration. With forward declaration here implementation
+// is more readable, than with interfaces approach and cause user needn't any
+// API methods on these abstractions it is acceptable here.
+
+// EmulatedNetworkNode is an abstraction for some network in the real world,
+// like 3G network between peers, or Wi-Fi for one peer and LTE for another.
+// Multiple networks can be joined into chain emulating a network path from
+// one peer to another.
+class EmulatedNetworkNode;
+
+// EmulatedRoute is handle for single route from one network interface on one
+// peer device to another network interface on another peer device.
+class EmulatedRoute;
+
+enum class EmulatedNetworkStatsGatheringMode {
+ // Gather main network stats counters. See more details on which particular
+ // metrics are collected in the `EmulatedNetworkStats` and
+ // `EmulatedNetworkNodeStats` documentation.
+ kDefault,
+ // kDefault + also gather per packet statistics. In this mode more memory
+ // will be used.
+ kDebug
+};
+
+struct EmulatedEndpointConfig {
+ enum class IpAddressFamily { kIpv4, kIpv6 };
+
+ // If specified will be used to name endpoint for logging purposes.
+ absl::optional<std::string> name = absl::nullopt;
+ IpAddressFamily generated_ip_family = IpAddressFamily::kIpv4;
+ // If specified will be used as IP address for endpoint node. Must be unique
+ // among all created nodes.
+ absl::optional<rtc::IPAddress> ip;
+ // Should endpoint be enabled or not, when it will be created.
+ // Enabled endpoints will be available for webrtc to send packets.
+ bool start_as_enabled = true;
+ // Network type which will be used to represent endpoint to WebRTC.
+ rtc::AdapterType type = rtc::AdapterType::ADAPTER_TYPE_UNKNOWN;
+ // Allow endpoint to send packets specifying source IP address different to
+ // the current endpoint IP address. If false endpoint will crash if attempt
+ // to send such packet will be done.
+ bool allow_send_packet_with_different_source_ip = false;
+ // Allow endpoint to receive packet with destination IP address different to
+ // the current endpoint IP address. If false endpoint will crash if such
+ // packet will arrive.
+ bool allow_receive_packets_with_different_dest_ip = false;
+};
+
+struct EmulatedTURNServerConfig {
+ EmulatedEndpointConfig client_config;
+ EmulatedEndpointConfig peer_config;
+};
+
+// EmulatedTURNServer is an abstraction for a TURN server.
+class EmulatedTURNServerInterface {
+ public:
+ struct IceServerConfig {
+ std::string username;
+ std::string password;
+ std::string url;
+ };
+
+ virtual ~EmulatedTURNServerInterface() {}
+
+ // Get an IceServer configuration suitable to add to a PeerConnection.
+ virtual IceServerConfig GetIceServerConfig() const = 0;
+
+ // Get non-null client endpoint, an endpoint that accepts TURN allocations.
+ // This shall typically be connected to one or more webrtc endpoint.
+ virtual EmulatedEndpoint* GetClientEndpoint() const = 0;
+
+ // Returns socket address, which client should use to connect to TURN server
+ // and do TURN allocation.
+ virtual rtc::SocketAddress GetClientEndpointAddress() const = 0;
+
+ // Get non-null peer endpoint, that is "connected to the internet".
+ // This shall typically be connected to another TURN server.
+ virtual EmulatedEndpoint* GetPeerEndpoint() const = 0;
+};
+
+// Provide interface to obtain all required objects to inject network emulation
+// layer into PeerConnection. Also contains information about network interfaces
+// accessible by PeerConnection.
+class EmulatedNetworkManagerInterface {
+ public:
+ virtual ~EmulatedNetworkManagerInterface() = default;
+
+ // Returns non-null pointer to thread that have to be used as network thread
+ // for WebRTC to properly setup network emulation. Returned thread is owned
+ // by EmulatedNetworkManagerInterface implementation.
+ virtual rtc::Thread* network_thread() = 0;
+ // Returns non-null pointer to network manager that have to be injected into
+ // WebRTC to properly setup network emulation. Returned manager is owned by
+ // EmulatedNetworkManagerInterface implementation.
+ virtual rtc::NetworkManager* network_manager() = 0;
+ // Returns non-null pointer to packet socket factory that have to be injected
+ // into WebRTC to properly setup network emulation. Returned factory is owned
+ // by EmulatedNetworkManagerInterface implementation.
+ virtual rtc::PacketSocketFactory* packet_socket_factory() = 0;
+ webrtc::webrtc_pc_e2e::PeerNetworkDependencies network_dependencies() {
+ return {network_thread(), network_manager(), packet_socket_factory()};
+ }
+ // Returns list of endpoints that are associated with this instance. Pointers
+ // are guaranteed to be non-null and are owned by NetworkEmulationManager.
+ virtual std::vector<EmulatedEndpoint*> endpoints() const = 0;
+
+ // Passes summarized network stats for endpoints for this manager into
+ // specified `stats_callback`. Callback will be executed on network emulation
+ // internal task queue.
+ virtual void GetStats(
+ std::function<void(EmulatedNetworkStats)> stats_callback) const = 0;
+};
+
+enum class TimeMode { kRealTime, kSimulated };
+
+// Called implicitly when parsing an ABSL_FLAG of type TimeMode.
+// from the command line flag value `text`.
+// Returns `true` and sets `*mode` on success;
+// returns `false` and sets `*error` on failure.
+bool AbslParseFlag(absl::string_view text, TimeMode* mode, std::string* error);
+
+// AbslUnparseFlag returns a textual flag value corresponding to the TimeMode
+// `mode`.
+std::string AbslUnparseFlag(TimeMode mode);
+
+// Provides an API for creating and configuring emulated network layer.
+// All objects returned by this API are owned by NetworkEmulationManager itself
+// and will be deleted when manager will be deleted.
+class NetworkEmulationManager {
+ public:
+ // Helper struct to simplify creation of simulated network behaviors. Contains
+ // non-owning pointers as the underlying instances are owned by the manager.
+ struct SimulatedNetworkNode {
+ SimulatedNetworkInterface* simulation;
+ EmulatedNetworkNode* node;
+
+ class Builder {
+ public:
+ explicit Builder(NetworkEmulationManager* net) : net_(net) {}
+ Builder() : net_(nullptr) {}
+ Builder(const Builder&) = default;
+ // Sets the config state, note that this will replace any previously set
+ // values.
+ Builder& config(BuiltInNetworkBehaviorConfig config);
+ Builder& delay_ms(int queue_delay_ms);
+ Builder& capacity_kbps(int link_capacity_kbps);
+ Builder& capacity_Mbps(int link_capacity_Mbps);
+ Builder& loss(double loss_rate);
+ Builder& packet_queue_length(int max_queue_length_in_packets);
+ SimulatedNetworkNode Build(uint64_t random_seed = 1) const;
+ SimulatedNetworkNode Build(NetworkEmulationManager* net,
+ uint64_t random_seed = 1) const;
+
+ private:
+ NetworkEmulationManager* const net_;
+ BuiltInNetworkBehaviorConfig config_;
+ };
+ };
+ virtual ~NetworkEmulationManager() = default;
+
+ virtual TimeController* time_controller() = 0;
+ // Returns a mode in which underlying time controller operates.
+ virtual TimeMode time_mode() const = 0;
+
+ // Creates an emulated network node, which represents ideal network with
+ // unlimited capacity, no delay and no packet loss.
+ EmulatedNetworkNode* CreateUnconstrainedEmulatedNode() {
+ return CreateEmulatedNode(BuiltInNetworkBehaviorConfig());
+ }
+ // Creates an emulated network node, which represents single network in
+ // the emulated network layer. Uses default implementation on network behavior
+ // which can be configured with `config`. `random_seed` can be provided to
+ // alter randomization behavior.
+ virtual EmulatedNetworkNode* CreateEmulatedNode(
+ BuiltInNetworkBehaviorConfig config,
+ uint64_t random_seed = 1) = 0;
+ // Creates an emulated network node, which represents single network in
+ // the emulated network layer. `network_behavior` determines how created node
+ // will forward incoming packets to the next receiver.
+ virtual EmulatedNetworkNode* CreateEmulatedNode(
+ std::unique_ptr<NetworkBehaviorInterface> network_behavior) = 0;
+
+ virtual SimulatedNetworkNode::Builder NodeBuilder() = 0;
+
+ // Creates an emulated endpoint, which represents single network interface on
+ // the peer's device.
+ virtual EmulatedEndpoint* CreateEndpoint(EmulatedEndpointConfig config) = 0;
+ // Enable emulated endpoint to make it available for webrtc.
+ // Caller mustn't enable currently enabled endpoint.
+ virtual void EnableEndpoint(EmulatedEndpoint* endpoint) = 0;
+ // Disable emulated endpoint to make it unavailable for webrtc.
+ // Caller mustn't disable currently disabled endpoint.
+ virtual void DisableEndpoint(EmulatedEndpoint* endpoint) = 0;
+
+ // Creates a route between endpoints going through specified network nodes.
+ // This route is single direction only and describe how traffic that was
+ // sent by network interface `from` have to be delivered to the network
+ // interface `to`. Return object can be used to remove created route. The
+ // route must contains at least one network node inside it.
+ //
+ // Assume that E{0-9} are endpoints and N{0-9} are network nodes, then
+ // creation of the route have to follow these rules:
+ // 1. A route consists of a source endpoint, an ordered list of one or
+ // more network nodes, and a destination endpoint.
+ // 2. If (E1, ..., E2) is a route, then E1 != E2.
+ // In other words, the source and the destination may not be the same.
+ // 3. Given two simultaneously existing routes (E1, ..., E2) and
+ // (E3, ..., E4), either E1 != E3 or E2 != E4.
+ // In other words, there may be at most one route from any given source
+ // endpoint to any given destination endpoint.
+ // 4. Given two simultaneously existing routes (E1, ..., N1, ..., E2)
+ // and (E3, ..., N2, ..., E4), either N1 != N2 or E2 != E4.
+ // In other words, a network node may not belong to two routes that lead
+ // to the same destination endpoint.
+ virtual EmulatedRoute* CreateRoute(
+ EmulatedEndpoint* from,
+ const std::vector<EmulatedNetworkNode*>& via_nodes,
+ EmulatedEndpoint* to) = 0;
+
+ // Creates a route over the given `via_nodes` creating the required endpoints
+ // in the process. The returned EmulatedRoute pointer can be used in other
+ // calls as a transport route for message or cross traffic.
+ virtual EmulatedRoute* CreateRoute(
+ const std::vector<EmulatedNetworkNode*>& via_nodes) = 0;
+
+ // Creates a default route between endpoints going through specified network
+ // nodes. Default route is used for packet when there is no known route for
+ // packet's destination IP.
+ //
+ // This route is single direction only and describe how traffic that was
+ // sent by network interface `from` have to be delivered in case if routing
+ // was unspecified. Return object can be used to remove created route. The
+ // route must contains at least one network node inside it.
+ //
+ // Assume that E{0-9} are endpoints and N{0-9} are network nodes, then
+ // creation of the route have to follow these rules:
+ // 1. A route consists of a source endpoint, an ordered list of one or
+ // more network nodes, and a destination endpoint.
+ // 2. If (E1, ..., E2) is a route, then E1 != E2.
+ // In other words, the source and the destination may not be the same.
+ // 3. Given two simultaneously existing routes (E1, ..., E2) and
+ // (E3, ..., E4), either E1 != E3 or E2 != E4.
+ // In other words, there may be at most one route from any given source
+ // endpoint to any given destination endpoint.
+ // 4. Given two simultaneously existing routes (E1, ..., N1, ..., E2)
+ // and (E3, ..., N2, ..., E4), either N1 != N2 or E2 != E4.
+ // In other words, a network node may not belong to two routes that lead
+ // to the same destination endpoint.
+ // 5. Any node N can belong to only one default route.
+ virtual EmulatedRoute* CreateDefaultRoute(
+ EmulatedEndpoint* from,
+ const std::vector<EmulatedNetworkNode*>& via_nodes,
+ EmulatedEndpoint* to) = 0;
+
+ // Removes route previously created by CreateRoute(...).
+ // Caller mustn't call this function with route, that have been already
+ // removed earlier. Removing a route that is currently in use will lead to
+ // packets being dropped.
+ virtual void ClearRoute(EmulatedRoute* route) = 0;
+
+ // Creates a simulated TCP connection using `send_route` for traffic and
+ // `ret_route` for feedback. This can be used to emulate HTTP cross traffic
+ // and to implement realistic reliable signaling over lossy networks.
+ // TODO(srte): Handle clearing of the routes involved.
+ virtual TcpMessageRoute* CreateTcpRoute(EmulatedRoute* send_route,
+ EmulatedRoute* ret_route) = 0;
+
+ // Creates a route over the given `via_nodes`. Returns an object that can be
+ // used to emulate network load with cross traffic over the created route.
+ virtual CrossTrafficRoute* CreateCrossTrafficRoute(
+ const std::vector<EmulatedNetworkNode*>& via_nodes) = 0;
+
+ // Starts generating cross traffic using given `generator`. Takes ownership
+ // over the generator.
+ virtual CrossTrafficGenerator* StartCrossTraffic(
+ std::unique_ptr<CrossTrafficGenerator> generator) = 0;
+
+ // Stops generating cross traffic that was started using given `generator`.
+ // The `generator` shouldn't be used after and the reference may be invalid.
+ virtual void StopCrossTraffic(CrossTrafficGenerator* generator) = 0;
+
+ // Creates EmulatedNetworkManagerInterface which can be used then to inject
+ // network emulation layer into PeerConnection. `endpoints` - are available
+ // network interfaces for PeerConnection. If endpoint is enabled, it will be
+ // immediately available for PeerConnection, otherwise user will be able to
+ // enable endpoint later to make it available for PeerConnection.
+ virtual EmulatedNetworkManagerInterface*
+ CreateEmulatedNetworkManagerInterface(
+ const std::vector<EmulatedEndpoint*>& endpoints) = 0;
+
+ // Passes combined network stats for all specified `endpoints` into specified
+ // `stats_callback`. Callback will be executed on network emulation
+ // internal task queue.
+ virtual void GetStats(
+ rtc::ArrayView<EmulatedEndpoint* const> endpoints,
+ std::function<void(EmulatedNetworkStats)> stats_callback) = 0;
+
+ // Passes combined network stats for all specified `nodes` into specified
+ // `stats_callback`. Callback will be executed on network emulation
+ // internal task queue.
+ virtual void GetStats(
+ rtc::ArrayView<EmulatedNetworkNode* const> nodes,
+ std::function<void(EmulatedNetworkNodeStats)> stats_callback) = 0;
+
+ // Create a EmulatedTURNServer.
+ // The TURN server has 2 endpoints that need to be connected with routes,
+ // - GetClientEndpoint() - the endpoint that accepts TURN allocations.
+ // - GetPeerEndpoint() - the endpoint that is "connected to the internet".
+ virtual EmulatedTURNServerInterface* CreateTURNServer(
+ EmulatedTURNServerConfig config) = 0;
+
+ // Create a pair of EmulatedNetworkManagerInterfaces connected to each other.
+ std::pair<EmulatedNetworkManagerInterface*, EmulatedNetworkManagerInterface*>
+ CreateEndpointPairWithTwoWayRoutes(
+ const BuiltInNetworkBehaviorConfig& config);
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_NETWORK_EMULATION_MANAGER_H_
diff --git a/third_party/libwebrtc/api/test/pclf/BUILD.gn b/third_party/libwebrtc/api/test/pclf/BUILD.gn
new file mode 100644
index 0000000000..0526478e8b
--- /dev/null
+++ b/third_party/libwebrtc/api/test/pclf/BUILD.gn
@@ -0,0 +1,114 @@
+# Copyright (c) 2022 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.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("media_configuration") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [
+ "media_configuration.cc",
+ "media_configuration.h",
+ ]
+
+ deps = [
+ "../..:array_view",
+ "../..:audio_options_api",
+ "../..:audio_quality_analyzer_api",
+ "../..:callfactory_api",
+ "../..:fec_controller_api",
+ "../..:frame_generator_api",
+ "../..:function_view",
+ "../..:libjingle_peerconnection_api",
+ "../..:media_stream_interface",
+ "../..:packet_socket_factory",
+ "../..:peer_network_dependencies",
+ "../..:rtp_parameters",
+ "../..:simulated_network_api",
+ "../..:stats_observer_interface",
+ "../..:track_id_stream_info_map",
+ "../..:video_quality_analyzer_api",
+ "../../../modules/audio_processing:api",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:network",
+ "../../../rtc_base:rtc_certificate_generator",
+ "../../../rtc_base:ssl",
+ "../../../rtc_base:stringutils",
+ "../../../rtc_base:threading",
+ "../../../test:fileutils",
+ "../../../test:video_test_support",
+ "../../../test/pc/e2e/analyzer/video:video_dumping",
+ "../../audio:audio_mixer_api",
+ "../../rtc_event_log",
+ "../../task_queue",
+ "../../transport:network_control",
+ "../../units:time_delta",
+ "../../video_codecs:video_codecs_api",
+ "../video:video_frame_writer",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+rtc_library("media_quality_test_params") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [ "media_quality_test_params.h" ]
+
+ deps = [
+ ":media_configuration",
+ "../../../api:callfactory_api",
+ "../../../api:fec_controller_api",
+ "../../../api:field_trials_view",
+ "../../../api:libjingle_peerconnection_api",
+ "../../../api:packet_socket_factory",
+ "../../../api/audio:audio_mixer_api",
+ "../../../api/rtc_event_log",
+ "../../../api/task_queue",
+ "../../../api/transport:network_control",
+ "../../../api/video_codecs:video_codecs_api",
+ "../../../modules/audio_processing:api",
+ "../../../p2p:rtc_p2p",
+ "../../../rtc_base:network",
+ "../../../rtc_base:rtc_certificate_generator",
+ "../../../rtc_base:ssl",
+ "../../../rtc_base:threading",
+ ]
+}
+
+rtc_library("peer_configurer") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [
+ "peer_configurer.cc",
+ "peer_configurer.h",
+ ]
+ deps = [
+ ":media_configuration",
+ ":media_quality_test_params",
+ "../../../api:callfactory_api",
+ "../../../api:create_peer_connection_quality_test_frame_generator",
+ "../../../api:fec_controller_api",
+ "../../../api:packet_socket_factory",
+ "../../../api:peer_network_dependencies",
+ "../../../api/audio:audio_mixer_api",
+ "../../../api/rtc_event_log",
+ "../../../api/task_queue",
+ "../../../api/transport:network_control",
+ "../../../api/video_codecs:video_codecs_api",
+ "../../../modules/audio_processing:api",
+ "../../../rtc_base:network",
+ "../../../rtc_base:rtc_certificate_generator",
+ "../../../rtc_base:ssl",
+ "../../../rtc_base:threading",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
diff --git a/third_party/libwebrtc/api/test/pclf/DEPS b/third_party/libwebrtc/api/test/pclf/DEPS
new file mode 100644
index 0000000000..60cc0aeeb3
--- /dev/null
+++ b/third_party/libwebrtc/api/test/pclf/DEPS
@@ -0,0 +1,13 @@
+specific_include_rules = {
+ ".*": [
+ "+modules/audio_processing/include/audio_processing.h",
+ "+rtc_base/checks.h",
+ "+rtc_base/network.h",
+ "+rtc_base/rtc_certificate_generator.h",
+ "+rtc_base/ssl_certificate.h",
+ "+rtc_base/thread.h",
+ ],
+ "media_quality_test_params\.h": [
+ "+p2p/base/port_allocator.h",
+ ],
+}
diff --git a/third_party/libwebrtc/api/test/pclf/media_configuration.cc b/third_party/libwebrtc/api/test/pclf/media_configuration.cc
new file mode 100644
index 0000000000..56b9e52e01
--- /dev/null
+++ b/third_party/libwebrtc/api/test/pclf/media_configuration.cc
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2022 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 "api/test/pclf/media_configuration.h"
+
+#include <string>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/test/video/video_frame_writer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/pc/e2e/analyzer/video/video_dumping.h"
+#include "test/testsupport/file_utils.h"
+#include "test/testsupport/video_frame_writer.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+namespace {
+
+std::string SpecToString(VideoResolution::Spec spec) {
+ switch (spec) {
+ case VideoResolution::Spec::kNone:
+ return "None";
+ case VideoResolution::Spec::kMaxFromSender:
+ return "MaxFromSender";
+ }
+}
+
+void AppendResolution(const VideoResolution& resolution,
+ rtc::StringBuilder& builder) {
+ builder << "_" << resolution.width() << "x" << resolution.height() << "_"
+ << resolution.fps();
+}
+
+} // namespace
+
+ScreenShareConfig::ScreenShareConfig(TimeDelta slide_change_interval)
+ : slide_change_interval(slide_change_interval) {
+ RTC_CHECK_GT(slide_change_interval.ms(), 0);
+}
+VideoSimulcastConfig::VideoSimulcastConfig(int simulcast_streams_count)
+ : simulcast_streams_count(simulcast_streams_count) {
+ RTC_CHECK_GT(simulcast_streams_count, 1);
+}
+EmulatedSFUConfig::EmulatedSFUConfig(int target_layer_index)
+ : target_layer_index(target_layer_index) {
+ RTC_CHECK_GE(target_layer_index, 0);
+}
+
+EmulatedSFUConfig::EmulatedSFUConfig(absl::optional<int> target_layer_index,
+ absl::optional<int> target_temporal_index)
+ : target_layer_index(target_layer_index),
+ target_temporal_index(target_temporal_index) {
+ RTC_CHECK_GE(target_temporal_index.value_or(0), 0);
+ if (target_temporal_index)
+ RTC_CHECK_GE(*target_temporal_index, 0);
+}
+
+VideoResolution::VideoResolution(size_t width, size_t height, int32_t fps)
+ : width_(width), height_(height), fps_(fps), spec_(Spec::kNone) {}
+VideoResolution::VideoResolution(Spec spec)
+ : width_(0), height_(0), fps_(0), spec_(spec) {}
+
+bool VideoResolution::operator==(const VideoResolution& other) const {
+ if (spec_ != Spec::kNone && spec_ == other.spec_) {
+ // If there is some particular spec set, then it doesn't matter what
+ // values we have in other fields.
+ return true;
+ }
+ return width_ == other.width_ && height_ == other.height_ &&
+ fps_ == other.fps_ && spec_ == other.spec_;
+}
+bool VideoResolution::operator!=(const VideoResolution& other) const {
+ return !(*this == other);
+}
+
+bool VideoResolution::IsRegular() const {
+ return spec_ == Spec::kNone;
+}
+std::string VideoResolution::ToString() const {
+ rtc::StringBuilder out;
+ out << "{ width=" << width_ << ", height=" << height_ << ", fps=" << fps_
+ << ", spec=" << SpecToString(spec_) << " }";
+ return out.Release();
+}
+
+VideoDumpOptions::VideoDumpOptions(
+ absl::string_view output_directory,
+ int sampling_modulo,
+ bool export_frame_ids,
+ std::function<std::unique_ptr<test::VideoFrameWriter>(
+ absl::string_view file_name_prefix,
+ const VideoResolution& resolution)> video_frame_writer_factory)
+ : output_directory_(output_directory),
+ sampling_modulo_(sampling_modulo),
+ export_frame_ids_(export_frame_ids),
+ video_frame_writer_factory_(video_frame_writer_factory) {
+ RTC_CHECK_GT(sampling_modulo, 0);
+}
+
+VideoDumpOptions::VideoDumpOptions(absl::string_view output_directory,
+ bool export_frame_ids)
+ : VideoDumpOptions(output_directory,
+ kDefaultSamplingModulo,
+ export_frame_ids) {}
+
+std::unique_ptr<test::VideoFrameWriter>
+VideoDumpOptions::CreateInputDumpVideoFrameWriter(
+ absl::string_view stream_label,
+ const VideoResolution& resolution) const {
+ std::unique_ptr<test::VideoFrameWriter> writer = video_frame_writer_factory_(
+ GetInputDumpFileName(stream_label, resolution), resolution);
+ absl::optional<std::string> frame_ids_file =
+ GetInputFrameIdsDumpFileName(stream_label, resolution);
+ if (frame_ids_file.has_value()) {
+ writer = CreateVideoFrameWithIdsWriter(std::move(writer), *frame_ids_file);
+ }
+ return writer;
+}
+
+std::unique_ptr<test::VideoFrameWriter>
+VideoDumpOptions::CreateOutputDumpVideoFrameWriter(
+ absl::string_view stream_label,
+ absl::string_view receiver,
+ const VideoResolution& resolution) const {
+ std::unique_ptr<test::VideoFrameWriter> writer = video_frame_writer_factory_(
+ GetOutputDumpFileName(stream_label, receiver, resolution), resolution);
+ absl::optional<std::string> frame_ids_file =
+ GetOutputFrameIdsDumpFileName(stream_label, receiver, resolution);
+ if (frame_ids_file.has_value()) {
+ writer = CreateVideoFrameWithIdsWriter(std::move(writer), *frame_ids_file);
+ }
+ return writer;
+}
+
+std::unique_ptr<test::VideoFrameWriter>
+VideoDumpOptions::Y4mVideoFrameWriterFactory(
+ absl::string_view file_name_prefix,
+ const VideoResolution& resolution) {
+ return std::make_unique<test::Y4mVideoFrameWriterImpl>(
+ std::string(file_name_prefix) + ".y4m", resolution.width(),
+ resolution.height(), resolution.fps());
+}
+
+std::string VideoDumpOptions::GetInputDumpFileName(
+ absl::string_view stream_label,
+ const VideoResolution& resolution) const {
+ rtc::StringBuilder file_name;
+ file_name << stream_label;
+ AppendResolution(resolution, file_name);
+ return test::JoinFilename(output_directory_, file_name.Release());
+}
+
+absl::optional<std::string> VideoDumpOptions::GetInputFrameIdsDumpFileName(
+ absl::string_view stream_label,
+ const VideoResolution& resolution) const {
+ if (!export_frame_ids_) {
+ return absl::nullopt;
+ }
+ return GetInputDumpFileName(stream_label, resolution) + ".frame_ids.txt";
+}
+
+std::string VideoDumpOptions::GetOutputDumpFileName(
+ absl::string_view stream_label,
+ absl::string_view receiver,
+ const VideoResolution& resolution) const {
+ rtc::StringBuilder file_name;
+ file_name << stream_label << "_" << receiver;
+ AppendResolution(resolution, file_name);
+ return test::JoinFilename(output_directory_, file_name.Release());
+}
+
+absl::optional<std::string> VideoDumpOptions::GetOutputFrameIdsDumpFileName(
+ absl::string_view stream_label,
+ absl::string_view receiver,
+ const VideoResolution& resolution) const {
+ if (!export_frame_ids_) {
+ return absl::nullopt;
+ }
+ return GetOutputDumpFileName(stream_label, receiver, resolution) +
+ ".frame_ids.txt";
+}
+
+std::string VideoDumpOptions::ToString() const {
+ rtc::StringBuilder out;
+ out << "{ output_directory_=" << output_directory_
+ << ", sampling_modulo_=" << sampling_modulo_
+ << ", export_frame_ids_=" << export_frame_ids_ << " }";
+ return out.Release();
+}
+
+VideoConfig::VideoConfig(const VideoResolution& resolution)
+ : width(resolution.width()),
+ height(resolution.height()),
+ fps(resolution.fps()) {
+ RTC_CHECK(resolution.IsRegular());
+}
+VideoConfig::VideoConfig(size_t width, size_t height, int32_t fps)
+ : width(width), height(height), fps(fps) {}
+VideoConfig::VideoConfig(std::string stream_label,
+ size_t width,
+ size_t height,
+ int32_t fps)
+ : width(width),
+ height(height),
+ fps(fps),
+ stream_label(std::move(stream_label)) {}
+
+AudioConfig::AudioConfig(std::string stream_label)
+ : stream_label(std::move(stream_label)) {}
+
+VideoCodecConfig::VideoCodecConfig(std::string name)
+ : name(std::move(name)), required_params() {}
+VideoCodecConfig::VideoCodecConfig(
+ std::string name,
+ std::map<std::string, std::string> required_params)
+ : name(std::move(name)), required_params(std::move(required_params)) {}
+
+absl::optional<VideoResolution> VideoSubscription::GetMaxResolution(
+ rtc::ArrayView<const VideoConfig> video_configs) {
+ std::vector<VideoResolution> resolutions;
+ for (const auto& video_config : video_configs) {
+ resolutions.push_back(video_config.GetResolution());
+ }
+ return GetMaxResolution(resolutions);
+}
+
+absl::optional<VideoResolution> VideoSubscription::GetMaxResolution(
+ rtc::ArrayView<const VideoResolution> resolutions) {
+ if (resolutions.empty()) {
+ return absl::nullopt;
+ }
+
+ VideoResolution max_resolution;
+ for (const VideoResolution& resolution : resolutions) {
+ if (max_resolution.width() < resolution.width()) {
+ max_resolution.set_width(resolution.width());
+ }
+ if (max_resolution.height() < resolution.height()) {
+ max_resolution.set_height(resolution.height());
+ }
+ if (max_resolution.fps() < resolution.fps()) {
+ max_resolution.set_fps(resolution.fps());
+ }
+ }
+ return max_resolution;
+}
+
+bool VideoSubscription::operator==(const VideoSubscription& other) const {
+ return default_resolution_ == other.default_resolution_ &&
+ peers_resolution_ == other.peers_resolution_;
+}
+bool VideoSubscription::operator!=(const VideoSubscription& other) const {
+ return !(*this == other);
+}
+
+VideoSubscription& VideoSubscription::SubscribeToPeer(
+ absl::string_view peer_name,
+ VideoResolution resolution) {
+ peers_resolution_[std::string(peer_name)] = resolution;
+ return *this;
+}
+
+VideoSubscription& VideoSubscription::SubscribeToAllPeers(
+ VideoResolution resolution) {
+ default_resolution_ = resolution;
+ return *this;
+}
+
+absl::optional<VideoResolution> VideoSubscription::GetResolutionForPeer(
+ absl::string_view peer_name) const {
+ auto it = peers_resolution_.find(std::string(peer_name));
+ if (it == peers_resolution_.end()) {
+ return default_resolution_;
+ }
+ return it->second;
+}
+
+std::vector<std::string> VideoSubscription::GetSubscribedPeers() const {
+ std::vector<std::string> subscribed_streams;
+ subscribed_streams.reserve(peers_resolution_.size());
+ for (const auto& entry : peers_resolution_) {
+ subscribed_streams.push_back(entry.first);
+ }
+ return subscribed_streams;
+}
+
+std::string VideoSubscription::ToString() const {
+ rtc::StringBuilder out;
+ out << "{ default_resolution_=[";
+ if (default_resolution_.has_value()) {
+ out << default_resolution_->ToString();
+ } else {
+ out << "undefined";
+ }
+ out << "], {";
+ for (const auto& [peer_name, resolution] : peers_resolution_) {
+ out << "[" << peer_name << ": " << resolution.ToString() << "], ";
+ }
+ out << "} }";
+ return out.Release();
+}
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/pclf/media_configuration.h b/third_party/libwebrtc/api/test/pclf/media_configuration.h
new file mode 100644
index 0000000000..8e841a265b
--- /dev/null
+++ b/third_party/libwebrtc/api/test/pclf/media_configuration.h
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_PCLF_MEDIA_CONFIGURATION_H_
+#define API_TEST_PCLF_MEDIA_CONFIGURATION_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/async_resolver_factory.h"
+#include "api/audio/audio_mixer.h"
+#include "api/audio_options.h"
+#include "api/call/call_factory_interface.h"
+#include "api/fec_controller.h"
+#include "api/function_view.h"
+#include "api/media_stream_interface.h"
+#include "api/peer_connection_interface.h"
+#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
+#include "api/rtp_parameters.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/test/audio_quality_analyzer_interface.h"
+#include "api/test/frame_generator_interface.h"
+#include "api/test/peer_network_dependencies.h"
+#include "api/test/simulated_network.h"
+#include "api/test/stats_observer_interface.h"
+#include "api/test/track_id_stream_info_map.h"
+#include "api/test/video/video_frame_writer.h"
+#include "api/test/video_quality_analyzer_interface.h"
+#include "api/transport/network_control.h"
+#include "api/units/time_delta.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/network.h"
+#include "rtc_base/rtc_certificate_generator.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/thread.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+constexpr size_t kDefaultSlidesWidth = 1850;
+constexpr size_t kDefaultSlidesHeight = 1110;
+
+// The index of required capturing device in OS provided list of video
+// devices. On Linux and Windows the list will be obtained via
+// webrtc::VideoCaptureModule::DeviceInfo, on Mac OS via
+// [RTCCameraVideoCapturer captureDevices].
+enum class CapturingDeviceIndex : size_t {};
+
+// Contains parameters for screen share scrolling.
+//
+// If scrolling is enabled, then it will be done by putting sliding window
+// on source video and moving this window from top left corner to the
+// bottom right corner of the picture.
+//
+// In such case source dimensions must be greater or equal to the sliding
+// window dimensions. So `source_width` and `source_height` are the dimensions
+// of the source frame, while `VideoConfig::width` and `VideoConfig::height`
+// are the dimensions of the sliding window.
+//
+// Because `source_width` and `source_height` are dimensions of the source
+// frame, they have to be width and height of videos from
+// `ScreenShareConfig::slides_yuv_file_names`.
+//
+// Because scrolling have to be done on single slide it also requires, that
+// `duration` must be less or equal to
+// `ScreenShareConfig::slide_change_interval`.
+struct ScrollingParams {
+ // Duration of scrolling.
+ TimeDelta duration;
+ // Width of source slides video.
+ size_t source_width = kDefaultSlidesWidth;
+ // Height of source slides video.
+ size_t source_height = kDefaultSlidesHeight;
+};
+
+// Contains screen share video stream properties.
+struct ScreenShareConfig {
+ explicit ScreenShareConfig(TimeDelta slide_change_interval);
+
+ // Shows how long one slide should be presented on the screen during
+ // slide generation.
+ TimeDelta slide_change_interval;
+ // If true, slides will be generated programmatically. No scrolling params
+ // will be applied in such case.
+ bool generate_slides = false;
+ // If present scrolling will be applied. Please read extra requirement on
+ // `slides_yuv_file_names` for scrolling.
+ absl::optional<ScrollingParams> scrolling_params;
+ // Contains list of yuv files with slides.
+ //
+ // If empty, default set of slides will be used. In such case
+ // `VideoConfig::width` must be equal to `kDefaultSlidesWidth` and
+ // `VideoConfig::height` must be equal to `kDefaultSlidesHeight` or if
+ // `scrolling_params` are specified, then `ScrollingParams::source_width`
+ // must be equal to `kDefaultSlidesWidth` and
+ // `ScrollingParams::source_height` must be equal to `kDefaultSlidesHeight`.
+ std::vector<std::string> slides_yuv_file_names;
+};
+
+// Config for Vp8 simulcast or non-standard Vp9 SVC testing.
+//
+// To configure standard SVC setting, use `scalability_mode` in the
+// `encoding_params` array.
+// This configures Vp9 SVC by requesting simulcast layers, the request is
+// internally converted to a request for SVC layers.
+//
+// SVC support is limited:
+// During SVC testing there is no SFU, so framework will try to emulate SFU
+// behavior in regular p2p call. Because of it there are such limitations:
+// * if `target_spatial_index` is not equal to the highest spatial layer
+// then no packet/frame drops are allowed.
+//
+// If there will be any drops, that will affect requested layer, then
+// WebRTC SVC implementation will continue decoding only the highest
+// available layer and won't restore lower layers, so analyzer won't
+// receive required data which will cause wrong results or test failures.
+struct VideoSimulcastConfig {
+ explicit VideoSimulcastConfig(int simulcast_streams_count);
+
+ // Specified amount of simulcast streams/SVC layers, depending on which
+ // encoder is used.
+ int simulcast_streams_count;
+};
+
+// Configuration for the emulated Selective Forward Unit (SFU)
+//
+// The framework can optionally filter out frames that are decoded
+// using an emulated SFU.
+// When using simulcast or SVC, it's not always desirable to receive
+// all frames. In a real world call, a SFU will only forward a subset
+// of the frames.
+// The emulated SFU is not able to change its configuration dynamically,
+// if adaptation happens during the call, layers may be dropped and the
+// analyzer won't receive the required data which will cause wrong results or
+// test failures.
+struct EmulatedSFUConfig {
+ EmulatedSFUConfig() = default;
+ explicit EmulatedSFUConfig(int target_layer_index);
+ EmulatedSFUConfig(absl::optional<int> target_layer_index,
+ absl::optional<int> target_temporal_index);
+
+ // Specifies simulcast or spatial index of the video stream to analyze.
+ // There are 2 cases:
+ // 1. simulcast encoding is used:
+ // in such case `target_layer_index` will specify the index of
+ // simulcast stream, that should be analyzed. Other streams will be
+ // dropped.
+ // 2. SVC encoding is used:
+ // in such case `target_layer_index` will specify the top interesting
+ // spatial layer and all layers below, including target one will be
+ // processed. All layers above target one will be dropped.
+ // If not specified then all streams will be received and analyzed.
+ // When set, it instructs the framework to create an emulated Selective
+ // Forwarding Unit (SFU) that will propagate only the requested layers.
+ absl::optional<int> target_layer_index;
+ // Specifies the index of the maximum temporal unit to keep.
+ // If not specified then all temporal layers will be received and analyzed.
+ // When set, it instructs the framework to create an emulated Selective
+ // Forwarding Unit (SFU) that will propagate only up to the requested layer.
+ absl::optional<int> target_temporal_index;
+};
+
+class VideoResolution {
+ public:
+ // Determines special resolutions, which can't be expressed in terms of
+ // width, height and fps.
+ enum class Spec {
+ // No extra spec set. It describes a regular resolution described by
+ // width, height and fps.
+ kNone,
+ // Describes resolution which contains max value among all sender's
+ // video streams in each dimension (width, height, fps).
+ kMaxFromSender
+ };
+
+ VideoResolution(size_t width, size_t height, int32_t fps);
+ explicit VideoResolution(Spec spec = Spec::kNone);
+
+ bool operator==(const VideoResolution& other) const;
+ bool operator!=(const VideoResolution& other) const;
+
+ size_t width() const { return width_; }
+ void set_width(size_t width) { width_ = width; }
+ size_t height() const { return height_; }
+ void set_height(size_t height) { height_ = height; }
+ int32_t fps() const { return fps_; }
+ void set_fps(int32_t fps) { fps_ = fps; }
+
+ // Returns if it is a regular resolution or not. The resolution is regular
+ // if it's spec is `Spec::kNone`.
+ bool IsRegular() const;
+
+ std::string ToString() const;
+
+ private:
+ size_t width_ = 0;
+ size_t height_ = 0;
+ int32_t fps_ = 0;
+ Spec spec_ = Spec::kNone;
+};
+
+class VideoDumpOptions {
+ public:
+ static constexpr int kDefaultSamplingModulo = 1;
+
+ // output_directory - the output directory where stream will be dumped. The
+ // output files' names will be constructed as
+ // <stream_name>_<receiver_name>_<resolution>.<extension> for output dumps
+ // and <stream_name>_<resolution>.<extension> for input dumps.
+ // By default <extension> is "y4m". Resolution is in the format
+ // <width>x<height>_<fps>.
+ // sampling_modulo - the module for the video frames to be dumped. Modulo
+ // equals X means every Xth frame will be written to the dump file. The
+ // value must be greater than 0. (Default: 1)
+ // export_frame_ids - specifies if frame ids should be exported together
+ // with content of the stream. If true, an output file with the same name as
+ // video dump and suffix ".frame_ids.txt" will be created. It will contain
+ // the frame ids in the same order as original frames in the output
+ // file with stream content. File will contain one frame id per line.
+ // (Default: false)
+ // `video_frame_writer_factory` - factory function to create a video frame
+ // writer for input and output video files. (Default: Y4M video writer
+ // factory).
+ explicit VideoDumpOptions(
+ absl::string_view output_directory,
+ int sampling_modulo = kDefaultSamplingModulo,
+ bool export_frame_ids = false,
+ std::function<std::unique_ptr<test::VideoFrameWriter>(
+ absl::string_view file_name_prefix,
+ const VideoResolution& resolution)> video_frame_writer_factory =
+ Y4mVideoFrameWriterFactory);
+ VideoDumpOptions(absl::string_view output_directory, bool export_frame_ids);
+
+ VideoDumpOptions(const VideoDumpOptions&) = default;
+ VideoDumpOptions& operator=(const VideoDumpOptions&) = default;
+ VideoDumpOptions(VideoDumpOptions&&) = default;
+ VideoDumpOptions& operator=(VideoDumpOptions&&) = default;
+
+ std::string output_directory() const { return output_directory_; }
+ int sampling_modulo() const { return sampling_modulo_; }
+ bool export_frame_ids() const { return export_frame_ids_; }
+
+ std::unique_ptr<test::VideoFrameWriter> CreateInputDumpVideoFrameWriter(
+ absl::string_view stream_label,
+ const VideoResolution& resolution) const;
+
+ std::unique_ptr<test::VideoFrameWriter> CreateOutputDumpVideoFrameWriter(
+ absl::string_view stream_label,
+ absl::string_view receiver,
+ const VideoResolution& resolution) const;
+
+ std::string ToString() const;
+
+ private:
+ static std::unique_ptr<test::VideoFrameWriter> Y4mVideoFrameWriterFactory(
+ absl::string_view file_name_prefix,
+ const VideoResolution& resolution);
+ std::string GetInputDumpFileName(absl::string_view stream_label,
+ const VideoResolution& resolution) const;
+ // Returns file name for input frame ids dump if `export_frame_ids()` is
+ // true, absl::nullopt otherwise.
+ absl::optional<std::string> GetInputFrameIdsDumpFileName(
+ absl::string_view stream_label,
+ const VideoResolution& resolution) const;
+ std::string GetOutputDumpFileName(absl::string_view stream_label,
+ absl::string_view receiver,
+ const VideoResolution& resolution) const;
+ // Returns file name for output frame ids dump if `export_frame_ids()` is
+ // true, absl::nullopt otherwise.
+ absl::optional<std::string> GetOutputFrameIdsDumpFileName(
+ absl::string_view stream_label,
+ absl::string_view receiver,
+ const VideoResolution& resolution) const;
+
+ std::string output_directory_;
+ int sampling_modulo_ = 1;
+ bool export_frame_ids_ = false;
+ std::function<std::unique_ptr<test::VideoFrameWriter>(
+ absl::string_view file_name_prefix,
+ const VideoResolution& resolution)>
+ video_frame_writer_factory_;
+};
+
+// Contains properties of single video stream.
+struct VideoConfig {
+ explicit VideoConfig(const VideoResolution& resolution);
+ VideoConfig(size_t width, size_t height, int32_t fps);
+ VideoConfig(std::string stream_label,
+ size_t width,
+ size_t height,
+ int32_t fps);
+
+ // Video stream width.
+ size_t width;
+ // Video stream height.
+ size_t height;
+ int32_t fps;
+ VideoResolution GetResolution() const {
+ return VideoResolution(width, height, fps);
+ }
+
+ // Have to be unique among all specified configs for all peers in the call.
+ // Will be auto generated if omitted.
+ absl::optional<std::string> stream_label;
+ // Will be set for current video track. If equals to kText or kDetailed -
+ // screencast in on.
+ absl::optional<VideoTrackInterface::ContentHint> content_hint;
+ // If presented video will be transfered in simulcast/SVC mode depending on
+ // which encoder is used.
+ //
+ // Simulcast is supported only from 1st added peer. For VP8 simulcast only
+ // without RTX is supported so it will be automatically disabled for all
+ // simulcast tracks. For VP9 simulcast enables VP9 SVC mode and support RTX,
+ // but only on non-lossy networks. See more in documentation to
+ // VideoSimulcastConfig.
+ absl::optional<VideoSimulcastConfig> simulcast_config;
+ // Configuration for the emulated Selective Forward Unit (SFU).
+ absl::optional<EmulatedSFUConfig> emulated_sfu_config;
+ // Encoding parameters for both singlecast and per simulcast layer.
+ // If singlecast is used, if not empty, a single value can be provided.
+ // If simulcast is used, if not empty, `encoding_params` size have to be
+ // equal to `simulcast_config.simulcast_streams_count`. Will be used to set
+ // transceiver send encoding params for each layer.
+ // RtpEncodingParameters::rid may be changed by fixture implementation to
+ // ensure signaling correctness.
+ std::vector<RtpEncodingParameters> encoding_params;
+ // Count of temporal layers for video stream. This value will be set into
+ // each RtpEncodingParameters of RtpParameters of corresponding
+ // RtpSenderInterface for this video stream.
+ absl::optional<int> temporal_layers_count;
+ // If specified defines how input should be dumped. It is actually one of
+ // the test's output file, which contains copy of what was captured during
+ // the test for this video stream on sender side. It is useful when
+ // generator is used as input.
+ absl::optional<VideoDumpOptions> input_dump_options;
+ // If specified defines how output should be dumped on the receiver side for
+ // this stream. The produced files contain what was rendered for this video
+ // stream on receiver side per each receiver.
+ absl::optional<VideoDumpOptions> output_dump_options;
+ // If set to true uses fixed frame rate while dumping output video to the
+ // file. Requested `VideoSubscription::fps()` will be used as frame rate.
+ bool output_dump_use_fixed_framerate = false;
+ // If true will display input and output video on the user's screen.
+ bool show_on_screen = false;
+ // If specified, determines a sync group to which this video stream belongs.
+ // According to bugs.webrtc.org/4762 WebRTC supports synchronization only
+ // for pair of single audio and single video stream.
+ absl::optional<std::string> sync_group;
+ // If specified, it will be set into RtpParameters of corresponding
+ // RtpSenderInterface for this video stream.
+ // Note that this setting takes precedence over `content_hint`.
+ absl::optional<DegradationPreference> degradation_preference;
+};
+
+// Contains properties for audio in the call.
+struct AudioConfig {
+ enum Mode {
+ kGenerated,
+ kFile,
+ };
+
+ AudioConfig() = default;
+ explicit AudioConfig(std::string stream_label);
+
+ // Have to be unique among all specified configs for all peers in the call.
+ // Will be auto generated if omitted.
+ absl::optional<std::string> stream_label;
+ Mode mode = kGenerated;
+ // Have to be specified only if mode = kFile
+ absl::optional<std::string> input_file_name;
+ // If specified the input stream will be also copied to specified file.
+ absl::optional<std::string> input_dump_file_name;
+ // If specified the output stream will be copied to specified file.
+ absl::optional<std::string> output_dump_file_name;
+
+ // Audio options to use.
+ cricket::AudioOptions audio_options;
+ // Sampling frequency of input audio data (from file or generated).
+ int sampling_frequency_in_hz = 48000;
+ // If specified, determines a sync group to which this audio stream belongs.
+ // According to bugs.webrtc.org/4762 WebRTC supports synchronization only
+ // for pair of single audio and single video stream.
+ absl::optional<std::string> sync_group;
+};
+
+struct VideoCodecConfig {
+ explicit VideoCodecConfig(std::string name);
+ VideoCodecConfig(std::string name,
+ std::map<std::string, std::string> required_params);
+ // Next two fields are used to specify concrete video codec, that should be
+ // used in the test. Video code will be negotiated in SDP during offer/
+ // answer exchange.
+ // Video codec name. You can find valid names in
+ // media/base/media_constants.h
+ std::string name;
+ // Map of parameters, that have to be specified on SDP codec. Each parameter
+ // is described by key and value. Codec parameters will match the specified
+ // map if and only if for each key from `required_params` there will be
+ // a parameter with name equal to this key and parameter value will be equal
+ // to the value from `required_params` for this key.
+ // If empty then only name will be used to match the codec.
+ std::map<std::string, std::string> required_params;
+};
+
+// Subscription to the remote video streams. It declares which remote stream
+// peer should receive and in which resolution (width x height x fps).
+class VideoSubscription {
+ public:
+ // Returns the resolution constructed as maximum from all resolution
+ // dimensions: width, height and fps.
+ static absl::optional<VideoResolution> GetMaxResolution(
+ rtc::ArrayView<const VideoConfig> video_configs);
+ static absl::optional<VideoResolution> GetMaxResolution(
+ rtc::ArrayView<const VideoResolution> resolutions);
+
+ bool operator==(const VideoSubscription& other) const;
+ bool operator!=(const VideoSubscription& other) const;
+
+ // Subscribes receiver to all streams sent by the specified peer with
+ // specified resolution. It will override any resolution that was used in
+ // `SubscribeToAll` independently from methods call order.
+ VideoSubscription& SubscribeToPeer(
+ absl::string_view peer_name,
+ VideoResolution resolution =
+ VideoResolution(VideoResolution::Spec::kMaxFromSender));
+
+ // Subscribes receiver to the all sent streams with specified resolution.
+ // If any stream was subscribed to with `SubscribeTo` method that will
+ // override resolution passed to this function independently from methods
+ // call order.
+ VideoSubscription& SubscribeToAllPeers(
+ VideoResolution resolution =
+ VideoResolution(VideoResolution::Spec::kMaxFromSender));
+
+ // Returns resolution for specific sender. If no specific resolution was
+ // set for this sender, then will return resolution used for all streams.
+ // If subscription doesn't subscribe to all streams, `absl::nullopt` will be
+ // returned.
+ absl::optional<VideoResolution> GetResolutionForPeer(
+ absl::string_view peer_name) const;
+
+ // Returns a maybe empty list of senders for which peer explicitly
+ // subscribed to with specific resolution.
+ std::vector<std::string> GetSubscribedPeers() const;
+
+ std::string ToString() const;
+
+ private:
+ absl::optional<VideoResolution> default_resolution_ = absl::nullopt;
+ std::map<std::string, VideoResolution> peers_resolution_;
+};
+
+// Contains configuration for echo emulator.
+struct EchoEmulationConfig {
+ // Delay which represents the echo path delay, i.e. how soon rendered signal
+ // should reach capturer.
+ TimeDelta echo_delay = TimeDelta::Millis(50);
+};
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_PCLF_MEDIA_CONFIGURATION_H_
diff --git a/third_party/libwebrtc/api/test/pclf/media_quality_test_params.h b/third_party/libwebrtc/api/test/pclf/media_quality_test_params.h
new file mode 100644
index 0000000000..3377d31f68
--- /dev/null
+++ b/third_party/libwebrtc/api/test/pclf/media_quality_test_params.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_PCLF_MEDIA_QUALITY_TEST_PARAMS_H_
+#define API_TEST_PCLF_MEDIA_QUALITY_TEST_PARAMS_H_
+
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/async_resolver_factory.h"
+#include "api/audio/audio_mixer.h"
+#include "api/call/call_factory_interface.h"
+#include "api/fec_controller.h"
+#include "api/field_trials_view.h"
+#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/test/pclf/media_configuration.h"
+#include "api/transport/network_control.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "p2p/base/port_allocator.h"
+#include "rtc_base/network.h"
+#include "rtc_base/rtc_certificate_generator.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/thread.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// Contains most part from PeerConnectionFactoryDependencies. Also all fields
+// are optional and defaults will be provided by fixture implementation if
+// any will be omitted.
+//
+// Separate class was introduced to clarify which components can be
+// overridden. For example worker and signaling threads will be provided by
+// fixture implementation. The same is applicable to the media engine. So user
+// can override only some parts of media engine like video encoder/decoder
+// factories.
+struct PeerConnectionFactoryComponents {
+ std::unique_ptr<TaskQueueFactory> task_queue_factory;
+ std::unique_ptr<CallFactoryInterface> call_factory;
+ std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory;
+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory;
+ std::unique_ptr<NetworkControllerFactoryInterface> network_controller_factory;
+ std::unique_ptr<NetEqFactory> neteq_factory;
+
+ // Will be passed to MediaEngineInterface, that will be used in
+ // PeerConnectionFactory.
+ std::unique_ptr<VideoEncoderFactory> video_encoder_factory;
+ std::unique_ptr<VideoDecoderFactory> video_decoder_factory;
+
+ std::unique_ptr<FieldTrialsView> trials;
+
+ rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing;
+ rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer;
+};
+
+// Contains most parts from PeerConnectionDependencies. Also all fields are
+// optional and defaults will be provided by fixture implementation if any
+// will be omitted.
+//
+// Separate class was introduced to clarify which components can be
+// overridden. For example observer, which is required to
+// PeerConnectionDependencies, will be provided by fixture implementation,
+// so client can't inject its own. Also only network manager can be overridden
+// inside port allocator.
+struct PeerConnectionComponents {
+ PeerConnectionComponents(rtc::NetworkManager* network_manager,
+ rtc::PacketSocketFactory* packet_socket_factory)
+ : network_manager(network_manager),
+ packet_socket_factory(packet_socket_factory) {
+ RTC_CHECK(network_manager);
+ }
+
+ rtc::NetworkManager* const network_manager;
+ rtc::PacketSocketFactory* const packet_socket_factory;
+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory;
+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator;
+ std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier;
+ std::unique_ptr<IceTransportFactory> ice_transport_factory;
+};
+
+// Contains all components, that can be overridden in peer connection. Also
+// has a network thread, that will be used to communicate with another peers.
+struct InjectableComponents {
+ InjectableComponents(rtc::Thread* network_thread,
+ rtc::NetworkManager* network_manager,
+ rtc::PacketSocketFactory* packet_socket_factory)
+ : network_thread(network_thread),
+ worker_thread(nullptr),
+ pcf_dependencies(std::make_unique<PeerConnectionFactoryComponents>()),
+ pc_dependencies(
+ std::make_unique<PeerConnectionComponents>(network_manager,
+ packet_socket_factory)) {
+ RTC_CHECK(network_thread);
+ }
+
+ rtc::Thread* const network_thread;
+ rtc::Thread* worker_thread;
+
+ std::unique_ptr<PeerConnectionFactoryComponents> pcf_dependencies;
+ std::unique_ptr<PeerConnectionComponents> pc_dependencies;
+};
+
+// Contains information about call media streams (up to 1 audio stream and
+// unlimited amount of video streams) and rtc configuration, that will be used
+// to set up peer connection.
+struct Params {
+ // Peer name. If empty - default one will be set by the fixture.
+ absl::optional<std::string> name;
+ // If `audio_config` is set audio stream will be configured
+ absl::optional<AudioConfig> audio_config;
+ // Flags to set on `cricket::PortAllocator`. These flags will be added
+ // to the default ones that are presented on the port allocator.
+ uint32_t port_allocator_extra_flags = cricket::kDefaultPortAllocatorFlags;
+ // If `rtc_event_log_path` is set, an RTCEventLog will be saved in that
+ // location and it will be available for further analysis.
+ absl::optional<std::string> rtc_event_log_path;
+ // If `aec_dump_path` is set, an AEC dump will be saved in that location and
+ // it will be available for further analysis.
+ absl::optional<std::string> aec_dump_path;
+
+ bool use_ulp_fec = false;
+ bool use_flex_fec = false;
+ // Specifies how much video encoder target bitrate should be different than
+ // target bitrate, provided by WebRTC stack. Must be greater then 0. Can be
+ // used to emulate overshooting of video encoders. This multiplier will
+ // be applied for all video encoder on both sides for all layers. Bitrate
+ // estimated by WebRTC stack will be multiplied by this multiplier and then
+ // provided into VideoEncoder::SetRates(...).
+ double video_encoder_bitrate_multiplier = 1.0;
+
+ PeerConnectionInterface::RTCConfiguration rtc_configuration;
+ PeerConnectionInterface::RTCOfferAnswerOptions rtc_offer_answer_options;
+ BitrateSettings bitrate_settings;
+ std::vector<VideoCodecConfig> video_codecs;
+
+ // A list of RTP header extensions which will be enforced on all video streams
+ // added to this peer.
+ std::vector<std::string> extra_video_rtp_header_extensions;
+ // A list of RTP header extensions which will be enforced on all audio streams
+ // added to this peer.
+ std::vector<std::string> extra_audio_rtp_header_extensions;
+};
+
+// Contains parameters that maybe changed by test writer during the test call.
+struct ConfigurableParams {
+ // If `video_configs` is empty - no video should be added to the test call.
+ std::vector<VideoConfig> video_configs;
+
+ VideoSubscription video_subscription =
+ VideoSubscription().SubscribeToAllPeers();
+};
+
+// Contains parameters, that describe how long framework should run quality
+// test.
+struct RunParams {
+ explicit RunParams(TimeDelta run_duration) : run_duration(run_duration) {}
+
+ // Specifies how long the test should be run. This time shows how long
+ // the media should flow after connection was established and before
+ // it will be shut downed.
+ TimeDelta run_duration;
+
+ // If set to true peers will be able to use Flex FEC, otherwise they won't
+ // be able to negotiate it even if it's enabled on per peer level.
+ bool enable_flex_fec_support = false;
+ // If true will set conference mode in SDP media section for all video
+ // tracks for all peers.
+ bool use_conference_mode = false;
+ // If specified echo emulation will be done, by mixing the render audio into
+ // the capture signal. In such case input signal will be reduced by half to
+ // avoid saturation or compression in the echo path simulation.
+ absl::optional<EchoEmulationConfig> echo_emulation_config;
+};
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_PCLF_MEDIA_QUALITY_TEST_PARAMS_H_
diff --git a/third_party/libwebrtc/api/test/pclf/peer_configurer.cc b/third_party/libwebrtc/api/test/pclf/peer_configurer.cc
new file mode 100644
index 0000000000..2203a4c4f0
--- /dev/null
+++ b/third_party/libwebrtc/api/test/pclf/peer_configurer.cc
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2022 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 "api/test/pclf/peer_configurer.h"
+
+#include <set>
+
+#include "absl/strings/string_view.h"
+#include "api/test/pclf/media_configuration.h"
+#include "api/test/pclf/media_quality_test_params.h"
+#include "api/test/peer_network_dependencies.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+PeerConfigurer::PeerConfigurer(
+ const PeerNetworkDependencies& network_dependencies)
+ : components_(std::make_unique<InjectableComponents>(
+ network_dependencies.network_thread,
+ network_dependencies.network_manager,
+ network_dependencies.packet_socket_factory)),
+ params_(std::make_unique<Params>()),
+ configurable_params_(std::make_unique<ConfigurableParams>()) {}
+
+PeerConfigurer* PeerConfigurer::SetName(absl::string_view name) {
+ params_->name = std::string(name);
+ return this;
+}
+
+PeerConfigurer* PeerConfigurer::SetTaskQueueFactory(
+ std::unique_ptr<TaskQueueFactory> task_queue_factory) {
+ components_->pcf_dependencies->task_queue_factory =
+ std::move(task_queue_factory);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetCallFactory(
+ std::unique_ptr<CallFactoryInterface> call_factory) {
+ components_->pcf_dependencies->call_factory = std::move(call_factory);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetEventLogFactory(
+ std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory) {
+ components_->pcf_dependencies->event_log_factory =
+ std::move(event_log_factory);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetFecControllerFactory(
+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory) {
+ components_->pcf_dependencies->fec_controller_factory =
+ std::move(fec_controller_factory);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetNetworkControllerFactory(
+ std::unique_ptr<NetworkControllerFactoryInterface>
+ network_controller_factory) {
+ components_->pcf_dependencies->network_controller_factory =
+ std::move(network_controller_factory);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetVideoEncoderFactory(
+ std::unique_ptr<VideoEncoderFactory> video_encoder_factory) {
+ components_->pcf_dependencies->video_encoder_factory =
+ std::move(video_encoder_factory);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetVideoDecoderFactory(
+ std::unique_ptr<VideoDecoderFactory> video_decoder_factory) {
+ components_->pcf_dependencies->video_decoder_factory =
+ std::move(video_decoder_factory);
+ return this;
+}
+
+PeerConfigurer* PeerConfigurer::SetAsyncResolverFactory(
+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory) {
+ components_->pc_dependencies->async_resolver_factory =
+ std::move(async_resolver_factory);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetRTCCertificateGenerator(
+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator) {
+ components_->pc_dependencies->cert_generator = std::move(cert_generator);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetSSLCertificateVerifier(
+ std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier) {
+ components_->pc_dependencies->tls_cert_verifier =
+ std::move(tls_cert_verifier);
+ return this;
+}
+
+PeerConfigurer* PeerConfigurer::AddVideoConfig(VideoConfig config) {
+ video_sources_.push_back(
+ CreateSquareFrameGenerator(config, /*type=*/absl::nullopt));
+ configurable_params_->video_configs.push_back(std::move(config));
+ return this;
+}
+PeerConfigurer* PeerConfigurer::AddVideoConfig(
+ VideoConfig config,
+ std::unique_ptr<test::FrameGeneratorInterface> generator) {
+ configurable_params_->video_configs.push_back(std::move(config));
+ video_sources_.push_back(std::move(generator));
+ return this;
+}
+PeerConfigurer* PeerConfigurer::AddVideoConfig(VideoConfig config,
+ CapturingDeviceIndex index) {
+ configurable_params_->video_configs.push_back(std::move(config));
+ video_sources_.push_back(index);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetVideoSubscription(
+ VideoSubscription subscription) {
+ configurable_params_->video_subscription = std::move(subscription);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetVideoCodecs(
+ std::vector<VideoCodecConfig> video_codecs) {
+ params_->video_codecs = std::move(video_codecs);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetExtraVideoRtpHeaderExtensions(
+ std::vector<std::string> extensions) {
+ params_->extra_video_rtp_header_extensions = std::move(extensions);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetAudioConfig(AudioConfig config) {
+ params_->audio_config = std::move(config);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetExtraAudioRtpHeaderExtensions(
+ std::vector<std::string> extensions) {
+ params_->extra_audio_rtp_header_extensions = std::move(extensions);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetUseUlpFEC(bool value) {
+ params_->use_ulp_fec = value;
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetUseFlexFEC(bool value) {
+ params_->use_flex_fec = value;
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetVideoEncoderBitrateMultiplier(
+ double multiplier) {
+ params_->video_encoder_bitrate_multiplier = multiplier;
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetNetEqFactory(
+ std::unique_ptr<NetEqFactory> neteq_factory) {
+ components_->pcf_dependencies->neteq_factory = std::move(neteq_factory);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetAudioProcessing(
+ rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing) {
+ components_->pcf_dependencies->audio_processing = audio_processing;
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetAudioMixer(
+ rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer) {
+ components_->pcf_dependencies->audio_mixer = audio_mixer;
+ return this;
+}
+
+PeerConfigurer* PeerConfigurer::SetUseNetworkThreadAsWorkerThread() {
+ components_->worker_thread = components_->network_thread;
+ return this;
+}
+
+PeerConfigurer* PeerConfigurer::SetRtcEventLogPath(std::string path) {
+ params_->rtc_event_log_path = std::move(path);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetAecDumpPath(std::string path) {
+ params_->aec_dump_path = std::move(path);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetRTCConfiguration(
+ PeerConnectionInterface::RTCConfiguration configuration) {
+ params_->rtc_configuration = std::move(configuration);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetRTCOfferAnswerOptions(
+ PeerConnectionInterface::RTCOfferAnswerOptions options) {
+ params_->rtc_offer_answer_options = std::move(options);
+ return this;
+}
+PeerConfigurer* PeerConfigurer::SetBitrateSettings(
+ BitrateSettings bitrate_settings) {
+ params_->bitrate_settings = bitrate_settings;
+ return this;
+}
+
+PeerConfigurer* PeerConfigurer::SetIceTransportFactory(
+ std::unique_ptr<IceTransportFactory> factory) {
+ components_->pc_dependencies->ice_transport_factory = std::move(factory);
+ return this;
+}
+
+PeerConfigurer* PeerConfigurer::SetPortAllocatorExtraFlags(
+ uint32_t extra_flags) {
+ params_->port_allocator_extra_flags = extra_flags;
+ return this;
+}
+std::unique_ptr<InjectableComponents> PeerConfigurer::ReleaseComponents() {
+ RTC_CHECK(components_);
+ auto components = std::move(components_);
+ components_ = nullptr;
+ return components;
+}
+
+// Returns Params and transfer ownership to the caller.
+// Can be called once.
+std::unique_ptr<Params> PeerConfigurer::ReleaseParams() {
+ RTC_CHECK(params_);
+ auto params = std::move(params_);
+ params_ = nullptr;
+ return params;
+}
+
+// Returns ConfigurableParams and transfer ownership to the caller.
+// Can be called once.
+std::unique_ptr<ConfigurableParams>
+PeerConfigurer::ReleaseConfigurableParams() {
+ RTC_CHECK(configurable_params_);
+ auto configurable_params = std::move(configurable_params_);
+ configurable_params_ = nullptr;
+ return configurable_params;
+}
+
+// Returns video sources and transfer frame generators ownership to the
+// caller. Can be called once.
+std::vector<PeerConfigurer::VideoSource> PeerConfigurer::ReleaseVideoSources() {
+ auto video_sources = std::move(video_sources_);
+ video_sources_.clear();
+ return video_sources;
+}
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/pclf/peer_configurer.h b/third_party/libwebrtc/api/test/pclf/peer_configurer.h
new file mode 100644
index 0000000000..996dc5cd89
--- /dev/null
+++ b/third_party/libwebrtc/api/test/pclf/peer_configurer.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_PCLF_PEER_CONFIGURER_H_
+#define API_TEST_PCLF_PEER_CONFIGURER_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/async_resolver_factory.h"
+#include "api/audio/audio_mixer.h"
+#include "api/call/call_factory_interface.h"
+#include "api/fec_controller.h"
+#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/test/create_peer_connection_quality_test_frame_generator.h"
+#include "api/test/pclf/media_configuration.h"
+#include "api/test/pclf/media_quality_test_params.h"
+#include "api/test/peer_network_dependencies.h"
+#include "api/transport/network_control.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "rtc_base/network.h"
+#include "rtc_base/rtc_certificate_generator.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/thread.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// This class is used to fully configure one peer inside a call.
+class PeerConfigurer {
+ public:
+ using VideoSource =
+ absl::variant<std::unique_ptr<test::FrameGeneratorInterface>,
+ CapturingDeviceIndex>;
+
+ explicit PeerConfigurer(const PeerNetworkDependencies& network_dependencies);
+
+ // Sets peer name that will be used to report metrics related to this peer.
+ // If not set, some default name will be assigned. All names have to be
+ // unique.
+ PeerConfigurer* SetName(absl::string_view name);
+
+ // The parameters of the following 9 methods will be passed to the
+ // PeerConnectionFactoryInterface implementation that will be created for
+ // this peer.
+ PeerConfigurer* SetTaskQueueFactory(
+ std::unique_ptr<TaskQueueFactory> task_queue_factory);
+ PeerConfigurer* SetCallFactory(
+ std::unique_ptr<CallFactoryInterface> call_factory);
+ PeerConfigurer* SetEventLogFactory(
+ std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory);
+ PeerConfigurer* SetFecControllerFactory(
+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory);
+ PeerConfigurer* SetNetworkControllerFactory(
+ std::unique_ptr<NetworkControllerFactoryInterface>
+ network_controller_factory);
+ PeerConfigurer* SetVideoEncoderFactory(
+ std::unique_ptr<VideoEncoderFactory> video_encoder_factory);
+ PeerConfigurer* SetVideoDecoderFactory(
+ std::unique_ptr<VideoDecoderFactory> video_decoder_factory);
+ // Set a custom NetEqFactory to be used in the call.
+ PeerConfigurer* SetNetEqFactory(std::unique_ptr<NetEqFactory> neteq_factory);
+ PeerConfigurer* SetAudioProcessing(
+ rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing);
+ PeerConfigurer* SetAudioMixer(
+ rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer);
+
+ // Forces the Peerconnection to use the network thread as the worker thread.
+ // Ie, worker thread and the network thread is the same thread.
+ PeerConfigurer* SetUseNetworkThreadAsWorkerThread();
+
+ // The parameters of the following 4 methods will be passed to the
+ // PeerConnectionInterface implementation that will be created for this
+ // peer.
+ PeerConfigurer* SetAsyncResolverFactory(
+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory);
+ PeerConfigurer* SetRTCCertificateGenerator(
+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator);
+ PeerConfigurer* SetSSLCertificateVerifier(
+ std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier);
+ PeerConfigurer* SetIceTransportFactory(
+ std::unique_ptr<IceTransportFactory> factory);
+ // Flags to set on `cricket::PortAllocator`. These flags will be added
+ // to the default ones that are presented on the port allocator.
+ // For possible values check p2p/base/port_allocator.h.
+ PeerConfigurer* SetPortAllocatorExtraFlags(uint32_t extra_flags);
+
+ // Add new video stream to the call that will be sent from this peer.
+ // Default implementation of video frames generator will be used.
+ PeerConfigurer* AddVideoConfig(VideoConfig config);
+ // Add new video stream to the call that will be sent from this peer with
+ // provided own implementation of video frames generator.
+ PeerConfigurer* AddVideoConfig(
+ VideoConfig config,
+ std::unique_ptr<test::FrameGeneratorInterface> generator);
+ // Add new video stream to the call that will be sent from this peer.
+ // Capturing device with specified index will be used to get input video.
+ PeerConfigurer* AddVideoConfig(VideoConfig config,
+ CapturingDeviceIndex capturing_device_index);
+ // Sets video subscription for the peer. By default subscription will
+ // include all streams with `VideoSubscription::kSameAsSendStream`
+ // resolution. To this behavior use this method.
+ PeerConfigurer* SetVideoSubscription(VideoSubscription subscription);
+ // Sets the list of video codecs used by the peer during the test. These
+ // codecs will be negotiated in SDP during offer/answer exchange. The order
+ // of these codecs during negotiation will be the same as in `video_codecs`.
+ // Codecs have to be available in codecs list provided by peer connection to
+ // be negotiated. If some of specified codecs won't be found, the test will
+ // crash.
+ PeerConfigurer* SetVideoCodecs(std::vector<VideoCodecConfig> video_codecs);
+ // Sets a list of RTP header extensions which will be enforced on all video
+ // streams added to this peer.
+ PeerConfigurer* SetExtraVideoRtpHeaderExtensions(
+ std::vector<std::string> extensions);
+ // Sets the audio stream for the call from this peer. If this method won't
+ // be invoked, this peer will send no audio.
+ PeerConfigurer* SetAudioConfig(AudioConfig config);
+ // Sets a list of RTP header extensions which will be enforced on all audio
+ // streams added to this peer.
+ PeerConfigurer* SetExtraAudioRtpHeaderExtensions(
+ std::vector<std::string> extensions);
+
+ // Set if ULP FEC should be used or not. False by default.
+ PeerConfigurer* SetUseUlpFEC(bool value);
+ // Set if Flex FEC should be used or not. False by default.
+ // Client also must enable `enable_flex_fec_support` in the `RunParams` to
+ // be able to use this feature.
+ PeerConfigurer* SetUseFlexFEC(bool value);
+ // Specifies how much video encoder target bitrate should be different than
+ // target bitrate, provided by WebRTC stack. Must be greater than 0. Can be
+ // used to emulate overshooting of video encoders. This multiplier will
+ // be applied for all video encoder on both sides for all layers. Bitrate
+ // estimated by WebRTC stack will be multiplied by this multiplier and then
+ // provided into VideoEncoder::SetRates(...). 1.0 by default.
+ PeerConfigurer* SetVideoEncoderBitrateMultiplier(double multiplier);
+
+ // If is set, an RTCEventLog will be saved in that location and it will be
+ // available for further analysis.
+ PeerConfigurer* SetRtcEventLogPath(std::string path);
+ // If is set, an AEC dump will be saved in that location and it will be
+ // available for further analysis.
+ PeerConfigurer* SetAecDumpPath(std::string path);
+ PeerConfigurer* SetRTCConfiguration(
+ PeerConnectionInterface::RTCConfiguration configuration);
+ PeerConfigurer* SetRTCOfferAnswerOptions(
+ PeerConnectionInterface::RTCOfferAnswerOptions options);
+ // Set bitrate parameters on PeerConnection. This constraints will be
+ // applied to all summed RTP streams for this peer.
+ PeerConfigurer* SetBitrateSettings(BitrateSettings bitrate_settings);
+
+ // Returns InjectableComponents and transfer ownership to the caller.
+ // Can be called once.
+ std::unique_ptr<InjectableComponents> ReleaseComponents();
+
+ // Returns Params and transfer ownership to the caller.
+ // Can be called once.
+ std::unique_ptr<Params> ReleaseParams();
+
+ // Returns ConfigurableParams and transfer ownership to the caller.
+ // Can be called once.
+ std::unique_ptr<ConfigurableParams> ReleaseConfigurableParams();
+
+ // Returns video sources and transfer frame generators ownership to the
+ // caller. Can be called once.
+ std::vector<VideoSource> ReleaseVideoSources();
+
+ InjectableComponents* components() { return components_.get(); }
+ Params* params() { return params_.get(); }
+ ConfigurableParams* configurable_params() {
+ return configurable_params_.get();
+ }
+ const Params& params() const { return *params_; }
+ const ConfigurableParams& configurable_params() const {
+ return *configurable_params_;
+ }
+ std::vector<VideoSource>* video_sources() { return &video_sources_; }
+
+ private:
+ std::unique_ptr<InjectableComponents> components_;
+ std::unique_ptr<Params> params_;
+ std::unique_ptr<ConfigurableParams> configurable_params_;
+ std::vector<VideoSource> video_sources_;
+};
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_PCLF_PEER_CONFIGURER_H_
diff --git a/third_party/libwebrtc/api/test/peer_network_dependencies.h b/third_party/libwebrtc/api/test/peer_network_dependencies.h
new file mode 100644
index 0000000000..6f85ad0a4d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/peer_network_dependencies.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 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 API_TEST_PEER_NETWORK_DEPENDENCIES_H_
+#define API_TEST_PEER_NETWORK_DEPENDENCIES_H_
+
+#include "api/packet_socket_factory.h"
+#include "rtc_base/network.h"
+#include "rtc_base/thread.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// The network dependencies needed when adding a peer to tests using
+// PeerConnectionE2EQualityTestFixture.
+struct PeerNetworkDependencies {
+ rtc::Thread* network_thread;
+ rtc::NetworkManager* network_manager;
+ rtc::PacketSocketFactory* packet_socket_factory;
+};
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_PEER_NETWORK_DEPENDENCIES_H_
diff --git a/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture.h b/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture.h
new file mode 100644
index 0000000000..74470cdf86
--- /dev/null
+++ b/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_PEERCONNECTION_QUALITY_TEST_FIXTURE_H_
+#define API_TEST_PEERCONNECTION_QUALITY_TEST_FIXTURE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/async_resolver_factory.h"
+#include "api/audio/audio_mixer.h"
+#include "api/call/call_factory_interface.h"
+#include "api/fec_controller.h"
+#include "api/function_view.h"
+#include "api/media_stream_interface.h"
+#include "api/peer_connection_interface.h"
+#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
+#include "api/rtp_parameters.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/test/audio_quality_analyzer_interface.h"
+#include "api/test/frame_generator_interface.h"
+#include "api/test/pclf/media_configuration.h"
+#include "api/test/pclf/media_quality_test_params.h"
+#include "api/test/pclf/peer_configurer.h"
+#include "api/test/peer_network_dependencies.h"
+#include "api/test/simulated_network.h"
+#include "api/test/stats_observer_interface.h"
+#include "api/test/track_id_stream_info_map.h"
+#include "api/test/video/video_frame_writer.h"
+#include "api/test/video_quality_analyzer_interface.h"
+#include "api/transport/network_control.h"
+#include "api/units/time_delta.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "media/base/media_constants.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/network.h"
+#include "rtc_base/rtc_certificate_generator.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/thread.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// API is in development. Can be changed/removed without notice.
+class PeerConnectionE2EQualityTestFixture {
+ public:
+ // Represent an entity that will report quality metrics after test.
+ class QualityMetricsReporter : public StatsObserverInterface {
+ public:
+ virtual ~QualityMetricsReporter() = default;
+
+ // Invoked by framework after peer connection factory and peer connection
+ // itself will be created but before offer/answer exchange will be started.
+ // `test_case_name` is name of test case, that should be used to report all
+ // metrics.
+ // `reporter_helper` is a pointer to a class that will allow track_id to
+ // stream_id matching. The caller is responsible for ensuring the
+ // TrackIdStreamInfoMap will be valid from Start() to
+ // StopAndReportResults().
+ virtual void Start(absl::string_view test_case_name,
+ const TrackIdStreamInfoMap* reporter_helper) = 0;
+
+ // Invoked by framework after call is ended and peer connection factory and
+ // peer connection are destroyed.
+ virtual void StopAndReportResults() = 0;
+ };
+
+ // Represents single participant in call and can be used to perform different
+ // in-call actions. Might be extended in future.
+ class PeerHandle {
+ public:
+ virtual ~PeerHandle() = default;
+ };
+
+ virtual ~PeerConnectionE2EQualityTestFixture() = default;
+
+ // Add activity that will be executed on the best effort at least after
+ // `target_time_since_start` after call will be set up (after offer/answer
+ // exchange, ICE gathering will be done and ICE candidates will passed to
+ // remote side). `func` param is amount of time spent from the call set up.
+ virtual void ExecuteAt(TimeDelta target_time_since_start,
+ std::function<void(TimeDelta)> func) = 0;
+ // Add activity that will be executed every `interval` with first execution
+ // on the best effort at least after `initial_delay_since_start` after call
+ // will be set up (after all participants will be connected). `func` param is
+ // amount of time spent from the call set up.
+ virtual void ExecuteEvery(TimeDelta initial_delay_since_start,
+ TimeDelta interval,
+ std::function<void(TimeDelta)> func) = 0;
+
+ // Add stats reporter entity to observe the test.
+ virtual void AddQualityMetricsReporter(
+ std::unique_ptr<QualityMetricsReporter> quality_metrics_reporter) = 0;
+
+ // Add a new peer to the call and return an object through which caller
+ // can configure peer's behavior.
+ // `network_dependencies` are used to provide networking for peer's peer
+ // connection. Members must be non-null.
+ // `configurer` function will be used to configure peer in the call.
+ virtual PeerHandle* AddPeer(std::unique_ptr<PeerConfigurer> configurer) = 0;
+
+ // Runs the media quality test, which includes setting up the call with
+ // configured participants, running it according to provided `run_params` and
+ // terminating it properly at the end. During call duration media quality
+ // metrics are gathered, which are then reported to stdout and (if configured)
+ // to the json/protobuf output file through the WebRTC perf test results
+ // reporting system.
+ virtual void Run(RunParams run_params) = 0;
+
+ // Returns real test duration - the time of test execution measured during
+ // test. Client must call this method only after test is finished (after
+ // Run(...) method returned). Test execution time is time from end of call
+ // setup (offer/answer, ICE candidates exchange done and ICE connected) to
+ // start of call tear down (PeerConnection closed).
+ virtual TimeDelta GetRealTestDuration() const = 0;
+};
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_PEERCONNECTION_QUALITY_TEST_FIXTURE_H_
diff --git a/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture_unittest.cc b/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture_unittest.cc
new file mode 100644
index 0000000000..26ae8cf98f
--- /dev/null
+++ b/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture_unittest.cc
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2022 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 "api/test/peerconnection_quality_test_fixture.h"
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/test/pclf/media_configuration.h"
+#include "api/test/video/video_frame_writer.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+namespace {
+
+using ::testing::Eq;
+
+TEST(PclfVideoSubscriptionTest,
+ MaxFromSenderSpecEqualIndependentOfOtherFields) {
+ VideoResolution r1(VideoResolution::Spec::kMaxFromSender);
+ r1.set_width(1);
+ r1.set_height(2);
+ r1.set_fps(3);
+ VideoResolution r2(VideoResolution::Spec::kMaxFromSender);
+ r1.set_width(4);
+ r1.set_height(5);
+ r1.set_fps(6);
+ EXPECT_EQ(r1, r2);
+}
+
+TEST(PclfVideoSubscriptionTest, WhenSpecIsNotSetFieldsAreCompared) {
+ VideoResolution test_resolution(/*width=*/1, /*height=*/2,
+ /*fps=*/3);
+ VideoResolution equal_resolution(/*width=*/1, /*height=*/2,
+ /*fps=*/3);
+ VideoResolution different_width(/*width=*/10, /*height=*/2,
+ /*fps=*/3);
+ VideoResolution different_height(/*width=*/1, /*height=*/20,
+ /*fps=*/3);
+ VideoResolution different_fps(/*width=*/1, /*height=*/20,
+ /*fps=*/30);
+
+ EXPECT_EQ(test_resolution, equal_resolution);
+ EXPECT_NE(test_resolution, different_width);
+ EXPECT_NE(test_resolution, different_height);
+ EXPECT_NE(test_resolution, different_fps);
+}
+
+TEST(PclfVideoSubscriptionTest, GetMaxResolutionForEmptyReturnsNullopt) {
+ absl::optional<VideoResolution> resolution =
+ VideoSubscription::GetMaxResolution(std::vector<VideoConfig>{});
+ ASSERT_FALSE(resolution.has_value());
+}
+
+TEST(PclfVideoSubscriptionTest, GetMaxResolutionSelectMaxForEachDimention) {
+ VideoConfig max_width(/*width=*/1000, /*height=*/1, /*fps=*/1);
+ VideoConfig max_height(/*width=*/1, /*height=*/100, /*fps=*/1);
+ VideoConfig max_fps(/*width=*/1, /*height=*/1, /*fps=*/10);
+
+ absl::optional<VideoResolution> resolution =
+ VideoSubscription::GetMaxResolution(
+ std::vector<VideoConfig>{max_width, max_height, max_fps});
+ ASSERT_TRUE(resolution.has_value());
+ EXPECT_EQ(resolution->width(), static_cast<size_t>(1000));
+ EXPECT_EQ(resolution->height(), static_cast<size_t>(100));
+ EXPECT_EQ(resolution->fps(), 10);
+}
+
+struct TestVideoFrameWriter : public test::VideoFrameWriter {
+ public:
+ TestVideoFrameWriter(absl::string_view file_name_prefix,
+ const VideoResolution& resolution)
+ : file_name_prefix(file_name_prefix), resolution(resolution) {}
+
+ bool WriteFrame(const VideoFrame& frame) override { return true; }
+
+ void Close() override {}
+
+ std::string file_name_prefix;
+ VideoResolution resolution;
+};
+
+TEST(VideoDumpOptionsTest, InputVideoWriterHasCorrectFileName) {
+ VideoResolution resolution(/*width=*/1280, /*height=*/720, /*fps=*/30);
+
+ TestVideoFrameWriter* writer = nullptr;
+ VideoDumpOptions options("foo", /*sampling_modulo=*/1,
+ /*export_frame_ids=*/false,
+ /*video_frame_writer_factory=*/
+ [&](absl::string_view file_name_prefix,
+ const VideoResolution& resolution) {
+ auto out = std::make_unique<TestVideoFrameWriter>(
+ file_name_prefix, resolution);
+ writer = out.get();
+ return out;
+ });
+ std::unique_ptr<test::VideoFrameWriter> created_writer =
+ options.CreateInputDumpVideoFrameWriter("alice-video", resolution);
+
+ ASSERT_TRUE(writer != nullptr);
+ ASSERT_THAT(writer->file_name_prefix,
+ Eq(test::JoinFilename("foo", "alice-video_1280x720_30")));
+ ASSERT_THAT(writer->resolution, Eq(resolution));
+}
+
+TEST(VideoDumpOptionsTest, OutputVideoWriterHasCorrectFileName) {
+ VideoResolution resolution(/*width=*/1280, /*height=*/720, /*fps=*/30);
+
+ TestVideoFrameWriter* writer = nullptr;
+ VideoDumpOptions options("foo", /*sampling_modulo=*/1,
+ /*export_frame_ids=*/false,
+ /*video_frame_writer_factory=*/
+ [&](absl::string_view file_name_prefix,
+ const VideoResolution& resolution) {
+ auto out = std::make_unique<TestVideoFrameWriter>(
+ file_name_prefix, resolution);
+ writer = out.get();
+ return out;
+ });
+ std::unique_ptr<test::VideoFrameWriter> created_writer =
+ options.CreateOutputDumpVideoFrameWriter("alice-video", "bob",
+ resolution);
+
+ ASSERT_TRUE(writer != nullptr);
+ ASSERT_THAT(writer->file_name_prefix,
+ Eq(test::JoinFilename("foo", "alice-video_bob_1280x720_30")));
+ ASSERT_THAT(writer->resolution, Eq(resolution));
+}
+
+} // namespace
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/simulated_network.h b/third_party/libwebrtc/api/test/simulated_network.h
new file mode 100644
index 0000000000..04c5517c8d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/simulated_network.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_SIMULATED_NETWORK_H_
+#define API_TEST_SIMULATED_NETWORK_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <deque>
+#include <queue>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "rtc_base/random.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+struct PacketInFlightInfo {
+ PacketInFlightInfo(size_t size, int64_t send_time_us, uint64_t packet_id)
+ : size(size), send_time_us(send_time_us), packet_id(packet_id) {}
+
+ size_t size;
+ int64_t send_time_us;
+ // Unique identifier for the packet in relation to other packets in flight.
+ uint64_t packet_id;
+};
+
+struct PacketDeliveryInfo {
+ static constexpr int kNotReceived = -1;
+ PacketDeliveryInfo(PacketInFlightInfo source, int64_t receive_time_us)
+ : receive_time_us(receive_time_us), packet_id(source.packet_id) {}
+
+ bool operator==(const PacketDeliveryInfo& other) const {
+ return receive_time_us == other.receive_time_us &&
+ packet_id == other.packet_id;
+ }
+
+ int64_t receive_time_us;
+ uint64_t packet_id;
+};
+
+// BuiltInNetworkBehaviorConfig is a built-in network behavior configuration
+// for built-in network behavior that will be used by WebRTC if no custom
+// NetworkBehaviorInterface is provided.
+struct BuiltInNetworkBehaviorConfig {
+ // Queue length in number of packets.
+ size_t queue_length_packets = 0;
+ // Delay in addition to capacity induced delay.
+ int queue_delay_ms = 0;
+ // Standard deviation of the extra delay.
+ int delay_standard_deviation_ms = 0;
+ // Link capacity in kbps.
+ int link_capacity_kbps = 0;
+ // Random packet loss.
+ int loss_percent = 0;
+ // If packets are allowed to be reordered.
+ bool allow_reordering = false;
+ // The average length of a burst of lost packets.
+ int avg_burst_loss_length = -1;
+ // Additional bytes to add to packet size.
+ int packet_overhead = 0;
+};
+
+// Interface that represents a Network behaviour.
+//
+// It is clients of this interface responsibility to enqueue and dequeue
+// packets (based on the estimated delivery time expressed by
+// NextDeliveryTimeUs).
+//
+// To enqueue packets, call EnqueuePacket:
+// EXPECT_TRUE(network.EnqueuePacket(
+// PacketInFlightInfo(/*size=*/1, /*send_time_us=*/0, /*packet_id=*/1)));
+//
+// To know when to call DequeueDeliverablePackets to pull packets out of the
+// network, call NextDeliveryTimeUs and schedule a task to invoke
+// DequeueDeliverablePackets (if not already scheduled).
+//
+// DequeueDeliverablePackets will return a vector of delivered packets, but this
+// vector can be empty in case of extra delay. In such case, make sure to invoke
+// NextDeliveryTimeUs and schedule a task to call DequeueDeliverablePackets for
+// the next estimated delivery of packets.
+//
+// std::vector<PacketDeliveryInfo> delivered_packets =
+// network.DequeueDeliverablePackets(/*receive_time_us=*/1000000);
+class NetworkBehaviorInterface {
+ public:
+ // Enqueues a packet in the network and returns true if the action was
+ // successful, false otherwise (for example, because the network capacity has
+ // been saturated). If the return value is false, the packet should be
+ // considered as dropped and it will not be returned by future calls
+ // to DequeueDeliverablePackets.
+ // Packets enqueued will exit the network when DequeueDeliverablePackets is
+ // called and enough time has passed (see NextDeliveryTimeUs).
+ virtual bool EnqueuePacket(PacketInFlightInfo packet_info) = 0;
+ // Retrieves all packets that should be delivered by the given receive time.
+ // Not all the packets in the returned std::vector are actually delivered.
+ // In order to know the state of each packet it is necessary to check the
+ // `receive_time_us` field of each packet. If that is set to
+ // PacketDeliveryInfo::kNotReceived then the packet is considered lost in the
+ // network.
+ virtual std::vector<PacketDeliveryInfo> DequeueDeliverablePackets(
+ int64_t receive_time_us) = 0;
+ // Returns time in microseconds when caller should call
+ // DequeueDeliverablePackets to get the next set of delivered packets. It is
+ // possible that no packet will be delivered by that time (e.g. in case of
+ // random extra delay), in such case this method should be called again to get
+ // the updated estimated delivery time.
+ virtual absl::optional<int64_t> NextDeliveryTimeUs() const = 0;
+ virtual ~NetworkBehaviorInterface() = default;
+};
+
+// Class simulating a network link. This is a simple and naive solution just
+// faking capacity and adding an extra transport delay in addition to the
+// capacity introduced delay.
+class SimulatedNetworkInterface : public NetworkBehaviorInterface {
+ public:
+ // Sets a new configuration.
+ virtual void SetConfig(const BuiltInNetworkBehaviorConfig& config) = 0;
+ virtual void UpdateConfig(
+ std::function<void(BuiltInNetworkBehaviorConfig*)> config_modifier) = 0;
+ // Pauses the network until `until_us`. This affects both delivery (calling
+ // DequeueDeliverablePackets before `until_us` results in an empty std::vector
+ // of packets) and capacity (the network is paused, so packets are not
+ // flowing and they will restart flowing at `until_us`).
+ virtual void PauseTransmissionUntil(int64_t until_us) = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_SIMULATED_NETWORK_H_
diff --git a/third_party/libwebrtc/api/test/simulcast_test_fixture.h b/third_party/libwebrtc/api/test/simulcast_test_fixture.h
new file mode 100644
index 0000000000..c7130d2909
--- /dev/null
+++ b/third_party/libwebrtc/api/test/simulcast_test_fixture.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_SIMULCAST_TEST_FIXTURE_H_
+#define API_TEST_SIMULCAST_TEST_FIXTURE_H_
+
+namespace webrtc {
+namespace test {
+
+class SimulcastTestFixture {
+ public:
+ virtual ~SimulcastTestFixture() = default;
+
+ virtual void TestKeyFrameRequestsOnAllStreams() = 0;
+ virtual void TestKeyFrameRequestsOnSpecificStreams() = 0;
+ virtual void TestPaddingAllStreams() = 0;
+ virtual void TestPaddingTwoStreams() = 0;
+ virtual void TestPaddingTwoStreamsOneMaxedOut() = 0;
+ virtual void TestPaddingOneStream() = 0;
+ virtual void TestPaddingOneStreamTwoMaxedOut() = 0;
+ virtual void TestSendAllStreams() = 0;
+ virtual void TestDisablingStreams() = 0;
+ virtual void TestActiveStreams() = 0;
+ virtual void TestSwitchingToOneStream() = 0;
+ virtual void TestSwitchingToOneOddStream() = 0;
+ virtual void TestSwitchingToOneSmallStream() = 0;
+ virtual void TestSpatioTemporalLayers333PatternEncoder() = 0;
+ virtual void TestSpatioTemporalLayers321PatternEncoder() = 0;
+ virtual void TestStrideEncodeDecode() = 0;
+ virtual void TestDecodeWidthHeightSet() = 0;
+ virtual void
+ TestEncoderInfoForDefaultTemporalLayerProfileHasFpsAllocation() = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_SIMULCAST_TEST_FIXTURE_H_
diff --git a/third_party/libwebrtc/api/test/stats_observer_interface.h b/third_party/libwebrtc/api/test/stats_observer_interface.h
new file mode 100644
index 0000000000..58d8f52d77
--- /dev/null
+++ b/third_party/libwebrtc/api/test/stats_observer_interface.h
@@ -0,0 +1,35 @@
+/*
+ * 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 API_TEST_STATS_OBSERVER_INTERFACE_H_
+#define API_TEST_STATS_OBSERVER_INTERFACE_H_
+
+#include "absl/strings/string_view.h"
+#include "api/stats/rtc_stats_report.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// API is in development and can be changed without notice.
+class StatsObserverInterface {
+ public:
+ virtual ~StatsObserverInterface() = default;
+
+ // Method called when stats reports are available for the PeerConnection
+ // identified by `pc_label`.
+ virtual void OnStatsReports(
+ absl::string_view pc_label,
+ const rtc::scoped_refptr<const RTCStatsReport>& report) = 0;
+};
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_STATS_OBSERVER_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/test/test_dependency_factory.cc b/third_party/libwebrtc/api/test/test_dependency_factory.cc
new file mode 100644
index 0000000000..41ad70cc3f
--- /dev/null
+++ b/third_party/libwebrtc/api/test/test_dependency_factory.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 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 "api/test/test_dependency_factory.h"
+
+#include <memory>
+#include <utility>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/platform_thread_types.h"
+
+namespace webrtc {
+
+namespace {
+// This checks everything in this file gets called on the same thread. It's
+// static because it needs to look at the static methods too.
+bool IsValidTestDependencyFactoryThread() {
+ const rtc::PlatformThreadRef main_thread = rtc::CurrentThreadRef();
+ return rtc::IsThreadRefEqual(main_thread, rtc::CurrentThreadRef());
+}
+} // namespace
+
+std::unique_ptr<TestDependencyFactory> TestDependencyFactory::instance_ =
+ nullptr;
+
+const TestDependencyFactory& TestDependencyFactory::GetInstance() {
+ RTC_DCHECK(IsValidTestDependencyFactoryThread());
+ if (instance_ == nullptr) {
+ instance_ = std::make_unique<TestDependencyFactory>();
+ }
+ return *instance_;
+}
+
+void TestDependencyFactory::SetInstance(
+ std::unique_ptr<TestDependencyFactory> instance) {
+ RTC_DCHECK(IsValidTestDependencyFactoryThread());
+ RTC_CHECK(instance_ == nullptr);
+ instance_ = std::move(instance);
+}
+
+std::unique_ptr<VideoQualityTestFixtureInterface::InjectionComponents>
+TestDependencyFactory::CreateComponents() const {
+ RTC_DCHECK(IsValidTestDependencyFactoryThread());
+ return nullptr;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/test_dependency_factory.h b/third_party/libwebrtc/api/test/test_dependency_factory.h
new file mode 100644
index 0000000000..29f00b8070
--- /dev/null
+++ b/third_party/libwebrtc/api/test/test_dependency_factory.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_TEST_DEPENDENCY_FACTORY_H_
+#define API_TEST_TEST_DEPENDENCY_FACTORY_H_
+
+#include <memory>
+
+#include "api/test/video_quality_test_fixture.h"
+
+namespace webrtc {
+
+// Override this class if to inject custom components into WebRTC tests.
+// Not all WebRTC tests get their components from here, so you need to make
+// sure the tests you want actually use this class.
+//
+// This class is not thread safe and you need to make call calls from the same
+// (test main) thread.
+class TestDependencyFactory {
+ public:
+ virtual ~TestDependencyFactory() = default;
+
+ // The singleton MUST be stateless since tests execute in any order. It must
+ // be set before tests start executing.
+ static const TestDependencyFactory& GetInstance();
+ static void SetInstance(std::unique_ptr<TestDependencyFactory> instance);
+
+ // Returns the component a test should use. Returning nullptr means that the
+ // test is free to use whatever defaults it wants. The injection components
+ // themselves can be mutable, but we need to make new ones for every test that
+ // executes so state doesn't spread between tests.
+ virtual std::unique_ptr<VideoQualityTestFixtureInterface::InjectionComponents>
+ CreateComponents() const;
+
+ private:
+ static std::unique_ptr<TestDependencyFactory> instance_;
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_TEST_DEPENDENCY_FACTORY_H_
diff --git a/third_party/libwebrtc/api/test/time_controller.cc b/third_party/libwebrtc/api/test/time_controller.cc
new file mode 100644
index 0000000000..364dbc235d
--- /dev/null
+++ b/third_party/libwebrtc/api/test/time_controller.cc
@@ -0,0 +1,43 @@
+/*
+ * 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 "api/test/time_controller.h"
+
+namespace webrtc {
+std::unique_ptr<TaskQueueFactory> TimeController::CreateTaskQueueFactory() {
+ class FactoryWrapper final : public TaskQueueFactory {
+ public:
+ explicit FactoryWrapper(TaskQueueFactory* inner_factory)
+ : inner_(inner_factory) {}
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ absl::string_view name,
+ Priority priority) const override {
+ return inner_->CreateTaskQueue(name, priority);
+ }
+
+ private:
+ TaskQueueFactory* const inner_;
+ };
+ return std::make_unique<FactoryWrapper>(GetTaskQueueFactory());
+}
+bool TimeController::Wait(const std::function<bool()>& condition,
+ TimeDelta max_duration) {
+ // Step size is chosen to be short enough to not significantly affect latency
+ // in real time tests while being long enough to avoid adding too much load to
+ // the system.
+ const auto kStep = TimeDelta::Millis(5);
+ for (auto elapsed = TimeDelta::Zero(); elapsed < max_duration;
+ elapsed += kStep) {
+ if (condition())
+ return true;
+ AdvanceTime(kStep);
+ }
+ return condition();
+}
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/time_controller.h b/third_party/libwebrtc/api/test/time_controller.h
new file mode 100644
index 0000000000..121f65cea9
--- /dev/null
+++ b/third_party/libwebrtc/api/test/time_controller.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 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 API_TEST_TIME_CONTROLLER_H_
+#define API_TEST_TIME_CONTROLLER_H_
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/synchronization/yield_policy.h"
+#include "rtc_base/thread.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+// Interface for controlling time progress. This allows us to execute test code
+// in either real time or simulated time by using different implementation of
+// this interface.
+class TimeController {
+ public:
+ virtual ~TimeController() = default;
+ // Provides a clock instance that follows implementation defined time
+ // progress.
+ virtual Clock* GetClock() = 0;
+ // The returned factory will created task queues that runs in implementation
+ // defined time domain.
+ virtual TaskQueueFactory* GetTaskQueueFactory() = 0;
+ // Simple helper to create an owned factory that can be used as a parameter
+ // for PeerConnectionFactory. Note that this might depend on the underlying
+ // time controller and therfore must be destroyed before the time controller
+ // is destroyed.
+ std::unique_ptr<TaskQueueFactory> CreateTaskQueueFactory();
+
+ // Creates an rtc::Thread instance. If `socket_server` is nullptr, a default
+ // noop socket server is created.
+ // Returned thread is not null and started.
+ virtual std::unique_ptr<rtc::Thread> CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server = nullptr) = 0;
+
+ // Creates an rtc::Thread instance that ensure that it's set as the current
+ // thread.
+ virtual rtc::Thread* GetMainThread() = 0;
+ // Allow task queues and process threads created by this instance to execute
+ // for the given `duration`.
+ virtual void AdvanceTime(TimeDelta duration) = 0;
+
+ // Waits until condition() == true, polling condition() in small time
+ // intervals.
+ // Returns true if condition() was evaluated to true before `max_duration`
+ // elapsed and false otherwise.
+ bool Wait(const std::function<bool()>& condition,
+ TimeDelta max_duration = TimeDelta::Seconds(5));
+};
+
+// Interface for telling time, scheduling an event to fire at a particular time,
+// and waiting for time to pass.
+class ControlledAlarmClock {
+ public:
+ virtual ~ControlledAlarmClock() = default;
+
+ // Gets a clock that tells the alarm clock's notion of time.
+ virtual Clock* GetClock() = 0;
+
+ // Schedules the alarm to fire at `deadline`.
+ // An alarm clock only supports one deadline. Calls to `ScheduleAlarmAt` with
+ // an earlier deadline will reset the alarm to fire earlier.Calls to
+ // `ScheduleAlarmAt` with a later deadline are ignored. Returns true if the
+ // deadline changed, false otherwise.
+ virtual bool ScheduleAlarmAt(Timestamp deadline) = 0;
+
+ // Sets the callback that should be run when the alarm fires.
+ virtual void SetCallback(std::function<void()> callback) = 0;
+
+ // Waits for `duration` to pass, according to the alarm clock.
+ virtual void Sleep(TimeDelta duration) = 0;
+};
+
+} // namespace webrtc
+#endif // API_TEST_TIME_CONTROLLER_H_
diff --git a/third_party/libwebrtc/api/test/track_id_stream_info_map.h b/third_party/libwebrtc/api/test/track_id_stream_info_map.h
new file mode 100644
index 0000000000..b016de57a9
--- /dev/null
+++ b/third_party/libwebrtc/api/test/track_id_stream_info_map.h
@@ -0,0 +1,44 @@
+/*
+ * 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 API_TEST_TRACK_ID_STREAM_INFO_MAP_H_
+#define API_TEST_TRACK_ID_STREAM_INFO_MAP_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+
+namespace webrtc {
+namespace webrtc_pc_e2e {
+
+// Instances of `TrackIdStreamInfoMap` provide bookkeeping capabilities that
+// are useful to associate stats reports track_ids to the remote stream info.
+class TrackIdStreamInfoMap {
+ public:
+ struct StreamInfo {
+ std::string receiver_peer;
+ std::string stream_label;
+ std::string sync_group;
+ };
+
+ virtual ~TrackIdStreamInfoMap() = default;
+
+ // These methods must be called on the same thread where
+ // StatsObserverInterface::OnStatsReports is invoked.
+
+ // Precondition: `track_id` must be already mapped to stream info.
+ virtual StreamInfo GetStreamInfoFromTrackId(
+ absl::string_view track_id) const = 0;
+};
+
+} // namespace webrtc_pc_e2e
+} // namespace webrtc
+
+#endif // API_TEST_TRACK_ID_STREAM_INFO_MAP_H_
diff --git a/third_party/libwebrtc/api/test/video/BUILD.gn b/third_party/libwebrtc/api/test/video/BUILD.gn
new file mode 100644
index 0000000000..d24ffa5fa6
--- /dev/null
+++ b/third_party/libwebrtc/api/test/video/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright (c) 2018 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.
+
+import("../../../webrtc.gni")
+
+rtc_library("function_video_factory") {
+ visibility = [ "*" ]
+ testonly = true
+ public = [
+ "function_video_decoder_factory.h",
+ "function_video_encoder_factory.h",
+ ]
+
+ deps = [
+ "../../../rtc_base:checks",
+ "../../video_codecs:video_codecs_api",
+ ]
+}
+
+rtc_library("video_frame_writer") {
+ visibility = [ "*" ]
+ testonly = true
+ public = [ "video_frame_writer.h" ]
+
+ deps = [ "../../video:video_frame" ]
+}
diff --git a/third_party/libwebrtc/api/test/video/function_video_decoder_factory.h b/third_party/libwebrtc/api/test/video/function_video_decoder_factory.h
new file mode 100644
index 0000000000..2145c71bff
--- /dev/null
+++ b/third_party/libwebrtc/api/test/video/function_video_decoder_factory.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_VIDEO_FUNCTION_VIDEO_DECODER_FACTORY_H_
+#define API_TEST_VIDEO_FUNCTION_VIDEO_DECODER_FACTORY_H_
+
+#include <functional>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_decoder.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace test {
+
+// A decoder factory producing decoders by calling a supplied create function.
+class FunctionVideoDecoderFactory final : public VideoDecoderFactory {
+ public:
+ explicit FunctionVideoDecoderFactory(
+ std::function<std::unique_ptr<VideoDecoder>()> create)
+ : create_([create = std::move(create)](const SdpVideoFormat&) {
+ return create();
+ }) {}
+ explicit FunctionVideoDecoderFactory(
+ std::function<std::unique_ptr<VideoDecoder>(const SdpVideoFormat&)>
+ create)
+ : create_(std::move(create)) {}
+ FunctionVideoDecoderFactory(
+ std::function<std::unique_ptr<VideoDecoder>()> create,
+ std::vector<SdpVideoFormat> sdp_video_formats)
+ : create_([create = std::move(create)](const SdpVideoFormat&) {
+ return create();
+ }),
+ sdp_video_formats_(std::move(sdp_video_formats)) {}
+
+ std::vector<SdpVideoFormat> GetSupportedFormats() const override {
+ return sdp_video_formats_;
+ }
+
+ std::unique_ptr<VideoDecoder> CreateVideoDecoder(
+ const SdpVideoFormat& format) override {
+ return create_(format);
+ }
+
+ private:
+ const std::function<std::unique_ptr<VideoDecoder>(const SdpVideoFormat&)>
+ create_;
+ const std::vector<SdpVideoFormat> sdp_video_formats_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_VIDEO_FUNCTION_VIDEO_DECODER_FACTORY_H_
diff --git a/third_party/libwebrtc/api/test/video/function_video_encoder_factory.h b/third_party/libwebrtc/api/test/video/function_video_encoder_factory.h
new file mode 100644
index 0000000000..98ece2bc94
--- /dev/null
+++ b/third_party/libwebrtc/api/test/video/function_video_encoder_factory.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_VIDEO_FUNCTION_VIDEO_ENCODER_FACTORY_H_
+#define API_TEST_VIDEO_FUNCTION_VIDEO_ENCODER_FACTORY_H_
+
+#include <functional>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace test {
+
+// An encoder factory producing encoders by calling a supplied create
+// function.
+class FunctionVideoEncoderFactory final : public VideoEncoderFactory {
+ public:
+ explicit FunctionVideoEncoderFactory(
+ std::function<std::unique_ptr<VideoEncoder>()> create)
+ : create_([create = std::move(create)](const SdpVideoFormat&) {
+ return create();
+ }) {}
+ explicit FunctionVideoEncoderFactory(
+ std::function<std::unique_ptr<VideoEncoder>(const SdpVideoFormat&)>
+ create)
+ : create_(std::move(create)) {}
+
+ // Unused by tests.
+ std::vector<SdpVideoFormat> GetSupportedFormats() const override {
+ RTC_DCHECK_NOTREACHED();
+ return {};
+ }
+
+ std::unique_ptr<VideoEncoder> CreateVideoEncoder(
+ const SdpVideoFormat& format) override {
+ return create_(format);
+ }
+
+ private:
+ const std::function<std::unique_ptr<VideoEncoder>(const SdpVideoFormat&)>
+ create_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_VIDEO_FUNCTION_VIDEO_ENCODER_FACTORY_H_
diff --git a/third_party/libwebrtc/api/test/video/video_frame_writer.h b/third_party/libwebrtc/api/test/video/video_frame_writer.h
new file mode 100644
index 0000000000..ac72534890
--- /dev/null
+++ b/third_party/libwebrtc/api/test/video/video_frame_writer.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_VIDEO_VIDEO_FRAME_WRITER_H_
+#define API_TEST_VIDEO_VIDEO_FRAME_WRITER_H_
+
+#include "api/video/video_frame.h"
+
+namespace webrtc {
+namespace test {
+
+class VideoFrameWriter {
+ public:
+ virtual ~VideoFrameWriter() = default;
+
+ // Writes `VideoFrame` and returns true if operation was successful, false
+ // otherwise.
+ //
+ // Calling `WriteFrame` after `Close` is not allowed.
+ virtual bool WriteFrame(const VideoFrame& frame) = 0;
+
+ // Closes writer and cleans up all resources. No invocations to `WriteFrame`
+ // are allowed after `Close` was invoked.
+ virtual void Close() = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_VIDEO_VIDEO_FRAME_WRITER_H_
diff --git a/third_party/libwebrtc/api/test/video_codec_tester.h b/third_party/libwebrtc/api/test/video_codec_tester.h
new file mode 100644
index 0000000000..0eaaa1b895
--- /dev/null
+++ b/third_party/libwebrtc/api/test/video_codec_tester.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2022 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 API_TEST_VIDEO_CODEC_TESTER_H_
+#define API_TEST_VIDEO_CODEC_TESTER_H_
+
+#include <memory>
+
+#include "absl/functional/any_invocable.h"
+#include "api/test/videocodec_test_stats.h"
+#include "api/video/encoded_image.h"
+#include "api/video/resolution.h"
+#include "api/video/video_frame.h"
+
+namespace webrtc {
+namespace test {
+
+// Interface for a video codec tester. The interface provides minimalistic set
+// of data structures that enables implementation of decode-only, encode-only
+// and encode-decode tests.
+class VideoCodecTester {
+ public:
+ // Pacing settings for codec input.
+ struct PacingSettings {
+ enum PacingMode {
+ // Pacing is not used. Frames are sent to codec back-to-back.
+ kNoPacing,
+ // Pace with the rate equal to the target video frame rate. Pacing time is
+ // derived from RTP timestamp.
+ kRealTime,
+ // Pace with the explicitly provided rate.
+ kConstantRate,
+ };
+ PacingMode mode = PacingMode::kNoPacing;
+ // Pacing rate for `kConstantRate` mode.
+ Frequency constant_rate = Frequency::Zero();
+ };
+
+ struct DecoderSettings {
+ PacingSettings pacing;
+ };
+
+ struct EncoderSettings {
+ PacingSettings pacing;
+ };
+
+ virtual ~VideoCodecTester() = default;
+
+ // Interface for a raw video frames source.
+ class RawVideoSource {
+ public:
+ virtual ~RawVideoSource() = default;
+
+ // Returns next frame. If no more frames to pull, returns `absl::nullopt`.
+ // For analysis and pacing purposes, frame must have RTP timestamp set. The
+ // timestamp must represent the target video frame rate and be unique.
+ virtual absl::optional<VideoFrame> PullFrame() = 0;
+
+ // Returns early pulled frame with RTP timestamp equal to `timestamp_rtp`.
+ virtual VideoFrame GetFrame(uint32_t timestamp_rtp,
+ Resolution resolution) = 0;
+ };
+
+ // Interface for a coded video frames source.
+ class CodedVideoSource {
+ public:
+ virtual ~CodedVideoSource() = default;
+
+ // Returns next frame. If no more frames to pull, returns `absl::nullopt`.
+ // For analysis and pacing purposes, frame must have RTP timestamp set. The
+ // timestamp must represent the target video frame rate and be unique.
+ virtual absl::optional<EncodedImage> PullFrame() = 0;
+ };
+
+ // Interface for a video encoder.
+ class Encoder {
+ public:
+ using EncodeCallback =
+ absl::AnyInvocable<void(const EncodedImage& encoded_frame)>;
+
+ virtual ~Encoder() = default;
+
+ virtual void Encode(const VideoFrame& frame, EncodeCallback callback) = 0;
+ };
+
+ // Interface for a video decoder.
+ class Decoder {
+ public:
+ using DecodeCallback =
+ absl::AnyInvocable<void(const VideoFrame& decoded_frame)>;
+
+ virtual ~Decoder() = default;
+
+ virtual void Decode(const EncodedImage& frame, DecodeCallback callback) = 0;
+ };
+
+ // Pulls coded video frames from `video_source` and passes them to `decoder`.
+ // Returns `VideoCodecTestStats` object that contains collected per-frame
+ // metrics.
+ virtual std::unique_ptr<VideoCodecTestStats> RunDecodeTest(
+ std::unique_ptr<CodedVideoSource> video_source,
+ std::unique_ptr<Decoder> decoder,
+ const DecoderSettings& decoder_settings) = 0;
+
+ // Pulls raw video frames from `video_source` and passes them to `encoder`.
+ // Returns `VideoCodecTestStats` object that contains collected per-frame
+ // metrics.
+ virtual std::unique_ptr<VideoCodecTestStats> RunEncodeTest(
+ std::unique_ptr<RawVideoSource> video_source,
+ std::unique_ptr<Encoder> encoder,
+ const EncoderSettings& encoder_settings) = 0;
+
+ // Pulls raw video frames from `video_source`, passes them to `encoder` and
+ // then passes encoded frames to `decoder`. Returns `VideoCodecTestStats`
+ // object that contains collected per-frame metrics.
+ virtual std::unique_ptr<VideoCodecTestStats> RunEncodeDecodeTest(
+ std::unique_ptr<RawVideoSource> video_source,
+ std::unique_ptr<Encoder> encoder,
+ std::unique_ptr<Decoder> decoder,
+ const EncoderSettings& encoder_settings,
+ const DecoderSettings& decoder_settings) = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_VIDEO_CODEC_TESTER_H_
diff --git a/third_party/libwebrtc/api/test/video_quality_analyzer_interface.h b/third_party/libwebrtc/api/test/video_quality_analyzer_interface.h
new file mode 100644
index 0000000000..d35be8ca1a
--- /dev/null
+++ b/third_party/libwebrtc/api/test/video_quality_analyzer_interface.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_VIDEO_QUALITY_ANALYZER_INTERFACE_H_
+#define API_TEST_VIDEO_QUALITY_ANALYZER_INTERFACE_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/test/stats_observer_interface.h"
+#include "api/video/encoded_image.h"
+#include "api/video/video_frame.h"
+#include "api/video_codecs/video_encoder.h"
+
+namespace webrtc {
+
+// API is in development and can be changed without notice.
+
+// Base interface for video quality analyzer for peer connection level end-2-end
+// tests. Interface has only one abstract method, which have to return frame id.
+// Other methods have empty implementation by default, so user can override only
+// required parts.
+//
+// VideoQualityAnalyzerInterface will be injected into WebRTC pipeline on both
+// sides of the call. Here is video data flow in WebRTC pipeline
+//
+// Alice:
+// ___________ ________ _________
+// | | | | | |
+// | Frame |-(A)→| WebRTC |-(B)→| Video |-(C)┐
+// | Generator | | Stack | | Decoder | |
+// ¯¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯ |
+// __↓________
+// | Transport |
+// | & |
+// | Network |
+// ¯¯|¯¯¯¯¯¯¯¯
+// Bob: |
+// _______ ________ _________ |
+// | | | | | | |
+// | Video |←(F)-| WebRTC |←(E)-| Video |←(D)----┘
+// | Sink | | Stack | | Decoder |
+// ¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯
+// The analyzer will be injected in all points from A to F.
+class VideoQualityAnalyzerInterface
+ : public webrtc_pc_e2e::StatsObserverInterface {
+ public:
+ // Contains extra statistic provided by video encoder.
+ struct EncoderStats {
+ std::string encoder_name = "unknown";
+ // TODO(hbos) https://crbug.com/webrtc/9547,
+ // https://crbug.com/webrtc/11443: improve stats API to make available
+ // there.
+ uint32_t target_encode_bitrate = 0;
+ // Encoder quantizer value.
+ int qp = -1;
+ };
+ // Contains extra statistic provided by video decoder.
+ struct DecoderStats {
+ std::string decoder_name = "unknown";
+ // Decode time provided by decoder itself. If decoder doesn’t produce such
+ // information can be omitted.
+ absl::optional<int32_t> decode_time_ms = absl::nullopt;
+ };
+
+ ~VideoQualityAnalyzerInterface() override = default;
+
+ // Will be called by framework before test.
+ // `test_case_name` is name of test case, that should be used to report all
+ // video metrics.
+ // `threads_count` is number of threads that analyzer can use for heavy
+ // calculations. Analyzer can perform simple calculations on the calling
+ // thread in each method, but should remember, that it is the same thread,
+ // that is used in video pipeline.
+ virtual void Start(std::string test_case_name,
+ rtc::ArrayView<const std::string> peer_names,
+ int max_threads_count) {}
+
+ // Will be called when frame was generated from the input stream.
+ // `peer_name` is name of the peer on which side frame was captured.
+ // Returns frame id, that will be set by framework to the frame.
+ virtual uint16_t OnFrameCaptured(absl::string_view peer_name,
+ const std::string& stream_label,
+ const VideoFrame& frame) = 0;
+ // Will be called before calling the encoder.
+ // `peer_name` is name of the peer on which side frame came to encoder.
+ virtual void OnFramePreEncode(absl::string_view peer_name,
+ const VideoFrame& frame) {}
+ // Will be called for each EncodedImage received from encoder. Single
+ // VideoFrame can produce multiple EncodedImages. Each encoded image will
+ // have id from VideoFrame.
+ // `peer_name` is name of the peer on which side frame was encoded.
+ virtual void OnFrameEncoded(absl::string_view peer_name,
+ uint16_t frame_id,
+ const EncodedImage& encoded_image,
+ const EncoderStats& stats,
+ bool discarded) {}
+ // Will be called for each frame dropped by encoder.
+ // `peer_name` is name of the peer on which side frame drop was detected.
+ virtual void OnFrameDropped(absl::string_view peer_name,
+ EncodedImageCallback::DropReason reason) {}
+ // Will be called before calling the decoder.
+ // `peer_name` is name of the peer on which side frame was received.
+ virtual void OnFramePreDecode(absl::string_view peer_name,
+ uint16_t frame_id,
+ const EncodedImage& encoded_image) {}
+ // Will be called after decoding the frame.
+ // `peer_name` is name of the peer on which side frame was decoded.
+ virtual void OnFrameDecoded(absl::string_view peer_name,
+ const VideoFrame& frame,
+ const DecoderStats& stats) {}
+ // Will be called when frame will be obtained from PeerConnection stack.
+ // `peer_name` is name of the peer on which side frame was rendered.
+ virtual void OnFrameRendered(absl::string_view peer_name,
+ const VideoFrame& frame) {}
+ // Will be called if encoder return not WEBRTC_VIDEO_CODEC_OK.
+ // All available codes are listed in
+ // modules/video_coding/include/video_error_codes.h
+ // `peer_name` is name of the peer on which side error acquired.
+ virtual void OnEncoderError(absl::string_view peer_name,
+ const VideoFrame& frame,
+ int32_t error_code) {}
+ // Will be called if decoder return not WEBRTC_VIDEO_CODEC_OK.
+ // All available codes are listed in
+ // modules/video_coding/include/video_error_codes.h
+ // `peer_name` is name of the peer on which side error acquired.
+ virtual void OnDecoderError(absl::string_view peer_name,
+ uint16_t frame_id,
+ int32_t error_code,
+ const DecoderStats& stats) {}
+ // Will be called every time new stats reports are available for the
+ // Peer Connection identified by `pc_label`.
+ void OnStatsReports(
+ absl::string_view pc_label,
+ const rtc::scoped_refptr<const RTCStatsReport>& report) override {}
+
+ // Will be called before test adds new participant in the middle of a call.
+ virtual void RegisterParticipantInCall(absl::string_view peer_name) {}
+ // Will be called after test removed existing participant in the middle of the
+ // call.
+ virtual void UnregisterParticipantInCall(absl::string_view peer_name) {}
+
+ // Tells analyzer that analysis complete and it should calculate final
+ // statistics.
+ virtual void Stop() {}
+
+ // Returns the last stream where this frame was captured. It means that if
+ // frame ids space wraps around, then stream label for frame id may change.
+ // It will crash, if the specified `frame_id` wasn't captured.
+ virtual std::string GetStreamLabel(uint16_t frame_id) = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_VIDEO_QUALITY_ANALYZER_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/test/video_quality_test_fixture.h b/third_party/libwebrtc/api/test/video_quality_test_fixture.h
new file mode 100644
index 0000000000..b45faef286
--- /dev/null
+++ b/third_party/libwebrtc/api/test/video_quality_test_fixture.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_VIDEO_QUALITY_TEST_FIXTURE_H_
+#define API_TEST_VIDEO_QUALITY_TEST_FIXTURE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/fec_controller.h"
+#include "api/media_types.h"
+#include "api/network_state_predictor.h"
+#include "api/test/simulated_network.h"
+#include "api/transport/bitrate_settings.h"
+#include "api/transport/network_control.h"
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "video/config/video_encoder_config.h"
+
+namespace webrtc {
+
+class VideoQualityTestFixtureInterface {
+ public:
+ // Parameters are grouped into smaller structs to make it easier to set
+ // the desired elements and skip unused.
+ struct Params {
+ struct CallConfig {
+ bool send_side_bwe = false;
+ bool generic_descriptor = false;
+ bool dependency_descriptor = false;
+ BitrateConstraints call_bitrate_config;
+ int num_thumbnails = 0;
+ // Indicates if secondary_(video|ss|screenshare) structures are used.
+ bool dual_video = false;
+ } call;
+ struct Video {
+ bool enabled = false;
+ size_t width = 640;
+ size_t height = 480;
+ int32_t fps = 30;
+ int min_bitrate_bps = 50;
+ int target_bitrate_bps = 800;
+ int max_bitrate_bps = 800;
+ bool suspend_below_min_bitrate = false;
+ std::string codec = "VP8";
+ int num_temporal_layers = 1;
+ int selected_tl = -1;
+ int min_transmit_bps = 0;
+ bool ulpfec = false;
+ bool flexfec = false;
+ bool automatic_scaling = false;
+ std::string clip_path; // "Generator" to generate frames instead.
+ size_t capture_device_index = 0;
+ SdpVideoFormat::Parameters sdp_params;
+ double encoder_overshoot_factor = 0.0;
+ } video[2];
+ struct Audio {
+ bool enabled = false;
+ bool sync_video = false;
+ bool dtx = false;
+ bool use_real_adm = false;
+ absl::optional<std::string> ana_config;
+ } audio;
+ struct Screenshare {
+ bool enabled = false;
+ bool generate_slides = false;
+ int32_t slide_change_interval = 10;
+ int32_t scroll_duration = 0;
+ std::vector<std::string> slides;
+ } screenshare[2];
+ struct Analyzer {
+ std::string test_label;
+ double avg_psnr_threshold = 0.0; // (*)
+ double avg_ssim_threshold = 0.0; // (*)
+ int test_durations_secs = 0;
+ std::string graph_data_output_filename;
+ std::string graph_title;
+ } analyzer;
+ // Config for default simulation implementation. Must be nullopt if
+ // `sender_network` and `receiver_network` in InjectionComponents are
+ // non-null. May be nullopt even if `sender_network` and `receiver_network`
+ // are null; in that case, a default config will be used.
+ absl::optional<BuiltInNetworkBehaviorConfig> config;
+ struct SS { // Spatial scalability.
+ std::vector<VideoStream> streams; // If empty, one stream is assumed.
+ size_t selected_stream = 0;
+ int num_spatial_layers = 0;
+ int selected_sl = -1;
+ InterLayerPredMode inter_layer_pred = InterLayerPredMode::kOn;
+ // If empty, bitrates are generated in VP9Impl automatically.
+ std::vector<SpatialLayer> spatial_layers;
+ // If set, default parameters will be used instead of `streams`.
+ bool infer_streams = false;
+ } ss[2];
+ struct Logging {
+ std::string rtc_event_log_name;
+ std::string rtp_dump_name;
+ std::string encoded_frame_base_path;
+ } logging;
+ };
+
+ // Contains objects, that will be injected on different layers of test
+ // framework to override the behavior of system parts.
+ struct InjectionComponents {
+ InjectionComponents();
+ ~InjectionComponents();
+
+ // Simulations of sender and receiver networks. They must either both be
+ // null (in which case `config` from Params is used), or both be non-null
+ // (in which case `config` from Params must be nullopt).
+ std::unique_ptr<NetworkBehaviorInterface> sender_network;
+ std::unique_ptr<NetworkBehaviorInterface> receiver_network;
+
+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory;
+ std::unique_ptr<VideoEncoderFactory> video_encoder_factory;
+ std::unique_ptr<VideoDecoderFactory> video_decoder_factory;
+ std::unique_ptr<NetworkStatePredictorFactoryInterface>
+ network_state_predictor_factory;
+ std::unique_ptr<NetworkControllerFactoryInterface>
+ network_controller_factory;
+ };
+
+ virtual ~VideoQualityTestFixtureInterface() = default;
+
+ virtual void RunWithAnalyzer(const Params& params) = 0;
+ virtual void RunWithRenderers(const Params& params) = 0;
+
+ virtual const std::map<uint8_t, webrtc::MediaType>& payload_type_map() = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_TEST_VIDEO_QUALITY_TEST_FIXTURE_H_
diff --git a/third_party/libwebrtc/api/test/videocodec_test_fixture.h b/third_party/libwebrtc/api/test/videocodec_test_fixture.h
new file mode 100644
index 0000000000..dbf20993e2
--- /dev/null
+++ b/third_party/libwebrtc/api/test/videocodec_test_fixture.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_VIDEOCODEC_TEST_FIXTURE_H_
+#define API_TEST_VIDEOCODEC_TEST_FIXTURE_H_
+
+#include <string>
+#include <vector>
+
+#include "api/test/videocodec_test_stats.h"
+#include "api/video_codecs/h264_profile_level_id.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "modules/video_coding/include/video_codec_interface.h"
+
+namespace webrtc {
+namespace test {
+
+// Rates for the encoder and the frame number when to apply profile.
+struct RateProfile {
+ size_t target_kbps;
+ double input_fps;
+ size_t frame_num;
+};
+
+struct RateControlThresholds {
+ double max_avg_bitrate_mismatch_percent;
+ double max_time_to_reach_target_bitrate_sec;
+ // TODO(ssilkin): Use absolute threshold for framerate.
+ double max_avg_framerate_mismatch_percent;
+ double max_avg_buffer_level_sec;
+ double max_max_key_frame_delay_sec;
+ double max_max_delta_frame_delay_sec;
+ size_t max_num_spatial_resizes;
+ size_t max_num_key_frames;
+};
+
+struct QualityThresholds {
+ double min_avg_psnr;
+ double min_min_psnr;
+ double min_avg_ssim;
+ double min_min_ssim;
+};
+
+struct BitstreamThresholds {
+ size_t max_max_nalu_size_bytes;
+};
+
+// NOTE: This class is still under development and may change without notice.
+class VideoCodecTestFixture {
+ public:
+ class EncodedFrameChecker {
+ public:
+ virtual ~EncodedFrameChecker() = default;
+ virtual void CheckEncodedFrame(VideoCodecType codec,
+ const EncodedImage& encoded_frame) const = 0;
+ };
+
+ struct Config {
+ Config();
+ void SetCodecSettings(std::string codec_name,
+ size_t num_simulcast_streams,
+ size_t num_spatial_layers,
+ size_t num_temporal_layers,
+ bool denoising_on,
+ bool frame_dropper_on,
+ bool spatial_resize_on,
+ size_t width,
+ size_t height);
+
+ size_t NumberOfCores() const;
+ size_t NumberOfTemporalLayers() const;
+ size_t NumberOfSpatialLayers() const;
+ size_t NumberOfSimulcastStreams() const;
+
+ std::string ToString() const;
+ std::string CodecName() const;
+
+ // Name of this config, to be used for accounting by the test runner.
+ std::string test_name;
+
+ // Plain name of YUV file to process without file extension.
+ std::string filename;
+ // Dimensions of test clip. Falls back to (codec_settings.width/height) if
+ // not set.
+ absl::optional<int> clip_width;
+ absl::optional<int> clip_height;
+ // Framerate of input clip. Defaults to 30fps if not set.
+ absl::optional<int> clip_fps;
+
+ // The resolution at which psnr/ssim comparisons should be made. Frames
+ // will be scaled to this size if different.
+ absl::optional<int> reference_width;
+ absl::optional<int> reference_height;
+
+ // File to process. This must be a video file in the YUV format.
+ std::string filepath;
+
+ // Number of frames to process.
+ size_t num_frames = 0;
+
+ // Bitstream constraints.
+ size_t max_payload_size_bytes = 1440;
+
+ // Should we decode the encoded frames?
+ bool decode = true;
+
+ // Force the encoder and decoder to use a single core for processing.
+ bool use_single_core = false;
+
+ // Should cpu usage be measured?
+ // If set to true, the encoding will run in real-time.
+ bool measure_cpu = false;
+
+ // Simulate frames arriving in real-time by adding delays between frames.
+ bool encode_in_real_time = false;
+
+ // Codec settings to use.
+ VideoCodec codec_settings;
+
+ // Name of the codec being tested.
+ std::string codec_name;
+
+ // Encoder and decoder format and parameters. If provided, format is used to
+ // instantiate the codec. If not provided, the test creates and uses the
+ // default `SdpVideoFormat` based on `codec_name`.
+ // Encoder and decoder name (`SdpVideoFormat::name`) should be the same as
+ // `codec_name`.
+ absl::optional<SdpVideoFormat> encoder_format;
+ absl::optional<SdpVideoFormat> decoder_format;
+
+ // H.264 specific settings.
+ struct H264CodecSettings {
+ H264Profile profile = H264Profile::kProfileConstrainedBaseline;
+ H264PacketizationMode packetization_mode =
+ H264PacketizationMode::NonInterleaved;
+ } h264_codec_settings;
+
+ // Custom checker that will be called for each frame.
+ const EncodedFrameChecker* encoded_frame_checker = nullptr;
+
+ // Print out frame level stats.
+ bool print_frame_level_stats = false;
+
+ // Path to a directory where encoded or/and decoded video should be saved.
+ std::string output_path;
+
+ // Should video be saved persistently to disk for post-run visualization?
+ struct VisualizationParams {
+ bool save_encoded_ivf = false;
+ bool save_decoded_y4m = false;
+ } visualization_params;
+
+ // Enables quality analysis for dropped frames.
+ bool analyze_quality_of_dropped_frames = false;
+ };
+
+ virtual ~VideoCodecTestFixture() = default;
+
+ virtual void RunTest(const std::vector<RateProfile>& rate_profiles,
+ const std::vector<RateControlThresholds>* rc_thresholds,
+ const std::vector<QualityThresholds>* quality_thresholds,
+ const BitstreamThresholds* bs_thresholds) = 0;
+ virtual VideoCodecTestStats& GetStats() = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_VIDEOCODEC_TEST_FIXTURE_H_
diff --git a/third_party/libwebrtc/api/test/videocodec_test_stats.cc b/third_party/libwebrtc/api/test/videocodec_test_stats.cc
new file mode 100644
index 0000000000..f082b1e935
--- /dev/null
+++ b/third_party/libwebrtc/api/test/videocodec_test_stats.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018 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 "api/test/videocodec_test_stats.h"
+
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+namespace test {
+
+VideoCodecTestStats::FrameStatistics::FrameStatistics(size_t frame_number,
+ size_t rtp_timestamp,
+ size_t spatial_idx)
+ : frame_number(frame_number),
+ rtp_timestamp(rtp_timestamp),
+ spatial_idx(spatial_idx) {}
+
+std::string VideoCodecTestStats::FrameStatistics::ToString() const {
+ rtc::StringBuilder ss;
+ for (const auto& entry : ToMap()) {
+ if (ss.size() > 0) {
+ ss << " ";
+ }
+ ss << entry.first << " " << entry.second;
+ }
+ return ss.Release();
+}
+
+std::map<std::string, std::string> VideoCodecTestStats::FrameStatistics::ToMap()
+ const {
+ std::map<std::string, std::string> map;
+ map["frame_number"] = std::to_string(frame_number);
+ map["decoded_width"] = std::to_string(decoded_width);
+ map["decoded_height"] = std::to_string(decoded_height);
+ map["spatial_idx"] = std::to_string(spatial_idx);
+ map["temporal_idx"] = std::to_string(temporal_idx);
+ map["inter_layer_predicted"] = std::to_string(inter_layer_predicted);
+ map["non_ref_for_inter_layer_pred"] =
+ std::to_string(non_ref_for_inter_layer_pred);
+ map["frame_type"] = std::to_string(static_cast<int>(frame_type));
+ map["length_bytes"] = std::to_string(length_bytes);
+ map["qp"] = std::to_string(qp);
+ map["psnr"] = std::to_string(psnr);
+ map["psnr_y"] = std::to_string(psnr_y);
+ map["psnr_u"] = std::to_string(psnr_u);
+ map["psnr_v"] = std::to_string(psnr_v);
+ map["ssim"] = std::to_string(ssim);
+ map["encode_time_us"] = std::to_string(encode_time_us);
+ map["decode_time_us"] = std::to_string(decode_time_us);
+ map["rtp_timestamp"] = std::to_string(rtp_timestamp);
+ map["target_bitrate_kbps"] = std::to_string(target_bitrate_kbps);
+ map["target_framerate_fps"] = std::to_string(target_framerate_fps);
+ return map;
+}
+
+std::string VideoCodecTestStats::VideoStatistics::ToString(
+ std::string prefix) const {
+ rtc::StringBuilder ss;
+ for (const auto& entry : ToMap()) {
+ if (ss.size() > 0) {
+ ss << "\n";
+ }
+ ss << prefix << entry.first << ": " << entry.second;
+ }
+ return ss.Release();
+}
+
+std::map<std::string, std::string> VideoCodecTestStats::VideoStatistics::ToMap()
+ const {
+ std::map<std::string, std::string> map;
+ map["target_bitrate_kbps"] = std::to_string(target_bitrate_kbps);
+ map["input_framerate_fps"] = std::to_string(input_framerate_fps);
+ map["spatial_idx"] = std::to_string(spatial_idx);
+ map["temporal_idx"] = std::to_string(temporal_idx);
+ map["width"] = std::to_string(width);
+ map["height"] = std::to_string(height);
+ map["length_bytes"] = std::to_string(length_bytes);
+ map["bitrate_kbps"] = std::to_string(bitrate_kbps);
+ map["framerate_fps"] = std::to_string(framerate_fps);
+ map["enc_speed_fps"] = std::to_string(enc_speed_fps);
+ map["dec_speed_fps"] = std::to_string(dec_speed_fps);
+ map["avg_encode_latency_sec"] = std::to_string(avg_encode_latency_sec);
+ map["max_encode_latency_sec"] = std::to_string(max_encode_latency_sec);
+ map["avg_decode_latency_sec"] = std::to_string(avg_decode_latency_sec);
+ map["max_decode_latency_sec"] = std::to_string(max_decode_latency_sec);
+ map["avg_delay_sec"] = std::to_string(avg_delay_sec);
+ map["max_key_frame_delay_sec"] = std::to_string(max_key_frame_delay_sec);
+ map["max_delta_frame_delay_sec"] = std::to_string(max_delta_frame_delay_sec);
+ map["time_to_reach_target_bitrate_sec"] =
+ std::to_string(time_to_reach_target_bitrate_sec);
+ map["avg_bitrate_mismatch_pct"] = std::to_string(avg_bitrate_mismatch_pct);
+ map["avg_framerate_mismatch_pct"] =
+ std::to_string(avg_framerate_mismatch_pct);
+ map["avg_key_frame_size_bytes"] = std::to_string(avg_key_frame_size_bytes);
+ map["avg_delta_frame_size_bytes"] =
+ std::to_string(avg_delta_frame_size_bytes);
+ map["avg_qp"] = std::to_string(avg_qp);
+ map["avg_psnr"] = std::to_string(avg_psnr);
+ map["min_psnr"] = std::to_string(min_psnr);
+ map["avg_ssim"] = std::to_string(avg_ssim);
+ map["min_ssim"] = std::to_string(min_ssim);
+ map["num_input_frames"] = std::to_string(num_input_frames);
+ map["num_encoded_frames"] = std::to_string(num_encoded_frames);
+ map["num_decoded_frames"] = std::to_string(num_decoded_frames);
+ map["num_dropped_frames"] =
+ std::to_string(num_input_frames - num_encoded_frames);
+ map["num_key_frames"] = std::to_string(num_key_frames);
+ map["num_spatial_resizes"] = std::to_string(num_spatial_resizes);
+ map["max_nalu_size_bytes"] = std::to_string(max_nalu_size_bytes);
+ return map;
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/test/videocodec_test_stats.h b/third_party/libwebrtc/api/test/videocodec_test_stats.h
new file mode 100644
index 0000000000..12c60638db
--- /dev/null
+++ b/third_party/libwebrtc/api/test/videocodec_test_stats.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018 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 API_TEST_VIDEOCODEC_TEST_STATS_H_
+#define API_TEST_VIDEOCODEC_TEST_STATS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/units/data_rate.h"
+#include "api/units/frequency.h"
+#include "api/video/video_frame_type.h"
+
+namespace webrtc {
+namespace test {
+
+// Statistics for a sequence of processed frames. This class is not thread safe.
+class VideoCodecTestStats {
+ public:
+ // Statistics for one processed frame.
+ struct FrameStatistics {
+ FrameStatistics(size_t frame_number,
+ size_t rtp_timestamp,
+ size_t spatial_idx);
+
+ std::string ToString() const;
+
+ // Returns name -> value text map of frame statistics.
+ std::map<std::string, std::string> ToMap() const;
+
+ size_t frame_number = 0;
+ size_t rtp_timestamp = 0;
+
+ // Encoding.
+ int64_t encode_start_ns = 0;
+ int encode_return_code = 0;
+ bool encoding_successful = false;
+ size_t encode_time_us = 0;
+ size_t target_bitrate_kbps = 0;
+ double target_framerate_fps = 0.0;
+ size_t length_bytes = 0;
+ VideoFrameType frame_type = VideoFrameType::kVideoFrameDelta;
+
+ // Layering.
+ size_t spatial_idx = 0;
+ size_t temporal_idx = 0;
+ bool inter_layer_predicted = false;
+ bool non_ref_for_inter_layer_pred = true;
+
+ // H264 specific.
+ size_t max_nalu_size_bytes = 0;
+
+ // Decoding.
+ int64_t decode_start_ns = 0;
+ int decode_return_code = 0;
+ bool decoding_successful = false;
+ size_t decode_time_us = 0;
+ size_t decoded_width = 0;
+ size_t decoded_height = 0;
+
+ // Quantization.
+ int qp = -1;
+
+ // Quality.
+ bool quality_analysis_successful = false;
+ float psnr_y = 0.0f;
+ float psnr_u = 0.0f;
+ float psnr_v = 0.0f;
+ float psnr = 0.0f; // 10 * log10(255^2 / (mse_y + mse_u + mse_v)).
+ float ssim = 0.0f; // 0.8 * ssim_y + 0.1 * (ssim_u + ssim_v).
+ };
+
+ struct VideoStatistics {
+ std::string ToString(std::string prefix) const;
+
+ // Returns name -> value text map of video statistics.
+ std::map<std::string, std::string> ToMap() const;
+
+ size_t target_bitrate_kbps = 0;
+ float input_framerate_fps = 0.0f;
+
+ size_t spatial_idx = 0;
+ size_t temporal_idx = 0;
+
+ size_t width = 0;
+ size_t height = 0;
+
+ size_t length_bytes = 0;
+ size_t bitrate_kbps = 0;
+ float framerate_fps = 0;
+
+ float enc_speed_fps = 0.0f;
+ float dec_speed_fps = 0.0f;
+
+ float avg_encode_latency_sec = 0.0f;
+ float max_encode_latency_sec = 0.0f;
+ float avg_decode_latency_sec = 0.0f;
+ float max_decode_latency_sec = 0.0f;
+
+ float avg_delay_sec = 0.0f;
+ float max_key_frame_delay_sec = 0.0f;
+ float max_delta_frame_delay_sec = 0.0f;
+ float time_to_reach_target_bitrate_sec = 0.0f;
+ float avg_bitrate_mismatch_pct = 0.0f;
+ float avg_framerate_mismatch_pct = 0.0f;
+
+ float avg_key_frame_size_bytes = 0.0f;
+ float avg_delta_frame_size_bytes = 0.0f;
+ float avg_qp = 0.0f;
+
+ float avg_psnr_y = 0.0f;
+ float avg_psnr_u = 0.0f;
+ float avg_psnr_v = 0.0f;
+ float avg_psnr = 0.0f;
+ float min_psnr = 0.0f;
+ float avg_ssim = 0.0f;
+ float min_ssim = 0.0f;
+
+ size_t num_input_frames = 0;
+ size_t num_encoded_frames = 0;
+ size_t num_decoded_frames = 0;
+ size_t num_key_frames = 0;
+ size_t num_spatial_resizes = 0;
+ size_t max_nalu_size_bytes = 0;
+ };
+
+ virtual ~VideoCodecTestStats() = default;
+
+ virtual std::vector<FrameStatistics> GetFrameStatistics() const = 0;
+
+ virtual std::vector<VideoStatistics> SliceAndCalcLayerVideoStatistic(
+ size_t first_frame_num,
+ size_t last_frame_num) = 0;
+
+ virtual VideoStatistics CalcVideoStatistic(size_t first_frame,
+ size_t last_frame,
+ DataRate target_bitrate,
+ Frequency target_framerate) = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // API_TEST_VIDEOCODEC_TEST_STATS_H_