Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 14:04:28 +01:00
parent 81b91f4139
commit f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions

View file

@ -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::GetRealTimeClock() {
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

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Parts of this file derived from Chromium's base/cpu.cc.
#include "rtc_base/system/arch.h"
#include "system_wrappers/include/cpu_features_wrapper.h"
#include "system_wrappers/include/field_trial.h"
#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER)
#include <intrin.h>
#endif
namespace webrtc {
// No CPU feature is available => straight C path.
int GetCPUInfoNoASM(CPUFeature feature) {
(void)feature;
return 0;
}
#if defined(WEBRTC_ARCH_X86_FAMILY)
#if defined(WEBRTC_ENABLE_AVX2)
// xgetbv returns the value of an Intel Extended Control Register (XCR).
// Currently only XCR0 is defined by Intel so `xcr` should always be zero.
static uint64_t xgetbv(uint32_t xcr) {
#if defined(_MSC_VER)
return _xgetbv(xcr);
#else
uint32_t eax, edx;
__asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
return (static_cast<uint64_t>(edx) << 32) | eax;
#endif // _MSC_VER
}
#endif // WEBRTC_ENABLE_AVX2
#ifndef _MSC_VER
// Intrinsic for "cpuid".
#if defined(__pic__) && defined(__i386__)
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile(
"mov %%ebx, %%edi\n"
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]),
"=d"(cpu_info[3])
: "a"(info_type));
}
#else
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile("cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
"=d"(cpu_info[3])
: "a"(info_type), "c"(0));
}
#endif
#endif // _MSC_VER
#endif // WEBRTC_ARCH_X86_FAMILY
#if defined(WEBRTC_ARCH_X86_FAMILY)
// Actual feature detection for x86.
int GetCPUInfo(CPUFeature feature) {
int cpu_info[4];
__cpuid(cpu_info, 1);
if (feature == kSSE2) {
return 0 != (cpu_info[3] & 0x04000000);
}
if (feature == kSSE3) {
return 0 != (cpu_info[2] & 0x00000001);
}
#if defined(WEBRTC_ENABLE_AVX2)
if (feature == kAVX2 &&
!webrtc::field_trial::IsEnabled("WebRTC-Avx2SupportKillSwitch")) {
int cpu_info7[4];
__cpuid(cpu_info7, 0);
int num_ids = cpu_info7[0];
if (num_ids < 7) {
return 0;
}
// Interpret CPU feature information.
__cpuid(cpu_info7, 7);
// AVX instructions can be used when
// a) AVX are supported by the CPU,
// b) XSAVE is supported by the CPU,
// c) XSAVE is enabled by the kernel.
// Compiling with MSVC and /arch:AVX2 surprisingly generates BMI2
// instructions (see crbug.com/1315519).
return (cpu_info[2] & 0x10000000) != 0 /* AVX */ &&
(cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
(cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
(xgetbv(0) & 0x00000006) == 6 /* XSAVE enabled by kernel */ &&
(cpu_info7[1] & 0x00000020) != 0 /* AVX2 */ &&
(cpu_info7[1] & 0x00000100) != 0 /* BMI2 */;
}
#endif // WEBRTC_ENABLE_AVX2
if (feature == kFMA3) {
return 0 != (cpu_info[2] & 0x00001000);
}
return 0;
}
#else
// Default to straight C for other platforms.
int GetCPUInfo(CPUFeature feature) {
(void)feature;
return 0;
}
#endif
} // namespace webrtc

View file

@ -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

View file

@ -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

View file

@ -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)
#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)
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

View file

@ -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

View file

