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:
committed by
Commit Bot
parent
6674846b4a
commit
bb547203bf
60
system_wrappers/source/aligned_array_unittest.cc
Normal file
60
system_wrappers/source/aligned_array_unittest.cc
Normal 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
|
||||
100
system_wrappers/source/aligned_malloc.cc
Normal file
100
system_wrappers/source/aligned_malloc.cc
Normal 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
|
||||
83
system_wrappers/source/aligned_malloc_unittest.cc
Normal file
83
system_wrappers/source/aligned_malloc_unittest.cc
Normal 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
|
||||
|
||||
49
system_wrappers/source/atomic32_darwin.cc
Normal file
49
system_wrappers/source/atomic32_darwin.cc
Normal 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
|
||||
53
system_wrappers/source/atomic32_non_darwin_unix.cc
Normal file
53
system_wrappers/source/atomic32_non_darwin_unix.cc
Normal 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
|
||||
60
system_wrappers/source/atomic32_win.cc
Normal file
60
system_wrappers/source/atomic32_win.cc
Normal 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
|
||||
266
system_wrappers/source/clock.cc
Normal file
266
system_wrappers/source/clock.cc
Normal 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, µseconds_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, µseconds_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
|
||||
34
system_wrappers/source/clock_unittest.cc
Normal file
34
system_wrappers/source/clock_unittest.cc
Normal 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
|
||||
72
system_wrappers/source/cpu_features.cc
Normal file
72
system_wrappers/source/cpu_features.cc
Normal 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;
|
||||
15
system_wrappers/source/cpu_features_android.c
Normal file
15
system_wrappers/source/cpu_features_android.c
Normal 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();
|
||||
}
|
||||
86
system_wrappers/source/cpu_features_linux.c
Normal file
86
system_wrappers/source/cpu_features_linux.c
Normal 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
|
||||
69
system_wrappers/source/cpu_info.cc
Normal file
69
system_wrappers/source/cpu_info.cc
Normal 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
|
||||
54
system_wrappers/source/event.cc
Normal file
54
system_wrappers/source/event.cc
Normal 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
|
||||
261
system_wrappers/source/event_timer_posix.cc
Normal file
261
system_wrappers/source/event_timer_posix.cc
Normal 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
|
||||
67
system_wrappers/source/event_timer_posix.h
Normal file
67
system_wrappers/source/event_timer_posix.h
Normal 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_
|
||||
198
system_wrappers/source/event_timer_posix_unittest.cc
Normal file
198
system_wrappers/source/event_timer_posix_unittest.cc
Normal 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
|
||||
78
system_wrappers/source/event_timer_win.cc
Normal file
78
system_wrappers/source/event_timer_win.cc
Normal 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
|
||||
40
system_wrappers/source/event_timer_win.h
Normal file
40
system_wrappers/source/event_timer_win.h
Normal 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_
|
||||
66
system_wrappers/source/field_trial_default.cc
Normal file
66
system_wrappers/source/field_trial_default.cc
Normal 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
|
||||
152
system_wrappers/source/file_impl.cc
Normal file
152
system_wrappers/source/file_impl.cc
Normal 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
|
||||
63
system_wrappers/source/logcat_trace_context.cc
Normal file
63
system_wrappers/source/logcat_trace_context.cc
Normal 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
|
||||
308
system_wrappers/source/metrics_default.cc
Normal file
308
system_wrappers/source/metrics_default.cc
Normal 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
|
||||
163
system_wrappers/source/metrics_default_unittest.cc
Normal file
163
system_wrappers/source/metrics_default_unittest.cc
Normal 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
|
||||
127
system_wrappers/source/metrics_unittest.cc
Normal file
127
system_wrappers/source/metrics_unittest.cc
Normal 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
|
||||
65
system_wrappers/source/ntp_time_unittest.cc
Normal file
65
system_wrappers/source/ntp_time_unittest.cc
Normal 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
|
||||
198
system_wrappers/source/rtp_to_ntp_estimator.cc
Normal file
198
system_wrappers/source/rtp_to_ntp_estimator.cc
Normal 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, ×tamp_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,
|
||||
¶ms_.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,
|
||||
×tamp_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
|
||||
294
system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
Normal file
294
system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
Normal 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, ×tamp_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,
|
||||
×tamp_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, ×tamp_ms));
|
||||
EXPECT_EQ(2, timestamp_ms);
|
||||
// Wrapped rtp.
|
||||
timestamp += kTimestampTicksPerMs;
|
||||
EXPECT_TRUE(estimator.Estimate(timestamp, ×tamp_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, ×tamp_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, ×tamp_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, ×tamp_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, ×tamp_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, ×tamp_ms));
|
||||
}
|
||||
|
||||
}; // namespace webrtc
|
||||
31
system_wrappers/source/rw_lock.cc
Normal file
31
system_wrappers/source/rw_lock.cc
Normal 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
|
||||
51
system_wrappers/source/rw_lock_posix.cc
Normal file
51
system_wrappers/source/rw_lock_posix.cc
Normal 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
|
||||
41
system_wrappers/source/rw_lock_posix.h
Normal file
41
system_wrappers/source/rw_lock_posix.h
Normal 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_
|
||||
97
system_wrappers/source/rw_lock_win.cc
Normal file
97
system_wrappers/source/rw_lock_win.cc
Normal 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
|
||||
40
system_wrappers/source/rw_lock_win.h
Normal file
40
system_wrappers/source/rw_lock_win.h
Normal 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_
|
||||
36
system_wrappers/source/sleep.cc
Normal file
36
system_wrappers/source/sleep.cc
Normal 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
|
||||
235
system_wrappers/source/timestamp_extrapolator.cc
Normal file
235
system_wrappers/source/timestamp_extrapolator.cc
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
583
system_wrappers/source/trace_impl.cc
Normal file
583
system_wrappers/source/trace_impl.cc
Normal 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
|
||||
105
system_wrappers/source/trace_impl.h
Normal file
105
system_wrappers/source/trace_impl.h
Normal 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_
|
||||
85
system_wrappers/source/trace_posix.cc
Normal file
85
system_wrappers/source/trace_posix.cc
Normal 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
|
||||
39
system_wrappers/source/trace_posix.h
Normal file
39
system_wrappers/source/trace_posix.h
Normal 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_
|
||||
97
system_wrappers/source/trace_win.cc
Normal file
97
system_wrappers/source/trace_win.cc
Normal 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
|
||||
36
system_wrappers/source/trace_win.h
Normal file
36
system_wrappers/source/trace_win.h
Normal 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_
|
||||
Reference in New Issue
Block a user