diff options
Diffstat (limited to '')
34 files changed, 4524 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..a6bcc9c28e --- /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/android_sdk:cpu_features" ] + } + + 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..10482ec2ea --- /dev/null +++ b/third_party/libwebrtc/system_wrappers/denormal_disabler_gn/moz.build @@ -0,0 +1,221 @@ +# 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_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_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_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["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["CPU_ARCH"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["CPU_ARCH"] == "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["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux": + + 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..9bbb117259 --- /dev/null +++ b/third_party/libwebrtc/system_wrappers/field_trial_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/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_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_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_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["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 += [ + "winmm" + ] + +if CONFIG["CPU_ARCH"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["CPU_ARCH"] == "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["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux": + + 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..612b4a5d6b --- /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 } 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..ca9ed6d09b --- /dev/null +++ b/third_party/libwebrtc/system_wrappers/include/metrics.h @@ -0,0 +1,436 @@ +// +// 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&...) {} +} +} + +#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..b4982671c9 --- /dev/null +++ b/third_party/libwebrtc/system_wrappers/metrics_gn/moz.build @@ -0,0 +1,221 @@ +# 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_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_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_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["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["CPU_ARCH"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["CPU_ARCH"] == "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["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux": + + 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..b676339eea --- /dev/null +++ b/third_party/libwebrtc/system_wrappers/source/cpu_features.cc @@ -0,0 +1,116 @@ +/* + * 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 + 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..8f15b4eb7a --- /dev/null +++ b/third_party/libwebrtc/system_wrappers/source/field_trial.cc @@ -0,0 +1,181 @@ +// 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 + RTC_DCHECK(absl::c_linear_search(kRegisteredFieldTrials, name) || + TestKeys().contains(name)) + << name << " is not registered."; +#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..bfc6aa12f9 --- /dev/null +++ b/third_party/libwebrtc/system_wrappers/system_wrappers_gn/moz.build @@ -0,0 +1,246 @@ +# 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_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_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_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["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["CPU_ARCH"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["CPU_ARCH"] == "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["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +Library("system_wrappers_gn") |