Compare commits

..

74 Commits

Author SHA1 Message Date
dijunkun 2d6cfb5c76 Support cursor control on MacOS 2023-12-06 15:24:01 +08:00
dijunkun ed8b536ac0 Add signal connection status 'NoSuchTransmissionId' 2023-12-04 14:04:36 +08:00
dijunkun 5e2d27e9d2 Fix ffmpeg link error on MacOS 2023-12-04 11:20:30 +08:00
dijunkun 47a2dc85f9 Fix screen capture on MacOS 2023-12-01 17:16:38 +08:00
dijunkun 5febe99bc2 Support screen capture on MacOS 2023-12-01 16:54:17 +08:00
dijunkun 97bed80088 Fix link flag for MacOS 2023-12-01 10:12:06 +08:00
dijunkun 070f7bd21e Disable ffmpeg openh264 codec 2023-11-29 22:57:29 -08:00
dijunkun 4a65a59803 Enable audio transmission 2023-11-29 22:04:53 -08:00
dijunkun 733434f9b3 Switch rtc core to branch opus 2023-11-21 22:36:36 -08:00
dijunkun 7b7787f638 Add audio capture test 2023-11-21 22:32:06 -08:00
dijunkun b64d399967 Capture full screen and resize to 1280x720 for Linux platform 2023-11-20 23:11:21 -08:00
dijunkun 65f9862929 Enable password checking when login 2023-11-20 22:48:18 -08:00
dijunkun 3065c15631 Save password in cache 2023-11-20 22:24:27 -08:00
dijunkun e28de1fbda Change folder name 2023-11-19 23:41:58 -08:00
dijunkun e802306148 Fix compile error 2023-11-19 23:30:41 -08:00
dijunkun 4a16857da8 Support generate makefile 2023-11-17 00:38:13 -08:00
dijunkun 6776b915da Do not refresh display frame if disconnected 2023-11-16 00:38:29 -08:00
dijunkun 311b94492a Fix received_frame flag error in display client 2023-11-16 00:32:52 -08:00
dijunkun be659f8e49 Fix display error on Linux 2023-11-16 00:27:45 -08:00
dijunkun 375d849786 Add library OpenFEC v1.4.2 2023-11-09 01:00:39 -08:00
dijunkun b347b160e2 Fix x11 screen capture memory leakage 2023-11-08 01:20:02 -08:00
dijunkun 31e5d5025a OpenH264 supports Windows platform 2023-11-07 15:27:57 +08:00
dijunkun 61b2eb2fdb Fix openh264 decode error caused by yuv stride 2023-11-06 19:02:39 -08:00
dijunkun a64655dec9 Implementation for openh264 codec 2023-11-03 02:31:57 -07:00
dijunkun 3399d43501 1.ImGUI display success; 2.To do: fix x264 encode green screen 2023-11-02 02:34:14 -07:00
dijunkun 5fb35ecd77 Fix ffmpeg link error on Linux platform 2023-11-01 21:42:35 -07:00
dijunkun 7a28cab427 Update x11 capture module 2023-10-31 02:35:53 -07:00
dijunkun a114ffdb36 Update linux capture module 2023-10-30 02:33:39 -07:00
dijunkun f766330039 Nice connection supports MacOSx 2023-10-16 13:56:21 +08:00
dijunkun 6b8e33b83c Add callback for connection status 2023-10-11 17:01:14 +08:00
dijunkun 9c16a24867 Not control mouse in DEBUG mode 2023-10-11 16:17:13 +08:00
dijunkun c5f2f6cf82 Add feature password 2023-10-11 16:03:22 +08:00
dijunkun 8064130356 Fix remote id cannot modify error 2023-10-11 15:20:53 +08:00
dijunkun 60c3390203 Fix default display resolution to 720p and change resize strategy 2023-10-11 14:58:04 +08:00
dijunkun f246ab8720 Fix signal server member list error when rejoin same one connection 2023-10-11 14:26:57 +08:00
dijunkun b887fcbf86 Fix ice status check error 2023-10-11 09:45:58 +08:00
dijunkun 7216d318b4 Fix crash during rejoin connection 2023-10-10 17:09:24 +08:00
dijunkun cb842276e8 Add password for connection 2023-10-10 16:21:04 +08:00
dijunkun 1acd613b45 Fix windows compile error 2023-10-10 11:05:15 +08:00
dijunkun 0bfe3bdfd0 Fix MacOSX compile error 2023-10-10 10:59:36 +08:00
dijunkun 610f89a828 Finish remote desk gui 2023-10-10 10:31:32 +08:00
dijunkun 82ef2a161d Combine server and client into a single program 2023-10-09 17:31:55 +08:00
dijunkun 32c8048430 Add ID input gui 2023-10-09 16:31:47 +08:00
dijunkun cb4648ce72 Fix mouse control 2023-10-09 15:05:10 +08:00
dijunkun ea2f5d319d Eable leave connection 2023-10-09 14:11:29 +08:00
dijunkun 45ccbe1637 Add main menu using imgui 2023-10-08 17:39:28 +08:00
dijunkun 0f2f984286 Use imgui 2023-10-08 16:33:53 +08:00
dijunkun 72d669f8bc Remove dependent for vcpkg::sdl2 2023-10-07 17:33:18 +08:00
dijunkun c2b69a0cf2 Fix cursor map error after resize client window 2023-10-07 15:13:24 +08:00
dijunkun 89fa82b165 Fix cursor position error 2023-10-07 15:12:09 +08:00
dijunkun c5f90e1aee Fix error caused by type 'long' has difference size in difference platforms 2023-10-07 14:43:33 +08:00
dijunkun 7618e4bab9 Fix MacOS compile error 2023-10-07 10:07:45 +08:00
dijunkun 1802453dbb Add -ldl link flag for Linux platform 2023-09-22 15:50:40 +08:00
dijunkun 67e7f2e82b Fix compile compatibility 2023-09-22 14:50:37 +08:00
dijunkun 287b7dbc94 Remote desk client supports Linux platform 2023-09-22 14:48:21 +08:00
dijunkun d20fee4a64 Remote desk client supports MacOS 2023-09-19 17:06:00 +08:00
dijunkun 297410b679 Fix data parse error 2023-09-14 16:32:22 +08:00
dijunkun 1f08c80aab Implementation for user data sending 2023-09-13 17:31:02 +08:00
dijunkun 238eef1c93 Implementation for jitter 2023-09-08 17:45:01 +08:00
dijunkun bde35e3b1c Combine Fu-A subframes into complete h264 frame 2023-09-08 16:09:23 +08:00
dijunkun 955182f5a0 Nalu slices test pass 2023-09-07 15:46:26 +08:00
dijunkun b1180f1e93 1.Implementation for rtp session module; 2.Separate signal server from main project 2023-09-06 11:29:34 +08:00
dijunkun d3e9df260a Use one thread to process render and mouse/key events 2023-09-02 00:20:55 +08:00
dijunkun 2088bf190c Use vcpkg static ffmpeg lib for windows 2023-09-01 21:34:08 +08:00
dijunkun 7dd304b686 Fix crash caused by remote desk client leaves 2023-09-01 18:08:56 +08:00
dijunkun c65e6b7af2 Fix kcp transmission error 2023-08-31 17:49:08 +08:00
dijunkun 72d4982f54 Use kcp as QoS module 2023-08-30 17:44:22 +08:00
dijunkun 1e90d99980 Fix sdl2 resize window 2023-08-30 10:02:58 +08:00
dijunkun a2000ddcd6 Use SDL2 to display BGRA frame 2023-08-30 00:29:08 +08:00
dijunkun ae67ad961e Use sdl2 to display capture screen 2023-08-29 17:33:58 +08:00
dijunkun 76a80e6d07 Remove files 2023-08-29 00:21:33 +08:00
dijunkun d4b1ac1fb8 wgc dll test pass 2023-08-28 17:19:46 +08:00
dijunkun e970bdc929 Add wgc demo 2023-08-28 00:53:55 +08:00
dijunkun 2b5c0ee533 Add application folder 2023-08-24 17:36:28 +08:00
559 changed files with 4391 additions and 97885 deletions
+1 -3
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
[submodule "thirdparty/projectx"]
path = thirdparty/projectx
url = git@github.com:dijunkun/projectx.git
-34
View File
@@ -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
View File
@@ -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.
-87
View File
@@ -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_
-319
View File
@@ -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_
-93
View File
@@ -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
-76
View File
@@ -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_
-127
View File
@@ -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_
-42
View File
@@ -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_
-51
View File
@@ -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_
-136
View File
@@ -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_
-59
View File
@@ -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
-61
View File
@@ -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_
-67
View File
@@ -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_
-107
View File
@@ -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_
-129
View File
@@ -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_
-203
View File
@@ -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
-42
View File
@@ -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_
-124
View File
@@ -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_
-107
View File
@@ -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
-292
View File
@@ -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_
-30
View File
@@ -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
-141
View File
@@ -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_
-26
View File
@@ -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
-60
View File
@@ -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_
-27
View File
@@ -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
-89
View File
@@ -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_
-32
View File
@@ -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
-104
View File
@@ -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_
-30
View File
@@ -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
-120
View File
@@ -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_
-275
View File
@@ -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_
-118
View File
@@ -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
-149
View File
@@ -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_
-390
View File
@@ -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
-140
View File
@@ -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;
}
-40
View File
@@ -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
-6
View File
@@ -1,6 +0,0 @@
#include "common.h"
int CommonDummy()
{
return 0;
}
-88
View File
@@ -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
-58
View File
@@ -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
-65
View File
@@ -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_
-36
View File
@@ -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
-130
View File
@@ -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
-61
View File
@@ -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_
-32
View File
@@ -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_
-39
View File
@@ -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
-64
View File
@@ -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_
-199
View File
@@ -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
-70
View File
@@ -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_
-44
View File
@@ -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
-72
View File
@@ -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_
-27
View File
@@ -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
-93
View File
@@ -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&section=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
-48
View File
@@ -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_
-70
View File
@@ -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_
-132
View File
@@ -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_
-28
View File
@@ -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_
-165
View File
@@ -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_
-318
View File
@@ -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_
-161
View File
@@ -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
-103
View File
@@ -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_
-75
View File
@@ -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_
-100
View File
@@ -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_
-103
View File
@@ -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
-24
View File
@@ -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_
-98
View File
@@ -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_
-233
View File
@@ -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
-132
View File
@@ -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_
-141
View File
@@ -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_
-309
View File
@@ -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
-48
View File
@@ -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_
-44
View File
@@ -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;
}
-126
View File
@@ -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
-127
View File
@@ -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;
}
-50
View File
@@ -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
-153
View File
@@ -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_);
}
-48
View File
@@ -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
-91
View File
@@ -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;
}
-39
View File
@@ -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
-61
View File
@@ -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
-59
View File
@@ -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