mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-05-11 22:51:22 +08:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d6cfb5c76 | |||
| ed8b536ac0 | |||
| 5e2d27e9d2 | |||
| 47a2dc85f9 | |||
| 5febe99bc2 | |||
| 97bed80088 | |||
| 070f7bd21e | |||
| 4a65a59803 | |||
| 733434f9b3 | |||
| 7b7787f638 | |||
| b64d399967 | |||
| 65f9862929 | |||
| 3065c15631 | |||
| e28de1fbda | |||
| e802306148 | |||
| 4a16857da8 | |||
| 6776b915da | |||
| 311b94492a | |||
| be659f8e49 | |||
| 375d849786 | |||
| b347b160e2 | |||
| 31e5d5025a | |||
| 61b2eb2fdb | |||
| a64655dec9 | |||
| 3399d43501 | |||
| 5fb35ecd77 | |||
| 7a28cab427 | |||
| a114ffdb36 | |||
| f766330039 | |||
| 6b8e33b83c | |||
| 9c16a24867 | |||
| c5f2f6cf82 | |||
| 8064130356 | |||
| 60c3390203 | |||
| f246ab8720 | |||
| b887fcbf86 | |||
| 7216d318b4 | |||
| cb842276e8 | |||
| 1acd613b45 | |||
| 0bfe3bdfd0 | |||
| 610f89a828 | |||
| 82ef2a161d | |||
| 32c8048430 | |||
| cb4648ce72 | |||
| ea2f5d319d | |||
| 45ccbe1637 | |||
| 0f2f984286 | |||
| 72d669f8bc | |||
| c2b69a0cf2 | |||
| 89fa82b165 | |||
| c5f90e1aee | |||
| 7618e4bab9 | |||
| 1802453dbb | |||
| 67e7f2e82b | |||
| 287b7dbc94 | |||
| d20fee4a64 | |||
| 297410b679 | |||
| 1f08c80aab | |||
| 238eef1c93 | |||
| bde35e3b1c | |||
| 955182f5a0 | |||
| b1180f1e93 | |||
| d3e9df260a | |||
| 2088bf190c | |||
| 7dd304b686 | |||
| c65e6b7af2 | |||
| 72d4982f54 | |||
| 1e90d99980 | |||
| a2000ddcd6 | |||
| ae67ad961e | |||
| 76a80e6d07 | |||
| d4b1ac1fb8 | |||
| e970bdc929 | |||
| 2b5c0ee533 |
+1
-3
@@ -1,12 +1,10 @@
|
||||
# Xmake cache
|
||||
.xmake/
|
||||
build/
|
||||
thirdparty/ffmpeg/lib/*
|
||||
.VSCodeCounter/
|
||||
|
||||
# MacOS Cache
|
||||
.DS_Store
|
||||
|
||||
# VSCode cache
|
||||
.vscode
|
||||
projectx.code-workspace
|
||||
continuous-desk.code-workspace
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "thirdparty/projectx"]
|
||||
path = thirdparty/projectx
|
||||
url = git@github.com:dijunkun/projectx.git
|
||||
@@ -1,34 +0,0 @@
|
||||
# projectx
|
||||
|
||||
vcpkg/buildtrees/versioning_/versions/pcre/69e232f12c4e3eab4115f0672466a6661978bea2$ vim portfile.cmake
|
||||
|
||||
- URLS "https://ftp.pcre.org/pub/pcre/pcre-${PCRE_VERSION}.zip"
|
||||
+ URLS "https://sourceforge.net/projects/pcre/files/pcre/${PCRE_VERSION}/pcre-${PCRE_VERSION}.zip"
|
||||
|
||||
linux
|
||||
|
||||
sudo apt-get install nvidia-cuda-toolkit
|
||||
solve <cuda.h>
|
||||
|
||||
sudo apt-get install libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-xfixes0-dev libxv-dev
|
||||
solve x11
|
||||
|
||||
sudo apt-get -y install libasound2-dev libsndio-dev libxcb-shm0-dev
|
||||
solve asound sndio xcb-shm
|
||||
|
||||
sudo apt-get -y install libasound2-dev libpulse-dev && rebuild
|
||||
solve error dsp no such audio device
|
||||
|
||||
sudo apt-get install libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libavdevice-dev
|
||||
|
||||
sudo apt remove libssl-dev libglib2.0-dev
|
||||
|
||||
install:
|
||||
@echo hello world
|
||||
install -D build/linux/x86_64/release/remote_desk -t /usr/bin
|
||||
install -D config/config.ini -t /usr/bin
|
||||
install -D build/linux/x86_64/release/libprojectx.so -t /usr/lib
|
||||
install -D thirdparty/nvcodec/Lib/x64/libnvidia-encode.so.1 -t /usr/lib
|
||||
install -D thirdparty/nvcodec/Lib/x64/libnvidia-encode.so -t /usr/lib
|
||||
install -D thirdparty/nvcodec/Lib/x64/libnvcuvid.so.1 -t /usr/lib
|
||||
install -D thirdparty/nvcodec/Lib/x64/libnvcuvid.so -t /usr/lib
|
||||
+3
-6
@@ -1,19 +1,16 @@
|
||||
[signal server]
|
||||
ip = 150.158.81.30
|
||||
ip = 120.77.216.215
|
||||
port = 9099
|
||||
|
||||
[stun server]
|
||||
ip = 150.158.81.30
|
||||
ip = 120.77.216.215
|
||||
port = 3478
|
||||
|
||||
[turn server]
|
||||
ip = 150.158.81.30
|
||||
ip = 120.77.216.215
|
||||
port = 3478
|
||||
username = dijunkun
|
||||
password = dijunkunpw
|
||||
|
||||
[hardware acceleration]
|
||||
turn_on = false
|
||||
|
||||
[av1 encoding]
|
||||
turn_on = true
|
||||
Binary file not shown.
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-03-14
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ANY_INVOCABLE_H_
|
||||
#define _ANY_INVOCABLE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
// 简化版的 AnyInvocable
|
||||
template <typename Signature>
|
||||
class AnyInvocable;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
class AnyInvocable<R(Args...)> {
|
||||
public:
|
||||
// 默认构造函数
|
||||
AnyInvocable() = default;
|
||||
|
||||
AnyInvocable(std::nullptr_t) noexcept : callable_(nullptr) {}
|
||||
|
||||
// 构造函数:接受一个可以调用的对象(排除 nullptr)
|
||||
template <typename Callable, typename = std::enable_if_t<!std::is_same_v<
|
||||
std::decay_t<Callable>, std::nullptr_t>>>
|
||||
AnyInvocable(Callable&& callable)
|
||||
: callable_(std::make_unique<CallableWrapper<Callable>>(
|
||||
std::forward<Callable>(callable))) {}
|
||||
|
||||
// 调用运算符(支持 void 和非 void 返回类型)
|
||||
R operator()(Args... args) {
|
||||
if (!callable_) {
|
||||
throw std::bad_function_call();
|
||||
}
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
callable_->Invoke(std::forward<Args>(args)...);
|
||||
} else {
|
||||
return callable_->Invoke(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
// 移动构造函数
|
||||
AnyInvocable(AnyInvocable&&) = default;
|
||||
// 移动赋值运算符
|
||||
AnyInvocable& operator=(AnyInvocable&&) = default;
|
||||
|
||||
// 判断是否有效
|
||||
explicit operator bool() const { return static_cast<bool>(callable_); }
|
||||
|
||||
private:
|
||||
// 抽象基类,允许不同类型的可调用对象
|
||||
struct CallableBase {
|
||||
virtual ~CallableBase() = default;
|
||||
virtual R Invoke(Args&&... args) = 0;
|
||||
};
|
||||
|
||||
// 模板派生类:实际存储 callable 对象
|
||||
template <typename Callable>
|
||||
struct CallableWrapper : public CallableBase {
|
||||
CallableWrapper(Callable&& callable)
|
||||
: callable_(std::forward<Callable>(callable)) {}
|
||||
|
||||
R Invoke(Args&&... args) override {
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
callable_(std::forward<Args>(args)...);
|
||||
} else {
|
||||
return callable_(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
Callable callable_;
|
||||
};
|
||||
|
||||
std::unique_ptr<CallableBase> callable_;
|
||||
};
|
||||
|
||||
// 简单的包装函数
|
||||
template <typename R, typename... Args>
|
||||
AnyInvocable<R(Args...)> MakeMoveOnlyFunction(std::function<R(Args...)>&& f) {
|
||||
return AnyInvocable<R(Args...)>(std::move(f));
|
||||
}
|
||||
|
||||
#endif // _ANY_INVOCABLE_H_
|
||||
@@ -1,319 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef API_ARRAY_VIEW_H_
|
||||
#define API_ARRAY_VIEW_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rtc_base/type_traits.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// tl;dr: rtc::ArrayView is the same thing as gsl::span from the Guideline
|
||||
// Support Library.
|
||||
//
|
||||
// Many functions read from or write to arrays. The obvious way to do this is
|
||||
// to use two arguments, a pointer to the first element and an element count:
|
||||
//
|
||||
// bool Contains17(const int* arr, size_t size) {
|
||||
// for (size_t i = 0; i < size; ++i) {
|
||||
// if (arr[i] == 17)
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// This is flexible, since it doesn't matter how the array is stored (C array,
|
||||
// std::vector, rtc::Buffer, ...), but it's error-prone because the caller has
|
||||
// to correctly specify the array length:
|
||||
//
|
||||
// Contains17(arr, arraysize(arr)); // C array
|
||||
// Contains17(arr.data(), arr.size()); // std::vector
|
||||
// Contains17(arr, size); // pointer + size
|
||||
// ...
|
||||
//
|
||||
// It's also kind of messy to have two separate arguments for what is
|
||||
// conceptually a single thing.
|
||||
//
|
||||
// Enter rtc::ArrayView<T>. It contains a T pointer (to an array it doesn't
|
||||
// own) and a count, and supports the basic things you'd expect, such as
|
||||
// indexing and iteration. It allows us to write our function like this:
|
||||
//
|
||||
// bool Contains17(rtc::ArrayView<const int> arr) {
|
||||
// for (auto e : arr) {
|
||||
// if (e == 17)
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// And even better, because a bunch of things will implicitly convert to
|
||||
// ArrayView, we can call it like this:
|
||||
//
|
||||
// Contains17(arr); // C array
|
||||
// Contains17(arr); // std::vector
|
||||
// Contains17(rtc::ArrayView<int>(arr, size)); // pointer + size
|
||||
// Contains17(nullptr); // nullptr -> empty ArrayView
|
||||
// ...
|
||||
//
|
||||
// ArrayView<T> stores both a pointer and a size, but you may also use
|
||||
// ArrayView<T, N>, which has a size that's fixed at compile time (which means
|
||||
// it only has to store the pointer).
|
||||
//
|
||||
// One important point is that ArrayView<T> and ArrayView<const T> are
|
||||
// different types, which allow and don't allow mutation of the array elements,
|
||||
// respectively. The implicit conversions work just like you'd hope, so that
|
||||
// e.g. vector<int> will convert to either ArrayView<int> or ArrayView<const
|
||||
// int>, but const vector<int> will convert only to ArrayView<const int>.
|
||||
// (ArrayView itself can be the source type in such conversions, so
|
||||
// ArrayView<int> will convert to ArrayView<const int>.)
|
||||
//
|
||||
// Note: ArrayView is tiny (just a pointer and a count if variable-sized, just
|
||||
// a pointer if fix-sized) and trivially copyable, so it's probably cheaper to
|
||||
// pass it by value than by const reference.
|
||||
|
||||
namespace array_view_internal {
|
||||
|
||||
// Magic constant for indicating that the size of an ArrayView is variable
|
||||
// instead of fixed.
|
||||
enum : std::ptrdiff_t { kArrayViewVarSize = -4711 };
|
||||
|
||||
// Base class for ArrayViews of fixed nonzero size.
|
||||
template <typename T, std::ptrdiff_t Size>
|
||||
class ArrayViewBase {
|
||||
static_assert(Size > 0, "ArrayView size must be variable or non-negative");
|
||||
|
||||
public:
|
||||
ArrayViewBase(T* data, size_t /* size */) : data_(data) {}
|
||||
|
||||
static constexpr size_t size() { return Size; }
|
||||
static constexpr bool empty() { return false; }
|
||||
T* data() const { return data_; }
|
||||
|
||||
protected:
|
||||
static constexpr bool fixed_size() { return true; }
|
||||
|
||||
private:
|
||||
T* data_;
|
||||
};
|
||||
|
||||
// Specialized base class for ArrayViews of fixed zero size.
|
||||
template <typename T>
|
||||
class ArrayViewBase<T, 0> {
|
||||
public:
|
||||
explicit ArrayViewBase(T* /* data */, size_t /* size */) {}
|
||||
|
||||
static constexpr size_t size() { return 0; }
|
||||
static constexpr bool empty() { return true; }
|
||||
T* data() const { return nullptr; }
|
||||
|
||||
protected:
|
||||
static constexpr bool fixed_size() { return true; }
|
||||
};
|
||||
|
||||
// Specialized base class for ArrayViews of variable size.
|
||||
template <typename T>
|
||||
class ArrayViewBase<T, array_view_internal::kArrayViewVarSize> {
|
||||
public:
|
||||
ArrayViewBase(T* data, size_t size)
|
||||
: data_(size == 0 ? nullptr : data), size_(size) {}
|
||||
|
||||
size_t size() const { return size_; }
|
||||
bool empty() const { return size_ == 0; }
|
||||
T* data() const { return data_; }
|
||||
|
||||
protected:
|
||||
static constexpr bool fixed_size() { return false; }
|
||||
|
||||
private:
|
||||
T* data_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
} // namespace array_view_internal
|
||||
|
||||
template <typename T,
|
||||
std::ptrdiff_t Size = array_view_internal::kArrayViewVarSize>
|
||||
class ArrayView final : public array_view_internal::ArrayViewBase<T, Size> {
|
||||
public:
|
||||
using value_type = T;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using const_iterator = const T*;
|
||||
|
||||
// Construct an ArrayView from a pointer and a length.
|
||||
template <typename U>
|
||||
ArrayView(U* data, size_t size)
|
||||
: array_view_internal::ArrayViewBase<T, Size>::ArrayViewBase(data, size) {
|
||||
}
|
||||
|
||||
// Construct an empty ArrayView. Note that fixed-size ArrayViews of size > 0
|
||||
// cannot be empty.
|
||||
ArrayView() : ArrayView(nullptr, 0) {}
|
||||
ArrayView(std::nullptr_t) // NOLINT
|
||||
: ArrayView() {}
|
||||
ArrayView(std::nullptr_t, size_t size)
|
||||
: ArrayView(static_cast<T*>(nullptr), size) {
|
||||
static_assert(Size == 0 || Size == array_view_internal::kArrayViewVarSize,
|
||||
"");
|
||||
}
|
||||
|
||||
// Construct an ArrayView from a C-style array.
|
||||
template <typename U, size_t N>
|
||||
ArrayView(U (&array)[N]) // NOLINT
|
||||
: ArrayView(array, N) {
|
||||
static_assert(Size == N || Size == array_view_internal::kArrayViewVarSize,
|
||||
"Array size must match ArrayView size");
|
||||
}
|
||||
|
||||
// (Only if size is fixed.) Construct a fixed size ArrayView<T, N> from a
|
||||
// non-const std::array instance. For an ArrayView with variable size, the
|
||||
// used ctor is ArrayView(U& u) instead.
|
||||
template <typename U, size_t N,
|
||||
typename std::enable_if<
|
||||
Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr>
|
||||
ArrayView(std::array<U, N>& u) // NOLINT
|
||||
: ArrayView(u.data(), u.size()) {}
|
||||
|
||||
// (Only if size is fixed.) Construct a fixed size ArrayView<T, N> where T is
|
||||
// const from a const(expr) std::array instance. For an ArrayView with
|
||||
// variable size, the used ctor is ArrayView(U& u) instead.
|
||||
template <typename U, size_t N,
|
||||
typename std::enable_if<
|
||||
Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr>
|
||||
ArrayView(const std::array<U, N>& u) // NOLINT
|
||||
: ArrayView(u.data(), u.size()) {}
|
||||
|
||||
// (Only if size is fixed.) Construct an ArrayView from any type U that has a
|
||||
// static constexpr size() method whose return value is equal to Size, and a
|
||||
// data() method whose return value converts implicitly to T*. In particular,
|
||||
// this means we allow conversion from ArrayView<T, N> to ArrayView<const T,
|
||||
// N>, but not the other way around. We also don't allow conversion from
|
||||
// ArrayView<T> to ArrayView<T, N>, or from ArrayView<T, M> to ArrayView<T,
|
||||
// N> when M != N.
|
||||
template <typename U, typename std::enable_if<
|
||||
Size != array_view_internal::kArrayViewVarSize &&
|
||||
HasDataAndSize<U, T>::value>::type* = nullptr>
|
||||
ArrayView(U& u) // NOLINT
|
||||
: ArrayView(u.data(), u.size()) {
|
||||
static_assert(U::size() == Size, "Sizes must match exactly");
|
||||
}
|
||||
template <typename U, typename std::enable_if<
|
||||
Size != array_view_internal::kArrayViewVarSize &&
|
||||
HasDataAndSize<U, T>::value>::type* = nullptr>
|
||||
ArrayView(const U& u) // NOLINT(runtime/explicit)
|
||||
: ArrayView(u.data(), u.size()) {
|
||||
static_assert(U::size() == Size, "Sizes must match exactly");
|
||||
}
|
||||
|
||||
// (Only if size is variable.) Construct an ArrayView from any type U that
|
||||
// has a size() method whose return value converts implicitly to size_t, and
|
||||
// a data() method whose return value converts implicitly to T*. In
|
||||
// particular, this means we allow conversion from ArrayView<T> to
|
||||
// ArrayView<const T>, but not the other way around. Other allowed
|
||||
// conversions include
|
||||
// ArrayView<T, N> to ArrayView<T> or ArrayView<const T>,
|
||||
// std::vector<T> to ArrayView<T> or ArrayView<const T>,
|
||||
// const std::vector<T> to ArrayView<const T>,
|
||||
// rtc::Buffer to ArrayView<uint8_t> or ArrayView<const uint8_t>, and
|
||||
// const rtc::Buffer to ArrayView<const uint8_t>.
|
||||
template <typename U, typename std::enable_if<
|
||||
Size == array_view_internal::kArrayViewVarSize &&
|
||||
HasDataAndSize<U, T>::value>::type* = nullptr>
|
||||
ArrayView(U& u) // NOLINT
|
||||
: ArrayView(u.data(), u.size()) {}
|
||||
template <typename U, typename std::enable_if<
|
||||
Size == array_view_internal::kArrayViewVarSize &&
|
||||
HasDataAndSize<U, T>::value>::type* = nullptr>
|
||||
ArrayView(const U& u) // NOLINT(runtime/explicit)
|
||||
: ArrayView(u.data(), u.size()) {}
|
||||
|
||||
// Indexing and iteration. These allow mutation even if the ArrayView is
|
||||
// const, because the ArrayView doesn't own the array. (To prevent mutation,
|
||||
// use a const element type.)
|
||||
T& operator[](size_t idx) const { return this->data()[idx]; }
|
||||
T* begin() const { return this->data(); }
|
||||
T* end() const { return this->data() + this->size(); }
|
||||
const T* cbegin() const { return this->data(); }
|
||||
const T* cend() const { return this->data() + this->size(); }
|
||||
std::reverse_iterator<T*> rbegin() const {
|
||||
return std::make_reverse_iterator(end());
|
||||
}
|
||||
std::reverse_iterator<T*> rend() const {
|
||||
return std::make_reverse_iterator(begin());
|
||||
}
|
||||
std::reverse_iterator<const T*> crbegin() const {
|
||||
return std::make_reverse_iterator(cend());
|
||||
}
|
||||
std::reverse_iterator<const T*> crend() const {
|
||||
return std::make_reverse_iterator(cbegin());
|
||||
}
|
||||
|
||||
ArrayView<T> subview(size_t offset, size_t size) const {
|
||||
return offset < this->size()
|
||||
? ArrayView<T>(this->data() + offset,
|
||||
std::min(size, this->size() - offset))
|
||||
: ArrayView<T>();
|
||||
}
|
||||
ArrayView<T> subview(size_t offset) const {
|
||||
return subview(offset, this->size());
|
||||
}
|
||||
};
|
||||
|
||||
// Comparing two ArrayViews compares their (pointer,size) pairs; it does *not*
|
||||
// dereference the pointers.
|
||||
template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2>
|
||||
bool operator==(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) {
|
||||
return a.data() == b.data() && a.size() == b.size();
|
||||
}
|
||||
template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2>
|
||||
bool operator!=(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// Variable-size ArrayViews are the size of two pointers; fixed-size ArrayViews
|
||||
// are the size of one pointer. (And as a special case, fixed-size ArrayViews
|
||||
// of size 0 require no storage.)
|
||||
static_assert(sizeof(ArrayView<int>) == 2 * sizeof(int*), "");
|
||||
static_assert(sizeof(ArrayView<int, 17>) == sizeof(int*), "");
|
||||
static_assert(std::is_empty<ArrayView<int, 0>>::value, "");
|
||||
|
||||
template <typename T>
|
||||
inline ArrayView<T> MakeArrayView(T* data, size_t size) {
|
||||
return ArrayView<T>(data, size);
|
||||
}
|
||||
|
||||
// Only for primitive types that have the same size and aligment.
|
||||
// Allow reinterpret cast of the array view to another primitive type of the
|
||||
// same size.
|
||||
// Template arguments order is (U, T, Size) to allow deduction of the template
|
||||
// arguments in client calls: reinterpret_array_view<target_type>(array_view).
|
||||
template <typename U, typename T, std::ptrdiff_t Size>
|
||||
inline ArrayView<U, Size> reinterpret_array_view(ArrayView<T, Size> view) {
|
||||
static_assert(sizeof(U) == sizeof(T) && alignof(U) == alignof(T),
|
||||
"ArrayView reinterpret_cast is only supported for casting "
|
||||
"between views that represent the same chunk of memory.");
|
||||
static_assert(
|
||||
std::is_fundamental<T>::value && std::is_fundamental<U>::value,
|
||||
"ArrayView reinterpret_cast is only supported for casting between "
|
||||
"fundamental types.");
|
||||
return ArrayView<U, Size>(reinterpret_cast<U*>(view.data()), view.size());
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // API_ARRAY_VIEW_H_
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* 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 "api/clock/clock.h"
|
||||
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
int64_t NtpOffsetUsCalledOnce() {
|
||||
constexpr int64_t kNtpJan1970Sec = 2208988800;
|
||||
int64_t clock_time = rtc::TimeMicros();
|
||||
int64_t utc_time = rtc::TimeUTCMicros();
|
||||
return utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec;
|
||||
}
|
||||
|
||||
NtpTime TimeMicrosToNtp(int64_t time_us) {
|
||||
static int64_t ntp_offset_us = NtpOffsetUsCalledOnce();
|
||||
|
||||
int64_t time_ntp_us = time_us + ntp_offset_us;
|
||||
|
||||
// Convert seconds to uint32 through uint64 for a well-defined cast.
|
||||
// A wrap around, which will happen in 2036, is expected for NTP time.
|
||||
uint32_t ntp_seconds =
|
||||
static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec);
|
||||
|
||||
// Scale fractions of the second to NTP resolution.
|
||||
constexpr int64_t kNtpFractionsInSecond = 1LL << 32;
|
||||
int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec;
|
||||
uint32_t ntp_fractions =
|
||||
us_fractions * kNtpFractionsInSecond / rtc::kNumMicrosecsPerSec;
|
||||
|
||||
return NtpTime(ntp_seconds, ntp_fractions);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class WebrtcClock : public Clock {
|
||||
public:
|
||||
WebrtcClock(std::shared_ptr<SystemClock> system_clock)
|
||||
: system_clock_(system_clock) {}
|
||||
WebrtcClock() = delete;
|
||||
|
||||
Timestamp CurrentTime() override {
|
||||
return Timestamp::Micros(system_clock_->CurrentTimeUs());
|
||||
}
|
||||
|
||||
NtpTime ConvertTimestampToNtpTime(Timestamp timestamp) override {
|
||||
int64_t time_us = timestamp.us();
|
||||
constexpr int64_t kNtpJan1970Sec = 2208988800;
|
||||
int64_t clock_time = system_clock_->CurrentTimeUs();
|
||||
int64_t utc_time = system_clock_->CurrentUtcTimeUs();
|
||||
static int64_t ntp_offset_us =
|
||||
utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec;
|
||||
|
||||
int64_t time_ntp_us = time_us + ntp_offset_us;
|
||||
|
||||
// Convert seconds to uint32 through uint64 for a well-defined cast.
|
||||
// A wrap around, which will happen in 2036, is expected for NTP time.
|
||||
uint32_t ntp_seconds =
|
||||
static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec);
|
||||
|
||||
// Scale fractions of the second to NTP resolution.
|
||||
constexpr int64_t kNtpFractionsInSecond = 1LL << 32;
|
||||
int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec;
|
||||
uint32_t ntp_fractions =
|
||||
us_fractions * kNtpFractionsInSecond / rtc::kNumMicrosecsPerSec;
|
||||
|
||||
return NtpTime(ntp_seconds, ntp_fractions);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<SystemClock> system_clock_;
|
||||
};
|
||||
|
||||
Clock* Clock::GetWebrtcClock(std::shared_ptr<SystemClock> system_clock) {
|
||||
static Clock* const clock = new WebrtcClock(system_clock);
|
||||
return clock;
|
||||
}
|
||||
|
||||
std::shared_ptr<Clock> Clock::GetWebrtcClockShared(
|
||||
std::shared_ptr<SystemClock> system_clock) {
|
||||
return std::make_shared<WebrtcClock>(system_clock);
|
||||
}
|
||||
} // namespace webrtc
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
|
||||
#define SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "api/ntp/ntp_time.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "clock/system_clock.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// January 1970, in NTP seconds.
|
||||
const uint32_t kNtpJan1970 = 2208988800UL;
|
||||
|
||||
// Magic NTP fractional unit.
|
||||
const double kMagicNtpFractionalUnit = 4.294967296E+9;
|
||||
|
||||
// A clock interface that allows reading of absolute and relative timestamps.
|
||||
class Clock {
|
||||
public:
|
||||
virtual ~Clock() {}
|
||||
|
||||
// Return a timestamp relative to an unspecified epoch.
|
||||
virtual Timestamp CurrentTime() = 0;
|
||||
int64_t TimeInMilliseconds() { return CurrentTime().ms(); }
|
||||
int64_t TimeInMicroseconds() { return CurrentTime().us(); }
|
||||
|
||||
// Retrieve an NTP absolute timestamp (with an epoch of Jan 1, 1900).
|
||||
NtpTime CurrentNtpTime() { return ConvertTimestampToNtpTime(CurrentTime()); }
|
||||
int64_t CurrentNtpInMilliseconds() { return CurrentNtpTime().ToMs(); }
|
||||
|
||||
// Converts between a relative timestamp returned by this clock, to NTP time.
|
||||
virtual NtpTime ConvertTimestampToNtpTime(Timestamp timestamp) = 0;
|
||||
int64_t ConvertTimestampToNtpTimeInMilliseconds(int64_t timestamp_ms) {
|
||||
return ConvertTimestampToNtpTime(Timestamp::Millis(timestamp_ms)).ToMs();
|
||||
}
|
||||
|
||||
// Converts NtpTime to a Timestamp with UTC epoch.
|
||||
// A `Minus Infinity` Timestamp is returned if the NtpTime is invalid.
|
||||
static Timestamp NtpToUtc(NtpTime ntp_time) {
|
||||
if (!ntp_time.Valid()) {
|
||||
return Timestamp::MinusInfinity();
|
||||
}
|
||||
// Seconds since UTC epoch.
|
||||
int64_t time = ntp_time.seconds() - kNtpJan1970;
|
||||
// Microseconds since UTC epoch (not including NTP fraction)
|
||||
time = time * 1'000'000;
|
||||
// Fractions part of the NTP time, in microseconds.
|
||||
int64_t time_fraction =
|
||||
DivideRoundToNearest(int64_t{ntp_time.fractions()} * 1'000'000,
|
||||
NtpTime::kFractionsPerSecond);
|
||||
return Timestamp::Micros(time + time_fraction);
|
||||
}
|
||||
|
||||
// Returns an instance of the real-time system clock implementation.
|
||||
static Clock* GetWebrtcClock(std::shared_ptr<SystemClock> system_clock);
|
||||
static std::shared_ptr<Clock> GetWebrtcClockShared(
|
||||
std::shared_ptr<SystemClock> system_clock);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef API_FUNCTION_VIEW_H_
|
||||
#define API_FUNCTION_VIEW_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
// Just like std::function, FunctionView will wrap any callable and hide its
|
||||
// actual type, exposing only its signature. But unlike std::function,
|
||||
// FunctionView doesn't own its callable---it just points to it. Thus, it's a
|
||||
// good choice mainly as a function argument when the callable argument will
|
||||
// not be called again once the function has returned.
|
||||
//
|
||||
// Its constructors are implicit, so that callers won't have to convert lambdas
|
||||
// and other callables to FunctionView<Blah(Blah, Blah)> explicitly. This is
|
||||
// safe because FunctionView is only a reference to the real callable.
|
||||
//
|
||||
// Example use:
|
||||
//
|
||||
// void SomeFunction(rtc::FunctionView<int(int)> index_transform);
|
||||
// ...
|
||||
// SomeFunction([](int i) { return 2 * i + 1; });
|
||||
//
|
||||
// Note: FunctionView is tiny (essentially just two pointers) and trivially
|
||||
// copyable, so it's probably cheaper to pass it by value than by const
|
||||
// reference.
|
||||
|
||||
namespace rtc {
|
||||
|
||||
template <typename T>
|
||||
class FunctionView; // Undefined.
|
||||
|
||||
template <typename RetT, typename... ArgT>
|
||||
class FunctionView<RetT(ArgT...)> final {
|
||||
public:
|
||||
// Constructor for lambdas and other callables; it accepts every type of
|
||||
// argument except those noted in its enable_if call.
|
||||
template <
|
||||
typename F,
|
||||
typename std::enable_if<
|
||||
// Not for function pointers; we have another constructor for that
|
||||
// below.
|
||||
!std::is_function<typename std::remove_pointer<
|
||||
typename std::remove_reference<F>::type>::type>::value &&
|
||||
|
||||
// Not for nullptr; we have another constructor for that below.
|
||||
!std::is_same<std::nullptr_t,
|
||||
typename std::remove_cv<F>::type>::value &&
|
||||
|
||||
// Not for FunctionView objects; we have another constructor for that
|
||||
// (the implicitly declared copy constructor).
|
||||
!std::is_same<FunctionView,
|
||||
typename std::remove_cv<typename std::remove_reference<
|
||||
F>::type>::type>::value>::type* = nullptr>
|
||||
FunctionView(F&& f)
|
||||
: call_(CallVoidPtr<typename std::remove_reference<F>::type>) {
|
||||
f_.void_ptr = &f;
|
||||
}
|
||||
|
||||
// Constructor that accepts function pointers. If the argument is null, the
|
||||
// result is an empty FunctionView.
|
||||
template <
|
||||
typename F,
|
||||
typename std::enable_if<std::is_function<typename std::remove_pointer<
|
||||
typename std::remove_reference<F>::type>::type>::value>::type* =
|
||||
nullptr>
|
||||
FunctionView(F&& f)
|
||||
: call_(f ? CallFunPtr<typename std::remove_pointer<F>::type> : nullptr) {
|
||||
f_.fun_ptr = reinterpret_cast<void (*)()>(f);
|
||||
}
|
||||
|
||||
// Constructor that accepts nullptr. It creates an empty FunctionView.
|
||||
template <typename F, typename std::enable_if<std::is_same<
|
||||
std::nullptr_t, typename std::remove_cv<F>::type>::
|
||||
value>::type* = nullptr>
|
||||
FunctionView(F&& /* f */) : call_(nullptr) {}
|
||||
|
||||
// Default constructor. Creates an empty FunctionView.
|
||||
FunctionView() : call_(nullptr) {}
|
||||
|
||||
RetT operator()(ArgT... args) const {
|
||||
return call_(f_, std::forward<ArgT>(args)...);
|
||||
}
|
||||
|
||||
// Returns true if we have a function, false if we don't (i.e., we're null).
|
||||
explicit operator bool() const { return !!call_; }
|
||||
|
||||
private:
|
||||
union VoidUnion {
|
||||
void* void_ptr;
|
||||
void (*fun_ptr)();
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
static RetT CallVoidPtr(VoidUnion vu, ArgT... args) {
|
||||
return (*static_cast<F*>(vu.void_ptr))(std::forward<ArgT>(args)...);
|
||||
}
|
||||
template <typename F>
|
||||
static RetT CallFunPtr(VoidUnion vu, ArgT... args) {
|
||||
return (reinterpret_cast<typename std::add_pointer<F>::type>(vu.fun_ptr))(
|
||||
std::forward<ArgT>(args)...);
|
||||
}
|
||||
|
||||
// A pointer to the callable thing, with type information erased. It's a
|
||||
// union because we have to use separate types depending on if the callable
|
||||
// thing is a function pointer or something else.
|
||||
VoidUnion f_;
|
||||
|
||||
// Pointer to a dispatch function that knows the type of the callable thing
|
||||
// that's stored in f_, and how to call it. A FunctionView object is empty
|
||||
// (null) iff call_ is null.
|
||||
RetT (*call_)(VoidUnion, ArgT...);
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // API_FUNCTION_VIEW_H_
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef API_MEDIA_TYPES_H_
|
||||
#define API_MEDIA_TYPES_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
// The cricket and webrtc have separate definitions for what a media type is.
|
||||
// They're not compatible. Watch out for this.
|
||||
|
||||
namespace cricket {
|
||||
|
||||
enum MediaType {
|
||||
MEDIA_TYPE_AUDIO,
|
||||
MEDIA_TYPE_VIDEO,
|
||||
MEDIA_TYPE_DATA,
|
||||
MEDIA_TYPE_UNSUPPORTED
|
||||
};
|
||||
|
||||
extern const char kMediaTypeAudio[];
|
||||
extern const char kMediaTypeVideo[];
|
||||
extern const char kMediaTypeData[];
|
||||
|
||||
std::string MediaTypeToString(MediaType type);
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
enum class MediaType { ANY, AUDIO, VIDEO, DATA };
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_MEDIA_TYPES_H_
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef API_NETWORK_STATE_PREDICTOR_H_
|
||||
#define API_NETWORK_STATE_PREDICTOR_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "api/transport/bandwidth_usage.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// TODO(yinwa): work in progress. API in class NetworkStatePredictor should not
|
||||
// be used by other users until this comment is removed.
|
||||
|
||||
// NetworkStatePredictor predict network state based on current network metrics.
|
||||
// Usage:
|
||||
// Setup by calling Initialize.
|
||||
// For each update, call Update. Update returns network state
|
||||
// prediction.
|
||||
class NetworkStatePredictor {
|
||||
public:
|
||||
virtual ~NetworkStatePredictor() {}
|
||||
|
||||
// Returns current network state prediction.
|
||||
// Inputs: send_time_ms - packet send time.
|
||||
// arrival_time_ms - packet arrival time.
|
||||
// network_state - computed network state.
|
||||
virtual BandwidthUsage Update(int64_t send_time_ms,
|
||||
int64_t arrival_time_ms,
|
||||
BandwidthUsage network_state) = 0;
|
||||
};
|
||||
|
||||
class NetworkStatePredictorFactoryInterface {
|
||||
public:
|
||||
virtual std::unique_ptr<NetworkStatePredictor>
|
||||
CreateNetworkStatePredictor() = 0;
|
||||
virtual ~NetworkStatePredictorFactoryInterface() = default;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_NETWORK_STATE_PREDICTOR_H_
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
|
||||
#define SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class NtpTime {
|
||||
public:
|
||||
static constexpr uint64_t kFractionsPerSecond = 0x100000000;
|
||||
NtpTime() : value_(0) {}
|
||||
explicit NtpTime(uint64_t value) : value_(value) {}
|
||||
NtpTime(uint32_t seconds, uint32_t fractions)
|
||||
: value_(seconds * kFractionsPerSecond + fractions) {}
|
||||
|
||||
NtpTime(const NtpTime&) = default;
|
||||
NtpTime& operator=(const NtpTime&) = default;
|
||||
explicit operator uint64_t() const { return value_; }
|
||||
|
||||
void Set(uint32_t seconds, uint32_t fractions) {
|
||||
value_ = seconds * kFractionsPerSecond + fractions;
|
||||
}
|
||||
void Reset() { value_ = 0; }
|
||||
|
||||
int64_t ToMs() const {
|
||||
static constexpr double kNtpFracPerMs = 4.294967296E6; // 2^32 / 1000.
|
||||
const double frac_ms = static_cast<double>(fractions()) / kNtpFracPerMs;
|
||||
return 1000 * static_cast<int64_t>(seconds()) +
|
||||
static_cast<int64_t>(frac_ms + 0.5);
|
||||
}
|
||||
// NTP standard (RFC1305, section 3.1) explicitly state value 0 is invalid.
|
||||
bool Valid() const { return value_ != 0; }
|
||||
|
||||
uint32_t seconds() const {
|
||||
return rtc::dchecked_cast<uint32_t>(value_ / kFractionsPerSecond);
|
||||
}
|
||||
uint32_t fractions() const {
|
||||
return rtc::dchecked_cast<uint32_t>(value_ % kFractionsPerSecond);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t value_;
|
||||
};
|
||||
|
||||
inline bool operator==(const NtpTime& n1, const NtpTime& n2) {
|
||||
return static_cast<uint64_t>(n1) == static_cast<uint64_t>(n2);
|
||||
}
|
||||
inline bool operator!=(const NtpTime& n1, const NtpTime& n2) {
|
||||
return !(n1 == n2);
|
||||
}
|
||||
|
||||
// Converts `int64_t` milliseconds to Q32.32-formatted fixed-point seconds.
|
||||
// Performs clamping if the result overflows or underflows.
|
||||
inline int64_t Int64MsToQ32x32(int64_t milliseconds) {
|
||||
// TODO(bugs.webrtc.org/10893): Change to use `rtc::saturated_cast` once the
|
||||
// bug has been fixed.
|
||||
double result =
|
||||
std::round(milliseconds * (NtpTime::kFractionsPerSecond / 1000.0));
|
||||
|
||||
// Explicitly cast values to double to avoid implicit conversion warnings
|
||||
// The conversion of the std::numeric_limits<int64_t>::max() triggers
|
||||
// -Wimplicit-int-float-conversion warning in clang 10.0.0 without explicit
|
||||
// cast
|
||||
if (result <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
|
||||
return std::numeric_limits<int64_t>::min();
|
||||
}
|
||||
|
||||
if (result >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
|
||||
return rtc::dchecked_cast<int64_t>(result);
|
||||
}
|
||||
|
||||
// Converts `int64_t` milliseconds to UQ32.32-formatted fixed-point seconds.
|
||||
// Performs clamping if the result overflows or underflows.
|
||||
inline uint64_t Int64MsToUQ32x32(int64_t milliseconds) {
|
||||
// TODO(bugs.webrtc.org/10893): Change to use `rtc::saturated_cast` once the
|
||||
// bug has been fixed.
|
||||
double result =
|
||||
std::round(milliseconds * (NtpTime::kFractionsPerSecond / 1000.0));
|
||||
|
||||
// Explicitly cast values to double to avoid implicit conversion warnings
|
||||
// The conversion of the std::numeric_limits<int64_t>::max() triggers
|
||||
// -Wimplicit-int-float-conversion warning in clang 10.0.0 without explicit
|
||||
// cast
|
||||
if (result <= static_cast<double>(std::numeric_limits<uint64_t>::min())) {
|
||||
return std::numeric_limits<uint64_t>::min();
|
||||
}
|
||||
|
||||
if (result >= static_cast<double>(std::numeric_limits<uint64_t>::max())) {
|
||||
return std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
|
||||
return rtc::dchecked_cast<uint64_t>(result);
|
||||
}
|
||||
|
||||
// Converts Q32.32-formatted fixed-point seconds to `int64_t` milliseconds.
|
||||
inline int64_t Q32x32ToInt64Ms(int64_t q32x32) {
|
||||
return rtc::dchecked_cast<int64_t>(
|
||||
std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond)));
|
||||
}
|
||||
|
||||
// Converts UQ32.32-formatted fixed-point seconds to `int64_t` milliseconds.
|
||||
inline int64_t UQ32x32ToInt64Ms(uint64_t q32x32) {
|
||||
return rtc::dchecked_cast<int64_t>(
|
||||
std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond)));
|
||||
}
|
||||
|
||||
// Converts UQ32.32-formatted fixed-point seconds to `int64_t` microseconds.
|
||||
inline int64_t UQ32x32ToInt64Us(uint64_t q32x32) {
|
||||
return rtc::dchecked_cast<int64_t>(
|
||||
std::round(q32x32 * (1'000'000.0 / NtpTime::kFractionsPerSecond)));
|
||||
}
|
||||
|
||||
// Converts Q32.32-formatted fixed-point seconds to `int64_t` microseconds.
|
||||
inline int64_t Q32x32ToInt64Us(int64_t q32x32) {
|
||||
return rtc::dchecked_cast<int64_t>(
|
||||
std::round(q32x32 * (1'000'000.0 / NtpTime::kFractionsPerSecond)));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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 "api/ntp/ntp_time_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/numerics/divide_round.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
uint32_t SaturatedToCompactNtp(TimeDelta delta) {
|
||||
constexpr uint32_t kMaxCompactNtp = 0xFFFFFFFF;
|
||||
constexpr int kCompactNtpInSecond = 0x10000;
|
||||
if (delta <= TimeDelta::Zero()) return 0;
|
||||
if (delta.us() >=
|
||||
kMaxCompactNtp * rtc::kNumMicrosecsPerSec / kCompactNtpInSecond)
|
||||
return kMaxCompactNtp;
|
||||
// To convert to compact ntp need to divide by 1e6 to get seconds,
|
||||
// then multiply by 0x10000 to get the final result.
|
||||
// To avoid float operations, multiplication and division swapped.
|
||||
return DivideRoundToNearest(delta.us() * kCompactNtpInSecond,
|
||||
rtc::kNumMicrosecsPerSec);
|
||||
}
|
||||
|
||||
TimeDelta CompactNtpIntervalToTimeDelta(uint32_t compact_ntp_interval) {
|
||||
// Convert to 64bit value to avoid multiplication overflow.
|
||||
int64_t value = int64_t{compact_ntp_interval};
|
||||
if (compact_ntp_interval > 0x8000'0000) {
|
||||
value -= (int64_t{1} << 32);
|
||||
}
|
||||
// To convert to TimeDelta need to divide by 2^16 to get seconds,
|
||||
// then multiply by 1'000'000 to get microseconds. To avoid float operations,
|
||||
// multiplication and division are swapped.
|
||||
int64_t us = DivideRoundToNearest(value * rtc::kNumMicrosecsPerSec, 1 << 16);
|
||||
return TimeDelta::Micros(us);
|
||||
}
|
||||
|
||||
TimeDelta CompactNtpRttToTimeDelta(uint32_t compact_ntp_interval) {
|
||||
static constexpr TimeDelta kMinRtt = TimeDelta::Millis(1);
|
||||
// Interval to convert expected to be positive, e.g. RTT or delay.
|
||||
// Because interval can be derived from non-monotonic ntp clock,
|
||||
// it might become negative that is indistinguishable from very large values.
|
||||
// Since very large RTT/delay is less likely than non-monotonic ntp clock,
|
||||
// such value is considered negative and converted to minimum value of 1ms.
|
||||
// Small RTT value is considered too good to be true and increased to 1ms.
|
||||
return std::max(CompactNtpIntervalToTimeDelta(compact_ntp_interval), kMinRtt);
|
||||
}
|
||||
} // namespace webrtc
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_RTP_RTCP_SOURCE_NTP_TIME_UTIL_H_
|
||||
#define MODULES_RTP_RTCP_SOURCE_NTP_TIME_UTIL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api/ntp/ntp_time.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Helper function for compact ntp representation:
|
||||
// RFC 3550, Section 4. Time Format.
|
||||
// Wallclock time is represented using the timestamp format of
|
||||
// the Network Time Protocol (NTP).
|
||||
// ...
|
||||
// In some fields where a more compact representation is
|
||||
// appropriate, only the middle 32 bits are used; that is, the low 16
|
||||
// bits of the integer part and the high 16 bits of the fractional part.
|
||||
inline uint32_t CompactNtp(NtpTime ntp) {
|
||||
return (ntp.seconds() << 16) | (ntp.fractions() >> 16);
|
||||
}
|
||||
|
||||
// Converts interval to compact ntp (1/2^16 seconds) resolution.
|
||||
// Negative values converted to 0, Overlarge values converted to max uint32_t.
|
||||
uint32_t SaturatedToCompactNtp(TimeDelta delta);
|
||||
|
||||
// Convert interval to the NTP time resolution (1/2^32 seconds ~= 0.2 ns).
|
||||
// For deltas with absolute value larger than 35 minutes result is unspecified.
|
||||
inline constexpr int64_t ToNtpUnits(TimeDelta delta) {
|
||||
// For better precision `delta` is taken with best TimeDelta precision (us),
|
||||
// then multiplaction and conversion to seconds are swapped to avoid float
|
||||
// arithmetic.
|
||||
// 2^31 us ~= 35.8 minutes.
|
||||
return (rtc::saturated_cast<int32_t>(delta.us()) * (int64_t{1} << 32)) /
|
||||
1'000'000;
|
||||
}
|
||||
|
||||
// Converts interval from compact ntp (1/2^16 seconds) resolution to TimeDelta.
|
||||
// This interval can be up to ~9.1 hours (2^15 seconds).
|
||||
// Values close to 2^16 seconds are considered negative.
|
||||
TimeDelta CompactNtpIntervalToTimeDelta(uint32_t compact_ntp_interval);
|
||||
|
||||
// Converts interval from compact ntp (1/2^16 seconds) resolution to TimeDelta.
|
||||
// This interval can be up to ~9.1 hours (2^15 seconds).
|
||||
// Values close to 2^16 seconds are considered negative and are converted to
|
||||
// minimum value of 1ms.
|
||||
TimeDelta CompactNtpRttToTimeDelta(uint32_t compact_ntp_interval);
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // MODULES_RTP_RTCP_SOURCE_NTP_TIME_UTIL_H_
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 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 API_REF_COUNT_H_
|
||||
#define API_REF_COUNT_H_
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Refcounted objects should implement the following informal interface:
|
||||
//
|
||||
// void AddRef() const ;
|
||||
// RefCountReleaseStatus Release() const;
|
||||
//
|
||||
// You may access members of a reference-counted object, including the AddRef()
|
||||
// and Release() methods, only if you already own a reference to it, or if
|
||||
// you're borrowing someone else's reference. (A newly created object is a
|
||||
// special case: the reference count is zero on construction, and the code that
|
||||
// creates the object should immediately call AddRef(), bringing the reference
|
||||
// count from zero to one, e.g., by constructing an rtc::scoped_refptr).
|
||||
//
|
||||
// AddRef() creates a new reference to the object.
|
||||
//
|
||||
// Release() releases a reference to the object; the caller now has one less
|
||||
// reference than before the call. Returns kDroppedLastRef if the number of
|
||||
// references dropped to zero because of this (in which case the object destroys
|
||||
// itself). Otherwise, returns kOtherRefsRemained, to signal that at the precise
|
||||
// time the caller's reference was dropped, other references still remained (but
|
||||
// if other threads own references, this may of course have changed by the time
|
||||
// Release() returns).
|
||||
//
|
||||
// The caller of Release() must treat it in the same way as a delete operation:
|
||||
// Regardless of the return value from Release(), the caller mustn't access the
|
||||
// object. The object might still be alive, due to references held by other
|
||||
// users of the object, but the object can go away at any time, e.g., as the
|
||||
// result of another thread calling Release().
|
||||
//
|
||||
// Calling AddRef() and Release() manually is discouraged. It's recommended to
|
||||
// use rtc::scoped_refptr to manage all pointers to reference counted objects.
|
||||
// Note that rtc::scoped_refptr depends on compile-time duck-typing; formally
|
||||
// implementing the below RefCountInterface is not required.
|
||||
|
||||
enum class RefCountReleaseStatus { kDroppedLastRef, kOtherRefsRemained };
|
||||
|
||||
// Interfaces where refcounting is part of the public api should
|
||||
// inherit this abstract interface. The implementation of these
|
||||
// methods is usually provided by the RefCountedObject template class,
|
||||
// applied as a leaf in the inheritance tree.
|
||||
class RefCountInterface {
|
||||
public:
|
||||
virtual void AddRef() const = 0;
|
||||
virtual RefCountReleaseStatus Release() const = 0;
|
||||
|
||||
// Non-public destructor, because Release() has exclusive responsibility for
|
||||
// destroying the object.
|
||||
protected:
|
||||
virtual ~RefCountInterface() {}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_REF_COUNT_H_
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef API_REF_COUNTED_BASE_H_
|
||||
#define API_REF_COUNTED_BASE_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "api/ref_count.h"
|
||||
#include "rtc_base/ref_counter.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RefCountedBase {
|
||||
public:
|
||||
RefCountedBase() = default;
|
||||
|
||||
RefCountedBase(const RefCountedBase&) = delete;
|
||||
RefCountedBase& operator=(const RefCountedBase&) = delete;
|
||||
|
||||
void AddRef() const { ref_count_.IncRef(); }
|
||||
RefCountReleaseStatus Release() const {
|
||||
const auto status = ref_count_.DecRef();
|
||||
if (status == RefCountReleaseStatus::kDroppedLastRef) {
|
||||
delete this;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Provided for internal webrtc subclasses for corner cases where it's
|
||||
// necessary to know whether or not a reference is exclusively held.
|
||||
bool HasOneRef() const { return ref_count_.HasOneRef(); }
|
||||
|
||||
virtual ~RefCountedBase() = default;
|
||||
|
||||
private:
|
||||
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
|
||||
};
|
||||
|
||||
// Template based version of `RefCountedBase` for simple implementations that do
|
||||
// not need (or want) destruction via virtual destructor or the overhead of a
|
||||
// vtable.
|
||||
//
|
||||
// To use:
|
||||
// struct MyInt : public rtc::RefCountedNonVirtual<MyInt> {
|
||||
// int foo_ = 0;
|
||||
// };
|
||||
//
|
||||
// rtc::scoped_refptr<MyInt> my_int(new MyInt());
|
||||
//
|
||||
// sizeof(MyInt) on a 32 bit system would then be 8, int + refcount and no
|
||||
// vtable generated.
|
||||
template <typename T>
|
||||
class RefCountedNonVirtual {
|
||||
public:
|
||||
RefCountedNonVirtual() = default;
|
||||
|
||||
RefCountedNonVirtual(const RefCountedNonVirtual&) = delete;
|
||||
RefCountedNonVirtual& operator=(const RefCountedNonVirtual&) = delete;
|
||||
|
||||
void AddRef() const { ref_count_.IncRef(); }
|
||||
RefCountReleaseStatus Release() const {
|
||||
// If you run into this assert, T has virtual methods. There are two
|
||||
// options:
|
||||
// 1) The class doesn't actually need virtual methods, the type is complete
|
||||
// so the virtual attribute(s) can be removed.
|
||||
// 2) The virtual methods are a part of the design of the class. In this
|
||||
// case you can consider using `RefCountedBase` instead or alternatively
|
||||
// use `rtc::RefCountedObject`.
|
||||
static_assert(!std::is_polymorphic<T>::value,
|
||||
"T has virtual methods. RefCountedBase is a better fit.");
|
||||
const auto status = ref_count_.DecRef();
|
||||
if (status == RefCountReleaseStatus::kDroppedLastRef) {
|
||||
delete static_cast<const T*>(this);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Provided for internal webrtc subclasses for corner cases where it's
|
||||
// necessary to know whether or not a reference is exclusively held.
|
||||
bool HasOneRef() const { return ref_count_.HasOneRef(); }
|
||||
|
||||
~RefCountedNonVirtual() = default;
|
||||
|
||||
private:
|
||||
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
// Backwards compatibe aliases.
|
||||
// TODO: https://issues.webrtc.org/42225969 - deprecate and remove.
|
||||
namespace rtc {
|
||||
using RefCountedBase = webrtc::RefCountedBase;
|
||||
template <typename T>
|
||||
using RefCountedNonVirtual = webrtc::RefCountedNonVirtual<T>;
|
||||
} // namespace rtc
|
||||
|
||||
#endif // API_REF_COUNTED_BASE_H_
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* 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 _RTP_RTCP_TYPEDEF_H_
|
||||
#define _RTP_RTCP_TYPEDEF_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
|
||||
#define RTCP_CNAME_SIZE 256 // RFC 3550 page 44, including null termination
|
||||
#define IP_PACKET_SIZE 1500 // we assume ethernet
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const int kVideoPayloadTypeFrequency = 90000;
|
||||
|
||||
// TODO(bugs.webrtc.org/6458): Remove this when all the depending projects are
|
||||
// updated to correctly set rtp rate for RtcpSender.
|
||||
const int kBogusRtpRateForAudioRtcp = 8000;
|
||||
|
||||
// Minimum RTP header size in bytes.
|
||||
const uint8_t kRtpHeaderSize = 12;
|
||||
|
||||
// This enum must not have any gaps, i.e., all integers between
|
||||
// kRtpExtensionNone and kRtpExtensionNumberOfExtensions must be valid enum
|
||||
// entries.
|
||||
enum RTPExtensionType : int {
|
||||
kRtpExtensionNone,
|
||||
kRtpExtensionTransmissionTimeOffset,
|
||||
kRtpExtensionAudioLevel,
|
||||
kRtpExtensionCsrcAudioLevel,
|
||||
kRtpExtensionInbandComfortNoise,
|
||||
kRtpExtensionAbsoluteSendTime,
|
||||
kRtpExtensionAbsoluteCaptureTime,
|
||||
kRtpExtensionVideoRotation,
|
||||
kRtpExtensionTransportSequenceNumber,
|
||||
kRtpExtensionTransportSequenceNumber02,
|
||||
kRtpExtensionPlayoutDelay,
|
||||
kRtpExtensionVideoContentType,
|
||||
kRtpExtensionVideoLayersAllocation,
|
||||
kRtpExtensionVideoTiming,
|
||||
kRtpExtensionRtpStreamId,
|
||||
kRtpExtensionRepairedRtpStreamId,
|
||||
kRtpExtensionMid,
|
||||
kRtpExtensionGenericFrameDescriptor,
|
||||
kRtpExtensionGenericFrameDescriptor00 [[deprecated]] =
|
||||
kRtpExtensionGenericFrameDescriptor,
|
||||
kRtpExtensionDependencyDescriptor,
|
||||
kRtpExtensionGenericFrameDescriptor02 [[deprecated]] =
|
||||
kRtpExtensionDependencyDescriptor,
|
||||
kRtpExtensionColorSpace,
|
||||
kRtpExtensionVideoFrameTrackingId,
|
||||
kRtpExtensionCorruptionDetection,
|
||||
kRtpExtensionNumberOfExtensions // Must be the last entity in the enum.
|
||||
};
|
||||
|
||||
enum RTCPAppSubTypes { kAppSubtypeBwe = 0x00 };
|
||||
|
||||
// TODO(sprang): Make this an enum class once rtcp_receiver has been cleaned up.
|
||||
enum RTCPPacketType : uint32_t {
|
||||
kRtcpReport = 0x0001,
|
||||
kRtcpSr = 0x0002,
|
||||
kRtcpRr = 0x0004,
|
||||
kRtcpSdes = 0x0008,
|
||||
kRtcpBye = 0x0010,
|
||||
kRtcpPli = 0x0020,
|
||||
kRtcpNack = 0x0040,
|
||||
kRtcpFir = 0x0080,
|
||||
kRtcpTmmbr = 0x0100,
|
||||
kRtcpTmmbn = 0x0200,
|
||||
kRtcpSrReq = 0x0400,
|
||||
kRtcpLossNotification = 0x2000,
|
||||
kRtcpRemb = 0x10000,
|
||||
kRtcpTransmissionTimeOffset = 0x20000,
|
||||
kRtcpXrReceiverReferenceTime = 0x40000,
|
||||
kRtcpXrDlrrReportBlock = 0x80000,
|
||||
kRtcpTransportFeedback = 0x100000,
|
||||
kRtcpXrTargetBitrate = 0x200000,
|
||||
};
|
||||
|
||||
enum class KeyFrameReqMethod : uint8_t {
|
||||
kNone, // Don't request keyframes.
|
||||
kPliRtcp, // Request keyframes through Picture Loss Indication.
|
||||
kFirRtcp // Request keyframes through Full Intra-frame Request.
|
||||
};
|
||||
|
||||
enum RtxMode {
|
||||
kRtxOff = 0x0,
|
||||
kRtxRetransmitted = 0x1, // Only send retransmissions over RTX.
|
||||
kRtxRedundantPayloads = 0x2 // Preventively send redundant payloads
|
||||
// instead of padding.
|
||||
};
|
||||
|
||||
const size_t kRtxHeaderSize = 2;
|
||||
|
||||
// NOTE! `kNumMediaTypes` must be kept in sync with RtpPacketMediaType!
|
||||
static constexpr size_t kNumMediaTypes = 5;
|
||||
enum class RtpPacketMediaType : size_t {
|
||||
kAudio, // Audio media packets.
|
||||
kVideo, // Video media packets.
|
||||
kRetransmission, // Retransmisions, sent as response to NACK.
|
||||
kForwardErrorCorrection, // FEC packets.
|
||||
kPadding = kNumMediaTypes - 1, // RTX or plain padding sent to maintain BWE.
|
||||
// Again, don't forget to update `kNumMediaTypes` if you add another value!
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // _RTP_RTCP_TYPEDEF_H_
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
// Originally these classes are from Chromium.
|
||||
// http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h?view=markup
|
||||
|
||||
//
|
||||
// A smart pointer class for reference counted objects. Use this class instead
|
||||
// of calling AddRef and Release manually on a reference counted object to
|
||||
// avoid common memory leaks caused by forgetting to Release an object
|
||||
// reference. Sample usage:
|
||||
//
|
||||
// class MyFoo : public RefCounted<MyFoo> {
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// void some_function() {
|
||||
// scoped_refptr<MyFoo> foo = make_ref_counted<MyFoo>();
|
||||
// foo->Method(param);
|
||||
// // `foo` is released when this function returns
|
||||
// }
|
||||
//
|
||||
// void some_other_function() {
|
||||
// scoped_refptr<MyFoo> foo = make_ref_counted<MyFoo>();
|
||||
// ...
|
||||
// foo = nullptr; // explicitly releases `foo`
|
||||
// ...
|
||||
// if (foo)
|
||||
// foo->Method(param);
|
||||
// }
|
||||
//
|
||||
// The above examples show how scoped_refptr<T> acts like a pointer to T.
|
||||
// Given two scoped_refptr<T> classes, it is also possible to exchange
|
||||
// references between the two objects, like so:
|
||||
//
|
||||
// {
|
||||
// scoped_refptr<MyFoo> a = make_ref_counted<MyFoo>();
|
||||
// scoped_refptr<MyFoo> b;
|
||||
//
|
||||
// b.swap(a);
|
||||
// // now, `b` references the MyFoo object, and `a` references null.
|
||||
// }
|
||||
//
|
||||
// To make both `a` and `b` in the above example reference the same MyFoo
|
||||
// object, simply use the assignment operator:
|
||||
//
|
||||
// {
|
||||
// scoped_refptr<MyFoo> a = make_ref_counted<MyFoo>();
|
||||
// scoped_refptr<MyFoo> b;
|
||||
//
|
||||
// b = a;
|
||||
// // now, `a` and `b` each own a reference to the same MyFoo object.
|
||||
// }
|
||||
//
|
||||
|
||||
#ifndef API_SCOPED_REFPTR_H_
|
||||
#define API_SCOPED_REFPTR_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <class T>
|
||||
class scoped_refptr {
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
scoped_refptr() : ptr_(nullptr) {}
|
||||
scoped_refptr(std::nullptr_t) : ptr_(nullptr) {} // NOLINT(runtime/explicit)
|
||||
|
||||
explicit scoped_refptr(T* p) : ptr_(p) {}
|
||||
|
||||
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {}
|
||||
|
||||
// Move constructors.
|
||||
scoped_refptr(scoped_refptr<T>&& r) noexcept : ptr_(std::move(r.ptr_)) {}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(std::move(r.ptr_)) {}
|
||||
|
||||
~scoped_refptr() = default;
|
||||
|
||||
T* get() const { return ptr_.get(); }
|
||||
explicit operator bool() const { return ptr_ != nullptr; }
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_.get(); }
|
||||
|
||||
T* release() {
|
||||
T* retVal = ptr_.get();
|
||||
ptr_.reset();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
scoped_refptr<T>& operator=(T* p) {
|
||||
ptr_.reset(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
|
||||
ptr_ = r.ptr_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
|
||||
ptr_ = r.ptr_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
scoped_refptr<T>& operator=(scoped_refptr<T>&& r) noexcept {
|
||||
ptr_ = std::move(r.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr<T>& operator=(scoped_refptr<U>&& r) noexcept {
|
||||
ptr_ = std::move(r.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(T** pp) noexcept { std::swap(ptr_, *pp); }
|
||||
|
||||
void swap(scoped_refptr<T>& r) noexcept { std::swap(ptr_, r.ptr_); }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<T> ptr_;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
|
||||
return a.get() == b.get();
|
||||
}
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator==(const scoped_refptr<T>& a, std::nullptr_t) {
|
||||
return a.get() == nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(const scoped_refptr<T>& a, std::nullptr_t) {
|
||||
return !(a == nullptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator==(std::nullptr_t, const scoped_refptr<T>& a) {
|
||||
return a.get() == nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(std::nullptr_t, const scoped_refptr<T>& a) {
|
||||
return !(a == nullptr);
|
||||
}
|
||||
|
||||
// Comparison with raw pointer.
|
||||
template <typename T, typename U>
|
||||
bool operator==(const scoped_refptr<T>& a, const U* b) {
|
||||
return a.get() == b;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const scoped_refptr<T>& a, const U* b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const T* a, const scoped_refptr<U>& b) {
|
||||
return a == b.get();
|
||||
}
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const T* a, const scoped_refptr<U>& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// Ordered comparison, needed for use as a std::map key.
|
||||
template <typename T, typename U>
|
||||
bool operator<(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
|
||||
return a.get() < b.get();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
namespace rtc {
|
||||
// Backwards compatible alias.
|
||||
// TODO: bugs.webrtc.org/42225969 - Deprecate and remove.
|
||||
using ::webrtc::scoped_refptr;
|
||||
} // namespace rtc
|
||||
|
||||
#endif // API_SCOPED_REFPTR_H_
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-15
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _BANDWIDTH_USAGE_H_
|
||||
#define _BANDWIDTH_USAGE_H_
|
||||
|
||||
enum class BandwidthUsage {
|
||||
kBwNormal = 0,
|
||||
kBwUnderusing = 1,
|
||||
kBwOverusing = 2,
|
||||
kLast
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 API_TRANSPORT_ECN_MARKING_H_
|
||||
#define API_TRANSPORT_ECN_MARKING_H_
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// TODO: bugs.webrtc.org/42225697 - L4S support is slowly being developed.
|
||||
// Help is appreciated.
|
||||
|
||||
// L4S Explicit Congestion Notification (ECN) .
|
||||
// https://www.rfc-editor.org/rfc/rfc9331.html ECT stands for ECN-Capable
|
||||
// Transport and CE stands for Congestion Experienced.
|
||||
|
||||
// RFC-3168, Section 5
|
||||
// +-----+-----+
|
||||
// | ECN FIELD |
|
||||
// +-----+-----+
|
||||
// ECT CE [Obsolete] RFC 2481 names for the ECN bits.
|
||||
// 0 0 Not-ECT
|
||||
// 0 1 ECT(1)
|
||||
// 1 0 ECT(0)
|
||||
// 1 1 CE
|
||||
|
||||
enum class EcnMarking {
|
||||
kNotEct = 0, // Not ECN-Capable Transport
|
||||
kEct1 = 1, // ECN-Capable Transport
|
||||
kEct0 = 2, // Not used by L4s (or webrtc.)
|
||||
kCe = 3, // Congestion experienced
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_TRANSPORT_ECN_MARKING_H_
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 API_TRANSPORT_NETWORK_CONTROL_H_
|
||||
#define API_TRANSPORT_NETWORK_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/time_delta.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class TargetTransferRateObserver {
|
||||
public:
|
||||
virtual ~TargetTransferRateObserver() = default;
|
||||
// Called to indicate target transfer rate as well as giving information about
|
||||
// the current estimate of network parameters.
|
||||
virtual void OnTargetTransferRate(TargetTransferRate) = 0;
|
||||
// Called to provide updates to the expected target rate in case it changes
|
||||
// before the first call to OnTargetTransferRate.
|
||||
virtual void OnStartRateUpdate(DataRate) {}
|
||||
};
|
||||
|
||||
// Configuration sent to factory create function. The parameters here are
|
||||
// optional to use for a network controller implementation.
|
||||
struct NetworkControllerConfig {
|
||||
explicit NetworkControllerConfig() {}
|
||||
|
||||
// The initial constraints to start with, these can be changed at any later
|
||||
// time by calls to OnTargetRateConstraints. Note that the starting rate
|
||||
// has to be set initially to provide a starting state for the network
|
||||
// controller, even though the field is marked as optional.
|
||||
TargetRateConstraints constraints;
|
||||
// Initial stream specific configuration, these are changed at any later time
|
||||
// by calls to OnStreamsConfig.
|
||||
StreamsConfig stream_based_config;
|
||||
};
|
||||
|
||||
// NetworkControllerInterface is implemented by network controllers. A network
|
||||
// controller is a class that uses information about network state and traffic
|
||||
// to estimate network parameters such as round trip time and bandwidth. Network
|
||||
// controllers does not guarantee thread safety, the interface must be used in a
|
||||
// non-concurrent fashion.
|
||||
class NetworkControllerInterface {
|
||||
public:
|
||||
virtual ~NetworkControllerInterface() = default;
|
||||
|
||||
// Called when network availabilty changes.
|
||||
virtual NetworkControlUpdate OnNetworkAvailability(NetworkAvailability) = 0;
|
||||
// Called when the receiving or sending endpoint changes address.
|
||||
virtual NetworkControlUpdate OnNetworkRouteChange(NetworkRouteChange) = 0;
|
||||
// Called periodically with a periodicy as specified by
|
||||
// NetworkControllerFactoryInterface::GetProcessInterval.
|
||||
virtual NetworkControlUpdate OnProcessInterval(ProcessInterval) = 0;
|
||||
// Called when remotely calculated bitrate is received.
|
||||
virtual NetworkControlUpdate OnRemoteBitrateReport(RemoteBitrateReport) = 0;
|
||||
// Called round trip time has been calculated by protocol specific mechanisms.
|
||||
virtual NetworkControlUpdate OnRoundTripTimeUpdate(RoundTripTimeUpdate) = 0;
|
||||
// Called when a packet is sent on the network.
|
||||
virtual NetworkControlUpdate OnSentPacket(SentPacket) = 0;
|
||||
// Called when a packet is received from the remote client.
|
||||
virtual NetworkControlUpdate OnReceivedPacket(ReceivedPacket) = 0;
|
||||
// Called when the stream specific configuration has been updated.
|
||||
virtual NetworkControlUpdate OnStreamsConfig(StreamsConfig) = 0;
|
||||
// Called when target transfer rate constraints has been changed.
|
||||
virtual NetworkControlUpdate OnTargetRateConstraints(
|
||||
TargetRateConstraints) = 0;
|
||||
// Called when a protocol specific calculation of packet loss has been made.
|
||||
virtual NetworkControlUpdate OnTransportLossReport(TransportLossReport) = 0;
|
||||
// Called with per packet feedback regarding receive time.
|
||||
virtual NetworkControlUpdate OnTransportPacketsFeedback(
|
||||
TransportPacketsFeedback) = 0;
|
||||
// Called with network state estimate updates.
|
||||
virtual NetworkControlUpdate OnNetworkStateEstimate(NetworkStateEstimate) = 0;
|
||||
};
|
||||
|
||||
// NetworkControllerFactoryInterface is an interface for creating a network
|
||||
// controller.
|
||||
class NetworkControllerFactoryInterface {
|
||||
public:
|
||||
virtual ~NetworkControllerFactoryInterface() = default;
|
||||
|
||||
// Used to create a new network controller, requires an observer to be
|
||||
// provided to handle callbacks.
|
||||
virtual std::unique_ptr<NetworkControllerInterface> Create(
|
||||
NetworkControllerConfig config) = 0;
|
||||
// Returns the interval by which the network controller expects
|
||||
// OnProcessInterval calls.
|
||||
virtual TimeDelta GetProcessInterval() const = 0;
|
||||
};
|
||||
|
||||
// Under development, subject to change without notice.
|
||||
class NetworkStateEstimator {
|
||||
public:
|
||||
// Gets the current best estimate according to the estimator.
|
||||
virtual std::optional<NetworkStateEstimate> GetCurrentEstimate() = 0;
|
||||
// Called with per packet feedback regarding receive time.
|
||||
// Used when the NetworkStateEstimator runs in the sending endpoint.
|
||||
virtual void OnTransportPacketsFeedback(const TransportPacketsFeedback&) = 0;
|
||||
// Called with per packet feedback regarding receive time.
|
||||
// Used when the NetworkStateEstimator runs in the receiving endpoint.
|
||||
virtual void OnReceivedPacket(const PacketResult&) {}
|
||||
// Called when the receiving or sending endpoint changes address.
|
||||
virtual void OnRouteChange(const NetworkRouteChange&) = 0;
|
||||
virtual ~NetworkStateEstimator() = default;
|
||||
};
|
||||
class NetworkStateEstimatorFactory {
|
||||
public:
|
||||
virtual std::unique_ptr<NetworkStateEstimator> Create() = 0;
|
||||
virtual ~NetworkStateEstimatorFactory() = default;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_TRANSPORT_NETWORK_CONTROL_H_
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "api/transport/network_types.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace webrtc {
|
||||
StreamsConfig::StreamsConfig() = default;
|
||||
StreamsConfig::StreamsConfig(const StreamsConfig&) = default;
|
||||
StreamsConfig::~StreamsConfig() = default;
|
||||
|
||||
TargetRateConstraints::TargetRateConstraints() = default;
|
||||
TargetRateConstraints::TargetRateConstraints(const TargetRateConstraints&) =
|
||||
default;
|
||||
TargetRateConstraints::~TargetRateConstraints() = default;
|
||||
|
||||
NetworkRouteChange::NetworkRouteChange() = default;
|
||||
NetworkRouteChange::NetworkRouteChange(const NetworkRouteChange&) = default;
|
||||
NetworkRouteChange::~NetworkRouteChange() = default;
|
||||
|
||||
PacketResult::PacketResult() = default;
|
||||
PacketResult::PacketResult(const PacketResult& other) = default;
|
||||
PacketResult::~PacketResult() = default;
|
||||
|
||||
bool PacketResult::ReceiveTimeOrder::operator()(const PacketResult& lhs,
|
||||
const PacketResult& rhs) {
|
||||
if (lhs.receive_time != rhs.receive_time)
|
||||
return lhs.receive_time < rhs.receive_time;
|
||||
if (lhs.sent_packet.send_time != rhs.sent_packet.send_time)
|
||||
return lhs.sent_packet.send_time < rhs.sent_packet.send_time;
|
||||
return lhs.sent_packet.sequence_number < rhs.sent_packet.sequence_number;
|
||||
}
|
||||
|
||||
TransportPacketsFeedback::TransportPacketsFeedback() = default;
|
||||
TransportPacketsFeedback::TransportPacketsFeedback(
|
||||
const TransportPacketsFeedback& other) = default;
|
||||
TransportPacketsFeedback::~TransportPacketsFeedback() = default;
|
||||
|
||||
std::vector<PacketResult> TransportPacketsFeedback::ReceivedWithSendInfo()
|
||||
const {
|
||||
std::vector<PacketResult> res;
|
||||
for (const PacketResult& fb : packet_feedbacks) {
|
||||
if (fb.IsReceived()) {
|
||||
res.push_back(fb);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<PacketResult> TransportPacketsFeedback::LostWithSendInfo() const {
|
||||
std::vector<PacketResult> res;
|
||||
for (const PacketResult& fb : packet_feedbacks) {
|
||||
if (!fb.IsReceived()) {
|
||||
res.push_back(fb);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<PacketResult> TransportPacketsFeedback::PacketsWithFeedback()
|
||||
const {
|
||||
return packet_feedbacks;
|
||||
}
|
||||
|
||||
std::vector<PacketResult> TransportPacketsFeedback::SortedByReceiveTime()
|
||||
const {
|
||||
std::vector<PacketResult> res;
|
||||
for (const PacketResult& fb : packet_feedbacks) {
|
||||
if (fb.IsReceived()) {
|
||||
res.push_back(fb);
|
||||
}
|
||||
}
|
||||
std::sort(res.begin(), res.end(), PacketResult::ReceiveTimeOrder());
|
||||
return res;
|
||||
}
|
||||
|
||||
NetworkControlUpdate::NetworkControlUpdate() = default;
|
||||
NetworkControlUpdate::NetworkControlUpdate(const NetworkControlUpdate&) =
|
||||
default;
|
||||
NetworkControlUpdate::~NetworkControlUpdate() = default;
|
||||
|
||||
PacedPacketInfo::PacedPacketInfo() = default;
|
||||
|
||||
PacedPacketInfo::PacedPacketInfo(int probe_cluster_id,
|
||||
int probe_cluster_min_probes,
|
||||
int probe_cluster_min_bytes)
|
||||
: probe_cluster_id(probe_cluster_id),
|
||||
probe_cluster_min_probes(probe_cluster_min_probes),
|
||||
probe_cluster_min_bytes(probe_cluster_min_bytes) {}
|
||||
|
||||
bool PacedPacketInfo::operator==(const PacedPacketInfo& rhs) const {
|
||||
return send_bitrate == rhs.send_bitrate &&
|
||||
probe_cluster_id == rhs.probe_cluster_id &&
|
||||
probe_cluster_min_probes == rhs.probe_cluster_min_probes &&
|
||||
probe_cluster_min_bytes == rhs.probe_cluster_min_bytes;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@@ -1,292 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 API_TRANSPORT_NETWORK_TYPES_H_
|
||||
#define API_TRANSPORT_NETWORK_TYPES_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "api/transport/ecn_marking.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Configuration
|
||||
|
||||
// Represents constraints and rates related to the currently enabled streams.
|
||||
// This is used as input to the congestion controller via the StreamsConfig
|
||||
// struct.
|
||||
struct BitrateAllocationLimits {
|
||||
// The total minimum send bitrate required by all sending streams.
|
||||
DataRate min_allocatable_rate = DataRate::Zero();
|
||||
// The total maximum allocatable bitrate for all currently available streams.
|
||||
DataRate max_allocatable_rate = DataRate::Zero();
|
||||
// The max bitrate to use for padding. The sum of the per-stream max padding
|
||||
// rate.
|
||||
DataRate max_padding_rate = DataRate::Zero();
|
||||
};
|
||||
|
||||
// Use StreamsConfig for information about streams that is required for specific
|
||||
// adjustments to the algorithms in network controllers. Especially useful
|
||||
// for experiments.
|
||||
struct StreamsConfig {
|
||||
StreamsConfig();
|
||||
StreamsConfig(const StreamsConfig&);
|
||||
~StreamsConfig();
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
std::optional<bool> requests_alr_probing;
|
||||
// If `enable_repeated_initial_probing` is set to true, Probes are sent
|
||||
// periodically every 1s during the first 5s after the network becomes
|
||||
// available. The probes ignores max_total_allocated_bitrate.
|
||||
std::optional<bool> enable_repeated_initial_probing;
|
||||
std::optional<double> pacing_factor;
|
||||
|
||||
// TODO(srte): Use BitrateAllocationLimits here.
|
||||
std::optional<DataRate> min_total_allocated_bitrate;
|
||||
std::optional<DataRate> max_padding_rate;
|
||||
std::optional<DataRate> max_total_allocated_bitrate;
|
||||
};
|
||||
|
||||
struct TargetRateConstraints {
|
||||
TargetRateConstraints();
|
||||
TargetRateConstraints(const TargetRateConstraints&);
|
||||
~TargetRateConstraints();
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
std::optional<DataRate> min_data_rate;
|
||||
std::optional<DataRate> max_data_rate;
|
||||
// The initial bandwidth estimate to base target rate on. This should be used
|
||||
// as the basis for initial OnTargetTransferRate and OnPacerConfig callbacks.
|
||||
std::optional<DataRate> starting_rate;
|
||||
};
|
||||
|
||||
// Send side information
|
||||
|
||||
struct NetworkAvailability {
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
bool network_available = false;
|
||||
};
|
||||
|
||||
struct NetworkRouteChange {
|
||||
NetworkRouteChange();
|
||||
NetworkRouteChange(const NetworkRouteChange&);
|
||||
~NetworkRouteChange();
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
// The TargetRateConstraints are set here so they can be changed synchronously
|
||||
// when network route changes.
|
||||
TargetRateConstraints constraints;
|
||||
};
|
||||
|
||||
struct PacedPacketInfo {
|
||||
PacedPacketInfo();
|
||||
PacedPacketInfo(int probe_cluster_id, int probe_cluster_min_probes,
|
||||
int probe_cluster_min_bytes);
|
||||
|
||||
bool operator==(const PacedPacketInfo& rhs) const;
|
||||
|
||||
// TODO(srte): Move probing info to a separate, optional struct.
|
||||
static constexpr int kNotAProbe = -1;
|
||||
DataRate send_bitrate = DataRate::BitsPerSec(0);
|
||||
int probe_cluster_id = kNotAProbe;
|
||||
int probe_cluster_min_probes = -1;
|
||||
int probe_cluster_min_bytes = -1;
|
||||
int probe_cluster_bytes_sent = 0;
|
||||
};
|
||||
|
||||
struct SentPacket {
|
||||
Timestamp send_time = Timestamp::PlusInfinity();
|
||||
// Size of packet with overhead up to IP layer.
|
||||
DataSize size = DataSize::Zero();
|
||||
// Size of preceeding packets that are not part of feedback.
|
||||
DataSize prior_unacked_data = DataSize::Zero();
|
||||
// Probe cluster id and parameters including bitrate, number of packets and
|
||||
// number of bytes.
|
||||
PacedPacketInfo pacing_info;
|
||||
// True if the packet is an audio packet, false for video, padding, RTX etc.
|
||||
bool audio = false;
|
||||
// Transport independent sequence number, any tracked packet should have a
|
||||
// sequence number that is unique over the whole call and increasing by 1 for
|
||||
// each packet.
|
||||
int64_t sequence_number;
|
||||
// Tracked data in flight when the packet was sent, excluding unacked data.
|
||||
DataSize data_in_flight = DataSize::Zero();
|
||||
};
|
||||
|
||||
struct ReceivedPacket {
|
||||
Timestamp send_time = Timestamp::MinusInfinity();
|
||||
Timestamp receive_time = Timestamp::PlusInfinity();
|
||||
DataSize size = DataSize::Zero();
|
||||
};
|
||||
|
||||
// Transport level feedback
|
||||
|
||||
struct RemoteBitrateReport {
|
||||
Timestamp receive_time = Timestamp::PlusInfinity();
|
||||
DataRate bandwidth = DataRate::Infinity();
|
||||
};
|
||||
|
||||
struct RoundTripTimeUpdate {
|
||||
Timestamp receive_time = Timestamp::PlusInfinity();
|
||||
TimeDelta round_trip_time = TimeDelta::PlusInfinity();
|
||||
bool smoothed = false;
|
||||
};
|
||||
|
||||
struct TransportLossReport {
|
||||
Timestamp receive_time = Timestamp::PlusInfinity();
|
||||
Timestamp start_time = Timestamp::PlusInfinity();
|
||||
Timestamp end_time = Timestamp::PlusInfinity();
|
||||
uint64_t packets_lost_delta = 0;
|
||||
uint64_t packets_received_delta = 0;
|
||||
};
|
||||
|
||||
// Packet level feedback
|
||||
|
||||
struct PacketResult {
|
||||
class ReceiveTimeOrder {
|
||||
public:
|
||||
bool operator()(const PacketResult& lhs, const PacketResult& rhs);
|
||||
};
|
||||
|
||||
PacketResult();
|
||||
PacketResult(const PacketResult&);
|
||||
~PacketResult();
|
||||
|
||||
inline bool IsReceived() const { return !receive_time.IsPlusInfinity(); }
|
||||
|
||||
SentPacket sent_packet;
|
||||
Timestamp receive_time = Timestamp::PlusInfinity();
|
||||
EcnMarking ecn = EcnMarking::kNotEct;
|
||||
};
|
||||
|
||||
struct TransportPacketsFeedback {
|
||||
TransportPacketsFeedback();
|
||||
TransportPacketsFeedback(const TransportPacketsFeedback& other);
|
||||
~TransportPacketsFeedback();
|
||||
|
||||
Timestamp feedback_time = Timestamp::PlusInfinity();
|
||||
DataSize data_in_flight = DataSize::Zero();
|
||||
bool transport_supports_ecn = false;
|
||||
std::vector<PacketResult> packet_feedbacks;
|
||||
|
||||
// Arrival times for messages without send time information.
|
||||
std::vector<Timestamp> sendless_arrival_times;
|
||||
|
||||
std::vector<PacketResult> ReceivedWithSendInfo() const;
|
||||
std::vector<PacketResult> LostWithSendInfo() const;
|
||||
std::vector<PacketResult> PacketsWithFeedback() const;
|
||||
std::vector<PacketResult> SortedByReceiveTime() const;
|
||||
};
|
||||
|
||||
// Network estimation
|
||||
|
||||
struct NetworkEstimate {
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
// Deprecated, use TargetTransferRate::target_rate instead.
|
||||
DataRate bandwidth = DataRate::Infinity();
|
||||
TimeDelta round_trip_time = TimeDelta::PlusInfinity();
|
||||
TimeDelta bwe_period = TimeDelta::PlusInfinity();
|
||||
|
||||
float loss_rate_ratio = 0;
|
||||
};
|
||||
|
||||
// Network control
|
||||
|
||||
struct PacerConfig {
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
// Pacer should send at most data_window data over time_window duration.
|
||||
DataSize data_window = DataSize::Infinity();
|
||||
TimeDelta time_window = TimeDelta::PlusInfinity();
|
||||
// Pacer should send at least pad_window data over time_window duration.
|
||||
DataSize pad_window = DataSize::Zero();
|
||||
DataRate data_rate() const { return data_window / time_window; }
|
||||
DataRate pad_rate() const { return pad_window / time_window; }
|
||||
};
|
||||
|
||||
struct ProbeClusterConfig {
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
DataRate target_data_rate = DataRate::Zero();
|
||||
// Duration of a probe.
|
||||
TimeDelta target_duration = TimeDelta::Zero();
|
||||
// Delta time between sent bursts of packets during probe.
|
||||
TimeDelta min_probe_delta = TimeDelta::Millis(2);
|
||||
int32_t target_probe_count = 0;
|
||||
int32_t id = 0;
|
||||
};
|
||||
|
||||
struct TargetTransferRate {
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
// The estimate on which the target rate is based on.
|
||||
NetworkEstimate network_estimate;
|
||||
DataRate target_rate = DataRate::Zero();
|
||||
DataRate stable_target_rate = DataRate::Zero();
|
||||
double cwnd_reduce_ratio = 0;
|
||||
};
|
||||
|
||||
// Contains updates of network controller comand state. Using optionals to
|
||||
// indicate whether a member has been updated. The array of probe clusters
|
||||
// should be used to send out probes if not empty.
|
||||
struct NetworkControlUpdate {
|
||||
NetworkControlUpdate();
|
||||
NetworkControlUpdate(const NetworkControlUpdate&);
|
||||
~NetworkControlUpdate();
|
||||
|
||||
bool has_updates() const {
|
||||
return congestion_window.has_value() || pacer_config.has_value() ||
|
||||
!probe_cluster_configs.empty() || target_rate.has_value();
|
||||
}
|
||||
|
||||
std::optional<DataSize> congestion_window;
|
||||
std::optional<PacerConfig> pacer_config;
|
||||
std::vector<ProbeClusterConfig> probe_cluster_configs;
|
||||
std::optional<TargetTransferRate> target_rate;
|
||||
};
|
||||
|
||||
// Process control
|
||||
struct ProcessInterval {
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
std::optional<DataSize> pacer_queue;
|
||||
};
|
||||
|
||||
// Under development, subject to change without notice.
|
||||
struct NetworkStateEstimate {
|
||||
double confidence = NAN;
|
||||
// The time the estimate was received/calculated.
|
||||
Timestamp update_time = Timestamp::MinusInfinity();
|
||||
Timestamp last_receive_time = Timestamp::MinusInfinity();
|
||||
Timestamp last_send_time = Timestamp::MinusInfinity();
|
||||
|
||||
// Total estimated link capacity.
|
||||
DataRate link_capacity = DataRate::MinusInfinity();
|
||||
// Used as a safe measure of available capacity.
|
||||
DataRate link_capacity_lower = DataRate::MinusInfinity();
|
||||
// Used as limit for increasing bitrate.
|
||||
DataRate link_capacity_upper = DataRate::MinusInfinity();
|
||||
|
||||
TimeDelta pre_link_buffer_delay = TimeDelta::MinusInfinity();
|
||||
TimeDelta post_link_buffer_delay = TimeDelta::MinusInfinity();
|
||||
TimeDelta propagation_delay = TimeDelta::MinusInfinity();
|
||||
|
||||
// Only for debugging
|
||||
TimeDelta time_delta = TimeDelta::MinusInfinity();
|
||||
Timestamp last_feed_time = Timestamp::MinusInfinity();
|
||||
double cross_delay_rate = NAN;
|
||||
double spike_delay_rate = NAN;
|
||||
DataRate link_capacity_std_dev = DataRate::MinusInfinity();
|
||||
DataRate link_capacity_min = DataRate::MinusInfinity();
|
||||
double cross_traffic_ratio = NAN;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_TRANSPORT_NETWORK_TYPES_H_
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "api/units/data_rate.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
std::string ToString(DataRate value) {
|
||||
if (value.IsPlusInfinity()) {
|
||||
return "+inf bps";
|
||||
} else if (value.IsMinusInfinity()) {
|
||||
return "-inf bps";
|
||||
} else {
|
||||
if (value.bps() == 0 || value.bps() % 1000 != 0) {
|
||||
return std::to_string(value.bps()) + " bps";
|
||||
} else {
|
||||
return std::to_string(value.kbps()) + " kbps";
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace webrtc
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 API_UNITS_DATA_RATE_H_
|
||||
#define API_UNITS_DATA_RATE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/frequency.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
namespace webrtc {
|
||||
// DataRate is a class that represents a given data rate. This can be used to
|
||||
// represent bandwidth, encoding bitrate, etc. The internal storage is bits per
|
||||
// second (bps).
|
||||
class DataRate final : public rtc_units_impl::RelativeUnit<DataRate> {
|
||||
public:
|
||||
template <typename T>
|
||||
static constexpr DataRate BitsPerSec(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromValue(value);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr DataRate BytesPerSec(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromFraction(8, value);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr DataRate KilobitsPerSec(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromFraction(1000, value);
|
||||
}
|
||||
static constexpr DataRate Infinity() { return PlusInfinity(); }
|
||||
|
||||
constexpr DataRate() = default;
|
||||
|
||||
template <typename Sink>
|
||||
friend void AbslStringify(Sink& sink, DataRate value);
|
||||
|
||||
template <typename T = int64_t>
|
||||
constexpr T bps() const {
|
||||
return ToValue<T>();
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
constexpr T bytes_per_sec() const {
|
||||
return ToFraction<8, T>();
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
constexpr T kbps() const {
|
||||
return ToFraction<1000, T>();
|
||||
}
|
||||
constexpr int64_t bps_or(int64_t fallback_value) const {
|
||||
return ToValueOr(fallback_value);
|
||||
}
|
||||
constexpr int64_t kbps_or(int64_t fallback_value) const {
|
||||
return ToFractionOr<1000>(fallback_value);
|
||||
}
|
||||
|
||||
private:
|
||||
// Bits per second used internally to simplify debugging by making the value
|
||||
// more recognizable.
|
||||
friend class rtc_units_impl::UnitBase<DataRate>;
|
||||
using RelativeUnit::RelativeUnit;
|
||||
static constexpr bool one_sided = true;
|
||||
};
|
||||
|
||||
namespace data_rate_impl {
|
||||
inline constexpr int64_t Microbits(const DataSize& size) {
|
||||
constexpr int64_t kMaxBeforeConversion =
|
||||
std::numeric_limits<int64_t>::max() / 8000000;
|
||||
return size.bytes() * 8000000;
|
||||
}
|
||||
|
||||
inline constexpr int64_t MillibytePerSec(const DataRate& size) {
|
||||
constexpr int64_t kMaxBeforeConversion =
|
||||
std::numeric_limits<int64_t>::max() / (1000 / 8);
|
||||
return size.bps() * (1000 / 8);
|
||||
}
|
||||
} // namespace data_rate_impl
|
||||
|
||||
inline constexpr DataRate operator/(const DataSize size,
|
||||
const TimeDelta duration) {
|
||||
return DataRate::BitsPerSec(data_rate_impl::Microbits(size) / duration.us());
|
||||
}
|
||||
inline constexpr TimeDelta operator/(const DataSize size, const DataRate rate) {
|
||||
return TimeDelta::Micros(data_rate_impl::Microbits(size) / rate.bps());
|
||||
}
|
||||
inline constexpr DataSize operator*(const DataRate rate,
|
||||
const TimeDelta duration) {
|
||||
int64_t microbits = rate.bps() * duration.us();
|
||||
return DataSize::Bytes((microbits + 4000000) / 8000000);
|
||||
}
|
||||
inline constexpr DataSize operator*(const TimeDelta duration,
|
||||
const DataRate rate) {
|
||||
return rate * duration;
|
||||
}
|
||||
|
||||
inline constexpr DataSize operator/(const DataRate rate,
|
||||
const Frequency frequency) {
|
||||
int64_t millihertz = frequency.millihertz<int64_t>();
|
||||
// Note that the value is truncated here reather than rounded, potentially
|
||||
// introducing an error of .5 bytes if rounding were expected.
|
||||
return DataSize::Bytes(data_rate_impl::MillibytePerSec(rate) / millihertz);
|
||||
}
|
||||
inline constexpr Frequency operator/(const DataRate rate, const DataSize size) {
|
||||
return Frequency::MilliHertz(data_rate_impl::MillibytePerSec(rate) /
|
||||
size.bytes());
|
||||
}
|
||||
inline constexpr DataRate operator*(const DataSize size,
|
||||
const Frequency frequency) {
|
||||
int64_t millibits_per_second =
|
||||
size.bytes() * 8 * frequency.millihertz<int64_t>();
|
||||
return DataRate::BitsPerSec((millibits_per_second + 500) / 1000);
|
||||
}
|
||||
inline constexpr DataRate operator*(const Frequency frequency,
|
||||
const DataSize size) {
|
||||
return size * frequency;
|
||||
}
|
||||
|
||||
std::string ToString(DataRate value);
|
||||
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, DataRate value) {
|
||||
sink.Append(ToString(value));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_UNITS_DATA_RATE_H_
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "api/units/data_size.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
std::string ToString(DataSize value) {
|
||||
if (value.IsPlusInfinity()) {
|
||||
return "+inf bytes";
|
||||
} else if (value.IsMinusInfinity()) {
|
||||
return "-inf bytes";
|
||||
} else {
|
||||
return std::to_string(value.bytes()) + " bytes";
|
||||
}
|
||||
}
|
||||
} // namespace webrtc
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 API_UNITS_DATA_SIZE_H_
|
||||
#define API_UNITS_DATA_SIZE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "unit_base.h" // IWYU pragma: export
|
||||
|
||||
namespace webrtc {
|
||||
// DataSize is a class represeting a count of bytes.
|
||||
class DataSize final : public rtc_units_impl::RelativeUnit<DataSize> {
|
||||
public:
|
||||
template <typename T>
|
||||
static constexpr DataSize Bytes(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromValue(value);
|
||||
}
|
||||
static constexpr DataSize Infinity() { return PlusInfinity(); }
|
||||
|
||||
constexpr DataSize() = default;
|
||||
|
||||
template <typename Sink>
|
||||
friend void AbslStringify(Sink& sink, DataSize value);
|
||||
|
||||
template <typename T = int64_t>
|
||||
constexpr T bytes() const {
|
||||
return ToValue<T>();
|
||||
}
|
||||
|
||||
constexpr int64_t bytes_or(int64_t fallback_value) const {
|
||||
return ToValueOr(fallback_value);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class rtc_units_impl::UnitBase<DataSize>;
|
||||
using RelativeUnit::RelativeUnit;
|
||||
static constexpr bool one_sided = true;
|
||||
};
|
||||
|
||||
std::string ToString(DataSize value);
|
||||
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, DataSize value) {
|
||||
sink.Append(ToString(value));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_UNITS_DATA_SIZE_H_
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include "frequency.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace webrtc {
|
||||
std::string ToString(Frequency value) {
|
||||
if (value.IsPlusInfinity()) {
|
||||
return "+inf Hz";
|
||||
} else if (value.IsMinusInfinity()) {
|
||||
return "-inf Hz";
|
||||
} else if (value.millihertz<int64_t>() % 1000 != 0) {
|
||||
return std::to_string(value.hertz<double>()) + " Hz";
|
||||
} else {
|
||||
return std::to_string(value.hertz<int64_t>()) + " Hz";
|
||||
}
|
||||
}
|
||||
} // namespace webrtc
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef API_UNITS_FREQUENCY_H_
|
||||
#define API_UNITS_FREQUENCY_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
#include "unit_base.h" // IWYU pragma: export
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class Frequency final : public rtc_units_impl::RelativeUnit<Frequency> {
|
||||
public:
|
||||
template <typename T>
|
||||
static constexpr Frequency MilliHertz(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromValue(value);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr Frequency Hertz(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromFraction(1'000, value);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr Frequency KiloHertz(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromFraction(1'000'000, value);
|
||||
}
|
||||
|
||||
constexpr Frequency() = default;
|
||||
|
||||
template <typename Sink>
|
||||
friend void AbslStringify(Sink& sink, Frequency value);
|
||||
|
||||
template <typename T = int64_t>
|
||||
constexpr T hertz() const {
|
||||
return ToFraction<1000, T>();
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
constexpr T millihertz() const {
|
||||
return ToValue<T>();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class rtc_units_impl::UnitBase<Frequency>;
|
||||
using RelativeUnit::RelativeUnit;
|
||||
static constexpr bool one_sided = true;
|
||||
};
|
||||
|
||||
inline constexpr Frequency operator/(int64_t nominator,
|
||||
const TimeDelta& interval) {
|
||||
constexpr int64_t kKiloPerMicro = 1000 * 1000000;
|
||||
return Frequency::MilliHertz(nominator * kKiloPerMicro / interval.us());
|
||||
}
|
||||
|
||||
inline constexpr TimeDelta operator/(int64_t nominator,
|
||||
const Frequency& frequency) {
|
||||
constexpr int64_t kMegaPerMilli = 1000000 * 1000;
|
||||
return TimeDelta::Micros(nominator * kMegaPerMilli / frequency.millihertz());
|
||||
}
|
||||
|
||||
inline constexpr double operator*(Frequency frequency, TimeDelta time_delta) {
|
||||
return frequency.hertz<double>() * time_delta.seconds<double>();
|
||||
}
|
||||
inline constexpr double operator*(TimeDelta time_delta, Frequency frequency) {
|
||||
return frequency * time_delta;
|
||||
}
|
||||
|
||||
std::string ToString(Frequency value);
|
||||
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, Frequency value) {
|
||||
sink.Append(ToString(value));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // API_UNITS_FREQUENCY_H_
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "api/units/time_delta.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
std::string ToString(TimeDelta value) {
|
||||
if (value.IsPlusInfinity()) {
|
||||
return "+inf ms";
|
||||
} else if (value.IsMinusInfinity()) {
|
||||
return "-inf ms";
|
||||
} else {
|
||||
if (value.us() == 0 || (value.us() % 1000) != 0)
|
||||
return std::to_string(value.us()) + " us";
|
||||
else if (value.ms() % 1000 != 0)
|
||||
return std::to_string(value.ms()) + " ms";
|
||||
else
|
||||
return std::to_string(value.seconds()) + " s";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 API_UNITS_TIME_DELTA_H_
|
||||
#define API_UNITS_TIME_DELTA_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "unit_base.h" // IWYU pragma: export
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// TimeDelta represents the difference between two timestamps. Commonly this can
|
||||
// be a duration. However since two Timestamps are not guaranteed to have the
|
||||
// same epoch (they might come from different computers, making exact
|
||||
// synchronisation infeasible), the duration covered by a TimeDelta can be
|
||||
// undefined. To simplify usage, it can be constructed and converted to
|
||||
// different units, specifically seconds (s), milliseconds (ms) and
|
||||
// microseconds (us).
|
||||
class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
|
||||
public:
|
||||
template <typename T>
|
||||
static constexpr TimeDelta Minutes(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return Seconds(value * 60);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr TimeDelta Seconds(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromFraction(1'000'000, value);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr TimeDelta Millis(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromFraction(1'000, value);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr TimeDelta Micros(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromValue(value);
|
||||
}
|
||||
|
||||
constexpr TimeDelta() = default;
|
||||
|
||||
template <typename Sink>
|
||||
friend void AbslStringify(Sink& sink, TimeDelta value);
|
||||
|
||||
template <typename T = int64_t>
|
||||
constexpr T seconds() const {
|
||||
return ToFraction<1000000, T>();
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
constexpr T ms() const {
|
||||
return ToFraction<1000, T>();
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
constexpr T us() const {
|
||||
return ToValue<T>();
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
constexpr T ns() const {
|
||||
return ToMultiple<1000, T>();
|
||||
}
|
||||
|
||||
constexpr int64_t seconds_or(int64_t fallback_value) const {
|
||||
return ToFractionOr<1000000>(fallback_value);
|
||||
}
|
||||
constexpr int64_t ms_or(int64_t fallback_value) const {
|
||||
return ToFractionOr<1000>(fallback_value);
|
||||
}
|
||||
constexpr int64_t us_or(int64_t fallback_value) const {
|
||||
return ToValueOr(fallback_value);
|
||||
}
|
||||
|
||||
constexpr TimeDelta Abs() const {
|
||||
return us() < 0 ? TimeDelta::Micros(-us()) : *this;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class rtc_units_impl::UnitBase<TimeDelta>;
|
||||
using RelativeUnit::RelativeUnit;
|
||||
static constexpr bool one_sided = false;
|
||||
};
|
||||
|
||||
std::string ToString(TimeDelta value);
|
||||
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, TimeDelta value) {
|
||||
sink.Append(ToString(value));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_UNITS_TIME_DELTA_H_
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "api/units/timestamp.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace webrtc {
|
||||
std::string ToString(Timestamp value) {
|
||||
if (value.IsPlusInfinity()) {
|
||||
return "+inf ms";
|
||||
} else if (value.IsMinusInfinity()) {
|
||||
return "-inf ms";
|
||||
} else {
|
||||
if (value.us() == 0 || (value.us() % 1000) != 0)
|
||||
return std::to_string(value.us()) + " us";
|
||||
else if (value.ms() % 1000 != 0)
|
||||
return std::to_string(value.ms()) + " ms";
|
||||
else
|
||||
return std::to_string(value.seconds()) + " s";
|
||||
}
|
||||
}
|
||||
} // namespace webrtc
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 API_UNITS_TIMESTAMP_H_
|
||||
#define API_UNITS_TIMESTAMP_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "time_delta.h"
|
||||
#include "unit_base.h" // IWYU pragma: export
|
||||
|
||||
namespace webrtc {
|
||||
// Timestamp represents the time that has passed since some unspecified epoch.
|
||||
// The epoch is assumed to be before any represented timestamps, this means that
|
||||
// negative values are not valid. The most notable feature is that the
|
||||
// difference of two Timestamps results in a TimeDelta.
|
||||
class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
|
||||
public:
|
||||
template <typename T>
|
||||
static constexpr Timestamp Seconds(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromFraction(1'000'000, value);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr Timestamp Millis(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromFraction(1'000, value);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr Timestamp Micros(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return FromValue(value);
|
||||
}
|
||||
|
||||
Timestamp() = delete;
|
||||
|
||||
template <typename Sink>
|
||||
friend void AbslStringify(Sink& sink, Timestamp value);
|
||||
|
||||
template <typename T = int64_t>
|
||||
constexpr T seconds() const {
|
||||
return ToFraction<1000000, T>();
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
constexpr T ms() const {
|
||||
return ToFraction<1000, T>();
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
constexpr T us() const {
|
||||
return ToValue<T>();
|
||||
}
|
||||
|
||||
constexpr int64_t seconds_or(int64_t fallback_value) const {
|
||||
return ToFractionOr<1000000>(fallback_value);
|
||||
}
|
||||
constexpr int64_t ms_or(int64_t fallback_value) const {
|
||||
return ToFractionOr<1000>(fallback_value);
|
||||
}
|
||||
constexpr int64_t us_or(int64_t fallback_value) const {
|
||||
return ToValueOr(fallback_value);
|
||||
}
|
||||
|
||||
constexpr Timestamp operator+(const TimeDelta delta) const {
|
||||
if (IsPlusInfinity() || delta.IsPlusInfinity()) {
|
||||
return PlusInfinity();
|
||||
} else if (IsMinusInfinity() || delta.IsMinusInfinity()) {
|
||||
return MinusInfinity();
|
||||
}
|
||||
return Timestamp::Micros(us() + delta.us());
|
||||
}
|
||||
constexpr Timestamp operator-(const TimeDelta delta) const {
|
||||
if (IsPlusInfinity() || delta.IsMinusInfinity()) {
|
||||
return PlusInfinity();
|
||||
} else if (IsMinusInfinity() || delta.IsPlusInfinity()) {
|
||||
return MinusInfinity();
|
||||
}
|
||||
return Timestamp::Micros(us() - delta.us());
|
||||
}
|
||||
constexpr TimeDelta operator-(const Timestamp other) const {
|
||||
if (IsPlusInfinity() || other.IsMinusInfinity()) {
|
||||
return TimeDelta::PlusInfinity();
|
||||
} else if (IsMinusInfinity() || other.IsPlusInfinity()) {
|
||||
return TimeDelta::MinusInfinity();
|
||||
}
|
||||
return TimeDelta::Micros(us() - other.us());
|
||||
}
|
||||
constexpr Timestamp& operator-=(const TimeDelta delta) {
|
||||
*this = *this - delta;
|
||||
return *this;
|
||||
}
|
||||
constexpr Timestamp& operator+=(const TimeDelta delta) {
|
||||
*this = *this + delta;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class rtc_units_impl::UnitBase<Timestamp>;
|
||||
using UnitBase::UnitBase;
|
||||
static constexpr bool one_sided = true;
|
||||
};
|
||||
|
||||
std::string ToString(Timestamp value);
|
||||
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, Timestamp value) {
|
||||
sink.Append(ToString(value));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_UNITS_TIMESTAMP_H_
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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 RTC_BASE_UNITS_UNIT_BASE_H_
|
||||
#define RTC_BASE_UNITS_UNIT_BASE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rtc_base/numerics/divide_round.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace rtc_units_impl {
|
||||
|
||||
// UnitBase is a base class for implementing custom value types with a specific
|
||||
// unit. It provides type safety and commonly useful operations. The underlying
|
||||
// storage is always an int64_t, it's up to the unit implementation to choose
|
||||
// what scale it represents.
|
||||
//
|
||||
// It's used like:
|
||||
// class MyUnit: public UnitBase<MyUnit> {...};
|
||||
//
|
||||
// Unit_T is the subclass representing the specific unit.
|
||||
template <class Unit_T>
|
||||
class UnitBase {
|
||||
public:
|
||||
UnitBase() = delete;
|
||||
static constexpr Unit_T Zero() { return Unit_T(0); }
|
||||
static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); }
|
||||
static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); }
|
||||
|
||||
constexpr bool IsZero() const { return value_ == 0; }
|
||||
constexpr bool IsFinite() const { return !IsInfinite(); }
|
||||
constexpr bool IsInfinite() const {
|
||||
return value_ == PlusInfinityVal() || value_ == MinusInfinityVal();
|
||||
}
|
||||
constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); }
|
||||
constexpr bool IsMinusInfinity() const {
|
||||
return value_ == MinusInfinityVal();
|
||||
}
|
||||
|
||||
constexpr bool operator==(const UnitBase<Unit_T>& other) const {
|
||||
return value_ == other.value_;
|
||||
}
|
||||
constexpr bool operator!=(const UnitBase<Unit_T>& other) const {
|
||||
return value_ != other.value_;
|
||||
}
|
||||
constexpr bool operator<=(const UnitBase<Unit_T>& other) const {
|
||||
return value_ <= other.value_;
|
||||
}
|
||||
constexpr bool operator>=(const UnitBase<Unit_T>& other) const {
|
||||
return value_ >= other.value_;
|
||||
}
|
||||
constexpr bool operator>(const UnitBase<Unit_T>& other) const {
|
||||
return value_ > other.value_;
|
||||
}
|
||||
constexpr bool operator<(const UnitBase<Unit_T>& other) const {
|
||||
return value_ < other.value_;
|
||||
}
|
||||
constexpr Unit_T RoundTo(const Unit_T& resolution) const {
|
||||
return Unit_T((value_ + resolution.value_ / 2) / resolution.value_) *
|
||||
resolution.value_;
|
||||
}
|
||||
constexpr Unit_T RoundUpTo(const Unit_T& resolution) const {
|
||||
return Unit_T((value_ + resolution.value_ - 1) / resolution.value_) *
|
||||
resolution.value_;
|
||||
}
|
||||
constexpr Unit_T RoundDownTo(const Unit_T& resolution) const {
|
||||
return Unit_T(value_ / resolution.value_) * resolution.value_;
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T, typename std::enable_if<
|
||||
std::is_integral<T>::value>::type* = nullptr>
|
||||
static constexpr Unit_T FromValue(T value) {
|
||||
return Unit_T(rtc::dchecked_cast<int64_t>(value));
|
||||
}
|
||||
template <typename T, typename std::enable_if<
|
||||
std::is_floating_point<T>::value>::type* = nullptr>
|
||||
static constexpr Unit_T FromValue(T value) {
|
||||
if (value == std::numeric_limits<T>::infinity()) {
|
||||
return PlusInfinity();
|
||||
} else if (value == -std::numeric_limits<T>::infinity()) {
|
||||
return MinusInfinity();
|
||||
} else {
|
||||
return FromValue(rtc::dchecked_cast<int64_t>(value));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
std::is_integral<T>::value>::type* = nullptr>
|
||||
static constexpr Unit_T FromFraction(int64_t denominator, T value) {
|
||||
return Unit_T(rtc::dchecked_cast<int64_t>(value * denominator));
|
||||
}
|
||||
template <typename T, typename std::enable_if<
|
||||
std::is_floating_point<T>::value>::type* = nullptr>
|
||||
static constexpr Unit_T FromFraction(int64_t denominator, T value) {
|
||||
return FromValue(value * denominator);
|
||||
}
|
||||
|
||||
template <typename T = int64_t>
|
||||
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
ToValue() const {
|
||||
return rtc::dchecked_cast<T>(value_);
|
||||
}
|
||||
template <typename T>
|
||||
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
ToValue() const {
|
||||
return IsPlusInfinity() ? std::numeric_limits<T>::infinity()
|
||||
: IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
|
||||
: value_;
|
||||
}
|
||||
template <typename T>
|
||||
constexpr T ToValueOr(T fallback_value) const {
|
||||
return IsFinite() ? value_ : fallback_value;
|
||||
}
|
||||
|
||||
template <int64_t Denominator, typename T = int64_t>
|
||||
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
ToFraction() const {
|
||||
return rtc::dchecked_cast<T>(DivideRoundToNearest(value_, Denominator));
|
||||
}
|
||||
template <int64_t Denominator, typename T>
|
||||
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
ToFraction() const {
|
||||
return ToValue<T>() * (1 / static_cast<T>(Denominator));
|
||||
}
|
||||
|
||||
template <int64_t Denominator>
|
||||
constexpr int64_t ToFractionOr(int64_t fallback_value) const {
|
||||
return IsFinite() ? DivideRoundToNearest(value_, Denominator)
|
||||
: fallback_value;
|
||||
}
|
||||
|
||||
template <int64_t Factor, typename T = int64_t>
|
||||
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
ToMultiple() const {
|
||||
return rtc::dchecked_cast<T>(ToValue() * Factor);
|
||||
}
|
||||
template <int64_t Factor, typename T>
|
||||
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
ToMultiple() const {
|
||||
return ToValue<T>() * Factor;
|
||||
}
|
||||
|
||||
explicit constexpr UnitBase(int64_t value) : value_(value) {}
|
||||
|
||||
private:
|
||||
template <class RelativeUnit_T>
|
||||
friend class RelativeUnit;
|
||||
|
||||
static inline constexpr int64_t PlusInfinityVal() {
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
static inline constexpr int64_t MinusInfinityVal() {
|
||||
return std::numeric_limits<int64_t>::min();
|
||||
}
|
||||
|
||||
constexpr Unit_T& AsSubClassRef() { return static_cast<Unit_T&>(*this); }
|
||||
constexpr const Unit_T& AsSubClassRef() const {
|
||||
return static_cast<const Unit_T&>(*this);
|
||||
}
|
||||
|
||||
int64_t value_;
|
||||
};
|
||||
|
||||
// Extends UnitBase to provide operations for relative units, that is, units
|
||||
// that have a meaningful relation between values such that a += b is a
|
||||
// sensible thing to do. For a,b <- same unit.
|
||||
template <class Unit_T>
|
||||
class RelativeUnit : public UnitBase<Unit_T> {
|
||||
public:
|
||||
constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const {
|
||||
return std::max(min_value,
|
||||
std::min(UnitBase<Unit_T>::AsSubClassRef(), max_value));
|
||||
}
|
||||
constexpr void Clamp(Unit_T min_value, Unit_T max_value) {
|
||||
*this = Clamped(min_value, max_value);
|
||||
}
|
||||
constexpr Unit_T operator+(const Unit_T other) const {
|
||||
if (this->IsPlusInfinity() || other.IsPlusInfinity()) {
|
||||
return this->PlusInfinity();
|
||||
} else if (this->IsMinusInfinity() || other.IsMinusInfinity()) {
|
||||
return this->MinusInfinity();
|
||||
}
|
||||
return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue());
|
||||
}
|
||||
constexpr Unit_T operator-(const Unit_T other) const {
|
||||
if (this->IsPlusInfinity() || other.IsMinusInfinity()) {
|
||||
return this->PlusInfinity();
|
||||
} else if (this->IsMinusInfinity() || other.IsPlusInfinity()) {
|
||||
return this->MinusInfinity();
|
||||
}
|
||||
return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue());
|
||||
}
|
||||
constexpr Unit_T& operator+=(const Unit_T other) {
|
||||
*this = *this + other;
|
||||
return this->AsSubClassRef();
|
||||
}
|
||||
constexpr Unit_T& operator-=(const Unit_T other) {
|
||||
*this = *this - other;
|
||||
return this->AsSubClassRef();
|
||||
}
|
||||
constexpr double operator/(const Unit_T other) const {
|
||||
return UnitBase<Unit_T>::template ToValue<double>() /
|
||||
other.template ToValue<double>();
|
||||
}
|
||||
template <typename T,
|
||||
typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
|
||||
constexpr Unit_T operator/(T scalar) const {
|
||||
return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() / scalar));
|
||||
}
|
||||
template <typename T,
|
||||
typename std::enable_if_t<std::is_integral_v<T>>* = nullptr>
|
||||
constexpr Unit_T operator/(T scalar) const {
|
||||
return UnitBase<Unit_T>::FromValue(this->ToValue() / scalar);
|
||||
}
|
||||
constexpr Unit_T operator*(double scalar) const {
|
||||
return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() * scalar));
|
||||
}
|
||||
constexpr Unit_T operator*(int64_t scalar) const {
|
||||
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
|
||||
}
|
||||
constexpr Unit_T operator*(int32_t scalar) const {
|
||||
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
|
||||
}
|
||||
constexpr Unit_T operator*(size_t scalar) const {
|
||||
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
|
||||
}
|
||||
|
||||
protected:
|
||||
using UnitBase<Unit_T>::UnitBase;
|
||||
constexpr RelativeUnit() : UnitBase<Unit_T>(0) {}
|
||||
};
|
||||
|
||||
template <class Unit_T>
|
||||
inline constexpr Unit_T operator*(double scalar, RelativeUnit<Unit_T> other) {
|
||||
return other * scalar;
|
||||
}
|
||||
template <class Unit_T>
|
||||
inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit<Unit_T> other) {
|
||||
return other * scalar;
|
||||
}
|
||||
template <class Unit_T>
|
||||
inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) {
|
||||
return other * scalar;
|
||||
}
|
||||
template <class Unit_T>
|
||||
inline constexpr Unit_T operator*(size_t scalar, RelativeUnit<Unit_T> other) {
|
||||
return other * scalar;
|
||||
}
|
||||
|
||||
template <class Unit_T>
|
||||
inline constexpr Unit_T operator-(RelativeUnit<Unit_T> other) {
|
||||
if (other.IsPlusInfinity()) return UnitBase<Unit_T>::MinusInfinity();
|
||||
if (other.IsMinusInfinity()) return UnitBase<Unit_T>::PlusInfinity();
|
||||
return -1 * other;
|
||||
}
|
||||
|
||||
} // namespace rtc_units_impl
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_UNITS_UNIT_BASE_H_
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "api/video/video_timing.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "log.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) {
|
||||
if (time_ms < base_ms) {
|
||||
LOG_ERROR("Delta {} ms expected to be positive", (time_ms - base_ms));
|
||||
}
|
||||
return rtc::saturated_cast<uint16_t>(time_ms - base_ms);
|
||||
}
|
||||
|
||||
uint16_t VideoSendTiming::GetDeltaCappedMs(TimeDelta delta) {
|
||||
if (delta < TimeDelta::Zero()) {
|
||||
LOG_ERROR("Delta {} ms expected to be positive", delta.ms());
|
||||
}
|
||||
return rtc::saturated_cast<uint16_t>(delta.ms());
|
||||
}
|
||||
|
||||
TimingFrameInfo::TimingFrameInfo()
|
||||
: rtp_timestamp(0),
|
||||
capture_time_ms(-1),
|
||||
encode_start_ms(-1),
|
||||
encode_finish_ms(-1),
|
||||
packetization_finish_ms(-1),
|
||||
pacer_exit_ms(-1),
|
||||
network_timestamp_ms(-1),
|
||||
network2_timestamp_ms(-1),
|
||||
receive_start_ms(-1),
|
||||
receive_finish_ms(-1),
|
||||
decode_start_ms(-1),
|
||||
decode_finish_ms(-1),
|
||||
render_time_ms(-1),
|
||||
flags(VideoSendTiming::kNotTriggered) {}
|
||||
|
||||
int64_t TimingFrameInfo::EndToEndDelay() const {
|
||||
return capture_time_ms >= 0 ? decode_finish_ms - capture_time_ms : -1;
|
||||
}
|
||||
|
||||
bool TimingFrameInfo::IsLongerThan(const TimingFrameInfo& other) const {
|
||||
int64_t other_delay = other.EndToEndDelay();
|
||||
return other_delay == -1 || EndToEndDelay() > other_delay;
|
||||
}
|
||||
|
||||
bool TimingFrameInfo::operator<(const TimingFrameInfo& other) const {
|
||||
return other.IsLongerThan(*this);
|
||||
}
|
||||
|
||||
bool TimingFrameInfo::operator<=(const TimingFrameInfo& other) const {
|
||||
return !IsLongerThan(other);
|
||||
}
|
||||
|
||||
bool TimingFrameInfo::IsOutlier() const {
|
||||
return !IsInvalid() && (flags & VideoSendTiming::kTriggeredBySize);
|
||||
}
|
||||
|
||||
bool TimingFrameInfo::IsTimerTriggered() const {
|
||||
return !IsInvalid() && (flags & VideoSendTiming::kTriggeredByTimer);
|
||||
}
|
||||
|
||||
bool TimingFrameInfo::IsInvalid() const {
|
||||
return flags == VideoSendTiming::kInvalid;
|
||||
}
|
||||
|
||||
std::string TimingFrameInfo::ToString() const {
|
||||
if (IsInvalid()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << rtp_timestamp << ',' << capture_time_ms << ',' << encode_start_ms
|
||||
<< ',' << encode_finish_ms << ',' << packetization_finish_ms << ','
|
||||
<< pacer_exit_ms << ',' << network_timestamp_ms << ','
|
||||
<< network2_timestamp_ms << ',' << receive_start_ms << ','
|
||||
<< receive_finish_ms << ',' << decode_start_ms << ',' << decode_finish_ms
|
||||
<< ',' << render_time_ms << ',' << IsOutlier() << ','
|
||||
<< IsTimerTriggered();
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
VideoPlayoutDelay::VideoPlayoutDelay(TimeDelta min, TimeDelta max)
|
||||
: min_(std::clamp(min, TimeDelta::Zero(), kMax)),
|
||||
max_(std::clamp(max, min_, kMax)) {
|
||||
if (!(TimeDelta::Zero() <= min && min <= max && max <= kMax)) {
|
||||
LOG_ERROR("Invalid video playout delay: [{},{}]. Clamped to [{},{}]", min,
|
||||
max, this->min(), this->max());
|
||||
}
|
||||
}
|
||||
|
||||
bool VideoPlayoutDelay::Set(TimeDelta min, TimeDelta max) {
|
||||
if (TimeDelta::Zero() <= min && min <= max && max <= kMax) {
|
||||
min_ = min;
|
||||
max_ = max;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef API_VIDEO_VIDEO_TIMING_H_
|
||||
#define API_VIDEO_VIDEO_TIMING_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Video timing timestamps in ms counted from capture_time_ms of a frame.
|
||||
// This structure represents data sent in video-timing RTP header extension.
|
||||
struct VideoSendTiming {
|
||||
enum TimingFrameFlags : uint8_t {
|
||||
kNotTriggered = 0, // Timing info valid, but not to be transmitted.
|
||||
// Used on send-side only.
|
||||
kTriggeredByTimer = 1 << 0, // Frame marked for tracing by periodic timer.
|
||||
kTriggeredBySize = 1 << 1, // Frame marked for tracing due to size.
|
||||
kInvalid = std::numeric_limits<uint8_t>::max() // Invalid, ignore!
|
||||
};
|
||||
|
||||
// Returns |time_ms - base_ms| capped at max 16-bit value.
|
||||
// Used to fill this data structure as per
|
||||
// https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores
|
||||
// 16-bit deltas of timestamps from packet capture time.
|
||||
static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms);
|
||||
static uint16_t GetDeltaCappedMs(TimeDelta delta);
|
||||
|
||||
uint16_t encode_start_delta_ms;
|
||||
uint16_t encode_finish_delta_ms;
|
||||
uint16_t packetization_finish_delta_ms;
|
||||
uint16_t pacer_exit_delta_ms;
|
||||
uint16_t network_timestamp_delta_ms;
|
||||
uint16_t network2_timestamp_delta_ms;
|
||||
uint8_t flags = TimingFrameFlags::kInvalid;
|
||||
};
|
||||
|
||||
// Used to report precise timings of a 'timing frames'. Contains all important
|
||||
// timestamps for a lifetime of that specific frame. Reported as a string via
|
||||
// GetStats(). Only frame which took the longest between two GetStats calls is
|
||||
// reported.
|
||||
struct TimingFrameInfo {
|
||||
TimingFrameInfo();
|
||||
|
||||
// Returns end-to-end delay of a frame, if sender and receiver timestamps are
|
||||
// synchronized, -1 otherwise.
|
||||
int64_t EndToEndDelay() const;
|
||||
|
||||
// Returns true if current frame took longer to process than `other` frame.
|
||||
// If other frame's clocks are not synchronized, current frame is always
|
||||
// preferred.
|
||||
bool IsLongerThan(const TimingFrameInfo& other) const;
|
||||
|
||||
// Returns true if flags are set to indicate this frame was marked for tracing
|
||||
// due to the size being outside some limit.
|
||||
bool IsOutlier() const;
|
||||
|
||||
// Returns true if flags are set to indicate this frame was marked fro tracing
|
||||
// due to cyclic timer.
|
||||
bool IsTimerTriggered() const;
|
||||
|
||||
// Returns true if the timing data is marked as invalid, in which case it
|
||||
// should be ignored.
|
||||
bool IsInvalid() const;
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
bool operator<(const TimingFrameInfo& other) const;
|
||||
|
||||
bool operator<=(const TimingFrameInfo& other) const;
|
||||
|
||||
uint32_t rtp_timestamp; // Identifier of a frame.
|
||||
// All timestamps below are in local monotonous clock of a receiver.
|
||||
// If sender clock is not yet estimated, sender timestamps
|
||||
// (capture_time_ms ... pacer_exit_ms) are negative values, still
|
||||
// relatively correct.
|
||||
int64_t capture_time_ms; // Captrue time of a frame.
|
||||
int64_t encode_start_ms; // Encode start time.
|
||||
int64_t encode_finish_ms; // Encode completion time.
|
||||
int64_t packetization_finish_ms; // Time when frame was passed to pacer.
|
||||
int64_t pacer_exit_ms; // Time when last packet was pushed out of pacer.
|
||||
// Two in-network RTP processor timestamps: meaning is application specific.
|
||||
int64_t network_timestamp_ms;
|
||||
int64_t network2_timestamp_ms;
|
||||
int64_t receive_start_ms; // First received packet time.
|
||||
int64_t receive_finish_ms; // Last received packet time.
|
||||
int64_t decode_start_ms; // Decode start time.
|
||||
int64_t decode_finish_ms; // Decode completion time.
|
||||
int64_t render_time_ms; // Proposed render time to insure smooth playback.
|
||||
|
||||
uint8_t flags; // Flags indicating validity and/or why tracing was triggered.
|
||||
};
|
||||
|
||||
// Minimum and maximum playout delay values from capture to render.
|
||||
// These are best effort values.
|
||||
//
|
||||
// min = max = 0 indicates that the receiver should try and render
|
||||
// frame as soon as possible.
|
||||
//
|
||||
// min = x, max = y indicates that the receiver is free to adapt
|
||||
// in the range (x, y) based on network jitter.
|
||||
// This class ensures invariant 0 <= min <= max <= kMax.
|
||||
class VideoPlayoutDelay {
|
||||
public:
|
||||
// Maximum supported value for the delay limit.
|
||||
static constexpr TimeDelta kMax = TimeDelta::Millis(10) * 0xFFF;
|
||||
|
||||
// Creates delay limits that indicates receiver should try to render frame
|
||||
// as soon as possible.
|
||||
static VideoPlayoutDelay Minimal() {
|
||||
return VideoPlayoutDelay(TimeDelta::Zero(), TimeDelta::Zero());
|
||||
}
|
||||
|
||||
// Creates valid, but unspecified limits.
|
||||
VideoPlayoutDelay() = default;
|
||||
VideoPlayoutDelay(const VideoPlayoutDelay&) = default;
|
||||
VideoPlayoutDelay& operator=(const VideoPlayoutDelay&) = default;
|
||||
VideoPlayoutDelay(TimeDelta min, TimeDelta max);
|
||||
|
||||
bool Set(TimeDelta min, TimeDelta max);
|
||||
|
||||
TimeDelta min() const { return min_; }
|
||||
TimeDelta max() const { return max_; }
|
||||
|
||||
friend bool operator==(const VideoPlayoutDelay& lhs,
|
||||
const VideoPlayoutDelay& rhs) {
|
||||
return lhs.min_ == rhs.min_ && lhs.max_ == rhs.max_;
|
||||
}
|
||||
|
||||
private:
|
||||
TimeDelta min_ = TimeDelta::Zero();
|
||||
TimeDelta max_ = kMax;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_VIDEO_VIDEO_TIMING_H_
|
||||
@@ -1,390 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2024-12-18
|
||||
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _BYTE_IO_H_
|
||||
#define _BYTE_IO_H_
|
||||
|
||||
// This file contains classes for reading and writing integer types from/to
|
||||
// byte array representations. Signed/unsigned, partial (whole byte) sizes,
|
||||
// and big/little endian byte order is all supported.
|
||||
//
|
||||
// Usage examples:
|
||||
//
|
||||
// uint8_t* buffer = ...;
|
||||
//
|
||||
// // Read an unsigned 4 byte integer in big endian format
|
||||
// uint32_t val = ByteReader<uint32_t>::ReadBigEndian(buffer);
|
||||
//
|
||||
// // Read a signed 24-bit (3 byte) integer in little endian format
|
||||
// int32_t val = ByteReader<int32_t, 3>::ReadLittle(buffer);
|
||||
//
|
||||
// // Write an unsigned 8 byte integer in little endian format
|
||||
// ByteWriter<uint64_t>::WriteLittleEndian(buffer, val);
|
||||
//
|
||||
// Write an unsigned 40-bit (5 byte) integer in big endian format
|
||||
// ByteWriter<uint64_t, 5>::WriteBigEndian(buffer, val);
|
||||
//
|
||||
// These classes are implemented as recursive templetizations, intended to make
|
||||
// it easy for the compiler to completely inline the reading/writing.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
// According to ISO C standard ISO/IEC 9899, section 6.2.6.2 (2), the three
|
||||
// representations of signed integers allowed are two's complement, one's
|
||||
// complement and sign/magnitude. We can detect which is used by looking at
|
||||
// the two last bits of -1, which will be 11 in two's complement, 10 in one's
|
||||
// complement and 01 in sign/magnitude.
|
||||
// TODO(sprang): In the unlikely event that we actually need to support a
|
||||
// platform that doesn't use two's complement, implement conversion to/from
|
||||
// wire format.
|
||||
|
||||
// Assume the if any one signed integer type is two's complement, then all
|
||||
// other will be too.
|
||||
static_assert(
|
||||
(-1 & 0x03) == 0x03,
|
||||
"Only two's complement representation of signed integers supported.");
|
||||
|
||||
// Plain const char* won't work for static_assert, use #define instead.
|
||||
#define kSizeErrorMsg "Byte size must be less than or equal to data type size."
|
||||
|
||||
// Utility class for getting the unsigned equivalent of a signed type.
|
||||
template <typename T>
|
||||
struct UnsignedOf;
|
||||
|
||||
// Class for reading integers from a sequence of bytes.
|
||||
// T = type of integer, B = bytes to read, is_signed = true if signed integer.
|
||||
// If is_signed is true and B < sizeof(T), sign extension might be needed.
|
||||
template <typename T, unsigned int B = sizeof(T),
|
||||
bool is_signed = std::numeric_limits<T>::is_signed>
|
||||
class ByteReader;
|
||||
|
||||
// Specialization of ByteReader for unsigned types.
|
||||
template <typename T, unsigned int B>
|
||||
class ByteReader<T, B, false> {
|
||||
public:
|
||||
static T ReadBigEndian(const uint8_t* data) {
|
||||
static_assert(B <= sizeof(T), kSizeErrorMsg);
|
||||
return InternalReadBigEndian(data);
|
||||
}
|
||||
|
||||
static T ReadLittleEndian(const uint8_t* data) {
|
||||
static_assert(B <= sizeof(T), kSizeErrorMsg);
|
||||
return InternalReadLittleEndian(data);
|
||||
}
|
||||
|
||||
private:
|
||||
static T InternalReadBigEndian(const uint8_t* data) {
|
||||
T val(0);
|
||||
for (unsigned int i = 0; i < B; ++i)
|
||||
val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8);
|
||||
return val;
|
||||
}
|
||||
|
||||
static T InternalReadLittleEndian(const uint8_t* data) {
|
||||
T val(0);
|
||||
for (unsigned int i = 0; i < B; ++i)
|
||||
val |= static_cast<T>(data[i]) << (i * 8);
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of ByteReader for signed types.
|
||||
template <typename T, unsigned int B>
|
||||
class ByteReader<T, B, true> {
|
||||
public:
|
||||
typedef typename UnsignedOf<T>::Type U;
|
||||
|
||||
static T ReadBigEndian(const uint8_t* data) {
|
||||
U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data);
|
||||
if (B < sizeof(T)) unsigned_val = SignExtend(unsigned_val);
|
||||
return ReinterpretAsSigned(unsigned_val);
|
||||
}
|
||||
|
||||
static T ReadLittleEndian(const uint8_t* data) {
|
||||
U unsigned_val = ByteReader<T, B, false>::ReadLittleEndian(data);
|
||||
if (B < sizeof(T)) unsigned_val = SignExtend(unsigned_val);
|
||||
return ReinterpretAsSigned(unsigned_val);
|
||||
}
|
||||
|
||||
private:
|
||||
// As a hack to avoid implementation-specific or undefined behavior when
|
||||
// bit-shifting or casting signed integers, read as a signed equivalent
|
||||
// instead and convert to signed. This is safe since we have asserted that
|
||||
// two's complement for is used.
|
||||
static T ReinterpretAsSigned(U unsigned_val) {
|
||||
// An unsigned value with only the highest order bit set (ex 0x80).
|
||||
const U kUnsignedHighestBitMask = static_cast<U>(1)
|
||||
<< ((sizeof(U) * 8) - 1);
|
||||
// A signed value with only the highest bit set. Since this is two's
|
||||
// complement form, we can use the min value from std::numeric_limits.
|
||||
const T kSignedHighestBitMask = std::numeric_limits<T>::min();
|
||||
|
||||
T val;
|
||||
if ((unsigned_val & kUnsignedHighestBitMask) != 0) {
|
||||
// Casting is only safe when unsigned value can be represented in the
|
||||
// signed target type, so mask out highest bit and mask it back manually.
|
||||
val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask);
|
||||
val |= kSignedHighestBitMask;
|
||||
} else {
|
||||
val = static_cast<T>(unsigned_val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
// If number of bytes is less than native data type (eg 24 bit, in int32_t),
|
||||
// and the most significant bit of the actual data is set, we must sign
|
||||
// extend the remaining byte(s) with ones so that the correct negative
|
||||
// number is retained.
|
||||
// Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B
|
||||
static U SignExtend(const U val) {
|
||||
const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8));
|
||||
if ((kMsb & 0x80) != 0) {
|
||||
// Create a mask where all bits used by the B bytes are set to one,
|
||||
// for instance 0x00FFFFFF for B = 3. Bit-wise invert that mask (to
|
||||
// (0xFF000000 in the example above) and add it to the input value.
|
||||
// The "B % sizeof(T)" is a workaround to undefined values warnings for
|
||||
// B == sizeof(T), in which case this code won't be called anyway.
|
||||
const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1;
|
||||
return ~kUsedBitsMask | val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
// Class for writing integers to a sequence of bytes
|
||||
// T = type of integer, B = bytes to write
|
||||
template <typename T, unsigned int B = sizeof(T),
|
||||
bool is_signed = std::numeric_limits<T>::is_signed>
|
||||
class ByteWriter;
|
||||
|
||||
// Specialization of ByteWriter for unsigned types.
|
||||
template <typename T, unsigned int B>
|
||||
class ByteWriter<T, B, false> {
|
||||
public:
|
||||
static void WriteBigEndian(uint8_t* data, T val) {
|
||||
static_assert(B <= sizeof(T), kSizeErrorMsg);
|
||||
for (unsigned int i = 0; i < B; ++i) {
|
||||
data[i] = val >> ((B - 1 - i) * 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteLittleEndian(uint8_t* data, T val) {
|
||||
static_assert(B <= sizeof(T), kSizeErrorMsg);
|
||||
for (unsigned int i = 0; i < B; ++i) {
|
||||
data[i] = val >> (i * 8);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of ByteWriter for signed types.
|
||||
template <typename T, unsigned int B>
|
||||
class ByteWriter<T, B, true> {
|
||||
public:
|
||||
typedef typename UnsignedOf<T>::Type U;
|
||||
|
||||
static void WriteBigEndian(uint8_t* data, T val) {
|
||||
ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val));
|
||||
}
|
||||
|
||||
static void WriteLittleEndian(uint8_t* data, T val) {
|
||||
ByteWriter<U, B, false>::WriteLittleEndian(data,
|
||||
ReinterpretAsUnsigned(val));
|
||||
}
|
||||
|
||||
private:
|
||||
static U ReinterpretAsUnsigned(T val) {
|
||||
// According to ISO C standard ISO/IEC 9899, section 6.3.1.3 (1, 2) a
|
||||
// conversion from signed to unsigned keeps the value if the new type can
|
||||
// represent it, and otherwise adds one more than the max value of T until
|
||||
// the value is in range. For two's complement, this fortunately means
|
||||
// that the bit-wise value will be intact. Thus, since we have asserted that
|
||||
// two's complement form is actually used, a simple cast is sufficient.
|
||||
return static_cast<U>(val);
|
||||
}
|
||||
};
|
||||
|
||||
// ----- Below follows specializations of UnsignedOf utility class -----
|
||||
|
||||
template <>
|
||||
struct UnsignedOf<int8_t> {
|
||||
typedef uint8_t Type;
|
||||
};
|
||||
template <>
|
||||
struct UnsignedOf<int16_t> {
|
||||
typedef uint16_t Type;
|
||||
};
|
||||
template <>
|
||||
struct UnsignedOf<int32_t> {
|
||||
typedef uint32_t Type;
|
||||
};
|
||||
template <>
|
||||
struct UnsignedOf<int64_t> {
|
||||
typedef uint64_t Type;
|
||||
};
|
||||
|
||||
// ----- Below follows specializations for unsigned, B in { 1, 2, 4, 8 } -----
|
||||
|
||||
// TODO(sprang): Check if these actually help or if generic cases will be
|
||||
// unrolled to and optimized to similar performance.
|
||||
|
||||
// Specializations for single bytes
|
||||
template <typename T>
|
||||
class ByteReader<T, 1, false> {
|
||||
public:
|
||||
static T ReadBigEndian(const uint8_t* data) {
|
||||
static_assert(sizeof(T) == 1, kSizeErrorMsg);
|
||||
return data[0];
|
||||
}
|
||||
|
||||
static T ReadLittleEndian(const uint8_t* data) {
|
||||
static_assert(sizeof(T) == 1, kSizeErrorMsg);
|
||||
return data[0];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ByteWriter<T, 1, false> {
|
||||
public:
|
||||
static void WriteBigEndian(uint8_t* data, T val) {
|
||||
static_assert(sizeof(T) == 1, kSizeErrorMsg);
|
||||
data[0] = val;
|
||||
}
|
||||
|
||||
static void WriteLittleEndian(uint8_t* data, T val) {
|
||||
static_assert(sizeof(T) == 1, kSizeErrorMsg);
|
||||
data[0] = val;
|
||||
}
|
||||
};
|
||||
|
||||
// Specializations for two byte words
|
||||
template <typename T>
|
||||
class ByteReader<T, 2, false> {
|
||||
public:
|
||||
static T ReadBigEndian(const uint8_t* data) {
|
||||
static_assert(sizeof(T) >= 2, kSizeErrorMsg);
|
||||
return (data[0] << 8) | data[1];
|
||||
}
|
||||
|
||||
static T ReadLittleEndian(const uint8_t* data) {
|
||||
static_assert(sizeof(T) >= 2, kSizeErrorMsg);
|
||||
return data[0] | (data[1] << 8);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ByteWriter<T, 2, false> {
|
||||
public:
|
||||
static void WriteBigEndian(uint8_t* data, T val) {
|
||||
static_assert(sizeof(T) >= 2, kSizeErrorMsg);
|
||||
data[0] = val >> 8;
|
||||
data[1] = val;
|
||||
}
|
||||
|
||||
static void WriteLittleEndian(uint8_t* data, T val) {
|
||||
static_assert(sizeof(T) >= 2, kSizeErrorMsg);
|
||||
data[0] = val;
|
||||
data[1] = val >> 8;
|
||||
}
|
||||
};
|
||||
|
||||
// Specializations for four byte words.
|
||||
template <typename T>
|
||||
class ByteReader<T, 4, false> {
|
||||
public:
|
||||
static T ReadBigEndian(const uint8_t* data) {
|
||||
static_assert(sizeof(T) >= 4, kSizeErrorMsg);
|
||||
return (Get(data, 0) << 24) | (Get(data, 1) << 16) | (Get(data, 2) << 8) |
|
||||
Get(data, 3);
|
||||
}
|
||||
|
||||
static T ReadLittleEndian(const uint8_t* data) {
|
||||
static_assert(sizeof(T) >= 4, kSizeErrorMsg);
|
||||
return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) |
|
||||
(Get(data, 3) << 24);
|
||||
}
|
||||
|
||||
private:
|
||||
inline static T Get(const uint8_t* data, unsigned int index) {
|
||||
return static_cast<T>(data[index]);
|
||||
}
|
||||
};
|
||||
|
||||
// Specializations for four byte words.
|
||||
template <typename T>
|
||||
class ByteWriter<T, 4, false> {
|
||||
public:
|
||||
static void WriteBigEndian(uint8_t* data, T val) {
|
||||
static_assert(sizeof(T) >= 4, kSizeErrorMsg);
|
||||
data[0] = val >> 24;
|
||||
data[1] = val >> 16;
|
||||
data[2] = val >> 8;
|
||||
data[3] = val;
|
||||
}
|
||||
|
||||
static void WriteLittleEndian(uint8_t* data, T val) {
|
||||
static_assert(sizeof(T) >= 4, kSizeErrorMsg);
|
||||
data[0] = val;
|
||||
data[1] = val >> 8;
|
||||
data[2] = val >> 16;
|
||||
data[3] = val >> 24;
|
||||
}
|
||||
};
|
||||
|
||||
// Specializations for eight byte words.
|
||||
template <typename T>
|
||||
class ByteReader<T, 8, false> {
|
||||
public:
|
||||
static T ReadBigEndian(const uint8_t* data) {
|
||||
static_assert(sizeof(T) >= 8, kSizeErrorMsg);
|
||||
return (Get(data, 0) << 56) | (Get(data, 1) << 48) | (Get(data, 2) << 40) |
|
||||
(Get(data, 3) << 32) | (Get(data, 4) << 24) | (Get(data, 5) << 16) |
|
||||
(Get(data, 6) << 8) | Get(data, 7);
|
||||
}
|
||||
|
||||
static T ReadLittleEndian(const uint8_t* data) {
|
||||
static_assert(sizeof(T) >= 8, kSizeErrorMsg);
|
||||
return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) |
|
||||
(Get(data, 3) << 24) | (Get(data, 4) << 32) | (Get(data, 5) << 40) |
|
||||
(Get(data, 6) << 48) | (Get(data, 7) << 56);
|
||||
}
|
||||
|
||||
private:
|
||||
inline static T Get(const uint8_t* data, unsigned int index) {
|
||||
return static_cast<T>(data[index]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ByteWriter<T, 8, false> {
|
||||
public:
|
||||
static void WriteBigEndian(uint8_t* data, T val) {
|
||||
static_assert(sizeof(T) >= 8, kSizeErrorMsg);
|
||||
data[0] = val >> 56;
|
||||
data[1] = val >> 48;
|
||||
data[2] = val >> 40;
|
||||
data[3] = val >> 32;
|
||||
data[4] = val >> 24;
|
||||
data[5] = val >> 16;
|
||||
data[6] = val >> 8;
|
||||
data[7] = val;
|
||||
}
|
||||
|
||||
static void WriteLittleEndian(uint8_t* data, T val) {
|
||||
static_assert(sizeof(T) >= 8, kSizeErrorMsg);
|
||||
data[0] = val;
|
||||
data[1] = val >> 8;
|
||||
data[2] = val >> 16;
|
||||
data[3] = val >> 24;
|
||||
data[4] = val >> 32;
|
||||
data[5] = val >> 40;
|
||||
data[6] = val >> 48;
|
||||
data[7] = val >> 56;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,140 +0,0 @@
|
||||
#include "system_clock.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#if defined(__POSIX__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
int64_t SystemClock::ConvertToNtpTime(int64_t time_us) {
|
||||
constexpr int64_t kMicrosecondsPerSecond = 1000000;
|
||||
constexpr uint64_t kNtpFractionalUnit = 0x100000000; // 2^32
|
||||
uint32_t seconds = static_cast<uint32_t>(time_us / kMicrosecondsPerSecond);
|
||||
uint32_t fractions =
|
||||
static_cast<uint32_t>((time_us % kMicrosecondsPerSecond) *
|
||||
kNtpFractionalUnit / kMicrosecondsPerSecond);
|
||||
|
||||
return seconds * kNtpFractionalUnit + fractions;
|
||||
}
|
||||
|
||||
int64_t SystemClock::CurrentTimeNs() {
|
||||
int64_t ticks = -1; // Default to error case
|
||||
|
||||
#if defined(__APPLE__)
|
||||
static mach_timebase_info_data_t timebase;
|
||||
if (timebase.denom == 0 && mach_timebase_info(&timebase) != KERN_SUCCESS) {
|
||||
return -1; // Error case for macOS timebase info retrieval
|
||||
}
|
||||
ticks = static_cast<int64_t>(mach_absolute_time() * timebase.numer) /
|
||||
timebase.denom;
|
||||
|
||||
#elif defined(__POSIX__)
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
return -1; // Error case for POSIX clock retrieval
|
||||
}
|
||||
ticks = static_cast<int64_t>(ts.tv_sec) * kNumNanosecsPerSec +
|
||||
static_cast<int64_t>(ts.tv_nsec);
|
||||
|
||||
#elif defined(_WIN32)
|
||||
static volatile LONG last_timegettime = 0;
|
||||
static volatile int64_t num_wrap_timegettime = 0;
|
||||
volatile LONG* last_timegettime_ptr = &last_timegettime;
|
||||
|
||||
DWORD now = timeGetTime();
|
||||
DWORD old = InterlockedExchange(last_timegettime_ptr, now);
|
||||
|
||||
if (now < old) {
|
||||
// Handle wraparound (when timeGetTime() wraps around after ~49.7 days)
|
||||
if (old > 0xf0000000 && now < 0x0fffffff) {
|
||||
num_wrap_timegettime++;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert milliseconds to nanoseconds and add wraparound offset
|
||||
ticks = static_cast<int64_t>(now) + (num_wrap_timegettime << 32);
|
||||
ticks *= 1000000;
|
||||
#endif
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
int64_t SystemClock::CurrentTime() { return CurrentTimeNs() / 1000LL; }
|
||||
|
||||
int64_t SystemClock::CurrentTimeUs() { return CurrentTimeNs() / 1000LL; }
|
||||
|
||||
int64_t SystemClock::CurrentTimeMs() { return CurrentTimeNs() / 1000000LL; }
|
||||
|
||||
int64_t SystemClock::CurrentNtpTime() {
|
||||
return ConvertToNtpTime(CurrentTimeNs());
|
||||
}
|
||||
|
||||
int64_t SystemClock::CurrentNtpTimeMs() {
|
||||
int64_t ntp_ts = ConvertToNtpTime(CurrentTimeNs());
|
||||
uint32_t seconds = static_cast<uint32_t>(ntp_ts / 1000000000);
|
||||
uint32_t fractions = static_cast<uint32_t>(ntp_ts % 1000000000);
|
||||
|
||||
static constexpr double kNtpFracPerMs = 4.294967296E6; // 2^32 / 1000.
|
||||
const double frac_ms = static_cast<double>(fractions) / kNtpFracPerMs;
|
||||
return 1000 * static_cast<int64_t>(seconds) +
|
||||
static_cast<int64_t>(frac_ms + 0.5);
|
||||
}
|
||||
|
||||
int64_t SystemClock::CurrentUtcTimeNs() {
|
||||
#if defined(__POSIX__)
|
||||
struct timeval time;
|
||||
gettimeofday(&time, nullptr);
|
||||
return (static_cast<int64_t>(time.tv_sec) * 1000000000 + time.tv_usec * 1000);
|
||||
#elif defined(_WIN32)
|
||||
FILETIME file_time;
|
||||
GetSystemTimeAsFileTime(&file_time);
|
||||
int64_t file_time_100ns =
|
||||
((int64_t)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime;
|
||||
constexpr int64_t kUnixEpochFileTimeOffsetIn100ns = 116444736000000000LL;
|
||||
return (file_time_100ns - kUnixEpochFileTimeOffsetIn100ns) * 100;
|
||||
#elif defined(__APPLE__)
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
|
||||
return -1; // Error case for macOS clock retrieval
|
||||
}
|
||||
return static_cast<int64_t>(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t SystemClock::CurrentUtcTimeUs() { return CurrentUtcTimeNs() / 1000LL; }
|
||||
|
||||
int64_t SystemClock::CurrentUtcTimeMs() {
|
||||
return CurrentUtcTimeNs() / 1000000LL;
|
||||
}
|
||||
|
||||
int64_t SystemClock::CurrentUtcTime() {
|
||||
return CurrentUtcTimeNs() / 1000000000LL;
|
||||
}
|
||||
|
||||
int64_t SystemClock::NtpToUtc(int64_t ntp_time) {
|
||||
constexpr int64_t kNtpEpochOffset =
|
||||
2208988800LL; // NTP epoch starts at 1900-01-01, Unix epoch starts at
|
||||
// 1970-01-01
|
||||
constexpr int64_t kMicrosecondsPerSecond = 1000000;
|
||||
constexpr uint64_t kNtpFractionalUnit = 0x100000000; // 2^32
|
||||
|
||||
uint32_t seconds = static_cast<uint32_t>(ntp_time / kNtpFractionalUnit);
|
||||
uint32_t fractions = static_cast<uint32_t>(ntp_time % kNtpFractionalUnit);
|
||||
|
||||
int64_t unix_seconds = static_cast<int64_t>(seconds) - kNtpEpochOffset;
|
||||
int64_t microseconds =
|
||||
(static_cast<int64_t>(fractions) * kMicrosecondsPerSecond) /
|
||||
kNtpFractionalUnit;
|
||||
|
||||
return unix_seconds * kMicrosecondsPerSecond + microseconds;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-02-19
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SYSTEM_CLOCK_H_
|
||||
#define _SYSTEM_CLOCK_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
static const int64_t kNtpEpochOffset = 2208988800LL;
|
||||
|
||||
class SystemClock {
|
||||
public:
|
||||
SystemClock() = default;
|
||||
~SystemClock() = default;
|
||||
|
||||
int64_t CurrentTime();
|
||||
int64_t CurrentTimeUs();
|
||||
int64_t CurrentTimeMs();
|
||||
int64_t CurrentTimeNs();
|
||||
|
||||
int64_t CurrentNtpTime();
|
||||
int64_t CurrentNtpTimeMs();
|
||||
|
||||
int64_t CurrentUtcTime();
|
||||
int64_t CurrentUtcTimeMs();
|
||||
int64_t CurrentUtcTimeUs();
|
||||
int64_t CurrentUtcTimeNs();
|
||||
|
||||
int64_t ConvertToNtpTime(int64_t time_us);
|
||||
|
||||
int64_t NtpToUtc(int64_t ntp_time);
|
||||
|
||||
int64_t CurrentNtpInMilliseconds() { return CurrentNtpTimeMs(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "common.h"
|
||||
|
||||
int CommonDummy()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <unordered_set>
|
||||
|
||||
int CommonDummy();
|
||||
|
||||
constexpr size_t HASH_STRING_PIECE(const char *string_piece) {
|
||||
std::size_t result = 0;
|
||||
while (*string_piece) {
|
||||
result = (result * 131) + *string_piece++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr size_t operator"" _H(const char *string_piece, size_t) {
|
||||
return HASH_STRING_PIECE(string_piece);
|
||||
}
|
||||
|
||||
inline const std::string GetIceUsername(const std::string &sdp) {
|
||||
std::string result = "";
|
||||
|
||||
std::string start = "ice-ufrag:";
|
||||
std::string end = "\r\n";
|
||||
size_t startPos = sdp.find(start);
|
||||
size_t endPos = sdp.find(end);
|
||||
|
||||
if (startPos != std::string::npos && endPos != std::string::npos) {
|
||||
result = sdp.substr(startPos + start.length(),
|
||||
endPos - startPos - start.length());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// SSRCManager is used to manage the SSRCs that have been used.
|
||||
|
||||
class SSRCManager {
|
||||
public:
|
||||
static SSRCManager &Instance() {
|
||||
static SSRCManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void AddSsrc(uint32_t ssrc) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
ssrcs_.insert(ssrc);
|
||||
}
|
||||
|
||||
void DeleteSsrc(uint32_t ssrc) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
ssrcs_.erase(ssrc);
|
||||
}
|
||||
|
||||
bool Contains(uint32_t ssrc) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return ssrcs_.count(ssrc) > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
SSRCManager() = default;
|
||||
~SSRCManager() = default;
|
||||
SSRCManager(const SSRCManager &) = delete;
|
||||
SSRCManager &operator=(const SSRCManager &) = delete;
|
||||
|
||||
std::unordered_set<uint32_t> ssrcs_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
inline uint32_t GenerateRandomSSRC() {
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<uint32_t> dis(1, 0xFFFFFFFF);
|
||||
return dis(gen);
|
||||
}
|
||||
|
||||
inline uint32_t GenerateUniqueSsrc() {
|
||||
uint32_t new_ssrc;
|
||||
do {
|
||||
new_ssrc = GenerateRandomSSRC();
|
||||
} while (SSRCManager::Instance().Contains(new_ssrc));
|
||||
SSRCManager::Instance().AddSsrc(new_ssrc);
|
||||
return new_ssrc;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-22
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _COPY_ON_WRITE_BUFFER_H_
|
||||
#define _COPY_ON_WRITE_BUFFER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class CopyOnWriteBuffer {
|
||||
public:
|
||||
CopyOnWriteBuffer() = default;
|
||||
CopyOnWriteBuffer(size_t size) {
|
||||
buffer_ = std::make_shared<std::vector<uint8_t>>(size);
|
||||
}
|
||||
CopyOnWriteBuffer(const uint8_t* data, size_t size) {
|
||||
buffer_ = std::make_shared<std::vector<uint8_t>>(data, data + size);
|
||||
}
|
||||
|
||||
CopyOnWriteBuffer(const CopyOnWriteBuffer& other) = default;
|
||||
CopyOnWriteBuffer(CopyOnWriteBuffer&& other) noexcept = default;
|
||||
CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& other) = default;
|
||||
CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& other) noexcept = default;
|
||||
|
||||
void SetData(const uint8_t* data, size_t size) {
|
||||
buffer_ = std::make_shared<std::vector<uint8_t>>(data, data + size);
|
||||
}
|
||||
|
||||
void InsertDataAt(size_t offset, const uint8_t* data, size_t size) {
|
||||
EnsureUnique();
|
||||
buffer_->insert(buffer_->begin() + offset, data, data + size);
|
||||
}
|
||||
|
||||
const uint8_t* data() const { return buffer_ ? buffer_->data() : nullptr; }
|
||||
|
||||
size_t size() const { return buffer_ ? buffer_->size() : 0; }
|
||||
|
||||
uint8_t& operator[](size_t index) {
|
||||
EnsureUnique();
|
||||
return (*buffer_)[index];
|
||||
}
|
||||
|
||||
const uint8_t& operator[](size_t index) const { return (*buffer_)[index]; }
|
||||
|
||||
private:
|
||||
void EnsureUnique() {
|
||||
if (buffer_.use_count() != 1) {
|
||||
buffer_ = std::make_shared<std::vector<uint8_t>>(*buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<uint8_t>> buffer_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-03-12
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _INLINED_VECTOR_H_
|
||||
#define _INLINED_VECTOR_H_
|
||||
|
||||
#include <array>
|
||||
#include <initializer_list>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
template <typename T, size_t N>
|
||||
class InlinedVector {
|
||||
public:
|
||||
InlinedVector() : size_(0), use_heap_(false) {}
|
||||
|
||||
void push_back(const T& value) {
|
||||
if (!use_heap_ && size_ < N) {
|
||||
stack_data_[size_] = value;
|
||||
} else {
|
||||
if (!use_heap_) {
|
||||
heap_data_.reserve(N * 2);
|
||||
for (size_t i = 0; i < size_; ++i) {
|
||||
heap_data_.push_back(stack_data_[i]);
|
||||
}
|
||||
use_heap_ = true;
|
||||
}
|
||||
heap_data_.push_back(value);
|
||||
}
|
||||
++size_;
|
||||
}
|
||||
|
||||
void assign(size_t n, const T& value) {
|
||||
clear();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const { return size_; }
|
||||
T& operator[](size_t index) {
|
||||
return use_heap_ ? heap_data_[index] : stack_data_[index];
|
||||
}
|
||||
|
||||
const T& operator[](size_t index) const {
|
||||
return use_heap_ ? heap_data_[index] : stack_data_[index];
|
||||
}
|
||||
|
||||
private:
|
||||
void clear() {
|
||||
size_ = 0;
|
||||
use_heap_ = false;
|
||||
heap_data_.clear();
|
||||
}
|
||||
|
||||
size_t size_;
|
||||
bool use_heap_;
|
||||
std::array<T, N> stack_data_;
|
||||
std::vector<T> heap_data_;
|
||||
};
|
||||
|
||||
#endif // _INLINED_VECTOR_H_
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-14
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIMITS_BASE_H_
|
||||
#define _LIMITS_BASE_H_
|
||||
|
||||
#include <limits>
|
||||
|
||||
template <typename T>
|
||||
bool IsInfinite(const T& value) {
|
||||
return value == std::numeric_limits<T>::min() ||
|
||||
value == std::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool IsFinite(const T& value) {
|
||||
return !IsInfinite(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool IsPlusFinite(const T& value) {
|
||||
return value == std::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool IsMinusFinite(const T& value) {
|
||||
return value == std::numeric_limits<T>::min();
|
||||
}
|
||||
|
||||
#define INT64_T_MAX std::numeric_limits<int64_t>::max()
|
||||
#define INT64_T_MIN std::numeric_limits<int64_t>::min()
|
||||
|
||||
#endif
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-08
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MOD_OPS_H_
|
||||
#define _MOD_OPS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
template <unsigned long M> // NOLINT
|
||||
inline unsigned long Add(unsigned long a, unsigned long b) { // NOLINT
|
||||
// RTC_DCHECK_LT(a, M);
|
||||
unsigned long t = M - b % M; // NOLINT
|
||||
unsigned long res = a - t; // NOLINT
|
||||
if (t > a) return res + M;
|
||||
return res;
|
||||
}
|
||||
|
||||
template <unsigned long M> // NOLINT
|
||||
inline unsigned long Subtract(unsigned long a, unsigned long b) { // NOLINT
|
||||
// RTC_DCHECK_LT(a, M);
|
||||
unsigned long sub = b % M; // NOLINT
|
||||
if (a < sub) return M - (sub - a);
|
||||
return a - sub;
|
||||
}
|
||||
|
||||
// Calculates the forward difference between two wrapping numbers.
|
||||
//
|
||||
// Example:
|
||||
// uint8_t x = 253;
|
||||
// uint8_t y = 2;
|
||||
//
|
||||
// ForwardDiff(x, y) == 5
|
||||
//
|
||||
// 252 253 254 255 0 1 2 3
|
||||
// #################################################
|
||||
// | | x | | | | | y | |
|
||||
// #################################################
|
||||
// |----->----->----->----->----->
|
||||
//
|
||||
// ForwardDiff(y, x) == 251
|
||||
//
|
||||
// 252 253 254 255 0 1 2 3
|
||||
// #################################################
|
||||
// | | x | | | | | y | |
|
||||
// #################################################
|
||||
// -->-----> |----->---
|
||||
//
|
||||
// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the
|
||||
// largest value representable by T.
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M > 0), T>::type ForwardDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
// RTC_DCHECK_LT(a, M);
|
||||
// RTC_DCHECK_LT(b, M);
|
||||
return a <= b ? b - a : M - (a - b);
|
||||
}
|
||||
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M == 0), T>::type ForwardDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return b - a;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ForwardDiff(T a, T b) {
|
||||
return ForwardDiff<T, 0>(a, b);
|
||||
}
|
||||
|
||||
// Calculates the reverse difference between two wrapping numbers.
|
||||
//
|
||||
// Example:
|
||||
// uint8_t x = 253;
|
||||
// uint8_t y = 2;
|
||||
//
|
||||
// ReverseDiff(y, x) == 5
|
||||
//
|
||||
// 252 253 254 255 0 1 2 3
|
||||
// #################################################
|
||||
// | | x | | | | | y | |
|
||||
// #################################################
|
||||
// <-----<-----<-----<-----<-----|
|
||||
//
|
||||
// ReverseDiff(x, y) == 251
|
||||
//
|
||||
// 252 253 254 255 0 1 2 3
|
||||
// #################################################
|
||||
// | | x | | | | | y | |
|
||||
// #################################################
|
||||
// ---<-----| |<-----<--
|
||||
//
|
||||
// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the
|
||||
// largest value representable by T.
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M > 0), T>::type ReverseDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
// RTC_DCHECK_LT(a, M);
|
||||
// RTC_DCHECK_LT(b, M);
|
||||
return b <= a ? a - b : M - (b - a);
|
||||
}
|
||||
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M == 0), T>::type ReverseDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return a - b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ReverseDiff(T a, T b) {
|
||||
return ReverseDiff<T, 0>(a, b);
|
||||
}
|
||||
|
||||
// Calculates the minimum distance between to wrapping numbers.
|
||||
//
|
||||
// The minimum distance is defined as min(ForwardDiff(a, b), ReverseDiff(a, b))
|
||||
template <typename T, T M = 0>
|
||||
inline T MinDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return (std::min)(ForwardDiff<T, M>(a, b), ReverseDiff<T, M>(a, b));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
|
||||
#define MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <typename U>
|
||||
inline bool IsNewer(U value, U prev_value) {
|
||||
static_assert(!std::numeric_limits<U>::is_signed, "U must be unsigned");
|
||||
// kBreakpoint is the half-way mark for the type U. For instance, for a
|
||||
// uint16_t it will be 0x8000, and for a uint32_t, it will be 0x8000000.
|
||||
constexpr U kBreakpoint = (std::numeric_limits<U>::max() >> 1) + 1;
|
||||
// Distinguish between elements that are exactly kBreakpoint apart.
|
||||
// If t1>t2 and |t1-t2| = kBreakpoint: IsNewer(t1,t2)=true,
|
||||
// IsNewer(t2,t1)=false
|
||||
// rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
|
||||
if (value - prev_value == kBreakpoint) {
|
||||
return value > prev_value;
|
||||
}
|
||||
return value != prev_value &&
|
||||
static_cast<U>(value - prev_value) < kBreakpoint;
|
||||
}
|
||||
|
||||
// NB: Doesn't fulfill strict weak ordering requirements.
|
||||
// Mustn't be used as std::map Compare function.
|
||||
inline bool IsNewerSequenceNumber(uint16_t sequence_number,
|
||||
uint16_t prev_sequence_number) {
|
||||
return IsNewer(sequence_number, prev_sequence_number);
|
||||
}
|
||||
|
||||
// NB: Doesn't fulfill strict weak ordering requirements.
|
||||
// Mustn't be used as std::map Compare function.
|
||||
inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
|
||||
return IsNewer(timestamp, prev_timestamp);
|
||||
}
|
||||
|
||||
inline uint16_t LatestSequenceNumber(uint16_t sequence_number1,
|
||||
uint16_t sequence_number2) {
|
||||
return IsNewerSequenceNumber(sequence_number1, sequence_number2)
|
||||
? sequence_number1
|
||||
: sequence_number2;
|
||||
}
|
||||
|
||||
inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
|
||||
return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_ARRAYSIZE_H_
|
||||
#define RTC_BASE_ARRAYSIZE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// This file defines the arraysize() macro and is derived from Chromium's
|
||||
// base/macros.h.
|
||||
|
||||
// The arraysize(arr) macro returns the # of elements in an array arr.
|
||||
// The expression is a compile-time constant, and therefore can be
|
||||
// used in defining new arrays, for example. If you use arraysize on
|
||||
// a pointer by mistake, you will get a compile-time error.
|
||||
|
||||
// This template function declaration is used in defining arraysize.
|
||||
// Note that the function doesn't need an implementation, as we only
|
||||
// use its type.
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||
|
||||
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
||||
|
||||
#endif // RTC_BASE_ARRAYSIZE_H_
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "rtc_base/bitrate_tracker.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/rate_statistics.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
BitrateTracker::BitrateTracker(TimeDelta max_window_size)
|
||||
: impl_(max_window_size.ms(), RateStatistics::kBpsScale) {}
|
||||
|
||||
std::optional<DataRate> BitrateTracker::Rate(Timestamp now) const {
|
||||
if (std::optional<int64_t> rate = impl_.Rate(now.ms())) {
|
||||
return DataRate::BitsPerSec(*rate);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool BitrateTracker::SetWindowSize(TimeDelta window_size, Timestamp now) {
|
||||
return impl_.SetWindowSize(window_size.ms(), now.ms());
|
||||
}
|
||||
|
||||
void BitrateTracker::Update(int64_t bytes, Timestamp now) {
|
||||
impl_.Update(bytes, now.ms());
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 RTC_BASE_BITRATE_TRACKER_H_
|
||||
#define RTC_BASE_BITRATE_TRACKER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/rate_statistics.h"
|
||||
|
||||
namespace webrtc {
|
||||
// Class to estimate bitrates over running window.
|
||||
// Timestamps used in Update(), Rate() and SetWindowSize() must never
|
||||
// decrease for two consecutive calls.
|
||||
// This class is thread unsafe.
|
||||
class BitrateTracker {
|
||||
public:
|
||||
// max_window_sizes = Maximum window size for the rate estimation.
|
||||
// Initial window size is set to this, but may be changed
|
||||
// to something lower by calling SetWindowSize().
|
||||
explicit BitrateTracker(TimeDelta max_window_size);
|
||||
|
||||
BitrateTracker(const BitrateTracker&) = default;
|
||||
BitrateTracker(BitrateTracker&&) = default;
|
||||
BitrateTracker& operator=(const BitrateTracker&) = delete;
|
||||
BitrateTracker& operator=(BitrateTracker&&) = delete;
|
||||
|
||||
~BitrateTracker() = default;
|
||||
|
||||
// Resets instance to original state.
|
||||
void Reset() { impl_.Reset(); }
|
||||
|
||||
// Updates bitrate with a new data point, moving averaging window as needed.
|
||||
void Update(int64_t bytes, Timestamp now);
|
||||
void Update(DataSize size, Timestamp now) { Update(size.bytes(), now); }
|
||||
|
||||
// Returns bitrate, moving averaging window as needed.
|
||||
// Returns nullopt when bitrate can't be measured.
|
||||
std::optional<DataRate> Rate(Timestamp now) const;
|
||||
|
||||
// Update the size of the averaging window. The maximum allowed value for
|
||||
// `window_size` is `max_window_size` as supplied in the constructor.
|
||||
bool SetWindowSize(TimeDelta window_size, Timestamp now);
|
||||
|
||||
private:
|
||||
RateStatistics impl_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_BITRATE_TRACKER_H_
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004 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 RTC_BASE_BYTE_ORDER_H_
|
||||
#define RTC_BASE_BYTE_ORDER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#if defined(__POSIX__) && !defined(__native_client__)
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "rtc_base/system/arch.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
|
||||
#define htobe16(v) OSSwapHostToBigInt16(v)
|
||||
#define htobe32(v) OSSwapHostToBigInt32(v)
|
||||
#define htobe64(v) OSSwapHostToBigInt64(v)
|
||||
#define be16toh(v) OSSwapBigToHostInt16(v)
|
||||
#define be32toh(v) OSSwapBigToHostInt32(v)
|
||||
#define be64toh(v) OSSwapBigToHostInt64(v)
|
||||
|
||||
#define htole16(v) OSSwapHostToLittleInt16(v)
|
||||
#define htole32(v) OSSwapHostToLittleInt32(v)
|
||||
#define htole64(v) OSSwapHostToLittleInt64(v)
|
||||
#define le16toh(v) OSSwapLittleToHostInt16(v)
|
||||
#define le32toh(v) OSSwapLittleToHostInt32(v)
|
||||
#define le64toh(v) OSSwapLittleToHostInt64(v)
|
||||
|
||||
#elif defined(_WIN32) || defined(__native_client__)
|
||||
#if defined(_WIN32)
|
||||
#include <stdlib.h>
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h> // no-presubmit-check
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
|
||||
#define htobe16(v) htons(v)
|
||||
#define htobe32(v) htonl(v)
|
||||
#define be16toh(v) ntohs(v)
|
||||
#define be32toh(v) ntohl(v)
|
||||
#define htole16(v) (v)
|
||||
#define htole32(v) (v)
|
||||
#define htole64(v) (v)
|
||||
#define le16toh(v) (v)
|
||||
#define le32toh(v) (v)
|
||||
#define le64toh(v) (v)
|
||||
#if defined(_WIN32)
|
||||
#define htobe64(v) _byteswap_uint64(v)
|
||||
#define be64toh(v) _byteswap_uint64(v)
|
||||
#endif // defined(_WIN32)
|
||||
#if defined(__native_client__)
|
||||
#define htobe64(v) __builtin_bswap64(v)
|
||||
#define be64toh(v) __builtin_bswap64(v)
|
||||
#endif // defined(__native_client__)
|
||||
|
||||
#elif defined(WEBRTC_ARCH_BIG_ENDIAN)
|
||||
#define htobe16(v) (v)
|
||||
#define htobe32(v) (v)
|
||||
#define be16toh(v) (v)
|
||||
#define be32toh(v) (v)
|
||||
#define htole16(v) __builtin_bswap16(v)
|
||||
#define htole32(v) __builtin_bswap32(v)
|
||||
#define htole64(v) __builtin_bswap64(v)
|
||||
#define le16toh(v) __builtin_bswap16(v)
|
||||
#define le32toh(v) __builtin_bswap32(v)
|
||||
#define le64toh(v) __builtin_bswap64(v)
|
||||
#if defined(_WIN32)
|
||||
#define htobe64(v) (v)
|
||||
#define be64toh(v) (v)
|
||||
#endif // defined(_WIN32)
|
||||
#if defined(__native_client__)
|
||||
#define htobe64(v) (v)
|
||||
#define be64toh(v) (v)
|
||||
#endif // defined(__native_client__)
|
||||
#else
|
||||
#error WEBRTC_ARCH_BIG_ENDIAN or WEBRTC_ARCH_LITTLE_ENDIAN must be defined.
|
||||
#endif // defined(WEBRTC_ARCH_LITTLE_ENDIAN)
|
||||
|
||||
#elif defined(__POSIX__)
|
||||
#include <endian.h>
|
||||
#else
|
||||
#error "Missing byte order functions for this arch."
|
||||
#endif // defined(__APPLE__)
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Reading and writing of little and big-endian numbers from memory
|
||||
|
||||
inline void Set8(void* memory, size_t offset, uint8_t v) {
|
||||
static_cast<uint8_t*>(memory)[offset] = v;
|
||||
}
|
||||
|
||||
inline uint8_t Get8(const void* memory, size_t offset) {
|
||||
return static_cast<const uint8_t*>(memory)[offset];
|
||||
}
|
||||
|
||||
inline void SetBE16(void* memory, uint16_t v) {
|
||||
uint16_t val = htobe16(v);
|
||||
memcpy(memory, &val, sizeof(val));
|
||||
}
|
||||
|
||||
inline void SetBE32(void* memory, uint32_t v) {
|
||||
uint32_t val = htobe32(v);
|
||||
memcpy(memory, &val, sizeof(val));
|
||||
}
|
||||
|
||||
inline void SetBE64(void* memory, uint64_t v) {
|
||||
uint64_t val = htobe64(v);
|
||||
memcpy(memory, &val, sizeof(val));
|
||||
}
|
||||
|
||||
inline uint16_t GetBE16(const void* memory) {
|
||||
uint16_t val;
|
||||
memcpy(&val, memory, sizeof(val));
|
||||
return be16toh(val);
|
||||
}
|
||||
|
||||
inline uint32_t GetBE32(const void* memory) {
|
||||
uint32_t val;
|
||||
memcpy(&val, memory, sizeof(val));
|
||||
return be32toh(val);
|
||||
}
|
||||
|
||||
inline uint64_t GetBE64(const void* memory) {
|
||||
uint64_t val;
|
||||
memcpy(&val, memory, sizeof(val));
|
||||
return be64toh(val);
|
||||
}
|
||||
|
||||
inline void SetLE16(void* memory, uint16_t v) {
|
||||
uint16_t val = htole16(v);
|
||||
memcpy(memory, &val, sizeof(val));
|
||||
}
|
||||
|
||||
inline void SetLE32(void* memory, uint32_t v) {
|
||||
uint32_t val = htole32(v);
|
||||
memcpy(memory, &val, sizeof(val));
|
||||
}
|
||||
|
||||
inline void SetLE64(void* memory, uint64_t v) {
|
||||
uint64_t val = htole64(v);
|
||||
memcpy(memory, &val, sizeof(val));
|
||||
}
|
||||
|
||||
inline uint16_t GetLE16(const void* memory) {
|
||||
uint16_t val;
|
||||
memcpy(&val, memory, sizeof(val));
|
||||
return le16toh(val);
|
||||
}
|
||||
|
||||
inline uint32_t GetLE32(const void* memory) {
|
||||
uint32_t val;
|
||||
memcpy(&val, memory, sizeof(val));
|
||||
return le32toh(val);
|
||||
}
|
||||
|
||||
inline uint64_t GetLE64(const void* memory) {
|
||||
uint64_t val;
|
||||
memcpy(&val, memory, sizeof(val));
|
||||
return le64toh(val);
|
||||
}
|
||||
|
||||
// Check if the current host is big endian.
|
||||
inline bool IsHostBigEndian() {
|
||||
#if defined(WEBRTC_ARCH_BIG_ENDIAN)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint16_t HostToNetwork16(uint16_t n) { return htobe16(n); }
|
||||
|
||||
inline uint32_t HostToNetwork32(uint32_t n) { return htobe32(n); }
|
||||
|
||||
inline uint64_t HostToNetwork64(uint64_t n) { return htobe64(n); }
|
||||
|
||||
inline uint16_t NetworkToHost16(uint16_t n) { return be16toh(n); }
|
||||
|
||||
inline uint32_t NetworkToHost32(uint32_t n) { return be32toh(n); }
|
||||
|
||||
inline uint64_t NetworkToHost64(uint64_t n) { return be64toh(n); }
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_BYTE_ORDER_H_
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
|
||||
#define MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <typename U>
|
||||
inline bool IsNewer(U value, U prev_value) {
|
||||
static_assert(!std::numeric_limits<U>::is_signed, "U must be unsigned");
|
||||
// kBreakpoint is the half-way mark for the type U. For instance, for a
|
||||
// uint16_t it will be 0x8000, and for a uint32_t, it will be 0x8000000.
|
||||
constexpr U kBreakpoint = (std::numeric_limits<U>::max() >> 1) + 1;
|
||||
// Distinguish between elements that are exactly kBreakpoint apart.
|
||||
// If t1>t2 and |t1-t2| = kBreakpoint: IsNewer(t1,t2)=true,
|
||||
// IsNewer(t2,t1)=false
|
||||
// rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
|
||||
if (value - prev_value == kBreakpoint) {
|
||||
return value > prev_value;
|
||||
}
|
||||
return value != prev_value &&
|
||||
static_cast<U>(value - prev_value) < kBreakpoint;
|
||||
}
|
||||
|
||||
// NB: Doesn't fulfill strict weak ordering requirements.
|
||||
// Mustn't be used as std::map Compare function.
|
||||
inline bool IsNewerSequenceNumber(uint16_t sequence_number,
|
||||
uint16_t prev_sequence_number) {
|
||||
return IsNewer(sequence_number, prev_sequence_number);
|
||||
}
|
||||
|
||||
// NB: Doesn't fulfill strict weak ordering requirements.
|
||||
// Mustn't be used as std::map Compare function.
|
||||
inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
|
||||
return IsNewer(timestamp, prev_timestamp);
|
||||
}
|
||||
|
||||
inline uint16_t LatestSequenceNumber(uint16_t sequence_number1,
|
||||
uint16_t sequence_number2) {
|
||||
return IsNewerSequenceNumber(sequence_number1, sequence_number2)
|
||||
? sequence_number1
|
||||
: sequence_number2;
|
||||
}
|
||||
|
||||
inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
|
||||
return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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 "rtc_base/network/sent_packet.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
PacketInfo::PacketInfo() = default;
|
||||
PacketInfo::PacketInfo(const PacketInfo& info) = default;
|
||||
PacketInfo::~PacketInfo() = default;
|
||||
|
||||
SentPacket::SentPacket() = default;
|
||||
SentPacket::SentPacket(int64_t packet_id, int64_t send_time_ms)
|
||||
: packet_id(packet_id), send_time_ms(send_time_ms) {}
|
||||
SentPacket::SentPacket(int64_t packet_id,
|
||||
int64_t send_time_ms,
|
||||
const rtc::PacketInfo& info)
|
||||
: packet_id(packet_id), send_time_ms(send_time_ms), info(info) {}
|
||||
|
||||
} // namespace rtc
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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 RTC_BASE_NETWORK_SENT_PACKET_H_
|
||||
#define RTC_BASE_NETWORK_SENT_PACKET_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
enum class PacketType {
|
||||
kUnknown,
|
||||
kData,
|
||||
kIceConnectivityCheck,
|
||||
kIceConnectivityCheckResponse,
|
||||
kStunMessage,
|
||||
kTurnMessage,
|
||||
};
|
||||
|
||||
enum class PacketInfoProtocolType {
|
||||
kUnknown,
|
||||
kUdp,
|
||||
kTcp,
|
||||
kSsltcp,
|
||||
kTls,
|
||||
};
|
||||
|
||||
struct PacketInfo {
|
||||
PacketInfo();
|
||||
PacketInfo(const PacketInfo& info);
|
||||
~PacketInfo();
|
||||
|
||||
bool included_in_feedback = false;
|
||||
bool included_in_allocation = false;
|
||||
// `is_media` is true if this is an audio or video packet, excluding
|
||||
// retransmissions.
|
||||
bool is_media = false;
|
||||
PacketType packet_type = PacketType::kUnknown;
|
||||
PacketInfoProtocolType protocol = PacketInfoProtocolType::kUnknown;
|
||||
// A unique id assigned by the network manager, and std::nullopt if not set.
|
||||
std::optional<uint16_t> network_id;
|
||||
size_t packet_size_bytes = 0;
|
||||
size_t turn_overhead_bytes = 0;
|
||||
size_t ip_overhead_bytes = 0;
|
||||
};
|
||||
|
||||
struct SentPacket {
|
||||
SentPacket();
|
||||
SentPacket(int64_t packet_id, int64_t send_time_ms);
|
||||
SentPacket(int64_t packet_id, int64_t send_time_ms,
|
||||
const rtc::PacketInfo& info);
|
||||
|
||||
int64_t packet_id = -1;
|
||||
int64_t send_time_ms = -1;
|
||||
rtc::PacketInfo info;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NETWORK_SENT_PACKET_H_
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 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 "rtc_base/network_constants.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
std::string AdapterTypeToString(AdapterType type) {
|
||||
switch (type) {
|
||||
case ADAPTER_TYPE_ANY:
|
||||
return "Wildcard";
|
||||
case ADAPTER_TYPE_UNKNOWN:
|
||||
return "Unknown";
|
||||
case ADAPTER_TYPE_ETHERNET:
|
||||
return "Ethernet";
|
||||
case ADAPTER_TYPE_WIFI:
|
||||
return "Wifi";
|
||||
case ADAPTER_TYPE_CELLULAR:
|
||||
return "Cellular";
|
||||
case ADAPTER_TYPE_CELLULAR_2G:
|
||||
return "Cellular2G";
|
||||
case ADAPTER_TYPE_CELLULAR_3G:
|
||||
return "Cellular3G";
|
||||
case ADAPTER_TYPE_CELLULAR_4G:
|
||||
return "Cellular4G";
|
||||
case ADAPTER_TYPE_CELLULAR_5G:
|
||||
return "Cellular5G";
|
||||
case ADAPTER_TYPE_VPN:
|
||||
return "VPN";
|
||||
case ADAPTER_TYPE_LOOPBACK:
|
||||
return "Loopback";
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004 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 RTC_BASE_NETWORK_CONSTANTS_H_
|
||||
#define RTC_BASE_NETWORK_CONSTANTS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
constexpr uint16_t kNetworkCostMax = 999;
|
||||
constexpr uint16_t kNetworkCostCellular2G = 980;
|
||||
constexpr uint16_t kNetworkCostCellular3G = 910;
|
||||
constexpr uint16_t kNetworkCostCellular = 900;
|
||||
constexpr uint16_t kNetworkCostCellular4G = 500;
|
||||
constexpr uint16_t kNetworkCostCellular5G = 250;
|
||||
constexpr uint16_t kNetworkCostUnknown = 50;
|
||||
constexpr uint16_t kNetworkCostLow = 10;
|
||||
constexpr uint16_t kNetworkCostMin = 0;
|
||||
|
||||
// Add 1 to network cost of underlying network type
|
||||
// so that e.g a "plain" WIFI is prefered over a VPN over WIFI
|
||||
// everything else being equal.
|
||||
constexpr uint16_t kNetworkCostVpn = 1;
|
||||
|
||||
// alias
|
||||
constexpr uint16_t kNetworkCostHigh = kNetworkCostCellular;
|
||||
|
||||
enum AdapterType {
|
||||
// This enum resembles the one in Chromium net::ConnectionType.
|
||||
ADAPTER_TYPE_UNKNOWN = 0,
|
||||
ADAPTER_TYPE_ETHERNET = 1 << 0,
|
||||
ADAPTER_TYPE_WIFI = 1 << 1,
|
||||
ADAPTER_TYPE_CELLULAR = 1 << 2, // This is CELLULAR of unknown type.
|
||||
ADAPTER_TYPE_VPN = 1 << 3,
|
||||
ADAPTER_TYPE_LOOPBACK = 1 << 4,
|
||||
// ADAPTER_TYPE_ANY is used for a network, which only contains a single "any
|
||||
// address" IP address (INADDR_ANY for IPv4 or in6addr_any for IPv6), and can
|
||||
// use any/all network interfaces. Whereas ADAPTER_TYPE_UNKNOWN is used
|
||||
// when the network uses a specific interface/IP, but its interface type can
|
||||
// not be determined or not fit in this enum.
|
||||
ADAPTER_TYPE_ANY = 1 << 5,
|
||||
ADAPTER_TYPE_CELLULAR_2G = 1 << 6,
|
||||
ADAPTER_TYPE_CELLULAR_3G = 1 << 7,
|
||||
ADAPTER_TYPE_CELLULAR_4G = 1 << 8,
|
||||
ADAPTER_TYPE_CELLULAR_5G = 1 << 9
|
||||
};
|
||||
|
||||
std::string AdapterTypeToString(AdapterType type);
|
||||
|
||||
// Useful for testing!
|
||||
constexpr AdapterType kAllAdapterTypes[] = {
|
||||
ADAPTER_TYPE_UNKNOWN, ADAPTER_TYPE_ETHERNET,
|
||||
ADAPTER_TYPE_WIFI, ADAPTER_TYPE_CELLULAR,
|
||||
ADAPTER_TYPE_VPN, ADAPTER_TYPE_LOOPBACK,
|
||||
ADAPTER_TYPE_ANY, ADAPTER_TYPE_CELLULAR_2G,
|
||||
ADAPTER_TYPE_CELLULAR_3G, ADAPTER_TYPE_CELLULAR_4G,
|
||||
ADAPTER_TYPE_CELLULAR_5G,
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NETWORK_CONSTANTS_H_
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 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 "rtc_base/network_route.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
bool RouteEndpoint::operator==(const RouteEndpoint& other) const {
|
||||
return adapter_type_ == other.adapter_type_ &&
|
||||
adapter_id_ == other.adapter_id_ && network_id_ == other.network_id_ &&
|
||||
uses_turn_ == other.uses_turn_;
|
||||
}
|
||||
|
||||
bool NetworkRoute::operator==(const NetworkRoute& other) const {
|
||||
return connected == other.connected && local == other.local &&
|
||||
remote == other.remote && packet_overhead == other.packet_overhead &&
|
||||
last_sent_packet_id == other.last_sent_packet_id;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NETWORK_ROUTE_H_
|
||||
#define RTC_BASE_NETWORK_ROUTE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/network_constants.h"
|
||||
|
||||
// TODO(honghaiz): Make a directory that describes the interfaces and structs
|
||||
// the media code can rely on and the network code can implement, and both can
|
||||
// depend on that, but not depend on each other. Then, move this file to that
|
||||
// directory.
|
||||
namespace rtc {
|
||||
|
||||
class RouteEndpoint {
|
||||
public:
|
||||
RouteEndpoint() {} // Used by tests.
|
||||
RouteEndpoint(AdapterType adapter_type, uint16_t adapter_id,
|
||||
uint16_t network_id, bool uses_turn)
|
||||
: adapter_type_(adapter_type),
|
||||
adapter_id_(adapter_id),
|
||||
network_id_(network_id),
|
||||
uses_turn_(uses_turn) {}
|
||||
|
||||
RouteEndpoint(const RouteEndpoint&) = default;
|
||||
RouteEndpoint& operator=(const RouteEndpoint&) = default;
|
||||
|
||||
// Used by tests.
|
||||
static RouteEndpoint CreateWithNetworkId(uint16_t network_id) {
|
||||
return RouteEndpoint(ADAPTER_TYPE_UNKNOWN,
|
||||
/* adapter_id = */ 0, network_id,
|
||||
/* uses_turn = */ false);
|
||||
}
|
||||
RouteEndpoint CreateWithTurn(bool uses_turn) const {
|
||||
return RouteEndpoint(adapter_type_, adapter_id_, network_id_, uses_turn);
|
||||
}
|
||||
|
||||
AdapterType adapter_type() const { return adapter_type_; }
|
||||
uint16_t adapter_id() const { return adapter_id_; }
|
||||
uint16_t network_id() const { return network_id_; }
|
||||
bool uses_turn() const { return uses_turn_; }
|
||||
|
||||
bool operator==(const RouteEndpoint& other) const;
|
||||
|
||||
private:
|
||||
AdapterType adapter_type_ = ADAPTER_TYPE_UNKNOWN;
|
||||
uint16_t adapter_id_ = 0;
|
||||
uint16_t network_id_ = 0;
|
||||
bool uses_turn_ = false;
|
||||
};
|
||||
|
||||
struct NetworkRoute {
|
||||
bool connected = false;
|
||||
RouteEndpoint local;
|
||||
RouteEndpoint remote;
|
||||
// Last packet id sent on the PREVIOUS route.
|
||||
int last_sent_packet_id = -1;
|
||||
// The overhead in bytes from IP layer and above.
|
||||
// This is the maximum of any part of the route.
|
||||
int packet_overhead = 0;
|
||||
|
||||
std::string DebugString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "[ connected: " << connected << " local: [ " << local.adapter_id()
|
||||
<< "/" << local.network_id() << " "
|
||||
<< AdapterTypeToString(local.adapter_type())
|
||||
<< " turn: " << local.uses_turn() << " ] remote: [ "
|
||||
<< remote.adapter_id() << "/" << remote.network_id() << " "
|
||||
<< AdapterTypeToString(remote.adapter_type())
|
||||
<< " turn: " << remote.uses_turn()
|
||||
<< " ] packet_overhead_bytes: " << packet_overhead << " ]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
bool operator==(const NetworkRoute& other) const;
|
||||
bool operator!=(const NetworkRoute& other) { return !operator==(other); }
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NETWORK_ROUTE_H_
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_DIVIDE_ROUND_H_
|
||||
#define RTC_BASE_NUMERICS_DIVIDE_ROUND_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "safe_compare.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <typename Dividend, typename Divisor>
|
||||
inline auto constexpr DivideRoundUp(Dividend dividend, Divisor divisor) {
|
||||
static_assert(std::is_integral<Dividend>(), "");
|
||||
static_assert(std::is_integral<Divisor>(), "");
|
||||
|
||||
auto quotient = dividend / divisor;
|
||||
auto remainder = dividend % divisor;
|
||||
return quotient + (remainder > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
template <typename Dividend, typename Divisor>
|
||||
inline auto constexpr DivideRoundToNearest(Dividend dividend, Divisor divisor) {
|
||||
static_assert(std::is_integral<Dividend>(), "");
|
||||
static_assert(std::is_integral<Divisor>(), "");
|
||||
|
||||
if (dividend < Dividend{0}) {
|
||||
auto half_of_divisor = divisor / 2;
|
||||
auto quotient = dividend / divisor;
|
||||
auto remainder = dividend % divisor;
|
||||
if (rtc::SafeGt(-remainder, half_of_divisor)) {
|
||||
--quotient;
|
||||
}
|
||||
return quotient;
|
||||
}
|
||||
|
||||
auto half_of_divisor = (divisor - 1) / 2;
|
||||
auto quotient = dividend / divisor;
|
||||
auto remainder = dividend % divisor;
|
||||
if (rtc::SafeGt(remainder, half_of_divisor)) {
|
||||
++quotient;
|
||||
}
|
||||
return quotient;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_DIVIDE_ROUND_H_
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "event_based_exponential_moving_average.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace {
|
||||
|
||||
// For a normal distributed value, the 95% double sided confidence interval is
|
||||
// is 1.96 * stddev.
|
||||
constexpr double ninetyfive_percent_confidence = 1.96;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// `half_time` specifies how much weight will be given to old samples,
|
||||
// a sample gets exponentially less weight so that it's 50%
|
||||
// after `half_time` time units has passed.
|
||||
EventBasedExponentialMovingAverage::EventBasedExponentialMovingAverage(
|
||||
int half_time) {
|
||||
SetHalfTime(half_time);
|
||||
}
|
||||
|
||||
void EventBasedExponentialMovingAverage::SetHalfTime(int half_time) {
|
||||
tau_ = static_cast<double>(half_time) / log(2);
|
||||
Reset();
|
||||
}
|
||||
|
||||
void EventBasedExponentialMovingAverage::Reset() {
|
||||
value_ = std::nan("uninit");
|
||||
sample_variance_ = std::numeric_limits<double>::infinity();
|
||||
estimator_variance_ = 1;
|
||||
last_observation_timestamp_.reset();
|
||||
}
|
||||
|
||||
void EventBasedExponentialMovingAverage::AddSample(int64_t now, int sample) {
|
||||
if (!last_observation_timestamp_.has_value()) {
|
||||
value_ = sample;
|
||||
} else {
|
||||
// TODO(webrtc:11140): This should really be > (e.g not >=)
|
||||
// but some pesky tests run with simulated clock and let
|
||||
// samples arrive simultaneously!
|
||||
// Variance gets computed after second sample.
|
||||
int64_t age = now - *last_observation_timestamp_;
|
||||
double e = exp(-age / tau_);
|
||||
double alpha = e / (1 + e);
|
||||
double one_minus_alpha = 1 - alpha;
|
||||
double sample_diff = sample - value_;
|
||||
value_ = one_minus_alpha * value_ + alpha * sample;
|
||||
estimator_variance_ =
|
||||
(one_minus_alpha * one_minus_alpha) * estimator_variance_ +
|
||||
(alpha * alpha);
|
||||
if (sample_variance_ == std::numeric_limits<double>::infinity()) {
|
||||
// First variance.
|
||||
sample_variance_ = sample_diff * sample_diff;
|
||||
} else {
|
||||
double new_variance = one_minus_alpha * sample_variance_ +
|
||||
alpha * sample_diff * sample_diff;
|
||||
sample_variance_ = new_variance;
|
||||
}
|
||||
}
|
||||
last_observation_timestamp_ = now;
|
||||
}
|
||||
|
||||
double EventBasedExponentialMovingAverage::GetConfidenceInterval() const {
|
||||
return ninetyfive_percent_confidence *
|
||||
sqrt(sample_variance_ * estimator_variance_);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_
|
||||
#define RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
/**
|
||||
* This class implements exponential moving average for time series
|
||||
* estimating both value, variance and variance of estimator based on
|
||||
* https://en.wikipedia.org/w/index.php?title=Moving_average§ion=9#Application_to_measuring_computer_performance
|
||||
* with the additions from nisse@ added to
|
||||
* https://en.wikipedia.org/wiki/Talk:Moving_average.
|
||||
*
|
||||
* A sample gets exponentially less weight so that it's 50%
|
||||
* after `half_time` time units.
|
||||
*/
|
||||
class EventBasedExponentialMovingAverage {
|
||||
public:
|
||||
// `half_time` specifies how much weight will be given to old samples,
|
||||
// see example above.
|
||||
explicit EventBasedExponentialMovingAverage(int half_time);
|
||||
|
||||
void AddSample(int64_t now, int value);
|
||||
|
||||
double GetAverage() const { return value_; }
|
||||
double GetVariance() const { return sample_variance_; }
|
||||
|
||||
// Compute 95% confidence interval assuming that
|
||||
// - variance of samples are normal distributed.
|
||||
// - variance of estimator is normal distributed.
|
||||
//
|
||||
// The returned values specifies the distance from the average,
|
||||
// i.e if X = GetAverage(), m = GetConfidenceInterval()
|
||||
// then a there is 95% likelihood that the observed variables is inside
|
||||
// [ X +/- m ].
|
||||
double GetConfidenceInterval() const;
|
||||
|
||||
// Reset
|
||||
void Reset();
|
||||
|
||||
// Update the half_time.
|
||||
// NOTE: resets estimate too.
|
||||
void SetHalfTime(int half_time);
|
||||
|
||||
private:
|
||||
double tau_;
|
||||
double value_ = std::nan("uninit");
|
||||
double sample_variance_ = std::numeric_limits<double>::infinity();
|
||||
// This is the ratio between variance of the estimate and variance of samples.
|
||||
double estimator_variance_ = 1;
|
||||
std::optional<int64_t> last_observation_timestamp_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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 "exp_filter.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
const float ExpFilter::kValueUndefined = -1.0f;
|
||||
|
||||
void ExpFilter::Reset(float alpha) {
|
||||
alpha_ = alpha;
|
||||
filtered_ = kValueUndefined;
|
||||
}
|
||||
|
||||
float ExpFilter::Apply(float exp, float sample) {
|
||||
if (filtered_ == kValueUndefined) {
|
||||
// Initialize filtered value.
|
||||
filtered_ = sample;
|
||||
} else if (exp == 1.0) {
|
||||
filtered_ = alpha_ * filtered_ + (1 - alpha_) * sample;
|
||||
} else {
|
||||
float alpha = std::pow(alpha_, exp);
|
||||
filtered_ = alpha * filtered_ + (1 - alpha) * sample;
|
||||
}
|
||||
if (max_ != kValueUndefined && filtered_ > max_) {
|
||||
filtered_ = max_;
|
||||
}
|
||||
return filtered_;
|
||||
}
|
||||
|
||||
void ExpFilter::UpdateBase(float alpha) { alpha_ = alpha; }
|
||||
} // namespace rtc
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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 RTC_BASE_NUMERICS_EXP_FILTER_H_
|
||||
#define RTC_BASE_NUMERICS_EXP_FILTER_H_
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// This class can be used, for example, for smoothing the result of bandwidth
|
||||
// estimation and packet loss estimation.
|
||||
|
||||
class ExpFilter {
|
||||
public:
|
||||
static const float kValueUndefined;
|
||||
|
||||
explicit ExpFilter(float alpha, float max = kValueUndefined) : max_(max) {
|
||||
Reset(alpha);
|
||||
}
|
||||
|
||||
// Resets the filter to its initial state, and resets filter factor base to
|
||||
// the given value `alpha`.
|
||||
void Reset(float alpha);
|
||||
|
||||
// Applies the filter with a given exponent on the provided sample:
|
||||
// y(k) = min(alpha_^ exp * y(k-1) + (1 - alpha_^ exp) * sample, max_).
|
||||
float Apply(float exp, float sample);
|
||||
|
||||
// Returns current filtered value.
|
||||
float filtered() const { return filtered_; }
|
||||
|
||||
// Changes the filter factor base to the given value `alpha`.
|
||||
void UpdateBase(float alpha);
|
||||
|
||||
private:
|
||||
float alpha_; // Filter factor base.
|
||||
float filtered_; // Current filter output.
|
||||
const float max_;
|
||||
};
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_EXP_FILTER_H_
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "rtc_base/numerics/histogram_percentile_counter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace rtc {
|
||||
HistogramPercentileCounter::HistogramPercentileCounter(
|
||||
uint32_t long_tail_boundary)
|
||||
: histogram_low_(size_t{long_tail_boundary}),
|
||||
long_tail_boundary_(long_tail_boundary),
|
||||
total_elements_(0),
|
||||
total_elements_low_(0) {}
|
||||
|
||||
HistogramPercentileCounter::~HistogramPercentileCounter() = default;
|
||||
|
||||
void HistogramPercentileCounter::Add(const HistogramPercentileCounter& other) {
|
||||
for (uint32_t value = 0; value < other.long_tail_boundary_; ++value) {
|
||||
Add(value, other.histogram_low_[value]);
|
||||
}
|
||||
for (const auto& it : histogram_high_) {
|
||||
Add(it.first, it.second);
|
||||
}
|
||||
}
|
||||
|
||||
void HistogramPercentileCounter::Add(uint32_t value, size_t count) {
|
||||
if (value < long_tail_boundary_) {
|
||||
histogram_low_[value] += count;
|
||||
total_elements_low_ += count;
|
||||
} else {
|
||||
histogram_high_[value] += count;
|
||||
}
|
||||
total_elements_ += count;
|
||||
}
|
||||
|
||||
void HistogramPercentileCounter::Add(uint32_t value) { Add(value, 1); }
|
||||
|
||||
std::optional<uint32_t> HistogramPercentileCounter::GetPercentile(
|
||||
float fraction) {
|
||||
if (total_elements_ == 0) return std::nullopt;
|
||||
size_t elements_to_skip = static_cast<size_t>(
|
||||
std::max(0.0f, std::ceil(total_elements_ * fraction) - 1));
|
||||
if (elements_to_skip >= total_elements_)
|
||||
elements_to_skip = total_elements_ - 1;
|
||||
if (elements_to_skip < total_elements_low_) {
|
||||
for (uint32_t value = 0; value < long_tail_boundary_; ++value) {
|
||||
if (elements_to_skip < histogram_low_[value]) return value;
|
||||
elements_to_skip -= histogram_low_[value];
|
||||
}
|
||||
} else {
|
||||
elements_to_skip -= total_elements_low_;
|
||||
for (const auto& it : histogram_high_) {
|
||||
if (elements_to_skip < it.second) return it.first;
|
||||
elements_to_skip -= it.second;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_HISTOGRAM_PERCENTILE_COUNTER_H_
|
||||
#define RTC_BASE_NUMERICS_HISTOGRAM_PERCENTILE_COUNTER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace rtc {
|
||||
// Calculates percentiles on the stream of data. Use `Add` methods to add new
|
||||
// values. Use `GetPercentile` to get percentile of the currently added values.
|
||||
class HistogramPercentileCounter {
|
||||
public:
|
||||
// Values below `long_tail_boundary` are stored as the histogram in an array.
|
||||
// Values above - in a map.
|
||||
explicit HistogramPercentileCounter(uint32_t long_tail_boundary);
|
||||
~HistogramPercentileCounter();
|
||||
void Add(uint32_t value);
|
||||
void Add(uint32_t value, size_t count);
|
||||
void Add(const HistogramPercentileCounter& other);
|
||||
// Argument should be from 0 to 1.
|
||||
std::optional<uint32_t> GetPercentile(float fraction);
|
||||
|
||||
private:
|
||||
std::vector<size_t> histogram_low_;
|
||||
std::map<uint32_t, size_t> histogram_high_;
|
||||
const uint32_t long_tail_boundary_;
|
||||
size_t total_elements_;
|
||||
size_t total_elements_low_;
|
||||
};
|
||||
} // namespace rtc
|
||||
#endif // RTC_BASE_NUMERICS_HISTOGRAM_PERCENTILE_COUNTER_H_
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005 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 API_NUMERICS_MATH_UTILS_H_
|
||||
#define API_NUMERICS_MATH_UTILS_H_
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace webrtc {
|
||||
namespace webrtc_impl {
|
||||
// Given two numbers `x` and `y` such that x >= y, computes the difference
|
||||
// x - y without causing undefined behavior due to signed overflow.
|
||||
template <typename T>
|
||||
typename std::make_unsigned<T>::type unsigned_difference(T x, T y) {
|
||||
static_assert(
|
||||
std::is_signed<T>::value,
|
||||
"Function unsigned_difference is only meaningful for signed types.");
|
||||
typedef typename std::make_unsigned<T>::type unsigned_type;
|
||||
// int -> unsigned conversion repeatedly adds UINT_MAX + 1 until the number
|
||||
// can be represented as an unsigned. Since we know that the actual
|
||||
// difference x - y can be represented as an unsigned, it is sufficient to
|
||||
// compute the difference modulo UINT_MAX + 1, i.e using unsigned arithmetic.
|
||||
return static_cast<unsigned_type>(x) - static_cast<unsigned_type>(y);
|
||||
}
|
||||
|
||||
// Provide neutral element with respect to min().
|
||||
// Typically used as an initial value for running minimum.
|
||||
template <typename T,
|
||||
typename std::enable_if<std::numeric_limits<T>::has_infinity>::type* =
|
||||
nullptr>
|
||||
constexpr T infinity_or_max() {
|
||||
return std::numeric_limits<T>::infinity();
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<!std::numeric_limits<
|
||||
T>::has_infinity>::type* = nullptr>
|
||||
constexpr T infinity_or_max() {
|
||||
// Fallback to max().
|
||||
return std::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
// Provide neutral element with respect to max().
|
||||
// Typically used as an initial value for running maximum.
|
||||
template <typename T,
|
||||
typename std::enable_if<std::numeric_limits<T>::has_infinity>::type* =
|
||||
nullptr>
|
||||
constexpr T minus_infinity_or_min() {
|
||||
static_assert(std::is_signed<T>::value, "Unsupported. Please open a bug.");
|
||||
return -std::numeric_limits<T>::infinity();
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<!std::numeric_limits<
|
||||
T>::has_infinity>::type* = nullptr>
|
||||
constexpr T minus_infinity_or_min() {
|
||||
// Fallback to min().
|
||||
return std::numeric_limits<T>::min();
|
||||
}
|
||||
|
||||
} // namespace webrtc_impl
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_NUMERICS_MATH_UTILS_H_
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_MOD_OPS_H_
|
||||
#define RTC_BASE_NUMERICS_MOD_OPS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <unsigned long M> // NOLINT
|
||||
inline unsigned long Add(unsigned long a, unsigned long b) { // NOLINT
|
||||
unsigned long t = M - b % M; // NOLINT
|
||||
unsigned long res = a - t; // NOLINT
|
||||
if (t > a) return res + M;
|
||||
return res;
|
||||
}
|
||||
|
||||
template <unsigned long M> // NOLINT
|
||||
inline unsigned long Subtract(unsigned long a, unsigned long b) { // NOLINT
|
||||
unsigned long sub = b % M; // NOLINT
|
||||
if (a < sub) return M - (sub - a);
|
||||
return a - sub;
|
||||
}
|
||||
|
||||
// Calculates the forward difference between two wrapping numbers.
|
||||
//
|
||||
// Example:
|
||||
// uint8_t x = 253;
|
||||
// uint8_t y = 2;
|
||||
//
|
||||
// ForwardDiff(x, y) == 5
|
||||
//
|
||||
// 252 253 254 255 0 1 2 3
|
||||
// #################################################
|
||||
// | | x | | | | | y | |
|
||||
// #################################################
|
||||
// |----->----->----->----->----->
|
||||
//
|
||||
// ForwardDiff(y, x) == 251
|
||||
//
|
||||
// 252 253 254 255 0 1 2 3
|
||||
// #################################################
|
||||
// | | x | | | | | y | |
|
||||
// #################################################
|
||||
// -->-----> |----->---
|
||||
//
|
||||
// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the
|
||||
// largest value representable by T.
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M > 0), T>::type ForwardDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return a <= b ? b - a : M - (a - b);
|
||||
}
|
||||
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M == 0), T>::type ForwardDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return b - a;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ForwardDiff(T a, T b) {
|
||||
return ForwardDiff<T, 0>(a, b);
|
||||
}
|
||||
|
||||
// Calculates the reverse difference between two wrapping numbers.
|
||||
//
|
||||
// Example:
|
||||
// uint8_t x = 253;
|
||||
// uint8_t y = 2;
|
||||
//
|
||||
// ReverseDiff(y, x) == 5
|
||||
//
|
||||
// 252 253 254 255 0 1 2 3
|
||||
// #################################################
|
||||
// | | x | | | | | y | |
|
||||
// #################################################
|
||||
// <-----<-----<-----<-----<-----|
|
||||
//
|
||||
// ReverseDiff(x, y) == 251
|
||||
//
|
||||
// 252 253 254 255 0 1 2 3
|
||||
// #################################################
|
||||
// | | x | | | | | y | |
|
||||
// #################################################
|
||||
// ---<-----| |<-----<--
|
||||
//
|
||||
// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the
|
||||
// largest value representable by T.
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M > 0), T>::type ReverseDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return b <= a ? a - b : M - (b - a);
|
||||
}
|
||||
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M == 0), T>::type ReverseDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return a - b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ReverseDiff(T a, T b) {
|
||||
return ReverseDiff<T, 0>(a, b);
|
||||
}
|
||||
|
||||
// Calculates the minimum distance between to wrapping numbers.
|
||||
//
|
||||
// The minimum distance is defined as min(ForwardDiff(a, b), ReverseDiff(a, b))
|
||||
template <typename T, T M = 0>
|
||||
inline T MinDiff(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return std::min(ForwardDiff<T, M>(a, b), ReverseDiff<T, M>(a, b));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_MOD_OPS_H_
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_MOVING_MAX_COUNTER_H_
|
||||
#define RTC_BASE_NUMERICS_MOVING_MAX_COUNTER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <deque>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Implements moving max: can add samples to it and calculate maximum over some
|
||||
// fixed moving window.
|
||||
//
|
||||
// Window size is configured at constructor.
|
||||
// Samples can be added with `Add()` and max over current window is returned by
|
||||
// `MovingMax`. `current_time_ms` in successive calls to Add and MovingMax
|
||||
// should never decrease as if it's a wallclock time.
|
||||
template <class T>
|
||||
class MovingMaxCounter {
|
||||
public:
|
||||
explicit MovingMaxCounter(int64_t window_length_ms);
|
||||
|
||||
MovingMaxCounter(const MovingMaxCounter&) = delete;
|
||||
MovingMaxCounter& operator=(const MovingMaxCounter&) = delete;
|
||||
|
||||
// Advances the current time, and adds a new sample. The new current time must
|
||||
// be at least as large as the old current time.
|
||||
void Add(const T& sample, int64_t current_time_ms);
|
||||
// Advances the current time, and returns the maximum sample in the time
|
||||
// window ending at the current time. The new current time must be at least as
|
||||
// large as the old current time.
|
||||
std::optional<T> Max(int64_t current_time_ms);
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
// Throws out obsolete samples.
|
||||
void RollWindow(int64_t new_time_ms);
|
||||
const int64_t window_length_ms_;
|
||||
// This deque stores (timestamp, sample) pairs in chronological order; new
|
||||
// pairs are only ever added at the end. However, because they can't affect
|
||||
// the Max() calculation, pairs older than window_length_ms_ are discarded,
|
||||
// and if an older pair has a sample that's smaller than that of a younger
|
||||
// pair, the older pair is discarded. As a result, the sequence of timestamps
|
||||
// is strictly increasing, and the sequence of samples is strictly decreasing.
|
||||
std::deque<std::pair<int64_t, T>> samples_;
|
||||
#if RTC_DCHECK_IS_ON
|
||||
int64_t last_call_time_ms_ = std::numeric_limits<int64_t>::min();
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
MovingMaxCounter<T>::MovingMaxCounter(int64_t window_length_ms)
|
||||
: window_length_ms_(window_length_ms) {}
|
||||
|
||||
template <class T>
|
||||
void MovingMaxCounter<T>::Add(const T& sample, int64_t current_time_ms) {
|
||||
RollWindow(current_time_ms);
|
||||
// Remove samples that will never be maximum in any window: newly added sample
|
||||
// will always be in all windows the previous samples are. Thus, smaller or
|
||||
// equal samples could be removed. This will maintain the invariant - deque
|
||||
// contains strictly decreasing sequence of values.
|
||||
while (!samples_.empty() && samples_.back().second <= sample) {
|
||||
samples_.pop_back();
|
||||
}
|
||||
// Add the new sample but only if there's no existing sample at the same time.
|
||||
// Due to checks above, the already existing element will be larger, so the
|
||||
// new sample will never be the maximum in any window.
|
||||
if (samples_.empty() || samples_.back().first < current_time_ms) {
|
||||
samples_.emplace_back(std::make_pair(current_time_ms, sample));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::optional<T> MovingMaxCounter<T>::Max(int64_t current_time_ms) {
|
||||
RollWindow(current_time_ms);
|
||||
std::optional<T> res;
|
||||
if (!samples_.empty()) {
|
||||
res.emplace(samples_.front().second);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void MovingMaxCounter<T>::Reset() {
|
||||
samples_.clear();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void MovingMaxCounter<T>::RollWindow(int64_t new_time_ms) {
|
||||
#if RTC_DCHECK_IS_ON
|
||||
last_call_time_ms_ = new_time_ms;
|
||||
#endif
|
||||
const int64_t window_begin_ms = new_time_ms - window_length_ms_;
|
||||
auto it = samples_.begin();
|
||||
while (it != samples_.end() && it->first < window_begin_ms) {
|
||||
++it;
|
||||
}
|
||||
samples_.erase(samples_.begin(), it);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_MOVING_MAX_COUNTER_H_
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_MOVING_PERCENTILE_FILTER_H_
|
||||
#define RTC_BASE_NUMERICS_MOVING_PERCENTILE_FILTER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <list>
|
||||
|
||||
#include "percentile_filter.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Class to efficiently get moving percentile filter from a stream of samples.
|
||||
template <typename T>
|
||||
class MovingPercentileFilter {
|
||||
public:
|
||||
// Construct filter. `percentile` defines what percentile to track and
|
||||
// `window_size` is how many latest samples are stored for finding the
|
||||
// percentile. `percentile` must be between 0.0 and 1.0 (inclusive) and
|
||||
// `window_size` must be greater than 0.
|
||||
MovingPercentileFilter(float percentile, size_t window_size);
|
||||
|
||||
MovingPercentileFilter(const MovingPercentileFilter&) = delete;
|
||||
MovingPercentileFilter& operator=(const MovingPercentileFilter&) = delete;
|
||||
|
||||
// Insert a new sample.
|
||||
void Insert(const T& value);
|
||||
|
||||
// Removes all samples;
|
||||
void Reset();
|
||||
|
||||
// Get percentile over the latest window.
|
||||
T GetFilteredValue() const;
|
||||
|
||||
// The number of samples that are currently stored.
|
||||
size_t GetNumberOfSamplesStored() const;
|
||||
|
||||
private:
|
||||
PercentileFilter<T> percentile_filter_;
|
||||
std::list<T> samples_;
|
||||
size_t samples_stored_;
|
||||
const size_t window_size_;
|
||||
};
|
||||
|
||||
// Convenience type for the common median case.
|
||||
template <typename T>
|
||||
class MovingMedianFilter : public MovingPercentileFilter<T> {
|
||||
public:
|
||||
explicit MovingMedianFilter(size_t window_size)
|
||||
: MovingPercentileFilter<T>(0.5f, window_size) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
MovingPercentileFilter<T>::MovingPercentileFilter(float percentile,
|
||||
size_t window_size)
|
||||
: percentile_filter_(percentile),
|
||||
samples_stored_(0),
|
||||
window_size_(window_size) {}
|
||||
|
||||
template <typename T>
|
||||
void MovingPercentileFilter<T>::Insert(const T& value) {
|
||||
percentile_filter_.Insert(value);
|
||||
samples_.emplace_back(value);
|
||||
++samples_stored_;
|
||||
if (samples_stored_ > window_size_) {
|
||||
percentile_filter_.Erase(samples_.front());
|
||||
samples_.pop_front();
|
||||
--samples_stored_;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T MovingPercentileFilter<T>::GetFilteredValue() const {
|
||||
return percentile_filter_.GetPercentileValue();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MovingPercentileFilter<T>::Reset() {
|
||||
percentile_filter_.Reset();
|
||||
samples_.clear();
|
||||
samples_stored_ = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t MovingPercentileFilter<T>::GetNumberOfSamplesStored() const {
|
||||
return samples_stored_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // RTC_BASE_NUMERICS_MOVING_PERCENTILE_FILTER_H_
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_PERCENTILE_FILTER_H_
|
||||
#define RTC_BASE_NUMERICS_PERCENTILE_FILTER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Class to efficiently get the percentile value from a group of observations.
|
||||
// The percentile is the value below which a given percentage of the
|
||||
// observations fall.
|
||||
template <typename T>
|
||||
class PercentileFilter {
|
||||
public:
|
||||
// Construct filter. `percentile` should be between 0 and 1.
|
||||
explicit PercentileFilter(float percentile);
|
||||
|
||||
// Insert one observation. The complexity of this operation is logarithmic in
|
||||
// the size of the container.
|
||||
void Insert(const T& value);
|
||||
|
||||
// Remove one observation or return false if `value` doesn't exist in the
|
||||
// container. The complexity of this operation is logarithmic in the size of
|
||||
// the container.
|
||||
bool Erase(const T& value);
|
||||
|
||||
// Get the percentile value. The complexity of this operation is constant.
|
||||
T GetPercentileValue() const;
|
||||
|
||||
// Removes all the stored observations.
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
// Update iterator and index to point at target percentile value.
|
||||
void UpdatePercentileIterator();
|
||||
|
||||
const float percentile_;
|
||||
std::multiset<T> set_;
|
||||
// Maintain iterator and index of current target percentile value.
|
||||
typename std::multiset<T>::iterator percentile_it_;
|
||||
int64_t percentile_index_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
PercentileFilter<T>::PercentileFilter(float percentile)
|
||||
: percentile_(percentile),
|
||||
percentile_it_(set_.begin()),
|
||||
percentile_index_(0) {}
|
||||
|
||||
template <typename T>
|
||||
void PercentileFilter<T>::Insert(const T& value) {
|
||||
// Insert element at the upper bound.
|
||||
set_.insert(value);
|
||||
if (set_.size() == 1u) {
|
||||
// First element inserted - initialize percentile iterator and index.
|
||||
percentile_it_ = set_.begin();
|
||||
percentile_index_ = 0;
|
||||
} else if (value < *percentile_it_) {
|
||||
// If new element is before us, increment `percentile_index_`.
|
||||
++percentile_index_;
|
||||
}
|
||||
UpdatePercentileIterator();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool PercentileFilter<T>::Erase(const T& value) {
|
||||
typename std::multiset<T>::const_iterator it = set_.lower_bound(value);
|
||||
// Ignore erase operation if the element is not present in the current set.
|
||||
if (it == set_.end() || *it != value) return false;
|
||||
if (it == percentile_it_) {
|
||||
// If same iterator, update to the following element. Index is not
|
||||
// affected.
|
||||
percentile_it_ = set_.erase(it);
|
||||
} else {
|
||||
set_.erase(it);
|
||||
// If erased element was before us, decrement `percentile_index_`.
|
||||
if (value <= *percentile_it_) --percentile_index_;
|
||||
}
|
||||
UpdatePercentileIterator();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void PercentileFilter<T>::UpdatePercentileIterator() {
|
||||
if (set_.empty()) return;
|
||||
const int64_t index = static_cast<int64_t>(percentile_ * (set_.size() - 1));
|
||||
std::advance(percentile_it_, index - percentile_index_);
|
||||
percentile_index_ = index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T PercentileFilter<T>::GetPercentileValue() const {
|
||||
return set_.empty() ? T() : *percentile_it_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void PercentileFilter<T>::Reset() {
|
||||
set_.clear();
|
||||
percentile_it_ = set_.begin();
|
||||
percentile_index_ = 0;
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_PERCENTILE_FILTER_H_
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 RTC_BASE_NUMERICS_RATIONAL_H_
|
||||
#define RTC_BASE_NUMERICS_RATIONAL_H_
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// This is the worst implementation of a rational...
|
||||
struct Rational {
|
||||
int numerator;
|
||||
int denominator;
|
||||
|
||||
bool operator==(const Rational& other) const {
|
||||
return numerator == other.numerator && denominator == other.denominator;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_RATIONAL_H_
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef API_NUMERICS_RUNNING_STATISTICS_H_
|
||||
#define API_NUMERICS_RUNNING_STATISTICS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include "rtc_base/numerics/math_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace webrtc_impl {
|
||||
|
||||
// tl;dr: Robust and efficient online computation of statistics,
|
||||
// using Welford's method for variance. [1]
|
||||
//
|
||||
// This should be your go-to class if you ever need to compute
|
||||
// min, max, mean, variance and standard deviation.
|
||||
// If you need to get percentiles, please use webrtc::SamplesStatsCounter.
|
||||
//
|
||||
// Please note RemoveSample() won't affect min and max.
|
||||
// If you want a full-fledged moving window over N last samples,
|
||||
// please use webrtc::RollingAccumulator.
|
||||
//
|
||||
// The measures return std::nullopt if no samples were fed (Size() == 0),
|
||||
// otherwise the returned optional is guaranteed to contain a value.
|
||||
//
|
||||
// [1]
|
||||
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
|
||||
|
||||
// The type T is a scalar which must be convertible to double.
|
||||
// Rationale: we often need greater precision for measures
|
||||
// than for the samples themselves.
|
||||
template <typename T>
|
||||
class RunningStatistics {
|
||||
public:
|
||||
// Update stats ////////////////////////////////////////////
|
||||
|
||||
// Add a value participating in the statistics in O(1) time.
|
||||
void AddSample(T sample) {
|
||||
max_ = std::max(max_, sample);
|
||||
min_ = std::min(min_, sample);
|
||||
sum_ += sample;
|
||||
++size_;
|
||||
// Welford's incremental update.
|
||||
const double delta = sample - mean_;
|
||||
mean_ += delta / size_;
|
||||
const double delta2 = sample - mean_;
|
||||
cumul_ += delta * delta2;
|
||||
}
|
||||
|
||||
// Remove a previously added value in O(1) time.
|
||||
// Nb: This doesn't affect min or max.
|
||||
// Calling RemoveSample when Size()==0 is incorrect.
|
||||
void RemoveSample(T sample) {
|
||||
// In production, just saturate at 0.
|
||||
if (Size() == 0) {
|
||||
return;
|
||||
}
|
||||
// Since samples order doesn't matter, this is the
|
||||
// exact reciprocal of Welford's incremental update.
|
||||
--size_;
|
||||
const double delta = sample - mean_;
|
||||
mean_ -= delta / size_;
|
||||
const double delta2 = sample - mean_;
|
||||
cumul_ -= delta * delta2;
|
||||
}
|
||||
|
||||
// Merge other stats, as if samples were added one by one, but in O(1).
|
||||
void MergeStatistics(const RunningStatistics<T>& other) {
|
||||
if (other.size_ == 0) {
|
||||
return;
|
||||
}
|
||||
max_ = std::max(max_, other.max_);
|
||||
min_ = std::min(min_, other.min_);
|
||||
const int64_t new_size = size_ + other.size_;
|
||||
const double new_mean =
|
||||
(mean_ * size_ + other.mean_ * other.size_) / new_size;
|
||||
// Each cumulant must be corrected.
|
||||
// * from: sum((x_i - mean_)²)
|
||||
// * to: sum((x_i - new_mean)²)
|
||||
auto delta = [new_mean](const RunningStatistics<T>& stats) {
|
||||
return stats.size_ * (new_mean * (new_mean - 2 * stats.mean_) +
|
||||
stats.mean_ * stats.mean_);
|
||||
};
|
||||
cumul_ = cumul_ + delta(*this) + other.cumul_ + delta(other);
|
||||
mean_ = new_mean;
|
||||
size_ = new_size;
|
||||
}
|
||||
|
||||
// Get Measures ////////////////////////////////////////////
|
||||
|
||||
// Returns number of samples involved via AddSample() or MergeStatistics(),
|
||||
// minus number of times RemoveSample() was called.
|
||||
int64_t Size() const { return size_; }
|
||||
|
||||
// Returns minimum among all seen samples, in O(1) time.
|
||||
// This isn't affected by RemoveSample().
|
||||
std::optional<T> GetMin() const {
|
||||
if (size_ == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return min_;
|
||||
}
|
||||
|
||||
// Returns maximum among all seen samples, in O(1) time.
|
||||
// This isn't affected by RemoveSample().
|
||||
std::optional<T> GetMax() const {
|
||||
if (size_ == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return max_;
|
||||
}
|
||||
|
||||
// Returns sum in O(1) time.
|
||||
std::optional<double> GetSum() const {
|
||||
if (size_ == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return sum_;
|
||||
}
|
||||
|
||||
// Returns mean in O(1) time.
|
||||
std::optional<double> GetMean() const {
|
||||
if (size_ == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return mean_;
|
||||
}
|
||||
|
||||
// Returns unbiased sample variance in O(1) time.
|
||||
std::optional<double> GetVariance() const {
|
||||
if (size_ == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return cumul_ / size_;
|
||||
}
|
||||
|
||||
// Returns unbiased standard deviation in O(1) time.
|
||||
std::optional<double> GetStandardDeviation() const {
|
||||
if (size_ == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::sqrt(*GetVariance());
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t size_ = 0; // Samples seen.
|
||||
T min_ = infinity_or_max<T>();
|
||||
T max_ = minus_infinity_or_min<T>();
|
||||
double mean_ = 0;
|
||||
double cumul_ = 0; // Variance * size_, sometimes noted m2.
|
||||
double sum_ = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc_impl
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_NUMERICS_RUNNING_STATISTICS_H_
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
// This file defines six constexpr functions:
|
||||
//
|
||||
// rtc::SafeEq // ==
|
||||
// rtc::SafeNe // !=
|
||||
// rtc::SafeLt // <
|
||||
// rtc::SafeLe // <=
|
||||
// rtc::SafeGt // >
|
||||
// rtc::SafeGe // >=
|
||||
//
|
||||
// They each accept two arguments of arbitrary types, and in almost all cases,
|
||||
// they simply call the appropriate comparison operator. However, if both
|
||||
// arguments are integers, they don't compare them using C++'s quirky rules,
|
||||
// but instead adhere to the true mathematical definitions. It is as if the
|
||||
// arguments were first converted to infinite-range signed integers, and then
|
||||
// compared, although of course nothing expensive like that actually takes
|
||||
// place. In practice, for signed/signed and unsigned/unsigned comparisons and
|
||||
// some mixed-signed comparisons with a compile-time constant, the overhead is
|
||||
// zero; in the remaining cases, it is just a few machine instructions (no
|
||||
// branches).
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_SAFE_COMPARE_H_
|
||||
#define RTC_BASE_NUMERICS_SAFE_COMPARE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "rtc_base/type_traits.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
namespace safe_cmp_impl {
|
||||
|
||||
template <size_t N>
|
||||
struct LargerIntImpl : std::false_type {};
|
||||
template <>
|
||||
struct LargerIntImpl<sizeof(int8_t)> : std::true_type {
|
||||
using type = int16_t;
|
||||
};
|
||||
template <>
|
||||
struct LargerIntImpl<sizeof(int16_t)> : std::true_type {
|
||||
using type = int32_t;
|
||||
};
|
||||
template <>
|
||||
struct LargerIntImpl<sizeof(int32_t)> : std::true_type {
|
||||
using type = int64_t;
|
||||
};
|
||||
|
||||
// LargerInt<T1, T2>::value is true iff there's a signed type that's larger
|
||||
// than T1 (and no larger than the larger of T2 and int*, for performance
|
||||
// reasons); and if there is such a type, LargerInt<T1, T2>::type is an alias
|
||||
// for it.
|
||||
template <typename T1, typename T2>
|
||||
struct LargerInt
|
||||
: LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*)
|
||||
? sizeof(T1)
|
||||
: 0> {};
|
||||
|
||||
template <typename T>
|
||||
constexpr typename std::make_unsigned<T>::type MakeUnsigned(T a) {
|
||||
return static_cast<typename std::make_unsigned<T>::type>(a);
|
||||
}
|
||||
|
||||
// Overload for when both T1 and T2 have the same signedness.
|
||||
template <typename Op, typename T1, typename T2,
|
||||
typename std::enable_if<std::is_signed<T1>::value ==
|
||||
std::is_signed<T2>::value>::type* = nullptr>
|
||||
constexpr bool Cmp(T1 a, T2 b) {
|
||||
return Op::Op(a, b);
|
||||
}
|
||||
|
||||
// Overload for signed - unsigned comparison that can be promoted to a bigger
|
||||
// signed type.
|
||||
template <typename Op, typename T1, typename T2,
|
||||
typename std::enable_if<std::is_signed<T1>::value &&
|
||||
std::is_unsigned<T2>::value &&
|
||||
LargerInt<T2, T1>::value>::type* = nullptr>
|
||||
constexpr bool Cmp(T1 a, T2 b) {
|
||||
return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b));
|
||||
}
|
||||
|
||||
// Overload for unsigned - signed comparison that can be promoted to a bigger
|
||||
// signed type.
|
||||
template <typename Op, typename T1, typename T2,
|
||||
typename std::enable_if<std::is_unsigned<T1>::value &&
|
||||
std::is_signed<T2>::value &&
|
||||
LargerInt<T1, T2>::value>::type* = nullptr>
|
||||
constexpr bool Cmp(T1 a, T2 b) {
|
||||
return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b);
|
||||
}
|
||||
|
||||
// Overload for signed - unsigned comparison that can't be promoted to a bigger
|
||||
// signed type.
|
||||
template <typename Op, typename T1, typename T2,
|
||||
typename std::enable_if<std::is_signed<T1>::value &&
|
||||
std::is_unsigned<T2>::value &&
|
||||
!LargerInt<T2, T1>::value>::type* = nullptr>
|
||||
constexpr bool Cmp(T1 a, T2 b) {
|
||||
return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b);
|
||||
}
|
||||
|
||||
// Overload for unsigned - signed comparison that can't be promoted to a bigger
|
||||
// signed type.
|
||||
template <typename Op, typename T1, typename T2,
|
||||
typename std::enable_if<std::is_unsigned<T1>::value &&
|
||||
std::is_signed<T2>::value &&
|
||||
!LargerInt<T1, T2>::value>::type* = nullptr>
|
||||
constexpr bool Cmp(T1 a, T2 b) {
|
||||
return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b));
|
||||
}
|
||||
|
||||
#define RTC_SAFECMP_MAKE_OP(name, op) \
|
||||
struct name { \
|
||||
template <typename T1, typename T2> \
|
||||
static constexpr bool Op(T1 a, T2 b) { \
|
||||
return a op b; \
|
||||
} \
|
||||
};
|
||||
RTC_SAFECMP_MAKE_OP(EqOp, ==)
|
||||
RTC_SAFECMP_MAKE_OP(NeOp, !=)
|
||||
RTC_SAFECMP_MAKE_OP(LtOp, <)
|
||||
RTC_SAFECMP_MAKE_OP(LeOp, <=)
|
||||
RTC_SAFECMP_MAKE_OP(GtOp, >)
|
||||
RTC_SAFECMP_MAKE_OP(GeOp, >=)
|
||||
#undef RTC_SAFECMP_MAKE_OP
|
||||
|
||||
} // namespace safe_cmp_impl
|
||||
|
||||
#define RTC_SAFECMP_MAKE_FUN(name) \
|
||||
template <typename T1, typename T2> \
|
||||
constexpr \
|
||||
typename std::enable_if<IsIntlike<T1>::value && IsIntlike<T2>::value, \
|
||||
bool>::type Safe##name(T1 a, T2 b) { \
|
||||
/* Unary plus here turns enums into real integral types. */ \
|
||||
return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b); \
|
||||
} \
|
||||
template <typename T1, typename T2> \
|
||||
constexpr \
|
||||
typename std::enable_if<!IsIntlike<T1>::value || !IsIntlike<T2>::value, \
|
||||
bool>::type Safe##name(const T1& a, \
|
||||
const T2& b) { \
|
||||
return safe_cmp_impl::name##Op::Op(a, b); \
|
||||
}
|
||||
RTC_SAFECMP_MAKE_FUN(Eq)
|
||||
RTC_SAFECMP_MAKE_FUN(Ne)
|
||||
RTC_SAFECMP_MAKE_FUN(Lt)
|
||||
RTC_SAFECMP_MAKE_FUN(Le)
|
||||
RTC_SAFECMP_MAKE_FUN(Gt)
|
||||
RTC_SAFECMP_MAKE_FUN(Ge)
|
||||
#undef RTC_SAFECMP_MAKE_FUN
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_SAFE_COMPARE_H_
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
// Borrowed from Chromium's src/base/numerics/safe_conversions.h.
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
|
||||
#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "rtc_base/numerics/safe_conversions_impl.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Convenience function that returns true if the supplied value is in range
|
||||
// for the destination type.
|
||||
template <typename Dst, typename Src>
|
||||
inline constexpr bool IsValueInRangeForNumericType(Src value) {
|
||||
return internal::RangeCheck<Dst>(value) == internal::TYPE_VALID;
|
||||
}
|
||||
|
||||
// checked_cast<> and dchecked_cast<> are analogous to static_cast<> for
|
||||
// numeric types, except that they [D]CHECK that the specified numeric
|
||||
// conversion will not overflow or underflow. NaN source will always trigger
|
||||
// the [D]CHECK.
|
||||
template <typename Dst, typename Src>
|
||||
inline constexpr Dst checked_cast(Src value) {
|
||||
return static_cast<Dst>(value);
|
||||
}
|
||||
template <typename Dst, typename Src>
|
||||
inline constexpr Dst dchecked_cast(Src value) {
|
||||
return static_cast<Dst>(value);
|
||||
}
|
||||
|
||||
// saturated_cast<> is analogous to static_cast<> for numeric types, except
|
||||
// that the specified numeric conversion will saturate rather than overflow or
|
||||
// underflow. NaN assignment to an integral will trigger a RTC_CHECK condition.
|
||||
template <typename Dst, typename Src>
|
||||
inline constexpr Dst saturated_cast(Src value) {
|
||||
// Optimization for floating point values, which already saturate.
|
||||
if (std::numeric_limits<Dst>::is_iec559) return static_cast<Dst>(value);
|
||||
|
||||
switch (internal::RangeCheck<Dst>(value)) {
|
||||
case internal::TYPE_VALID:
|
||||
return static_cast<Dst>(value);
|
||||
|
||||
case internal::TYPE_UNDERFLOW:
|
||||
return std::numeric_limits<Dst>::min();
|
||||
|
||||
case internal::TYPE_OVERFLOW:
|
||||
return std::numeric_limits<Dst>::max();
|
||||
|
||||
// Should fail only on attempting to assign NaN to a saturated integer.
|
||||
case internal::TYPE_INVALID:
|
||||
return static_cast<Dst>(value);
|
||||
}
|
||||
|
||||
return static_cast<Dst>(value);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
// Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h.
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
|
||||
#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
namespace rtc {
|
||||
namespace internal {
|
||||
|
||||
enum DstSign { DST_UNSIGNED, DST_SIGNED };
|
||||
|
||||
enum SrcSign { SRC_UNSIGNED, SRC_SIGNED };
|
||||
|
||||
enum DstRange { OVERLAPS_RANGE, CONTAINS_RANGE };
|
||||
|
||||
// Helper templates to statically determine if our destination type can contain
|
||||
// all values represented by the source type.
|
||||
|
||||
template <typename Dst, typename Src,
|
||||
DstSign IsDstSigned =
|
||||
std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED,
|
||||
SrcSign IsSrcSigned =
|
||||
std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED>
|
||||
struct StaticRangeCheck {};
|
||||
|
||||
template <typename Dst, typename Src>
|
||||
struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_SIGNED> {
|
||||
typedef std::numeric_limits<Dst> DstLimits;
|
||||
typedef std::numeric_limits<Src> SrcLimits;
|
||||
// Compare based on max_exponent, which we must compute for integrals.
|
||||
static const size_t kDstMaxExponent =
|
||||
DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1);
|
||||
static const size_t kSrcMaxExponent =
|
||||
SrcLimits::is_iec559 ? SrcLimits::max_exponent : (sizeof(Src) * 8 - 1);
|
||||
static const DstRange value =
|
||||
kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE;
|
||||
};
|
||||
|
||||
template <typename Dst, typename Src>
|
||||
struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED> {
|
||||
static const DstRange value =
|
||||
sizeof(Dst) >= sizeof(Src) ? CONTAINS_RANGE : OVERLAPS_RANGE;
|
||||
};
|
||||
|
||||
template <typename Dst, typename Src>
|
||||
struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_UNSIGNED> {
|
||||
typedef std::numeric_limits<Dst> DstLimits;
|
||||
typedef std::numeric_limits<Src> SrcLimits;
|
||||
// Compare based on max_exponent, which we must compute for integrals.
|
||||
static const size_t kDstMaxExponent =
|
||||
DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1);
|
||||
static const size_t kSrcMaxExponent = sizeof(Src) * 8;
|
||||
static const DstRange value =
|
||||
kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE;
|
||||
};
|
||||
|
||||
template <typename Dst, typename Src>
|
||||
struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_SIGNED> {
|
||||
static const DstRange value = OVERLAPS_RANGE;
|
||||
};
|
||||
|
||||
enum RangeCheckResult {
|
||||
TYPE_VALID = 0, // Value can be represented by the destination type.
|
||||
TYPE_UNDERFLOW = 1, // Value would overflow.
|
||||
TYPE_OVERFLOW = 2, // Value would underflow.
|
||||
TYPE_INVALID = 3 // Source value is invalid (i.e. NaN).
|
||||
};
|
||||
|
||||
// This macro creates a RangeCheckResult from an upper and lower bound
|
||||
// check by taking advantage of the fact that only NaN can be out of range in
|
||||
// both directions at once.
|
||||
#define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \
|
||||
RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \
|
||||
((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW))
|
||||
|
||||
template <typename Dst, typename Src,
|
||||
DstSign IsDstSigned =
|
||||
std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED,
|
||||
SrcSign IsSrcSigned =
|
||||
std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED,
|
||||
DstRange IsSrcRangeContained = StaticRangeCheck<Dst, Src>::value>
|
||||
struct RangeCheckImpl {};
|
||||
|
||||
// The following templates are for ranges that must be verified at runtime. We
|
||||
// split it into checks based on signedness to avoid confusing casts and
|
||||
// compiler warnings on signed an unsigned comparisons.
|
||||
|
||||
// Dst range always contains the result: nothing to check.
|
||||
template <typename Dst, typename Src, DstSign IsDstSigned, SrcSign IsSrcSigned>
|
||||
struct RangeCheckImpl<Dst, Src, IsDstSigned, IsSrcSigned, CONTAINS_RANGE> {
|
||||
static constexpr RangeCheckResult Check(Src /* value */) {
|
||||
return TYPE_VALID;
|
||||
}
|
||||
};
|
||||
|
||||
// Signed to signed narrowing.
|
||||
template <typename Dst, typename Src>
|
||||
struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
|
||||
static constexpr RangeCheckResult Check(Src value) {
|
||||
typedef std::numeric_limits<Dst> DstLimits;
|
||||
return DstLimits::is_iec559
|
||||
? BASE_NUMERIC_RANGE_CHECK_RESULT(
|
||||
value <= static_cast<Src>(DstLimits::max()),
|
||||
value >= static_cast<Src>(DstLimits::max() * -1))
|
||||
: BASE_NUMERIC_RANGE_CHECK_RESULT(
|
||||
value <= static_cast<Src>(DstLimits::max()),
|
||||
value >= static_cast<Src>(DstLimits::min()));
|
||||
}
|
||||
};
|
||||
|
||||
// Unsigned to unsigned narrowing.
|
||||
template <typename Dst, typename Src>
|
||||
struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
|
||||
static constexpr RangeCheckResult Check(Src value) {
|
||||
typedef std::numeric_limits<Dst> DstLimits;
|
||||
return BASE_NUMERIC_RANGE_CHECK_RESULT(
|
||||
value <= static_cast<Src>(DstLimits::max()), true);
|
||||
}
|
||||
};
|
||||
|
||||
// Unsigned to signed.
|
||||
template <typename Dst, typename Src>
|
||||
struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
|
||||
static constexpr RangeCheckResult Check(Src value) {
|
||||
typedef std::numeric_limits<Dst> DstLimits;
|
||||
return sizeof(Dst) > sizeof(Src)
|
||||
? TYPE_VALID
|
||||
: BASE_NUMERIC_RANGE_CHECK_RESULT(
|
||||
value <= static_cast<Src>(DstLimits::max()), true);
|
||||
}
|
||||
};
|
||||
|
||||
// Signed to unsigned.
|
||||
template <typename Dst, typename Src>
|
||||
struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
|
||||
typedef std::numeric_limits<Dst> DstLimits;
|
||||
typedef std::numeric_limits<Src> SrcLimits;
|
||||
// Compare based on max_exponent, which we must compute for integrals.
|
||||
static constexpr size_t DstMaxExponent() { return sizeof(Dst) * 8; }
|
||||
static constexpr size_t SrcMaxExponent() {
|
||||
return SrcLimits::is_iec559 ? SrcLimits::max_exponent
|
||||
: (sizeof(Src) * 8 - 1);
|
||||
}
|
||||
static constexpr RangeCheckResult Check(Src value) {
|
||||
return (DstMaxExponent() >= SrcMaxExponent())
|
||||
? BASE_NUMERIC_RANGE_CHECK_RESULT(true,
|
||||
value >= static_cast<Src>(0))
|
||||
: BASE_NUMERIC_RANGE_CHECK_RESULT(
|
||||
value <= static_cast<Src>(DstLimits::max()),
|
||||
value >= static_cast<Src>(0));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Dst, typename Src>
|
||||
inline constexpr RangeCheckResult RangeCheck(Src value) {
|
||||
static_assert(std::numeric_limits<Src>::is_specialized,
|
||||
"argument must be numeric");
|
||||
static_assert(std::numeric_limits<Dst>::is_specialized,
|
||||
"result must be numeric");
|
||||
return RangeCheckImpl<Dst, Src>::Check(value);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
|
||||
@@ -1,318 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Minimum and maximum
|
||||
// ===================
|
||||
//
|
||||
// rtc::SafeMin(x, y)
|
||||
// rtc::SafeMax(x, y)
|
||||
//
|
||||
// (These are both constexpr.)
|
||||
//
|
||||
// Accept two arguments of either any two integral or any two floating-point
|
||||
// types, and return the smaller and larger value, respectively, with no
|
||||
// truncation or wrap-around. If only one of the input types is statically
|
||||
// guaranteed to be able to represent the result, the return type is that type;
|
||||
// if either one would do, the result type is the smaller type. (One of these
|
||||
// two cases always applies.)
|
||||
//
|
||||
// * The case with one floating-point and one integral type is not allowed,
|
||||
// because the floating-point type will have greater range, but may not
|
||||
// have sufficient precision to represent the integer value exactly.)
|
||||
//
|
||||
// Clamp (a.k.a. constrain to a given interval)
|
||||
// ============================================
|
||||
//
|
||||
// rtc::SafeClamp(x, a, b)
|
||||
//
|
||||
// Accepts three arguments of any mix of integral types or any mix of
|
||||
// floating-point types, and returns the value in the closed interval [a, b]
|
||||
// that is closest to x (that is, if x < a it returns a; if x > b it returns b;
|
||||
// and if a <= x <= b it returns x). As for SafeMin() and SafeMax(), there is
|
||||
// no truncation or wrap-around. The result type
|
||||
//
|
||||
// 1. is statically guaranteed to be able to represent the result;
|
||||
//
|
||||
// 2. is no larger than the largest of the three argument types; and
|
||||
//
|
||||
// 3. has the same signedness as the type of the first argument, if this is
|
||||
// possible without violating the First or Second Law.
|
||||
//
|
||||
// There is always at least one type that meets criteria 1 and 2. If more than
|
||||
// one type meets these criteria equally well, the result type is one of the
|
||||
// types that is smallest. Note that unlike SafeMin() and SafeMax(),
|
||||
// SafeClamp() will sometimes pick a return type that isn't the type of any of
|
||||
// its arguments.
|
||||
//
|
||||
// * In this context, a type A is smaller than a type B if it has a smaller
|
||||
// range; that is, if A::max() - A::min() < B::max() - B::min(). For
|
||||
// example, int8_t < int16_t == uint16_t < int32_t, and all integral types
|
||||
// are smaller than all floating-point types.)
|
||||
//
|
||||
// * As for SafeMin and SafeMax, mixing integer and floating-point arguments
|
||||
// is not allowed, because floating-point types have greater range than
|
||||
// integer types, but do not have sufficient precision to represent the
|
||||
// values of most integer types exactly.
|
||||
//
|
||||
// Requesting a specific return type
|
||||
// =================================
|
||||
//
|
||||
// All three functions allow callers to explicitly specify the return type as a
|
||||
// template parameter, overriding the default return type. E.g.
|
||||
//
|
||||
// rtc::SafeMin<int>(x, y) // returns an int
|
||||
//
|
||||
// If the requested type is statically guaranteed to be able to represent the
|
||||
// result, then everything's fine, and the return type is as requested. But if
|
||||
// the requested type is too small, a static_assert is triggered.
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_SAFE_MINMAX_H_
|
||||
#define RTC_BASE_NUMERICS_SAFE_MINMAX_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rtc_base/type_traits.h"
|
||||
#include "safe_compare.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
namespace safe_minmax_impl {
|
||||
|
||||
// Make the range of a type available via something other than a constexpr
|
||||
// function, to work around MSVC limitations. See
|
||||
// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
|
||||
template <typename T>
|
||||
struct Limits {
|
||||
static constexpr T lowest = std::numeric_limits<T>::lowest();
|
||||
static constexpr T max = std::numeric_limits<T>::max();
|
||||
};
|
||||
|
||||
template <typename T, bool is_enum = std::is_enum<T>::value>
|
||||
struct UnderlyingType;
|
||||
|
||||
template <typename T>
|
||||
struct UnderlyingType<T, false> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnderlyingType<T, true> {
|
||||
using type = typename std::underlying_type<T>::type;
|
||||
};
|
||||
|
||||
// Given two types T1 and T2, find types that can hold the smallest (in
|
||||
// ::min_t) and the largest (in ::max_t) of the two values.
|
||||
template <typename T1, typename T2, bool int1 = IsIntlike<T1>::value,
|
||||
bool int2 = IsIntlike<T2>::value>
|
||||
struct MType {
|
||||
static_assert(int1 == int2,
|
||||
"You may not mix integral and floating-point arguments");
|
||||
};
|
||||
|
||||
// Specialization for when neither type is integral (and therefore presumably
|
||||
// floating-point).
|
||||
template <typename T1, typename T2>
|
||||
struct MType<T1, T2, false, false> {
|
||||
using min_t = typename std::common_type<T1, T2>::type;
|
||||
static_assert(std::is_same<min_t, T1>::value ||
|
||||
std::is_same<min_t, T2>::value,
|
||||
"");
|
||||
|
||||
using max_t = typename std::common_type<T1, T2>::type;
|
||||
static_assert(std::is_same<max_t, T1>::value ||
|
||||
std::is_same<max_t, T2>::value,
|
||||
"");
|
||||
};
|
||||
|
||||
// Specialization for when both types are integral.
|
||||
template <typename T1, typename T2>
|
||||
struct MType<T1, T2, true, true> {
|
||||
// The type with the lowest minimum value. In case of a tie, the type with
|
||||
// the lowest maximum value. In case that too is a tie, the types have the
|
||||
// same range, and we arbitrarily pick T1.
|
||||
using min_t = typename std::conditional<
|
||||
SafeLt(Limits<T1>::lowest, Limits<T2>::lowest), T1,
|
||||
typename std::conditional<
|
||||
SafeGt(Limits<T1>::lowest, Limits<T2>::lowest), T2,
|
||||
typename std::conditional<SafeLe(Limits<T1>::max, Limits<T2>::max),
|
||||
T1, T2>::type>::type>::type;
|
||||
static_assert(std::is_same<min_t, T1>::value ||
|
||||
std::is_same<min_t, T2>::value,
|
||||
"");
|
||||
|
||||
// The type with the highest maximum value. In case of a tie, the types have
|
||||
// the same range (because in C++, integer types with the same maximum also
|
||||
// have the same minimum).
|
||||
static_assert(SafeNe(Limits<T1>::max, Limits<T2>::max) ||
|
||||
SafeEq(Limits<T1>::lowest, Limits<T2>::lowest),
|
||||
"integer types with the same max should have the same min");
|
||||
using max_t =
|
||||
typename std::conditional<SafeGe(Limits<T1>::max, Limits<T2>::max), T1,
|
||||
T2>::type;
|
||||
static_assert(std::is_same<max_t, T1>::value ||
|
||||
std::is_same<max_t, T2>::value,
|
||||
"");
|
||||
};
|
||||
|
||||
// A dummy type that we pass around at compile time but never actually use.
|
||||
// Declared but not defined.
|
||||
struct DefaultType;
|
||||
|
||||
// ::type is A, except we fall back to B if A is DefaultType. We static_assert
|
||||
// that the chosen type can hold all values that B can hold.
|
||||
template <typename A, typename B>
|
||||
struct TypeOr {
|
||||
using type = typename std::conditional<std::is_same<A, DefaultType>::value, B,
|
||||
A>::type;
|
||||
static_assert(SafeLe(Limits<type>::lowest, Limits<B>::lowest) &&
|
||||
SafeGe(Limits<type>::max, Limits<B>::max),
|
||||
"The specified type isn't large enough");
|
||||
static_assert(IsIntlike<type>::value == IsIntlike<B>::value &&
|
||||
std::is_floating_point<type>::value ==
|
||||
std::is_floating_point<type>::value,
|
||||
"float<->int conversions not allowed");
|
||||
};
|
||||
|
||||
} // namespace safe_minmax_impl
|
||||
|
||||
template <
|
||||
typename R = safe_minmax_impl::DefaultType,
|
||||
typename T1 = safe_minmax_impl::DefaultType,
|
||||
typename T2 = safe_minmax_impl::DefaultType,
|
||||
typename R2 = typename safe_minmax_impl::TypeOr<
|
||||
R,
|
||||
typename safe_minmax_impl::MType<
|
||||
typename safe_minmax_impl::UnderlyingType<T1>::type,
|
||||
typename safe_minmax_impl::UnderlyingType<T2>::type>::min_t>::type>
|
||||
constexpr R2 SafeMin(T1 a, T2 b) {
|
||||
static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value,
|
||||
"The first argument must be integral or floating-point");
|
||||
static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value,
|
||||
"The second argument must be integral or floating-point");
|
||||
return SafeLt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
|
||||
}
|
||||
|
||||
template <
|
||||
typename R = safe_minmax_impl::DefaultType,
|
||||
typename T1 = safe_minmax_impl::DefaultType,
|
||||
typename T2 = safe_minmax_impl::DefaultType,
|
||||
typename R2 = typename safe_minmax_impl::TypeOr<
|
||||
R,
|
||||
typename safe_minmax_impl::MType<
|
||||
typename safe_minmax_impl::UnderlyingType<T1>::type,
|
||||
typename safe_minmax_impl::UnderlyingType<T2>::type>::max_t>::type>
|
||||
constexpr R2 SafeMax(T1 a, T2 b) {
|
||||
static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value,
|
||||
"The first argument must be integral or floating-point");
|
||||
static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value,
|
||||
"The second argument must be integral or floating-point");
|
||||
return SafeGt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
|
||||
}
|
||||
|
||||
namespace safe_minmax_impl {
|
||||
|
||||
// Given three types T, L, and H, let ::type be a suitable return value for
|
||||
// SafeClamp(T, L, H). See the docs at the top of this file for details.
|
||||
template <typename T, typename L, typename H, bool int1 = IsIntlike<T>::value,
|
||||
bool int2 = IsIntlike<L>::value, bool int3 = IsIntlike<H>::value>
|
||||
struct ClampType {
|
||||
static_assert(int1 == int2 && int1 == int3,
|
||||
"You may not mix integral and floating-point arguments");
|
||||
};
|
||||
|
||||
// Specialization for when all three types are floating-point.
|
||||
template <typename T, typename L, typename H>
|
||||
struct ClampType<T, L, H, false, false, false> {
|
||||
using type = typename std::common_type<T, L, H>::type;
|
||||
};
|
||||
|
||||
// Specialization for when all three types are integral.
|
||||
template <typename T, typename L, typename H>
|
||||
struct ClampType<T, L, H, true, true, true> {
|
||||
private:
|
||||
// Range of the return value. The return type must be able to represent this
|
||||
// full range.
|
||||
static constexpr auto r_min =
|
||||
SafeMax(Limits<L>::lowest, SafeMin(Limits<H>::lowest, Limits<T>::lowest));
|
||||
static constexpr auto r_max =
|
||||
SafeMin(Limits<H>::max, SafeMax(Limits<L>::max, Limits<T>::max));
|
||||
|
||||
// Is the given type an acceptable return type? (That is, can it represent
|
||||
// all possible return values, and is it no larger than the largest of the
|
||||
// input types?)
|
||||
template <typename A>
|
||||
struct AcceptableType {
|
||||
private:
|
||||
static constexpr bool not_too_large = sizeof(A) <= sizeof(L) ||
|
||||
sizeof(A) <= sizeof(H) ||
|
||||
sizeof(A) <= sizeof(T);
|
||||
static constexpr bool range_contained =
|
||||
SafeLe(Limits<A>::lowest, r_min) && SafeLe(r_max, Limits<A>::max);
|
||||
|
||||
public:
|
||||
static constexpr bool value = not_too_large && range_contained;
|
||||
};
|
||||
|
||||
using best_signed_type = typename std::conditional<
|
||||
AcceptableType<int8_t>::value, int8_t,
|
||||
typename std::conditional<
|
||||
AcceptableType<int16_t>::value, int16_t,
|
||||
typename std::conditional<AcceptableType<int32_t>::value, int32_t,
|
||||
int64_t>::type>::type>::type;
|
||||
|
||||
using best_unsigned_type = typename std::conditional<
|
||||
AcceptableType<uint8_t>::value, uint8_t,
|
||||
typename std::conditional<
|
||||
AcceptableType<uint16_t>::value, uint16_t,
|
||||
typename std::conditional<AcceptableType<uint32_t>::value, uint32_t,
|
||||
uint64_t>::type>::type>::type;
|
||||
|
||||
public:
|
||||
// Pick the best type, preferring the same signedness as T but falling back
|
||||
// to the other one if necessary.
|
||||
using type = typename std::conditional<
|
||||
std::is_signed<T>::value,
|
||||
typename std::conditional<AcceptableType<best_signed_type>::value,
|
||||
best_signed_type, best_unsigned_type>::type,
|
||||
typename std::conditional<AcceptableType<best_unsigned_type>::value,
|
||||
best_unsigned_type,
|
||||
best_signed_type>::type>::type;
|
||||
static_assert(AcceptableType<type>::value, "");
|
||||
};
|
||||
|
||||
} // namespace safe_minmax_impl
|
||||
|
||||
template <
|
||||
typename R = safe_minmax_impl::DefaultType,
|
||||
typename T = safe_minmax_impl::DefaultType,
|
||||
typename L = safe_minmax_impl::DefaultType,
|
||||
typename H = safe_minmax_impl::DefaultType,
|
||||
typename R2 = typename safe_minmax_impl::TypeOr<
|
||||
R, typename safe_minmax_impl::ClampType<
|
||||
typename safe_minmax_impl::UnderlyingType<T>::type,
|
||||
typename safe_minmax_impl::UnderlyingType<L>::type,
|
||||
typename safe_minmax_impl::UnderlyingType<H>::type>::type>::type>
|
||||
R2 SafeClamp(T x, L min, H max) {
|
||||
static_assert(IsIntlike<H>::value || std::is_floating_point<H>::value,
|
||||
"The first argument must be integral or floating-point");
|
||||
static_assert(IsIntlike<T>::value || std::is_floating_point<T>::value,
|
||||
"The second argument must be integral or floating-point");
|
||||
static_assert(IsIntlike<L>::value || std::is_floating_point<L>::value,
|
||||
"The third argument must be integral or floating-point");
|
||||
return SafeLe(x, min) ? static_cast<R2>(min)
|
||||
: SafeGe(x, max) ? static_cast<R2>(max)
|
||||
: static_cast<R2>(x);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_SAFE_MINMAX_H_
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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 RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UNWRAPPER_H_
|
||||
#define RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UNWRAPPER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "sequence_number_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// A sequence number unwrapper where the first unwrapped value equals the
|
||||
// first value being unwrapped.
|
||||
template <typename T, T M = 0>
|
||||
class SeqNumUnwrapper {
|
||||
static_assert(
|
||||
std::is_unsigned<T>::value &&
|
||||
std::numeric_limits<T>::max() < std::numeric_limits<int64_t>::max(),
|
||||
"Type unwrapped must be an unsigned integer smaller than int64_t.");
|
||||
|
||||
public:
|
||||
// Unwraps `value` and updates the internal state of the unwrapper.
|
||||
int64_t Unwrap(T value) {
|
||||
if (!last_value_) {
|
||||
last_unwrapped_ = {value};
|
||||
} else {
|
||||
last_unwrapped_ += Delta(*last_value_, value);
|
||||
}
|
||||
|
||||
last_value_ = value;
|
||||
return last_unwrapped_;
|
||||
}
|
||||
|
||||
// Returns the `value` without updating the internal state of the unwrapper.
|
||||
int64_t PeekUnwrap(T value) const {
|
||||
if (!last_value_) {
|
||||
return value;
|
||||
}
|
||||
return last_unwrapped_ + Delta(*last_value_, value);
|
||||
}
|
||||
|
||||
// Resets the unwrapper to its initial state. Unwrapped sequence numbers will
|
||||
// being at 0 after resetting.
|
||||
void Reset() {
|
||||
last_unwrapped_ = 0;
|
||||
last_value_.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
static int64_t Delta(T last_value, T new_value) {
|
||||
constexpr int64_t kBackwardAdjustment =
|
||||
M == 0 ? int64_t{std::numeric_limits<T>::max()} + 1 : M;
|
||||
int64_t result = ForwardDiff<T, M>(last_value, new_value);
|
||||
if (!AheadOrAt<T, M>(new_value, last_value)) {
|
||||
result -= kBackwardAdjustment;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t last_unwrapped_ = 0;
|
||||
std::optional<T> last_value_;
|
||||
};
|
||||
|
||||
using RtpTimestampUnwrapper = SeqNumUnwrapper<uint32_t>;
|
||||
using RtpSequenceNumberUnwrapper = SeqNumUnwrapper<uint16_t>;
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UNWRAPPER_H_
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UTIL_H_
|
||||
#define RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UTIL_H_
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "mod_ops.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Test if the sequence number `a` is ahead or at sequence number `b`.
|
||||
//
|
||||
// If `M` is an even number and the two sequence numbers are at max distance
|
||||
// from each other, then the sequence number with the highest value is
|
||||
// considered to be ahead.
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M > 0), bool>::type AheadOrAt(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
const T maxDist = M / 2;
|
||||
if (!(M & 1) && MinDiff<T, M>(a, b) == maxDist) return b < a;
|
||||
return ForwardDiff<T, M>(b, a) <= maxDist;
|
||||
}
|
||||
|
||||
template <typename T, T M>
|
||||
inline typename std::enable_if<(M == 0), bool>::type AheadOrAt(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
const T maxDist = std::numeric_limits<T>::max() / 2 + T(1);
|
||||
if (a - b == maxDist) return b < a;
|
||||
return ForwardDiff(b, a) < maxDist;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool AheadOrAt(T a, T b) {
|
||||
return AheadOrAt<T, 0>(a, b);
|
||||
}
|
||||
|
||||
// Test if the sequence number `a` is ahead of sequence number `b`.
|
||||
//
|
||||
// If `M` is an even number and the two sequence numbers are at max distance
|
||||
// from each other, then the sequence number with the highest value is
|
||||
// considered to be ahead.
|
||||
template <typename T, T M = 0>
|
||||
inline bool AheadOf(T a, T b) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Type must be an unsigned integer.");
|
||||
return a != b && AheadOrAt<T, M>(a, b);
|
||||
}
|
||||
|
||||
// Comparator used to compare sequence numbers in a continuous fashion.
|
||||
//
|
||||
// WARNING! If used to sort sequence numbers of length M then the interval
|
||||
// covered by the sequence numbers may not be larger than floor(M/2).
|
||||
template <typename T, T M = 0>
|
||||
struct AscendingSeqNumComp {
|
||||
bool operator()(T a, T b) const { return AheadOf<T, M>(a, b); }
|
||||
};
|
||||
|
||||
// Comparator used to compare sequence numbers in a continuous fashion.
|
||||
//
|
||||
// WARNING! If used to sort sequence numbers of length M then the interval
|
||||
// covered by the sequence numbers may not be larger than floor(M/2).
|
||||
template <typename T, T M = 0>
|
||||
struct DescendingSeqNumComp {
|
||||
bool operator()(T a, T b) const { return AheadOf<T, M>(b, a); }
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UTIL_H_
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* 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 "rtc_base/rate_statistics.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include "log.h"
|
||||
#include "rtc_base/numerics/safe_compare.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
RateStatistics::Bucket::Bucket(int64_t timestamp)
|
||||
: sum(0), num_samples(0), timestamp(timestamp) {}
|
||||
|
||||
RateStatistics::RateStatistics(int64_t window_size_ms, float scale)
|
||||
: accumulated_count_(0),
|
||||
first_timestamp_(-1),
|
||||
num_samples_(0),
|
||||
scale_(scale),
|
||||
max_window_size_ms_(window_size_ms),
|
||||
current_window_size_ms_(max_window_size_ms_) {}
|
||||
|
||||
RateStatistics::RateStatistics(const RateStatistics& other)
|
||||
: buckets_(other.buckets_),
|
||||
accumulated_count_(other.accumulated_count_),
|
||||
first_timestamp_(other.first_timestamp_),
|
||||
overflow_(other.overflow_),
|
||||
num_samples_(other.num_samples_),
|
||||
scale_(other.scale_),
|
||||
max_window_size_ms_(other.max_window_size_ms_),
|
||||
current_window_size_ms_(other.current_window_size_ms_) {}
|
||||
|
||||
RateStatistics::RateStatistics(RateStatistics&& other) = default;
|
||||
|
||||
RateStatistics::~RateStatistics() {}
|
||||
|
||||
void RateStatistics::Reset() {
|
||||
accumulated_count_ = 0;
|
||||
overflow_ = false;
|
||||
num_samples_ = 0;
|
||||
first_timestamp_ = -1;
|
||||
current_window_size_ms_ = max_window_size_ms_;
|
||||
buckets_.clear();
|
||||
}
|
||||
|
||||
void RateStatistics::Update(int64_t count, int64_t now_ms) {
|
||||
// Don't reset `first_timestamp_` if the last sample removed by EraseOld() was
|
||||
// recent. This ensures that the window maintains its intended duration even
|
||||
// when samples are received near the boundary. Use a margin of 50% of the
|
||||
// current window size.
|
||||
const int64_t recent_sample_time_margin = 1.5 * current_window_size_ms_;
|
||||
bool last_sample_is_recent =
|
||||
!buckets_.empty() &&
|
||||
buckets_.back().timestamp > now_ms - recent_sample_time_margin;
|
||||
|
||||
EraseOld(now_ms);
|
||||
if (first_timestamp_ == -1 || (num_samples_ == 0 && !last_sample_is_recent)) {
|
||||
first_timestamp_ = now_ms;
|
||||
}
|
||||
|
||||
if (buckets_.empty() || now_ms != buckets_.back().timestamp) {
|
||||
if (!buckets_.empty() && now_ms < buckets_.back().timestamp) {
|
||||
LOG_WARN(
|
||||
"Timestamp {} is before the last added timestamp in the rate window: "
|
||||
"{}, aligning to that.",
|
||||
now_ms, buckets_.back().timestamp);
|
||||
now_ms = buckets_.back().timestamp;
|
||||
}
|
||||
buckets_.emplace_back(now_ms);
|
||||
}
|
||||
Bucket& last_bucket = buckets_.back();
|
||||
last_bucket.sum += count;
|
||||
++last_bucket.num_samples;
|
||||
|
||||
if (std::numeric_limits<int64_t>::max() - accumulated_count_ > count) {
|
||||
accumulated_count_ += count;
|
||||
} else {
|
||||
overflow_ = true;
|
||||
}
|
||||
++num_samples_;
|
||||
}
|
||||
|
||||
std::optional<int64_t> RateStatistics::Rate(int64_t now_ms) const {
|
||||
// Yeah, this const_cast ain't pretty, but the alternative is to declare most
|
||||
// of the members as mutable...
|
||||
const_cast<RateStatistics*>(this)->EraseOld(now_ms);
|
||||
|
||||
int active_window_size = 0;
|
||||
if (first_timestamp_ != -1) {
|
||||
if (first_timestamp_ <= now_ms - current_window_size_ms_) {
|
||||
// Count window as full even if no data points currently in view, if the
|
||||
// data stream started before the window.
|
||||
active_window_size = current_window_size_ms_;
|
||||
} else {
|
||||
// Size of a single bucket is 1ms, so even if now_ms == first_timestmap_
|
||||
// the window size should be 1.
|
||||
active_window_size = now_ms - first_timestamp_ + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If window is a single bucket or there is only one sample in a data set that
|
||||
// has not grown to the full window size, or if the accumulator has
|
||||
// overflowed, treat this as rate unavailable.
|
||||
if (num_samples_ == 0 || active_window_size <= 1 ||
|
||||
(num_samples_ <= 1 &&
|
||||
rtc::SafeLt(active_window_size, current_window_size_ms_)) ||
|
||||
overflow_) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
float scale = static_cast<float>(scale_) / active_window_size;
|
||||
float result = accumulated_count_ * scale + 0.5f;
|
||||
|
||||
// Better return unavailable rate than garbage value (undefined behavior).
|
||||
if (result > static_cast<float>(std::numeric_limits<int64_t>::max())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return rtc::dchecked_cast<int64_t>(result);
|
||||
}
|
||||
|
||||
void RateStatistics::EraseOld(int64_t now_ms) {
|
||||
// New oldest time that is included in data set.
|
||||
const int64_t new_oldest_time = now_ms - current_window_size_ms_ + 1;
|
||||
|
||||
// Loop over buckets and remove too old data points.
|
||||
while (!buckets_.empty() && buckets_.front().timestamp < new_oldest_time) {
|
||||
const Bucket& oldest_bucket = buckets_.front();
|
||||
accumulated_count_ -= oldest_bucket.sum;
|
||||
num_samples_ -= oldest_bucket.num_samples;
|
||||
buckets_.pop_front();
|
||||
// This does not clear overflow_ even when counter is empty.
|
||||
// TODO(https://bugs.webrtc.org/11247): Consider if overflow_ can be reset.
|
||||
}
|
||||
}
|
||||
|
||||
bool RateStatistics::SetWindowSize(int64_t window_size_ms, int64_t now_ms) {
|
||||
if (window_size_ms <= 0 || window_size_ms > max_window_size_ms_) return false;
|
||||
if (first_timestamp_ != -1) {
|
||||
// If the window changes (e.g. decreases - removing data point, then
|
||||
// increases again) we need to update the first timestamp mark as
|
||||
// otherwise it indicates the window coveres a region of zeros, suddenly
|
||||
// under-estimating the rate.
|
||||
first_timestamp_ = std::max(first_timestamp_, now_ms - window_size_ms + 1);
|
||||
}
|
||||
current_window_size_ms_ = window_size_ms;
|
||||
EraseOld(now_ms);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_RATE_STATISTICS_H_
|
||||
#define RTC_BASE_RATE_STATISTICS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Class to estimate rates based on counts in a sequence of 1-millisecond
|
||||
// intervals.
|
||||
|
||||
// This class uses int64 for all its numbers because some rates can be very
|
||||
// high; for instance, a 20 Mbit/sec video stream can wrap a 32-bit byte
|
||||
// counter in 14 minutes.
|
||||
|
||||
// Note that timestamps used in Update(), Rate() and SetWindowSize() must never
|
||||
// decrease for two consecutive calls.
|
||||
// TODO(bugs.webrtc.org/11600): Migrate from int64_t to Timestamp.
|
||||
|
||||
class RateStatistics {
|
||||
public:
|
||||
static constexpr float kBpsScale = 8000.0f;
|
||||
|
||||
// max_window_size_ms = Maximum window size in ms for the rate estimation.
|
||||
// Initial window size is set to this, but may be changed
|
||||
// to something lower by calling SetWindowSize().
|
||||
// scale = coefficient to convert counts/ms to desired unit
|
||||
// ex: kBpsScale (8000) for bits/s if count represents bytes.
|
||||
RateStatistics(int64_t max_window_size_ms, float scale);
|
||||
|
||||
RateStatistics(const RateStatistics& other);
|
||||
|
||||
RateStatistics(RateStatistics&& other);
|
||||
|
||||
~RateStatistics();
|
||||
|
||||
// Reset instance to original state.
|
||||
void Reset();
|
||||
|
||||
// Update rate with a new data point, moving averaging window as needed.
|
||||
void Update(int64_t count, int64_t now_ms);
|
||||
|
||||
// Note that despite this being a const method, it still updates the internal
|
||||
// state (moves averaging window), but it doesn't make any alterations that
|
||||
// are observable from the other methods, as long as supplied timestamps are
|
||||
// from a monotonic clock. Ie, it doesn't matter if this call moves the
|
||||
// window, since any subsequent call to Update or Rate would still have moved
|
||||
// the window as much or more.
|
||||
std::optional<int64_t> Rate(int64_t now_ms) const;
|
||||
|
||||
// Update the size of the averaging window. The maximum allowed value for
|
||||
// window_size_ms is max_window_size_ms as supplied in the constructor.
|
||||
bool SetWindowSize(int64_t window_size_ms, int64_t now_ms);
|
||||
|
||||
private:
|
||||
void EraseOld(int64_t now_ms);
|
||||
|
||||
struct Bucket {
|
||||
explicit Bucket(int64_t timestamp);
|
||||
int64_t sum; // Sum of all samples in this bucket.
|
||||
int num_samples; // Number of samples in this bucket.
|
||||
const int64_t timestamp; // Timestamp this bucket corresponds to.
|
||||
};
|
||||
// All buckets within the time window, ordered by time.
|
||||
std::deque<Bucket> buckets_;
|
||||
|
||||
// Total count recorded in all buckets.
|
||||
int64_t accumulated_count_;
|
||||
|
||||
// Timestamp of the first data point seen, or -1 of none seen.
|
||||
int64_t first_timestamp_;
|
||||
|
||||
// True if accumulated_count_ has ever grown too large to be
|
||||
// contained in its integer type.
|
||||
bool overflow_ = false;
|
||||
|
||||
// The total number of samples in the buckets.
|
||||
int num_samples_;
|
||||
|
||||
// To convert counts/ms to desired units
|
||||
const float scale_;
|
||||
|
||||
// The window sizes, in ms, over which the rate is calculated.
|
||||
const int64_t max_window_size_ms_;
|
||||
int64_t current_window_size_ms_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_RATE_STATISTICS_H_
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef RTC_BASE_REF_COUNTER_H_
|
||||
#define RTC_BASE_REF_COUNTER_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "api/ref_count.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace webrtc_impl {
|
||||
|
||||
class RefCounter {
|
||||
public:
|
||||
explicit RefCounter(int ref_count) : ref_count_(ref_count) {}
|
||||
RefCounter() = delete;
|
||||
|
||||
void IncRef() {
|
||||
// Relaxed memory order: The current thread is allowed to act on the
|
||||
// resource protected by the reference counter both before and after the
|
||||
// atomic op, so this function doesn't prevent memory access reordering.
|
||||
ref_count_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// Returns kDroppedLastRef if this call dropped the last reference; the caller
|
||||
// should therefore free the resource protected by the reference counter.
|
||||
// Otherwise, returns kOtherRefsRemained (note that in case of multithreading,
|
||||
// some other caller may have dropped the last reference by the time this call
|
||||
// returns; all we know is that we didn't do it).
|
||||
RefCountReleaseStatus DecRef() {
|
||||
// Use release-acquire barrier to ensure all actions on the protected
|
||||
// resource are finished before the resource can be freed.
|
||||
// When ref_count_after_subtract > 0, this function require
|
||||
// std::memory_order_release part of the barrier.
|
||||
// When ref_count_after_subtract == 0, this function require
|
||||
// std::memory_order_acquire part of the barrier.
|
||||
// In addition std::memory_order_release is used for synchronization with
|
||||
// the HasOneRef function to make sure all actions on the protected resource
|
||||
// are finished before the resource is assumed to have exclusive access.
|
||||
int ref_count_after_subtract =
|
||||
ref_count_.fetch_sub(1, std::memory_order_acq_rel) - 1;
|
||||
return ref_count_after_subtract == 0
|
||||
? RefCountReleaseStatus::kDroppedLastRef
|
||||
: RefCountReleaseStatus::kOtherRefsRemained;
|
||||
}
|
||||
|
||||
// Return whether the reference count is one. If the reference count is used
|
||||
// in the conventional way, a reference count of 1 implies that the current
|
||||
// thread owns the reference and no other thread shares it. This call performs
|
||||
// the test for a reference count of one, and performs the memory barrier
|
||||
// needed for the owning thread to act on the resource protected by the
|
||||
// reference counter, knowing that it has exclusive access.
|
||||
bool HasOneRef() const {
|
||||
// To ensure resource protected by the reference counter has exclusive
|
||||
// access, all changes to the resource before it was released by other
|
||||
// threads must be visible by current thread. That is provided by release
|
||||
// (in DecRef) and acquire (in this function) ordering.
|
||||
return ref_count_.load(std::memory_order_acquire) == 1;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int> ref_count_;
|
||||
};
|
||||
|
||||
} // namespace webrtc_impl
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_REF_COUNTER_H_
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
// This file contains platform-specific typedefs and defines.
|
||||
// Much of it is derived from Chromium's build/build_config.h.
|
||||
|
||||
#ifndef RTC_BASE_SYSTEM_ARCH_H_
|
||||
#define RTC_BASE_SYSTEM_ARCH_H_
|
||||
|
||||
// Processor architecture detection. For more info on what's defined, see:
|
||||
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
// https://www.agner.org/optimize/calling_conventions.pdf
|
||||
// https://sourceforge.net/p/predef/wiki/Architectures/
|
||||
// or with gcc, run: "echo | gcc -E -dM -"
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define WEBRTC_ARCH_X86_FAMILY
|
||||
#define WEBRTC_ARCH_X86_64
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(_M_ARM64) || defined(__aarch64__)
|
||||
#define WEBRTC_ARCH_ARM_FAMILY
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
#define WEBRTC_ARCH_X86_FAMILY
|
||||
#define WEBRTC_ARCH_X86
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(_M_ARM) || defined(__ARMEL__)
|
||||
#define WEBRTC_ARCH_ARM_FAMILY
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__MIPSEL__) || defined(__MIPSEB__)
|
||||
#define WEBRTC_ARCH_MIPS_FAMILY
|
||||
#if defined(__LP64__)
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#else
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#endif
|
||||
#if defined(__MIPSEL__)
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#else
|
||||
#define WEBRTC_ARCH_BIG_ENDIAN
|
||||
#endif
|
||||
#elif defined(__PPC__)
|
||||
#if defined(__PPC64__)
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#else
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#endif
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#else
|
||||
#define WEBRTC_ARCH_BIG_ENDIAN
|
||||
#endif
|
||||
#elif defined(__sparc) || defined(__sparc__)
|
||||
#if __SIZEOF_LONG__ == 8
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#else
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#endif
|
||||
#define WEBRTC_ARCH_BIG_ENDIAN
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__riscv) && __riscv_xlen == 32
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__loongarch32)
|
||||
#define WEBRTC_ARCH_LOONG_FAMILY
|
||||
#define WEBRTC_ARCH_LOONG32
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__loongarch64)
|
||||
#define WEBRTC_ARCH_LOONG_FAMILY
|
||||
#define WEBRTC_ARCH_LOONG64
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__pnacl__)
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#else
|
||||
#error Please add support for your architecture in rtc_base/system/arch.h
|
||||
#endif
|
||||
|
||||
#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
|
||||
#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#endif // RTC_BASE_SYSTEM_ARCH_H_
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// If WEBRTC_EXCLUDE_SYSTEM_TIME is set, an implementation of
|
||||
// rtc::SystemTimeNanos() must be provided externally.
|
||||
#ifndef WEBRTC_EXCLUDE_SYSTEM_TIME
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
// clang-format off
|
||||
// clang formatting would put <windows.h> last,
|
||||
// which leads to compilation failure.
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <sys/timeb.h>
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
#include "system_time.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
int64_t SystemTimeNanos() {
|
||||
int64_t ticks;
|
||||
#if defined(__APPLE__)
|
||||
static mach_timebase_info_data_t timebase;
|
||||
if (timebase.denom == 0) {
|
||||
// Get the timebase if this is the first time we run.
|
||||
// Recommended by Apple's QA1398.
|
||||
if (mach_timebase_info(&timebase) != KERN_SUCCESS) {
|
||||
}
|
||||
}
|
||||
// Use timebase to convert absolute time tick units into nanoseconds.
|
||||
const auto mul = [](uint64_t a, uint32_t b) -> int64_t {
|
||||
return rtc::dchecked_cast<int64_t>(a * b);
|
||||
};
|
||||
ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom;
|
||||
#elif defined(__linux__)
|
||||
struct timespec ts;
|
||||
// TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not
|
||||
// supported?
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
|
||||
static_cast<int64_t>(ts.tv_nsec);
|
||||
#elif defined(WINUWP)
|
||||
ticks = WinUwpSystemTimeNanos();
|
||||
#elif defined(_WIN32)
|
||||
// TODO(webrtc:14601): Fix the volatile increment instead of suppressing the
|
||||
// warning.
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-volatile"
|
||||
#endif
|
||||
static volatile LONG last_timegettime = 0;
|
||||
static volatile int64_t num_wrap_timegettime = 0;
|
||||
volatile LONG* last_timegettime_ptr = &last_timegettime;
|
||||
DWORD now = timeGetTime();
|
||||
// Atomically update the last gotten time
|
||||
DWORD old = InterlockedExchange(last_timegettime_ptr, now);
|
||||
if (now < old) {
|
||||
// If now is earlier than old, there may have been a race between threads.
|
||||
// 0x0fffffff ~3.1 days, the code will not take that long to execute
|
||||
// so it must have been a wrap around.
|
||||
if (old > 0xf0000000 && now < 0x0fffffff) {
|
||||
num_wrap_timegettime++;
|
||||
}
|
||||
}
|
||||
ticks = now + (num_wrap_timegettime << 32);
|
||||
// TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
ticks = ticks * kNumNanosecsPerMillisec;
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported platform.
|
||||
#endif
|
||||
return ticks;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
#endif // WEBRTC_EXCLUDE_SYSTEM_TIME
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_SYSTEM_TIME_H_
|
||||
#define RTC_BASE_SYSTEM_TIME_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Returns the actual system time, even if a clock is set for testing.
|
||||
// Useful for timeouts while using a test clock, or for logging.
|
||||
int64_t SystemTimeNanos();
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_SYSTEM_TIME_H_
|
||||
@@ -1,98 +0,0 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Borrowed from
|
||||
// https://code.google.com/p/gperftools/source/browse/src/base/thread_annotations.h
|
||||
// but adapted for clang attributes instead of the gcc.
|
||||
//
|
||||
// This header file contains the macro definitions for thread safety
|
||||
// annotations that allow the developers to document the locking policies
|
||||
// of their multi-threaded code. The annotations can also help program
|
||||
// analysis tools to identify potential thread safety issues.
|
||||
|
||||
#ifndef RTC_BASE_THREAD_ANNOTATIONS_H_
|
||||
#define RTC_BASE_THREAD_ANNOTATIONS_H_
|
||||
|
||||
#if defined(__clang__) && (!defined(SWIG))
|
||||
#define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
#define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
#endif
|
||||
|
||||
// Document if a shared variable/field needs to be protected by a lock.
|
||||
// GUARDED_BY allows the user to specify a particular lock that should be
|
||||
// held when accessing the annotated variable.
|
||||
#define RTC_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||
|
||||
// Document if the memory location pointed to by a pointer should be guarded
|
||||
// by a lock when dereferencing the pointer. Note that a pointer variable to a
|
||||
// shared memory location could itself be a shared variable. For example, if a
|
||||
// shared global pointer q, which is guarded by mu1, points to a shared memory
|
||||
// location that is guarded by mu2, q should be annotated as follows:
|
||||
// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
|
||||
#define RTC_PT_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||
|
||||
// Document the acquisition order between locks that can be held
|
||||
// simultaneously by a thread. For any two locks that need to be annotated
|
||||
// to establish an acquisition order, only one of them needs the annotation.
|
||||
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
|
||||
// and ACQUIRED_BEFORE.)
|
||||
#define RTC_ACQUIRED_AFTER(x) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x))
|
||||
#define RTC_ACQUIRED_BEFORE(x) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x))
|
||||
|
||||
// The following three annotations document the lock requirements for
|
||||
// functions/methods.
|
||||
|
||||
// Document if a function expects certain locks to be held before it is called
|
||||
#define RTC_EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
|
||||
#define RTC_SHARED_LOCKS_REQUIRED(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
|
||||
|
||||
// Document the locks acquired in the body of the function. These locks
|
||||
// cannot be held when calling this function (as google3's Mutex locks are
|
||||
// non-reentrant).
|
||||
#define RTC_LOCKS_EXCLUDED(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
|
||||
|
||||
// Document the lock the annotated function returns without acquiring it.
|
||||
#define RTC_LOCK_RETURNED(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
|
||||
|
||||
// Document if a class/type is a lockable type (such as the Mutex class).
|
||||
#define RTC_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(lockable)
|
||||
|
||||
// Document if a class is a scoped lockable type (such as the MutexLock class).
|
||||
#define RTC_SCOPED_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||
|
||||
// The following annotations specify lock and unlock primitives.
|
||||
#define RTC_EXCLUSIVE_LOCK_FUNCTION(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
|
||||
|
||||
#define RTC_SHARED_LOCK_FUNCTION(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
|
||||
|
||||
#define RTC_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
|
||||
|
||||
#define RTC_SHARED_TRYLOCK_FUNCTION(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
|
||||
|
||||
#define RTC_UNLOCK_FUNCTION(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
|
||||
|
||||
#define RTC_ASSERT_EXCLUSIVE_LOCK(...) \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
|
||||
|
||||
// An escape hatch for thread safety analysis to ignore the annotated function.
|
||||
#define RTC_NO_THREAD_SAFETY_ANALYSIS \
|
||||
RTC_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
#endif // RTC_BASE_THREAD_ANNOTATIONS_H_
|
||||
@@ -1,233 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004 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 <stdint.h>
|
||||
|
||||
#if defined(__POSIX__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
#include "rtc_base/system_time.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
#if defined(_WIN32)
|
||||
#include "rtc_base/win32.h"
|
||||
#endif
|
||||
|
||||
namespace rtc {
|
||||
|
||||
#if defined(_WIN32) || defined(WINUWP)
|
||||
// FileTime (January 1st 1601) to Unix time (January 1st 1970)
|
||||
// offset in units of 100ns.
|
||||
static constexpr uint64_t kFileTimeToUnixTimeEpochOffset =
|
||||
116444736000000000ULL;
|
||||
static constexpr uint64_t kFileTimeToMicroSeconds = 10LL;
|
||||
#endif
|
||||
|
||||
ClockInterface* g_clock = nullptr;
|
||||
|
||||
ClockInterface* SetClockForTesting(ClockInterface* clock) {
|
||||
ClockInterface* prev = g_clock;
|
||||
g_clock = clock;
|
||||
return prev;
|
||||
}
|
||||
|
||||
ClockInterface* GetClockForTesting() { return g_clock; }
|
||||
|
||||
#if defined(WINUWP)
|
||||
|
||||
namespace {
|
||||
|
||||
class TimeHelper final {
|
||||
public:
|
||||
TimeHelper(const TimeHelper&) = delete;
|
||||
|
||||
// Resets the clock based upon an NTP server. This routine must be called
|
||||
// prior to the main system start-up to ensure all clocks are based upon
|
||||
// an NTP server time if NTP synchronization is required. No critical
|
||||
// section is used thus this method must be called prior to any clock
|
||||
// routines being used.
|
||||
static void SyncWithNtp(int64_t ntp_server_time_ms) {
|
||||
auto& singleton = Singleton();
|
||||
TIME_ZONE_INFORMATION time_zone;
|
||||
GetTimeZoneInformation(&time_zone);
|
||||
int64_t time_zone_bias_ns =
|
||||
rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
|
||||
singleton.app_start_time_ns_ =
|
||||
(ntp_server_time_ms - kNTPTimeToUnixTimeEpochOffset) * 1000000 -
|
||||
time_zone_bias_ns;
|
||||
singleton.UpdateReferenceTime();
|
||||
}
|
||||
|
||||
// Returns the number of nanoseconds that have passed since unix epoch.
|
||||
static int64_t TicksNs() {
|
||||
auto& singleton = Singleton();
|
||||
int64_t result = 0;
|
||||
LARGE_INTEGER qpcnt;
|
||||
QueryPerformanceCounter(&qpcnt);
|
||||
result = rtc::dchecked_cast<int64_t>(
|
||||
(rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
|
||||
rtc::dchecked_cast<uint64_t>(singleton.os_ticks_per_second_)) *
|
||||
10000);
|
||||
result = singleton.app_start_time_ns_ + result -
|
||||
singleton.time_since_os_start_ns_;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
TimeHelper() {
|
||||
TIME_ZONE_INFORMATION time_zone;
|
||||
GetTimeZoneInformation(&time_zone);
|
||||
int64_t time_zone_bias_ns =
|
||||
rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
|
||||
FILETIME ft;
|
||||
// This will give us system file in UTC format.
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
LARGE_INTEGER li;
|
||||
li.HighPart = ft.dwHighDateTime;
|
||||
li.LowPart = ft.dwLowDateTime;
|
||||
|
||||
app_start_time_ns_ = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) * 100 -
|
||||
time_zone_bias_ns;
|
||||
|
||||
UpdateReferenceTime();
|
||||
}
|
||||
|
||||
static TimeHelper& Singleton() {
|
||||
static TimeHelper singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void UpdateReferenceTime() {
|
||||
LARGE_INTEGER qpfreq;
|
||||
QueryPerformanceFrequency(&qpfreq);
|
||||
os_ticks_per_second_ = rtc::dchecked_cast<int64_t>(qpfreq.QuadPart);
|
||||
|
||||
LARGE_INTEGER qpcnt;
|
||||
QueryPerformanceCounter(&qpcnt);
|
||||
time_since_os_start_ns_ = rtc::dchecked_cast<int64_t>(
|
||||
(rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
|
||||
rtc::dchecked_cast<uint64_t>(os_ticks_per_second_)) *
|
||||
10000);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L;
|
||||
|
||||
// The number of nanoseconds since unix system epoch
|
||||
int64_t app_start_time_ns_;
|
||||
// The number of nanoseconds since the OS started
|
||||
int64_t time_since_os_start_ns_;
|
||||
// The OS calculated ticks per second
|
||||
int64_t os_ticks_per_second_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void SyncWithNtp(int64_t time_from_ntp_server_ms) {
|
||||
TimeHelper::SyncWithNtp(time_from_ntp_server_ms);
|
||||
}
|
||||
|
||||
int64_t WinUwpSystemTimeNanos() { return TimeHelper::TicksNs(); }
|
||||
|
||||
#endif // defined(WINUWP)
|
||||
|
||||
int64_t SystemTimeMillis() {
|
||||
return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec);
|
||||
}
|
||||
|
||||
int64_t TimeNanos() {
|
||||
if (g_clock) {
|
||||
return g_clock->TimeNanos();
|
||||
}
|
||||
return SystemTimeNanos();
|
||||
}
|
||||
|
||||
uint32_t Time32() {
|
||||
return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec);
|
||||
}
|
||||
|
||||
int64_t TimeMillis() { return TimeNanos() / kNumNanosecsPerMillisec; }
|
||||
|
||||
int64_t TimeMicros() { return TimeNanos() / kNumNanosecsPerMicrosec; }
|
||||
|
||||
int64_t TimeAfter(int64_t elapsed) { return TimeMillis() + elapsed; }
|
||||
|
||||
int32_t TimeDiff32(uint32_t later, uint32_t earlier) { return later - earlier; }
|
||||
|
||||
int64_t TimeDiff(int64_t later, int64_t earlier) { return later - earlier; }
|
||||
|
||||
int64_t TmToSeconds(const tm& tm) {
|
||||
static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
static short int cumul_mdays[12] = {0, 31, 59, 90, 120, 151,
|
||||
181, 212, 243, 273, 304, 334};
|
||||
int year = tm.tm_year + 1900;
|
||||
int month = tm.tm_mon;
|
||||
int day = tm.tm_mday - 1; // Make 0-based like the rest.
|
||||
int hour = tm.tm_hour;
|
||||
int min = tm.tm_min;
|
||||
int sec = tm.tm_sec;
|
||||
|
||||
bool expiry_in_leap_year =
|
||||
(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
|
||||
|
||||
if (year < 1970) return -1;
|
||||
if (month < 0 || month > 11) return -1;
|
||||
if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1))
|
||||
return -1;
|
||||
if (hour < 0 || hour > 23) return -1;
|
||||
if (min < 0 || min > 59) return -1;
|
||||
if (sec < 0 || sec > 59) return -1;
|
||||
|
||||
day += cumul_mdays[month];
|
||||
|
||||
// Add number of leap days between 1970 and the expiration year, inclusive.
|
||||
day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) +
|
||||
(year / 400 - 1970 / 400));
|
||||
|
||||
// We will have added one day too much above if expiration is during a leap
|
||||
// year, and expiration is in January or February.
|
||||
if (expiry_in_leap_year && month <= 2 - 1) // `month` is zero based.
|
||||
day -= 1;
|
||||
|
||||
// Combine all variables into seconds from 1970-01-01 00:00 (except `month`
|
||||
// which was accumulated into `day` above).
|
||||
return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60 +
|
||||
min) *
|
||||
60 +
|
||||
sec;
|
||||
}
|
||||
|
||||
int64_t TimeUTCMicros() {
|
||||
if (g_clock) {
|
||||
return g_clock->TimeNanos() / kNumNanosecsPerMicrosec;
|
||||
}
|
||||
#if defined(__POSIX__)
|
||||
struct timeval time;
|
||||
gettimeofday(&time, nullptr);
|
||||
// Convert from second (1.0) and microsecond (1e-6).
|
||||
return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec +
|
||||
time.tv_usec);
|
||||
#elif defined(_WIN32)
|
||||
FILETIME ft;
|
||||
// This will give us system file in UTC format in multiples of 100ns.
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
LARGE_INTEGER li;
|
||||
li.HighPart = ft.dwHighDateTime;
|
||||
li.LowPart = ft.dwLowDateTime;
|
||||
return (li.QuadPart - kFileTimeToUnixTimeEpochOffset) /
|
||||
kFileTimeToMicroSeconds;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t TimeUTCMillis() { return TimeUTCMicros() / kNumMicrosecsPerMillisec; }
|
||||
|
||||
} // namespace rtc
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005 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 RTC_BASE_TIME_UTILS_H_
|
||||
#define RTC_BASE_TIME_UTILS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "rtc_base/system_time.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
static const int64_t kNumMillisecsPerSec = INT64_C(1000);
|
||||
static const int64_t kNumMicrosecsPerSec = INT64_C(1000000);
|
||||
static const int64_t kNumNanosecsPerSec = INT64_C(1000000000);
|
||||
|
||||
static const int64_t kNumMicrosecsPerMillisec =
|
||||
kNumMicrosecsPerSec / kNumMillisecsPerSec;
|
||||
static const int64_t kNumNanosecsPerMillisec =
|
||||
kNumNanosecsPerSec / kNumMillisecsPerSec;
|
||||
static const int64_t kNumNanosecsPerMicrosec =
|
||||
kNumNanosecsPerSec / kNumMicrosecsPerSec;
|
||||
|
||||
// Elapsed milliseconds between NTP base, 1900 January 1 00:00 GMT
|
||||
// (see https://tools.ietf.org/html/rfc868), and January 1 00:00 GMT 1970
|
||||
// epoch. This is useful when converting between the NTP time base and the
|
||||
// time base used in RTCP reports.
|
||||
constexpr int64_t kNtpJan1970Millisecs = 2'208'988'800 * kNumMillisecsPerSec;
|
||||
|
||||
// TODO(honghaiz): Define a type for the time value specifically.
|
||||
|
||||
class ClockInterface {
|
||||
public:
|
||||
virtual ~ClockInterface() {}
|
||||
virtual int64_t TimeNanos() const = 0;
|
||||
};
|
||||
|
||||
// Sets the global source of time. This is useful mainly for unit tests.
|
||||
//
|
||||
// Returns the previously set ClockInterface, or nullptr if none is set.
|
||||
//
|
||||
// Does not transfer ownership of the clock. SetClockForTesting(nullptr)
|
||||
// should be called before the ClockInterface is deleted.
|
||||
//
|
||||
// This method is not thread-safe; it should only be used when no other thread
|
||||
// is running (for example, at the start/end of a unit test, or start/end of
|
||||
// main()).
|
||||
//
|
||||
// TODO(deadbeef): Instead of having functions that access this global
|
||||
// ClockInterface, we may want to pass the ClockInterface into everything
|
||||
// that uses it, eliminating the need for a global variable and this function.
|
||||
ClockInterface* SetClockForTesting(ClockInterface* clock);
|
||||
|
||||
// Returns previously set clock, or nullptr if no custom clock is being used.
|
||||
ClockInterface* GetClockForTesting();
|
||||
|
||||
#if defined(WINUWP)
|
||||
// Synchronizes the current clock based upon an NTP server's epoch in
|
||||
// milliseconds.
|
||||
void SyncWithNtp(int64_t time_from_ntp_server_ms);
|
||||
|
||||
// Returns the current time in nanoseconds. The clock is synchonized with the
|
||||
// system wall clock time upon instatiation. It may also be synchronized using
|
||||
// the SyncWithNtp() function above. Please note that the clock will most likely
|
||||
// drift away from the system wall clock time as time goes by.
|
||||
int64_t WinUwpSystemTimeNanos();
|
||||
#endif // defined(WINUWP)
|
||||
|
||||
// Returns the actual system time, even if a clock is set for testing.
|
||||
// Useful for timeouts while using a test clock, or for logging.
|
||||
int64_t SystemTimeMillis();
|
||||
|
||||
// Returns the current time in milliseconds in 32 bits.
|
||||
uint32_t Time32();
|
||||
|
||||
// Returns the current time in milliseconds in 64 bits.
|
||||
int64_t TimeMillis();
|
||||
// Deprecated. Do not use this in any new code.
|
||||
inline int64_t Time() { return TimeMillis(); }
|
||||
|
||||
// Returns the current time in microseconds.
|
||||
int64_t TimeMicros();
|
||||
|
||||
// Returns the current time in nanoseconds.
|
||||
int64_t TimeNanos();
|
||||
|
||||
// Returns a future timestamp, 'elapsed' milliseconds from now.
|
||||
int64_t TimeAfter(int64_t elapsed);
|
||||
|
||||
// Number of milliseconds that would elapse between 'earlier' and 'later'
|
||||
// timestamps. The value is negative if 'later' occurs before 'earlier'.
|
||||
int64_t TimeDiff(int64_t later, int64_t earlier);
|
||||
int32_t TimeDiff32(uint32_t later, uint32_t earlier);
|
||||
|
||||
// The number of milliseconds that have elapsed since 'earlier'.
|
||||
inline int64_t TimeSince(int64_t earlier) { return TimeMillis() - earlier; }
|
||||
|
||||
// The number of milliseconds that will elapse between now and 'later'.
|
||||
inline int64_t TimeUntil(int64_t later) { return later - TimeMillis(); }
|
||||
|
||||
// Convert from tm, which is relative to 1900-01-01 00:00 to number of
|
||||
// seconds from 1970-01-01 00:00 ("epoch"). Don't return time_t since that
|
||||
// is still 32 bits on many systems.
|
||||
int64_t TmToSeconds(const tm& tm);
|
||||
|
||||
// Return the number of microseconds since January 1, 1970, UTC.
|
||||
// Useful mainly when producing logs to be correlated with other
|
||||
// devices, and when the devices in question all have properly
|
||||
// synchronized clocks.
|
||||
//
|
||||
// Note that this function obeys the system's idea about what the time
|
||||
// is. It is not guaranteed to be monotonic; it will jump in case the
|
||||
// system time is changed, e.g., by some other process calling
|
||||
// settimeofday. Always use rtc::TimeMicros(), not this function, for
|
||||
// measuring time intervals and timeouts.
|
||||
int64_t TimeUTCMicros();
|
||||
|
||||
// Return the number of milliseconds since January 1, 1970, UTC.
|
||||
// See above.
|
||||
int64_t TimeUTCMillis();
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_TIME_UTILS_H_
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_TYPE_TRAITS_H_
|
||||
#define RTC_BASE_TYPE_TRAITS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Determines if the given class has zero-argument .data() and .size() methods
|
||||
// whose return values are convertible to T* and size_t, respectively.
|
||||
template <typename DS, typename T>
|
||||
class HasDataAndSize {
|
||||
private:
|
||||
template <
|
||||
typename C,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<decltype(std::declval<C>().data()), T*>::value &&
|
||||
std::is_convertible<decltype(std::declval<C>().size()),
|
||||
std::size_t>::value>::type* = nullptr>
|
||||
static int Test(int);
|
||||
|
||||
template <typename>
|
||||
static char Test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = std::is_same<decltype(Test<DS>(0)), int>::value;
|
||||
};
|
||||
|
||||
namespace test_has_data_and_size {
|
||||
|
||||
template <typename DR, typename SR>
|
||||
struct Test1 {
|
||||
DR data();
|
||||
SR size();
|
||||
};
|
||||
static_assert(HasDataAndSize<Test1<int*, int>, int>::value, "");
|
||||
static_assert(HasDataAndSize<Test1<int*, int>, const int>::value, "");
|
||||
static_assert(HasDataAndSize<Test1<const int*, int>, const int>::value, "");
|
||||
static_assert(!HasDataAndSize<Test1<const int*, int>, int>::value,
|
||||
"implicit cast of const int* to int*");
|
||||
static_assert(!HasDataAndSize<Test1<char*, size_t>, int>::value,
|
||||
"implicit cast of char* to int*");
|
||||
|
||||
struct Test2 {
|
||||
int* data;
|
||||
size_t size;
|
||||
};
|
||||
static_assert(!HasDataAndSize<Test2, int>::value,
|
||||
".data and .size aren't functions");
|
||||
|
||||
struct Test3 {
|
||||
int* data();
|
||||
};
|
||||
static_assert(!HasDataAndSize<Test3, int>::value, ".size() is missing");
|
||||
|
||||
class Test4 {
|
||||
int* data();
|
||||
size_t size();
|
||||
};
|
||||
static_assert(!HasDataAndSize<Test4, int>::value,
|
||||
".data() and .size() are private");
|
||||
|
||||
} // namespace test_has_data_and_size
|
||||
|
||||
namespace type_traits_impl {
|
||||
|
||||
// Determines if the given type is an enum that converts implicitly to
|
||||
// an integral type.
|
||||
template <typename T>
|
||||
struct IsIntEnum {
|
||||
private:
|
||||
// This overload is used if the type is an enum, and unary plus
|
||||
// compiles and turns it into an integral type.
|
||||
template <typename X,
|
||||
typename std::enable_if<
|
||||
std::is_enum<X>::value &&
|
||||
std::is_integral<decltype(+std::declval<X>())>::value>::type* =
|
||||
nullptr>
|
||||
static int Test(int);
|
||||
|
||||
// Otherwise, this overload is used.
|
||||
template <typename>
|
||||
static char Test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
std::is_same<decltype(Test<typename std::remove_reference<T>::type>(0)),
|
||||
int>::value;
|
||||
};
|
||||
|
||||
} // namespace type_traits_impl
|
||||
|
||||
// Determines if the given type is integral, or an enum that
|
||||
// converts implicitly to an integral type.
|
||||
template <typename T>
|
||||
struct IsIntlike {
|
||||
private:
|
||||
using X = typename std::remove_reference<T>::type;
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
std::is_integral<X>::value || type_traits_impl::IsIntEnum<X>::value;
|
||||
};
|
||||
|
||||
namespace test_enum_intlike {
|
||||
|
||||
enum E1 { e1 };
|
||||
enum { e2 };
|
||||
enum class E3 { e3 };
|
||||
struct S {};
|
||||
|
||||
static_assert(type_traits_impl::IsIntEnum<E1>::value, "");
|
||||
static_assert(type_traits_impl::IsIntEnum<decltype(e2)>::value, "");
|
||||
static_assert(!type_traits_impl::IsIntEnum<E3>::value, "");
|
||||
static_assert(!type_traits_impl::IsIntEnum<int>::value, "");
|
||||
static_assert(!type_traits_impl::IsIntEnum<float>::value, "");
|
||||
static_assert(!type_traits_impl::IsIntEnum<S>::value, "");
|
||||
|
||||
static_assert(IsIntlike<E1>::value, "");
|
||||
static_assert(IsIntlike<decltype(e2)>::value, "");
|
||||
static_assert(!IsIntlike<E3>::value, "");
|
||||
static_assert(IsIntlike<int>::value, "");
|
||||
static_assert(!IsIntlike<float>::value, "");
|
||||
static_assert(!IsIntlike<S>::value, "");
|
||||
|
||||
} // namespace test_enum_intlike
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_TYPE_TRAITS_H_
|
||||
@@ -1,309 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004 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 "rtc_base/win32.h"
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "rtc_base/arraysize.h"
|
||||
#include "rtc_base/byte_order.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Helper function declarations for inet_ntop/inet_pton.
|
||||
static const char* inet_ntop_v4(const void* src, char* dst, socklen_t size);
|
||||
static const char* inet_ntop_v6(const void* src, char* dst, socklen_t size);
|
||||
static int inet_pton_v4(const char* src, void* dst);
|
||||
static int inet_pton_v6(const char* src, void* dst);
|
||||
|
||||
// Implementation of inet_ntop (create a printable representation of an
|
||||
// ip address). XP doesn't have its own inet_ntop, and
|
||||
// WSAAddressToString requires both IPv6 to be installed and for Winsock
|
||||
// to be initialized.
|
||||
const char* win32_inet_ntop(int af, const void* src, char* dst,
|
||||
socklen_t size) {
|
||||
if (!src || !dst) {
|
||||
return nullptr;
|
||||
}
|
||||
switch (af) {
|
||||
case AF_INET: {
|
||||
return inet_ntop_v4(src, dst, size);
|
||||
}
|
||||
case AF_INET6: {
|
||||
return inet_ntop_v6(src, dst, size);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// As above, but for inet_pton. Implements inet_pton for v4 and v6.
|
||||
// Note that our inet_ntop will output normal 'dotted' v4 addresses only.
|
||||
int win32_inet_pton(int af, const char* src, void* dst) {
|
||||
if (!src || !dst) {
|
||||
return 0;
|
||||
}
|
||||
if (af == AF_INET) {
|
||||
return inet_pton_v4(src, dst);
|
||||
} else if (af == AF_INET6) {
|
||||
return inet_pton_v6(src, dst);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Helper function for inet_ntop for IPv4 addresses.
|
||||
// Outputs "dotted-quad" decimal notation.
|
||||
const char* inet_ntop_v4(const void* src, char* dst, socklen_t size) {
|
||||
if (size < INET_ADDRSTRLEN) {
|
||||
return nullptr;
|
||||
}
|
||||
const struct in_addr* as_in_addr =
|
||||
reinterpret_cast<const struct in_addr*>(src);
|
||||
snprintf(dst, size, "%d.%d.%d.%d", as_in_addr->S_un.S_un_b.s_b1,
|
||||
as_in_addr->S_un.S_un_b.s_b2, as_in_addr->S_un.S_un_b.s_b3,
|
||||
as_in_addr->S_un.S_un_b.s_b4);
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Helper function for inet_ntop for IPv6 addresses.
|
||||
const char* inet_ntop_v6(const void* src, char* dst, socklen_t size) {
|
||||
if (size < INET6_ADDRSTRLEN) {
|
||||
return nullptr;
|
||||
}
|
||||
const uint16_t* as_shorts = reinterpret_cast<const uint16_t*>(src);
|
||||
int runpos[8];
|
||||
int current = 1;
|
||||
int max = 0;
|
||||
int maxpos = -1;
|
||||
int run_array_size = arraysize(runpos);
|
||||
// Run over the address marking runs of 0s.
|
||||
for (int i = 0; i < run_array_size; ++i) {
|
||||
if (as_shorts[i] == 0) {
|
||||
runpos[i] = current;
|
||||
if (current > max) {
|
||||
maxpos = i;
|
||||
max = current;
|
||||
}
|
||||
++current;
|
||||
} else {
|
||||
runpos[i] = -1;
|
||||
current = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (max > 0) {
|
||||
int tmpmax = maxpos;
|
||||
// Run back through, setting -1 for all but the longest run.
|
||||
for (int i = run_array_size - 1; i >= 0; i--) {
|
||||
if (i > tmpmax) {
|
||||
runpos[i] = -1;
|
||||
} else if (runpos[i] == -1) {
|
||||
// We're less than maxpos, we hit a -1, so the 'good' run is done.
|
||||
// Setting tmpmax -1 means all remaining positions get set to -1.
|
||||
tmpmax = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* cursor = dst;
|
||||
// Print IPv4 compatible and IPv4 mapped addresses using the IPv4 helper.
|
||||
// These addresses have an initial run of either eight zero-bytes followed
|
||||
// by 0xFFFF, or an initial run of ten zero-bytes.
|
||||
if (runpos[0] == 1 &&
|
||||
(maxpos == 5 || (maxpos == 4 && as_shorts[5] == 0xFFFF))) {
|
||||
*cursor++ = ':';
|
||||
*cursor++ = ':';
|
||||
if (maxpos == 4) {
|
||||
cursor += snprintf(cursor, INET6_ADDRSTRLEN - 2, "ffff:");
|
||||
}
|
||||
const struct in_addr* as_v4 =
|
||||
reinterpret_cast<const struct in_addr*>(&(as_shorts[6]));
|
||||
inet_ntop_v4(as_v4, cursor,
|
||||
static_cast<socklen_t>(INET6_ADDRSTRLEN - (cursor - dst)));
|
||||
} else {
|
||||
for (int i = 0; i < run_array_size; ++i) {
|
||||
if (runpos[i] == -1) {
|
||||
cursor += snprintf(cursor, INET6_ADDRSTRLEN - (cursor - dst), "%x",
|
||||
NetworkToHost16(as_shorts[i]));
|
||||
if (i != 7 && runpos[i + 1] != 1) {
|
||||
*cursor++ = ':';
|
||||
}
|
||||
} else if (runpos[i] == 1) {
|
||||
// Entered the run; print the colons and skip the run.
|
||||
*cursor++ = ':';
|
||||
*cursor++ = ':';
|
||||
i += (max - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Helper function for inet_pton for IPv4 addresses.
|
||||
// `src` points to a character string containing an IPv4 network address in
|
||||
// dotted-decimal format, "ddd.ddd.ddd.ddd", where ddd is a decimal number
|
||||
// of up to three digits in the range 0 to 255.
|
||||
// The address is converted and copied to dst,
|
||||
// which must be sizeof(struct in_addr) (4) bytes (32 bits) long.
|
||||
int inet_pton_v4(const char* src, void* dst) {
|
||||
const int kIpv4AddressSize = 4;
|
||||
int found = 0;
|
||||
const char* src_pos = src;
|
||||
unsigned char result[kIpv4AddressSize] = {0};
|
||||
|
||||
while (*src_pos != '\0') {
|
||||
// strtol won't treat whitespace characters in the begining as an error,
|
||||
// so check to ensure this is started with digit before passing to strtol.
|
||||
if (!isdigit(*src_pos)) {
|
||||
return 0;
|
||||
}
|
||||
char* end_pos;
|
||||
long value = strtol(src_pos, &end_pos, 10);
|
||||
if (value < 0 || value > 255 || src_pos == end_pos) {
|
||||
return 0;
|
||||
}
|
||||
++found;
|
||||
if (found > kIpv4AddressSize) {
|
||||
return 0;
|
||||
}
|
||||
result[found - 1] = static_cast<unsigned char>(value);
|
||||
src_pos = end_pos;
|
||||
if (*src_pos == '.') {
|
||||
// There's more.
|
||||
++src_pos;
|
||||
} else if (*src_pos != '\0') {
|
||||
// If it's neither '.' nor '\0' then return fail.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (found != kIpv4AddressSize) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(dst, result, sizeof(result));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Helper function for inet_pton for IPv6 addresses.
|
||||
int inet_pton_v6(const char* src, void* dst) {
|
||||
// sscanf will pick any other invalid chars up, but it parses 0xnnnn as hex.
|
||||
// Check for literal x in the input string.
|
||||
const char* readcursor = src;
|
||||
char c = *readcursor++;
|
||||
while (c) {
|
||||
if (c == 'x') {
|
||||
return 0;
|
||||
}
|
||||
c = *readcursor++;
|
||||
}
|
||||
readcursor = src;
|
||||
|
||||
struct in6_addr an_addr;
|
||||
memset(&an_addr, 0, sizeof(an_addr));
|
||||
|
||||
uint16_t* addr_cursor = reinterpret_cast<uint16_t*>(&an_addr.s6_addr[0]);
|
||||
uint16_t* addr_end = reinterpret_cast<uint16_t*>(&an_addr.s6_addr[16]);
|
||||
bool seencompressed = false;
|
||||
|
||||
// Addresses that start with "::" (i.e., a run of initial zeros) or
|
||||
// "::ffff:" can potentially be IPv4 mapped or compatibility addresses.
|
||||
// These have dotted-style IPv4 addresses on the end (e.g. "::192.168.7.1").
|
||||
if (*readcursor == ':' && *(readcursor + 1) == ':' &&
|
||||
*(readcursor + 2) != 0) {
|
||||
// Check for periods, which we'll take as a sign of v4 addresses.
|
||||
const char* addrstart = readcursor + 2;
|
||||
if (strchr(addrstart, '.')) {
|
||||
const char* colon = strchr(addrstart, ':');
|
||||
if (colon) {
|
||||
uint16_t a_short;
|
||||
int bytesread = 0;
|
||||
if (sscanf(addrstart, "%hx%n", &a_short, &bytesread) != 1 ||
|
||||
a_short != 0xFFFF || bytesread != 4) {
|
||||
// Colons + periods means has to be ::ffff:a.b.c.d. But it wasn't.
|
||||
return 0;
|
||||
} else {
|
||||
an_addr.s6_addr[10] = 0xFF;
|
||||
an_addr.s6_addr[11] = 0xFF;
|
||||
addrstart = colon + 1;
|
||||
}
|
||||
}
|
||||
struct in_addr v4;
|
||||
if (inet_pton_v4(addrstart, &v4.s_addr)) {
|
||||
memcpy(&an_addr.s6_addr[12], &v4, sizeof(v4));
|
||||
memcpy(dst, &an_addr, sizeof(an_addr));
|
||||
return 1;
|
||||
} else {
|
||||
// Invalid v4 address.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For addresses without a trailing IPv4 component ('normal' IPv6 addresses).
|
||||
while (*readcursor != 0 && addr_cursor < addr_end) {
|
||||
if (*readcursor == ':') {
|
||||
if (*(readcursor + 1) == ':') {
|
||||
if (seencompressed) {
|
||||
// Can only have one compressed run of zeroes ("::") per address.
|
||||
return 0;
|
||||
}
|
||||
// Hit a compressed run. Count colons to figure out how much of the
|
||||
// address is skipped.
|
||||
readcursor += 2;
|
||||
const char* coloncounter = readcursor;
|
||||
int coloncount = 0;
|
||||
if (*coloncounter == 0) {
|
||||
// Special case - trailing ::.
|
||||
addr_cursor = addr_end;
|
||||
} else {
|
||||
while (*coloncounter) {
|
||||
if (*coloncounter == ':') {
|
||||
++coloncount;
|
||||
}
|
||||
++coloncounter;
|
||||
}
|
||||
// (coloncount + 1) is the number of shorts left in the address.
|
||||
// If this number is greater than the number of available shorts, the
|
||||
// address is malformed.
|
||||
if (coloncount + 1 > addr_end - addr_cursor) {
|
||||
return 0;
|
||||
}
|
||||
addr_cursor = addr_end - (coloncount + 1);
|
||||
seencompressed = true;
|
||||
}
|
||||
} else {
|
||||
++readcursor;
|
||||
}
|
||||
} else {
|
||||
uint16_t word;
|
||||
int bytesread = 0;
|
||||
if (sscanf(readcursor, "%4hx%n", &word, &bytesread) != 1) {
|
||||
return 0;
|
||||
} else {
|
||||
*addr_cursor = HostToNetwork16(word);
|
||||
++addr_cursor;
|
||||
readcursor += bytesread;
|
||||
if (*readcursor != ':' && *readcursor != '\0') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*readcursor != '\0' || addr_cursor < addr_end) {
|
||||
// Catches addresses too short or too long.
|
||||
return 0;
|
||||
}
|
||||
memcpy(dst, &an_addr, sizeof(an_addr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004 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 RTC_BASE_WIN32_H_
|
||||
#define RTC_BASE_WIN32_H_
|
||||
|
||||
#ifndef _WIN32
|
||||
#error "Only #include this header in Windows builds"
|
||||
#endif
|
||||
|
||||
// Make sure we don't get min/max macros
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <winsock2.h>
|
||||
|
||||
// Must be after winsock2.h.
|
||||
#include <windows.h>
|
||||
|
||||
typedef int socklen_t;
|
||||
|
||||
#ifndef SECURITY_MANDATORY_LABEL_AUTHORITY
|
||||
// Add defines that we use if we are compiling against older sdks
|
||||
#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
|
||||
#define TokenIntegrityLevel static_cast<TOKEN_INFORMATION_CLASS>(0x19)
|
||||
typedef struct _TOKEN_MANDATORY_LABEL {
|
||||
SID_AND_ATTRIBUTES Label;
|
||||
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
|
||||
#endif // SECURITY_MANDATORY_LABEL_AUTHORITY
|
||||
|
||||
#undef SetPort
|
||||
|
||||
namespace rtc {
|
||||
|
||||
const char* win32_inet_ntop(int af, const void* src, char* dst, socklen_t size);
|
||||
int win32_inet_pton(int af, const char* src, void* dst);
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_WIN32_H_
|
||||
@@ -1,44 +0,0 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
template <typename U>
|
||||
inline bool IsNewer(U value, U prev_value) {
|
||||
static_assert(!std::numeric_limits<U>::is_signed, "U must be unsigned");
|
||||
// kBreakpoint is the half-way mark for the type U. For instance, for a
|
||||
// uint16_t it will be 0x8000, and for a uint32_t, it will be 0x8000000.
|
||||
constexpr U kBreakpoint = (std::numeric_limits<U>::max() >> 1) + 1;
|
||||
// Distinguish between elements that are exactly kBreakpoint apart.
|
||||
// If t1>t2 and |t1-t2| = kBreakpoint: IsNewer(t1,t2)=true,
|
||||
// IsNewer(t2,t1)=false
|
||||
// rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
|
||||
if (value - prev_value == kBreakpoint) {
|
||||
return value > prev_value;
|
||||
}
|
||||
return value != prev_value &&
|
||||
static_cast<U>(value - prev_value) < kBreakpoint;
|
||||
}
|
||||
|
||||
// NB: Doesn't fulfill strict weak ordering requirements.
|
||||
// Mustn't be used as std::map Compare function.
|
||||
inline bool IsNewerSequenceNumber(uint16_t sequence_number,
|
||||
uint16_t prev_sequence_number) {
|
||||
return IsNewer(sequence_number, prev_sequence_number);
|
||||
}
|
||||
|
||||
// NB: Doesn't fulfill strict weak ordering requirements.
|
||||
// Mustn't be used as std::map Compare function.
|
||||
inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
|
||||
return IsNewer(timestamp, prev_timestamp);
|
||||
}
|
||||
|
||||
inline uint16_t LatestSequenceNumber(uint16_t sequence_number1,
|
||||
uint16_t sequence_number2) {
|
||||
return IsNewerSequenceNumber(sequence_number1, sequence_number2)
|
||||
? sequence_number1
|
||||
: sequence_number2;
|
||||
}
|
||||
|
||||
inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
|
||||
return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-03-14
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _TASK_QUEUE_H_
|
||||
#define _TASK_QUEUE_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "any_invocable.h"
|
||||
|
||||
class TaskQueue {
|
||||
public:
|
||||
TaskQueue(std::string task_name, size_t numThreads = 1)
|
||||
: task_name_(task_name),
|
||||
stop_(false),
|
||||
workers_(),
|
||||
taskQueue_(),
|
||||
mutex_(),
|
||||
cond_var_() {
|
||||
for (size_t i = 0; i < numThreads; i++) {
|
||||
workers_.emplace_back([this]() { this->WorkerThread(); });
|
||||
}
|
||||
}
|
||||
|
||||
~TaskQueue() {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
stop_ = true;
|
||||
}
|
||||
cond_var_.notify_all();
|
||||
for (std::thread &worker : workers_) {
|
||||
if (worker.joinable()) {
|
||||
worker.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PostTask(AnyInvocable<void()> task) {
|
||||
PostDelayedTask(std::move(task), 0);
|
||||
}
|
||||
|
||||
void PostDelayedTask(AnyInvocable<void()> task, int delay_ms) {
|
||||
auto execute_time =
|
||||
std::chrono::steady_clock::now() + std::chrono::milliseconds(delay_ms);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
taskQueue_.emplace(execute_time, std::move(task));
|
||||
}
|
||||
cond_var_.notify_one();
|
||||
}
|
||||
|
||||
void ClearTasks() {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
stop_ = true;
|
||||
while (!taskQueue_.empty()) {
|
||||
taskQueue_.pop();
|
||||
}
|
||||
}
|
||||
cond_var_.notify_all();
|
||||
for (std::thread &worker : workers_) {
|
||||
if (worker.joinable()) {
|
||||
worker.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct TaskItem {
|
||||
std::chrono::steady_clock::time_point execute_time;
|
||||
AnyInvocable<void()> task = nullptr;
|
||||
|
||||
TaskItem(std::chrono::steady_clock::time_point time,
|
||||
AnyInvocable<void()> func)
|
||||
: execute_time(time), task(std::move(func)) {}
|
||||
|
||||
bool operator>(const TaskItem &other) const {
|
||||
return execute_time > other.execute_time;
|
||||
}
|
||||
};
|
||||
|
||||
void WorkerThread() {
|
||||
while (true) {
|
||||
AnyInvocable<void()> task;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cond_var_.wait(lock, [this]() { return !taskQueue_.empty() || stop_; });
|
||||
|
||||
if (stop_ && taskQueue_.empty()) return;
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (taskQueue_.top().execute_time > now) {
|
||||
cond_var_.wait_until(lock, taskQueue_.top().execute_time,
|
||||
[this]() { return stop_; });
|
||||
}
|
||||
|
||||
if (stop_ && taskQueue_.empty()) return;
|
||||
|
||||
task = std::move(
|
||||
const_cast<AnyInvocable<void()> &>(taskQueue_.top().task));
|
||||
taskQueue_.pop();
|
||||
}
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
std::string task_name_;
|
||||
std::vector<std::thread> workers_;
|
||||
std::priority_queue<TaskItem, std::vector<TaskItem>, std::greater<>>
|
||||
taskQueue_;
|
||||
mutable std::mutex mutex_;
|
||||
std::condition_variable cond_var_;
|
||||
bool stop_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,127 +0,0 @@
|
||||
#include "fec_decoder.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
FecDecoder::FecDecoder() {}
|
||||
|
||||
FecDecoder::~FecDecoder() {}
|
||||
|
||||
int FecDecoder::Init() {
|
||||
fec_codec_id_ = OF_CODEC_REED_SOLOMON_GF_2_M_STABLE;
|
||||
|
||||
fec_rs_params_ = (of_rs_2_m_parameters_t *)calloc(1, sizeof(*fec_params_));
|
||||
if (nullptr == fec_rs_params_) {
|
||||
LOG_ERROR("Create FEC decoder params failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fec_rs_params_->m = 8;
|
||||
fec_params_ = (of_parameters_t *)fec_rs_params_;
|
||||
|
||||
if (OF_STATUS_OK !=
|
||||
of_create_codec_instance(&fec_session_, fec_codec_id_, OF_DECODER, 2)) {
|
||||
LOG_ERROR("Create FEC decoder instance failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FecDecoder::Release() {
|
||||
if (!fec_session_) {
|
||||
LOG_ERROR("Invalid FEC decoder instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
if (OF_STATUS_OK != of_release_codec_instance(fec_session_)) {
|
||||
LOG_ERROR("Release FEC decoder instance failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fec_rs_params_) {
|
||||
free(fec_rs_params_);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FecDecoder::ResetParams(unsigned int source_symbol_num) {
|
||||
if (!fec_session_) {
|
||||
LOG_ERROR("Invalid FEC decoder instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_of_received_symbols_ = 0;
|
||||
num_of_source_packets_ = source_symbol_num;
|
||||
num_of_total_packets_ =
|
||||
(unsigned int)floor((double)source_symbol_num / (double)code_rate_);
|
||||
|
||||
LOG_ERROR("Set s[{}] r[{}]", num_of_source_packets_,
|
||||
num_of_total_packets_ - source_symbol_num);
|
||||
|
||||
fec_params_->nb_source_symbols = source_symbol_num;
|
||||
fec_params_->nb_repair_symbols = num_of_total_packets_ - source_symbol_num;
|
||||
fec_params_->encoding_symbol_length = max_size_of_packet_;
|
||||
|
||||
if (OF_STATUS_OK != of_set_fec_parameters(fec_session_, fec_params_)) {
|
||||
LOG_ERROR("Set FEC params failed for codec_id {}", (int)fec_codec_id_);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t **FecDecoder::DecodeWithNewSymbol(const char *fec_symbol,
|
||||
unsigned int fec_symbol_id) {
|
||||
if (!fec_session_) {
|
||||
LOG_ERROR("Invalid FEC decoder instance");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
num_of_received_symbols_++;
|
||||
if (OF_STATUS_ERROR == of_decode_with_new_symbol(
|
||||
fec_session_, (char *)fec_symbol, fec_symbol_id)) {
|
||||
LOG_ERROR("Decode wit new symbol failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((num_of_received_symbols_ >= fec_params_->nb_source_symbols) &&
|
||||
(true == of_is_decoding_complete(fec_session_))) {
|
||||
uint8_t **source_packets =
|
||||
(uint8_t **)calloc(num_of_total_packets_, sizeof(uint8_t *));
|
||||
if (!source_packets) {
|
||||
LOG_ERROR("Calloc failed for source_packets with size [{}])",
|
||||
num_of_total_packets_);
|
||||
}
|
||||
|
||||
if (OF_STATUS_OK !=
|
||||
of_get_source_symbols_tab(fec_session_, (void **)source_packets)) {
|
||||
LOG_ERROR("Get source symbols failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return source_packets;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int FecDecoder::ReleaseSourcePackets(uint8_t **source_packets) {
|
||||
if (nullptr == source_packets) {
|
||||
LOG_ERROR(
|
||||
"Release source packets failed, due to source_packets is nullptr");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// for (unsigned int index = 0; index < num_of_source_packets_; index++) {
|
||||
// if (source_packets[index]) {
|
||||
// LOG_ERROR("Free [{}]", index);
|
||||
// free(source_packets[index]);
|
||||
// }
|
||||
// }
|
||||
free(source_packets);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-11-15
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _FEC_DECODER_H_
|
||||
#define _FEC_DECODER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "lib_common/of_openfec_api.h"
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
class FecDecoder {
|
||||
public:
|
||||
FecDecoder();
|
||||
~FecDecoder();
|
||||
|
||||
public:
|
||||
int Init();
|
||||
int Release();
|
||||
int ResetParams(unsigned int source_symbol_num);
|
||||
uint8_t **DecodeWithNewSymbol(const char *fec_symbol,
|
||||
unsigned int fec_symbol_id);
|
||||
int ReleaseSourcePackets(uint8_t **source_packets);
|
||||
|
||||
private:
|
||||
double code_rate_ = 0.667;
|
||||
int max_size_of_packet_ = 1400;
|
||||
|
||||
private:
|
||||
of_codec_id_t fec_codec_id_ = OF_CODEC_REED_SOLOMON_GF_2_M_STABLE;
|
||||
of_session_t *fec_session_ = nullptr;
|
||||
of_parameters_t *fec_params_ = nullptr;
|
||||
of_rs_2_m_parameters_t *fec_rs_params_ = nullptr;
|
||||
of_ldpc_parameters_t *fec_ldpc_params_ = nullptr;
|
||||
|
||||
unsigned int num_of_received_symbols_ = 0;
|
||||
unsigned int num_of_source_packets_ = 0;
|
||||
unsigned int num_of_total_packets_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,153 +0,0 @@
|
||||
#include "fec_encoder.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
FecEncoder::FecEncoder() {}
|
||||
|
||||
FecEncoder::~FecEncoder() {}
|
||||
|
||||
int FecEncoder::Init() {
|
||||
fec_codec_id_ = OF_CODEC_REED_SOLOMON_GF_2_M_STABLE;
|
||||
|
||||
fec_rs_params_ = (of_rs_2_m_parameters_t *)calloc(1, sizeof(*fec_params_));
|
||||
if (nullptr == fec_rs_params_) {
|
||||
LOG_ERROR("Create FEC codec params failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fec_rs_params_->m = 8;
|
||||
fec_params_ = (of_parameters_t *)fec_rs_params_;
|
||||
|
||||
if (OF_STATUS_OK !=
|
||||
of_create_codec_instance(&fec_session_, fec_codec_id_, OF_ENCODER, 2)) {
|
||||
LOG_ERROR("Create FEC codec instance failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FecEncoder::Release() {
|
||||
if (!fec_session_) {
|
||||
LOG_ERROR("Invalid FEC codec instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
if (OF_STATUS_OK != of_release_codec_instance(fec_session_)) {
|
||||
LOG_ERROR("Release FEC codec instance failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fec_rs_params_) {
|
||||
free(fec_rs_params_);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t **FecEncoder::Encode(const char *data, size_t len) {
|
||||
uint8_t **fec_packets = nullptr;
|
||||
|
||||
unsigned int last_packet_size = len % max_size_of_packet_;
|
||||
uint8_t num_of_source_packets =
|
||||
(uint8_t)(len / max_size_of_packet_) + (last_packet_size ? 1 : 0);
|
||||
uint8_t num_of_total_packets =
|
||||
(uint8_t)floor((double)num_of_source_packets / code_rate_);
|
||||
|
||||
fec_params_->nb_source_symbols = num_of_source_packets;
|
||||
fec_params_->nb_repair_symbols = num_of_total_packets - num_of_source_packets;
|
||||
|
||||
fec_params_->encoding_symbol_length = max_size_of_packet_;
|
||||
|
||||
if (OF_STATUS_OK != of_set_fec_parameters(fec_session_, fec_params_)) {
|
||||
LOG_ERROR("Set FEC params failed for codec_id {}", (int)fec_codec_id_);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fec_packets = (uint8_t **)calloc(num_of_total_packets, sizeof(uint8_t *));
|
||||
|
||||
if (nullptr == fec_packets) {
|
||||
LOG_ERROR("Calloc failed for fec_packets with size [{}])",
|
||||
num_of_total_packets);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int esi = 0; esi < num_of_source_packets; esi++) {
|
||||
if (esi != (num_of_source_packets - 1)) {
|
||||
fec_packets[esi] =
|
||||
(uint8_t *)calloc(max_size_of_packet_, sizeof(uint8_t));
|
||||
if (nullptr == fec_packets[esi]) {
|
||||
LOG_ERROR("Calloc failed for fec_packets[{}] with size [{}])", esi,
|
||||
max_size_of_packet_);
|
||||
ReleaseFecPackets(fec_packets, len);
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(fec_packets[esi], data + esi * max_size_of_packet_,
|
||||
max_size_of_packet_);
|
||||
} else {
|
||||
fec_packets[esi] =
|
||||
(uint8_t *)calloc(max_size_of_packet_, sizeof(uint8_t));
|
||||
if (nullptr == fec_packets[esi]) {
|
||||
LOG_ERROR("Calloc failed for fec_packets[{}] with size [{}])", esi,
|
||||
last_packet_size);
|
||||
ReleaseFecPackets(fec_packets, len);
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(fec_packets[esi], data + esi * max_size_of_packet_,
|
||||
last_packet_size);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int esi = num_of_source_packets; esi < num_of_total_packets;
|
||||
esi++) {
|
||||
fec_packets[esi] = (uint8_t *)calloc(max_size_of_packet_, sizeof(uint8_t));
|
||||
if (nullptr == fec_packets[esi]) {
|
||||
LOG_ERROR("Calloc failed for fec_packets[{}] with size [{}])", esi,
|
||||
max_size_of_packet_);
|
||||
ReleaseFecPackets(fec_packets, len);
|
||||
return nullptr;
|
||||
}
|
||||
if (OF_STATUS_OK !=
|
||||
of_build_repair_symbol(fec_session_, (void **)fec_packets, esi)) {
|
||||
LOG_ERROR("Build repair symbols failed for esi [{}]", esi);
|
||||
ReleaseFecPackets(fec_packets, len);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return fec_packets;
|
||||
}
|
||||
|
||||
int FecEncoder::ReleaseFecPackets(uint8_t **fec_packets, size_t len) {
|
||||
if (nullptr == fec_packets) {
|
||||
LOG_ERROR("Release Fec packets failed, due to fec_packets is nullptr");
|
||||
return -1;
|
||||
}
|
||||
unsigned int last_packet_size = len % max_size_of_packet_;
|
||||
uint8_t num_of_source_packets =
|
||||
(uint8_t)(len / max_size_of_packet_) + (last_packet_size ? 1 : 0);
|
||||
uint8_t num_of_total_packets =
|
||||
(uint8_t)floor((double)num_of_source_packets / code_rate_);
|
||||
|
||||
for (int esi = 0; esi < num_of_total_packets; esi++) {
|
||||
if (fec_packets[esi]) {
|
||||
free(fec_packets[esi]);
|
||||
}
|
||||
}
|
||||
free(fec_packets);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FecEncoder::GetFecPacketsParams(unsigned int source_length,
|
||||
uint8_t &num_of_total_packets,
|
||||
uint8_t &num_of_source_packets,
|
||||
unsigned int &last_packet_size) {
|
||||
last_packet_size = source_length % max_size_of_packet_;
|
||||
num_of_source_packets = (uint8_t)(source_length / max_size_of_packet_) +
|
||||
(last_packet_size ? 1 : 0);
|
||||
num_of_total_packets =
|
||||
(uint8_t)floor((double)num_of_source_packets / code_rate_);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-11-13
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _FEC_ENCODER_H_
|
||||
#define _FEC_ENCODER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "lib_common/of_openfec_api.h"
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
class FecEncoder {
|
||||
public:
|
||||
FecEncoder();
|
||||
~FecEncoder();
|
||||
|
||||
public:
|
||||
int Init();
|
||||
int Release();
|
||||
uint8_t **Encode(const char *data, size_t len);
|
||||
int ReleaseFecPackets(uint8_t **fec_packets, size_t len);
|
||||
void GetFecPacketsParams(unsigned int source_length,
|
||||
uint8_t &num_of_total_packets,
|
||||
uint8_t &num_of_source_packets,
|
||||
unsigned int &last_packet_size);
|
||||
|
||||
private:
|
||||
double code_rate_ = 0.667;
|
||||
int max_size_of_packet_ = 1400;
|
||||
|
||||
private:
|
||||
of_codec_id_t fec_codec_id_ = OF_CODEC_REED_SOLOMON_GF_2_M_STABLE;
|
||||
of_session_t *fec_session_ = nullptr;
|
||||
of_parameters_t *fec_params_ = nullptr;
|
||||
of_rs_2_m_parameters_t *fec_rs_params_ = nullptr;
|
||||
of_ldpc_parameters_t *fec_ldpc_params_ = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,91 +0,0 @@
|
||||
#include "audio_frame.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
AudioFrame::AudioFrame() {}
|
||||
|
||||
AudioFrame::AudioFrame(size_t size) {
|
||||
buffer_ = new uint8_t[size];
|
||||
size_ = size;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
}
|
||||
|
||||
AudioFrame::AudioFrame(const uint8_t *buffer, size_t size) {
|
||||
buffer_ = new uint8_t[size];
|
||||
memcpy(buffer_, buffer, size);
|
||||
size_ = size;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
}
|
||||
|
||||
AudioFrame::AudioFrame(const uint8_t *buffer, size_t size, size_t width,
|
||||
size_t height) {
|
||||
buffer_ = new uint8_t[size];
|
||||
memcpy(buffer_, buffer, size);
|
||||
size_ = size;
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
|
||||
AudioFrame::AudioFrame(const AudioFrame &audio_frame) {
|
||||
if (audio_frame.size_ > 0) {
|
||||
buffer_ = new uint8_t[audio_frame.size_];
|
||||
memcpy(buffer_, audio_frame.buffer_, audio_frame.size_);
|
||||
size_ = audio_frame.size_;
|
||||
width_ = audio_frame.width_;
|
||||
height_ = audio_frame.height_;
|
||||
}
|
||||
}
|
||||
|
||||
AudioFrame::AudioFrame(AudioFrame &&audio_frame)
|
||||
: buffer_((uint8_t *)std::move(audio_frame.buffer_)),
|
||||
size_(audio_frame.size_),
|
||||
width_(audio_frame.width_),
|
||||
height_(audio_frame.height_) {
|
||||
audio_frame.buffer_ = nullptr;
|
||||
audio_frame.size_ = 0;
|
||||
audio_frame.width_ = 0;
|
||||
audio_frame.height_ = 0;
|
||||
}
|
||||
|
||||
AudioFrame &AudioFrame::operator=(const AudioFrame &audio_frame) {
|
||||
if (&audio_frame != this) {
|
||||
if (buffer_) {
|
||||
delete buffer_;
|
||||
buffer_ = nullptr;
|
||||
}
|
||||
buffer_ = new uint8_t[audio_frame.size_];
|
||||
memcpy(buffer_, audio_frame.buffer_, audio_frame.size_);
|
||||
size_ = audio_frame.size_;
|
||||
width_ = audio_frame.width_;
|
||||
height_ = audio_frame.height_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
AudioFrame &AudioFrame::operator=(AudioFrame &&audio_frame) {
|
||||
if (&audio_frame != this) {
|
||||
buffer_ = std::move(audio_frame.buffer_);
|
||||
audio_frame.buffer_ = nullptr;
|
||||
size_ = audio_frame.size_;
|
||||
audio_frame.size_ = 0;
|
||||
width_ = audio_frame.width_;
|
||||
audio_frame.width_ = 0;
|
||||
height_ = audio_frame.height_;
|
||||
audio_frame.height_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
AudioFrame::~AudioFrame() {
|
||||
if (buffer_) {
|
||||
delete buffer_;
|
||||
buffer_ = nullptr;
|
||||
}
|
||||
|
||||
size_ = 0;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-11-24
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _AUDIO_FRAME_H_
|
||||
#define _AUDIO_FRAME_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
class AudioFrame {
|
||||
public:
|
||||
AudioFrame();
|
||||
AudioFrame(size_t size);
|
||||
AudioFrame(const uint8_t *buffer, size_t size);
|
||||
AudioFrame(const uint8_t *buffer, size_t size, size_t width, size_t height);
|
||||
AudioFrame(const AudioFrame &audio_frame);
|
||||
AudioFrame(AudioFrame &&audio_frame);
|
||||
AudioFrame &operator=(const AudioFrame &audio_frame);
|
||||
AudioFrame &operator=(AudioFrame &&audio_frame);
|
||||
|
||||
~AudioFrame();
|
||||
|
||||
public:
|
||||
const uint8_t *Buffer() { return buffer_; }
|
||||
size_t Size() { return size_; }
|
||||
|
||||
uint8_t *GetBuffer() { return buffer_; }
|
||||
|
||||
private:
|
||||
size_t width_ = 0;
|
||||
size_t height_ = 0;
|
||||
uint8_t *buffer_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-03-19
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DECODED_FRAME_H_
|
||||
#define _DECODED_FRAME_H_
|
||||
|
||||
#include "video_frame.h"
|
||||
|
||||
class DecodedFrame : public VideoFrame {
|
||||
public:
|
||||
DecodedFrame(const uint8_t *buffer, size_t size, uint32_t width,
|
||||
uint32_t height)
|
||||
: VideoFrame(buffer, size, width, height) {}
|
||||
DecodedFrame(const uint8_t *buffer, size_t size) : VideoFrame(buffer, size) {}
|
||||
DecodedFrame(size_t size, uint32_t width, uint32_t height)
|
||||
: VideoFrame(size, width, height) {}
|
||||
DecodedFrame() = default;
|
||||
~DecodedFrame() = default;
|
||||
|
||||
int64_t ReceivedTimestamp() const { return received_timestamp_us_; }
|
||||
|
||||
void SetReceivedTimestamp(int64_t received_timestamp_us) {
|
||||
received_timestamp_us_ = received_timestamp_us;
|
||||
}
|
||||
|
||||
int64_t CapturedTimestamp() const { return captured_timestamp_us_; }
|
||||
|
||||
void SetCapturedTimestamp(int64_t captured_timestamp_us) {
|
||||
captured_timestamp_us_ = captured_timestamp_us;
|
||||
}
|
||||
|
||||
int64_t DecodedTimestamp() const { return decoded_timestamp_us_; }
|
||||
|
||||
void SetDecodedTimestamp(int64_t decoded_timestamp_us) {
|
||||
decoded_timestamp_us_ = decoded_timestamp_us;
|
||||
}
|
||||
|
||||
uint32_t DecodedWidth() const { return decoded_width_; }
|
||||
|
||||
void SetDecodedWidth(uint32_t decoded_width) {
|
||||
decoded_width_ = decoded_width;
|
||||
}
|
||||
|
||||
uint32_t DecodedHeight() const { return decoded_height_; }
|
||||
|
||||
void SetDecodedHeight(uint32_t decoded_height) {
|
||||
decoded_height_ = decoded_height;
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t received_timestamp_us_ = 0;
|
||||
int64_t captured_timestamp_us_ = 0;
|
||||
int64_t decoded_timestamp_us_ = 0;
|
||||
uint32_t decoded_width_ = 0;
|
||||
uint32_t decoded_height_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-03-19
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ENCODED_FRAME_H_
|
||||
#define _ENCODED_FRAME_H_
|
||||
|
||||
#include "video_frame.h"
|
||||
|
||||
class EncodedFrame : public VideoFrame {
|
||||
public:
|
||||
EncodedFrame(const uint8_t *buffer, size_t size, uint32_t width,
|
||||
uint32_t height)
|
||||
: VideoFrame(buffer, size, width, height) {}
|
||||
EncodedFrame(const uint8_t *buffer, size_t size) : VideoFrame(buffer, size) {}
|
||||
EncodedFrame(size_t size, uint32_t width, uint32_t height)
|
||||
: VideoFrame(size, width, height) {}
|
||||
EncodedFrame() = default;
|
||||
~EncodedFrame() = default;
|
||||
|
||||
int64_t CapturedTimestamp() const { return captured_timestamp_us_; }
|
||||
|
||||
void SetCapturedTimestamp(int64_t captured_timestamp_us) {
|
||||
captured_timestamp_us_ = captured_timestamp_us;
|
||||
}
|
||||
|
||||
int64_t EncodedTimestamp() const { return encoded_timestamp_us_; }
|
||||
|
||||
void SetEncodedTimestamp(int64_t encoded_timestamp_us) {
|
||||
encoded_timestamp_us_ = encoded_timestamp_us;
|
||||
}
|
||||
|
||||
VideoFrameType FrameType() const { return frame_type_; }
|
||||
|
||||
void SetFrameType(VideoFrameType frame_type) { frame_type_ = frame_type; }
|
||||
|
||||
uint32_t EncodedWidth() const { return encoded_width_; }
|
||||
|
||||
void SetEncodedWidth(uint32_t encoded_width) {
|
||||
encoded_width_ = encoded_width;
|
||||
}
|
||||
|
||||
uint32_t EncodedHeight() const { return encoded_height_; }
|
||||
|
||||
void SetEncodedHeight(uint32_t encoded_height) {
|
||||
encoded_height_ = encoded_height;
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t captured_timestamp_us_ = 0;
|
||||
int64_t encoded_timestamp_us_ = 0;
|
||||
VideoFrameType frame_type_ = VideoFrameType::kVideoFrameDelta;
|
||||
uint32_t encoded_width_ = 0;
|
||||
uint32_t encoded_height_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user