summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/webrtc/system_wrappers/source
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/webrtc/system_wrappers/source')
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/aligned_array_unittest.cc60
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/aligned_malloc.cc100
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/aligned_malloc_unittest.cc82
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/atomic32.cc47
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/clock.cc266
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/clock_unittest.cc34
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features.cc74
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features_android.c15
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features_linux.c86
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/cpu_info.cc69
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/droid-cpu-features.c397
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/droid-cpu-features.h56
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/event.cc55
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix.cc261
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix.h64
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix_unittest.cc198
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_win.cc77
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_win.h40
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/field_trial_default.cc65
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/file_impl.cc152
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/metrics_default.cc303
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/metrics_default_unittest.cc161
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/metrics_unittest.cc113
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/ntp_time_unittest.cc65
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/rtp_to_ntp_estimator.cc205
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc295
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock.cc31
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_posix.cc50
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_posix.h41
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_win.cc95
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_win.h40
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/sleep.cc36
-rw-r--r--third_party/libwebrtc/webrtc/system_wrappers/source/timestamp_extrapolator.cc208
33 files changed, 3841 insertions, 0 deletions
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_array_unittest.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_array_unittest.cc
new file mode 100644
index 0000000000..e5a3c18fcc
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_array_unittest.cc
@@ -0,0 +1,60 @@
+/*
+ * 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/aligned_array.h"
+
+#include <stdint.h>
+
+#include "test/gtest.h"
+
+namespace {
+
+bool IsAligned(const void* ptr, size_t alignment) {
+ return reinterpret_cast<uintptr_t>(ptr) % alignment == 0;
+}
+
+} // namespace
+
+namespace webrtc {
+
+TEST(AlignedArrayTest, CheckAlignment) {
+ AlignedArray<bool> arr(10, 7, 128);
+ ASSERT_TRUE(IsAligned(arr.Array(), 128));
+ for (size_t i = 0; i < 10; ++i) {
+ ASSERT_TRUE(IsAligned(arr.Row(i), 128));
+ ASSERT_EQ(arr.Row(i), arr.Array()[i]);
+ }
+}
+
+TEST(AlignedArrayTest, CheckOverlap) {
+ AlignedArray<size_t> arr(10, 7, 128);
+
+ for (size_t i = 0; i < 10; ++i) {
+ for (size_t j = 0; j < 7; ++j) {
+ arr.At(i, j) = 20 * i + j;
+ }
+ }
+
+ for (size_t i = 0; i < 10; ++i) {
+ for (size_t j = 0; j < 7; ++j) {
+ ASSERT_EQ(arr.At(i, j), 20 * i + j);
+ ASSERT_EQ(arr.Row(i)[j], 20 * i + j);
+ ASSERT_EQ(arr.Array()[i][j], 20 * i + j);
+ }
+ }
+}
+
+TEST(AlignedArrayTest, CheckRowsCols) {
+ AlignedArray<bool> arr(10, 7, 128);
+ ASSERT_EQ(arr.rows(), 10u);
+ ASSERT_EQ(arr.cols(), 7u);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_malloc.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_malloc.cc
new file mode 100644
index 0000000000..43ece9e681
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_malloc.cc
@@ -0,0 +1,100 @@
+/*
+ * 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/aligned_malloc.h"
+
+#include <memory.h>
+#include <stdlib.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <stdint.h>
+#endif
+
+#include "typedefs.h" // NOLINT(build/include)
+
+// Reference on memory alignment:
+// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
+namespace webrtc {
+
+uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
+ // The pointer should be aligned with |alignment| bytes. The - 1 guarantees
+ // that it is aligned towards the closest higher (right) address.
+ return (start_pos + alignment - 1) & ~(alignment - 1);
+}
+
+// Alignment must be an integer power of two.
+bool ValidAlignment(size_t alignment) {
+ if (!alignment) {
+ return false;
+ }
+ return (alignment & (alignment - 1)) == 0;
+}
+
+void* GetRightAlign(const void* pointer, size_t alignment) {
+ if (!pointer) {
+ return NULL;
+ }
+ if (!ValidAlignment(alignment)) {
+ return NULL;
+ }
+ uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
+ return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
+}
+
+void* AlignedMalloc(size_t size, size_t alignment) {
+ if (size == 0) {
+ return NULL;
+ }
+ if (!ValidAlignment(alignment)) {
+ return NULL;
+ }
+
+ // The memory is aligned towards the lowest address that so only
+ // alignment - 1 bytes needs to be allocated.
+ // A pointer to the start of the memory must be stored so that it can be
+ // retreived for deletion, ergo the sizeof(uintptr_t).
+ void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
+ if (memory_pointer == NULL) {
+ return NULL;
+ }
+
+ // Aligning after the sizeof(uintptr_t) bytes will leave room for the header
+ // in the same memory block.
+ uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
+ align_start_pos += sizeof(uintptr_t);
+ uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
+ void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
+
+ // Store the address to the beginning of the memory just before the aligned
+ // memory.
+ uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
+ void* header_pointer = reinterpret_cast<void*>(header_pos);
+ uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
+ memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
+
+ return aligned_pointer;
+}
+
+void AlignedFree(void* mem_block) {
+ if (mem_block == NULL) {
+ return;
+ }
+ uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
+ uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
+
+ // Read out the address of the AlignedMemory struct from the header.
+ uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
+ void* memory_start = reinterpret_cast<void*>(memory_start_pos);
+ free(memory_start);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_malloc_unittest.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_malloc_unittest.cc
new file mode 100644
index 0000000000..7afbf6d1bb
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/aligned_malloc_unittest.cc
@@ -0,0 +1,82 @@
+/*
+ * 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/aligned_malloc.h"
+
+#include <memory>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <stdint.h>
+#endif
+
+#include "test/gtest.h"
+#include "typedefs.h" // NOLINT(build/include)
+
+namespace webrtc {
+
+// Returns true if |size| and |alignment| are valid combinations.
+bool CorrectUsage(size_t size, size_t alignment) {
+ std::unique_ptr<char, AlignedFreeDeleter> scoped(
+ static_cast<char*>(AlignedMalloc(size, alignment)));
+ if (scoped.get() == NULL) {
+ return false;
+ }
+ const uintptr_t scoped_address = reinterpret_cast<uintptr_t>(scoped.get());
+ return 0u == scoped_address % alignment;
+}
+
+TEST(AlignedMalloc, GetRightAlign) {
+ const size_t size = 100;
+ const size_t alignment = 32;
+ const size_t left_misalignment = 1;
+ std::unique_ptr<char, AlignedFreeDeleter> scoped(
+ static_cast<char*>(AlignedMalloc(size, alignment)));
+ EXPECT_TRUE(scoped.get() != NULL);
+ const uintptr_t aligned_address = reinterpret_cast<uintptr_t>(scoped.get());
+ const uintptr_t misaligned_address = aligned_address - left_misalignment;
+ const char* misaligned_ptr =
+ reinterpret_cast<const char*>(misaligned_address);
+ const char* realigned_ptr = GetRightAlign(misaligned_ptr, alignment);
+ EXPECT_EQ(scoped.get(), realigned_ptr);
+}
+
+TEST(AlignedMalloc, IncorrectSize) {
+ const size_t incorrect_size = 0;
+ const size_t alignment = 64;
+ EXPECT_FALSE(CorrectUsage(incorrect_size, alignment));
+}
+
+TEST(AlignedMalloc, IncorrectAlignment) {
+ const size_t size = 100;
+ const size_t incorrect_alignment = 63;
+ EXPECT_FALSE(CorrectUsage(size, incorrect_alignment));
+}
+
+TEST(AlignedMalloc, AlignTo2Bytes) {
+ size_t size = 100;
+ size_t alignment = 2;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+TEST(AlignedMalloc, AlignTo32Bytes) {
+ size_t size = 100;
+ size_t alignment = 32;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+TEST(AlignedMalloc, AlignTo128Bytes) {
+ size_t size = 100;
+ size_t alignment = 128;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/atomic32.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/atomic32.cc
new file mode 100644
index 0000000000..581c13e0c3
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/atomic32.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "system_wrappers/include/atomic32.h"
+
+#include <assert.h>
+
+#include "common_types.h" // NOLINT(build/include)
+
+namespace webrtc {
+
+Atomic32::Atomic32(int32_t initial_value) : value_(initial_value) {}
+
+Atomic32::~Atomic32() {}
+
+int32_t Atomic32::operator++() {
+ return ++value_;
+}
+
+int32_t Atomic32::operator--() {
+ return --value_;
+}
+
+int32_t Atomic32::operator+=(int32_t value) {
+ return value_ += value;
+}
+
+int32_t Atomic32::operator-=(int32_t value) {
+ return value_ -= value;
+}
+
+bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
+ return value_.compare_exchange_strong(compare_value, new_value);
+}
+
+int32_t Atomic32::Value() const {
+ return value_.load();
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/clock.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/clock.cc
new file mode 100644
index 0000000000..61fc4a49a6
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/clock.cc
@@ -0,0 +1,266 @@
+/*
+ * 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"
+
+#if defined(_WIN32)
+
+// Windows needs to be included before mmsystem.h
+#include "rtc_base/win32.h"
+
+#include <MMSystem.h>
+
+#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC) || (defined WEBRTC_BSD))
+
+#include <sys/time.h>
+#include <time.h>
+
+#endif
+
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/timeutils.h"
+#include "system_wrappers/include/rw_lock_wrapper.h"
+
+namespace webrtc {
+
+class RealTimeClock : public Clock {
+ // Return a timestamp in milliseconds relative to some arbitrary source; the
+ // source is fixed for this clock.
+ int64_t TimeInMilliseconds() const override { return rtc::TimeMillis(); }
+
+ // Return a timestamp in microseconds relative to some arbitrary source; the
+ // source is fixed for this clock.
+ int64_t TimeInMicroseconds() const override { return rtc::TimeMicros(); }
+
+ // Retrieve an NTP absolute timestamp.
+ NtpTime CurrentNtpTime() const override {
+ timeval tv = CurrentTimeVal();
+ double microseconds_in_seconds;
+ uint32_t seconds;
+ Adjust(tv, &seconds, &microseconds_in_seconds);
+ uint32_t fractions = static_cast<uint32_t>(
+ microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5);
+ return NtpTime(seconds, fractions);
+ }
+
+ // Retrieve an NTP absolute timestamp in milliseconds.
+ int64_t CurrentNtpInMilliseconds() const override {
+ timeval tv = CurrentTimeVal();
+ uint32_t seconds;
+ double microseconds_in_seconds;
+ Adjust(tv, &seconds, &microseconds_in_seconds);
+ return 1000 * static_cast<int64_t>(seconds) +
+ static_cast<int64_t>(1000.0 * microseconds_in_seconds + 0.5);
+ }
+
+ protected:
+ virtual timeval CurrentTimeVal() const = 0;
+
+ static void Adjust(const timeval& tv,
+ uint32_t* adjusted_s,
+ double* adjusted_us_in_s) {
+ *adjusted_s = tv.tv_sec + kNtpJan1970;
+ *adjusted_us_in_s = tv.tv_usec / 1e6;
+
+ if (*adjusted_us_in_s >= 1) {
+ *adjusted_us_in_s -= 1;
+ ++*adjusted_s;
+ } else if (*adjusted_us_in_s < -1) {
+ *adjusted_us_in_s += 1;
+ --*adjusted_s;
+ }
+ }
+};
+
+#if defined(_WIN32)
+// TODO(pbos): Consider modifying the implementation to synchronize itself
+// against system time (update ref_point_, make it non-const) periodically to
+// prevent clock drift.
+class WindowsRealTimeClock : public RealTimeClock {
+ public:
+ WindowsRealTimeClock()
+ : last_time_ms_(0),
+ num_timer_wraps_(0),
+ ref_point_(GetSystemReferencePoint()) {}
+
+ virtual ~WindowsRealTimeClock() {}
+
+ protected:
+ struct ReferencePoint {
+ FILETIME file_time;
+ LARGE_INTEGER counter_ms;
+ };
+
+ timeval CurrentTimeVal() const override {
+ const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
+
+ FILETIME StartTime;
+ uint64_t Time;
+ struct timeval tv;
+
+ // We can't use query performance counter since they can change depending on
+ // speed stepping.
+ GetTime(&StartTime);
+
+ Time = (((uint64_t)StartTime.dwHighDateTime) << 32) +
+ (uint64_t)StartTime.dwLowDateTime;
+
+ // Convert the hecto-nano second time to tv format.
+ Time -= FILETIME_1970;
+
+ tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000);
+ tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
+ return tv;
+ }
+
+ void GetTime(FILETIME* current_time) const {
+ DWORD t;
+ LARGE_INTEGER elapsed_ms;
+ {
+ rtc::CritScope lock(&crit_);
+ // time MUST be fetched inside the critical section to avoid non-monotonic
+ // last_time_ms_ values that'll register as incorrect wraparounds due to
+ // concurrent calls to GetTime.
+ t = timeGetTime();
+ if (t < last_time_ms_)
+ num_timer_wraps_++;
+ last_time_ms_ = t;
+ elapsed_ms.HighPart = num_timer_wraps_;
+ }
+ elapsed_ms.LowPart = t;
+ elapsed_ms.QuadPart = elapsed_ms.QuadPart - ref_point_.counter_ms.QuadPart;
+
+ // Translate to 100-nanoseconds intervals (FILETIME resolution)
+ // and add to reference FILETIME to get current FILETIME.
+ ULARGE_INTEGER filetime_ref_as_ul;
+ filetime_ref_as_ul.HighPart = ref_point_.file_time.dwHighDateTime;
+ filetime_ref_as_ul.LowPart = ref_point_.file_time.dwLowDateTime;
+ filetime_ref_as_ul.QuadPart +=
+ static_cast<ULONGLONG>((elapsed_ms.QuadPart) * 1000 * 10);
+
+ // Copy to result
+ current_time->dwHighDateTime = filetime_ref_as_ul.HighPart;
+ current_time->dwLowDateTime = filetime_ref_as_ul.LowPart;
+ }
+
+ static ReferencePoint GetSystemReferencePoint() {
+ ReferencePoint ref = {};
+ FILETIME ft0 = {};
+ FILETIME ft1 = {};
+ // Spin waiting for a change in system time. As soon as this change happens,
+ // get the matching call for timeGetTime() as soon as possible. This is
+ // assumed to be the most accurate offset that we can get between
+ // timeGetTime() and system time.
+
+ // Set timer accuracy to 1 ms.
+ timeBeginPeriod(1);
+ GetSystemTimeAsFileTime(&ft0);
+ do {
+ GetSystemTimeAsFileTime(&ft1);
+
+ ref.counter_ms.QuadPart = timeGetTime();
+ Sleep(0);
+ } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
+ (ft0.dwLowDateTime == ft1.dwLowDateTime));
+ ref.file_time = ft1;
+ timeEndPeriod(1);
+ return ref;
+ }
+
+ // mutable as time-accessing functions are const.
+ rtc::CriticalSection crit_;
+ mutable DWORD last_time_ms_;
+ mutable LONG num_timer_wraps_;
+ const ReferencePoint ref_point_;
+};
+
+#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC)) || (defined WEBRTC_BSD)
+class UnixRealTimeClock : public RealTimeClock {
+ public:
+ UnixRealTimeClock() {}
+
+ ~UnixRealTimeClock() override {}
+
+ protected:
+ timeval CurrentTimeVal() const override {
+ struct timeval tv;
+ struct timezone tz;
+ tz.tz_minuteswest = 0;
+ tz.tz_dsttime = 0;
+ gettimeofday(&tv, &tz);
+ return tv;
+ }
+};
+#endif
+
+#if defined(_WIN32)
+static WindowsRealTimeClock* volatile g_shared_clock = nullptr;
+#endif
+Clock* Clock::GetRealTimeClock() {
+#if defined(_WIN32)
+ // This read relies on volatile read being atomic-load-acquire. This is
+ // true in MSVC since at least 2005:
+ // "A read of a volatile object (volatile read) has Acquire semantics"
+ if (g_shared_clock != nullptr)
+ return g_shared_clock;
+ WindowsRealTimeClock* clock = new WindowsRealTimeClock;
+ if (InterlockedCompareExchangePointer(
+ reinterpret_cast<void* volatile*>(&g_shared_clock), clock, nullptr) !=
+ nullptr) {
+ // g_shared_clock was assigned while we constructed/tried to assign our
+ // instance, delete our instance and use the existing one.
+ delete clock;
+ }
+ return g_shared_clock;
+#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_BSD) || (defined WEBRTC_MAC))
+ static UnixRealTimeClock clock;
+ return &clock;
+#else
+ return NULL;
+#endif
+}
+
+SimulatedClock::SimulatedClock(int64_t initial_time_us)
+ : time_us_(initial_time_us), lock_(RWLockWrapper::CreateRWLock()) {}
+
+SimulatedClock::~SimulatedClock() {}
+
+int64_t SimulatedClock::TimeInMilliseconds() const {
+ ReadLockScoped synchronize(*lock_);
+ return (time_us_ + 500) / 1000;
+}
+
+int64_t SimulatedClock::TimeInMicroseconds() const {
+ ReadLockScoped synchronize(*lock_);
+ return time_us_;
+}
+
+NtpTime SimulatedClock::CurrentNtpTime() const {
+ int64_t now_ms = TimeInMilliseconds();
+ uint32_t seconds = (now_ms / 1000) + kNtpJan1970;
+ uint32_t fractions =
+ static_cast<uint32_t>((now_ms % 1000) * kMagicNtpFractionalUnit / 1000);
+ return NtpTime(seconds, fractions);
+}
+
+int64_t SimulatedClock::CurrentNtpInMilliseconds() const {
+ return TimeInMilliseconds() + 1000 * static_cast<int64_t>(kNtpJan1970);
+}
+
+void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
+ AdvanceTimeMicroseconds(1000 * milliseconds);
+}
+
+void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) {
+ WriteLockScoped synchronize(*lock_);
+ time_us_ += microseconds;
+}
+
+}; // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/clock_unittest.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/clock_unittest.cc
new file mode 100644
index 0000000000..f7b0ed7a47
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/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/webrtc/system_wrappers/source/cpu_features.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features.cc
new file mode 100644
index 0000000000..061e763559
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features.cc
@@ -0,0 +1,74 @@
+/*
+ * 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 "system_wrappers/include/cpu_features_wrapper.h"
+
+#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER)
+#include <intrin.h>
+#endif
+
+#include "typedefs.h" // NOLINT(build/include)
+
+// No CPU feature is available => straight C path.
+int GetCPUInfoNoASM(CPUFeature feature) {
+ (void)feature;
+ return 0;
+}
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#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));
+}
+#endif
+#endif // _MSC_VER
+#endif // WEBRTC_ARCH_X86_FAMILY
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+// Actual feature detection for x86.
+static 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);
+ }
+ return 0;
+}
+#else
+// Default to straight C for other platforms.
+static int GetCPUInfo(CPUFeature feature) {
+ (void)feature;
+ return 0;
+}
+
+#endif
+
+WebRtc_CPUInfo WebRtc_GetCPUInfo = GetCPUInfo;
+WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM = GetCPUInfoNoASM;
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features_android.c b/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features_android.c
new file mode 100644
index 0000000000..0cb3a6c5ee
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features_android.c
@@ -0,0 +1,15 @@
+/*
+ * 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>
+
+uint64_t WebRtc_GetCPUFeaturesARM(void) {
+ return android_getCpuFeatures();
+}
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features_linux.c b/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features_linux.c
new file mode 100644
index 0000000000..9c5645068a
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_features_linux.c
@@ -0,0 +1,86 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <features.h>
+#ifndef __GLIBC_PREREQ
+#define __GLIBC_PREREQ(a, b) 0
+#endif
+#if __GLIBC_PREREQ(2, 16)
+#include <sys/auxv.h>
+#else
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <link.h>
+#endif
+#include "system_wrappers/include/cpu_features_wrapper.h"
+
+#if defined(WEBRTC_ARCH_ARM_FAMILY)
+#include <asm/hwcap.h>
+
+uint64_t WebRtc_GetCPUFeaturesARM(void) {
+ uint64_t result = 0;
+ int architecture = 0;
+ unsigned long hwcap = 0;
+ const char* platform = NULL;
+#if __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 // __GLIBC_PREREQ(2,16)
+#if defined(__aarch64__)
+ 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;
+}
+#endif // WEBRTC_ARCH_ARM_FAMILY
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_info.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_info.cc
new file mode 100644
index 0000000000..f631be1db0
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/cpu_info.cc
@@ -0,0 +1,69 @@
+/*
+ * 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>
+#include <winsock2.h>
+#ifndef EXCLUDE_D3D9
+#include <d3d9.h>
+#endif
+#elif defined(WEBRTC_LINUX) || defined(WEBRTC_BSD)
+#include <unistd.h>
+#endif
+#if defined(WEBRTC_MAC)
+#include <sys/sysctl.h>
+#endif
+
+#include "rtc_base/logging.h"
+
+namespace internal {
+static int DetectNumberOfCores() {
+ // We fall back on assuming a single core in case of errors.
+ int number_of_cores = 1;
+
+#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));
+#elif defined(WEBRTC_MAC)
+ 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;
+ }
+#else
+ RTC_LOG(LS_ERROR) << "No function to get number of cores";
+#endif
+
+ RTC_LOG(LS_INFO) << "Available number of cores: " << number_of_cores;
+
+ 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 uint32_t logical_cpus = 0;
+ if (!logical_cpus)
+ logical_cpus = static_cast<uint32_t>(internal::DetectNumberOfCores());
+ return logical_cpus;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/droid-cpu-features.c b/third_party/libwebrtc/webrtc/system_wrappers/source/droid-cpu-features.c
new file mode 100644
index 0000000000..cc24b30056
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/droid-cpu-features.c
@@ -0,0 +1,397 @@
+/*
+ * 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 <sys/system_properties.h>
+#ifdef __arm__
+#include <machine/cpu-features.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "droid-cpu-features.h"
+
+static pthread_once_t g_once;
+static AndroidCpuFamily g_cpuFamily;
+static uint64_t g_cpuFeatures;
+static int g_cpuCount;
+
+static const int android_cpufeatures_debug = 0;
+
+#ifdef __arm__
+# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM
+#elif defined __i386__
+# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86
+#else
+# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN
+#endif
+
+#define D(...) \
+ do { \
+ if (android_cpufeatures_debug) { \
+ printf(__VA_ARGS__); fflush(stdout); \
+ } \
+ } while (0)
+
+#ifdef __i386__
+static __inline__ void x86_cpuid(int func, int values[4])
+{
+ int a, b, c, d;
+ /* We need to preserve ebx since we're compiling PIC code */
+ /* this means we can't use "=b" for the second output register */
+ __asm__ __volatile__ ( \
+ "push %%ebx\n"
+ "cpuid\n" \
+ "mov %1, %%ebx\n"
+ "pop %%ebx\n"
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "a" (func) \
+ );
+ values[0] = a;
+ values[1] = b;
+ values[2] = c;
+ values[3] = d;
+}
+#endif
+
+/* Read the content of /proc/cpuinfo into a user-provided buffer.
+ * Return the length of the data, or -1 on error. Does *not*
+ * zero-terminate the content. Will not read more
+ * than 'buffsize' bytes.
+ */
+static int
+read_file(const char* pathname, char* buffer, size_t buffsize)
+{
+ int fd, len;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ do {
+ len = read(fd, buffer, buffsize);
+ } while (len < 0 && errno == EINTR);
+
+ close(fd);
+
+ return len;
+}
+
+/* Extract the content of a the first occurence of a given field in
+ * the content of /proc/cpuinfo and return it as a heap-allocated
+ * string that must be freed by the caller.
+ *
+ * Return NULL if not found
+ */
+static char*
+extract_cpuinfo_field(char* buffer, int buflen, const char* field)
+{
+ int fieldlen = strlen(field);
+ char* bufend = buffer + buflen;
+ char* result = NULL;
+ int len, ignore;
+ const char *p, *q;
+
+ /* Look for first field occurence, and ensures it starts the line.
+ */
+ p = buffer;
+ bufend = buffer + buflen;
+ for (;;) {
+ p = memmem(p, bufend-p, field, fieldlen);
+ if (p == NULL)
+ goto EXIT;
+
+ if (p == buffer || p[-1] == '\n')
+ break;
+
+ p += fieldlen;
+ }
+
+ /* Skip to the first column followed by a space */
+ p += fieldlen;
+ p = memchr(p, ':', bufend-p);
+ if (p == NULL || p[1] != ' ')
+ goto EXIT;
+
+ /* Find the end of the line */
+ p += 2;
+ q = memchr(p, '\n', bufend-p);
+ if (q == NULL)
+ q = bufend;
+
+ /* Copy the line into a heap-allocated buffer */
+ len = q-p;
+ result = malloc(len+1);
+ if (result == NULL)
+ goto EXIT;
+
+ memcpy(result, p, len);
+ result[len] = '\0';
+
+EXIT:
+ return result;
+}
+
+/* Count the number of occurences of a given field prefix in /proc/cpuinfo.
+ */
+static int
+count_cpuinfo_field(char* buffer, int buflen, const char* field)
+{
+ int fieldlen = strlen(field);
+ const char* p = buffer;
+ const char* bufend = buffer + buflen;
+ const char* q;
+ int count = 0;
+
+ for (;;) {
+ const char* q;
+
+ p = memmem(p, bufend-p, field, fieldlen);
+ if (p == NULL)
+ break;
+
+ /* Ensure that the field is at the start of a line */
+ if (p > buffer && p[-1] != '\n') {
+ p += fieldlen;
+ continue;
+ }
+
+
+ /* skip any whitespace */
+ q = p + fieldlen;
+ while (q < bufend && (*q == ' ' || *q == '\t'))
+ q++;
+
+ /* we must have a colon now */
+ if (q < bufend && *q == ':') {
+ count += 1;
+ q ++;
+ }
+ p = q;
+ }
+
+ return count;
+}
+
+/* Like strlen(), but for constant string literals */
+#define STRLEN_CONST(x) ((sizeof(x)-1)
+
+
+/* Checks that a space-separated list of items contains one given 'item'.
+ * Returns 1 if found, 0 otherwise.
+ */
+static int
+has_list_item(const char* list, const char* item)
+{
+ const char* p = list;
+ int itemlen = strlen(item);
+
+ if (list == NULL)
+ return 0;
+
+ while (*p) {
+ const char* q;
+
+ /* skip spaces */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ /* find end of current list item */
+ q = p;
+ while (*q && *q != ' ' && *q != '\t')
+ q++;
+
+ if (itemlen == q-p && !memcmp(p, item, itemlen))
+ return 1;
+
+ /* skip to next item */
+ p = q;
+ }
+ return 0;
+}
+
+
+static void
+android_cpuInit(void)
+{
+ char cpuinfo[4096];
+ int cpuinfo_len;
+
+ g_cpuFamily = DEFAULT_CPU_FAMILY;
+ g_cpuFeatures = 0;
+ g_cpuCount = 1;
+
+ cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo);
+ D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len,
+ cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo);
+
+ if (cpuinfo_len < 0) /* should not happen */ {
+ return;
+ }
+
+ /* Count the CPU cores, the value may be 0 for single-core CPUs */
+ g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "processor");
+ if (g_cpuCount == 0) {
+ g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "Processor");
+ if (g_cpuCount == 0) {
+ g_cpuCount = 1;
+ }
+ }
+
+ D("found cpuCount = %d\n", g_cpuCount);
+
+#ifdef __ARM_ARCH__
+ {
+ char* features = NULL;
+ char* architecture = NULL;
+
+ /* Extract architecture from the "CPU Architecture" field.
+ * The list is well-known, unlike the the output of
+ * the 'Processor' field which can vary greatly.
+ *
+ * See the definition of the 'proc_arch' array in
+ * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in
+ * same file.
+ */
+ char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture");
+
+ if (cpuArch != NULL) {
+ char* end;
+ long archNumber;
+ int hasARMv7 = 0;
+
+ D("found cpuArch = '%s'\n", cpuArch);
+
+ /* read the initial decimal number, ignore the rest */
+ archNumber = strtol(cpuArch, &end, 10);
+
+ /* Here we assume that ARMv8 will be upwards compatible with v7
+ * in the future. Unfortunately, there is no 'Features' field to
+ * indicate that Thumb-2 is supported.
+ */
+ if (end > cpuArch && archNumber >= 7) {
+ hasARMv7 = 1;
+ }
+
+ /* Unfortunately, it seems that certain ARMv6-based CPUs
+ * report an incorrect architecture number of 7!
+ *
+ * See http://code.google.com/p/android/issues/detail?id=10812
+ *
+ * We try to correct this by looking at the 'elf_format'
+ * field reported by the 'Processor' field, which is of the
+ * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
+ * an ARMv6-one.
+ */
+ if (hasARMv7) {
+ char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
+ "Processor");
+ if (cpuProc != NULL) {
+ D("found cpuProc = '%s'\n", cpuProc);
+ if (has_list_item(cpuProc, "(v6l)")) {
+ D("CPU processor and architecture mismatch!!\n");
+ hasARMv7 = 0;
+ }
+ free(cpuProc);
+ }
+ }
+
+ if (hasARMv7) {
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
+ }
+
+ /* The LDREX / STREX instructions are available from ARMv6 */
+ if (archNumber >= 6) {
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
+ }
+
+ free(cpuArch);
+ }
+
+ /* Extract the list of CPU features from 'Features' field */
+ char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features");
+
+ if (cpuFeatures != NULL) {
+
+ D("found cpuFeatures = '%s'\n", cpuFeatures);
+
+ if (has_list_item(cpuFeatures, "vfpv3"))
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
+
+ else if (has_list_item(cpuFeatures, "vfpv3d16"))
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
+
+ if (has_list_item(cpuFeatures, "neon")) {
+ /* Note: Certain kernels only report neon but not vfpv3
+ * in their features list. However, ARM mandates
+ * that if Neon is implemented, so must be VFPv3
+ * so always set the flag.
+ */
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON |
+ ANDROID_CPU_ARM_FEATURE_VFPv3;
+ }
+ free(cpuFeatures);
+ }
+ }
+#endif /* __ARM_ARCH__ */
+
+#ifdef __i386__
+ g_cpuFamily = ANDROID_CPU_FAMILY_X86;
+
+ int regs[4];
+
+/* According to http://en.wikipedia.org/wiki/CPUID */
+#define VENDOR_INTEL_b 0x756e6547
+#define VENDOR_INTEL_c 0x6c65746e
+#define VENDOR_INTEL_d 0x49656e69
+
+ x86_cpuid(0, regs);
+ int vendorIsIntel = (regs[1] == VENDOR_INTEL_b &&
+ regs[2] == VENDOR_INTEL_c &&
+ regs[3] == VENDOR_INTEL_d);
+
+ x86_cpuid(1, regs);
+ if ((regs[2] & (1 << 9)) != 0) {
+ g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
+ }
+ if ((regs[2] & (1 << 23)) != 0) {
+ g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
+ }
+ if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) {
+ g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
+ }
+#endif
+}
+
+
+AndroidCpuFamily
+android_getCpuFamily(void)
+{
+ pthread_once(&g_once, android_cpuInit);
+ return g_cpuFamily;
+}
+
+
+uint64_t
+android_getCpuFeatures(void)
+{
+ pthread_once(&g_once, android_cpuInit);
+ return g_cpuFeatures;
+}
+
+
+int
+android_getCpuCount(void)
+{
+ pthread_once(&g_once, android_cpuInit);
+ return g_cpuCount;
+}
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/droid-cpu-features.h b/third_party/libwebrtc/webrtc/system_wrappers/source/droid-cpu-features.h
new file mode 100644
index 0000000000..f20c0bc4d9
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/droid-cpu-features.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+// You can download Android source at
+// http://source.android.com/source/downloading.html
+// Original files are in ndk/sources/android/cpufeatures
+// Revision is Change-Id: I9a0629efba36a6023f05e5f092e7addcc1b7d2a9
+
+#ifndef CPU_FEATURES_H
+#define CPU_FEATURES_H
+
+#include <sys/cdefs.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+typedef enum {
+ ANDROID_CPU_FAMILY_UNKNOWN = 0,
+ ANDROID_CPU_FAMILY_ARM,
+ ANDROID_CPU_FAMILY_X86,
+
+ ANDROID_CPU_FAMILY_MAX /* do not remove */
+
+} AndroidCpuFamily;
+
+/* Return family of the device's CPU */
+extern AndroidCpuFamily android_getCpuFamily(void);
+
+enum {
+ ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0),
+ ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1),
+ ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2),
+ ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3),
+};
+
+enum {
+ ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0),
+ ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1),
+ ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2),
+};
+
+extern uint64_t android_getCpuFeatures(void);
+
+/* Return the number of CPU cores detected on this device. */
+extern int android_getCpuCount(void);
+
+__END_DECLS
+
+#endif /* CPU_FEATURES_H */
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/event.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/event.cc
new file mode 100644
index 0000000000..aac69f6e02
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/event.cc
@@ -0,0 +1,55 @@
+/*
+ * 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/event_wrapper.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+#include "system_wrappers/source/event_timer_win.h"
+#elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+#include <ApplicationServices/ApplicationServices.h>
+#include <pthread.h>
+#include "system_wrappers/source/event_timer_posix.h"
+#else
+#include <pthread.h>
+#include "system_wrappers/source/event_timer_posix.h"
+#endif
+
+#include "rtc_base/event.h"
+
+namespace webrtc {
+
+class EventWrapperImpl : public EventWrapper {
+ public:
+ EventWrapperImpl() : event_(false, false) {}
+ ~EventWrapperImpl() override {}
+
+ bool Set() override {
+ event_.Set();
+ return true;
+ }
+
+ EventTypeWrapper Wait(unsigned long max_time) override {
+ int to_wait = max_time == WEBRTC_EVENT_INFINITE
+ ? rtc::Event::kForever
+ : static_cast<int>(max_time);
+ return event_.Wait(to_wait) ? kEventSignaled : kEventTimeout;
+ }
+
+ private:
+ rtc::Event event_;
+};
+
+// static
+EventWrapper* EventWrapper::Create() {
+ return new EventWrapperImpl();
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix.cc
new file mode 100644
index 0000000000..2a6a580c64
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix.cc
@@ -0,0 +1,261 @@
+/*
+ * 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/source/event_timer_posix.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// static
+EventTimerWrapper* EventTimerWrapper::Create() {
+ return new EventTimerPosix();
+}
+
+const int64_t kNanosecondsPerMillisecond = 1000000;
+const int64_t kNanosecondsPerSecond = 1000000000;
+
+EventTimerPosix::EventTimerPosix()
+ : event_set_(false),
+ timer_thread_(nullptr),
+ created_at_(),
+ periodic_(false),
+ time_ms_(0),
+ count_(0),
+ is_stopping_(false) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mutex_, &attr);
+ pthread_condattr_t cond_attr;
+ pthread_condattr_init(&cond_attr);
+// TODO(sprang): Remove HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC special case once
+// all supported Android platforms support pthread_condattr_setclock.
+// TODO(sprang): Add support for monotonic clock on Apple platforms.
+#if !(defined(WEBRTC_MAC) || defined(WEBRTC_IOS)) && \
+ !(defined(WEBRTC_ANDROID) && \
+ defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+ pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
+#endif
+ pthread_cond_init(&cond_, &cond_attr);
+ pthread_condattr_destroy(&cond_attr);
+}
+
+EventTimerPosix::~EventTimerPosix() {
+ StopTimer();
+ pthread_cond_destroy(&cond_);
+ pthread_mutex_destroy(&mutex_);
+}
+
+// TODO(pbos): Make this void.
+bool EventTimerPosix::Set() {
+ RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
+ event_set_ = true;
+ pthread_cond_signal(&cond_);
+ pthread_mutex_unlock(&mutex_);
+ return true;
+}
+
+EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout_ms) {
+ int ret_val = 0;
+ RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
+
+ if (!event_set_) {
+ if (WEBRTC_EVENT_INFINITE != timeout_ms) {
+ timespec end_at;
+#ifndef WEBRTC_MAC
+ clock_gettime(CLOCK_MONOTONIC, &end_at);
+#else
+ timeval value;
+ struct timezone time_zone;
+ time_zone.tz_minuteswest = 0;
+ time_zone.tz_dsttime = 0;
+ gettimeofday(&value, &time_zone);
+ TIMEVAL_TO_TIMESPEC(&value, &end_at);
+#endif
+ end_at.tv_sec += timeout_ms / 1000;
+ end_at.tv_nsec += (timeout_ms % 1000) * kNanosecondsPerMillisecond;
+
+ if (end_at.tv_nsec >= kNanosecondsPerSecond) {
+ end_at.tv_sec++;
+ end_at.tv_nsec -= kNanosecondsPerSecond;
+ }
+ while (ret_val == 0 && !event_set_) {
+#if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+ ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, &end_at);
+#else
+ ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
+#endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
+ }
+ } else {
+ while (ret_val == 0 && !event_set_)
+ ret_val = pthread_cond_wait(&cond_, &mutex_);
+ }
+ }
+
+ RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
+
+ // Reset and signal if set, regardless of why the thread woke up.
+ if (event_set_) {
+ ret_val = 0;
+ event_set_ = false;
+ }
+ pthread_mutex_unlock(&mutex_);
+
+ return ret_val == 0 ? kEventSignaled : kEventTimeout;
+}
+
+EventTypeWrapper EventTimerPosix::Wait(timespec* end_at, bool reset_event) {
+ int ret_val = 0;
+ RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
+ if (reset_event) {
+ // Only wake for new events or timeouts.
+ event_set_ = false;
+ }
+
+ while (ret_val == 0 && !event_set_) {
+#if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+ ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, end_at);
+#else
+ ret_val = pthread_cond_timedwait(&cond_, &mutex_, end_at);
+#endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
+ }
+
+ RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
+
+ // Reset and signal if set, regardless of why the thread woke up.
+ if (event_set_) {
+ ret_val = 0;
+ event_set_ = false;
+ }
+ pthread_mutex_unlock(&mutex_);
+
+ return ret_val == 0 ? kEventSignaled : kEventTimeout;
+}
+
+rtc::PlatformThread* EventTimerPosix::CreateThread() {
+ const char* kThreadName = "WebRtc_event_timer_thread";
+ return new rtc::PlatformThread(Run, this, kThreadName);
+}
+
+bool EventTimerPosix::StartTimer(bool periodic, unsigned long time_ms) {
+ pthread_mutex_lock(&mutex_);
+ if (timer_thread_) {
+ if (periodic_) {
+ // Timer already started.
+ pthread_mutex_unlock(&mutex_);
+ return false;
+ } else {
+ // New one shot timer.
+ time_ms_ = time_ms;
+ created_at_.tv_sec = 0;
+ timer_event_->Set();
+ pthread_mutex_unlock(&mutex_);
+ return true;
+ }
+ }
+
+ // Start the timer thread.
+ timer_event_.reset(new EventTimerPosix());
+ timer_thread_.reset(CreateThread());
+ periodic_ = periodic;
+ time_ms_ = time_ms;
+ timer_thread_->Start();
+ timer_thread_->SetPriority(rtc::kRealtimePriority);
+ pthread_mutex_unlock(&mutex_);
+
+ return true;
+}
+
+bool EventTimerPosix::Run(void* obj) {
+ return static_cast<EventTimerPosix*>(obj)->Process();
+}
+
+bool EventTimerPosix::Process() {
+ pthread_mutex_lock(&mutex_);
+ if (is_stopping_) {
+ pthread_mutex_unlock(&mutex_);
+ return false;
+ }
+ if (created_at_.tv_sec == 0) {
+#ifndef WEBRTC_MAC
+ RTC_CHECK_EQ(0, clock_gettime(CLOCK_MONOTONIC, &created_at_));
+#else
+ timeval value;
+ struct timezone time_zone;
+ time_zone.tz_minuteswest = 0;
+ time_zone.tz_dsttime = 0;
+ gettimeofday(&value, &time_zone);
+ TIMEVAL_TO_TIMESPEC(&value, &created_at_);
+#endif
+ count_ = 0;
+ }
+
+ timespec end_at;
+ unsigned long long total_delta_ms = time_ms_ * ++count_;
+ if (!periodic_ && count_ >= 1) {
+ // No need to wake up often if we're not going to signal waiting threads.
+ total_delta_ms =
+ std::min<uint64_t>(total_delta_ms, 60 * kNanosecondsPerSecond);
+ }
+
+ end_at.tv_sec = created_at_.tv_sec + total_delta_ms / 1000;
+ end_at.tv_nsec = created_at_.tv_nsec +
+ (total_delta_ms % 1000) * kNanosecondsPerMillisecond;
+
+ if (end_at.tv_nsec >= kNanosecondsPerSecond) {
+ end_at.tv_sec++;
+ end_at.tv_nsec -= kNanosecondsPerSecond;
+ }
+
+ pthread_mutex_unlock(&mutex_);
+ // Reset event on first call so that we don't immediately return here if this
+ // thread was not blocked on timer_event_->Wait when the StartTimer() call
+ // was made.
+ if (timer_event_->Wait(&end_at, count_ == 1) == kEventSignaled)
+ return true;
+
+ pthread_mutex_lock(&mutex_);
+ if (periodic_ || count_ == 1)
+ Set();
+ pthread_mutex_unlock(&mutex_);
+
+ return true;
+}
+
+bool EventTimerPosix::StopTimer() {
+ pthread_mutex_lock(&mutex_);
+ is_stopping_ = true;
+ pthread_mutex_unlock(&mutex_);
+
+ if (timer_event_)
+ timer_event_->Set();
+
+ if (timer_thread_) {
+ timer_thread_->Stop();
+ timer_thread_.reset();
+ }
+ timer_event_.reset();
+
+ // Set time to zero to force new reference time for the timer.
+ memset(&created_at_, 0, sizeof(created_at_));
+ count_ = 0;
+ return true;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix.h b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix.h
new file mode 100644
index 0000000000..72d6753e53
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix.h
@@ -0,0 +1,64 @@
+/*
+ * 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_SOURCE_EVENT_POSIX_H_
+#define SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
+
+#include "system_wrappers/include/event_wrapper.h"
+
+#include <memory>
+
+#include <pthread.h>
+#include <time.h>
+
+#include "rtc_base/platform_thread.h"
+
+namespace webrtc {
+
+enum State { kUp = 1, kDown = 2 };
+
+class EventTimerPosix : public EventTimerWrapper {
+ public:
+ EventTimerPosix();
+ ~EventTimerPosix() override;
+
+ EventTypeWrapper Wait(unsigned long max_time) override;
+ bool Set() override;
+
+ bool StartTimer(bool periodic, unsigned long time) override;
+ bool StopTimer() override;
+
+ private:
+ friend class EventTimerPosixTest;
+
+ static bool Run(void* obj);
+ bool Process();
+ EventTypeWrapper Wait(timespec* end_at, bool reset_state);
+
+ virtual rtc::PlatformThread* CreateThread();
+
+ pthread_cond_t cond_;
+ pthread_mutex_t mutex_;
+ bool event_set_;
+
+ // TODO(pbos): Remove unique_ptr and use PlatformThread directly.
+ std::unique_ptr<rtc::PlatformThread> timer_thread_;
+ std::unique_ptr<EventTimerPosix> timer_event_;
+ timespec created_at_;
+
+ bool periodic_;
+ unsigned long time_ms_;
+ unsigned long count_;
+ bool is_stopping_;
+};
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix_unittest.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix_unittest.cc
new file mode 100644
index 0000000000..e0c5cbc477
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_posix_unittest.cc
@@ -0,0 +1,198 @@
+/*
+ * 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 "system_wrappers/source/event_timer_posix.h"
+
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/event.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+enum class ThreadState {
+ kNotStarted,
+ kWaiting,
+ kRequestProcessCall,
+ kCallingProcess,
+ kProcessDone,
+ kContinue,
+ kExiting,
+ kDead
+};
+
+class EventTimerPosixTest : public testing::Test, public EventTimerPosix {
+ public:
+ EventTimerPosixTest()
+ : thread_state_(ThreadState::kNotStarted),
+ process_event_(false, true),
+ main_event_(false, true),
+ process_thread_id_(0),
+ process_thread_(nullptr) {}
+ virtual ~EventTimerPosixTest() {}
+
+ rtc::PlatformThread* CreateThread() override {
+ EXPECT_TRUE(process_thread_ == nullptr);
+ process_thread_ =
+ new rtc::PlatformThread(Run, this, "EventTimerPosixTestThread");
+ return process_thread_;
+ }
+
+ static bool Run(void* obj) {
+ return static_cast<EventTimerPosixTest*>(obj)->Process();
+ }
+
+ bool Process() {
+ bool res = ProcessInternal();
+ if (!res) {
+ rtc::CritScope cs(&lock_);
+ thread_state_ = ThreadState::kDead;
+ main_event_.Set();
+ }
+ return res;
+ }
+
+ bool ProcessInternal() {
+ {
+ rtc::CritScope cs(&lock_);
+ if (thread_state_ == ThreadState::kNotStarted) {
+ if (!ChangeThreadState(ThreadState::kNotStarted,
+ ThreadState::kContinue)) {
+ ADD_FAILURE() << "Unable to start process thread";
+ return false;
+ }
+ process_thread_id_ = rtc::CurrentThreadId();
+ }
+ }
+
+ if (!ChangeThreadState(ThreadState::kContinue, ThreadState::kWaiting))
+ return false;
+
+ if (!AwaitThreadState(ThreadState::kRequestProcessCall,
+ rtc::Event::kForever))
+ return false;
+
+ if (!ChangeThreadState(ThreadState::kRequestProcessCall,
+ ThreadState::kCallingProcess))
+ return false;
+
+ EventTimerPosix::Process();
+
+ if (!ChangeThreadState(ThreadState::kCallingProcess,
+ ThreadState::kProcessDone))
+ return false;
+
+ if (!AwaitThreadState(ThreadState::kContinue, rtc::Event::kForever))
+ return false;
+
+ return true;
+ }
+
+ bool IsProcessThread() {
+ rtc::CritScope cs(&lock_);
+ return process_thread_id_ == rtc::CurrentThreadId();
+ }
+
+ bool ChangeThreadState(ThreadState prev_state, ThreadState new_state) {
+ rtc::CritScope cs(&lock_);
+ if (thread_state_ != prev_state)
+ return false;
+ thread_state_ = new_state;
+ if (IsProcessThread()) {
+ main_event_.Set();
+ } else {
+ process_event_.Set();
+ }
+ return true;
+ }
+
+ bool AwaitThreadState(ThreadState state, int timeout) {
+ rtc::Event* event = IsProcessThread() ? &process_event_ : &main_event_;
+ do {
+ rtc::CritScope cs(&lock_);
+ if (state != ThreadState::kDead && thread_state_ == ThreadState::kExiting)
+ return false;
+ if (thread_state_ == state)
+ return true;
+ } while (event->Wait(timeout));
+ return false;
+ }
+
+ bool CallProcess(int timeout_ms) {
+ return AwaitThreadState(ThreadState::kWaiting, timeout_ms) &&
+ ChangeThreadState(ThreadState::kWaiting,
+ ThreadState::kRequestProcessCall);
+ }
+
+ bool AwaitProcessDone(int timeout_ms) {
+ return AwaitThreadState(ThreadState::kProcessDone, timeout_ms) &&
+ ChangeThreadState(ThreadState::kProcessDone, ThreadState::kContinue);
+ }
+
+ void TearDown() override {
+ if (process_thread_) {
+ {
+ rtc::CritScope cs(&lock_);
+ if (thread_state_ != ThreadState::kDead) {
+ thread_state_ = ThreadState::kExiting;
+ process_event_.Set();
+ }
+ }
+ ASSERT_TRUE(AwaitThreadState(ThreadState::kDead, 5000));
+ }
+ }
+
+ ThreadState thread_state_;
+ rtc::CriticalSection lock_;
+ rtc::Event process_event_;
+ rtc::Event main_event_;
+ rtc::PlatformThreadId process_thread_id_;
+ rtc::PlatformThread* process_thread_;
+};
+
+TEST_F(EventTimerPosixTest, WaiterBlocksUntilTimeout) {
+ const int kTimerIntervalMs = 100;
+ const int kTimeoutMs = 5000;
+ ASSERT_TRUE(StartTimer(false, kTimerIntervalMs));
+ ASSERT_TRUE(CallProcess(kTimeoutMs));
+ EventTypeWrapper res = Wait(kTimeoutMs);
+ EXPECT_EQ(kEventSignaled, res);
+ ASSERT_TRUE(AwaitProcessDone(kTimeoutMs));
+}
+
+TEST_F(EventTimerPosixTest, WaiterWakesImmediatelyAfterTimeout) {
+ const int kTimerIntervalMs = 100;
+ const int kTimeoutMs = 5000;
+ ASSERT_TRUE(StartTimer(false, kTimerIntervalMs));
+ ASSERT_TRUE(CallProcess(kTimeoutMs));
+ ASSERT_TRUE(AwaitProcessDone(kTimeoutMs));
+ EventTypeWrapper res = Wait(0);
+ EXPECT_EQ(kEventSignaled, res);
+}
+
+TEST_F(EventTimerPosixTest, WaiterBlocksUntilTimeoutProcessInactiveOnStart) {
+ const int kTimerIntervalMs = 100;
+ const int kTimeoutMs = 5000;
+ // First call to StartTimer initializes thread.
+ ASSERT_TRUE(StartTimer(false, kTimerIntervalMs));
+
+ // Process thread currently _not_ blocking on Process() call.
+ ASSERT_TRUE(AwaitThreadState(ThreadState::kWaiting, kTimeoutMs));
+
+ // Start new one-off timer, then call Process().
+ ASSERT_TRUE(StartTimer(false, kTimerIntervalMs));
+ ASSERT_TRUE(CallProcess(kTimeoutMs));
+
+ EventTypeWrapper res = Wait(kTimeoutMs);
+ EXPECT_EQ(kEventSignaled, res);
+
+ ASSERT_TRUE(AwaitProcessDone(kTimeoutMs));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_win.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_win.cc
new file mode 100644
index 0000000000..b6a93feb82
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_win.cc
@@ -0,0 +1,77 @@
+/*
+ * 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/source/event_timer_win.h"
+
+#include "Mmsystem.h"
+
+namespace webrtc {
+
+// static
+EventTimerWrapper* EventTimerWrapper::Create() {
+ return new EventTimerWin();
+}
+
+EventTimerWin::EventTimerWin()
+ : event_(::CreateEvent(NULL, // security attributes
+ FALSE, // manual reset
+ FALSE, // initial state
+ NULL)), // name of event
+ timerID_(NULL) {}
+
+EventTimerWin::~EventTimerWin() {
+ StopTimer();
+ CloseHandle(event_);
+}
+
+bool EventTimerWin::Set() {
+ // Note: setting an event that is already set has no effect.
+ return SetEvent(event_) == 1;
+}
+
+EventTypeWrapper EventTimerWin::Wait(unsigned long max_time) {
+ unsigned long res = WaitForSingleObject(event_, max_time);
+ switch (res) {
+ case WAIT_OBJECT_0:
+ return kEventSignaled;
+ case WAIT_TIMEOUT:
+ return kEventTimeout;
+ default:
+ return kEventError;
+ }
+}
+
+bool EventTimerWin::StartTimer(bool periodic, unsigned long time) {
+ if (timerID_ != NULL) {
+ timeKillEvent(timerID_);
+ timerID_ = NULL;
+ }
+
+ if (periodic) {
+ timerID_ = timeSetEvent(time, 0, (LPTIMECALLBACK)HANDLE(event_), 0,
+ TIME_PERIODIC | TIME_CALLBACK_EVENT_PULSE);
+ } else {
+ timerID_ = timeSetEvent(time, 0, (LPTIMECALLBACK)HANDLE(event_), 0,
+ TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
+ }
+
+ return timerID_ != NULL;
+}
+
+bool EventTimerWin::StopTimer() {
+ if (timerID_ != NULL) {
+ timeKillEvent(timerID_);
+ timerID_ = NULL;
+ }
+
+ return true;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_win.h b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_win.h
new file mode 100644
index 0000000000..5631a3fbc4
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/event_timer_win.h
@@ -0,0 +1,40 @@
+/*
+ * 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_SOURCE_EVENT_WIN_H_
+#define SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
+
+#include <windows.h>
+
+#include "system_wrappers/include/event_wrapper.h"
+
+#include "typedefs.h" // NOLINT(build/include)
+
+namespace webrtc {
+
+class EventTimerWin : public EventTimerWrapper {
+ public:
+ EventTimerWin();
+ virtual ~EventTimerWin();
+
+ virtual EventTypeWrapper Wait(unsigned long max_time);
+ virtual bool Set();
+
+ virtual bool StartTimer(bool periodic, unsigned long time);
+ virtual bool StopTimer();
+
+ private:
+ HANDLE event_;
+ uint32_t timerID_;
+};
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/field_trial_default.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/field_trial_default.cc
new file mode 100644
index 0000000000..e8d8917874
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/field_trial_default.cc
@@ -0,0 +1,65 @@
+// 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_default.h"
+#include "system_wrappers/include/field_trial.h"
+
+#include <string>
+
+// 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;
+
+std::string FindFullName(const std::string& name) {
+ if (trials_init_string == NULL)
+ return std::string();
+
+ std::string trials_string(trials_init_string);
+ if (trials_string.empty())
+ return std::string();
+
+ static const char kPersistentStringSeparator = '/';
+ 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;
+ std::string field_name(trials_string, next_item,
+ field_name_end - next_item);
+ std::string field_value(trials_string, field_name_end + 1,
+ field_value_end - field_name_end - 1);
+ next_item = field_value_end + 1;
+
+ if (name == field_name)
+ return field_value;
+ }
+ return std::string();
+}
+
+// Optionally initialize field trial from a string.
+void InitFieldTrialsFromString(const char* trials_string) {
+ trials_init_string = trials_string;
+}
+
+const char* GetFieldTrialString() {
+ return trials_init_string;
+}
+
+} // namespace field_trial
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/file_impl.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/file_impl.cc
new file mode 100644
index 0000000000..350aaeb15b
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/file_impl.cc
@@ -0,0 +1,152 @@
+/*
+ * 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/file_wrapper.h"
+
+#ifdef _WIN32
+#include <Windows.h>
+#else
+#include <stdarg.h>
+#include <string.h>
+#endif
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+FILE* FileOpen(const char* file_name_utf8, bool read_only) {
+#if defined(_WIN32)
+ int len = MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, nullptr, 0);
+ std::wstring wstr(len, 0);
+ MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, &wstr[0], len);
+ FILE* file = _wfopen(wstr.c_str(), read_only ? L"rb" : L"wb");
+#else
+ FILE* file = fopen(file_name_utf8, read_only ? "rb" : "wb");
+#endif
+ return file;
+}
+} // namespace
+
+// static
+FileWrapper* FileWrapper::Create() {
+ return new FileWrapper();
+}
+
+// static
+FileWrapper FileWrapper::Open(const char* file_name_utf8, bool read_only) {
+ return FileWrapper(FileOpen(file_name_utf8, read_only), 0);
+}
+
+FileWrapper::FileWrapper() {}
+
+FileWrapper::FileWrapper(FILE* file, size_t max_size)
+ : file_(file), max_size_in_bytes_(max_size) {}
+
+FileWrapper::~FileWrapper() {
+ CloseFileImpl();
+}
+
+FileWrapper::FileWrapper(FileWrapper&& other) {
+ operator=(std::move(other));
+}
+
+FileWrapper& FileWrapper::operator=(FileWrapper&& other) {
+ file_ = other.file_;
+ max_size_in_bytes_ = other.max_size_in_bytes_;
+ position_ = other.position_;
+ other.file_ = nullptr;
+ return *this;
+}
+
+void FileWrapper::CloseFile() {
+ rtc::CritScope lock(&lock_);
+ CloseFileImpl();
+}
+
+int FileWrapper::Rewind() {
+ rtc::CritScope lock(&lock_);
+ if (file_ != nullptr) {
+ position_ = 0;
+ return fseek(file_, 0, SEEK_SET);
+ }
+ return -1;
+}
+
+void FileWrapper::SetMaxFileSize(size_t bytes) {
+ rtc::CritScope lock(&lock_);
+ max_size_in_bytes_ = bytes;
+}
+
+int FileWrapper::Flush() {
+ rtc::CritScope lock(&lock_);
+ return FlushImpl();
+}
+
+bool FileWrapper::OpenFile(const char* file_name_utf8, bool read_only) {
+ size_t length = strlen(file_name_utf8);
+ if (length > kMaxFileNameSize - 1)
+ return false;
+
+ rtc::CritScope lock(&lock_);
+ if (file_ != nullptr)
+ return false;
+
+ file_ = FileOpen(file_name_utf8, read_only);
+ return file_ != nullptr;
+}
+
+bool FileWrapper::OpenFromFileHandle(FILE* handle) {
+ if (!handle)
+ return false;
+ rtc::CritScope lock(&lock_);
+ CloseFileImpl();
+ file_ = handle;
+ return true;
+}
+
+int FileWrapper::Read(void* buf, size_t length) {
+ rtc::CritScope lock(&lock_);
+ if (file_ == nullptr)
+ return -1;
+
+ size_t bytes_read = fread(buf, 1, length, file_);
+ return static_cast<int>(bytes_read);
+}
+
+bool FileWrapper::Write(const void* buf, size_t length) {
+ if (buf == nullptr)
+ return false;
+
+ rtc::CritScope lock(&lock_);
+
+ if (file_ == nullptr)
+ return false;
+
+ // Check if it's time to stop writing.
+ if (max_size_in_bytes_ > 0 && (position_ + length) > max_size_in_bytes_)
+ return false;
+
+ size_t num_bytes = fwrite(buf, 1, length, file_);
+ position_ += num_bytes;
+
+ return num_bytes == length;
+}
+
+void FileWrapper::CloseFileImpl() {
+ if (file_ != nullptr)
+ fclose(file_);
+ file_ = nullptr;
+}
+
+int FileWrapper::FlushImpl() {
+ return (file_ != nullptr) ? fflush(file_) : -1;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_default.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_default.cc
new file mode 100644
index 0000000000..fbb2956301
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_default.cc
@@ -0,0 +1,303 @@
+// 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_default.h"
+
+#include <algorithm>
+
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/thread_annotations.h"
+#include "system_wrappers/include/metrics.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(const std::string& name, int min, int max, int bucket_count)
+ : min_(min), max_(max), info_(name, min, max, bucket_count) {
+ RTC_DCHECK_GT(bucket_count, 0);
+ }
+
+ void Add(int sample) {
+ sample = std::min(sample, max_);
+ sample = std::max(sample, min_ - 1); // Underflow bucket.
+
+ rtc::CritScope cs(&crit_);
+ 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() {
+ rtc::CritScope cs(&crit_);
+ 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() {
+ rtc::CritScope cs(&crit_);
+ info_.samples.clear();
+ }
+
+ int NumEvents(int sample) const {
+ rtc::CritScope cs(&crit_);
+ const auto it = info_.samples.find(sample);
+ return (it == info_.samples.end()) ? 0 : it->second;
+ }
+
+ int NumSamples() const {
+ int num_samples = 0;
+ rtc::CritScope cs(&crit_);
+ for (const auto& sample : info_.samples) {
+ num_samples += sample.second;
+ }
+ return num_samples;
+ }
+
+ int MinSample() const {
+ rtc::CritScope cs(&crit_);
+ return (info_.samples.empty()) ? -1 : info_.samples.begin()->first;
+ }
+
+ private:
+ rtc::CriticalSection crit_;
+ const int min_;
+ const int max_;
+ SampleInfo info_ RTC_GUARDED_BY(crit_);
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogram);
+};
+
+class RtcHistogramMap {
+ public:
+ RtcHistogramMap() {}
+ ~RtcHistogramMap() {}
+
+ Histogram* GetCountsHistogram(const std::string& name,
+ int min,
+ int max,
+ int bucket_count) {
+ rtc::CritScope cs(&crit_);
+ 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_[name].reset(hist);
+ return reinterpret_cast<Histogram*>(hist);
+ }
+
+ Histogram* GetEnumerationHistogram(const std::string& name, int boundary) {
+ rtc::CritScope cs(&crit_);
+ 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_[name].reset(hist);
+ return reinterpret_cast<Histogram*>(hist);
+ }
+
+ void GetAndReset(
+ std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) {
+ rtc::CritScope cs(&crit_);
+ 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() {
+ rtc::CritScope cs(&crit_);
+ for (const auto& kv : map_)
+ kv.second->Reset();
+ }
+
+ int NumEvents(const std::string& name, int sample) const {
+ rtc::CritScope cs(&crit_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? 0 : it->second->NumEvents(sample);
+ }
+
+ int NumSamples(const std::string& name) const {
+ rtc::CritScope cs(&crit_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? 0 : it->second->NumSamples();
+ }
+
+ int MinSample(const std::string& name) const {
+ rtc::CritScope cs(&crit_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? -1 : it->second->MinSample();
+ }
+
+ private:
+ rtc::CriticalSection crit_;
+ std::map<std::string, std::unique_ptr<RtcHistogram>> map_
+ RTC_GUARDED_BY(crit_);
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogramMap);
+};
+
+// 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 RtcHistogramMap* volatile g_rtc_histogram_map = nullptr;
+
+void CreateMap() {
+ RtcHistogramMap* map = rtc::AtomicOps::AcquireLoadPtr(&g_rtc_histogram_map);
+ if (map == nullptr) {
+ RtcHistogramMap* new_map = new RtcHistogramMap();
+ RtcHistogramMap* old_map = rtc::AtomicOps::CompareAndSwapPtr(
+ &g_rtc_histogram_map, static_cast<RtcHistogramMap*>(nullptr), new_map);
+ if (old_map != nullptr)
+ 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 volatile int g_rtc_histogram_called = 0;
+#endif
+
+// Gets the map (or nullptr).
+RtcHistogramMap* GetMap() {
+#if RTC_DCHECK_IS_ON
+ rtc::AtomicOps::ReleaseStore(&g_rtc_histogram_called, 1);
+#endif
+ return g_rtc_histogram_map;
+}
+} // namespace
+
+// 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(const std::string& 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(const std::string& 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(const std::string& name,
+ int boundary) {
+ RtcHistogramMap* map = GetMap();
+ if (!map)
+ return nullptr;
+
+ return map->GetEnumerationHistogram(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);
+}
+
+SampleInfo::SampleInfo(const std::string& 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_default.h.
+void Enable() {
+ RTC_DCHECK(g_rtc_histogram_map == nullptr);
+#if RTC_DCHECK_IS_ON
+ RTC_DCHECK_EQ(0, rtc::AtomicOps::AcquireLoad(&g_rtc_histogram_called));
+#endif
+ CreateMap();
+}
+
+void GetAndReset(
+ std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) {
+ histograms->clear();
+ RtcHistogramMap* map = GetMap();
+ if (map)
+ map->GetAndReset(histograms);
+}
+
+void Reset() {
+ RtcHistogramMap* map = GetMap();
+ if (map)
+ map->Reset();
+}
+
+int NumEvents(const std::string& name, int sample) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->NumEvents(name, sample) : 0;
+}
+
+int NumSamples(const std::string& name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->NumSamples(name) : 0;
+}
+
+int MinSample(const std::string& name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->MinSample(name) : -1;
+}
+
+} // namespace metrics
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_default_unittest.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_default_unittest.cc
new file mode 100644
index 0000000000..fa253a9bfe
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_default_unittest.cc
@@ -0,0 +1,161 @@
+/*
+ * 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 "system_wrappers/include/metrics_default.h"
+#include "system_wrappers/include/metrics.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+const int kSample = 22;
+const char kName[] = "Name";
+
+int NumSamples(
+ const std::string& name,
+ const std::map<std::string, std::unique_ptr<metrics::SampleInfo>>&
+ 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(const std::string& name,
+ int sample,
+ const std::map<std::string, std::unique_ptr<metrics::SampleInfo>>&
+ 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:
+ virtual void SetUp() { 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>> 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>> 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
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_unittest.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_unittest.cc
new file mode 100644
index 0000000000..53d43cd2b1
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/metrics_unittest.cc
@@ -0,0 +1,113 @@
+/*
+ * 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 "system_wrappers/include/metrics_default.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+const int kSample = 22;
+
+void AddSparseSample(const std::string& name, int sample) {
+ RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample);
+}
+void AddSampleWithVaryingName(int index, const std::string& name, int sample) {
+ RTC_HISTOGRAMS_COUNTS_100(index, name, sample);
+}
+} // namespace
+
+class MetricsTest : public ::testing::Test {
+ public:
+ MetricsTest() {}
+
+ protected:
+ virtual void SetUp() { metrics::Reset(); }
+};
+
+TEST_F(MetricsTest, InitiallyNoSamples) {
+ EXPECT_EQ(0, metrics::NumSamples("NonExisting"));
+ EXPECT_EQ(0, metrics::NumEvents("NonExisting", kSample));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+TEST_F(MetricsTest, RtcHistogramCounts_AddMultipleSamples) {
+ const std::string kName = "Counts200";
+ const int kNumSamples = 10;
+ 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));
+ }
+}
+
+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));
+}
+
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+TEST_F(MetricsTest, 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"));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/ntp_time_unittest.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/ntp_time_unittest.cc
new file mode 100644
index 0000000000..7be464d02d
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/ntp_time_unittest.cc
@@ -0,0 +1,65 @@
+/*
+ * 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 "system_wrappers/include/clock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+const uint32_t kNtpSec = 0x12345678;
+const uint32_t kNtpFrac = 0x23456789;
+
+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::NtpToMs(ntp.seconds(), ntp.fractions()));
+ 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));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/rtp_to_ntp_estimator.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/rtp_to_ntp_estimator.cc
new file mode 100644
index 0000000000..21f64eca25
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/rtp_to_ntp_estimator.cc
@@ -0,0 +1,205 @@
+/*
+ * 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 "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+namespace {
+// Number of RTCP SR reports to use to map between RTP and NTP.
+const size_t kNumRtcpReportsToUse = 2;
+// Number of parameters samples used to smooth.
+const size_t kNumSamplesToSmooth = 20;
+
+
+// Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps.
+bool CalculateFrequency(int64_t ntp_ms1,
+ uint32_t rtp_timestamp1,
+ int64_t ntp_ms2,
+ uint32_t rtp_timestamp2,
+ double* frequency_khz) {
+ if (ntp_ms1 <= ntp_ms2)
+ return false;
+
+ *frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) /
+ static_cast<double>(ntp_ms1 - ntp_ms2);
+ return true;
+}
+
+bool Contains(const std::list<RtpToNtpEstimator::RtcpMeasurement>& measurements,
+ const RtpToNtpEstimator::RtcpMeasurement& other) {
+ for (const auto& measurement : measurements) {
+ if (measurement.IsEqual(other))
+ return true;
+ }
+ return false;
+}
+} // namespace
+
+bool RtpToNtpEstimator::Parameters::operator<(const Parameters& other) const {
+ if (frequency_khz < other.frequency_khz - 1e-6) {
+ return true;
+ } else if (frequency_khz > other.frequency_khz + 1e-6) {
+ return false;
+ } else {
+ return offset_ms < other.offset_ms - 1e-6;
+ }
+}
+
+bool RtpToNtpEstimator::Parameters::operator==(const Parameters& other) const {
+ return !(other < *this || *this < other);
+}
+
+bool RtpToNtpEstimator::Parameters::operator!=(const Parameters& other) const {
+ return other < *this || *this < other;
+}
+
+bool RtpToNtpEstimator::Parameters::operator<=(const Parameters& other) const {
+ return !(other < *this);
+}
+
+RtpToNtpEstimator::RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs,
+ uint32_t ntp_frac,
+ int64_t unwrapped_timestamp)
+ : ntp_time(ntp_secs, ntp_frac),
+ unwrapped_rtp_timestamp(unwrapped_timestamp) {}
+
+bool RtpToNtpEstimator::RtcpMeasurement::IsEqual(
+ const RtcpMeasurement& other) const {
+ // Use || since two equal timestamps will result in zero frequency and in
+ // RtpToNtpMs, |rtp_timestamp_ms| is estimated by dividing by the frequency.
+ return (ntp_time == other.ntp_time) ||
+ (unwrapped_rtp_timestamp == other.unwrapped_rtp_timestamp);
+}
+
+// Class for converting an RTP timestamp to the NTP domain.
+RtpToNtpEstimator::RtpToNtpEstimator()
+ : consecutive_invalid_samples_(0),
+ smoothing_filter_(kNumSamplesToSmooth),
+ params_calculated_(false) {}
+
+RtpToNtpEstimator::~RtpToNtpEstimator() {}
+
+void RtpToNtpEstimator::UpdateParameters() {
+ if (measurements_.size() != kNumRtcpReportsToUse)
+ return;
+
+ Parameters params;
+ int64_t timestamp_new = measurements_.front().unwrapped_rtp_timestamp;
+ int64_t timestamp_old = measurements_.back().unwrapped_rtp_timestamp;
+
+ int64_t ntp_ms_new = measurements_.front().ntp_time.ToMs();
+ int64_t ntp_ms_old = measurements_.back().ntp_time.ToMs();
+
+ if (!CalculateFrequency(ntp_ms_new, timestamp_new, ntp_ms_old, timestamp_old,
+ &params.frequency_khz)) {
+ return;
+ }
+ params.offset_ms = timestamp_new - params.frequency_khz * ntp_ms_new;
+ params_calculated_ = true;
+ smoothing_filter_.Insert(params);
+}
+
+bool RtpToNtpEstimator::UpdateMeasurements(uint32_t ntp_secs,
+ uint32_t ntp_frac,
+ uint32_t rtp_timestamp,
+ bool* new_rtcp_sr) {
+ *new_rtcp_sr = false;
+
+ int64_t unwrapped_rtp_timestamp = unwrapper_.Unwrap(rtp_timestamp);
+
+ RtcpMeasurement new_measurement(ntp_secs, ntp_frac, unwrapped_rtp_timestamp);
+
+ if (Contains(measurements_, new_measurement)) {
+ // RTCP SR report already added.
+ return true;
+ }
+
+ if (!new_measurement.ntp_time.Valid())
+ return false;
+
+ int64_t ntp_ms_new = new_measurement.ntp_time.ToMs();
+ bool invalid_sample = false;
+ if (!measurements_.empty()) {
+ int64_t old_rtp_timestamp = measurements_.front().unwrapped_rtp_timestamp;
+ int64_t old_ntp_ms = measurements_.front().ntp_time.ToMs();
+ if (ntp_ms_new <= old_ntp_ms) {
+ 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 false;
+ }
+ RTC_LOG(LS_WARNING) << "Multiple consecutively invalid RTCP SR reports, "
+ "clearing measurements.";
+ measurements_.clear();
+ smoothing_filter_.Reset();
+ params_calculated_ = false;
+ }
+ consecutive_invalid_samples_ = 0;
+
+ // Insert new RTCP SR report.
+ if (measurements_.size() == kNumRtcpReportsToUse)
+ measurements_.pop_back();
+
+ measurements_.push_front(new_measurement);
+ *new_rtcp_sr = true;
+
+ // List updated, calculate new parameters.
+ UpdateParameters();
+ return true;
+}
+
+bool RtpToNtpEstimator::Estimate(int64_t rtp_timestamp,
+ int64_t* rtp_timestamp_ms) const {
+ if (!params_calculated_)
+ return false;
+
+ int64_t rtp_timestamp_unwrapped = unwrapper_.Unwrap(rtp_timestamp);
+
+ Parameters params = smoothing_filter_.GetFilteredValue();
+
+ // params_calculated_ should not be true unless ms params.frequency_khz has
+ // been calculated to something non zero.
+ RTC_DCHECK_NE(params.frequency_khz, 0.0);
+ double rtp_ms =
+ (static_cast<double>(rtp_timestamp_unwrapped) - params.offset_ms) /
+ params.frequency_khz +
+ 0.5f;
+
+ if (rtp_ms < 0)
+ return false;
+
+ *rtp_timestamp_ms = rtp_ms;
+ return true;
+}
+
+const rtc::Optional<RtpToNtpEstimator::Parameters> RtpToNtpEstimator::params()
+ const {
+ rtc::Optional<Parameters> res;
+ if (params_calculated_) {
+ res.emplace(smoothing_filter_.GetFilteredValue());
+ }
+ return res;
+}
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
new file mode 100644
index 0000000000..0647ec8cad
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
@@ -0,0 +1,295 @@
+/*
+ * 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 "test/gtest.h"
+
+namespace webrtc {
+namespace {
+const uint32_t kOneMsInNtpFrac = 4294967;
+const uint32_t kTimestampTicksPerMs = 90;
+} // namespace
+
+TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp) {
+ RtpToNtpEstimator estimator;
+ bool new_sr;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 1;
+ uint32_t timestamp = 0;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= kTimestampTicksPerMs;
+ // 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_FALSE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+}
+
+TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp_Wraparound_Detected) {
+ RtpToNtpEstimator estimator;
+ bool new_sr;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 1;
+ uint32_t timestamp = 0xFFFFFFFE;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += 2 * kOneMsInNtpFrac;
+ timestamp += 2 * kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= kTimestampTicksPerMs;
+ // Expected to fail since the older RTCP has a smaller RTP timestamp than the
+ // newer (old:10, new:4294967206).
+ EXPECT_FALSE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+}
+
+TEST(WrapAroundTests, NewRtcpWrapped) {
+ RtpToNtpEstimator estimator;
+ bool new_sr;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 1;
+ uint32_t timestamp = 0xFFFFFFFF;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ int64_t timestamp_ms = -1;
+ EXPECT_TRUE(estimator.Estimate(0xFFFFFFFF, &timestamp_ms));
+ // 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(0, timestamp_ms);
+}
+
+TEST(WrapAroundTests, RtpWrapped) {
+ RtpToNtpEstimator estimator;
+ bool new_sr;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 1;
+ uint32_t timestamp = 0xFFFFFFFF - 2 * kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+
+ int64_t timestamp_ms = -1;
+ EXPECT_TRUE(
+ estimator.Estimate(0xFFFFFFFF - 2 * kTimestampTicksPerMs, &timestamp_ms));
+ // 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(0, timestamp_ms);
+ // Two kTimestampTicksPerMs advanced.
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
+ EXPECT_EQ(2, timestamp_ms);
+ // Wrapped rtp.
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
+ EXPECT_EQ(3, timestamp_ms);
+}
+
+TEST(WrapAroundTests, OldRtp_RtcpsWrapped) {
+ RtpToNtpEstimator estimator;
+ bool new_sr;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 1;
+ uint32_t timestamp = 0xFFFFFFFF;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ timestamp -= 2 * kTimestampTicksPerMs;
+ int64_t timestamp_ms = 0xFFFFFFFF;
+ EXPECT_FALSE(estimator.Estimate(timestamp, &timestamp_ms));
+}
+
+TEST(WrapAroundTests, OldRtp_NewRtcpWrapped) {
+ RtpToNtpEstimator estimator;
+ bool new_sr;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 1;
+ uint32_t timestamp = 0xFFFFFFFF;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ timestamp -= kTimestampTicksPerMs;
+ int64_t timestamp_ms = -1;
+ EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
+ // Constructed at the same time as the first RTCP and should therefore be
+ // mapped to zero.
+ EXPECT_EQ(0, timestamp_ms);
+}
+
+TEST(WrapAroundTests, GracefullyHandleRtpJump) {
+ RtpToNtpEstimator estimator;
+ bool new_sr;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 1;
+ uint32_t timestamp = 0;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= kTimestampTicksPerMs;
+ int64_t timestamp_ms = -1;
+ EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
+ // Constructed at the same time as the first RTCP and should therefore be
+ // mapped to zero.
+ EXPECT_EQ(0, timestamp_ms);
+
+ timestamp -= 0xFFFFF;
+ for (int i = 0; i < RtpToNtpEstimator::kMaxInvalidSamples - 1; ++i) {
+ EXPECT_FALSE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ }
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+
+ timestamp_ms = -1;
+ EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
+ // 6 milliseconds has passed since the start of the test.
+ EXPECT_EQ(6, timestamp_ms);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForZeroNtp) {
+ RtpToNtpEstimator estimator;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 0;
+ uint32_t timestamp = 0x12345678;
+ bool new_sr;
+ EXPECT_FALSE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_FALSE(new_sr);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForEqualNtp) {
+ RtpToNtpEstimator estimator;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 699925050;
+ uint32_t timestamp = 0x12345678;
+ bool new_sr;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_TRUE(new_sr);
+ // Ntp time already added, list not updated.
+ ++timestamp;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_FALSE(new_sr);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForOldNtp) {
+ RtpToNtpEstimator estimator;
+ uint32_t ntp_sec = 1;
+ uint32_t ntp_frac = 699925050;
+ uint32_t timestamp = 0x12345678;
+ bool new_sr;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_TRUE(new_sr);
+ // Old ntp time, list not updated.
+ ntp_frac -= kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_FALSE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForEqualTimestamp) {
+ RtpToNtpEstimator estimator;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 2;
+ uint32_t timestamp = 0x12345678;
+ bool new_sr;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_TRUE(new_sr);
+ // Timestamp already added, list not updated.
+ ++ntp_frac;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_FALSE(new_sr);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForOldRtpTimestamp) {
+ RtpToNtpEstimator estimator;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 2;
+ uint32_t timestamp = 0x12345678;
+ bool new_sr;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_TRUE(new_sr);
+ // Old timestamp, list not updated.
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= kTimestampTicksPerMs;
+ EXPECT_FALSE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_FALSE(new_sr);
+}
+
+TEST(UpdateRtcpMeasurementTests, VerifyParameters) {
+ RtpToNtpEstimator estimator;
+ uint32_t ntp_sec = 1;
+ uint32_t ntp_frac = 2;
+ uint32_t timestamp = 0x12345678;
+ bool new_sr;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_TRUE(new_sr);
+ EXPECT_FALSE(estimator.params());
+ // Add second report, parameters should be calculated.
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_TRUE(estimator.params());
+ EXPECT_DOUBLE_EQ(90.0, estimator.params()->frequency_khz);
+ EXPECT_NE(0.0, estimator.params()->offset_ms);
+}
+
+TEST(RtpToNtpTests, FailsForNoParameters) {
+ RtpToNtpEstimator estimator;
+ uint32_t ntp_sec = 1;
+ uint32_t ntp_frac = 2;
+ uint32_t timestamp = 0x12345678;
+ bool new_sr;
+ EXPECT_TRUE(
+ estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+ EXPECT_TRUE(new_sr);
+ // Parameters are not calculated, conversion of RTP to NTP time should fail.
+ EXPECT_FALSE(estimator.params());
+ int64_t timestamp_ms = -1;
+ EXPECT_FALSE(estimator.Estimate(timestamp, &timestamp_ms));
+}
+
+}; // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock.cc
new file mode 100644
index 0000000000..c38c44ad75
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock.cc
@@ -0,0 +1,31 @@
+/*
+ * 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/rw_lock_wrapper.h"
+
+#include <assert.h>
+
+#if defined(_WIN32)
+#include "system_wrappers/source/rw_lock_win.h"
+#else
+#include "system_wrappers/source/rw_lock_posix.h"
+#endif
+
+namespace webrtc {
+
+RWLockWrapper* RWLockWrapper::CreateRWLock() {
+#ifdef _WIN32
+ return RWLockWin::Create();
+#else
+ return RWLockPosix::Create();
+#endif
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_posix.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_posix.cc
new file mode 100644
index 0000000000..412873c770
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_posix.cc
@@ -0,0 +1,50 @@
+/*
+ * 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/source/rw_lock_posix.h"
+
+namespace webrtc {
+
+RWLockPosix::RWLockPosix() : lock_() {}
+
+RWLockPosix::~RWLockPosix() {
+ pthread_rwlock_destroy(&lock_);
+}
+
+RWLockPosix* RWLockPosix::Create() {
+ RWLockPosix* ret_val = new RWLockPosix();
+ if (!ret_val->Init()) {
+ delete ret_val;
+ return NULL;
+ }
+ return ret_val;
+}
+
+bool RWLockPosix::Init() {
+ return pthread_rwlock_init(&lock_, 0) == 0;
+}
+
+void RWLockPosix::AcquireLockExclusive() {
+ pthread_rwlock_wrlock(&lock_);
+}
+
+void RWLockPosix::ReleaseLockExclusive() {
+ pthread_rwlock_unlock(&lock_);
+}
+
+void RWLockPosix::AcquireLockShared() {
+ pthread_rwlock_rdlock(&lock_);
+}
+
+void RWLockPosix::ReleaseLockShared() {
+ pthread_rwlock_unlock(&lock_);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_posix.h b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_posix.h
new file mode 100644
index 0000000000..d15682b928
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_posix.h
@@ -0,0 +1,41 @@
+/*
+ * 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_SOURCE_RW_LOCK_POSIX_H_
+#define SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
+
+#include "system_wrappers/include/rw_lock_wrapper.h"
+#include "typedefs.h" // NOLINT(build/include)
+
+#include <pthread.h>
+
+namespace webrtc {
+
+class RWLockPosix : public RWLockWrapper {
+ public:
+ static RWLockPosix* Create();
+ ~RWLockPosix() override;
+
+ void AcquireLockExclusive() override;
+ void ReleaseLockExclusive() override;
+
+ void AcquireLockShared() override;
+ void ReleaseLockShared() override;
+
+ private:
+ RWLockPosix();
+ bool Init();
+
+ pthread_rwlock_t lock_;
+};
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_win.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_win.cc
new file mode 100644
index 0000000000..23df15a275
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_win.cc
@@ -0,0 +1,95 @@
+/*
+ * 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/source/rw_lock_win.h"
+
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+static bool native_rw_locks_supported = false;
+static bool module_load_attempted = false;
+static HMODULE library = NULL;
+
+typedef void(WINAPI* InitializeSRWLock)(PSRWLOCK);
+
+typedef void(WINAPI* AcquireSRWLockExclusive)(PSRWLOCK);
+typedef void(WINAPI* ReleaseSRWLockExclusive)(PSRWLOCK);
+
+typedef void(WINAPI* AcquireSRWLockShared)(PSRWLOCK);
+typedef void(WINAPI* ReleaseSRWLockShared)(PSRWLOCK);
+
+InitializeSRWLock initialize_srw_lock;
+AcquireSRWLockExclusive acquire_srw_lock_exclusive;
+AcquireSRWLockShared acquire_srw_lock_shared;
+ReleaseSRWLockShared release_srw_lock_shared;
+ReleaseSRWLockExclusive release_srw_lock_exclusive;
+
+RWLockWin::RWLockWin() {
+ initialize_srw_lock(&lock_);
+}
+
+RWLockWin* RWLockWin::Create() {
+ if (!LoadModule()) {
+ return NULL;
+ }
+ return new RWLockWin();
+}
+
+void RWLockWin::AcquireLockExclusive() {
+ acquire_srw_lock_exclusive(&lock_);
+}
+
+void RWLockWin::ReleaseLockExclusive() {
+ release_srw_lock_exclusive(&lock_);
+}
+
+void RWLockWin::AcquireLockShared() {
+ acquire_srw_lock_shared(&lock_);
+}
+
+void RWLockWin::ReleaseLockShared() {
+ release_srw_lock_shared(&lock_);
+}
+
+bool RWLockWin::LoadModule() {
+ if (module_load_attempted) {
+ return native_rw_locks_supported;
+ }
+ module_load_attempted = true;
+ // Use native implementation if supported (i.e Vista+)
+ library = LoadLibrary(TEXT("Kernel32.dll"));
+ if (!library) {
+ return false;
+ }
+ RTC_LOG(LS_VERBOSE) << "Loaded Kernel.dll";
+
+ initialize_srw_lock =
+ (InitializeSRWLock)GetProcAddress(library, "InitializeSRWLock");
+
+ acquire_srw_lock_exclusive = (AcquireSRWLockExclusive)GetProcAddress(
+ library, "AcquireSRWLockExclusive");
+ release_srw_lock_exclusive = (ReleaseSRWLockExclusive)GetProcAddress(
+ library, "ReleaseSRWLockExclusive");
+ acquire_srw_lock_shared =
+ (AcquireSRWLockShared)GetProcAddress(library, "AcquireSRWLockShared");
+ release_srw_lock_shared =
+ (ReleaseSRWLockShared)GetProcAddress(library, "ReleaseSRWLockShared");
+
+ if (initialize_srw_lock && acquire_srw_lock_exclusive &&
+ release_srw_lock_exclusive && acquire_srw_lock_shared &&
+ release_srw_lock_shared) {
+ RTC_LOG(LS_VERBOSE) << "Loaded Native RW Lock";
+ native_rw_locks_supported = true;
+ }
+ return native_rw_locks_supported;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_win.h b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_win.h
new file mode 100644
index 0000000000..41537ba10b
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/rw_lock_win.h
@@ -0,0 +1,40 @@
+/*
+ * 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_SOURCE_RW_LOCK_WIN_H_
+#define SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
+
+#include "system_wrappers/include/rw_lock_wrapper.h"
+
+#include <Windows.h>
+
+namespace webrtc {
+
+class RWLockWin : public RWLockWrapper {
+ public:
+ static RWLockWin* Create();
+ ~RWLockWin() {}
+
+ virtual void AcquireLockExclusive();
+ virtual void ReleaseLockExclusive();
+
+ virtual void AcquireLockShared();
+ virtual void ReleaseLockShared();
+
+ private:
+ RWLockWin();
+ static bool LoadModule();
+
+ SRWLOCK lock_;
+};
+
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
diff --git a/third_party/libwebrtc/webrtc/system_wrappers/source/sleep.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/sleep.cc
new file mode 100644
index 0000000000..e2fa486118
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/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/webrtc/system_wrappers/source/timestamp_extrapolator.cc b/third_party/libwebrtc/webrtc/system_wrappers/source/timestamp_extrapolator.cc
new file mode 100644
index 0000000000..b8c6ba0934
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/system_wrappers/source/timestamp_extrapolator.cc
@@ -0,0 +1,208 @@
+/*
+ * 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/timestamp_extrapolator.h"
+
+#include <algorithm>
+
+namespace webrtc {
+
+TimestampExtrapolator::TimestampExtrapolator(int64_t start_ms)
+ : _rwLock(RWLockWrapper::CreateRWLock()),
+ _startMs(0),
+ _firstTimestamp(0),
+ _wrapArounds(0),
+ _prevUnwrappedTimestamp(-1),
+ _prevWrapTimestamp(-1),
+ _lambda(1),
+ _firstAfterReset(true),
+ _packetCount(0),
+ _startUpFilterDelayInPackets(2),
+ _detectorAccumulatorPos(0),
+ _detectorAccumulatorNeg(0),
+ _alarmThreshold(60e3),
+ _accDrift(6600), // in timestamp ticks, i.e. 15 ms
+ _accMaxError(7000),
+ _pP11(1e10) {
+ Reset(start_ms);
+}
+
+TimestampExtrapolator::~TimestampExtrapolator() {
+ delete _rwLock;
+}
+
+void TimestampExtrapolator::Reset(int64_t start_ms) {
+ WriteLockScoped wl(*_rwLock);
+ _startMs = start_ms;
+ _prevMs = _startMs;
+ _firstTimestamp = 0;
+ _w[0] = 90.0;
+ _w[1] = 0;
+ _pP[0][0] = 1;
+ _pP[1][1] = _pP11;
+ _pP[0][1] = _pP[1][0] = 0;
+ _firstAfterReset = true;
+ _prevUnwrappedTimestamp = -1;
+ _prevWrapTimestamp = -1;
+ _wrapArounds = 0;
+ _packetCount = 0;
+ _detectorAccumulatorPos = 0;
+ _detectorAccumulatorNeg = 0;
+}
+
+void TimestampExtrapolator::Update(int64_t tMs, uint32_t ts90khz) {
+ _rwLock->AcquireLockExclusive();
+ if (tMs - _prevMs > 10e3) {
+ // Ten seconds without a complete frame.
+ // Reset the extrapolator
+ _rwLock->ReleaseLockExclusive();
+ Reset(tMs);
+ _rwLock->AcquireLockExclusive();
+ } else {
+ _prevMs = tMs;
+ }
+
+ // Remove offset to prevent badly scaled matrices
+ tMs -= _startMs;
+
+ CheckForWrapArounds(ts90khz);
+
+ int64_t unwrapped_ts90khz =
+ static_cast<int64_t>(ts90khz) +
+ _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
+
+ if (_firstAfterReset) {
+ // Make an initial guess of the offset,
+ // should be almost correct since tMs - _startMs
+ // should about zero at this time.
+ _w[1] = -_w[0] * tMs;
+ _firstTimestamp = unwrapped_ts90khz;
+ _firstAfterReset = false;
+ }
+
+ double residual = (static_cast<double>(unwrapped_ts90khz) - _firstTimestamp) -
+ static_cast<double>(tMs) * _w[0] - _w[1];
+ if (DelayChangeDetection(residual) &&
+ _packetCount >= _startUpFilterDelayInPackets) {
+ // A sudden change of average network delay has been detected.
+ // Force the filter to adjust its offset parameter by changing
+ // the offset uncertainty. Don't do this during startup.
+ _pP[1][1] = _pP11;
+ }
+
+ if (_prevUnwrappedTimestamp >= 0 &&
+ unwrapped_ts90khz < _prevUnwrappedTimestamp) {
+ // Drop reordered frames.
+ _rwLock->ReleaseLockExclusive();
+ return;
+ }
+
+ // T = [t(k) 1]';
+ // that = T'*w;
+ // K = P*T/(lambda + T'*P*T);
+ double K[2];
+ K[0] = _pP[0][0] * tMs + _pP[0][1];
+ K[1] = _pP[1][0] * tMs + _pP[1][1];
+ double TPT = _lambda + tMs * K[0] + K[1];
+ K[0] /= TPT;
+ K[1] /= TPT;
+ // w = w + K*(ts(k) - that);
+ _w[0] = _w[0] + K[0] * residual;
+ _w[1] = _w[1] + K[1] * residual;
+ // P = 1/lambda*(P - K*T'*P);
+ double p00 =
+ 1 / _lambda * (_pP[0][0] - (K[0] * tMs * _pP[0][0] + K[0] * _pP[1][0]));
+ double p01 =
+ 1 / _lambda * (_pP[0][1] - (K[0] * tMs * _pP[0][1] + K[0] * _pP[1][1]));
+ _pP[1][0] =
+ 1 / _lambda * (_pP[1][0] - (K[1] * tMs * _pP[0][0] + K[1] * _pP[1][0]));
+ _pP[1][1] =
+ 1 / _lambda * (_pP[1][1] - (K[1] * tMs * _pP[0][1] + K[1] * _pP[1][1]));
+ _pP[0][0] = p00;
+ _pP[0][1] = p01;
+ _prevUnwrappedTimestamp = unwrapped_ts90khz;
+ if (_packetCount < _startUpFilterDelayInPackets) {
+ _packetCount++;
+ }
+ _rwLock->ReleaseLockExclusive();
+}
+
+int64_t TimestampExtrapolator::ExtrapolateLocalTime(uint32_t timestamp90khz) {
+ ReadLockScoped rl(*_rwLock);
+ int64_t localTimeMs = 0;
+ CheckForWrapArounds(timestamp90khz);
+ double unwrapped_ts90khz =
+ static_cast<double>(timestamp90khz) +
+ _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
+ if (_packetCount == 0) {
+ localTimeMs = -1;
+ } else if (_packetCount < _startUpFilterDelayInPackets) {
+ localTimeMs =
+ _prevMs +
+ static_cast<int64_t>(
+ static_cast<double>(unwrapped_ts90khz - _prevUnwrappedTimestamp) /
+ 90.0 +
+ 0.5);
+ } else {
+ if (_w[0] < 1e-3) {
+ localTimeMs = _startMs;
+ } else {
+ double timestampDiff =
+ unwrapped_ts90khz - static_cast<double>(_firstTimestamp);
+ localTimeMs = static_cast<int64_t>(static_cast<double>(_startMs) +
+ (timestampDiff - _w[1]) / _w[0] + 0.5);
+ }
+ }
+ return localTimeMs;
+}
+
+// Investigates if the timestamp clock has overflowed since the last timestamp
+// and keeps track of the number of wrap arounds since reset.
+void TimestampExtrapolator::CheckForWrapArounds(uint32_t ts90khz) {
+ if (_prevWrapTimestamp == -1) {
+ _prevWrapTimestamp = ts90khz;
+ return;
+ }
+ if (ts90khz < _prevWrapTimestamp) {
+ // This difference will probably be less than -2^31 if we have had a wrap
+ // around (e.g. timestamp = 1, _previousTimestamp = 2^32 - 1). Since it is
+ // casted to a Word32, it should be positive.
+ if (static_cast<int32_t>(ts90khz - _prevWrapTimestamp) > 0) {
+ // Forward wrap around
+ _wrapArounds++;
+ }
+ }
+ // This difference will probably be less than -2^31 if we have had a backward
+ // wrap around. Since it is casted to a Word32, it should be positive.
+ else if (static_cast<int32_t>(_prevWrapTimestamp - ts90khz) > 0) {
+ // Backward wrap around
+ _wrapArounds--;
+ }
+ _prevWrapTimestamp = ts90khz;
+}
+
+bool TimestampExtrapolator::DelayChangeDetection(double error) {
+ // CUSUM detection of sudden delay changes
+ error = (error > 0) ? std::min(error, _accMaxError)
+ : std::max(error, -_accMaxError);
+ _detectorAccumulatorPos =
+ std::max(_detectorAccumulatorPos + error - _accDrift, (double)0);
+ _detectorAccumulatorNeg =
+ std::min(_detectorAccumulatorNeg + error + _accDrift, (double)0);
+ if (_detectorAccumulatorPos > _alarmThreshold ||
+ _detectorAccumulatorNeg < -_alarmThreshold) {
+ // Alarm
+ _detectorAccumulatorPos = _detectorAccumulatorNeg = 0;
+ return true;
+ }
+ return false;
+}
+
+} // namespace webrtc