@ -0,0 +1,186 @@
// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
//
#include "system_wrappers/include/field_trial.h"
#include <stddef.h>
#include <map>
#include <string>
#include <utility>
#include "absl/algorithm/container.h"
#include "absl/strings/string_view.h"
#include "experiments/registered_field_trials.h"
#include "rtc_base/checks.h"
#include "rtc_base/containers/flat_set.h"
#include "rtc_base/logging.h"
#include "rtc_base/string_encode.h"
// Simple field trial implementation, which allows client to
// specify desired flags in InitFieldTrialsFromString.
namespace webrtc {
namespace field_trial {
static const char* trials_init_string = NULL;
namespace {
constexpr char kPersistentStringSeparator = '/';
flat_set<std::string>& TestKeys() {
static auto* test_keys = new flat_set<std::string>();
return *test_keys;
}
// Validates the given field trial string.
// E.g.:
// "WebRTC-experimentFoo/Enabled/WebRTC-experimentBar/Enabled100kbps/"
// Assigns the process to group "Enabled" on WebRTCExperimentFoo trial
// and to group "Enabled100kbps" on WebRTCExperimentBar.
//
// E.g. invalid config:
// "WebRTC-experiment1/Enabled" (note missing / separator at the end).
bool FieldTrialsStringIsValidInternal(const absl::string_view trials) {
if (trials.empty())
return true;
size_t next_item = 0;
std::map<absl::string_view, absl::string_view> field_trials;
while (next_item < trials.length()) {
size_t name_end = trials.find(kPersistentStringSeparator, next_item);
if (name_end == trials.npos || next_item == name_end)
return false;
size_t group_name_end =
trials.find(kPersistentStringSeparator, name_end + 1);
if (group_name_end == trials.npos || name_end + 1 == group_name_end)
return false;
absl::string_view name = trials.substr(next_item, name_end - next_item);
absl::string_view group_name =
trials.substr(name_end + 1, group_name_end - name_end - 1);
next_item = group_name_end + 1;
// Fail if duplicate with different group name.
if (field_trials.find(name) != field_trials.end() &&
field_trials.find(name)->second != group_name) {
return false;
}
field_trials[name] = group_name;
}
return true;
}
} // namespace
bool FieldTrialsStringIsValid(absl::string_view trials_string) {
return FieldTrialsStringIsValidInternal(trials_string);
}
void InsertOrReplaceFieldTrialStringsInMap(
std::map<std::string, std::string>* fieldtrial_map,
const absl::string_view trials_string) {
if (FieldTrialsStringIsValidInternal(trials_string)) {
std::vector<absl::string_view> tokens = rtc::split(trials_string, '/');
// Skip last token which is empty due to trailing '/'.
for (size_t idx = 0; idx < tokens.size() - 1; idx += 2) {
(*fieldtrial_map)[std::string(tokens[idx])] =
std::string(tokens[idx + 1]);
}
} else {
RTC_DCHECK_NOTREACHED() << "Invalid field trials string:" << trials_string;
}
}
std::string MergeFieldTrialsStrings(absl::string_view first,
absl::string_view second) {
std::map<std::string, std::string> fieldtrial_map;
InsertOrReplaceFieldTrialStringsInMap(&fieldtrial_map, first);
InsertOrReplaceFieldTrialStringsInMap(&fieldtrial_map, second);
// Merge into fieldtrial string.
std::string merged = "";
for (auto const& fieldtrial : fieldtrial_map) {
merged += fieldtrial.first + '/' + fieldtrial.second + '/';
}
return merged;
}
#ifndef WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
std::string FindFullName(absl::string_view name) {
#if WEBRTC_STRICT_FIELD_TRIALS == 1
RTC_DCHECK(absl::c_linear_search(kRegisteredFieldTrials, name) ||
TestKeys().contains(name))
<< name << " is not registered, see g3doc/field-trials.md.";
#elif WEBRTC_STRICT_FIELD_TRIALS == 2
RTC_LOG_IF(LS_WARNING,
!(absl::c_linear_search(kRegisteredFieldTrials, name) ||
TestKeys().contains(name)))
<< name << " is not registered, see g3doc/field-trials.md.";
#endif
if (trials_init_string == NULL)
return std::string();
absl::string_view trials_string(trials_init_string);
if (trials_string.empty())
return std::string();
size_t next_item = 0;
while (next_item < trials_string.length()) {
// Find next name/value pair in field trial configuration string.
size_t field_name_end =
trials_string.find(kPersistentStringSeparator, next_item);
if (field_name_end == trials_string.npos || field_name_end == next_item)
break;
size_t field_value_end =
trials_string.find(kPersistentStringSeparator, field_name_end + 1);
if (field_value_end == trials_string.npos ||
field_value_end == field_name_end + 1)
break;
absl::string_view field_name =
trials_string.substr(next_item, field_name_end - next_item);
absl::string_view field_value = trials_string.substr(
field_name_end + 1, field_value_end - field_name_end - 1);
next_item = field_value_end + 1;
if (name == field_name)
return std::string(field_value);
}
return std::string();
}
#endif // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
// Optionally initialize field trial from a string.
void InitFieldTrialsFromString(const char* trials_string) {
RTC_LOG(LS_INFO) << "Setting field trial string:" << trials_string;
if (trials_string) {
RTC_DCHECK(FieldTrialsStringIsValidInternal(trials_string))
<< "Invalid field trials string:" << trials_string;
};
trials_init_string = trials_string;
}
const char* GetFieldTrialString() {
return trials_init_string;
}
FieldTrialsAllowedInScopeForTesting::FieldTrialsAllowedInScopeForTesting(
flat_set<std::string> keys) {
TestKeys() = std::move(keys);
}
FieldTrialsAllowedInScopeForTesting::~FieldTrialsAllowedInScopeForTesting() {
TestKeys().clear();
}
} // namespace field_trial
} // namespace webrtc

View file

@ -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

View file

@ -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

View file

@ -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