Moving src/webrtc into src/.

In order to eliminate the WebRTC Subtree mirror in Chromium, 
WebRTC is moving the content of the src/webrtc directory up
to the src/ directory.

NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
TBR=tommi@webrtc.org

Bug: chromium:611808
Change-Id: Iac59c5b51b950f174119565bac87955a7994bc38
Reviewed-on: https://webrtc-review.googlesource.com/1560
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Henrik Kjellander <kjellander@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#19845}
This commit is contained in:
Mirko Bonadei
2017-09-15 06:15:48 +02:00
committed by Commit Bot
parent 6674846b4a
commit bb547203bf
4576 changed files with 1092 additions and 1196 deletions

View File

@ -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 "webrtc/system_wrappers/include/aligned_array.h"
#include <stdint.h>
#include "webrtc/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

View File

@ -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 "webrtc/system_wrappers/include/aligned_malloc.h"
#include <memory.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <stdint.h>
#endif
#include "webrtc/typedefs.h"
// 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

View File

@ -0,0 +1,83 @@
/*
* 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 "webrtc/system_wrappers/include/aligned_malloc.h"
#include <memory>
#ifdef _WIN32
#include <windows.h>
#else
#include <stdint.h>
#endif
#include "webrtc/test/gtest.h"
#include "webrtc/typedefs.h"
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

View File

@ -0,0 +1,49 @@
/*
* 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 "webrtc/system_wrappers/include/atomic32.h"
#include <assert.h>
#include <libkern/OSAtomic.h>
#include <stdlib.h>
#include "webrtc/common_types.h"
namespace webrtc {
Atomic32::Atomic32(int32_t initial_value)
: value_(initial_value) {
assert(Is32bitAligned());
}
Atomic32::~Atomic32() {
}
int32_t Atomic32::operator++() {
return OSAtomicIncrement32Barrier(&value_);
}
int32_t Atomic32::operator--() {
return OSAtomicDecrement32Barrier(&value_);
}
int32_t Atomic32::operator+=(int32_t value) {
return OSAtomicAdd32Barrier(value, &value_);
}
int32_t Atomic32::operator-=(int32_t value) {
return OSAtomicAdd32Barrier(-value, &value_);
}
bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
return OSAtomicCompareAndSwap32Barrier(compare_value, new_value, &value_);
}
} // namespace webrtc

View File

@ -0,0 +1,53 @@
/*
* 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 "webrtc/system_wrappers/include/atomic32.h"
#include <assert.h>
#include <inttypes.h>
#include <malloc.h>
#include "webrtc/common_types.h"
namespace webrtc {
Atomic32::Atomic32(int32_t initial_value)
: value_(initial_value) {
assert(Is32bitAligned());
}
Atomic32::~Atomic32() {
}
int32_t Atomic32::operator++() {
return __sync_fetch_and_add(&value_, 1) + 1;
}
int32_t Atomic32::operator--() {
return __sync_fetch_and_sub(&value_, 1) - 1;
}
int32_t Atomic32::operator+=(int32_t value) {
int32_t return_value = __sync_fetch_and_add(&value_, value);
return_value += value;
return return_value;
}
int32_t Atomic32::operator-=(int32_t value) {
int32_t return_value = __sync_fetch_and_sub(&value_, value);
return_value -= value;
return return_value;
}
bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
return __sync_bool_compare_and_swap(&value_, compare_value, new_value);
}
} // namespace webrtc

View File

@ -0,0 +1,60 @@
/*
* 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 "webrtc/system_wrappers/include/atomic32.h"
#include <assert.h>
#include <windows.h>
#include "webrtc/common_types.h"
namespace webrtc {
Atomic32::Atomic32(int32_t initial_value)
: value_(initial_value) {
static_assert(sizeof(value_) == sizeof(LONG),
"counter variable is the expected size");
assert(Is32bitAligned());
}
Atomic32::~Atomic32() {
}
int32_t Atomic32::operator++() {
return static_cast<int32_t>(InterlockedIncrement(
reinterpret_cast<volatile LONG*>(&value_)));
}
int32_t Atomic32::operator--() {
return static_cast<int32_t>(InterlockedDecrement(
reinterpret_cast<volatile LONG*>(&value_)));
}
int32_t Atomic32::operator+=(int32_t value) {
return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&value_),
value);
}
int32_t Atomic32::operator-=(int32_t value) {
return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&value_),
-value);
}
bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
const LONG old_value = InterlockedCompareExchange(
reinterpret_cast<volatile LONG*>(&value_),
new_value,
compare_value);
// If the old value and the compare value is the same an exchange happened.
return (old_value == compare_value);
}
} // namespace webrtc

View File

@ -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 "webrtc/system_wrappers/include/clock.h"
#if defined(_WIN32)
// Windows needs to be included before mmsystem.h
#include "webrtc/rtc_base/win32.h"
#include <MMSystem.h>
#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
#include <sys/time.h>
#include <time.h>
#endif
#include "webrtc/rtc_base/criticalsection.h"
#include "webrtc/rtc_base/timeutils.h"
#include "webrtc/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))
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_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

View File

@ -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 "webrtc/system_wrappers/include/clock.h"
#include "webrtc/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

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Parts of this file derived from Chromium's base/cpu.cc.
#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER)
#include <intrin.h>
#endif
#include "webrtc/typedefs.h"
// 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;

View File

@ -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();
}

View File

@ -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 "webrtc/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

View File

@ -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 "webrtc/system_wrappers/include/cpu_info.h"
#if defined(WEBRTC_WIN)
#include <winsock2.h>
#include <windows.h>
#ifndef EXCLUDE_D3D9
#include <d3d9.h>
#endif
#elif defined(WEBRTC_LINUX)
#include <unistd.h>
#endif
#if defined(WEBRTC_MAC)
#include <sys/sysctl.h>
#endif
#include "webrtc/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)
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)) {
LOG(LS_ERROR) << "Failed to get number of cores";
number_of_cores = 1;
}
#else
LOG(LS_ERROR) << "No function to get number of cores";
#endif
LOG(LS_INFO) << "Available number of cores: " << number_of_cores;
return number_of_cores;
}
}
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

View File

@ -0,0 +1,54 @@
/*
* 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 "webrtc/system_wrappers/include/event_wrapper.h"
#if defined(_WIN32)
#include <windows.h>
#include "webrtc/system_wrappers/source/event_timer_win.h"
#elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
#include <ApplicationServices/ApplicationServices.h>
#include <pthread.h>
#include "webrtc/system_wrappers/source/event_timer_posix.h"
#else
#include <pthread.h>
#include "webrtc/system_wrappers/source/event_timer_posix.h"
#endif
#include "webrtc/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

View File

@ -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 "webrtc/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 "webrtc/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

View File

@ -0,0 +1,67 @@
/*
* 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
#include "webrtc/system_wrappers/include/event_wrapper.h"
#include <memory>
#include <pthread.h>
#include <time.h>
#include "webrtc/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 // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_

View File

@ -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 "webrtc/system_wrappers/source/event_timer_posix.h"
#include "webrtc/rtc_base/criticalsection.h"
#include "webrtc/rtc_base/event.h"
#include "webrtc/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

View File

@ -0,0 +1,78 @@
/*
* 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 "webrtc/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

View File

@ -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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
#include <windows.h>
#include "webrtc/system_wrappers/include/event_wrapper.h"
#include "webrtc/typedefs.h"
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 // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_

View File

@ -0,0 +1,66 @@
// 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 "webrtc/system_wrappers/include/field_trial.h"
#include "webrtc/system_wrappers/include/field_trial_default.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

View File

@ -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 "webrtc/system_wrappers/include/file_wrapper.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <stdarg.h>
#include <string.h>
#endif
#include "webrtc/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

View File

@ -0,0 +1,63 @@
/*
* 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 "webrtc/system_wrappers/include/logcat_trace_context.h"
#include <android/log.h>
#include <assert.h>
#include "webrtc/rtc_base/logging.h"
namespace webrtc {
static android_LogPriority AndroidLogPriorityFromWebRtcLogLevel(
TraceLevel webrtc_level) {
// NOTE: this mapping is somewhat arbitrary. StateInfo and Info are mapped
// to DEBUG because they are highly verbose in webrtc code (which is
// unfortunate).
switch (webrtc_level) {
case webrtc::kTraceStateInfo: return ANDROID_LOG_DEBUG;
case webrtc::kTraceWarning: return ANDROID_LOG_WARN;
case webrtc::kTraceError: return ANDROID_LOG_ERROR;
case webrtc::kTraceCritical: return ANDROID_LOG_FATAL;
case webrtc::kTraceApiCall: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceModuleCall: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceMemory: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceTimer: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceStream: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceDebug: return ANDROID_LOG_DEBUG;
case webrtc::kTraceInfo: return ANDROID_LOG_DEBUG;
case webrtc::kTraceTerseInfo: return ANDROID_LOG_INFO;
default:
LOG(LS_ERROR) << "Unexpected log level" << webrtc_level;
return ANDROID_LOG_FATAL;
}
}
LogcatTraceContext::LogcatTraceContext() {
webrtc::Trace::CreateTrace();
if (webrtc::Trace::SetTraceCallback(this) != 0)
assert(false);
}
LogcatTraceContext::~LogcatTraceContext() {
if (webrtc::Trace::SetTraceCallback(NULL) != 0)
assert(false);
webrtc::Trace::ReturnTrace();
}
void LogcatTraceContext::Print(TraceLevel level,
const char* message,
int length) {
__android_log_print(AndroidLogPriorityFromWebRtcLogLevel(level),
"WEBRTC", "%.*s", length, message);
}
} // namespace webrtc

View File

@ -0,0 +1,308 @@
// 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 "webrtc/system_wrappers/include/metrics_default.h"
#include <algorithm>
#include "webrtc/rtc_base/criticalsection.h"
#include "webrtc/rtc_base/thread_annotations.h"
#include "webrtc/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);
}
const std::string& GetHistogramName(Histogram* histogram_pointer) {
RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer);
return ptr->name();
}
// 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

View File

@ -0,0 +1,163 @@
/*
* 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 "webrtc/system_wrappers/include/metrics.h"
#include "webrtc/system_wrappers/include/metrics_default.h"
#include "webrtc/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

View File

@ -0,0 +1,127 @@
/*
* 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 "webrtc/system_wrappers/include/metrics.h"
#include "webrtc/system_wrappers/include/metrics_default.h"
#include "webrtc/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);
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
void AddSample(const std::string& name, int sample) {
RTC_HISTOGRAM_COUNTS_100(name, sample);
}
#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
} // 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"));
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(MetricsTest, RtcHistogram_FailsForNonConstantName) {
AddSample("ConstantName1", kSample);
EXPECT_DEATH(AddSample("NotConstantName1", kSample), "");
}
#endif
} // namespace webrtc

View File

@ -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 "webrtc/system_wrappers/include/clock.h"
#include "webrtc/system_wrappers/include/ntp_time.h"
#include "webrtc/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

View File

@ -0,0 +1,198 @@
/*
* 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 "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/logging.h"
#include "webrtc/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;
// 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;
}
// Detects if there has been a wraparound between |old_timestamp| and
// |new_timestamp|, and compensates by adding 2^32 if that is the case.
bool CompensateForWrapAround(uint32_t new_timestamp,
uint32_t old_timestamp,
int64_t* compensated_timestamp) {
int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp);
if (wraps < 0) {
// Reordering, don't use this packet.
return false;
}
*compensated_timestamp = new_timestamp + (wraps << 32);
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
RtpToNtpEstimator::RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t timestamp)
: ntp_time(ntp_secs, ntp_frac), rtp_timestamp(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) || (rtp_timestamp == other.rtp_timestamp);
}
// Class for converting an RTP timestamp to the NTP domain.
RtpToNtpEstimator::RtpToNtpEstimator() : consecutive_invalid_samples_(0) {}
RtpToNtpEstimator::~RtpToNtpEstimator() {}
void RtpToNtpEstimator::UpdateParameters() {
if (measurements_.size() != kNumRtcpReportsToUse)
return;
int64_t timestamp_new = measurements_.front().rtp_timestamp;
int64_t timestamp_old = measurements_.back().rtp_timestamp;
if (!CompensateForWrapAround(timestamp_new, timestamp_old, &timestamp_new))
return;
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;
}
bool RtpToNtpEstimator::UpdateMeasurements(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t rtp_timestamp,
bool* new_rtcp_sr) {
*new_rtcp_sr = false;
RtcpMeasurement new_measurement(ntp_secs, ntp_frac, 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;
for (const auto& measurement : measurements_) {
if (ntp_ms_new <= measurement.ntp_time.ToMs()) {
// Old report.
invalid_sample = true;
break;
}
int64_t timestamp_new = new_measurement.rtp_timestamp;
if (!CompensateForWrapAround(timestamp_new, measurement.rtp_timestamp,
&timestamp_new)) {
invalid_sample = true;
break;
}
if (timestamp_new <= measurement.rtp_timestamp) {
LOG(LS_WARNING)
<< "Newer RTCP SR report with older RTP timestamp, dropping";
invalid_sample = true;
break;
}
}
if (invalid_sample) {
++consecutive_invalid_samples_;
if (consecutive_invalid_samples_ < kMaxInvalidSamples) {
return false;
}
LOG(LS_WARNING) << "Multiple consecutively invalid RTCP SR reports, "
"clearing measurements.";
measurements_.clear();
}
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 || measurements_.empty())
return false;
uint32_t rtp_timestamp_old = measurements_.back().rtp_timestamp;
int64_t rtp_timestamp_unwrapped;
if (!CompensateForWrapAround(rtp_timestamp, rtp_timestamp_old,
&rtp_timestamp_unwrapped)) {
return false;
}
// params_.calculated should not be true unless params_.frequency_khz has been
// set 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;
}
int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) {
if (new_timestamp < old_timestamp) {
// This difference should be less than -2^31 if we have had a wrap around
// (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is
// cast to a int32_t, it should be positive.
if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) {
// Forward wrap around.
return 1;
}
} else if (static_cast<int32_t>(old_timestamp - new_timestamp) > 0) {
// This difference should be less than -2^31 if we have had a backward wrap
// around. Since it is cast to a int32_t, it should be positive.
return -1;
}
return 0;
}
} // namespace webrtc

View File

@ -0,0 +1,294 @@
/*
* 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 "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace {
const uint32_t kOneMsInNtpFrac = 4294967;
const uint32_t kTimestampTicksPerMs = 90;
} // namespace
TEST(WrapAroundTests, NoWrap) {
EXPECT_EQ(0, CheckForWrapArounds(0xFFFFFFFF, 0xFFFFFFFE));
EXPECT_EQ(0, CheckForWrapArounds(1, 0));
EXPECT_EQ(0, CheckForWrapArounds(0x00010000, 0x0000FFFF));
}
TEST(WrapAroundTests, ForwardWrap) {
EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFFFFFF));
EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFF0000));
EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFFFFFF));
EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFF0000));
}
TEST(WrapAroundTests, BackwardWrap) {
EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0));
EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0));
EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0x0000FFFF));
EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0x0000FFFF));
}
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;
// Expected to fail since the older RTCP has a smaller RTP timestamp than the
// newer (old:0, 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 = 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));
timestamp -= 2 * kTimestampTicksPerMs;
int64_t timestamp_ms = -1;
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().calculated);
// 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().calculated);
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().calculated);
int64_t timestamp_ms = -1;
EXPECT_FALSE(estimator.Estimate(timestamp, &timestamp_ms));
}
}; // namespace webrtc

View File

@ -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 "webrtc/system_wrappers/include/rw_lock_wrapper.h"
#include <assert.h>
#if defined(_WIN32)
#include "webrtc/system_wrappers/source/rw_lock_win.h"
#else
#include "webrtc/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

View File

@ -0,0 +1,51 @@
/*
* 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 "webrtc/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

View File

@ -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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
#include "webrtc/typedefs.h"
#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 // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_

View File

@ -0,0 +1,97 @@
/*
* 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 "webrtc/system_wrappers/source/rw_lock_win.h"
#include "webrtc/system_wrappers/include/trace.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;
}
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "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) {
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Native RW Lock");
native_rw_locks_supported = true;
}
return native_rw_locks_supported;
}
} // namespace webrtc

View File

@ -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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
#include "webrtc/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 // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// An OS-independent sleep function.
#include "webrtc/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

View File

@ -0,0 +1,235 @@
/*
* 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 "webrtc/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;
}
}

View File

@ -0,0 +1,583 @@
/*
* 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 "webrtc/system_wrappers/source/trace_impl.h"
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "webrtc/rtc_base/atomicops.h"
#include "webrtc/rtc_base/platform_thread.h"
#ifdef _WIN32
#include "webrtc/system_wrappers/source/trace_win.h"
#else
#include "webrtc/system_wrappers/source/trace_posix.h"
#endif // _WIN32
#define KEY_LEN_CHARS 31
#ifdef _WIN32
#pragma warning(disable:4355)
#endif // _WIN32
namespace webrtc {
const int Trace::kBoilerplateLength = 71;
const int Trace::kTimestampPosition = 13;
const int Trace::kTimestampLength = 12;
volatile int Trace::level_filter_ = kTraceDefault;
// Construct On First Use idiom. Avoids "static initialization order fiasco".
TraceImpl* TraceImpl::StaticInstance(CountOperation count_operation,
const TraceLevel level) {
// Sanities to avoid taking lock unless absolutely necessary (for
// performance reasons). count_operation == kAddRefNoCreate implies that a
// message will be written to file.
if ((level != kTraceAll) && (count_operation == kAddRefNoCreate)) {
if (!(level & level_filter())) {
return NULL;
}
}
TraceImpl* impl =
GetStaticInstance<TraceImpl>(count_operation);
return impl;
}
TraceImpl* TraceImpl::GetTrace(const TraceLevel level) {
return StaticInstance(kAddRefNoCreate, level);
}
TraceImpl* TraceImpl::CreateInstance() {
#if defined(_WIN32)
return new TraceWindows();
#else
return new TracePosix();
#endif
}
TraceImpl::TraceImpl()
: callback_(NULL),
row_count_text_(0),
file_count_text_(0),
trace_file_(FileWrapper::Create()) {
}
TraceImpl::~TraceImpl() {
trace_file_->CloseFile();
}
int32_t TraceImpl::AddThreadId(char* trace_message) const {
uint32_t thread_id = rtc::CurrentThreadId();
// Messages is 12 characters.
return sprintf(trace_message, "%10u; ", thread_id);
}
int32_t TraceImpl::AddLevel(char* sz_message, const TraceLevel level) const {
const int kMessageLength = 12;
switch (level) {
case kTraceTerseInfo:
// Add the appropriate amount of whitespace.
memset(sz_message, ' ', kMessageLength);
sz_message[kMessageLength] = '\0';
break;
case kTraceStateInfo:
sprintf(sz_message, "STATEINFO ; ");
break;
case kTraceWarning:
sprintf(sz_message, "WARNING ; ");
break;
case kTraceError:
sprintf(sz_message, "ERROR ; ");
break;
case kTraceCritical:
sprintf(sz_message, "CRITICAL ; ");
break;
case kTraceInfo:
sprintf(sz_message, "DEBUGINFO ; ");
break;
case kTraceModuleCall:
sprintf(sz_message, "MODULECALL; ");
break;
case kTraceMemory:
sprintf(sz_message, "MEMORY ; ");
break;
case kTraceTimer:
sprintf(sz_message, "TIMER ; ");
break;
case kTraceStream:
sprintf(sz_message, "STREAM ; ");
break;
case kTraceApiCall:
sprintf(sz_message, "APICALL ; ");
break;
case kTraceDebug:
sprintf(sz_message, "DEBUG ; ");
break;
default:
assert(false);
return 0;
}
// All messages are 12 characters.
return kMessageLength;
}
int32_t TraceImpl::AddModuleAndId(char* trace_message,
const TraceModule module,
const int32_t id) const {
// Use long int to prevent problems with different definitions of
// int32_t.
// TODO(hellner): is this actually a problem? If so, it should be better to
// clean up int32_t
const long int idl = id;
const int kMessageLength = 25;
if (idl != -1) {
const unsigned long int id_engine = id >> 16;
const unsigned long int id_channel = id & 0xffff;
switch (module) {
case kTraceUndefined:
// Add the appropriate amount of whitespace.
memset(trace_message, ' ', kMessageLength);
trace_message[kMessageLength] = '\0';
break;
case kTraceVoice:
sprintf(trace_message, " VOICE:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceVideo:
sprintf(trace_message, " VIDEO:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceUtility:
sprintf(trace_message, " UTILITY:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceRtpRtcp:
sprintf(trace_message, " RTP/RTCP:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceTransport:
sprintf(trace_message, " TRANSPORT:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceAudioCoding:
sprintf(trace_message, "AUDIO CODING:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceSrtp:
sprintf(trace_message, " SRTP:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceAudioMixerServer:
sprintf(trace_message, " AUDIO MIX/S:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceAudioMixerClient:
sprintf(trace_message, " AUDIO MIX/C:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceVideoCoding:
sprintf(trace_message, "VIDEO CODING:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceVideoMixer:
// Print sleep time and API call
sprintf(trace_message, " VIDEO MIX:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceFile:
sprintf(trace_message, " FILE:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceAudioProcessing:
sprintf(trace_message, " AUDIO PROC:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceAudioDevice:
sprintf(trace_message, "AUDIO DEVICE:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceVideoRenderer:
sprintf(trace_message, "VIDEO RENDER:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceVideoCapture:
sprintf(trace_message, "VIDEO CAPTUR:%5ld %5ld;", id_engine,
id_channel);
break;
case kTraceRemoteBitrateEstimator:
sprintf(trace_message, " BWE RBE:%5ld %5ld;", id_engine,
id_channel);
break;
}
} else {
switch (module) {
case kTraceUndefined:
// Add the appropriate amount of whitespace.
memset(trace_message, ' ', kMessageLength);
trace_message[kMessageLength] = '\0';
break;
case kTraceVoice:
sprintf(trace_message, " VOICE:%11ld;", idl);
break;
case kTraceVideo:
sprintf(trace_message, " VIDEO:%11ld;", idl);
break;
case kTraceUtility:
sprintf(trace_message, " UTILITY:%11ld;", idl);
break;
case kTraceRtpRtcp:
sprintf(trace_message, " RTP/RTCP:%11ld;", idl);
break;
case kTraceTransport:
sprintf(trace_message, " TRANSPORT:%11ld;", idl);
break;
case kTraceAudioCoding:
sprintf(trace_message, "AUDIO CODING:%11ld;", idl);
break;
case kTraceSrtp:
sprintf(trace_message, " SRTP:%11ld;", idl);
break;
case kTraceAudioMixerServer:
sprintf(trace_message, " AUDIO MIX/S:%11ld;", idl);
break;
case kTraceAudioMixerClient:
sprintf(trace_message, " AUDIO MIX/C:%11ld;", idl);
break;
case kTraceVideoCoding:
sprintf(trace_message, "VIDEO CODING:%11ld;", idl);
break;
case kTraceVideoMixer:
sprintf(trace_message, " VIDEO MIX:%11ld;", idl);
break;
case kTraceFile:
sprintf(trace_message, " FILE:%11ld;", idl);
break;
case kTraceAudioProcessing:
sprintf(trace_message, " AUDIO PROC:%11ld;", idl);
break;
case kTraceAudioDevice:
sprintf(trace_message, "AUDIO DEVICE:%11ld;", idl);
break;
case kTraceVideoRenderer:
sprintf(trace_message, "VIDEO RENDER:%11ld;", idl);
break;
case kTraceVideoCapture:
sprintf(trace_message, "VIDEO CAPTUR:%11ld;", idl);
break;
case kTraceRemoteBitrateEstimator:
sprintf(trace_message, " BWE RBE:%11ld;", idl);
break;
}
}
return kMessageLength;
}
int32_t TraceImpl::SetTraceFileImpl(const char* file_name_utf8,
const bool add_file_counter) {
rtc::CritScope lock(&crit_);
trace_file_->CloseFile();
trace_file_path_.clear();
if (file_name_utf8) {
if (add_file_counter) {
file_count_text_ = 1;
char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize];
CreateFileName(file_name_utf8, file_name_with_counter_utf8,
file_count_text_);
if (!trace_file_->OpenFile(file_name_with_counter_utf8, false)) {
return -1;
}
trace_file_path_ = file_name_with_counter_utf8;
} else {
file_count_text_ = 0;
if (!trace_file_->OpenFile(file_name_utf8, false)) {
return -1;
}
trace_file_path_ = file_name_utf8;
}
}
row_count_text_ = 0;
return 0;
}
int32_t TraceImpl::SetTraceCallbackImpl(TraceCallback* callback) {
rtc::CritScope lock(&crit_);
callback_ = callback;
return 0;
}
int32_t TraceImpl::AddMessage(
char* trace_message,
const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
const uint16_t written_so_far) const {
int length = 0;
if (written_so_far >= WEBRTC_TRACE_MAX_MESSAGE_SIZE) {
return -1;
}
// - 2 to leave room for newline and NULL termination.
#ifdef _WIN32
length = _snprintf(trace_message,
WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
"%s", msg);
if (length < 0) {
length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
trace_message[length] = 0;
}
#else
length = snprintf(trace_message,
WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
"%s", msg);
if (length < 0 ||
length > WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2) {
length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
trace_message[length] = 0;
}
#endif
// Length with NULL termination.
return length + 1;
}
void TraceImpl::AddMessageToList(
const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
const uint16_t length,
const TraceLevel level) {
rtc::CritScope lock(&crit_);
if (callback_)
callback_->Print(level, trace_message, length);
WriteToFile(trace_message, length);
}
void TraceImpl::WriteToFile(const char* msg, uint16_t length) {
if (!trace_file_->is_open())
return;
if (row_count_text_ > WEBRTC_TRACE_MAX_FILE_SIZE) {
// wrap file
row_count_text_ = 0;
trace_file_->Flush();
if (file_count_text_ == 0) {
trace_file_->Rewind();
} else {
char new_file_name[FileWrapper::kMaxFileNameSize];
// get current name
file_count_text_++;
UpdateFileName(new_file_name, file_count_text_);
trace_file_->CloseFile();
trace_file_path_.clear();
if (!trace_file_->OpenFile(new_file_name, false)) {
return;
}
trace_file_path_ = new_file_name;
}
}
if (row_count_text_ == 0) {
char message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
int32_t length = AddDateTimeInfo(message);
if (length != -1) {
message[length] = 0;
message[length - 1] = '\n';
trace_file_->Write(message, length);
row_count_text_++;
}
}
char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
memcpy(trace_message, msg, length);
trace_message[length] = 0;
trace_message[length - 1] = '\n';
trace_file_->Write(trace_message, length);
row_count_text_++;
}
void TraceImpl::AddImpl(const TraceLevel level,
const TraceModule module,
const int32_t id,
const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE]) {
if (!TraceCheck(level))
return;
char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
char* message_ptr = &trace_message[0];
int32_t len = AddLevel(message_ptr, level);
if (len == -1)
return;
message_ptr += len;
int32_t ack_len = len;
len = AddTime(message_ptr, level);
if (len == -1)
return;
message_ptr += len;
ack_len += len;
len = AddModuleAndId(message_ptr, module, id);
if (len == -1)
return;
message_ptr += len;
ack_len += len;
len = AddThreadId(message_ptr);
if (len < 0)
return;
message_ptr += len;
ack_len += len;
len = AddMessage(message_ptr, msg, static_cast<uint16_t>(ack_len));
if (len == -1)
return;
ack_len += len;
AddMessageToList(trace_message, static_cast<uint16_t>(ack_len), level);
}
bool TraceImpl::TraceCheck(const TraceLevel level) const {
return (level & level_filter()) ? true : false;
}
bool TraceImpl::UpdateFileName(
char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
const uint32_t new_count) const {
int32_t length = static_cast<int32_t>(trace_file_path_.length());
int32_t length_without_file_ending = length - 1;
while (length_without_file_ending > 0) {
if (trace_file_path_[length_without_file_ending] == '.') {
break;
} else {
length_without_file_ending--;
}
}
if (length_without_file_ending == 0) {
length_without_file_ending = length;
}
int32_t length_to_ = length_without_file_ending - 1;
while (length_to_ > 0) {
if (trace_file_path_[length_to_] == '_') {
break;
} else {
length_to_--;
}
}
memcpy(file_name_with_counter_utf8, &trace_file_path_[0], length_to_);
sprintf(file_name_with_counter_utf8 + length_to_, "_%lu%s",
static_cast<long unsigned int>(new_count),
&trace_file_path_[length_without_file_ending]);
return true;
}
bool TraceImpl::CreateFileName(
const char file_name_utf8[FileWrapper::kMaxFileNameSize],
char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
const uint32_t new_count) const {
int32_t length = (int32_t)strlen(file_name_utf8);
if (length < 0) {
return false;
}
int32_t length_without_file_ending = length - 1;
while (length_without_file_ending > 0) {
if (file_name_utf8[length_without_file_ending] == '.') {
break;
} else {
length_without_file_ending--;
}
}
if (length_without_file_ending == 0) {
length_without_file_ending = length;
}
memcpy(file_name_with_counter_utf8, file_name_utf8,
length_without_file_ending);
sprintf(file_name_with_counter_utf8 + length_without_file_ending, "_%lu%s",
static_cast<long unsigned int>(new_count),
file_name_utf8 + length_without_file_ending);
return true;
}
// static
void Trace::CreateTrace() {
TraceImpl::StaticInstance(kAddRef);
}
// static
void Trace::ReturnTrace() {
TraceImpl::StaticInstance(kRelease);
}
// static
void Trace::set_level_filter(int filter) {
rtc::AtomicOps::ReleaseStore(&level_filter_, filter);
}
// static
int Trace::level_filter() {
return rtc::AtomicOps::AcquireLoad(&level_filter_);
}
// static
int32_t Trace::SetTraceFile(const char* file_name,
const bool add_file_counter) {
TraceImpl* trace = TraceImpl::GetTrace();
if (trace) {
int ret_val = trace->SetTraceFileImpl(file_name, add_file_counter);
ReturnTrace();
return ret_val;
}
return -1;
}
int32_t Trace::SetTraceCallback(TraceCallback* callback) {
TraceImpl* trace = TraceImpl::GetTrace();
if (trace) {
int ret_val = trace->SetTraceCallbackImpl(callback);
ReturnTrace();
return ret_val;
}
return -1;
}
void Trace::Add(const TraceLevel level, const TraceModule module,
const int32_t id, const char* msg, ...) {
TraceImpl* trace = TraceImpl::GetTrace(level);
if (trace) {
if (trace->TraceCheck(level)) {
char temp_buff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
char* buff = 0;
if (msg) {
va_list args;
va_start(args, msg);
#ifdef _WIN32
_vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
#else
vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
#endif
va_end(args);
buff = temp_buff;
}
trace->AddImpl(level, module, id, buff);
}
ReturnTrace();
}
}
} // namespace webrtc

View File

@ -0,0 +1,105 @@
/*
* 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_
#include <memory>
#include "webrtc/rtc_base/criticalsection.h"
#include "webrtc/rtc_base/platform_thread.h"
#include "webrtc/system_wrappers/include/event_wrapper.h"
#include "webrtc/system_wrappers/include/file_wrapper.h"
#include "webrtc/system_wrappers/include/static_instance.h"
#include "webrtc/system_wrappers/include/trace.h"
namespace webrtc {
#define WEBRTC_TRACE_MAX_MESSAGE_SIZE 1024
// Total buffer size is WEBRTC_TRACE_NUM_ARRAY (number of buffer partitions) *
// WEBRTC_TRACE_MAX_QUEUE (number of lines per buffer partition) *
// WEBRTC_TRACE_MAX_MESSAGE_SIZE (number of 1 byte charachters per line) =
// 1 or 4 Mbyte.
#define WEBRTC_TRACE_MAX_FILE_SIZE 100*1000
// Number of rows that may be written to file. On average 110 bytes per row (max
// 256 bytes per row). So on average 110*100*1000 = 11 Mbyte, max 256*100*1000 =
// 25.6 Mbyte
class TraceImpl : public Trace {
public:
virtual ~TraceImpl();
static TraceImpl* CreateInstance();
static TraceImpl* GetTrace(const TraceLevel level = kTraceAll);
int32_t SetTraceFileImpl(const char* file_name, const bool add_file_counter);
int32_t SetTraceCallbackImpl(TraceCallback* callback);
void AddImpl(const TraceLevel level, const TraceModule module,
const int32_t id, const char* msg);
bool TraceCheck(const TraceLevel level) const;
protected:
TraceImpl();
static TraceImpl* StaticInstance(CountOperation count_operation,
const TraceLevel level = kTraceAll);
int32_t AddThreadId(char* trace_message) const;
// OS specific implementations.
virtual int32_t AddTime(char* trace_message,
const TraceLevel level) const = 0;
virtual int32_t AddDateTimeInfo(char* trace_message) const = 0;
private:
friend class Trace;
int32_t AddLevel(char* sz_message, const TraceLevel level) const;
int32_t AddModuleAndId(char* trace_message, const TraceModule module,
const int32_t id) const;
int32_t AddMessage(char* trace_message,
const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
const uint16_t written_so_far) const;
void AddMessageToList(
const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
const uint16_t length,
const TraceLevel level);
bool UpdateFileName(
char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
const uint32_t new_count) const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
bool CreateFileName(
const char file_name_utf8[FileWrapper::kMaxFileNameSize],
char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
const uint32_t new_count) const;
void WriteToFile(const char* msg, uint16_t length)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
TraceCallback* callback_ RTC_GUARDED_BY(crit_);
uint32_t row_count_text_ RTC_GUARDED_BY(crit_);
uint32_t file_count_text_ RTC_GUARDED_BY(crit_);
const std::unique_ptr<FileWrapper> trace_file_ RTC_GUARDED_BY(crit_);
std::string trace_file_path_ RTC_GUARDED_BY(crit_);
rtc::CriticalSection crit_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_

View File

@ -0,0 +1,85 @@
/*
* 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 "webrtc/system_wrappers/source/trace_posix.h"
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
namespace webrtc {
TracePosix::TracePosix() {
struct timeval system_time_high_res;
gettimeofday(&system_time_high_res, 0);
prev_api_tick_count_ = prev_tick_count_ = system_time_high_res.tv_sec;
}
int32_t TracePosix::AddTime(char* trace_message, const TraceLevel level) const {
struct timeval system_time_high_res;
if (gettimeofday(&system_time_high_res, 0) == -1) {
return -1;
}
struct tm buffer;
const struct tm* system_time =
localtime_r(&system_time_high_res.tv_sec, &buffer);
const uint32_t ms_time = system_time_high_res.tv_usec / 1000;
uint32_t prev_tickCount = 0;
{
rtc::CritScope lock(&crit_sect_);
if (level == kTraceApiCall) {
prev_tickCount = prev_tick_count_;
prev_tick_count_ = ms_time;
} else {
prev_tickCount = prev_api_tick_count_;
prev_api_tick_count_ = ms_time;
}
}
uint32_t dw_delta_time = ms_time - prev_tickCount;
if (prev_tickCount == 0) {
dw_delta_time = 0;
}
if (dw_delta_time > 0x0fffffff) {
// Either wraparound or data race.
dw_delta_time = 0;
}
if (dw_delta_time > 99999) {
dw_delta_time = 99999;
}
sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5lu) ", system_time->tm_hour,
system_time->tm_min, system_time->tm_sec, ms_time,
static_cast<unsigned long>(dw_delta_time));
// Messages are 22 characters.
return 22;
}
int32_t TracePosix::AddDateTimeInfo(char* trace_message) const {
time_t t;
time(&t);
char buffer[26]; // man ctime says buffer should have room for >=26 bytes.
sprintf(trace_message, "Local Date: %s", ctime_r(&t, buffer));
int32_t len = static_cast<int32_t>(strlen(trace_message));
if ('\n' == trace_message[len - 1]) {
trace_message[len - 1] = '\0';
--len;
}
// Messages is 12 characters.
return len + 1;
}
} // namespace webrtc

View File

@ -0,0 +1,39 @@
/*
* 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_
#include "webrtc/rtc_base/criticalsection.h"
#include "webrtc/system_wrappers/source/trace_impl.h"
namespace webrtc {
class TracePosix : public TraceImpl {
public:
TracePosix();
~TracePosix() override = default;
// This method can be called on several different threads different from
// the creating thread.
int32_t AddTime(char* trace_message, const TraceLevel level) const override;
int32_t AddDateTimeInfo(char* trace_message) const override;
private:
volatile mutable uint32_t prev_api_tick_count_;
volatile mutable uint32_t prev_tick_count_;
rtc::CriticalSection crit_sect_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_

View File

@ -0,0 +1,97 @@
/*
* 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 "webrtc/system_wrappers/source/trace_win.h"
#include <assert.h>
#include <stdarg.h>
#include "Mmsystem.h"
namespace webrtc {
TraceWindows::TraceWindows()
: prev_api_tick_count_(0),
prev_tick_count_(0) {
}
TraceWindows::~TraceWindows() {
}
int32_t TraceWindows::AddTime(char* trace_message,
const TraceLevel level) const {
uint32_t dw_current_time = timeGetTime();
SYSTEMTIME system_time;
GetSystemTime(&system_time);
if (level == kTraceApiCall) {
uint32_t dw_delta_time = dw_current_time - prev_tick_count_;
prev_tick_count_ = dw_current_time;
if (prev_tick_count_ == 0) {
dw_delta_time = 0;
}
if (dw_delta_time > 0x0fffffff) {
// Either wrap-around or data race.
dw_delta_time = 0;
}
if (dw_delta_time > 99999) {
dw_delta_time = 99999;
}
sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5u) ", system_time.wHour,
system_time.wMinute, system_time.wSecond,
system_time.wMilliseconds, dw_delta_time);
} else {
uint32_t dw_delta_time = dw_current_time - prev_api_tick_count_;
prev_api_tick_count_ = dw_current_time;
if (prev_api_tick_count_ == 0) {
dw_delta_time = 0;
}
if (dw_delta_time > 0x0fffffff) {
// Either wraparound or data race.
dw_delta_time = 0;
}
if (dw_delta_time > 99999) {
dw_delta_time = 99999;
}
sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5u) ", system_time.wHour,
system_time.wMinute, system_time.wSecond,
system_time.wMilliseconds, dw_delta_time);
}
return 22;
}
int32_t TraceWindows::AddDateTimeInfo(char* trace_message) const {
prev_api_tick_count_ = timeGetTime();
prev_tick_count_ = prev_api_tick_count_;
SYSTEMTIME sys_time;
GetLocalTime(&sys_time);
TCHAR sz_date_str[20];
TCHAR sz_time_str[20];
// Create date string (e.g. Apr 04 2002)
GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &sys_time, TEXT("MMM dd yyyy"),
sz_date_str, 20);
// Create time string (e.g. 15:32:08)
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &sys_time, TEXT("HH':'mm':'ss"),
sz_time_str, 20);
sprintf(trace_message, "Local Date: %ls Local Time: %ls", sz_date_str,
sz_time_str);
// Include NULL termination (hence + 1).
return static_cast<int32_t>(strlen(trace_message) + 1);
}
} // namespace webrtc

View File

@ -0,0 +1,36 @@
/*
* 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_
#include <stdio.h>
#include <windows.h>
#include "webrtc/system_wrappers/source/trace_impl.h"
namespace webrtc {
class TraceWindows : public TraceImpl {
public:
TraceWindows();
virtual ~TraceWindows();
virtual int32_t AddTime(char* trace_message, const TraceLevel level) const;
virtual int32_t AddDateTimeInfo(char* trace_message) const;
private:
volatile mutable uint32_t prev_api_tick_count_;
volatile mutable uint32_t prev_tick_count_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_