summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/system_wrappers
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/system_wrappers')
-rw-r--r--third_party/libwebrtc/system_wrappers/BUILD.gn166
-rw-r--r--third_party/libwebrtc/system_wrappers/DEPS3
-rw-r--r--third_party/libwebrtc/system_wrappers/OWNERS2
-rw-r--r--third_party/libwebrtc/system_wrappers/denormal_disabler_gn/moz.build225
-rw-r--r--third_party/libwebrtc/system_wrappers/field_trial_gn/moz.build232
-rw-r--r--third_party/libwebrtc/system_wrappers/include/clock.h84
-rw-r--r--third_party/libwebrtc/system_wrappers/include/cpu_features_wrapper.h42
-rw-r--r--third_party/libwebrtc/system_wrappers/include/cpu_info.h28
-rw-r--r--third_party/libwebrtc/system_wrappers/include/denormal_disabler.h56
-rw-r--r--third_party/libwebrtc/system_wrappers/include/field_trial.h116
-rw-r--r--third_party/libwebrtc/system_wrappers/include/metrics.h460
-rw-r--r--third_party/libwebrtc/system_wrappers/include/ntp_time.h124
-rw-r--r--third_party/libwebrtc/system_wrappers/include/rtp_to_ntp_estimator.h72
-rw-r--r--third_party/libwebrtc/system_wrappers/include/sleep.h24
-rw-r--r--third_party/libwebrtc/system_wrappers/metrics_gn/moz.build225
-rw-r--r--third_party/libwebrtc/system_wrappers/source/DEPS6
-rw-r--r--third_party/libwebrtc/system_wrappers/source/clock.cc102
-rw-r--r--third_party/libwebrtc/system_wrappers/source/clock_unittest.cc34
-rw-r--r--third_party/libwebrtc/system_wrappers/source/cpu_features.cc119
-rw-r--r--third_party/libwebrtc/system_wrappers/source/cpu_features_android.cc19
-rw-r--r--third_party/libwebrtc/system_wrappers/source/cpu_features_linux.cc97
-rw-r--r--third_party/libwebrtc/system_wrappers/source/cpu_info.cc72
-rw-r--r--third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc111
-rw-r--r--third_party/libwebrtc/system_wrappers/source/denormal_disabler_unittest.cc226
-rw-r--r--third_party/libwebrtc/system_wrappers/source/field_trial.cc186
-rw-r--r--third_party/libwebrtc/system_wrappers/source/field_trial_unittest.cc107
-rw-r--r--third_party/libwebrtc/system_wrappers/source/metrics.cc331
-rw-r--r--third_party/libwebrtc/system_wrappers/source/metrics_default_unittest.cc174
-rw-r--r--third_party/libwebrtc/system_wrappers/source/metrics_unittest.cc136
-rw-r--r--third_party/libwebrtc/system_wrappers/source/ntp_time_unittest.cc280
-rw-r--r--third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator.cc153
-rw-r--r--third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc277
-rw-r--r--third_party/libwebrtc/system_wrappers/source/sleep.cc36
-rw-r--r--third_party/libwebrtc/system_wrappers/system_wrappers_gn/moz.build250
34 files changed, 4575 insertions, 0 deletions
diff --git a/third_party/libwebrtc/system_wrappers/BUILD.gn b/third_party/libwebrtc/system_wrappers/BUILD.gn
new file mode 100644
index 0000000000..2576d4e3f3
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/BUILD.gn
@@ -0,0 +1,166 @@
+# Copyright (c) 2014 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.
+
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+import("../webrtc.gni")
+
+rtc_library("system_wrappers") {
+ visibility = [ "*" ]
+ sources = [
+ "include/clock.h",
+ "include/cpu_features_wrapper.h",
+ "include/cpu_info.h",
+ "include/ntp_time.h",
+ "include/rtp_to_ntp_estimator.h",
+ "include/sleep.h",
+ "source/clock.cc",
+ "source/cpu_features.cc",
+ "source/cpu_info.cc",
+ "source/rtp_to_ntp_estimator.cc",
+ "source/sleep.cc",
+ ]
+
+ defines = []
+ libs = []
+ deps = [
+ ":field_trial",
+ "../api:array_view",
+ "../api/units:timestamp",
+ "../modules:module_api_public",
+ "../rtc_base:checks",
+ "../rtc_base:logging",
+ "../rtc_base:safe_conversions",
+ "../rtc_base:timeutils",
+ "../rtc_base/synchronization:mutex",
+ "../rtc_base/system:arch",
+ "../rtc_base/system:rtc_export",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+
+ if (is_android) {
+ if (build_with_mozilla) {
+ include_dirs = [
+ "/config/external/nspr",
+ "/nsprpub/lib/ds",
+ "/nsprpub/pr/include",
+ ]
+ } else {
+ sources += [ "source/cpu_features_android.cc" ]
+ deps += [ "//third_party/cpu_features:ndk_compat" ]
+ }
+
+ libs += [ "log" ]
+ }
+
+ if (is_linux || is_chromeos) {
+ if (!build_with_chromium) {
+ sources += [ "source/cpu_features_linux.cc" ]
+ }
+
+ libs += [ "rt" ]
+ }
+
+ if (is_win) {
+ libs += [ "winmm.lib" ]
+
+ # Windows needs ../rtc_base due to include of
+ # webrtc/rtc_base/win32.h in source/clock.cc.
+ deps += [ "../rtc_base:win32" ]
+ }
+
+ deps += [ "../rtc_base:rtc_numerics" ]
+}
+
+rtc_library("field_trial") {
+ visibility = [ "*" ]
+ public = [ "include/field_trial.h" ]
+ sources = [ "source/field_trial.cc" ]
+ if (rtc_exclude_field_trial_default) {
+ defines = [ "WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT" ]
+ }
+ deps = [
+ "../experiments:registered_field_trials",
+ "../rtc_base:checks",
+ "../rtc_base:logging",
+ "../rtc_base:stringutils",
+ "../rtc_base/containers:flat_set",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/algorithm:container",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+rtc_library("metrics") {
+ visibility = [ "*" ]
+ public = [ "include/metrics.h" ]
+ sources = [ "source/metrics.cc" ]
+ if (rtc_exclude_metrics_default) {
+ defines = [ "WEBRTC_EXCLUDE_METRICS_DEFAULT" ]
+ }
+ deps = [
+ "../rtc_base:checks",
+ "../rtc_base:macromagic",
+ "../rtc_base:stringutils",
+ "../rtc_base/synchronization:mutex",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_library("denormal_disabler") {
+ visibility = [ "*" ]
+ public = [ "include/denormal_disabler.h" ]
+ sources = [ "source/denormal_disabler.cc" ]
+ deps = [
+ "../rtc_base:checks",
+ "../rtc_base/system:arch",
+ ]
+ if (is_clang) {
+ cflags_cc = [ "-Wno-unused-private-field" ]
+ }
+}
+
+if (rtc_include_tests && !build_with_chromium) {
+ rtc_test("system_wrappers_unittests") {
+ testonly = true
+ sources = [
+ "source/clock_unittest.cc",
+ "source/denormal_disabler_unittest.cc",
+ "source/field_trial_unittest.cc",
+ "source/metrics_default_unittest.cc",
+ "source/metrics_unittest.cc",
+ "source/ntp_time_unittest.cc",
+ "source/rtp_to_ntp_estimator_unittest.cc",
+ ]
+
+ deps = [
+ ":denormal_disabler",
+ ":field_trial",
+ ":metrics",
+ ":system_wrappers",
+ "../rtc_base:checks",
+ "../rtc_base:random",
+ "../rtc_base:stringutils",
+ "../test:rtc_expect_death",
+ "../test:test_main",
+ "../test:test_support",
+ "//testing/gtest",
+ ]
+
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_support" ]
+
+ shard_timeout = 900
+ }
+ }
+}
diff --git a/third_party/libwebrtc/system_wrappers/DEPS b/third_party/libwebrtc/system_wrappers/DEPS
new file mode 100644
index 0000000000..f1bede577d
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+]
+
diff --git a/third_party/libwebrtc/system_wrappers/OWNERS b/third_party/libwebrtc/system_wrappers/OWNERS
new file mode 100644
index 0000000000..f7bd06a0c3
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/OWNERS
@@ -0,0 +1,2 @@
+henrika@webrtc.org
+mflodman@webrtc.org
diff --git a/third_party/libwebrtc/system_wrappers/denormal_disabler_gn/moz.build b/third_party/libwebrtc/system_wrappers/denormal_disabler_gn/moz.build
new file mode 100644
index 0000000000..5a007d6343
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/denormal_disabler_gn/moz.build
@@ -0,0 +1,225 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["RTC_ENABLE_WIN_WGC"] = True
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("denormal_disabler_gn")
diff --git a/third_party/libwebrtc/system_wrappers/field_trial_gn/moz.build b/third_party/libwebrtc/system_wrappers/field_trial_gn/moz.build
new file mode 100644
index 0000000000..e23512e425
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/field_trial_gn/moz.build
@@ -0,0 +1,232 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/system_wrappers/source/field_trial.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["RTC_ENABLE_WIN_WGC"] = True
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "crypt32",
+ "iphlpapi",
+ "secur32",
+ "winmm"
+ ]
+
+if CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("field_trial_gn")
diff --git a/third_party/libwebrtc/system_wrappers/include/clock.h b/third_party/libwebrtc/system_wrappers/include/clock.h
new file mode 100644
index 0000000000..214b34c970
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/clock.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 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 SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
+#define SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
+
+#include <stdint.h>
+
+#include <atomic>
+#include <memory>
+
+#include "api/units/timestamp.h"
+#include "rtc_base/system/rtc_export.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+
+// January 1970, in NTP seconds.
+const uint32_t kNtpJan1970 = 2208988800UL;
+
+// Magic NTP fractional unit.
+const double kMagicNtpFractionalUnit = 4.294967296E+9;
+
+// A clock interface that allows reading of absolute and relative timestamps.
+class RTC_EXPORT Clock {
+ public:
+ virtual ~Clock() {}
+
+ // Return a timestamp relative to an unspecified epoch.
+ virtual Timestamp CurrentTime() = 0;
+ int64_t TimeInMilliseconds() { return CurrentTime().ms(); }
+ int64_t TimeInMicroseconds() { return CurrentTime().us(); }
+
+ // Retrieve an NTP absolute timestamp (with an epoch of Jan 1, 1900).
+ NtpTime CurrentNtpTime() { return ConvertTimestampToNtpTime(CurrentTime()); }
+ int64_t CurrentNtpInMilliseconds() { return CurrentNtpTime().ToMs(); }
+
+ // Converts between a relative timestamp returned by this clock, to NTP time.
+ virtual NtpTime ConvertTimestampToNtpTime(Timestamp timestamp) = 0;
+ int64_t ConvertTimestampToNtpTimeInMilliseconds(int64_t timestamp_ms) {
+ return ConvertTimestampToNtpTime(Timestamp::Millis(timestamp_ms)).ToMs();
+ }
+
+ // Returns an instance of the real-time system clock implementation.
+ static Clock* GetRealTimeClockRaw();
+};
+
+class SimulatedClock : public Clock {
+ public:
+ // The constructors assume an epoch of Jan 1, 1970.
+ explicit SimulatedClock(int64_t initial_time_us);
+ explicit SimulatedClock(Timestamp initial_time);
+ ~SimulatedClock() override;
+
+ // Return a timestamp with an epoch of Jan 1, 1970.
+ Timestamp CurrentTime() override;
+
+ NtpTime ConvertTimestampToNtpTime(Timestamp timestamp) override;
+
+ // Advance the simulated clock with a given number of milliseconds or
+ // microseconds.
+ void AdvanceTimeMilliseconds(int64_t milliseconds);
+ void AdvanceTimeMicroseconds(int64_t microseconds);
+ void AdvanceTime(TimeDelta delta);
+
+ private:
+ // The time is read and incremented with relaxed order. Each thread will see
+ // monotonically increasing time, and when threads post tasks or messages to
+ // one another, the synchronization done as part of the message passing should
+ // ensure that any causual chain of events on multiple threads also
+ // corresponds to monotonically increasing time.
+ std::atomic<int64_t> time_us_;
+};
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
diff --git a/third_party/libwebrtc/system_wrappers/include/cpu_features_wrapper.h b/third_party/libwebrtc/system_wrappers/include/cpu_features_wrapper.h
new file mode 100644
index 0000000000..254e2d8dda
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/cpu_features_wrapper.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011 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 SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
+#define SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
+
+#include <stdint.h>
+
+namespace webrtc {
+
+// List of features in x86.
+typedef enum { kSSE2, kSSE3, kAVX2, kFMA3 } CPUFeature;
+
+// List of features in ARM.
+enum {
+ kCPUFeatureARMv7 = (1 << 0),
+ kCPUFeatureVFPv3 = (1 << 1),
+ kCPUFeatureNEON = (1 << 2),
+ kCPUFeatureLDREXSTREX = (1 << 3)
+};
+
+// Returns true if the CPU supports the feature.
+int GetCPUInfo(CPUFeature feature);
+
+// No CPU feature is available => straight C path.
+int GetCPUInfoNoASM(CPUFeature feature);
+
+// Return the features in an ARM device.
+// It detects the features in the hardware platform, and returns supported
+// values in the above enum definition as a bitmask.
+uint64_t GetCPUFeaturesARM(void);
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
diff --git a/third_party/libwebrtc/system_wrappers/include/cpu_info.h b/third_party/libwebrtc/system_wrappers/include/cpu_info.h
new file mode 100644
index 0000000000..ab546c7214
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/cpu_info.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011 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 SYSTEM_WRAPPERS_INCLUDE_CPU_INFO_H_
+#define SYSTEM_WRAPPERS_INCLUDE_CPU_INFO_H_
+
+#include <stdint.h>
+
+namespace webrtc {
+
+class CpuInfo {
+ public:
+ static uint32_t DetectNumberOfCores();
+
+ private:
+ CpuInfo() {}
+};
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_CPU_INFO_H_
diff --git a/third_party/libwebrtc/system_wrappers/include/denormal_disabler.h b/third_party/libwebrtc/system_wrappers/include/denormal_disabler.h
new file mode 100644
index 0000000000..bd3d401327
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/denormal_disabler.h
@@ -0,0 +1,56 @@
+/*
+ * 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 SYSTEM_WRAPPERS_INCLUDE_DENORMAL_DISABLER_H_
+#define SYSTEM_WRAPPERS_INCLUDE_DENORMAL_DISABLER_H_
+
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+
+// Activates the hardware (HW) way to flush denormals (see [1]) to zero as they
+// can very seriously impact performance. At destruction time restores the
+// denormals handling state read by the ctor; hence, supports nested calls.
+// Equals a no-op if the architecture is not x86 or ARM or if the compiler is
+// not CLANG.
+// [1] https://en.wikipedia.org/wiki/Denormal_number
+//
+// Example usage:
+//
+// void Foo() {
+// DenormalDisabler d;
+// ...
+// }
+class DenormalDisabler {
+ public:
+ // Ctor. If architecture and compiler are supported, stores the HW settings
+ // for denormals, disables denormals and sets `disabling_activated_` to true.
+ // Otherwise, only sets `disabling_activated_` to false.
+ DenormalDisabler();
+ // Ctor. Same as above, but also requires `enabled` to be true to disable
+ // denormals.
+ explicit DenormalDisabler(bool enabled);
+ DenormalDisabler(const DenormalDisabler&) = delete;
+ DenormalDisabler& operator=(const DenormalDisabler&) = delete;
+ // Dtor. If `disabling_activated_` is true, restores the denormals HW settings
+ // read by the ctor before denormals were disabled. Otherwise it's a no-op.
+ ~DenormalDisabler();
+
+ // Returns true if architecture and compiler are supported.
+ static bool IsSupported();
+
+ private:
+ const int status_word_;
+ const bool disabling_activated_;
+};
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_DENORMAL_DISABLER_H_
diff --git a/third_party/libwebrtc/system_wrappers/include/field_trial.h b/third_party/libwebrtc/system_wrappers/include/field_trial.h
new file mode 100644
index 0000000000..8d0ad258c1
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/field_trial.h
@@ -0,0 +1,116 @@
+//
+// Copyright (c) 2014 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 SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_
+#define SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/containers/flat_set.h"
+
+// Field trials allow webrtc clients (such as Chrome) to turn on feature code
+// in binaries out in the field and gather information with that.
+//
+// By default WebRTC provides an implementation of field trials that can be
+// found in system_wrappers/source/field_trial.cc. If clients want to provide
+// a custom version, they will have to:
+//
+// 1. Compile WebRTC defining the preprocessor macro
+// WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT (if GN is used this can be achieved
+// by setting the GN arg rtc_exclude_field_trial_default to true).
+// 2. Provide an implementation of:
+// std::string webrtc::field_trial::FindFullName(absl::string_view trial).
+//
+// They are designed to wire up directly to chrome field trials and to speed up
+// developers by reducing the need to wire APIs to control whether a feature is
+// on/off. E.g. to experiment with a new method that could lead to a different
+// trade-off between CPU/bandwidth:
+//
+// 1 - Develop the feature with default behaviour off:
+//
+// if (FieldTrial::FindFullName("WebRTCExperimentMethod2") == "Enabled")
+// method2();
+// else
+// method1();
+//
+// 2 - Once the changes are rolled to chrome, the new code path can be
+// controlled as normal chrome field trials.
+//
+// 3 - Evaluate the new feature and clean the code paths.
+//
+// Notes:
+// - NOT every feature is a candidate to be controlled by this mechanism as
+// it may require negotiation between involved parties (e.g. SDP).
+//
+// TODO(andresp): since chrome --force-fieldtrials does not marks the trial
+// as active it does not get propagated to the renderer process. For now one
+// needs to push a config with start_active:true or run a local finch
+// server.
+//
+// TODO(andresp): find out how to get bots to run tests with trials enabled.
+
+namespace webrtc {
+namespace field_trial {
+
+// Returns the group name chosen for the named trial, or the empty string
+// if the trial does not exists.
+//
+// Note: To keep things tidy append all the trial names with WebRTC.
+std::string FindFullName(absl::string_view name);
+
+// Convenience method, returns true iff FindFullName(name) return a string that
+// starts with "Enabled".
+// TODO(tommi): Make sure all implementations support this.
+inline bool IsEnabled(absl::string_view name) {
+ return FindFullName(name).find("Enabled") == 0;
+}
+
+// Convenience method, returns true iff FindFullName(name) return a string that
+// starts with "Disabled".
+inline bool IsDisabled(absl::string_view name) {
+ return FindFullName(name).find("Disabled") == 0;
+}
+
+// Optionally initialize field trial from a string.
+// This method can be called at most once before any other call into webrtc.
+// E.g. before the peer connection factory is constructed.
+// Note: trials_string must never be destroyed.
+void InitFieldTrialsFromString(const char* trials_string);
+
+const char* GetFieldTrialString();
+
+// Validates the given field trial string.
+bool FieldTrialsStringIsValid(absl::string_view trials_string);
+
+// Merges two field trial strings.
+//
+// If a key (trial) exists twice with conflicting values (groups), the value
+// in 'second' takes precedence.
+// Shall only be called with valid FieldTrial strings.
+std::string MergeFieldTrialsStrings(absl::string_view first,
+ absl::string_view second);
+
+// This helper allows to temporary "register" a field trial within the current
+// scope. This is only useful for tests that use the global field trial string,
+// otherwise you can use `webrtc::FieldTrialsRegistry`.
+//
+// If you want to isolate changes to the global field trial string itself within
+// the current scope you should use `webrtc::test::ScopedFieldTrials`.
+class FieldTrialsAllowedInScopeForTesting {
+ public:
+ explicit FieldTrialsAllowedInScopeForTesting(flat_set<std::string> keys);
+ ~FieldTrialsAllowedInScopeForTesting();
+};
+
+} // namespace field_trial
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_
diff --git a/third_party/libwebrtc/system_wrappers/include/metrics.h b/third_party/libwebrtc/system_wrappers/include/metrics.h
new file mode 100644
index 0000000000..6e2da1b9ac
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/metrics.h
@@ -0,0 +1,460 @@
+//
+// Copyright (c) 2014 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 SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
+#define SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
+
+#include <stddef.h>
+
+#include <atomic>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/string_utils.h"
+
+#if defined(RTC_DISABLE_METRICS)
+#define RTC_METRICS_ENABLED 0
+#else
+#define RTC_METRICS_ENABLED 1
+#endif
+
+namespace webrtc {
+namespace metrics_impl {
+template <typename... Ts>
+void NoOp(const Ts&...) {}
+} // namespace metrics_impl
+} // namespace webrtc
+
+#if RTC_METRICS_ENABLED
+#define EXPECT_METRIC_EQ(val1, val2) EXPECT_EQ(val1, val2)
+#define EXPECT_METRIC_EQ_WAIT(val1, val2, timeout) \
+ EXPECT_EQ_WAIT(val1, val2, timeout)
+#define EXPECT_METRIC_GT(val1, val2) EXPECT_GT(val1, val2)
+#define EXPECT_METRIC_LE(val1, val2) EXPECT_LE(val1, val2)
+#define EXPECT_METRIC_TRUE(conditon) EXPECT_TRUE(conditon)
+#define EXPECT_METRIC_FALSE(conditon) EXPECT_FALSE(conditon)
+#define EXPECT_METRIC_THAT(value, matcher) EXPECT_THAT(value, matcher)
+#else
+#define EXPECT_METRIC_EQ(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
+#define EXPECT_METRIC_EQ_WAIT(val1, val2, timeout) \
+ webrtc::metrics_impl::NoOp(val1, val2, timeout)
+#define EXPECT_METRIC_GT(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
+#define EXPECT_METRIC_LE(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
+#define EXPECT_METRIC_TRUE(condition) \
+ webrtc::metrics_impl::NoOp(condition || true)
+#define EXPECT_METRIC_FALSE(condition) \
+ webrtc::metrics_impl::NoOp(condition && false)
+#define EXPECT_METRIC_THAT(value, matcher) \
+ webrtc::metrics_impl::NoOp(value, testing::_)
+#endif
+
+#if RTC_METRICS_ENABLED
+// Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate
+// statistics.
+//
+// Histogram for counters.
+// RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count);
+//
+// Histogram for enumerators.
+// The boundary should be above the max enumerator sample.
+// RTC_HISTOGRAM_ENUMERATION(name, sample, boundary);
+//
+//
+// The macros use the methods HistogramFactoryGetCounts,
+// HistogramFactoryGetEnumeration and HistogramAdd.
+//
+// By default WebRTC provides implementations of the aforementioned methods
+// that can be found in system_wrappers/source/metrics.cc. If clients want to
+// provide a custom version, they will have to:
+//
+// 1. Compile WebRTC defining the preprocessor macro
+// WEBRTC_EXCLUDE_METRICS_DEFAULT (if GN is used this can be achieved
+// by setting the GN arg rtc_exclude_metrics_default to true).
+// 2. Provide implementations of:
+// Histogram* webrtc::metrics::HistogramFactoryGetCounts(
+// absl::string_view name, int sample, int min, int max,
+// int bucket_count);
+// Histogram* webrtc::metrics::HistogramFactoryGetEnumeration(
+// absl::string_view name, int sample, int boundary);
+// void webrtc::metrics::HistogramAdd(
+// Histogram* histogram_pointer, absl::string_view name, int sample);
+//
+// Example usage:
+//
+// RTC_HISTOGRAM_COUNTS("WebRTC.Video.NacksSent", nacks_sent, 1, 100000, 100);
+//
+// enum Types {
+// kTypeX,
+// kTypeY,
+// kBoundary,
+// };
+//
+// RTC_HISTOGRAM_ENUMERATION("WebRTC.Types", kTypeX, kBoundary);
+//
+// NOTE: It is recommended to do the Chromium review for modifications to
+// histograms.xml before new metrics are committed to WebRTC.
+
+// Macros for adding samples to a named histogram.
+
+// Histogram for counters (exponentially spaced buckets).
+#define RTC_HISTOGRAM_COUNTS_100(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50)
+
+#define RTC_HISTOGRAM_COUNTS_200(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50)
+
+#define RTC_HISTOGRAM_COUNTS_500(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50)
+
+#define RTC_HISTOGRAM_COUNTS_1000(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_10000(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_100000(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50)
+
+#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
+ RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
+ webrtc::metrics::HistogramFactoryGetCounts( \
+ name, min, max, bucket_count))
+
+#define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count) \
+ RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
+ webrtc::metrics::HistogramFactoryGetCountsLinear( \
+ name, min, max, bucket_count))
+
+// Slow metrics: pointer to metric is acquired at each call and is not cached.
+//
+#define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100, 50)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 200, 50)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 500, 50)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 1000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 10000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \
+ RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, \
+ webrtc::metrics::HistogramFactoryGetCounts( \
+ name, min, max, bucket_count))
+
+// Histogram for percentage (evenly spaced buckets).
+#define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) \
+ RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 101)
+
+// Histogram for booleans.
+#define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) \
+ RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 2)
+
+// Histogram for enumerators (evenly spaced buckets).
+// `boundary` should be above the max enumerator sample.
+//
+// TODO(qingsi): Refactor the default implementation given by RtcHistogram,
+// which is already sparse, and remove the boundary argument from the macro.
+#define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
+ RTC_HISTOGRAM_COMMON_BLOCK_SLOW( \
+ name, sample, \
+ webrtc::metrics::SparseHistogramFactoryGetEnumeration(name, boundary))
+
+// Histogram for percentage (evenly spaced buckets).
+#define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
+ RTC_HISTOGRAM_ENUMERATION(name, sample, 101)
+
+// Histogram for booleans.
+#define RTC_HISTOGRAM_BOOLEAN(name, sample) \
+ RTC_HISTOGRAM_ENUMERATION(name, sample, 2)
+
+// Histogram for enumerators (evenly spaced buckets).
+// `boundary` should be above the max enumerator sample.
+#define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
+ RTC_HISTOGRAM_COMMON_BLOCK_SLOW( \
+ name, sample, \
+ webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
+
+// The name of the histogram should not vary.
+#define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \
+ factory_get_invocation) \
+ do { \
+ static std::atomic<webrtc::metrics::Histogram*> atomic_histogram_pointer( \
+ nullptr); \
+ webrtc::metrics::Histogram* histogram_pointer = \
+ atomic_histogram_pointer.load(std::memory_order_acquire); \
+ if (!histogram_pointer) { \
+ histogram_pointer = factory_get_invocation; \
+ webrtc::metrics::Histogram* null_histogram = nullptr; \
+ atomic_histogram_pointer.compare_exchange_strong(null_histogram, \
+ histogram_pointer); \
+ } \
+ if (histogram_pointer) { \
+ webrtc::metrics::HistogramAdd(histogram_pointer, sample); \
+ } \
+ } while (0)
+
+// The histogram is constructed/found for each call.
+// May be used for histograms with infrequent updates.`
+#define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
+ do { \
+ webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation; \
+ if (histogram_pointer) { \
+ webrtc::metrics::HistogramAdd(histogram_pointer, sample); \
+ } \
+ } while (0)
+
+// Helper macros.
+// Macros for calling a histogram with varying name (e.g. when using a metric
+// in different modes such as real-time vs screenshare). Fast, because pointer
+// is cached. `index` should be different for different names. Allowed `index`
+// values are 0, 1, and 2.
+#define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50))
+
+#define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_ENUMERATION(name, sample, boundary))
+
+#define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_PERCENTAGE(name, sample))
+
+#define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \
+ do { \
+ switch (index) { \
+ case 0: \
+ macro_invocation; \
+ break; \
+ case 1: \
+ macro_invocation; \
+ break; \
+ case 2: \
+ macro_invocation; \
+ break; \
+ default: \
+ RTC_DCHECK_NOTREACHED(); \
+ } \
+ } while (0)
+
+#else
+
+////////////////////////////////////////////////////////////////////////////////
+// This section defines no-op alternatives to the metrics macros when
+// RTC_METRICS_ENABLED is defined.
+
+#define RTC_HISTOGRAM_COUNTS_100(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_200(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_500(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_1000(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_10000(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_100000(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
+ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
+
+#define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count) \
+ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \
+ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
+
+#define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
+ webrtc::metrics_impl::NoOp(name, sample, boundary)
+
+#define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_BOOLEAN(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
+ webrtc::metrics_impl::NoOp(name, sample, boundary)
+
+#define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \
+ factory_get_invocation) \
+ webrtc::metrics_impl::NoOp(constant_name, sample, factory_get_invocation)
+
+#define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
+ webrtc::metrics_impl::NoOp(name, sample, factory_get_invocation)
+
+#define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \
+ webrtc::metrics_impl::NoOp(index, name, sample, boundary)
+
+#define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \
+ webrtc::metrics_impl::NoOp(index, name, sample, macro_invocation)
+
+#endif // RTC_METRICS_ENABLED
+
+namespace webrtc {
+namespace metrics {
+
+// Time that should have elapsed for stats that are gathered once per call.
+constexpr int kMinRunTimeInSeconds = 10;
+
+class Histogram;
+
+// Functions for getting pointer to histogram (constructs or finds the named
+// histogram).
+
+// Get histogram for counters.
+Histogram* HistogramFactoryGetCounts(absl::string_view name,
+ int min,
+ int max,
+ int bucket_count);
+
+// Get histogram for counters with linear bucket spacing.
+Histogram* HistogramFactoryGetCountsLinear(absl::string_view name,
+ int min,
+ int max,
+ int bucket_count);
+
+// Get histogram for enumerators.
+// `boundary` should be above the max enumerator sample.
+Histogram* HistogramFactoryGetEnumeration(absl::string_view name, int boundary);
+
+// Get sparse histogram for enumerators.
+// `boundary` should be above the max enumerator sample.
+Histogram* SparseHistogramFactoryGetEnumeration(absl::string_view name,
+ int boundary);
+
+// Function for adding a `sample` to a histogram.
+void HistogramAdd(Histogram* histogram_pointer, int sample);
+
+struct SampleInfo {
+ SampleInfo(absl::string_view name, int min, int max, size_t bucket_count);
+ ~SampleInfo();
+
+ const std::string name;
+ const int min;
+ const int max;
+ const size_t bucket_count;
+ std::map<int, int> samples; // <value, # of events>
+};
+
+// Enables collection of samples.
+// This method should be called before any other call into webrtc.
+void Enable();
+
+// Gets histograms and clears all samples.
+void GetAndReset(
+ std::map<std::string, std::unique_ptr<SampleInfo>, rtc::AbslStringViewCmp>*
+ histograms);
+
+// Functions below are mainly for testing.
+
+// Clears all samples.
+void Reset();
+
+// Returns the number of times the `sample` has been added to the histogram.
+int NumEvents(absl::string_view name, int sample);
+
+// Returns the total number of added samples to the histogram.
+int NumSamples(absl::string_view name);
+
+// Returns the minimum sample value (or -1 if the histogram has no samples).
+int MinSample(absl::string_view name);
+
+// Returns a map with keys the samples with at least one event and values the
+// number of events for that sample.
+std::map<int, int> Samples(absl::string_view name);
+
+} // namespace metrics
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
diff --git a/third_party/libwebrtc/system_wrappers/include/ntp_time.h b/third_party/libwebrtc/system_wrappers/include/ntp_time.h
new file mode 100644
index 0000000000..b912bc8a0c
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/ntp_time.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015 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 SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
+#define SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
+
+#include <cmath>
+#include <cstdint>
+#include <limits>
+
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+class NtpTime {
+ public:
+ static constexpr uint64_t kFractionsPerSecond = 0x100000000;
+ NtpTime() : value_(0) {}
+ explicit NtpTime(uint64_t value) : value_(value) {}
+ NtpTime(uint32_t seconds, uint32_t fractions)
+ : value_(seconds * kFractionsPerSecond + fractions) {}
+
+ NtpTime(const NtpTime&) = default;
+ NtpTime& operator=(const NtpTime&) = default;
+ explicit operator uint64_t() const { return value_; }
+
+ void Set(uint32_t seconds, uint32_t fractions) {
+ value_ = seconds * kFractionsPerSecond + fractions;
+ }
+ void Reset() { value_ = 0; }
+
+ int64_t ToMs() const {
+ static constexpr double kNtpFracPerMs = 4.294967296E6; // 2^32 / 1000.
+ const double frac_ms = static_cast<double>(fractions()) / kNtpFracPerMs;
+ return 1000 * static_cast<int64_t>(seconds()) +
+ static_cast<int64_t>(frac_ms + 0.5);
+ }
+ // NTP standard (RFC1305, section 3.1) explicitly state value 0 is invalid.
+ bool Valid() const { return value_ != 0; }
+
+ uint32_t seconds() const {
+ return rtc::dchecked_cast<uint32_t>(value_ / kFractionsPerSecond);
+ }
+ uint32_t fractions() const {
+ return rtc::dchecked_cast<uint32_t>(value_ % kFractionsPerSecond);
+ }
+
+ private:
+ uint64_t value_;
+};
+
+inline bool operator==(const NtpTime& n1, const NtpTime& n2) {
+ return static_cast<uint64_t>(n1) == static_cast<uint64_t>(n2);
+}
+inline bool operator!=(const NtpTime& n1, const NtpTime& n2) {
+ return !(n1 == n2);
+}
+
+// Converts `int64_t` milliseconds to Q32.32-formatted fixed-point seconds.
+// Performs clamping if the result overflows or underflows.
+inline int64_t Int64MsToQ32x32(int64_t milliseconds) {
+ // TODO(bugs.webrtc.org/10893): Change to use `rtc::saturated_cast` once the
+ // bug has been fixed.
+ double result =
+ std::round(milliseconds * (NtpTime::kFractionsPerSecond / 1000.0));
+
+ // Explicitly cast values to double to avoid implicit conversion warnings
+ // The conversion of the std::numeric_limits<int64_t>::max() triggers
+ // -Wimplicit-int-float-conversion warning in clang 10.0.0 without explicit
+ // cast
+ if (result <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
+ return std::numeric_limits<int64_t>::min();
+ }
+
+ if (result >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
+ return std::numeric_limits<int64_t>::max();
+ }
+
+ return rtc::dchecked_cast<int64_t>(result);
+}
+
+// Converts `int64_t` milliseconds to UQ32.32-formatted fixed-point seconds.
+// Performs clamping if the result overflows or underflows.
+inline uint64_t Int64MsToUQ32x32(int64_t milliseconds) {
+ // TODO(bugs.webrtc.org/10893): Change to use `rtc::saturated_cast` once the
+ // bug has been fixed.
+ double result =
+ std::round(milliseconds * (NtpTime::kFractionsPerSecond / 1000.0));
+
+ // Explicitly cast values to double to avoid implicit conversion warnings
+ // The conversion of the std::numeric_limits<int64_t>::max() triggers
+ // -Wimplicit-int-float-conversion warning in clang 10.0.0 without explicit
+ // cast
+ if (result <= static_cast<double>(std::numeric_limits<uint64_t>::min())) {
+ return std::numeric_limits<uint64_t>::min();
+ }
+
+ if (result >= static_cast<double>(std::numeric_limits<uint64_t>::max())) {
+ return std::numeric_limits<uint64_t>::max();
+ }
+
+ return rtc::dchecked_cast<uint64_t>(result);
+}
+
+// Converts Q32.32-formatted fixed-point seconds to `int64_t` milliseconds.
+inline int64_t Q32x32ToInt64Ms(int64_t q32x32) {
+ return rtc::dchecked_cast<int64_t>(
+ std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond)));
+}
+
+// Converts UQ32.32-formatted fixed-point seconds to `int64_t` milliseconds.
+inline int64_t UQ32x32ToInt64Ms(uint64_t q32x32) {
+ return rtc::dchecked_cast<int64_t>(
+ std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond)));
+}
+
+} // namespace webrtc
+#endif // SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
diff --git a/third_party/libwebrtc/system_wrappers/include/rtp_to_ntp_estimator.h b/third_party/libwebrtc/system_wrappers/include/rtp_to_ntp_estimator.h
new file mode 100644
index 0000000000..a5c7a157b6
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/rtp_to_ntp_estimator.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012 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 SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_
+#define SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_
+
+#include <stdint.h>
+
+#include <list>
+
+#include "absl/types/optional.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/sequence_number_unwrapper.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+
+// Converts an RTP timestamp to the NTP domain.
+// The class needs to be trained with (at least 2) RTP/NTP timestamp pairs from
+// RTCP sender reports before the convertion can be done.
+class RtpToNtpEstimator {
+ public:
+ static constexpr int kMaxInvalidSamples = 3;
+
+ RtpToNtpEstimator() = default;
+ RtpToNtpEstimator(const RtpToNtpEstimator&) = delete;
+ RtpToNtpEstimator& operator=(const RtpToNtpEstimator&) = delete;
+ ~RtpToNtpEstimator() = default;
+
+ enum UpdateResult { kInvalidMeasurement, kSameMeasurement, kNewMeasurement };
+ // Updates measurements with RTP/NTP timestamp pair from a RTCP sender report.
+ UpdateResult UpdateMeasurements(NtpTime ntp, uint32_t rtp_timestamp);
+
+ // Converts an RTP timestamp to the NTP domain.
+ // Returns invalid NtpTime (i.e. NtpTime(0)) on failure.
+ NtpTime Estimate(uint32_t rtp_timestamp) const;
+
+ // Returns estimated rtp_timestamp frequency, or 0 on failure.
+ double EstimatedFrequencyKhz() const;
+
+ private:
+ // Estimated parameters from RTP and NTP timestamp pairs in `measurements_`.
+ // Defines linear estimation: NtpTime (in units of 1s/2^32) =
+ // `Parameters::slope` * rtp_timestamp + `Parameters::offset`.
+ struct Parameters {
+ double slope;
+ double offset;
+ };
+
+ // RTP and NTP timestamp pair from a RTCP SR report.
+ struct RtcpMeasurement {
+ NtpTime ntp_time;
+ int64_t unwrapped_rtp_timestamp;
+ };
+
+ void UpdateParameters();
+
+ int consecutive_invalid_samples_ = 0;
+ std::list<RtcpMeasurement> measurements_;
+ absl::optional<Parameters> params_;
+ mutable RtpTimestampUnwrapper unwrapper_;
+};
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_
diff --git a/third_party/libwebrtc/system_wrappers/include/sleep.h b/third_party/libwebrtc/system_wrappers/include/sleep.h
new file mode 100644
index 0000000000..3bf8df219f
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/include/sleep.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+// An OS-independent sleep function.
+
+#ifndef SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
+#define SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
+
+namespace webrtc {
+
+// This function sleeps for the specified number of milliseconds.
+// It may return early if the thread is woken by some other event,
+// such as the delivery of a signal on Unix.
+void SleepMs(int msecs);
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
diff --git a/third_party/libwebrtc/system_wrappers/metrics_gn/moz.build b/third_party/libwebrtc/system_wrappers/metrics_gn/moz.build
new file mode 100644
index 0000000000..aa35ad0401
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/metrics_gn/moz.build
@@ -0,0 +1,225 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/system_wrappers/source/metrics.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["RTC_ENABLE_WIN_WGC"] = True
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("metrics_gn")
diff --git a/third_party/libwebrtc/system_wrappers/source/DEPS b/third_party/libwebrtc/system_wrappers/source/DEPS
new file mode 100644
index 0000000000..ac7f5a234f
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/DEPS
@@ -0,0 +1,6 @@
+specific_include_rules = {
+ # TODO(bugs.webrtc.org/10335): Remove rule when global string is removed.
+ "field_trial\.cc": [
+ "+experiments/registered_field_trials.h",
+ ],
+}
diff --git a/third_party/libwebrtc/system_wrappers/source/clock.cc b/third_party/libwebrtc/system_wrappers/source/clock.cc
new file mode 100644
index 0000000000..f7460b831c
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/clock.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013 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 "system_wrappers/include/clock.h"
+
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+namespace {
+
+int64_t NtpOffsetUsCalledOnce() {
+ constexpr int64_t kNtpJan1970Sec = 2208988800;
+ int64_t clock_time = rtc::TimeMicros();
+ int64_t utc_time = rtc::TimeUTCMicros();
+ return utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec;
+}
+
+NtpTime TimeMicrosToNtp(int64_t time_us) {
+ static int64_t ntp_offset_us = NtpOffsetUsCalledOnce();
+
+ int64_t time_ntp_us = time_us + ntp_offset_us;
+ RTC_DCHECK_GE(time_ntp_us, 0); // Time before year 1900 is unsupported.
+
+ // Convert seconds to uint32 through uint64 for a well-defined cast.
+ // A wrap around, which will happen in 2036, is expected for NTP time.
+ uint32_t ntp_seconds =
+ static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec);
+
+ // Scale fractions of the second to NTP resolution.
+ constexpr int64_t kNtpFractionsInSecond = 1LL << 32;
+ int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec;
+ uint32_t ntp_fractions =
+ us_fractions * kNtpFractionsInSecond / rtc::kNumMicrosecsPerSec;
+
+ return NtpTime(ntp_seconds, ntp_fractions);
+}
+
+} // namespace
+
+class RealTimeClock : public Clock {
+ public:
+ RealTimeClock() = default;
+
+ Timestamp CurrentTime() override {
+ return Timestamp::Micros(rtc::TimeMicros());
+ }
+
+ NtpTime ConvertTimestampToNtpTime(Timestamp timestamp) override {
+ return TimeMicrosToNtp(timestamp.us());
+ }
+};
+
+Clock* Clock::GetRealTimeClockRaw() {
+ static Clock* const clock = new RealTimeClock();
+ return clock;
+}
+
+SimulatedClock::SimulatedClock(int64_t initial_time_us)
+ : time_us_(initial_time_us) {}
+
+SimulatedClock::SimulatedClock(Timestamp initial_time)
+ : SimulatedClock(initial_time.us()) {}
+
+SimulatedClock::~SimulatedClock() {}
+
+Timestamp SimulatedClock::CurrentTime() {
+ return Timestamp::Micros(time_us_.load(std::memory_order_relaxed));
+}
+
+NtpTime SimulatedClock::ConvertTimestampToNtpTime(Timestamp timestamp) {
+ int64_t now_us = timestamp.us();
+ uint32_t seconds = (now_us / 1'000'000) + kNtpJan1970;
+ uint32_t fractions = static_cast<uint32_t>(
+ (now_us % 1'000'000) * kMagicNtpFractionalUnit / 1'000'000);
+ return NtpTime(seconds, fractions);
+}
+
+void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
+ AdvanceTime(TimeDelta::Millis(milliseconds));
+}
+
+void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) {
+ AdvanceTime(TimeDelta::Micros(microseconds));
+}
+
+// TODO(bugs.webrtc.org(12102): It's desirable to let a single thread own
+// advancement of the clock. We could then replace this read-modify-write
+// operation with just a thread checker. But currently, that breaks a couple of
+// tests, in particular, RepeatingTaskTest.ClockIntegration and
+// CallStatsTest.LastProcessedRtt.
+void SimulatedClock::AdvanceTime(TimeDelta delta) {
+ time_us_.fetch_add(delta.us(), std::memory_order_relaxed);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/clock_unittest.cc b/third_party/libwebrtc/system_wrappers/source/clock_unittest.cc
new file mode 100644
index 0000000000..f7b0ed7a47
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/clock_unittest.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2012 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 "system_wrappers/include/clock.h"
+
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(ClockTest, NtpTime) {
+ Clock* clock = Clock::GetRealTimeClock();
+
+ // To ensure the test runs correctly even on a heavily loaded system, do not
+ // compare the seconds/fractions and millisecond values directly. Instead,
+ // we check that the NTP time is between the "milliseconds" values returned
+ // right before and right after the call.
+ // The comparison includes 1 ms of margin to account for the rounding error in
+ // the conversion.
+ int64_t milliseconds_lower_bound = clock->CurrentNtpInMilliseconds();
+ NtpTime ntp_time = clock->CurrentNtpTime();
+ int64_t milliseconds_upper_bound = clock->CurrentNtpInMilliseconds();
+ EXPECT_GT(milliseconds_lower_bound / 1000, kNtpJan1970);
+ EXPECT_LE(milliseconds_lower_bound - 1, ntp_time.ToMs());
+ EXPECT_GE(milliseconds_upper_bound + 1, ntp_time.ToMs());
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/cpu_features.cc b/third_party/libwebrtc/system_wrappers/source/cpu_features.cc
new file mode 100644
index 0000000000..8cd701eb41
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/cpu_features.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+// Parts of this file derived from Chromium's base/cpu.cc.
+
+#include "rtc_base/system/arch.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+#include "system_wrappers/include/field_trial.h"
+
+#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER)
+#include <intrin.h>
+#endif
+
+namespace webrtc {
+
+// No CPU feature is available => straight C path.
+int GetCPUInfoNoASM(CPUFeature feature) {
+ (void)feature;
+ return 0;
+}
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+
+#if defined(WEBRTC_ENABLE_AVX2)
+// xgetbv returns the value of an Intel Extended Control Register (XCR).
+// Currently only XCR0 is defined by Intel so `xcr` should always be zero.
+static uint64_t xgetbv(uint32_t xcr) {
+#if defined(_MSC_VER)
+ return _xgetbv(xcr);
+#else
+ uint32_t eax, edx;
+
+ __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
+ return (static_cast<uint64_t>(edx) << 32) | eax;
+#endif // _MSC_VER
+}
+#endif // WEBRTC_ENABLE_AVX2
+
+#ifndef _MSC_VER
+// Intrinsic for "cpuid".
+#if defined(__pic__) && defined(__i386__)
+static inline void __cpuid(int cpu_info[4], int info_type) {
+ __asm__ volatile(
+ "mov %%ebx, %%edi\n"
+ "cpuid\n"
+ "xchg %%edi, %%ebx\n"
+ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]),
+ "=d"(cpu_info[3])
+ : "a"(info_type));
+}
+#else
+static inline void __cpuid(int cpu_info[4], int info_type) {
+ __asm__ volatile("cpuid\n"
+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
+ "=d"(cpu_info[3])
+ : "a"(info_type), "c"(0));
+}
+#endif
+#endif // _MSC_VER
+#endif // WEBRTC_ARCH_X86_FAMILY
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+// Actual feature detection for x86.
+int GetCPUInfo(CPUFeature feature) {
+ int cpu_info[4];
+ __cpuid(cpu_info, 1);
+ if (feature == kSSE2) {
+ return 0 != (cpu_info[3] & 0x04000000);
+ }
+ if (feature == kSSE3) {
+ return 0 != (cpu_info[2] & 0x00000001);
+ }
+#if defined(WEBRTC_ENABLE_AVX2)
+ if (feature == kAVX2 &&
+ !webrtc::field_trial::IsEnabled("WebRTC-Avx2SupportKillSwitch")) {
+ int cpu_info7[4];
+ __cpuid(cpu_info7, 0);
+ int num_ids = cpu_info7[0];
+ if (num_ids < 7) {
+ return 0;
+ }
+ // Interpret CPU feature information.
+ __cpuid(cpu_info7, 7);
+
+ // AVX instructions can be used when
+ // a) AVX are supported by the CPU,
+ // b) XSAVE is supported by the CPU,
+ // c) XSAVE is enabled by the kernel.
+ // Compiling with MSVC and /arch:AVX2 surprisingly generates BMI2
+ // instructions (see crbug.com/1315519).
+ return (cpu_info[2] & 0x10000000) != 0 /* AVX */ &&
+ (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
+ (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
+ (xgetbv(0) & 0x00000006) == 6 /* XSAVE enabled by kernel */ &&
+ (cpu_info7[1] & 0x00000020) != 0 /* AVX2 */ &&
+ (cpu_info7[1] & 0x00000100) != 0 /* BMI2 */;
+ }
+#endif // WEBRTC_ENABLE_AVX2
+ if (feature == kFMA3) {
+ return 0 != (cpu_info[2] & 0x00001000);
+ }
+ return 0;
+}
+#else
+// Default to straight C for other platforms.
+int GetCPUInfo(CPUFeature feature) {
+ (void)feature;
+ return 0;
+}
+#endif
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/cpu_features_android.cc b/third_party/libwebrtc/system_wrappers/source/cpu_features_android.cc
new file mode 100644
index 0000000000..95cc609b09
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/cpu_features_android.cc
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2012 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 <cpu-features.h>
+
+namespace webrtc {
+
+uint64_t GetCPUFeaturesARM(void) {
+ return android_getCpuFeatures();
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/cpu_features_linux.cc b/third_party/libwebrtc/system_wrappers/source/cpu_features_linux.cc
new file mode 100644
index 0000000000..2d79dde111
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/cpu_features_linux.cc
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include <features.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __GLIBC_PREREQ
+#define WEBRTC_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b)
+#else
+#define WEBRTC_GLIBC_PREREQ(a, b) 0
+#endif
+
+#if WEBRTC_GLIBC_PREREQ(2, 16)
+#include <sys/auxv.h>
+#else
+#include <errno.h>
+#include <fcntl.h>
+#include <link.h>
+#include <unistd.h>
+#endif
+
+#include "rtc_base/system/arch.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+
+#if defined(WEBRTC_ARCH_ARM_FAMILY)
+#include <asm/hwcap.h>
+
+namespace webrtc {
+
+uint64_t GetCPUFeaturesARM(void) {
+ uint64_t result = 0;
+ int architecture = 0;
+ uint64_t hwcap = 0;
+ const char* platform = NULL;
+#if WEBRTC_GLIBC_PREREQ(2, 16)
+ hwcap = getauxval(AT_HWCAP);
+ platform = (const char*)getauxval(AT_PLATFORM);
+#else
+ ElfW(auxv_t) auxv;
+ int fd = open("/proc/self/auxv", O_RDONLY);
+ if (fd >= 0) {
+ while (hwcap == 0 || platform == NULL) {
+ if (read(fd, &auxv, sizeof(auxv)) < (ssize_t)sizeof(auxv)) {
+ if (errno == EINTR)
+ continue;
+ break;
+ }
+ switch (auxv.a_type) {
+ case AT_HWCAP:
+ hwcap = auxv.a_un.a_val;
+ break;
+ case AT_PLATFORM:
+ platform = (const char*)auxv.a_un.a_val;
+ break;
+ }
+ }
+ close(fd);
+ }
+#endif // WEBRTC_GLIBC_PREREQ(2, 16)
+#if defined(__aarch64__)
+ (void)platform;
+ architecture = 8;
+ if ((hwcap & HWCAP_FP) != 0)
+ result |= kCPUFeatureVFPv3;
+ if ((hwcap & HWCAP_ASIMD) != 0)
+ result |= kCPUFeatureNEON;
+#else
+ if (platform != NULL) {
+ /* expect a string in the form "v6l" or "v7l", etc.
+ */
+ if (platform[0] == 'v' && '0' <= platform[1] && platform[1] <= '9' &&
+ (platform[2] == 'l' || platform[2] == 'b')) {
+ architecture = platform[1] - '0';
+ }
+ }
+ if ((hwcap & HWCAP_VFPv3) != 0)
+ result |= kCPUFeatureVFPv3;
+ if ((hwcap & HWCAP_NEON) != 0)
+ result |= kCPUFeatureNEON;
+#endif
+ if (architecture >= 7)
+ result |= kCPUFeatureARMv7;
+ if (architecture >= 6)
+ result |= kCPUFeatureLDREXSTREX;
+ return result;
+}
+
+} // namespace webrtc
+#endif // WEBRTC_ARCH_ARM_FAMILY
diff --git a/third_party/libwebrtc/system_wrappers/source/cpu_info.cc b/third_party/libwebrtc/system_wrappers/source/cpu_info.cc
new file mode 100644
index 0000000000..94aed09c48
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/cpu_info.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011 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 "system_wrappers/include/cpu_info.h"
+
+#if defined(WEBRTC_WIN)
+#include <windows.h>
+#elif defined(WEBRTC_LINUX) || defined(WEBRTC_BSD)
+#include <unistd.h>
+#elif defined(WEBRTC_MAC)
+#include <sys/sysctl.h>
+#elif defined(WEBRTC_FUCHSIA)
+#include <zircon/syscalls.h>
+#endif
+
+#include "rtc_base/logging.h"
+
+namespace internal {
+static int DetectNumberOfCores() {
+ int number_of_cores;
+
+#if defined(WEBRTC_WIN)
+ SYSTEM_INFO si;
+ GetNativeSystemInfo(&si);
+ number_of_cores = static_cast<int>(si.dwNumberOfProcessors);
+#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID) || defined(WEBRTC_BSD)
+ number_of_cores = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
+ if (number_of_cores <= 0) {
+ RTC_LOG(LS_ERROR) << "Failed to get number of cores";
+ number_of_cores = 1;
+ }
+#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
+ int name[] = {CTL_HW, HW_AVAILCPU};
+ size_t size = sizeof(number_of_cores);
+ if (0 != sysctl(name, 2, &number_of_cores, &size, NULL, 0)) {
+ RTC_LOG(LS_ERROR) << "Failed to get number of cores";
+ number_of_cores = 1;
+ }
+#elif defined(WEBRTC_FUCHSIA)
+ number_of_cores = zx_system_get_num_cpus();
+#else
+ RTC_LOG(LS_ERROR) << "No function to get number of cores";
+ number_of_cores = 1;
+#endif
+
+ RTC_LOG(LS_INFO) << "Available number of cores: " << number_of_cores;
+
+ RTC_CHECK_GT(number_of_cores, 0);
+ return number_of_cores;
+}
+} // namespace internal
+
+namespace webrtc {
+
+uint32_t CpuInfo::DetectNumberOfCores() {
+ // Statically cache the number of system cores available since if the process
+ // is running in a sandbox, we may only be able to read the value once (before
+ // the sandbox is initialized) and not thereafter.
+ // For more information see crbug.com/176522.
+ static const uint32_t logical_cpus =
+ static_cast<uint32_t>(internal::DetectNumberOfCores());
+ return logical_cpus;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc b/third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc
new file mode 100644
index 0000000000..bb9c05643c
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc
@@ -0,0 +1,111 @@
+/*
+ * 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 "system_wrappers/include/denormal_disabler.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(__clang__)
+#define WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED
+#endif
+
+#if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED) || \
+ defined(WEBRTC_ARCH_ARM_FAMILY)
+#define WEBRTC_DENORMAL_DISABLER_SUPPORTED
+#endif
+
+constexpr int kUnspecifiedStatusWord = -1;
+
+#if defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
+
+// Control register bit mask to disable denormals on the hardware.
+#if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
+// On x86 two bits are used: flush-to-zero (FTZ) and denormals-are-zero (DAZ).
+constexpr int kDenormalBitMask = 0x8040;
+#elif defined(WEBRTC_ARCH_ARM_FAMILY)
+// On ARM one bit is used: flush-to-zero (FTZ).
+constexpr int kDenormalBitMask = 1 << 24;
+#endif
+
+// Reads the relevant CPU control register and returns its value for supported
+// architectures and compilers. Otherwise returns `kUnspecifiedStatusWord`.
+int ReadStatusWord() {
+ int result = kUnspecifiedStatusWord;
+#if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
+ asm volatile("stmxcsr %0" : "=m"(result));
+#elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_32_BITS)
+ asm volatile("vmrs %[result], FPSCR" : [result] "=r"(result));
+#elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_64_BITS)
+ asm volatile("mrs %x[result], FPCR" : [result] "=r"(result));
+#endif
+ return result;
+}
+
+// Writes `status_word` in the relevant CPU control register if the architecture
+// and the compiler are supported.
+void SetStatusWord(int status_word) {
+#if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
+ asm volatile("ldmxcsr %0" : : "m"(status_word));
+#elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_32_BITS)
+ asm volatile("vmsr FPSCR, %[src]" : : [src] "r"(status_word));
+#elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_64_BITS)
+ asm volatile("msr FPCR, %x[src]" : : [src] "r"(status_word));
+#endif
+}
+
+// Returns true if the status word indicates that denormals are enabled.
+constexpr bool DenormalsEnabled(int status_word) {
+ return (status_word & kDenormalBitMask) != kDenormalBitMask;
+}
+
+#endif // defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
+
+} // namespace
+
+#if defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
+DenormalDisabler::DenormalDisabler() : DenormalDisabler(/*enabled=*/true) {}
+
+DenormalDisabler::DenormalDisabler(bool enabled)
+ : status_word_(enabled ? ReadStatusWord() : kUnspecifiedStatusWord),
+ disabling_activated_(enabled && DenormalsEnabled(status_word_)) {
+ if (disabling_activated_) {
+ RTC_DCHECK_NE(status_word_, kUnspecifiedStatusWord);
+ SetStatusWord(status_word_ | kDenormalBitMask);
+ RTC_DCHECK(!DenormalsEnabled(ReadStatusWord()));
+ }
+}
+
+bool DenormalDisabler::IsSupported() {
+ return true;
+}
+
+DenormalDisabler::~DenormalDisabler() {
+ if (disabling_activated_) {
+ RTC_DCHECK_NE(status_word_, kUnspecifiedStatusWord);
+ SetStatusWord(status_word_);
+ }
+}
+#else
+DenormalDisabler::DenormalDisabler() : DenormalDisabler(/*enabled=*/false) {}
+
+DenormalDisabler::DenormalDisabler(bool enabled)
+ : status_word_(kUnspecifiedStatusWord), disabling_activated_(false) {}
+
+bool DenormalDisabler::IsSupported() {
+ return false;
+}
+
+DenormalDisabler::~DenormalDisabler() = default;
+#endif
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/denormal_disabler_unittest.cc b/third_party/libwebrtc/system_wrappers/source/denormal_disabler_unittest.cc
new file mode 100644
index 0000000000..a2849f853f
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/denormal_disabler_unittest.cc
@@ -0,0 +1,226 @@
+/*
+ * 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 "system_wrappers/include/denormal_disabler.h"
+
+#include <cmath>
+#include <limits>
+#include <vector>
+
+#include "rtc_base/checks.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+constexpr float kSmallest = std::numeric_limits<float>::min();
+
+// Float values such that, if used as divisors of `kSmallest`, the division
+// produces a denormal or zero depending on whether denormals are enabled.
+constexpr float kDenormalDivisors[] = {123.125f, 97.0f, 32.0f, 5.0f, 1.5f};
+
+// Returns true if the result of `dividend` / `divisor` is a denormal.
+// `dividend` and `divisor` must not be denormals.
+bool DivisionIsDenormal(float dividend, float divisor) {
+ RTC_DCHECK_GE(std::fabsf(dividend), kSmallest);
+ RTC_DCHECK_GE(std::fabsf(divisor), kSmallest);
+ volatile float division = dividend / divisor;
+ return division != 0.0f && std::fabsf(division) < kSmallest;
+}
+
+} // namespace
+
+class DenormalDisablerParametrization : public ::testing::TestWithParam<bool> {
+};
+
+// Checks that +inf and -inf are not zeroed regardless of whether
+// architecture and compiler are supported.
+TEST_P(DenormalDisablerParametrization, InfNotZeroedExplicitlySetEnabled) {
+ DenormalDisabler denormal_disabler(/*enabled=*/GetParam());
+ constexpr float kMax = std::numeric_limits<float>::max();
+ for (float x : {-2.0f, 2.0f}) {
+ SCOPED_TRACE(x);
+ volatile float multiplication = kMax * x;
+ EXPECT_TRUE(std::isinf(multiplication));
+ }
+}
+
+// Checks that a NaN is not zeroed regardless of whether architecture and
+// compiler are supported.
+TEST_P(DenormalDisablerParametrization, NanNotZeroedExplicitlySetEnabled) {
+ DenormalDisabler denormal_disabler(/*enabled=*/GetParam());
+ volatile float kNan = std::sqrt(-1.0f);
+ EXPECT_TRUE(std::isnan(kNan));
+}
+
+INSTANTIATE_TEST_SUITE_P(DenormalDisabler,
+ DenormalDisablerParametrization,
+ ::testing::Values(false, true),
+ [](const ::testing::TestParamInfo<bool>& info) {
+ return info.param ? "enabled" : "disabled";
+ });
+
+// Checks that +inf and -inf are not zeroed regardless of whether
+// architecture and compiler are supported.
+TEST(DenormalDisabler, InfNotZeroed) {
+ DenormalDisabler denormal_disabler;
+ constexpr float kMax = std::numeric_limits<float>::max();
+ for (float x : {-2.0f, 2.0f}) {
+ SCOPED_TRACE(x);
+ volatile float multiplication = kMax * x;
+ EXPECT_TRUE(std::isinf(multiplication));
+ }
+}
+
+// Checks that a NaN is not zeroed regardless of whether architecture and
+// compiler are supported.
+TEST(DenormalDisabler, NanNotZeroed) {
+ DenormalDisabler denormal_disabler;
+ volatile float kNan = std::sqrt(-1.0f);
+ EXPECT_TRUE(std::isnan(kNan));
+}
+
+// Checks that denormals are not zeroed if `DenormalDisabler` is disabled and
+// architecture and compiler are supported.
+TEST(DenormalDisabler, DoNotZeroDenormalsIfDisabled) {
+ if (!DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "Unsupported platform.";
+ }
+ ASSERT_TRUE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]))
+ << "Precondition not met: denormals must be enabled.";
+ DenormalDisabler denormal_disabler(/*enabled=*/false);
+ for (float x : kDenormalDivisors) {
+ SCOPED_TRACE(x);
+ EXPECT_TRUE(DivisionIsDenormal(-kSmallest, x));
+ EXPECT_TRUE(DivisionIsDenormal(kSmallest, x));
+ }
+}
+
+// Checks that denormals are zeroed if `DenormalDisabler` is enabled if
+// architecture and compiler are supported.
+TEST(DenormalDisabler, ZeroDenormals) {
+ if (!DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "Unsupported platform.";
+ }
+ DenormalDisabler denormal_disabler;
+ for (float x : kDenormalDivisors) {
+ SCOPED_TRACE(x);
+ EXPECT_FALSE(DivisionIsDenormal(-kSmallest, x));
+ EXPECT_FALSE(DivisionIsDenormal(kSmallest, x));
+ }
+}
+
+// Checks that denormals are zeroed if `DenormalDisabler` is enabled if
+// architecture and compiler are supported.
+TEST(DenormalDisabler, ZeroDenormalsExplicitlyEnabled) {
+ if (!DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "Unsupported platform.";
+ }
+ DenormalDisabler denormal_disabler(/*enabled=*/true);
+ for (float x : kDenormalDivisors) {
+ SCOPED_TRACE(x);
+ EXPECT_FALSE(DivisionIsDenormal(-kSmallest, x));
+ EXPECT_FALSE(DivisionIsDenormal(kSmallest, x));
+ }
+}
+
+// Checks that the `DenormalDisabler` dtor re-enables denormals if previously
+// enabled and architecture and compiler are supported.
+TEST(DenormalDisabler, RestoreDenormalsEnabled) {
+ if (!DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "Unsupported platform.";
+ }
+ ASSERT_TRUE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]))
+ << "Precondition not met: denormals must be enabled.";
+ {
+ DenormalDisabler denormal_disabler;
+ ASSERT_FALSE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+ }
+ EXPECT_TRUE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+}
+
+// Checks that the `DenormalDisabler` dtor re-enables denormals if previously
+// enabled and architecture and compiler are supported.
+TEST(DenormalDisabler, RestoreDenormalsEnabledExplicitlyEnabled) {
+ if (!DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "Unsupported platform.";
+ }
+ ASSERT_TRUE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]))
+ << "Precondition not met: denormals must be enabled.";
+ {
+ DenormalDisabler denormal_disabler(/*enabled=*/true);
+ ASSERT_FALSE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+ }
+ EXPECT_TRUE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+}
+
+// Checks that the `DenormalDisabler` dtor keeps denormals disabled if
+// architecture and compiler are supported and if previously disabled - i.e.,
+// nested usage is supported.
+TEST(DenormalDisabler, ZeroDenormalsNested) {
+ if (!DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "Unsupported platform.";
+ }
+ DenormalDisabler d1;
+ ASSERT_FALSE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+ {
+ DenormalDisabler d2;
+ ASSERT_FALSE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+ }
+ EXPECT_FALSE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+}
+
+// Checks that the `DenormalDisabler` dtor keeps denormals disabled if
+// architecture and compiler are supported and if previously disabled - i.e.,
+// nested usage is supported.
+TEST(DenormalDisabler, ZeroDenormalsNestedExplicitlyEnabled) {
+ if (!DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "Unsupported platform.";
+ }
+ DenormalDisabler d1(/*enabled=*/true);
+ ASSERT_FALSE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+ {
+ DenormalDisabler d2(/*enabled=*/true);
+ ASSERT_FALSE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+ }
+ EXPECT_FALSE(DivisionIsDenormal(kSmallest, kDenormalDivisors[0]));
+}
+
+// Checks that `DenormalDisabler` does not zero denormals if architecture and
+// compiler are not supported.
+TEST(DenormalDisabler, DoNotZeroDenormalsIfUnsupported) {
+ if (DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "This test should only run on platforms without support "
+ "for DenormalDisabler.";
+ }
+ DenormalDisabler denormal_disabler;
+ for (float x : kDenormalDivisors) {
+ SCOPED_TRACE(x);
+ EXPECT_TRUE(DivisionIsDenormal(-kSmallest, x));
+ EXPECT_TRUE(DivisionIsDenormal(kSmallest, x));
+ }
+}
+
+// Checks that `DenormalDisabler` does not zero denormals if architecture and
+// compiler are not supported.
+TEST(DenormalDisabler, DoNotZeroDenormalsIfUnsupportedExplicitlyEnabled) {
+ if (DenormalDisabler::IsSupported()) {
+ GTEST_SKIP() << "This test should only run on platforms without support "
+ "for DenormalDisabler.";
+ }
+ DenormalDisabler denormal_disabler(/*enabled=*/true);
+ for (float x : kDenormalDivisors) {
+ SCOPED_TRACE(x);
+ EXPECT_TRUE(DivisionIsDenormal(-kSmallest, x));
+ EXPECT_TRUE(DivisionIsDenormal(kSmallest, x));
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/field_trial.cc b/third_party/libwebrtc/system_wrappers/source/field_trial.cc
new file mode 100644
index 0000000000..a1d21fa3ef
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/field_trial.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2014 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 "system_wrappers/include/field_trial.h"
+
+#include <stddef.h>
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "absl/algorithm/container.h"
+#include "absl/strings/string_view.h"
+#include "experiments/registered_field_trials.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/containers/flat_set.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/string_encode.h"
+
+// Simple field trial implementation, which allows client to
+// specify desired flags in InitFieldTrialsFromString.
+namespace webrtc {
+namespace field_trial {
+
+static const char* trials_init_string = NULL;
+
+namespace {
+
+constexpr char kPersistentStringSeparator = '/';
+
+flat_set<std::string>& TestKeys() {
+ static auto* test_keys = new flat_set<std::string>();
+ return *test_keys;
+}
+
+// Validates the given field trial string.
+// E.g.:
+// "WebRTC-experimentFoo/Enabled/WebRTC-experimentBar/Enabled100kbps/"
+// Assigns the process to group "Enabled" on WebRTCExperimentFoo trial
+// and to group "Enabled100kbps" on WebRTCExperimentBar.
+//
+// E.g. invalid config:
+// "WebRTC-experiment1/Enabled" (note missing / separator at the end).
+bool FieldTrialsStringIsValidInternal(const absl::string_view trials) {
+ if (trials.empty())
+ return true;
+
+ size_t next_item = 0;
+ std::map<absl::string_view, absl::string_view> field_trials;
+ while (next_item < trials.length()) {
+ size_t name_end = trials.find(kPersistentStringSeparator, next_item);
+ if (name_end == trials.npos || next_item == name_end)
+ return false;
+ size_t group_name_end =
+ trials.find(kPersistentStringSeparator, name_end + 1);
+ if (group_name_end == trials.npos || name_end + 1 == group_name_end)
+ return false;
+ absl::string_view name = trials.substr(next_item, name_end - next_item);
+ absl::string_view group_name =
+ trials.substr(name_end + 1, group_name_end - name_end - 1);
+
+ next_item = group_name_end + 1;
+
+ // Fail if duplicate with different group name.
+ if (field_trials.find(name) != field_trials.end() &&
+ field_trials.find(name)->second != group_name) {
+ return false;
+ }
+
+ field_trials[name] = group_name;
+ }
+
+ return true;
+}
+
+} // namespace
+
+bool FieldTrialsStringIsValid(absl::string_view trials_string) {
+ return FieldTrialsStringIsValidInternal(trials_string);
+}
+
+void InsertOrReplaceFieldTrialStringsInMap(
+ std::map<std::string, std::string>* fieldtrial_map,
+ const absl::string_view trials_string) {
+ if (FieldTrialsStringIsValidInternal(trials_string)) {
+ std::vector<absl::string_view> tokens = rtc::split(trials_string, '/');
+ // Skip last token which is empty due to trailing '/'.
+ for (size_t idx = 0; idx < tokens.size() - 1; idx += 2) {
+ (*fieldtrial_map)[std::string(tokens[idx])] =
+ std::string(tokens[idx + 1]);
+ }
+ } else {
+ RTC_DCHECK_NOTREACHED() << "Invalid field trials string:" << trials_string;
+ }
+}
+
+std::string MergeFieldTrialsStrings(absl::string_view first,
+ absl::string_view second) {
+ std::map<std::string, std::string> fieldtrial_map;
+ InsertOrReplaceFieldTrialStringsInMap(&fieldtrial_map, first);
+ InsertOrReplaceFieldTrialStringsInMap(&fieldtrial_map, second);
+
+ // Merge into fieldtrial string.
+ std::string merged = "";
+ for (auto const& fieldtrial : fieldtrial_map) {
+ merged += fieldtrial.first + '/' + fieldtrial.second + '/';
+ }
+ return merged;
+}
+
+#ifndef WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
+std::string FindFullName(absl::string_view name) {
+#if WEBRTC_STRICT_FIELD_TRIALS == 1
+ RTC_DCHECK(absl::c_linear_search(kRegisteredFieldTrials, name) ||
+ TestKeys().contains(name))
+ << name << " is not registered, see g3doc/field-trials.md.";
+#elif WEBRTC_STRICT_FIELD_TRIALS == 2
+ RTC_LOG_IF(LS_WARNING,
+ !(absl::c_linear_search(kRegisteredFieldTrials, name) ||
+ TestKeys().contains(name)))
+ << name << " is not registered, see g3doc/field-trials.md.";
+#endif
+
+ if (trials_init_string == NULL)
+ return std::string();
+
+ absl::string_view trials_string(trials_init_string);
+ if (trials_string.empty())
+ return std::string();
+
+ size_t next_item = 0;
+ while (next_item < trials_string.length()) {
+ // Find next name/value pair in field trial configuration string.
+ size_t field_name_end =
+ trials_string.find(kPersistentStringSeparator, next_item);
+ if (field_name_end == trials_string.npos || field_name_end == next_item)
+ break;
+ size_t field_value_end =
+ trials_string.find(kPersistentStringSeparator, field_name_end + 1);
+ if (field_value_end == trials_string.npos ||
+ field_value_end == field_name_end + 1)
+ break;
+ absl::string_view field_name =
+ trials_string.substr(next_item, field_name_end - next_item);
+ absl::string_view field_value = trials_string.substr(
+ field_name_end + 1, field_value_end - field_name_end - 1);
+ next_item = field_value_end + 1;
+
+ if (name == field_name)
+ return std::string(field_value);
+ }
+ return std::string();
+}
+#endif // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
+
+// Optionally initialize field trial from a string.
+void InitFieldTrialsFromString(const char* trials_string) {
+ RTC_LOG(LS_INFO) << "Setting field trial string:" << trials_string;
+ if (trials_string) {
+ RTC_DCHECK(FieldTrialsStringIsValidInternal(trials_string))
+ << "Invalid field trials string:" << trials_string;
+ };
+ trials_init_string = trials_string;
+}
+
+const char* GetFieldTrialString() {
+ return trials_init_string;
+}
+
+FieldTrialsAllowedInScopeForTesting::FieldTrialsAllowedInScopeForTesting(
+ flat_set<std::string> keys) {
+ TestKeys() = std::move(keys);
+}
+
+FieldTrialsAllowedInScopeForTesting::~FieldTrialsAllowedInScopeForTesting() {
+ TestKeys().clear();
+}
+
+} // namespace field_trial
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/field_trial_unittest.cc b/third_party/libwebrtc/system_wrappers/source/field_trial_unittest.cc
new file mode 100644
index 0000000000..ada6313e67
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/field_trial_unittest.cc
@@ -0,0 +1,107 @@
+/*
+ * 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 "system_wrappers/include/field_trial.h"
+
+#include "rtc_base/checks.h"
+#include "test/gtest.h"
+#include "test/testsupport/rtc_expect_death.h"
+
+namespace webrtc {
+namespace field_trial {
+#if GTEST_HAS_DEATH_TEST && RTC_DCHECK_IS_ON && !defined(WEBRTC_ANDROID) && \
+ !defined(WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT)
+TEST(FieldTrialValidationTest, AcceptsValidInputs) {
+ InitFieldTrialsFromString("");
+ InitFieldTrialsFromString("Audio/Enabled/");
+ InitFieldTrialsFromString("Audio/Enabled/Video/Disabled/");
+ EXPECT_TRUE(FieldTrialsStringIsValid(""));
+ EXPECT_TRUE(FieldTrialsStringIsValid("Audio/Enabled/"));
+ EXPECT_TRUE(FieldTrialsStringIsValid("Audio/Enabled/Video/Disabled/"));
+
+ // Duplicate trials with the same value is fine
+ InitFieldTrialsFromString("Audio/Enabled/Audio/Enabled/");
+ InitFieldTrialsFromString("Audio/Enabled/B/C/Audio/Enabled/");
+ EXPECT_TRUE(FieldTrialsStringIsValid("Audio/Enabled/Audio/Enabled/"));
+ EXPECT_TRUE(FieldTrialsStringIsValid("Audio/Enabled/B/C/Audio/Enabled/"));
+}
+
+TEST(FieldTrialValidationDeathTest, RejectsBadInputs) {
+ // Bad delimiters
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("Audio/EnabledVideo/Disabled/"),
+ "Invalid field trials string:");
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("Audio/Enabled//Video/Disabled/"),
+ "Invalid field trials string:");
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("/Audio/Enabled/Video/Disabled/"),
+ "Invalid field trials string:");
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("Audio/Enabled/Video/Disabled"),
+ "Invalid field trials string:");
+ RTC_EXPECT_DEATH(
+ InitFieldTrialsFromString("Audio/Enabled/Video/Disabled/garbage"),
+ "Invalid field trials string:");
+ EXPECT_FALSE(FieldTrialsStringIsValid("Audio/EnabledVideo/Disabled/"));
+ EXPECT_FALSE(FieldTrialsStringIsValid("Audio/Enabled//Video/Disabled/"));
+ EXPECT_FALSE(FieldTrialsStringIsValid("/Audio/Enabled/Video/Disabled/"));
+ EXPECT_FALSE(FieldTrialsStringIsValid("Audio/Enabled/Video/Disabled"));
+ EXPECT_FALSE(
+ FieldTrialsStringIsValid("Audio/Enabled/Video/Disabled/garbage"));
+
+ // Empty trial or group
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("Audio//"),
+ "Invalid field trials string:");
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("/Enabled/"),
+ "Invalid field trials string:");
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("//"),
+ "Invalid field trials string:");
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("//Enabled"),
+ "Invalid field trials string:");
+ EXPECT_FALSE(FieldTrialsStringIsValid("Audio//"));
+ EXPECT_FALSE(FieldTrialsStringIsValid("/Enabled/"));
+ EXPECT_FALSE(FieldTrialsStringIsValid("//"));
+ EXPECT_FALSE(FieldTrialsStringIsValid("//Enabled"));
+
+ // Duplicate trials with different values is not fine
+ RTC_EXPECT_DEATH(InitFieldTrialsFromString("Audio/Enabled/Audio/Disabled/"),
+ "Invalid field trials string:");
+ RTC_EXPECT_DEATH(
+ InitFieldTrialsFromString("Audio/Enabled/B/C/Audio/Disabled/"),
+ "Invalid field trials string:");
+ EXPECT_FALSE(FieldTrialsStringIsValid("Audio/Enabled/Audio/Disabled/"));
+ EXPECT_FALSE(FieldTrialsStringIsValid("Audio/Enabled/B/C/Audio/Disabled/"));
+}
+
+TEST(FieldTrialMergingTest, MergesValidInput) {
+ EXPECT_EQ(MergeFieldTrialsStrings("Video/Enabled/", "Audio/Enabled/"),
+ "Audio/Enabled/Video/Enabled/");
+ EXPECT_EQ(MergeFieldTrialsStrings("Audio/Disabled/Video/Enabled/",
+ "Audio/Enabled/"),
+ "Audio/Enabled/Video/Enabled/");
+ EXPECT_EQ(
+ MergeFieldTrialsStrings("Audio/Enabled/Video/Enabled/", "Audio/Enabled/"),
+ "Audio/Enabled/Video/Enabled/");
+ EXPECT_EQ(
+ MergeFieldTrialsStrings("Audio/Enabled/Audio/Enabled/", "Video/Enabled/"),
+ "Audio/Enabled/Video/Enabled/");
+}
+
+TEST(FieldTrialMergingDeathTest, DchecksBadInput) {
+ RTC_EXPECT_DEATH(MergeFieldTrialsStrings("Audio/Enabled/", "garbage"),
+ "Invalid field trials string:");
+}
+
+TEST(FieldTrialMergingTest, HandlesEmptyInput) {
+ EXPECT_EQ(MergeFieldTrialsStrings("", "Audio/Enabled/"), "Audio/Enabled/");
+ EXPECT_EQ(MergeFieldTrialsStrings("Audio/Enabled/", ""), "Audio/Enabled/");
+ EXPECT_EQ(MergeFieldTrialsStrings("", ""), "");
+}
+#endif // GTEST_HAS_DEATH_TEST && RTC_DCHECK_IS_ON && !defined(WEBRTC_ANDROID)
+ // && !defined(WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT)
+
+} // namespace field_trial
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/metrics.cc b/third_party/libwebrtc/system_wrappers/source/metrics.cc
new file mode 100644
index 0000000000..39ca590070
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/metrics.cc
@@ -0,0 +1,331 @@
+// Copyright (c) 2014 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 "system_wrappers/include/metrics.h"
+
+#include <algorithm>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/string_utils.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
+
+// Default implementation of histogram methods for WebRTC clients that do not
+// want to provide their own implementation.
+
+namespace webrtc {
+namespace metrics {
+class Histogram;
+
+namespace {
+// Limit for the maximum number of sample values that can be stored.
+// TODO(asapersson): Consider using bucket count (and set up
+// linearly/exponentially spaced buckets) if samples are logged more frequently.
+const int kMaxSampleMapSize = 300;
+
+class RtcHistogram {
+ public:
+ RtcHistogram(absl::string_view name, int min, int max, int bucket_count)
+ : min_(min), max_(max), info_(name, min, max, bucket_count) {
+ RTC_DCHECK_GT(bucket_count, 0);
+ }
+
+ RtcHistogram(const RtcHistogram&) = delete;
+ RtcHistogram& operator=(const RtcHistogram&) = delete;
+
+ void Add(int sample) {
+ sample = std::min(sample, max_);
+ sample = std::max(sample, min_ - 1); // Underflow bucket.
+
+ MutexLock lock(&mutex_);
+ if (info_.samples.size() == kMaxSampleMapSize &&
+ info_.samples.find(sample) == info_.samples.end()) {
+ return;
+ }
+ ++info_.samples[sample];
+ }
+
+ // Returns a copy (or nullptr if there are no samples) and clears samples.
+ std::unique_ptr<SampleInfo> GetAndReset() {
+ MutexLock lock(&mutex_);
+ if (info_.samples.empty())
+ return nullptr;
+
+ SampleInfo* copy =
+ new SampleInfo(info_.name, info_.min, info_.max, info_.bucket_count);
+
+ std::swap(info_.samples, copy->samples);
+
+ return std::unique_ptr<SampleInfo>(copy);
+ }
+
+ const std::string& name() const { return info_.name; }
+
+ // Functions only for testing.
+ void Reset() {
+ MutexLock lock(&mutex_);
+ info_.samples.clear();
+ }
+
+ int NumEvents(int sample) const {
+ MutexLock lock(&mutex_);
+ const auto it = info_.samples.find(sample);
+ return (it == info_.samples.end()) ? 0 : it->second;
+ }
+
+ int NumSamples() const {
+ int num_samples = 0;
+ MutexLock lock(&mutex_);
+ for (const auto& sample : info_.samples) {
+ num_samples += sample.second;
+ }
+ return num_samples;
+ }
+
+ int MinSample() const {
+ MutexLock lock(&mutex_);
+ return (info_.samples.empty()) ? -1 : info_.samples.begin()->first;
+ }
+
+ std::map<int, int> Samples() const {
+ MutexLock lock(&mutex_);
+ return info_.samples;
+ }
+
+ private:
+ mutable Mutex mutex_;
+ const int min_;
+ const int max_;
+ SampleInfo info_ RTC_GUARDED_BY(mutex_);
+};
+
+class RtcHistogramMap {
+ public:
+ RtcHistogramMap() {}
+ ~RtcHistogramMap() {}
+
+ RtcHistogramMap(const RtcHistogramMap&) = delete;
+ RtcHistogramMap& operator=(const RtcHistogramMap&) = delete;
+
+ Histogram* GetCountsHistogram(absl::string_view name,
+ int min,
+ int max,
+ int bucket_count) {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ if (it != map_.end())
+ return reinterpret_cast<Histogram*>(it->second.get());
+
+ RtcHistogram* hist = new RtcHistogram(name, min, max, bucket_count);
+ map_.emplace(name, hist);
+ return reinterpret_cast<Histogram*>(hist);
+ }
+
+ Histogram* GetEnumerationHistogram(absl::string_view name, int boundary) {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ if (it != map_.end())
+ return reinterpret_cast<Histogram*>(it->second.get());
+
+ RtcHistogram* hist = new RtcHistogram(name, 1, boundary, boundary + 1);
+ map_.emplace(name, hist);
+ return reinterpret_cast<Histogram*>(hist);
+ }
+
+ void GetAndReset(std::map<std::string,
+ std::unique_ptr<SampleInfo>,
+ rtc::AbslStringViewCmp>* histograms) {
+ MutexLock lock(&mutex_);
+ for (const auto& kv : map_) {
+ std::unique_ptr<SampleInfo> info = kv.second->GetAndReset();
+ if (info)
+ histograms->insert(std::make_pair(kv.first, std::move(info)));
+ }
+ }
+
+ // Functions only for testing.
+ void Reset() {
+ MutexLock lock(&mutex_);
+ for (const auto& kv : map_)
+ kv.second->Reset();
+ }
+
+ int NumEvents(absl::string_view name, int sample) const {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? 0 : it->second->NumEvents(sample);
+ }
+
+ int NumSamples(absl::string_view name) const {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? 0 : it->second->NumSamples();
+ }
+
+ int MinSample(absl::string_view name) const {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? -1 : it->second->MinSample();
+ }
+
+ std::map<int, int> Samples(absl::string_view name) const {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? std::map<int, int>() : it->second->Samples();
+ }
+
+ private:
+ mutable Mutex mutex_;
+ std::map<std::string, std::unique_ptr<RtcHistogram>, rtc::AbslStringViewCmp>
+ map_ RTC_GUARDED_BY(mutex_);
+};
+
+// RtcHistogramMap is allocated upon call to Enable().
+// The histogram getter functions, which return pointer values to the histograms
+// in the map, are cached in WebRTC. Therefore, this memory is not freed by the
+// application (the memory will be reclaimed by the OS).
+static std::atomic<RtcHistogramMap*> g_rtc_histogram_map(nullptr);
+
+void CreateMap() {
+ RtcHistogramMap* map = g_rtc_histogram_map.load(std::memory_order_acquire);
+ if (map == nullptr) {
+ RtcHistogramMap* new_map = new RtcHistogramMap();
+ if (!g_rtc_histogram_map.compare_exchange_strong(map, new_map))
+ delete new_map;
+ }
+}
+
+// Set the first time we start using histograms. Used to make sure Enable() is
+// not called thereafter.
+#if RTC_DCHECK_IS_ON
+static std::atomic<int> g_rtc_histogram_called(0);
+#endif
+
+// Gets the map (or nullptr).
+RtcHistogramMap* GetMap() {
+#if RTC_DCHECK_IS_ON
+ g_rtc_histogram_called.store(1, std::memory_order_release);
+#endif
+ return g_rtc_histogram_map.load();
+}
+} // namespace
+
+#ifndef WEBRTC_EXCLUDE_METRICS_DEFAULT
+// Implementation of histogram methods in
+// webrtc/system_wrappers/interface/metrics.h.
+
+// Histogram with exponentially spaced buckets.
+// Creates (or finds) histogram.
+// The returned histogram pointer is cached (and used for adding samples in
+// subsequent calls).
+Histogram* HistogramFactoryGetCounts(absl::string_view name,
+ int min,
+ int max,
+ int bucket_count) {
+ // TODO(asapersson): Alternative implementation will be needed if this
+ // histogram type should be truly exponential.
+ return HistogramFactoryGetCountsLinear(name, min, max, bucket_count);
+}
+
+// Histogram with linearly spaced buckets.
+// Creates (or finds) histogram.
+// The returned histogram pointer is cached (and used for adding samples in
+// subsequent calls).
+Histogram* HistogramFactoryGetCountsLinear(absl::string_view name,
+ int min,
+ int max,
+ int bucket_count) {
+ RtcHistogramMap* map = GetMap();
+ if (!map)
+ return nullptr;
+
+ return map->GetCountsHistogram(name, min, max, bucket_count);
+}
+
+// Histogram with linearly spaced buckets.
+// Creates (or finds) histogram.
+// The returned histogram pointer is cached (and used for adding samples in
+// subsequent calls).
+Histogram* HistogramFactoryGetEnumeration(absl::string_view name,
+ int boundary) {
+ RtcHistogramMap* map = GetMap();
+ if (!map)
+ return nullptr;
+
+ return map->GetEnumerationHistogram(name, boundary);
+}
+
+// Our default implementation reuses the non-sparse histogram.
+Histogram* SparseHistogramFactoryGetEnumeration(absl::string_view name,
+ int boundary) {
+ return HistogramFactoryGetEnumeration(name, boundary);
+}
+
+// Fast path. Adds `sample` to cached `histogram_pointer`.
+void HistogramAdd(Histogram* histogram_pointer, int sample) {
+ RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer);
+ ptr->Add(sample);
+}
+
+#endif // WEBRTC_EXCLUDE_METRICS_DEFAULT
+
+SampleInfo::SampleInfo(absl::string_view name,
+ int min,
+ int max,
+ size_t bucket_count)
+ : name(name), min(min), max(max), bucket_count(bucket_count) {}
+
+SampleInfo::~SampleInfo() {}
+
+// Implementation of global functions in metrics.h.
+void Enable() {
+ RTC_DCHECK(g_rtc_histogram_map.load() == nullptr);
+#if RTC_DCHECK_IS_ON
+ RTC_DCHECK_EQ(0, g_rtc_histogram_called.load(std::memory_order_acquire));
+#endif
+ CreateMap();
+}
+
+void GetAndReset(
+ std::map<std::string, std::unique_ptr<SampleInfo>, rtc::AbslStringViewCmp>*
+ histograms) {
+ histograms->clear();
+ RtcHistogramMap* map = GetMap();
+ if (map)
+ map->GetAndReset(histograms);
+}
+
+void Reset() {
+ RtcHistogramMap* map = GetMap();
+ if (map)
+ map->Reset();
+}
+
+int NumEvents(absl::string_view name, int sample) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->NumEvents(name, sample) : 0;
+}
+
+int NumSamples(absl::string_view name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->NumSamples(name) : 0;
+}
+
+int MinSample(absl::string_view name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->MinSample(name) : -1;
+}
+
+std::map<int, int> Samples(absl::string_view name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->Samples(name) : std::map<int, int>();
+}
+
+} // namespace metrics
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/metrics_default_unittest.cc b/third_party/libwebrtc/system_wrappers/source/metrics_default_unittest.cc
new file mode 100644
index 0000000000..a27e9038a3
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/metrics_default_unittest.cc
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/string_utils.h"
+#include "system_wrappers/include/metrics.h"
+#include "test/gtest.h"
+
+#if RTC_METRICS_ENABLED
+namespace webrtc {
+
+namespace {
+const int kSample = 22;
+const char kName[] = "Name";
+
+int NumSamples(absl::string_view name,
+ const std::map<std::string,
+ std::unique_ptr<metrics::SampleInfo>,
+ rtc::AbslStringViewCmp>& histograms) {
+ const auto it = histograms.find(name);
+ if (it == histograms.end())
+ return 0;
+
+ int num_samples = 0;
+ for (const auto& sample : it->second->samples)
+ num_samples += sample.second;
+
+ return num_samples;
+}
+
+int NumEvents(absl::string_view name,
+ int sample,
+ const std::map<std::string,
+ std::unique_ptr<metrics::SampleInfo>,
+ rtc::AbslStringViewCmp>& histograms) {
+ const auto it = histograms.find(name);
+ if (it == histograms.end())
+ return 0;
+
+ const auto it_sample = it->second->samples.find(sample);
+ if (it_sample == it->second->samples.end())
+ return 0;
+
+ return it_sample->second;
+}
+} // namespace
+
+class MetricsDefaultTest : public ::testing::Test {
+ public:
+ MetricsDefaultTest() {}
+
+ protected:
+ void SetUp() override { metrics::Reset(); }
+};
+
+TEST_F(MetricsDefaultTest, Reset) {
+ RTC_HISTOGRAM_PERCENTAGE(kName, kSample);
+ EXPECT_EQ(1, metrics::NumSamples(kName));
+ metrics::Reset();
+ EXPECT_EQ(0, metrics::NumSamples(kName));
+}
+
+TEST_F(MetricsDefaultTest, NumSamples) {
+ RTC_HISTOGRAM_PERCENTAGE(kName, 5);
+ RTC_HISTOGRAM_PERCENTAGE(kName, 5);
+ RTC_HISTOGRAM_PERCENTAGE(kName, 10);
+ EXPECT_EQ(3, metrics::NumSamples(kName));
+ EXPECT_EQ(0, metrics::NumSamples("NonExisting"));
+}
+
+TEST_F(MetricsDefaultTest, NumEvents) {
+ RTC_HISTOGRAM_PERCENTAGE(kName, 5);
+ RTC_HISTOGRAM_PERCENTAGE(kName, 5);
+ RTC_HISTOGRAM_PERCENTAGE(kName, 10);
+ EXPECT_EQ(2, metrics::NumEvents(kName, 5));
+ EXPECT_EQ(1, metrics::NumEvents(kName, 10));
+ EXPECT_EQ(0, metrics::NumEvents(kName, 11));
+ EXPECT_EQ(0, metrics::NumEvents("NonExisting", 5));
+}
+
+TEST_F(MetricsDefaultTest, MinSample) {
+ RTC_HISTOGRAM_PERCENTAGE(kName, kSample);
+ RTC_HISTOGRAM_PERCENTAGE(kName, kSample + 1);
+ EXPECT_EQ(kSample, metrics::MinSample(kName));
+ EXPECT_EQ(-1, metrics::MinSample("NonExisting"));
+}
+
+TEST_F(MetricsDefaultTest, Overflow) {
+ const std::string kName = "Overflow";
+ // Samples should end up in overflow bucket.
+ RTC_HISTOGRAM_PERCENTAGE(kName, 101);
+ EXPECT_EQ(1, metrics::NumSamples(kName));
+ EXPECT_EQ(1, metrics::NumEvents(kName, 101));
+ RTC_HISTOGRAM_PERCENTAGE(kName, 102);
+ EXPECT_EQ(2, metrics::NumSamples(kName));
+ EXPECT_EQ(2, metrics::NumEvents(kName, 101));
+}
+
+TEST_F(MetricsDefaultTest, Underflow) {
+ const std::string kName = "Underflow";
+ // Samples should end up in underflow bucket.
+ RTC_HISTOGRAM_COUNTS_10000(kName, 0);
+ EXPECT_EQ(1, metrics::NumSamples(kName));
+ EXPECT_EQ(1, metrics::NumEvents(kName, 0));
+ RTC_HISTOGRAM_COUNTS_10000(kName, -1);
+ EXPECT_EQ(2, metrics::NumSamples(kName));
+ EXPECT_EQ(2, metrics::NumEvents(kName, 0));
+}
+
+TEST_F(MetricsDefaultTest, GetAndReset) {
+ std::map<std::string, std::unique_ptr<metrics::SampleInfo>,
+ rtc::AbslStringViewCmp>
+ histograms;
+ metrics::GetAndReset(&histograms);
+ EXPECT_EQ(0u, histograms.size());
+ RTC_HISTOGRAM_PERCENTAGE("Histogram1", 4);
+ RTC_HISTOGRAM_PERCENTAGE("Histogram1", 5);
+ RTC_HISTOGRAM_PERCENTAGE("Histogram1", 5);
+ RTC_HISTOGRAM_PERCENTAGE("Histogram2", 10);
+ EXPECT_EQ(3, metrics::NumSamples("Histogram1"));
+ EXPECT_EQ(1, metrics::NumSamples("Histogram2"));
+
+ metrics::GetAndReset(&histograms);
+ EXPECT_EQ(2u, histograms.size());
+ EXPECT_EQ(0, metrics::NumSamples("Histogram1"));
+ EXPECT_EQ(0, metrics::NumSamples("Histogram2"));
+
+ EXPECT_EQ(3, NumSamples("Histogram1", histograms));
+ EXPECT_EQ(1, NumSamples("Histogram2", histograms));
+ EXPECT_EQ(1, NumEvents("Histogram1", 4, histograms));
+ EXPECT_EQ(2, NumEvents("Histogram1", 5, histograms));
+ EXPECT_EQ(1, NumEvents("Histogram2", 10, histograms));
+
+ // Add samples after reset.
+ metrics::GetAndReset(&histograms);
+ EXPECT_EQ(0u, histograms.size());
+ RTC_HISTOGRAM_PERCENTAGE("Histogram1", 50);
+ RTC_HISTOGRAM_PERCENTAGE("Histogram2", 8);
+ EXPECT_EQ(1, metrics::NumSamples("Histogram1"));
+ EXPECT_EQ(1, metrics::NumSamples("Histogram2"));
+ EXPECT_EQ(1, metrics::NumEvents("Histogram1", 50));
+ EXPECT_EQ(1, metrics::NumEvents("Histogram2", 8));
+}
+
+TEST_F(MetricsDefaultTest, TestMinMaxBucket) {
+ const std::string kName = "MinMaxCounts100";
+ RTC_HISTOGRAM_COUNTS_100(kName, 4);
+
+ std::map<std::string, std::unique_ptr<metrics::SampleInfo>,
+ rtc::AbslStringViewCmp>
+ histograms;
+ metrics::GetAndReset(&histograms);
+ EXPECT_EQ(1u, histograms.size());
+ EXPECT_EQ(kName, histograms.begin()->second->name);
+ EXPECT_EQ(1, histograms.begin()->second->min);
+ EXPECT_EQ(100, histograms.begin()->second->max);
+ EXPECT_EQ(50u, histograms.begin()->second->bucket_count);
+ EXPECT_EQ(1u, histograms.begin()->second->samples.size());
+}
+
+} // namespace webrtc
+#endif
diff --git a/third_party/libwebrtc/system_wrappers/source/metrics_unittest.cc b/third_party/libwebrtc/system_wrappers/source/metrics_unittest.cc
new file mode 100644
index 0000000000..cd3807748c
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/metrics_unittest.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015 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 "system_wrappers/include/metrics.h"
+
+#include "absl/strings/string_view.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+
+#if RTC_METRICS_ENABLED
+namespace webrtc {
+namespace {
+const int kSample = 22;
+
+void AddSparseSample(absl::string_view name, int sample) {
+ RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample);
+}
+void AddSampleWithVaryingName(int index, absl::string_view name, int sample) {
+ RTC_HISTOGRAMS_COUNTS_100(index, name, sample);
+}
+} // namespace
+
+class MetricsTest : public ::testing::Test {
+ public:
+ MetricsTest() {}
+
+ protected:
+ void SetUp() override { metrics::Reset(); }
+};
+
+TEST_F(MetricsTest, InitiallyNoSamples) {
+ EXPECT_EQ(0, metrics::NumSamples("NonExisting"));
+ EXPECT_EQ(0, metrics::NumEvents("NonExisting", kSample));
+ EXPECT_THAT(metrics::Samples("NonExisting"), IsEmpty());
+}
+
+TEST_F(MetricsTest, RtcHistogramPercent_AddSample) {
+ const std::string kName = "Percentage";
+ RTC_HISTOGRAM_PERCENTAGE(kName, kSample);
+ EXPECT_EQ(1, metrics::NumSamples(kName));
+ EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
+}
+
+TEST_F(MetricsTest, RtcHistogramEnumeration_AddSample) {
+ const std::string kName = "Enumeration";
+ RTC_HISTOGRAM_ENUMERATION(kName, kSample, kSample + 1);
+ EXPECT_EQ(1, metrics::NumSamples(kName));
+ EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
+}
+
+TEST_F(MetricsTest, RtcHistogramBoolean_AddSample) {
+ const std::string kName = "Boolean";
+ const int kSample = 0;
+ RTC_HISTOGRAM_BOOLEAN(kName, kSample);
+ EXPECT_EQ(1, metrics::NumSamples(kName));
+ EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
+}
+
+TEST_F(MetricsTest, RtcHistogramCountsSparse_AddSample) {
+ const std::string kName = "CountsSparse100";
+ RTC_HISTOGRAM_COUNTS_SPARSE_100(kName, kSample);
+ EXPECT_EQ(1, metrics::NumSamples(kName));
+ EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
+}
+
+TEST_F(MetricsTest, RtcHistogramCounts_AddSample) {
+ const std::string kName = "Counts100";
+ RTC_HISTOGRAM_COUNTS_100(kName, kSample);
+ EXPECT_EQ(1, metrics::NumSamples(kName));
+ EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
+}
+
+TEST_F(MetricsTest, RtcHistogramCounts_AddMultipleSamples) {
+ const std::string kName = "Counts200";
+ const int kNumSamples = 10;
+ std::map<int, int> samples;
+ for (int i = 1; i <= kNumSamples; ++i) {
+ RTC_HISTOGRAM_COUNTS_200(kName, i);
+ EXPECT_EQ(1, metrics::NumEvents(kName, i));
+ EXPECT_EQ(i, metrics::NumSamples(kName));
+ samples[i] = 1;
+ }
+ EXPECT_EQ(samples, metrics::Samples(kName));
+}
+
+TEST_F(MetricsTest, RtcHistogramsCounts_AddSample) {
+ AddSampleWithVaryingName(0, "Name1", kSample);
+ AddSampleWithVaryingName(1, "Name2", kSample + 1);
+ AddSampleWithVaryingName(2, "Name3", kSample + 2);
+ EXPECT_EQ(1, metrics::NumSamples("Name1"));
+ EXPECT_EQ(1, metrics::NumSamples("Name2"));
+ EXPECT_EQ(1, metrics::NumSamples("Name3"));
+ EXPECT_EQ(1, metrics::NumEvents("Name1", kSample + 0));
+ EXPECT_EQ(1, metrics::NumEvents("Name2", kSample + 1));
+ EXPECT_EQ(1, metrics::NumEvents("Name3", kSample + 2));
+ EXPECT_THAT(metrics::Samples("Name1"), ElementsAre(Pair(kSample + 0, 1)));
+ EXPECT_THAT(metrics::Samples("Name2"), ElementsAre(Pair(kSample + 1, 1)));
+ EXPECT_THAT(metrics::Samples("Name3"), ElementsAre(Pair(kSample + 2, 1)));
+}
+
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+using MetricsDeathTest = MetricsTest;
+TEST_F(MetricsDeathTest, RtcHistogramsCounts_InvalidIndex) {
+ EXPECT_DEATH(RTC_HISTOGRAMS_COUNTS_1000(-1, "Name", kSample), "");
+ EXPECT_DEATH(RTC_HISTOGRAMS_COUNTS_1000(3, "Name", kSample), "");
+ EXPECT_DEATH(RTC_HISTOGRAMS_COUNTS_1000(3u, "Name", kSample), "");
+}
+#endif
+
+TEST_F(MetricsTest, RtcHistogramSparse_NonConstantNameWorks) {
+ AddSparseSample("Sparse1", kSample);
+ AddSparseSample("Sparse2", kSample);
+ EXPECT_EQ(1, metrics::NumSamples("Sparse1"));
+ EXPECT_EQ(1, metrics::NumSamples("Sparse2"));
+ EXPECT_THAT(metrics::Samples("Sparse1"), ElementsAre(Pair(kSample, 1)));
+ EXPECT_THAT(metrics::Samples("Sparse2"), ElementsAre(Pair(kSample, 1)));
+}
+
+} // namespace webrtc
+#endif
diff --git a/third_party/libwebrtc/system_wrappers/source/ntp_time_unittest.cc b/third_party/libwebrtc/system_wrappers/source/ntp_time_unittest.cc
new file mode 100644
index 0000000000..0705531e37
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/ntp_time_unittest.cc
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2014 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 "system_wrappers/include/ntp_time.h"
+
+#include <random>
+
+#include "system_wrappers/include/clock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+constexpr uint32_t kNtpSec = 0x12345678;
+constexpr uint32_t kNtpFrac = 0x23456789;
+
+constexpr int64_t kOneSecQ32x32 = uint64_t{1} << 32;
+constexpr int64_t kOneMsQ32x32 = 4294967;
+
+TEST(NtpTimeTest, NoValueMeansInvalid) {
+ NtpTime ntp;
+ EXPECT_FALSE(ntp.Valid());
+}
+
+TEST(NtpTimeTest, CanResetValue) {
+ NtpTime ntp(kNtpSec, kNtpFrac);
+ EXPECT_TRUE(ntp.Valid());
+ ntp.Reset();
+ EXPECT_FALSE(ntp.Valid());
+}
+
+TEST(NtpTimeTest, CanGetWhatIsSet) {
+ NtpTime ntp;
+ ntp.Set(kNtpSec, kNtpFrac);
+ EXPECT_EQ(kNtpSec, ntp.seconds());
+ EXPECT_EQ(kNtpFrac, ntp.fractions());
+}
+
+TEST(NtpTimeTest, SetIsSameAs2ParameterConstructor) {
+ NtpTime ntp1(kNtpSec, kNtpFrac);
+ NtpTime ntp2;
+ EXPECT_NE(ntp1, ntp2);
+
+ ntp2.Set(kNtpSec, kNtpFrac);
+ EXPECT_EQ(ntp1, ntp2);
+}
+
+TEST(NtpTimeTest, ToMsMeansToNtpMilliseconds) {
+ SimulatedClock clock(0x123456789abc);
+
+ NtpTime ntp = clock.CurrentNtpTime();
+ EXPECT_EQ(ntp.ToMs(), clock.CurrentNtpInMilliseconds());
+}
+
+TEST(NtpTimeTest, CanExplicitlyConvertToAndFromUint64) {
+ uint64_t untyped_time = 0x123456789;
+ NtpTime time(untyped_time);
+ EXPECT_EQ(untyped_time, static_cast<uint64_t>(time));
+ EXPECT_EQ(NtpTime(0x12345678, 0x90abcdef), NtpTime(0x1234567890abcdef));
+}
+
+TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearZero) {
+ // Zero
+ EXPECT_EQ(Int64MsToQ32x32(0), 0);
+
+ // Zero + 1 millisecond
+ EXPECT_EQ(Int64MsToQ32x32(1), kOneMsQ32x32);
+
+ // Zero - 1 millisecond
+ EXPECT_EQ(Int64MsToQ32x32(-1), -kOneMsQ32x32);
+
+ // Zero + 1 second
+ EXPECT_EQ(Int64MsToQ32x32(1000), kOneSecQ32x32);
+
+ // Zero - 1 second
+ EXPECT_EQ(Int64MsToQ32x32(-1000), -kOneSecQ32x32);
+}
+
+TEST(NtpTimeTest, VerifyInt64MsToUQ32x32NearZero) {
+ // Zero
+ EXPECT_EQ(Int64MsToUQ32x32(0), uint64_t{0});
+
+ // Zero + 1 millisecond
+ EXPECT_EQ(Int64MsToUQ32x32(1), uint64_t{kOneMsQ32x32});
+
+ // Zero - 1 millisecond
+ EXPECT_EQ(Int64MsToUQ32x32(-1), uint64_t{0}); // Clamped
+
+ // Zero + 1 second
+ EXPECT_EQ(Int64MsToUQ32x32(1000), uint64_t{kOneSecQ32x32});
+
+ // Zero - 1 second
+ EXPECT_EQ(Int64MsToUQ32x32(-1000), uint64_t{0}); // Clamped
+}
+
+TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearZero) {
+ // Zero
+ EXPECT_EQ(Q32x32ToInt64Ms(0), 0);
+
+ // Zero + 1 millisecond
+ EXPECT_EQ(Q32x32ToInt64Ms(kOneMsQ32x32), 1);
+
+ // Zero - 1 millisecond
+ EXPECT_EQ(Q32x32ToInt64Ms(-kOneMsQ32x32), -1);
+
+ // Zero + 1 second
+ EXPECT_EQ(Q32x32ToInt64Ms(kOneSecQ32x32), 1000);
+
+ // Zero - 1 second
+ EXPECT_EQ(Q32x32ToInt64Ms(-kOneSecQ32x32), -1000);
+}
+
+TEST(NtpTimeTest, VerifyUQ32x32ToInt64MsNearZero) {
+ // Zero
+ EXPECT_EQ(UQ32x32ToInt64Ms(0), 0);
+
+ // Zero + 1 millisecond
+ EXPECT_EQ(UQ32x32ToInt64Ms(kOneMsQ32x32), 1);
+
+ // Zero + 1 second
+ EXPECT_EQ(UQ32x32ToInt64Ms(kOneSecQ32x32), 1000);
+}
+
+TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearMax) {
+ constexpr int64_t kMaxQ32x32 = std::numeric_limits<int64_t>::max();
+ constexpr int64_t kBoundaryMs = (kMaxQ32x32 >> 32) * 1000 + 999;
+
+ // Max
+ const int64_t boundary_q32x32 = Int64MsToQ32x32(kBoundaryMs);
+ EXPECT_LE(boundary_q32x32, kMaxQ32x32);
+ EXPECT_GT(boundary_q32x32, kMaxQ32x32 - kOneMsQ32x32);
+
+ // Max + 1 millisecond
+ EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1), kMaxQ32x32); // Clamped
+
+ // Max - 1 millisecond
+ EXPECT_LE(Int64MsToQ32x32(kBoundaryMs - 1), kMaxQ32x32 - kOneMsQ32x32);
+
+ // Max + 1 second
+ EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1000), kMaxQ32x32); // Clamped
+
+ // Max - 1 second
+ EXPECT_LE(Int64MsToQ32x32(kBoundaryMs - 1000), kMaxQ32x32 - kOneSecQ32x32);
+}
+
+TEST(NtpTimeTest, VerifyInt64MsToUQ32x32NearMax) {
+ constexpr uint64_t kMaxUQ32x32 = std::numeric_limits<uint64_t>::max();
+ constexpr int64_t kBoundaryMs = (kMaxUQ32x32 >> 32) * 1000 + 999;
+
+ // Max
+ const uint64_t boundary_uq32x32 = Int64MsToUQ32x32(kBoundaryMs);
+ EXPECT_LE(boundary_uq32x32, kMaxUQ32x32);
+ EXPECT_GT(boundary_uq32x32, kMaxUQ32x32 - kOneMsQ32x32);
+
+ // Max + 1 millisecond
+ EXPECT_EQ(Int64MsToUQ32x32(kBoundaryMs + 1), kMaxUQ32x32); // Clamped
+
+ // Max - 1 millisecond
+ EXPECT_LE(Int64MsToUQ32x32(kBoundaryMs - 1), kMaxUQ32x32 - kOneMsQ32x32);
+
+ // Max + 1 second
+ EXPECT_EQ(Int64MsToUQ32x32(kBoundaryMs + 1000), kMaxUQ32x32); // Clamped
+
+ // Max - 1 second
+ EXPECT_LE(Int64MsToUQ32x32(kBoundaryMs - 1000), kMaxUQ32x32 - kOneSecQ32x32);
+}
+
+TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearMax) {
+ constexpr int64_t kMaxQ32x32 = std::numeric_limits<int64_t>::max();
+ constexpr int64_t kBoundaryMs = (kMaxQ32x32 >> 32) * 1000 + 1000;
+
+ // Max
+ EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32), kBoundaryMs);
+
+ // Max - 1 millisecond
+ EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32 - kOneMsQ32x32), kBoundaryMs - 1);
+
+ // Max - 1 second
+ EXPECT_EQ(Q32x32ToInt64Ms(kMaxQ32x32 - kOneSecQ32x32), kBoundaryMs - 1000);
+}
+
+TEST(NtpTimeTest, VerifyUQ32x32ToInt64MsNearMax) {
+ constexpr uint64_t kMaxUQ32x32 = std::numeric_limits<uint64_t>::max();
+ constexpr int64_t kBoundaryMs = (kMaxUQ32x32 >> 32) * 1000 + 1000;
+
+ // Max
+ EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32), kBoundaryMs);
+
+ // Max - 1 millisecond
+ EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32 - kOneMsQ32x32), kBoundaryMs - 1);
+
+ // Max - 1 second
+ EXPECT_EQ(UQ32x32ToInt64Ms(kMaxUQ32x32 - kOneSecQ32x32), kBoundaryMs - 1000);
+}
+
+TEST(NtpTimeTest, VerifyInt64MsToQ32x32NearMin) {
+ constexpr int64_t kBoundaryQ32x32 = 0x8000000000000000;
+ constexpr int64_t kBoundaryMs = -int64_t{0x80000000} * 1000;
+
+ // Min
+ EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs), kBoundaryQ32x32);
+
+ // Min + 1 millisecond
+ EXPECT_EQ(Q32x32ToInt64Ms(Int64MsToQ32x32(kBoundaryMs + 1)), kBoundaryMs + 1);
+
+ // Min - 1 millisecond
+ EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs - 1), kBoundaryQ32x32); // Clamped
+
+ // Min + 1 second
+ EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs + 1000),
+ kBoundaryQ32x32 + kOneSecQ32x32);
+
+ // Min - 1 second
+ EXPECT_EQ(Int64MsToQ32x32(kBoundaryMs - 1000), kBoundaryQ32x32); // Clamped
+}
+
+TEST(NtpTimeTest, VerifyQ32x32ToInt64MsNearMin) {
+ constexpr int64_t kBoundaryQ32x32 = 0x8000000000000000;
+ constexpr int64_t kBoundaryMs = -int64_t{0x80000000} * 1000;
+
+ // Min
+ EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32), kBoundaryMs);
+
+ // Min + 1 millisecond
+ EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32 + kOneMsQ32x32), kBoundaryMs + 1);
+
+ // Min + 1 second
+ EXPECT_EQ(Q32x32ToInt64Ms(kBoundaryQ32x32 + kOneSecQ32x32),
+ kBoundaryMs + 1000);
+}
+
+TEST(NtpTimeTest, VerifyInt64MsToQ32x32RoundTrip) {
+ constexpr int kIterations = 50000;
+
+ std::mt19937 generator(123456789);
+ std::uniform_int_distribution<int64_t> distribution(
+ Q32x32ToInt64Ms(std::numeric_limits<int64_t>::min()),
+ Q32x32ToInt64Ms(std::numeric_limits<int64_t>::max()));
+
+ for (int iteration = 0; iteration < kIterations; ++iteration) {
+ int64_t input_ms = distribution(generator);
+ int64_t transit_q32x32 = Int64MsToQ32x32(input_ms);
+ int64_t output_ms = Q32x32ToInt64Ms(transit_q32x32);
+
+ ASSERT_EQ(input_ms, output_ms)
+ << "iteration = " << iteration << ", input_ms = " << input_ms
+ << ", transit_q32x32 = " << transit_q32x32
+ << ", output_ms = " << output_ms;
+ }
+}
+
+TEST(NtpTimeTest, VerifyInt64MsToUQ32x32RoundTrip) {
+ constexpr int kIterations = 50000;
+
+ std::mt19937 generator(123456789);
+ std::uniform_int_distribution<uint64_t> distribution(
+ UQ32x32ToInt64Ms(std::numeric_limits<uint64_t>::min()),
+ UQ32x32ToInt64Ms(std::numeric_limits<uint64_t>::max()));
+
+ for (int iteration = 0; iteration < kIterations; ++iteration) {
+ uint64_t input_ms = distribution(generator);
+ uint64_t transit_uq32x32 = Int64MsToUQ32x32(input_ms);
+ uint64_t output_ms = UQ32x32ToInt64Ms(transit_uq32x32);
+
+ ASSERT_EQ(input_ms, output_ms)
+ << "iteration = " << iteration << ", input_ms = " << input_ms
+ << ", transit_uq32x32 = " << transit_uq32x32
+ << ", output_ms = " << output_ms;
+ }
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator.cc b/third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator.cc
new file mode 100644
index 0000000000..ef5d9a7508
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator.cc
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2012 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 "system_wrappers/include/rtp_to_ntp_estimator.h"
+
+#include <stddef.h>
+
+#include <cmath>
+#include <vector>
+
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace {
+// Maximum number of RTCP SR reports to use to map between RTP and NTP.
+constexpr size_t kNumRtcpReportsToUse = 20;
+// Don't allow NTP timestamps to jump more than 1 hour. Chosen arbitrary as big
+// enough to not affect normal use-cases. Yet it is smaller than RTP wrap-around
+// half-period (90khz RTP clock wrap-arounds every 13.25 hours). After half of
+// wrap-around period it is impossible to unwrap RTP timestamps correctly.
+constexpr uint64_t kMaxAllowedRtcpNtpInterval = uint64_t{60 * 60} << 32;
+} // namespace
+
+void RtpToNtpEstimator::UpdateParameters() {
+ size_t n = measurements_.size();
+ if (n < 2)
+ return;
+
+ // Run linear regression:
+ // Given x[] and y[] writes out such k and b that line y=k*x+b approximates
+ // given points in the best way (Least Squares Method).
+ auto x = [](const RtcpMeasurement& m) {
+ return static_cast<double>(m.unwrapped_rtp_timestamp);
+ };
+ auto y = [](const RtcpMeasurement& m) {
+ return static_cast<double>(static_cast<uint64_t>(m.ntp_time));
+ };
+
+ double avg_x = 0;
+ double avg_y = 0;
+ for (const RtcpMeasurement& m : measurements_) {
+ avg_x += x(m);
+ avg_y += y(m);
+ }
+ avg_x /= n;
+ avg_y /= n;
+
+ double variance_x = 0;
+ double covariance_xy = 0;
+ for (const RtcpMeasurement& m : measurements_) {
+ double normalized_x = x(m) - avg_x;
+ double normalized_y = y(m) - avg_y;
+ variance_x += normalized_x * normalized_x;
+ covariance_xy += normalized_x * normalized_y;
+ }
+
+ if (std::fabs(variance_x) < 1e-8)
+ return;
+
+ double k = covariance_xy / variance_x;
+ double b = avg_y - k * avg_x;
+ params_ = {{.slope = k, .offset = b}};
+}
+
+RtpToNtpEstimator::UpdateResult RtpToNtpEstimator::UpdateMeasurements(
+ NtpTime ntp,
+ uint32_t rtp_timestamp) {
+ int64_t unwrapped_rtp_timestamp = unwrapper_.Unwrap(rtp_timestamp);
+
+ RtcpMeasurement new_measurement = {
+ .ntp_time = ntp, .unwrapped_rtp_timestamp = unwrapped_rtp_timestamp};
+
+ for (const RtcpMeasurement& measurement : measurements_) {
+ // Use || since two equal timestamps will result in zero frequency.
+ if (measurement.ntp_time == ntp ||
+ measurement.unwrapped_rtp_timestamp == unwrapped_rtp_timestamp) {
+ return kSameMeasurement;
+ }
+ }
+
+ if (!new_measurement.ntp_time.Valid())
+ return kInvalidMeasurement;
+
+ uint64_t ntp_new = static_cast<uint64_t>(new_measurement.ntp_time);
+ bool invalid_sample = false;
+ if (!measurements_.empty()) {
+ int64_t old_rtp_timestamp = measurements_.front().unwrapped_rtp_timestamp;
+ uint64_t old_ntp = static_cast<uint64_t>(measurements_.front().ntp_time);
+ if (ntp_new <= old_ntp || ntp_new > old_ntp + kMaxAllowedRtcpNtpInterval) {
+ invalid_sample = true;
+ } else if (unwrapped_rtp_timestamp <= old_rtp_timestamp) {
+ RTC_LOG(LS_WARNING)
+ << "Newer RTCP SR report with older RTP timestamp, dropping";
+ invalid_sample = true;
+ } else if (unwrapped_rtp_timestamp - old_rtp_timestamp > (1 << 25)) {
+ // Sanity check. No jumps too far into the future in rtp.
+ invalid_sample = true;
+ }
+ }
+
+ if (invalid_sample) {
+ ++consecutive_invalid_samples_;
+ if (consecutive_invalid_samples_ < kMaxInvalidSamples) {
+ return kInvalidMeasurement;
+ }
+ RTC_LOG(LS_WARNING) << "Multiple consecutively invalid RTCP SR reports, "
+ "clearing measurements.";
+ measurements_.clear();
+ params_ = absl::nullopt;
+ }
+ consecutive_invalid_samples_ = 0;
+
+ // Insert new RTCP SR report.
+ if (measurements_.size() == kNumRtcpReportsToUse)
+ measurements_.pop_back();
+
+ measurements_.push_front(new_measurement);
+
+ // List updated, calculate new parameters.
+ UpdateParameters();
+ return kNewMeasurement;
+}
+
+NtpTime RtpToNtpEstimator::Estimate(uint32_t rtp_timestamp) const {
+ if (!params_)
+ return NtpTime();
+
+ double estimated =
+ static_cast<double>(unwrapper_.Unwrap(rtp_timestamp)) * params_->slope +
+ params_->offset + 0.5f;
+
+ return NtpTime(rtc::saturated_cast<uint64_t>(estimated));
+}
+
+double RtpToNtpEstimator::EstimatedFrequencyKhz() const {
+ if (!params_.has_value()) {
+ return 0.0;
+ }
+ static constexpr double kNtpUnitPerMs = 4.294967296E6; // 2^32 / 1000.
+ return kNtpUnitPerMs / params_->slope;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc b/third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
new file mode 100644
index 0000000000..81effd9452
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2012 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 "system_wrappers/include/rtp_to_ntp_estimator.h"
+
+#include <stddef.h>
+
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+constexpr uint64_t kOneMsInNtp = 4294967;
+constexpr uint64_t kOneHourInNtp = uint64_t{60 * 60} << 32;
+constexpr uint32_t kTimestampTicksPerMs = 90;
+} // namespace
+
+TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp) {
+ RtpToNtpEstimator estimator;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(kOneMsInNtp), 0),
+ RtpToNtpEstimator::kNewMeasurement);
+ // No wraparound will be detected, since we are not allowed to wrap below 0,
+ // but there will be huge rtp timestamp jump, e.g. old_timestamp = 0,
+ // new_timestamp = 4294967295, which should be detected.
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2 * kOneMsInNtp),
+ -kTimestampTicksPerMs),
+ RtpToNtpEstimator::kInvalidMeasurement);
+}
+
+TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp_Wraparound_Detected) {
+ RtpToNtpEstimator estimator;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFE),
+ RtpToNtpEstimator::kNewMeasurement);
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + 2 * kOneMsInNtp),
+ 0xFFFFFFFE + 2 * kTimestampTicksPerMs),
+ RtpToNtpEstimator::kNewMeasurement);
+ // Expected to fail since the older RTCP has a smaller RTP timestamp than the
+ // newer (old:10, new:4294967206).
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + 3 * kOneMsInNtp),
+ 0xFFFFFFFE + kTimestampTicksPerMs),
+ RtpToNtpEstimator::kInvalidMeasurement);
+}
+
+TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp_NegativeWraparound) {
+ RtpToNtpEstimator estimator;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0),
+ RtpToNtpEstimator::kNewMeasurement);
+ // Expected to fail since the older RTCP has a smaller RTP timestamp than the
+ // newer (old:0, new:-180).
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + 2 * kOneMsInNtp),
+ 0xFFFFFFFF - 2 * kTimestampTicksPerMs),
+ RtpToNtpEstimator::kInvalidMeasurement);
+}
+
+TEST(WrapAroundTests, NewRtcpWrapped) {
+ RtpToNtpEstimator estimator;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFF),
+ RtpToNtpEstimator::kNewMeasurement);
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
+ 0xFFFFFFFF + kTimestampTicksPerMs),
+ RtpToNtpEstimator::kNewMeasurement);
+ // Since this RTP packet has the same timestamp as the RTCP packet constructed
+ // at time 0 it should be mapped to 0 as well.
+ EXPECT_EQ(estimator.Estimate(0xFFFFFFFF), NtpTime(1));
+}
+
+TEST(WrapAroundTests, RtpWrapped) {
+ RtpToNtpEstimator estimator;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1),
+ 0xFFFFFFFF - 2 * kTimestampTicksPerMs),
+ RtpToNtpEstimator::kNewMeasurement);
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
+ 0xFFFFFFFF - kTimestampTicksPerMs),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ // Since this RTP packet has the same timestamp as the RTCP packet constructed
+ // at time 0 it should be mapped to 0 as well.
+ EXPECT_EQ(estimator.Estimate(0xFFFFFFFF - 2 * kTimestampTicksPerMs),
+ NtpTime(1));
+ // Two kTimestampTicksPerMs advanced.
+ EXPECT_EQ(estimator.Estimate(0xFFFFFFFF), NtpTime(1 + 2 * kOneMsInNtp));
+ // Wrapped rtp.
+ EXPECT_EQ(estimator.Estimate(0xFFFFFFFF + kTimestampTicksPerMs),
+ NtpTime(1 + 3 * kOneMsInNtp));
+}
+
+TEST(WrapAroundTests, OldRtp_RtcpsWrapped) {
+ RtpToNtpEstimator estimator;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFF),
+ RtpToNtpEstimator::kNewMeasurement);
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
+ 0xFFFFFFFF + kTimestampTicksPerMs),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ EXPECT_FALSE(estimator.Estimate(0xFFFFFFFF - kTimestampTicksPerMs).Valid());
+}
+
+TEST(WrapAroundTests, OldRtp_NewRtcpWrapped) {
+ RtpToNtpEstimator estimator;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFF),
+ RtpToNtpEstimator::kNewMeasurement);
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
+ 0xFFFFFFFF + kTimestampTicksPerMs),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ // Constructed at the same time as the first RTCP and should therefore be
+ // mapped to zero.
+ EXPECT_EQ(estimator.Estimate(0xFFFFFFFF), NtpTime(1));
+}
+
+TEST(WrapAroundTests, GracefullyHandleRtpJump) {
+ RtpToNtpEstimator estimator;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFF),
+ RtpToNtpEstimator::kNewMeasurement);
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
+ 0xFFFFFFFF + kTimestampTicksPerMs),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ // Constructed at the same time as the first RTCP and should therefore be
+ // mapped to zero.
+ EXPECT_EQ(estimator.Estimate(0xFFFFFFFF), NtpTime(1));
+
+ uint32_t timestamp = 0xFFFFFFFF - 0xFFFFF;
+ uint64_t ntp_raw = 1 + 2 * kOneMsInNtp;
+ for (int i = 0; i < RtpToNtpEstimator::kMaxInvalidSamples - 1; ++i) {
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
+ RtpToNtpEstimator::kInvalidMeasurement);
+ ntp_raw += kOneMsInNtp;
+ timestamp += kTimestampTicksPerMs;
+ }
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+ ntp_raw += kOneMsInNtp;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ EXPECT_EQ(estimator.Estimate(timestamp), NtpTime(ntp_raw));
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForZeroNtp) {
+ RtpToNtpEstimator estimator;
+
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(0), 0x12345678),
+ RtpToNtpEstimator::kInvalidMeasurement);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForEqualNtp) {
+ RtpToNtpEstimator estimator;
+ NtpTime ntp(0, 699925050);
+ uint32_t timestamp = 0x12345678;
+
+ EXPECT_EQ(estimator.UpdateMeasurements(ntp, timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+ // Ntp time already added, list not updated.
+ EXPECT_EQ(estimator.UpdateMeasurements(ntp, timestamp + 1),
+ RtpToNtpEstimator::kSameMeasurement);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForOldNtp) {
+ RtpToNtpEstimator estimator;
+ uint64_t ntp_raw = 699925050;
+ NtpTime ntp(ntp_raw);
+ uint32_t timestamp = 0x12345678;
+ EXPECT_EQ(estimator.UpdateMeasurements(ntp, timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ // Old ntp time, list not updated.
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw - kOneMsInNtp),
+ timestamp + kTimestampTicksPerMs),
+ RtpToNtpEstimator::kInvalidMeasurement);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForTooNewNtp) {
+ RtpToNtpEstimator estimator;
+
+ uint64_t ntp_raw = 699925050;
+ uint32_t timestamp = 0x12345678;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ // Ntp time from far future, list not updated.
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw + 2 * kOneHourInNtp),
+ timestamp + 10 * kTimestampTicksPerMs),
+ RtpToNtpEstimator::kInvalidMeasurement);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForEqualTimestamp) {
+ RtpToNtpEstimator estimator;
+
+ uint32_t timestamp = 0x12345678;
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2), timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+ // Timestamp already added, list not updated.
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(3), timestamp),
+ RtpToNtpEstimator::kSameMeasurement);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForOldRtpTimestamp) {
+ RtpToNtpEstimator estimator;
+ uint32_t timestamp = 0x12345678;
+
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2), timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+ // Old timestamp, list not updated.
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2 + kOneMsInNtp),
+ timestamp - kTimestampTicksPerMs),
+ RtpToNtpEstimator::kInvalidMeasurement);
+}
+
+TEST(UpdateRtcpMeasurementTests, VerifyParameters) {
+ RtpToNtpEstimator estimator;
+ uint32_t timestamp = 0x12345678;
+
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(kOneMsInNtp), timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ EXPECT_DOUBLE_EQ(estimator.EstimatedFrequencyKhz(), 0.0);
+
+ // Add second report, parameters should be calculated.
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2 * kOneMsInNtp),
+ timestamp + kTimestampTicksPerMs),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ EXPECT_NEAR(estimator.EstimatedFrequencyKhz(), kTimestampTicksPerMs, 0.01);
+}
+
+TEST(RtpToNtpTests, FailsForNoParameters) {
+ RtpToNtpEstimator estimator;
+ uint32_t timestamp = 0x12345678;
+
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+ // Parameters are not calculated, conversion of RTP to NTP time should fail.
+ EXPECT_DOUBLE_EQ(estimator.EstimatedFrequencyKhz(), 0.0);
+ EXPECT_FALSE(estimator.Estimate(timestamp).Valid());
+}
+
+TEST(RtpToNtpTests, AveragesErrorOut) {
+ RtpToNtpEstimator estimator;
+ uint64_t ntp_raw = 90000000; // More than 1 ms.
+ ASSERT_GT(ntp_raw, kOneMsInNtp);
+ uint32_t timestamp = 0x12345678;
+ constexpr uint64_t kNtpSecStep = uint64_t{1} << 32; // 1 second.
+ constexpr int kRtpTicksPerMs = 90;
+ constexpr int kRtpStep = kRtpTicksPerMs * 1000;
+
+ EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ Random rand(1123536L);
+ for (size_t i = 0; i < 1000; i++) {
+ // Advance both timestamps by exactly 1 second.
+ ntp_raw += kNtpSecStep;
+ timestamp += kRtpStep;
+ // Add upto 1ms of errors to NTP and RTP timestamps passed to estimator.
+ EXPECT_EQ(
+ estimator.UpdateMeasurements(
+ NtpTime(ntp_raw + rand.Rand(-int{kOneMsInNtp}, int{kOneMsInNtp})),
+ timestamp + rand.Rand(-kRtpTicksPerMs, kRtpTicksPerMs)),
+ RtpToNtpEstimator::kNewMeasurement);
+
+ NtpTime estimated_ntp = estimator.Estimate(timestamp);
+ EXPECT_TRUE(estimated_ntp.Valid());
+ // Allow upto 2 ms of error.
+ EXPECT_NEAR(ntp_raw, static_cast<uint64_t>(estimated_ntp), 2 * kOneMsInNtp);
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/source/sleep.cc b/third_party/libwebrtc/system_wrappers/source/sleep.cc
new file mode 100644
index 0000000000..e2fa486118
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/sleep.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+// An OS-independent sleep function.
+
+#include "system_wrappers/include/sleep.h"
+
+#ifdef _WIN32
+// For Sleep()
+#include <windows.h>
+#else
+// For nanosleep()
+#include <time.h>
+#endif
+
+namespace webrtc {
+
+void SleepMs(int msecs) {
+#ifdef _WIN32
+ Sleep(msecs);
+#else
+ struct timespec short_wait;
+ struct timespec remainder;
+ short_wait.tv_sec = msecs / 1000;
+ short_wait.tv_nsec = (msecs % 1000) * 1000 * 1000;
+ nanosleep(&short_wait, &remainder);
+#endif
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/system_wrappers/system_wrappers_gn/moz.build b/third_party/libwebrtc/system_wrappers/system_wrappers_gn/moz.build
new file mode 100644
index 0000000000..e53ea6babd
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/system_wrappers_gn/moz.build
@@ -0,0 +1,250 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/system_wrappers/source/clock.cc",
+ "/third_party/libwebrtc/system_wrappers/source/cpu_features.cc",
+ "/third_party/libwebrtc/system_wrappers/source/cpu_info.cc",
+ "/third_party/libwebrtc/system_wrappers/source/rtp_to_ntp_estimator.cc",
+ "/third_party/libwebrtc/system_wrappers/source/sleep.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ LOCAL_INCLUDES += [
+ "/config/external/nspr/",
+ "/nsprpub/lib/ds/",
+ "/nsprpub/pr/include/"
+ ]
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "rt"
+ ]
+
+ UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/system_wrappers/source/cpu_features_linux.cc"
+ ]
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["RTC_ENABLE_WIN_WGC"] = True
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "crypt32",
+ "iphlpapi",
+ "secur32",
+ "winmm"
+ ]
+
+if CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("system_wrappers_gn")