Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
7
TMessagesProj/jni/voip/webrtc/rtc_base/OWNERS
Normal file
7
TMessagesProj/jni/voip/webrtc/rtc_base/OWNERS
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
hta@webrtc.org
|
||||
mflodman@webrtc.org
|
||||
tommi@webrtc.org
|
||||
mbonadei@webrtc.org
|
||||
|
||||
per-file rate_statistics*=sprang@webrtc.org
|
||||
per-file rate_statistics*=stefan@webrtc.org
|
||||
32
TMessagesProj/jni/voip/webrtc/rtc_base/arraysize.h
Normal file
32
TMessagesProj/jni/voip/webrtc/rtc_base/arraysize.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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_
|
||||
204
TMessagesProj/jni/voip/webrtc/rtc_base/async_dns_resolver.cc
Normal file
204
TMessagesProj/jni/voip/webrtc/rtc_base/async_dns_resolver.cc
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright 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/async_dns_resolver.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "api/make_ref_counted.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/platform_thread.h"
|
||||
|
||||
#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
|
||||
#include <dispatch/dispatch.h>
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef __native_client__
|
||||
int ResolveHostname(absl::string_view hostname,
|
||||
int family,
|
||||
std::vector<rtc::IPAddress>* addresses) {
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
RTC_LOG(LS_WARNING) << "ResolveHostname() is not implemented for NaCl";
|
||||
return -1;
|
||||
}
|
||||
#else // notdef(__native_client__)
|
||||
int ResolveHostname(absl::string_view hostname,
|
||||
int family,
|
||||
std::vector<rtc::IPAddress>& addresses) {
|
||||
addresses.clear();
|
||||
struct addrinfo* result = nullptr;
|
||||
struct addrinfo hints = {0};
|
||||
hints.ai_family = family;
|
||||
// `family` here will almost always be AF_UNSPEC, because `family` comes from
|
||||
// AsyncResolver::addr_.family(), which comes from a SocketAddress constructed
|
||||
// with a hostname. When a SocketAddress is constructed with a hostname, its
|
||||
// family is AF_UNSPEC. However, if someday in the future we construct
|
||||
// a SocketAddress with both a hostname and a family other than AF_UNSPEC,
|
||||
// then it would be possible to get a specific family value here.
|
||||
|
||||
// The behavior of AF_UNSPEC is roughly "get both ipv4 and ipv6", as
|
||||
// documented by the various operating systems:
|
||||
// Linux: http://man7.org/linux/man-pages/man3/getaddrinfo.3.html
|
||||
// Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/
|
||||
// ms738520(v=vs.85).aspx
|
||||
// Mac: https://developer.apple.com/legacy/library/documentation/Darwin/
|
||||
// Reference/ManPages/man3/getaddrinfo.3.html
|
||||
// Android (source code, not documentation):
|
||||
// https://android.googlesource.com/platform/bionic/+/
|
||||
// 7e0bfb511e85834d7c6cb9631206b62f82701d60/libc/netbsd/net/getaddrinfo.c#1657
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
int ret =
|
||||
getaddrinfo(std::string(hostname).c_str(), nullptr, &hints, &result);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
struct addrinfo* cursor = result;
|
||||
for (; cursor; cursor = cursor->ai_next) {
|
||||
if (family == AF_UNSPEC || cursor->ai_family == family) {
|
||||
rtc::IPAddress ip;
|
||||
if (IPFromAddrInfo(cursor, &ip)) {
|
||||
addresses.push_back(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
freeaddrinfo(result);
|
||||
return 0;
|
||||
}
|
||||
#endif // !__native_client__
|
||||
|
||||
// Special task posting for Mac/iOS
|
||||
#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
|
||||
void GlobalGcdRunTask(void* context) {
|
||||
std::unique_ptr<absl::AnyInvocable<void() &&>> task(
|
||||
static_cast<absl::AnyInvocable<void() &&>*>(context));
|
||||
std::move (*task)();
|
||||
}
|
||||
|
||||
// Post a task into the system-defined global concurrent queue.
|
||||
void PostTaskToGlobalQueue(
|
||||
std::unique_ptr<absl::AnyInvocable<void() &&>> task) {
|
||||
dispatch_async_f(
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
||||
task.release(), &GlobalGcdRunTask);
|
||||
}
|
||||
#endif // defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
|
||||
|
||||
} // namespace
|
||||
|
||||
class AsyncDnsResolver::State : public rtc::RefCountedBase {
|
||||
public:
|
||||
enum class Status {
|
||||
kActive, // Running request, or able to be passed one
|
||||
kFinished, // Request has finished processing
|
||||
kDead // The owning AsyncDnsResolver has been deleted
|
||||
};
|
||||
static rtc::scoped_refptr<AsyncDnsResolver::State> Create() {
|
||||
return rtc::make_ref_counted<AsyncDnsResolver::State>();
|
||||
}
|
||||
|
||||
// Execute the passed function if the state is Active.
|
||||
void Finish(absl::AnyInvocable<void()> function) {
|
||||
webrtc::MutexLock lock(&mutex_);
|
||||
if (status_ != Status::kActive) {
|
||||
return;
|
||||
}
|
||||
status_ = Status::kFinished;
|
||||
function();
|
||||
}
|
||||
void Kill() {
|
||||
webrtc::MutexLock lock(&mutex_);
|
||||
status_ = Status::kDead;
|
||||
}
|
||||
|
||||
private:
|
||||
webrtc::Mutex mutex_;
|
||||
Status status_ RTC_GUARDED_BY(mutex_) = Status::kActive;
|
||||
};
|
||||
|
||||
AsyncDnsResolver::AsyncDnsResolver() : state_(State::Create()) {}
|
||||
|
||||
AsyncDnsResolver::~AsyncDnsResolver() {
|
||||
state_->Kill();
|
||||
}
|
||||
|
||||
void AsyncDnsResolver::Start(const rtc::SocketAddress& addr,
|
||||
absl::AnyInvocable<void()> callback) {
|
||||
Start(addr, addr.family(), std::move(callback));
|
||||
}
|
||||
|
||||
// Start address resolution of the hostname in `addr` matching `family`.
|
||||
void AsyncDnsResolver::Start(const rtc::SocketAddress& addr,
|
||||
int family,
|
||||
absl::AnyInvocable<void()> callback) {
|
||||
RTC_DCHECK_RUN_ON(&result_.sequence_checker_);
|
||||
result_.addr_ = addr;
|
||||
callback_ = std::move(callback);
|
||||
auto thread_function = [this, addr, family, flag = safety_.flag(),
|
||||
caller_task_queue = webrtc::TaskQueueBase::Current(),
|
||||
state = state_] {
|
||||
std::vector<rtc::IPAddress> addresses;
|
||||
int error = ResolveHostname(addr.hostname(), family, addresses);
|
||||
// We assume that the caller task queue is still around if the
|
||||
// AsyncDnsResolver has not been destroyed.
|
||||
state->Finish([this, error, flag, caller_task_queue,
|
||||
addresses = std::move(addresses)]() {
|
||||
caller_task_queue->PostTask(
|
||||
SafeTask(flag, [this, error, addresses = std::move(addresses)] {
|
||||
RTC_DCHECK_RUN_ON(&result_.sequence_checker_);
|
||||
result_.addresses_ = addresses;
|
||||
result_.error_ = error;
|
||||
callback_();
|
||||
}));
|
||||
});
|
||||
};
|
||||
#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
|
||||
PostTaskToGlobalQueue(
|
||||
std::make_unique<absl::AnyInvocable<void() &&>>(thread_function));
|
||||
#else
|
||||
rtc::PlatformThread::SpawnDetached(std::move(thread_function),
|
||||
"AsyncResolver");
|
||||
#endif
|
||||
}
|
||||
|
||||
const AsyncDnsResolverResult& AsyncDnsResolver::result() const {
|
||||
return result_;
|
||||
}
|
||||
|
||||
bool AsyncDnsResolverResultImpl::GetResolvedAddress(
|
||||
int family,
|
||||
rtc::SocketAddress* addr) const {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
RTC_DCHECK(addr);
|
||||
if (error_ != 0 || addresses_.empty())
|
||||
return false;
|
||||
|
||||
*addr = addr_;
|
||||
for (const auto& address : addresses_) {
|
||||
if (family == address.family()) {
|
||||
addr->SetResolvedIP(address);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AsyncDnsResolverResultImpl::GetError() const {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
return error_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
63
TMessagesProj/jni/voip/webrtc/rtc_base/async_dns_resolver.h
Normal file
63
TMessagesProj/jni/voip/webrtc/rtc_base/async_dns_resolver.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 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_ASYNC_DNS_RESOLVER_H_
|
||||
#define RTC_BASE_ASYNC_DNS_RESOLVER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "api/async_dns_resolver.h"
|
||||
#include "api/sequence_checker.h"
|
||||
#include "api/task_queue/pending_task_safety_flag.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
|
||||
namespace webrtc {
|
||||
// This file contains a default implementation of
|
||||
// webrtc::AsyncDnsResolverInterface, for use when there is no need for special
|
||||
// treatment.
|
||||
|
||||
class AsyncDnsResolverResultImpl : public AsyncDnsResolverResult {
|
||||
public:
|
||||
bool GetResolvedAddress(int family, rtc::SocketAddress* addr) const override;
|
||||
// Returns error from resolver.
|
||||
int GetError() const override;
|
||||
|
||||
private:
|
||||
friend class AsyncDnsResolver;
|
||||
RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_;
|
||||
rtc::SocketAddress addr_ RTC_GUARDED_BY(sequence_checker_);
|
||||
std::vector<rtc::IPAddress> addresses_ RTC_GUARDED_BY(sequence_checker_);
|
||||
int error_ RTC_GUARDED_BY(sequence_checker_);
|
||||
};
|
||||
|
||||
class RTC_EXPORT AsyncDnsResolver : public AsyncDnsResolverInterface {
|
||||
public:
|
||||
AsyncDnsResolver();
|
||||
~AsyncDnsResolver();
|
||||
// Start address resolution of the hostname in `addr`.
|
||||
void Start(const rtc::SocketAddress& addr,
|
||||
absl::AnyInvocable<void()> callback) override;
|
||||
// Start address resolution of the hostname in `addr` matching `family`.
|
||||
void Start(const rtc::SocketAddress& addr,
|
||||
int family,
|
||||
absl::AnyInvocable<void()> callback) override;
|
||||
const AsyncDnsResolverResult& result() const override;
|
||||
|
||||
private:
|
||||
class State;
|
||||
ScopedTaskSafety safety_; // To check for client going away
|
||||
rtc::scoped_refptr<State> state_; // To check for "this" going away
|
||||
AsyncDnsResolverResultImpl result_;
|
||||
absl::AnyInvocable<void()> callback_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // RTC_BASE_ASYNC_DNS_RESOLVER_H_
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/async_packet_socket.h"
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
PacketTimeUpdateParams::PacketTimeUpdateParams() = default;
|
||||
|
||||
PacketTimeUpdateParams::PacketTimeUpdateParams(
|
||||
const PacketTimeUpdateParams& other) = default;
|
||||
|
||||
PacketTimeUpdateParams::~PacketTimeUpdateParams() = default;
|
||||
|
||||
PacketOptions::PacketOptions() = default;
|
||||
PacketOptions::PacketOptions(DiffServCodePoint dscp) : dscp(dscp) {}
|
||||
PacketOptions::PacketOptions(const PacketOptions& other) = default;
|
||||
PacketOptions::~PacketOptions() = default;
|
||||
|
||||
AsyncPacketSocket::~AsyncPacketSocket() = default;
|
||||
|
||||
void AsyncPacketSocket::SubscribeCloseEvent(
|
||||
const void* removal_tag,
|
||||
std::function<void(AsyncPacketSocket*, int)> callback) {
|
||||
RTC_DCHECK_RUN_ON(&network_checker_);
|
||||
on_close_.AddReceiver(removal_tag, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncPacketSocket::UnsubscribeCloseEvent(const void* removal_tag) {
|
||||
RTC_DCHECK_RUN_ON(&network_checker_);
|
||||
on_close_.RemoveReceivers(removal_tag);
|
||||
}
|
||||
|
||||
void AsyncPacketSocket::RegisterReceivedPacketCallback(
|
||||
absl::AnyInvocable<void(AsyncPacketSocket*, const rtc::ReceivedPacket&)>
|
||||
received_packet_callback) {
|
||||
RTC_DCHECK_RUN_ON(&network_checker_);
|
||||
RTC_CHECK(!received_packet_callback_);
|
||||
received_packet_callback_ = std::move(received_packet_callback);
|
||||
}
|
||||
|
||||
void AsyncPacketSocket::DeregisterReceivedPacketCallback() {
|
||||
RTC_DCHECK_RUN_ON(&network_checker_);
|
||||
received_packet_callback_ = nullptr;
|
||||
}
|
||||
|
||||
void AsyncPacketSocket::NotifyPacketReceived(
|
||||
const rtc::ReceivedPacket& packet) {
|
||||
RTC_DCHECK_RUN_ON(&network_checker_);
|
||||
if (received_packet_callback_) {
|
||||
received_packet_callback_(this, packet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CopySocketInformationToPacketInfo(size_t packet_size_bytes,
|
||||
const AsyncPacketSocket& socket_from,
|
||||
bool is_connectionless,
|
||||
rtc::PacketInfo* info) {
|
||||
info->packet_size_bytes = packet_size_bytes;
|
||||
info->ip_overhead_bytes = socket_from.GetLocalAddress().ipaddr().overhead();
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
201
TMessagesProj/jni/voip/webrtc/rtc_base/async_packet_socket.h
Normal file
201
TMessagesProj/jni/voip/webrtc/rtc_base/async_packet_socket.h
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* 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_ASYNC_PACKET_SOCKET_H_
|
||||
#define RTC_BASE_ASYNC_PACKET_SOCKET_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "api/sequence_checker.h"
|
||||
#include "rtc_base/callback_list.h"
|
||||
#include "rtc_base/dscp.h"
|
||||
#include "rtc_base/network/received_packet.h"
|
||||
#include "rtc_base/network/sent_packet.h"
|
||||
#include "rtc_base/socket.h"
|
||||
#include "rtc_base/system/no_unique_address.h"
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
#include "rtc_base/third_party/sigslot/sigslot.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// This structure holds the info needed to update the packet send time header
|
||||
// extension, including the information needed to update the authentication tag
|
||||
// after changing the value.
|
||||
struct PacketTimeUpdateParams {
|
||||
PacketTimeUpdateParams();
|
||||
PacketTimeUpdateParams(const PacketTimeUpdateParams& other);
|
||||
~PacketTimeUpdateParams();
|
||||
|
||||
int rtp_sendtime_extension_id = -1; // extension header id present in packet.
|
||||
std::vector<char> srtp_auth_key; // Authentication key.
|
||||
int srtp_auth_tag_len = -1; // Authentication tag length.
|
||||
int64_t srtp_packet_index = -1; // Required for Rtp Packet authentication.
|
||||
};
|
||||
|
||||
// This structure holds meta information for the packet which is about to send
|
||||
// over network.
|
||||
struct RTC_EXPORT PacketOptions {
|
||||
PacketOptions();
|
||||
explicit PacketOptions(DiffServCodePoint dscp);
|
||||
PacketOptions(const PacketOptions& other);
|
||||
~PacketOptions();
|
||||
|
||||
DiffServCodePoint dscp = DSCP_NO_CHANGE;
|
||||
// When used with RTP packets (for example, webrtc::PacketOptions), the value
|
||||
// should be 16 bits. A value of -1 represents "not set".
|
||||
int64_t packet_id = -1;
|
||||
PacketTimeUpdateParams packet_time_params;
|
||||
// PacketInfo is passed to SentPacket when signaling this packet is sent.
|
||||
PacketInfo info_signaled_after_sent;
|
||||
// True if this is a batchable packet. Batchable packets are collected at low
|
||||
// levels and sent first when their AsyncPacketSocket receives a
|
||||
// OnSendBatchComplete call.
|
||||
bool batchable = false;
|
||||
// True if this is the last packet of a batch.
|
||||
bool last_packet_in_batch = false;
|
||||
};
|
||||
|
||||
// Provides the ability to receive packets asynchronously. Sends are not
|
||||
// buffered since it is acceptable to drop packets under high load.
|
||||
class RTC_EXPORT AsyncPacketSocket : public sigslot::has_slots<> {
|
||||
public:
|
||||
enum State {
|
||||
STATE_CLOSED,
|
||||
STATE_BINDING,
|
||||
STATE_BOUND,
|
||||
STATE_CONNECTING,
|
||||
STATE_CONNECTED
|
||||
};
|
||||
|
||||
AsyncPacketSocket() = default;
|
||||
~AsyncPacketSocket() override;
|
||||
|
||||
AsyncPacketSocket(const AsyncPacketSocket&) = delete;
|
||||
AsyncPacketSocket& operator=(const AsyncPacketSocket&) = delete;
|
||||
|
||||
// Returns current local address. Address may be set to null if the
|
||||
// socket is not bound yet (GetState() returns STATE_BINDING).
|
||||
virtual SocketAddress GetLocalAddress() const = 0;
|
||||
|
||||
// Returns remote address. Returns zeroes if this is not a client TCP socket.
|
||||
virtual SocketAddress GetRemoteAddress() const = 0;
|
||||
|
||||
// Send a packet.
|
||||
virtual int Send(const void* pv, size_t cb, const PacketOptions& options) = 0;
|
||||
virtual int SendTo(const void* pv,
|
||||
size_t cb,
|
||||
const SocketAddress& addr,
|
||||
const PacketOptions& options) = 0;
|
||||
|
||||
// Close the socket.
|
||||
virtual int Close() = 0;
|
||||
|
||||
// Returns current state of the socket.
|
||||
virtual State GetState() const = 0;
|
||||
|
||||
// Get/set options.
|
||||
virtual int GetOption(Socket::Option opt, int* value) = 0;
|
||||
virtual int SetOption(Socket::Option opt, int value) = 0;
|
||||
|
||||
// Get/Set current error.
|
||||
// TODO: Remove SetError().
|
||||
virtual int GetError() const = 0;
|
||||
virtual void SetError(int error) = 0;
|
||||
|
||||
// Register a callback to be called when the socket is closed.
|
||||
void SubscribeCloseEvent(
|
||||
const void* removal_tag,
|
||||
std::function<void(AsyncPacketSocket*, int)> callback);
|
||||
void UnsubscribeCloseEvent(const void* removal_tag);
|
||||
|
||||
void RegisterReceivedPacketCallback(
|
||||
absl::AnyInvocable<void(AsyncPacketSocket*, const rtc::ReceivedPacket&)>
|
||||
received_packet_callback);
|
||||
void DeregisterReceivedPacketCallback();
|
||||
|
||||
// Emitted each time a packet is sent.
|
||||
sigslot::signal2<AsyncPacketSocket*, const SentPacket&> SignalSentPacket;
|
||||
|
||||
// Emitted when the socket is currently able to send.
|
||||
sigslot::signal1<AsyncPacketSocket*> SignalReadyToSend;
|
||||
|
||||
// Emitted after address for the socket is allocated, i.e. binding
|
||||
// is finished. State of the socket is changed from BINDING to BOUND
|
||||
// (for UDP sockets).
|
||||
sigslot::signal2<AsyncPacketSocket*, const SocketAddress&> SignalAddressReady;
|
||||
|
||||
// Emitted for client TCP sockets when state is changed from
|
||||
// CONNECTING to CONNECTED.
|
||||
sigslot::signal1<AsyncPacketSocket*> SignalConnect;
|
||||
|
||||
void NotifyClosedForTest(int err) { NotifyClosed(err); }
|
||||
|
||||
protected:
|
||||
// TODO(bugs.webrtc.org/11943): Remove after updating downstream code.
|
||||
void SignalClose(AsyncPacketSocket* s, int err) {
|
||||
RTC_DCHECK_EQ(s, this);
|
||||
NotifyClosed(err);
|
||||
}
|
||||
|
||||
void NotifyClosed(int err) {
|
||||
RTC_DCHECK_RUN_ON(&network_checker_);
|
||||
on_close_.Send(this, err);
|
||||
}
|
||||
|
||||
// TODO(bugs.webrtc.org:15368): Deprecate and remove.
|
||||
void NotifyPacketReceived(AsyncPacketSocket*,
|
||||
const char* data,
|
||||
size_t size,
|
||||
const SocketAddress& address,
|
||||
const int64_t& packet_time_us) {
|
||||
NotifyPacketReceived(
|
||||
ReceivedPacket::CreateFromLegacy(data, size, packet_time_us, address));
|
||||
}
|
||||
|
||||
void NotifyPacketReceived(const rtc::ReceivedPacket& packet);
|
||||
|
||||
RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker network_checker_{
|
||||
webrtc::SequenceChecker::kDetached};
|
||||
|
||||
private:
|
||||
webrtc::CallbackList<AsyncPacketSocket*, int> on_close_
|
||||
RTC_GUARDED_BY(&network_checker_);
|
||||
absl::AnyInvocable<void(AsyncPacketSocket*, const rtc::ReceivedPacket&)>
|
||||
received_packet_callback_ RTC_GUARDED_BY(&network_checker_);
|
||||
};
|
||||
|
||||
// Listen socket, producing an AsyncPacketSocket when a peer connects.
|
||||
class RTC_EXPORT AsyncListenSocket : public sigslot::has_slots<> {
|
||||
public:
|
||||
enum class State {
|
||||
kClosed,
|
||||
kBound,
|
||||
};
|
||||
|
||||
// Returns current state of the socket.
|
||||
virtual State GetState() const = 0;
|
||||
|
||||
// Returns current local address. Address may be set to null if the
|
||||
// socket is not bound yet (GetState() returns kBinding).
|
||||
virtual SocketAddress GetLocalAddress() const = 0;
|
||||
|
||||
sigslot::signal2<AsyncListenSocket*, AsyncPacketSocket*> SignalNewConnection;
|
||||
};
|
||||
|
||||
void CopySocketInformationToPacketInfo(size_t packet_size_bytes,
|
||||
const AsyncPacketSocket& socket_from,
|
||||
bool is_connectionless,
|
||||
rtc::PacketInfo* info);
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_ASYNC_PACKET_SOCKET_H_
|
||||
113
TMessagesProj/jni/voip/webrtc/rtc_base/async_socket.cc
Normal file
113
TMessagesProj/jni/voip/webrtc/rtc_base/async_socket.cc
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2010 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can 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/async_socket.h"
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
AsyncSocketAdapter::AsyncSocketAdapter(Socket* socket)
|
||||
: socket_(absl::WrapUnique(socket)) {
|
||||
RTC_DCHECK(socket_);
|
||||
socket_->SignalConnectEvent.connect(this,
|
||||
&AsyncSocketAdapter::OnConnectEvent);
|
||||
socket_->SignalReadEvent.connect(this, &AsyncSocketAdapter::OnReadEvent);
|
||||
socket_->SignalWriteEvent.connect(this, &AsyncSocketAdapter::OnWriteEvent);
|
||||
socket_->SignalCloseEvent.connect(this, &AsyncSocketAdapter::OnCloseEvent);
|
||||
}
|
||||
|
||||
SocketAddress AsyncSocketAdapter::GetLocalAddress() const {
|
||||
return socket_->GetLocalAddress();
|
||||
}
|
||||
|
||||
SocketAddress AsyncSocketAdapter::GetRemoteAddress() const {
|
||||
return socket_->GetRemoteAddress();
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::Bind(const SocketAddress& addr) {
|
||||
return socket_->Bind(addr);
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::Connect(const SocketAddress& addr) {
|
||||
return socket_->Connect(addr);
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::Send(const void* pv, size_t cb) {
|
||||
return socket_->Send(pv, cb);
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::SendTo(const void* pv,
|
||||
size_t cb,
|
||||
const SocketAddress& addr) {
|
||||
return socket_->SendTo(pv, cb, addr);
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::Recv(void* pv, size_t cb, int64_t* timestamp) {
|
||||
return socket_->Recv(pv, cb, timestamp);
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::RecvFrom(void* pv,
|
||||
size_t cb,
|
||||
SocketAddress* paddr,
|
||||
int64_t* timestamp) {
|
||||
return socket_->RecvFrom(pv, cb, paddr, timestamp);
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::Listen(int backlog) {
|
||||
return socket_->Listen(backlog);
|
||||
}
|
||||
|
||||
Socket* AsyncSocketAdapter::Accept(SocketAddress* paddr) {
|
||||
return socket_->Accept(paddr);
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::Close() {
|
||||
return socket_->Close();
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::GetError() const {
|
||||
return socket_->GetError();
|
||||
}
|
||||
|
||||
void AsyncSocketAdapter::SetError(int error) {
|
||||
return socket_->SetError(error);
|
||||
}
|
||||
|
||||
Socket::ConnState AsyncSocketAdapter::GetState() const {
|
||||
return socket_->GetState();
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::GetOption(Option opt, int* value) {
|
||||
return socket_->GetOption(opt, value);
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::SetOption(Option opt, int value) {
|
||||
return socket_->SetOption(opt, value);
|
||||
}
|
||||
|
||||
void AsyncSocketAdapter::OnConnectEvent(Socket* socket) {
|
||||
SignalConnectEvent(this);
|
||||
}
|
||||
|
||||
void AsyncSocketAdapter::OnReadEvent(Socket* socket) {
|
||||
SignalReadEvent(this);
|
||||
}
|
||||
|
||||
void AsyncSocketAdapter::OnWriteEvent(Socket* socket) {
|
||||
SignalWriteEvent(this);
|
||||
}
|
||||
|
||||
void AsyncSocketAdapter::OnCloseEvent(Socket* socket, int err) {
|
||||
SignalCloseEvent(this, err);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
65
TMessagesProj/jni/voip/webrtc/rtc_base/async_socket.h
Normal file
65
TMessagesProj/jni/voip/webrtc/rtc_base/async_socket.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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_ASYNC_SOCKET_H_
|
||||
#define RTC_BASE_ASYNC_SOCKET_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rtc_base/socket.h"
|
||||
#include "rtc_base/socket_address.h"
|
||||
#include "rtc_base/third_party/sigslot/sigslot.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class AsyncSocketAdapter : public Socket, public sigslot::has_slots<> {
|
||||
public:
|
||||
// Takes ownership of the passed in socket.
|
||||
// TODO(bugs.webrtc.org/6424): Change to unique_ptr here and in callers.
|
||||
explicit AsyncSocketAdapter(Socket* socket);
|
||||
|
||||
SocketAddress GetLocalAddress() const override;
|
||||
SocketAddress GetRemoteAddress() const override;
|
||||
int Bind(const SocketAddress& addr) override;
|
||||
int Connect(const SocketAddress& addr) override;
|
||||
int Send(const void* pv, size_t cb) override;
|
||||
int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override;
|
||||
int Recv(void* pv, size_t cb, int64_t* timestamp) override;
|
||||
int RecvFrom(void* pv,
|
||||
size_t cb,
|
||||
SocketAddress* paddr,
|
||||
int64_t* timestamp) override;
|
||||
int Listen(int backlog) override;
|
||||
Socket* Accept(SocketAddress* paddr) override;
|
||||
int Close() override;
|
||||
int GetError() const override;
|
||||
void SetError(int error) override;
|
||||
ConnState GetState() const override;
|
||||
int GetOption(Option opt, int* value) override;
|
||||
int SetOption(Option opt, int value) override;
|
||||
|
||||
protected:
|
||||
virtual void OnConnectEvent(Socket* socket);
|
||||
virtual void OnReadEvent(Socket* socket);
|
||||
virtual void OnWriteEvent(Socket* socket);
|
||||
virtual void OnCloseEvent(Socket* socket, int err);
|
||||
|
||||
Socket* GetSocket() const { return socket_.get(); }
|
||||
|
||||
private:
|
||||
const std::unique_ptr<Socket> socket_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_ASYNC_SOCKET_H_
|
||||
358
TMessagesProj/jni/voip/webrtc/rtc_base/async_tcp_socket.cc
Normal file
358
TMessagesProj/jni/voip/webrtc/rtc_base/async_tcp_socket.cc
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* 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/async_tcp_socket.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "rtc_base/byte_order.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/network/sent_packet.h"
|
||||
#include "rtc_base/time_utils.h" // for TimeMillis
|
||||
|
||||
#if defined(WEBRTC_POSIX)
|
||||
#include <errno.h>
|
||||
#endif // WEBRTC_POSIX
|
||||
|
||||
namespace rtc {
|
||||
|
||||
static const size_t kMaxPacketSize = 64 * 1024;
|
||||
|
||||
typedef uint16_t PacketLength;
|
||||
static const size_t kPacketLenSize = sizeof(PacketLength);
|
||||
|
||||
static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
|
||||
|
||||
// The input buffer will be resized so that at least kMinimumRecvSize bytes can
|
||||
// be received (but it will not grow above the maximum size passed to the
|
||||
// constructor).
|
||||
static const size_t kMinimumRecvSize = 128;
|
||||
|
||||
static const int kListenBacklog = 5;
|
||||
|
||||
// Binds and connects `socket`
|
||||
Socket* AsyncTCPSocketBase::ConnectSocket(
|
||||
rtc::Socket* socket,
|
||||
const rtc::SocketAddress& bind_address,
|
||||
const rtc::SocketAddress& remote_address) {
|
||||
std::unique_ptr<rtc::Socket> owned_socket(socket);
|
||||
if (socket->Bind(bind_address) < 0) {
|
||||
RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
|
||||
return nullptr;
|
||||
}
|
||||
if (socket->Connect(remote_address) < 0) {
|
||||
RTC_LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
|
||||
return nullptr;
|
||||
}
|
||||
return owned_socket.release();
|
||||
}
|
||||
|
||||
AsyncTCPSocketBase::AsyncTCPSocketBase(Socket* socket, size_t max_packet_size)
|
||||
: socket_(socket),
|
||||
max_insize_(max_packet_size),
|
||||
max_outsize_(max_packet_size) {
|
||||
inbuf_.EnsureCapacity(kMinimumRecvSize);
|
||||
|
||||
socket_->SignalConnectEvent.connect(this,
|
||||
&AsyncTCPSocketBase::OnConnectEvent);
|
||||
socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
|
||||
socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
|
||||
socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
|
||||
}
|
||||
|
||||
AsyncTCPSocketBase::~AsyncTCPSocketBase() {}
|
||||
|
||||
SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
|
||||
return socket_->GetLocalAddress();
|
||||
}
|
||||
|
||||
SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
|
||||
return socket_->GetRemoteAddress();
|
||||
}
|
||||
|
||||
int AsyncTCPSocketBase::Close() {
|
||||
return socket_->Close();
|
||||
}
|
||||
|
||||
AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
|
||||
switch (socket_->GetState()) {
|
||||
case Socket::CS_CLOSED:
|
||||
return STATE_CLOSED;
|
||||
case Socket::CS_CONNECTING:
|
||||
return STATE_CONNECTING;
|
||||
case Socket::CS_CONNECTED:
|
||||
return STATE_CONNECTED;
|
||||
default:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return STATE_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
|
||||
return socket_->GetOption(opt, value);
|
||||
}
|
||||
|
||||
int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
|
||||
return socket_->SetOption(opt, value);
|
||||
}
|
||||
|
||||
int AsyncTCPSocketBase::GetError() const {
|
||||
return socket_->GetError();
|
||||
}
|
||||
|
||||
void AsyncTCPSocketBase::SetError(int error) {
|
||||
return socket_->SetError(error);
|
||||
}
|
||||
|
||||
int AsyncTCPSocketBase::SendTo(const void* pv,
|
||||
size_t cb,
|
||||
const SocketAddress& addr,
|
||||
const rtc::PacketOptions& options) {
|
||||
const SocketAddress& remote_address = GetRemoteAddress();
|
||||
if (addr == remote_address)
|
||||
return Send(pv, cb, options);
|
||||
// Remote address may be empty if there is a sudden network change.
|
||||
RTC_DCHECK(remote_address.IsNil());
|
||||
socket_->SetError(ENOTCONN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AsyncTCPSocketBase::FlushOutBuffer() {
|
||||
RTC_DCHECK_GT(outbuf_.size(), 0);
|
||||
rtc::ArrayView<uint8_t> view = outbuf_;
|
||||
int res;
|
||||
while (view.size() > 0) {
|
||||
res = socket_->Send(view.data(), view.size());
|
||||
if (res <= 0) {
|
||||
break;
|
||||
}
|
||||
if (static_cast<size_t>(res) > view.size()) {
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
view = view.subview(res);
|
||||
}
|
||||
if (res > 0) {
|
||||
// The output buffer may have been written out over multiple partial Send(),
|
||||
// so reconstruct the total written length.
|
||||
RTC_DCHECK_EQ(view.size(), 0);
|
||||
res = outbuf_.size();
|
||||
outbuf_.Clear();
|
||||
} else {
|
||||
// There was an error when calling Send(), so there will still be data left
|
||||
// to send at a later point.
|
||||
RTC_DCHECK_GT(view.size(), 0);
|
||||
// In the special case of EWOULDBLOCK, signal that we had a partial write.
|
||||
if (socket_->GetError() == EWOULDBLOCK) {
|
||||
res = outbuf_.size() - view.size();
|
||||
}
|
||||
if (view.size() < outbuf_.size()) {
|
||||
memmove(outbuf_.data(), view.data(), view.size());
|
||||
outbuf_.SetSize(view.size());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
|
||||
RTC_DCHECK(outbuf_.size() + cb <= max_outsize_);
|
||||
outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb);
|
||||
}
|
||||
|
||||
void AsyncTCPSocketBase::OnConnectEvent(Socket* socket) {
|
||||
SignalConnect(this);
|
||||
}
|
||||
|
||||
void AsyncTCPSocketBase::OnReadEvent(Socket* socket) {
|
||||
RTC_DCHECK(socket_.get() == socket);
|
||||
|
||||
size_t total_recv = 0;
|
||||
while (true) {
|
||||
size_t free_size = inbuf_.capacity() - inbuf_.size();
|
||||
if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) {
|
||||
inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2));
|
||||
free_size = inbuf_.capacity() - inbuf_.size();
|
||||
}
|
||||
|
||||
int len = socket_->Recv(inbuf_.data() + inbuf_.size(), free_size, nullptr);
|
||||
if (len < 0) {
|
||||
// TODO(stefan): Do something better like forwarding the error to the
|
||||
// user.
|
||||
if (!socket_->IsBlocking()) {
|
||||
RTC_LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
total_recv += len;
|
||||
inbuf_.SetSize(inbuf_.size() + len);
|
||||
if (!len || static_cast<size_t>(len) < free_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!total_recv) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t processed = ProcessInput(inbuf_);
|
||||
size_t bytes_remaining = inbuf_.size() - processed;
|
||||
if (processed > inbuf_.size()) {
|
||||
RTC_LOG(LS_ERROR) << "input buffer overflow";
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
inbuf_.Clear();
|
||||
} else {
|
||||
if (bytes_remaining > 0) {
|
||||
memmove(inbuf_.data(), inbuf_.data() + processed, bytes_remaining);
|
||||
}
|
||||
inbuf_.SetSize(bytes_remaining);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncTCPSocketBase::OnWriteEvent(Socket* socket) {
|
||||
RTC_DCHECK(socket_.get() == socket);
|
||||
|
||||
if (outbuf_.size() > 0) {
|
||||
FlushOutBuffer();
|
||||
}
|
||||
|
||||
if (outbuf_.size() == 0) {
|
||||
SignalReadyToSend(this);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncTCPSocketBase::OnCloseEvent(Socket* socket, int error) {
|
||||
NotifyClosed(error);
|
||||
}
|
||||
|
||||
// AsyncTCPSocket
|
||||
// Binds and connects `socket` and creates AsyncTCPSocket for
|
||||
// it. Takes ownership of `socket`. Returns null if bind() or
|
||||
// connect() fail (`socket` is destroyed in that case).
|
||||
AsyncTCPSocket* AsyncTCPSocket::Create(Socket* socket,
|
||||
const SocketAddress& bind_address,
|
||||
const SocketAddress& remote_address) {
|
||||
return new AsyncTCPSocket(
|
||||
AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address));
|
||||
}
|
||||
|
||||
AsyncTCPSocket::AsyncTCPSocket(Socket* socket)
|
||||
: AsyncTCPSocketBase(socket, kBufSize) {}
|
||||
|
||||
int AsyncTCPSocket::Send(const void* pv,
|
||||
size_t cb,
|
||||
const rtc::PacketOptions& options) {
|
||||
if (cb > kBufSize) {
|
||||
SetError(EMSGSIZE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we are blocking on send, then silently drop this packet
|
||||
if (!IsOutBufferEmpty())
|
||||
return static_cast<int>(cb);
|
||||
|
||||
PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
|
||||
AppendToOutBuffer(&pkt_len, kPacketLenSize);
|
||||
AppendToOutBuffer(pv, cb);
|
||||
|
||||
int res = FlushOutBuffer();
|
||||
if (res <= 0) {
|
||||
// drop packet if we made no progress
|
||||
ClearOutBuffer();
|
||||
return res;
|
||||
}
|
||||
|
||||
rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
|
||||
options.info_signaled_after_sent);
|
||||
CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info);
|
||||
SignalSentPacket(this, sent_packet);
|
||||
|
||||
// We claim to have sent the whole thing, even if we only sent partial
|
||||
return static_cast<int>(cb);
|
||||
}
|
||||
|
||||
size_t AsyncTCPSocket::ProcessInput(rtc::ArrayView<const uint8_t> data) {
|
||||
SocketAddress remote_addr(GetRemoteAddress());
|
||||
|
||||
size_t processed_bytes = 0;
|
||||
while (true) {
|
||||
size_t bytes_left = data.size() - processed_bytes;
|
||||
if (bytes_left < kPacketLenSize)
|
||||
return processed_bytes;
|
||||
|
||||
PacketLength pkt_len = rtc::GetBE16(data.data() + processed_bytes);
|
||||
if (bytes_left < kPacketLenSize + pkt_len)
|
||||
return processed_bytes;
|
||||
|
||||
rtc::ReceivedPacket received_packet(
|
||||
data.subview(processed_bytes + kPacketLenSize, pkt_len), remote_addr,
|
||||
webrtc::Timestamp::Micros(rtc::TimeMicros()));
|
||||
NotifyPacketReceived(received_packet);
|
||||
processed_bytes += kPacketLenSize + pkt_len;
|
||||
}
|
||||
}
|
||||
|
||||
AsyncTcpListenSocket::AsyncTcpListenSocket(std::unique_ptr<Socket> socket)
|
||||
: socket_(std::move(socket)) {
|
||||
RTC_DCHECK(socket_.get() != nullptr);
|
||||
socket_->SignalReadEvent.connect(this, &AsyncTcpListenSocket::OnReadEvent);
|
||||
if (socket_->Listen(kListenBacklog) < 0) {
|
||||
RTC_LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
|
||||
}
|
||||
}
|
||||
|
||||
AsyncTcpListenSocket::State AsyncTcpListenSocket::GetState() const {
|
||||
switch (socket_->GetState()) {
|
||||
case Socket::CS_CLOSED:
|
||||
return State::kClosed;
|
||||
case Socket::CS_CONNECTING:
|
||||
return State::kBound;
|
||||
default:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return State::kClosed;
|
||||
}
|
||||
}
|
||||
|
||||
SocketAddress AsyncTcpListenSocket::GetLocalAddress() const {
|
||||
return socket_->GetLocalAddress();
|
||||
}
|
||||
|
||||
void AsyncTcpListenSocket::OnReadEvent(Socket* socket) {
|
||||
RTC_DCHECK(socket_.get() == socket);
|
||||
|
||||
rtc::SocketAddress address;
|
||||
rtc::Socket* new_socket = socket->Accept(&address);
|
||||
if (!new_socket) {
|
||||
// TODO(stefan): Do something better like forwarding the error
|
||||
// to the user.
|
||||
RTC_LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
|
||||
return;
|
||||
}
|
||||
|
||||
HandleIncomingConnection(new_socket);
|
||||
|
||||
// Prime a read event in case data is waiting.
|
||||
new_socket->SignalReadEvent(new_socket);
|
||||
}
|
||||
|
||||
void AsyncTcpListenSocket::HandleIncomingConnection(Socket* socket) {
|
||||
SignalNewConnection(this, new AsyncTCPSocket(socket));
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
126
TMessagesProj/jni/voip/webrtc/rtc_base/async_tcp_socket.h
Normal file
126
TMessagesProj/jni/voip/webrtc/rtc_base/async_tcp_socket.h
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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_ASYNC_TCP_SOCKET_H_
|
||||
#define RTC_BASE_ASYNC_TCP_SOCKET_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "rtc_base/async_packet_socket.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
#include "rtc_base/socket.h"
|
||||
#include "rtc_base/socket_address.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Simulates UDP semantics over TCP. Send and Recv packet sizes
|
||||
// are preserved, and drops packets silently on Send, rather than
|
||||
// buffer them in user space.
|
||||
class AsyncTCPSocketBase : public AsyncPacketSocket {
|
||||
public:
|
||||
AsyncTCPSocketBase(Socket* socket, size_t max_packet_size);
|
||||
~AsyncTCPSocketBase() override;
|
||||
|
||||
AsyncTCPSocketBase(const AsyncTCPSocketBase&) = delete;
|
||||
AsyncTCPSocketBase& operator=(const AsyncTCPSocketBase&) = delete;
|
||||
|
||||
// Pure virtual methods to send and recv data.
|
||||
int Send(const void* pv,
|
||||
size_t cb,
|
||||
const rtc::PacketOptions& options) override = 0;
|
||||
// Must return the number of bytes processed.
|
||||
virtual size_t ProcessInput(rtc::ArrayView<const uint8_t> data) = 0;
|
||||
|
||||
SocketAddress GetLocalAddress() const override;
|
||||
SocketAddress GetRemoteAddress() const override;
|
||||
int SendTo(const void* pv,
|
||||
size_t cb,
|
||||
const SocketAddress& addr,
|
||||
const rtc::PacketOptions& options) override;
|
||||
int Close() override;
|
||||
|
||||
State GetState() const override;
|
||||
int GetOption(Socket::Option opt, int* value) override;
|
||||
int SetOption(Socket::Option opt, int value) override;
|
||||
int GetError() const override;
|
||||
void SetError(int error) override;
|
||||
|
||||
protected:
|
||||
// Binds and connects `socket` and creates AsyncTCPSocket for
|
||||
// it. Takes ownership of `socket`. Returns null if bind() or
|
||||
// connect() fail (`socket` is destroyed in that case).
|
||||
static Socket* ConnectSocket(Socket* socket,
|
||||
const SocketAddress& bind_address,
|
||||
const SocketAddress& remote_address);
|
||||
int FlushOutBuffer();
|
||||
// Add data to `outbuf_`.
|
||||
void AppendToOutBuffer(const void* pv, size_t cb);
|
||||
|
||||
// Helper methods for `outpos_`.
|
||||
bool IsOutBufferEmpty() const { return outbuf_.size() == 0; }
|
||||
void ClearOutBuffer() { outbuf_.Clear(); }
|
||||
|
||||
private:
|
||||
// Called by the underlying socket
|
||||
void OnConnectEvent(Socket* socket);
|
||||
void OnReadEvent(Socket* socket);
|
||||
void OnWriteEvent(Socket* socket);
|
||||
void OnCloseEvent(Socket* socket, int error);
|
||||
|
||||
std::unique_ptr<Socket> socket_;
|
||||
Buffer inbuf_;
|
||||
Buffer outbuf_;
|
||||
size_t max_insize_;
|
||||
size_t max_outsize_;
|
||||
};
|
||||
|
||||
class AsyncTCPSocket : public AsyncTCPSocketBase {
|
||||
public:
|
||||
// Binds and connects `socket` and creates AsyncTCPSocket for
|
||||
// it. Takes ownership of `socket`. Returns null if bind() or
|
||||
// connect() fail (`socket` is destroyed in that case).
|
||||
static AsyncTCPSocket* Create(Socket* socket,
|
||||
const SocketAddress& bind_address,
|
||||
const SocketAddress& remote_address);
|
||||
explicit AsyncTCPSocket(Socket* socket);
|
||||
~AsyncTCPSocket() override {}
|
||||
|
||||
AsyncTCPSocket(const AsyncTCPSocket&) = delete;
|
||||
AsyncTCPSocket& operator=(const AsyncTCPSocket&) = delete;
|
||||
|
||||
int Send(const void* pv,
|
||||
size_t cb,
|
||||
const rtc::PacketOptions& options) override;
|
||||
size_t ProcessInput(rtc::ArrayView<const uint8_t>) override;
|
||||
};
|
||||
|
||||
class AsyncTcpListenSocket : public AsyncListenSocket {
|
||||
public:
|
||||
explicit AsyncTcpListenSocket(std::unique_ptr<Socket> socket);
|
||||
|
||||
State GetState() const override;
|
||||
SocketAddress GetLocalAddress() const override;
|
||||
|
||||
virtual void HandleIncomingConnection(rtc::Socket* socket);
|
||||
|
||||
private:
|
||||
// Called by the underlying socket
|
||||
void OnReadEvent(Socket* socket);
|
||||
|
||||
std::unique_ptr<Socket> socket_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_ASYNC_TCP_SOCKET_H_
|
||||
157
TMessagesProj/jni/voip/webrtc/rtc_base/async_udp_socket.cc
Normal file
157
TMessagesProj/jni/voip/webrtc/rtc_base/async_udp_socket.cc
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* 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/async_udp_socket.h"
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/network/received_packet.h"
|
||||
#include "rtc_base/network/sent_packet.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Returns true if the experiement "WebRTC-SCM-Timestamp" is explicitly
|
||||
// disabled.
|
||||
static bool IsScmTimeStampExperimentDisabled() {
|
||||
return webrtc::field_trial::IsDisabled("WebRTC-SCM-Timestamp");
|
||||
}
|
||||
|
||||
AsyncUDPSocket* AsyncUDPSocket::Create(Socket* socket,
|
||||
const SocketAddress& bind_address) {
|
||||
std::unique_ptr<Socket> owned_socket(socket);
|
||||
if (socket->Bind(bind_address) < 0) {
|
||||
RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
|
||||
return nullptr;
|
||||
}
|
||||
return new AsyncUDPSocket(owned_socket.release());
|
||||
}
|
||||
|
||||
AsyncUDPSocket* AsyncUDPSocket::Create(SocketFactory* factory,
|
||||
const SocketAddress& bind_address) {
|
||||
Socket* socket = factory->CreateSocket(bind_address.family(), SOCK_DGRAM);
|
||||
if (!socket)
|
||||
return nullptr;
|
||||
return Create(socket, bind_address);
|
||||
}
|
||||
|
||||
AsyncUDPSocket::AsyncUDPSocket(Socket* socket) : socket_(socket) {
|
||||
sequence_checker_.Detach();
|
||||
// The socket should start out readable but not writable.
|
||||
socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent);
|
||||
socket_->SignalWriteEvent.connect(this, &AsyncUDPSocket::OnWriteEvent);
|
||||
}
|
||||
|
||||
SocketAddress AsyncUDPSocket::GetLocalAddress() const {
|
||||
return socket_->GetLocalAddress();
|
||||
}
|
||||
|
||||
SocketAddress AsyncUDPSocket::GetRemoteAddress() const {
|
||||
return socket_->GetRemoteAddress();
|
||||
}
|
||||
|
||||
int AsyncUDPSocket::Send(const void* pv,
|
||||
size_t cb,
|
||||
const rtc::PacketOptions& options) {
|
||||
rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
|
||||
options.info_signaled_after_sent);
|
||||
CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info);
|
||||
int ret = socket_->Send(pv, cb);
|
||||
SignalSentPacket(this, sent_packet);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AsyncUDPSocket::SendTo(const void* pv,
|
||||
size_t cb,
|
||||
const SocketAddress& addr,
|
||||
const rtc::PacketOptions& options) {
|
||||
rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
|
||||
options.info_signaled_after_sent);
|
||||
CopySocketInformationToPacketInfo(cb, *this, true, &sent_packet.info);
|
||||
int ret = socket_->SendTo(pv, cb, addr);
|
||||
SignalSentPacket(this, sent_packet);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AsyncUDPSocket::Close() {
|
||||
return socket_->Close();
|
||||
}
|
||||
|
||||
AsyncUDPSocket::State AsyncUDPSocket::GetState() const {
|
||||
return STATE_BOUND;
|
||||
}
|
||||
|
||||
int AsyncUDPSocket::GetOption(Socket::Option opt, int* value) {
|
||||
return socket_->GetOption(opt, value);
|
||||
}
|
||||
|
||||
int AsyncUDPSocket::SetOption(Socket::Option opt, int value) {
|
||||
return socket_->SetOption(opt, value);
|
||||
}
|
||||
|
||||
int AsyncUDPSocket::GetError() const {
|
||||
return socket_->GetError();
|
||||
}
|
||||
|
||||
void AsyncUDPSocket::SetError(int error) {
|
||||
return socket_->SetError(error);
|
||||
}
|
||||
|
||||
void AsyncUDPSocket::OnReadEvent(Socket* socket) {
|
||||
RTC_DCHECK(socket_.get() == socket);
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
|
||||
Socket::ReceiveBuffer receive_buffer(buffer_);
|
||||
int len = socket_->RecvFrom(receive_buffer);
|
||||
if (len < 0) {
|
||||
// An error here typically means we got an ICMP error in response to our
|
||||
// send datagram, indicating the remote address was unreachable.
|
||||
// When doing ICE, this kind of thing will often happen.
|
||||
// TODO: Do something better like forwarding the error to the user.
|
||||
SocketAddress local_addr = socket_->GetLocalAddress();
|
||||
RTC_LOG(LS_INFO) << "AsyncUDPSocket[" << local_addr.ToSensitiveString()
|
||||
<< "] receive failed with error " << socket_->GetError();
|
||||
return;
|
||||
}
|
||||
if (len == 0) {
|
||||
// Spurios wakeup.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!receive_buffer.arrival_time) {
|
||||
// Timestamp from socket is not available.
|
||||
receive_buffer.arrival_time = webrtc::Timestamp::Micros(rtc::TimeMicros());
|
||||
} else {
|
||||
if (!socket_time_offset_) {
|
||||
// Estimate timestamp offset from first packet arrival time unless
|
||||
// disabled
|
||||
bool estimate_time_offset = !IsScmTimeStampExperimentDisabled();
|
||||
if (estimate_time_offset) {
|
||||
socket_time_offset_ = webrtc::Timestamp::Micros(rtc::TimeMicros()) -
|
||||
*receive_buffer.arrival_time;
|
||||
} else {
|
||||
socket_time_offset_ = webrtc::TimeDelta::Micros(0);
|
||||
}
|
||||
}
|
||||
*receive_buffer.arrival_time += *socket_time_offset_;
|
||||
}
|
||||
NotifyPacketReceived(ReceivedPacket(receive_buffer.payload,
|
||||
receive_buffer.source_address,
|
||||
receive_buffer.arrival_time));
|
||||
}
|
||||
|
||||
void AsyncUDPSocket::OnWriteEvent(Socket* socket) {
|
||||
SignalReadyToSend(this);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
79
TMessagesProj/jni/voip/webrtc/rtc_base/async_udp_socket.h
Normal file
79
TMessagesProj/jni/voip/webrtc/rtc_base/async_udp_socket.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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_ASYNC_UDP_SOCKET_H_
|
||||
#define RTC_BASE_ASYNC_UDP_SOCKET_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/sequence_checker.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/async_packet_socket.h"
|
||||
#include "rtc_base/socket.h"
|
||||
#include "rtc_base/socket_address.h"
|
||||
#include "rtc_base/socket_factory.h"
|
||||
#include "rtc_base/system/no_unique_address.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Provides the ability to receive packets asynchronously. Sends are not
|
||||
// buffered since it is acceptable to drop packets under high load.
|
||||
class AsyncUDPSocket : public AsyncPacketSocket {
|
||||
public:
|
||||
// Binds `socket` and creates AsyncUDPSocket for it. Takes ownership
|
||||
// of `socket`. Returns null if bind() fails (`socket` is destroyed
|
||||
// in that case).
|
||||
static AsyncUDPSocket* Create(Socket* socket,
|
||||
const SocketAddress& bind_address);
|
||||
// Creates a new socket for sending asynchronous UDP packets using an
|
||||
// asynchronous socket from the given factory.
|
||||
static AsyncUDPSocket* Create(SocketFactory* factory,
|
||||
const SocketAddress& bind_address);
|
||||
explicit AsyncUDPSocket(Socket* socket);
|
||||
~AsyncUDPSocket() = default;
|
||||
|
||||
SocketAddress GetLocalAddress() const override;
|
||||
SocketAddress GetRemoteAddress() const override;
|
||||
int Send(const void* pv,
|
||||
size_t cb,
|
||||
const rtc::PacketOptions& options) override;
|
||||
int SendTo(const void* pv,
|
||||
size_t cb,
|
||||
const SocketAddress& addr,
|
||||
const rtc::PacketOptions& options) override;
|
||||
int Close() override;
|
||||
|
||||
State GetState() const override;
|
||||
int GetOption(Socket::Option opt, int* value) override;
|
||||
int SetOption(Socket::Option opt, int value) override;
|
||||
int GetError() const override;
|
||||
void SetError(int error) override;
|
||||
|
||||
private:
|
||||
// Called when the underlying socket is ready to be read from.
|
||||
void OnReadEvent(Socket* socket);
|
||||
// Called when the underlying socket is ready to send.
|
||||
void OnWriteEvent(Socket* socket);
|
||||
|
||||
RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_;
|
||||
std::unique_ptr<Socket> socket_;
|
||||
rtc::Buffer buffer_ RTC_GUARDED_BY(sequence_checker_);
|
||||
absl::optional<webrtc::TimeDelta> socket_time_offset_
|
||||
RTC_GUARDED_BY(sequence_checker_);
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_ASYNC_UDP_SOCKET_H_
|
||||
1454
TMessagesProj/jni/voip/webrtc/rtc_base/base64_unittest.cc
Normal file
1454
TMessagesProj/jni/voip/webrtc/rtc_base/base64_unittest.cc
Normal file
File diff suppressed because it is too large
Load diff
230
TMessagesProj/jni/voip/webrtc/rtc_base/bit_buffer.cc
Normal file
230
TMessagesProj/jni/voip/webrtc/rtc_base/bit_buffer.cc
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/bit_buffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "absl/numeric/bits.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns the highest byte of `val` in a uint8_t.
|
||||
uint8_t HighestByte(uint64_t val) {
|
||||
return static_cast<uint8_t>(val >> 56);
|
||||
}
|
||||
|
||||
// Returns the result of writing partial data from `source`, of
|
||||
// `source_bit_count` size in the highest bits, to `target` at
|
||||
// `target_bit_offset` from the highest bit.
|
||||
uint8_t WritePartialByte(uint8_t source,
|
||||
size_t source_bit_count,
|
||||
uint8_t target,
|
||||
size_t target_bit_offset) {
|
||||
RTC_DCHECK(target_bit_offset < 8);
|
||||
RTC_DCHECK(source_bit_count < 9);
|
||||
RTC_DCHECK(source_bit_count <= (8 - target_bit_offset));
|
||||
// Generate a mask for just the bits we're going to overwrite, so:
|
||||
uint8_t mask =
|
||||
// The number of bits we want, in the most significant bits...
|
||||
static_cast<uint8_t>(0xFF << (8 - source_bit_count))
|
||||
// ...shifted over to the target offset from the most signficant bit.
|
||||
>> target_bit_offset;
|
||||
|
||||
// We want the target, with the bits we'll overwrite masked off, or'ed with
|
||||
// the bits from the source we want.
|
||||
return (target & ~mask) | (source >> target_bit_offset);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace rtc {
|
||||
|
||||
BitBufferWriter::BitBufferWriter(uint8_t* bytes, size_t byte_count)
|
||||
: writable_bytes_(bytes),
|
||||
byte_count_(byte_count),
|
||||
byte_offset_(),
|
||||
bit_offset_() {
|
||||
RTC_DCHECK(static_cast<uint64_t>(byte_count_) <=
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
}
|
||||
|
||||
uint64_t BitBufferWriter::RemainingBitCount() const {
|
||||
return (static_cast<uint64_t>(byte_count_) - byte_offset_) * 8 - bit_offset_;
|
||||
}
|
||||
|
||||
bool BitBufferWriter::ConsumeBytes(size_t byte_count) {
|
||||
return ConsumeBits(byte_count * 8);
|
||||
}
|
||||
|
||||
bool BitBufferWriter::ConsumeBits(size_t bit_count) {
|
||||
if (bit_count > RemainingBitCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte_offset_ += (bit_offset_ + bit_count) / 8;
|
||||
bit_offset_ = (bit_offset_ + bit_count) % 8;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitBufferWriter::GetCurrentOffset(size_t* out_byte_offset,
|
||||
size_t* out_bit_offset) {
|
||||
RTC_CHECK(out_byte_offset != nullptr);
|
||||
RTC_CHECK(out_bit_offset != nullptr);
|
||||
*out_byte_offset = byte_offset_;
|
||||
*out_bit_offset = bit_offset_;
|
||||
}
|
||||
|
||||
bool BitBufferWriter::Seek(size_t byte_offset, size_t bit_offset) {
|
||||
if (byte_offset > byte_count_ || bit_offset > 7 ||
|
||||
(byte_offset == byte_count_ && bit_offset > 0)) {
|
||||
return false;
|
||||
}
|
||||
byte_offset_ = byte_offset;
|
||||
bit_offset_ = bit_offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteUInt8(uint8_t val) {
|
||||
return WriteBits(val, sizeof(uint8_t) * 8);
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteUInt16(uint16_t val) {
|
||||
return WriteBits(val, sizeof(uint16_t) * 8);
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteUInt32(uint32_t val) {
|
||||
return WriteBits(val, sizeof(uint32_t) * 8);
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteBits(uint64_t val, size_t bit_count) {
|
||||
if (bit_count > RemainingBitCount()) {
|
||||
return false;
|
||||
}
|
||||
size_t total_bits = bit_count;
|
||||
|
||||
// For simplicity, push the bits we want to read from val to the highest bits.
|
||||
val <<= (sizeof(uint64_t) * 8 - bit_count);
|
||||
|
||||
uint8_t* bytes = writable_bytes_ + byte_offset_;
|
||||
|
||||
// The first byte is relatively special; the bit offset to write to may put us
|
||||
// in the middle of the byte, and the total bit count to write may require we
|
||||
// save the bits at the end of the byte.
|
||||
size_t remaining_bits_in_current_byte = 8 - bit_offset_;
|
||||
size_t bits_in_first_byte =
|
||||
std::min(bit_count, remaining_bits_in_current_byte);
|
||||
*bytes = WritePartialByte(HighestByte(val), bits_in_first_byte, *bytes,
|
||||
bit_offset_);
|
||||
if (bit_count <= remaining_bits_in_current_byte) {
|
||||
// Nothing left to write, so quit early.
|
||||
return ConsumeBits(total_bits);
|
||||
}
|
||||
|
||||
// Subtract what we've written from the bit count, shift it off the value, and
|
||||
// write the remaining full bytes.
|
||||
val <<= bits_in_first_byte;
|
||||
bytes++;
|
||||
bit_count -= bits_in_first_byte;
|
||||
while (bit_count >= 8) {
|
||||
*bytes++ = HighestByte(val);
|
||||
val <<= 8;
|
||||
bit_count -= 8;
|
||||
}
|
||||
|
||||
// Last byte may also be partial, so write the remaining bits from the top of
|
||||
// val.
|
||||
if (bit_count > 0) {
|
||||
*bytes = WritePartialByte(HighestByte(val), bit_count, *bytes, 0);
|
||||
}
|
||||
|
||||
// All done! Consume the bits we've written.
|
||||
return ConsumeBits(total_bits);
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteNonSymmetric(uint32_t val, uint32_t num_values) {
|
||||
RTC_DCHECK_LT(val, num_values);
|
||||
RTC_DCHECK_LE(num_values, uint32_t{1} << 31);
|
||||
if (num_values == 1) {
|
||||
// When there is only one possible value, it requires zero bits to store it.
|
||||
// But WriteBits doesn't support writing zero bits.
|
||||
return true;
|
||||
}
|
||||
size_t count_bits = absl::bit_width(num_values);
|
||||
uint32_t num_min_bits_values = (uint32_t{1} << count_bits) - num_values;
|
||||
|
||||
return val < num_min_bits_values
|
||||
? WriteBits(val, count_bits - 1)
|
||||
: WriteBits(val + num_min_bits_values, count_bits);
|
||||
}
|
||||
|
||||
size_t BitBufferWriter::SizeNonSymmetricBits(uint32_t val,
|
||||
uint32_t num_values) {
|
||||
RTC_DCHECK_LT(val, num_values);
|
||||
RTC_DCHECK_LE(num_values, uint32_t{1} << 31);
|
||||
size_t count_bits = absl::bit_width(num_values);
|
||||
uint32_t num_min_bits_values = (uint32_t{1} << count_bits) - num_values;
|
||||
|
||||
return val < num_min_bits_values ? (count_bits - 1) : count_bits;
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteExponentialGolomb(uint32_t val) {
|
||||
// We don't support reading UINT32_MAX, because it doesn't fit in a uint32_t
|
||||
// when encoded, so don't support writing it either.
|
||||
if (val == std::numeric_limits<uint32_t>::max()) {
|
||||
return false;
|
||||
}
|
||||
uint64_t val_to_encode = static_cast<uint64_t>(val) + 1;
|
||||
|
||||
// We need to write bit_width(val+1) 0s and then val+1. Since val (as a
|
||||
// uint64_t) has leading zeros, we can just write the total golomb encoded
|
||||
// size worth of bits, knowing the value will appear last.
|
||||
return WriteBits(val_to_encode, absl::bit_width(val_to_encode) * 2 - 1);
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteSignedExponentialGolomb(int32_t val) {
|
||||
if (val == 0) {
|
||||
return WriteExponentialGolomb(0);
|
||||
} else if (val > 0) {
|
||||
uint32_t signed_val = val;
|
||||
return WriteExponentialGolomb((signed_val * 2) - 1);
|
||||
} else {
|
||||
if (val == std::numeric_limits<int32_t>::min())
|
||||
return false; // Not supported, would cause overflow.
|
||||
uint32_t signed_val = -val;
|
||||
return WriteExponentialGolomb(signed_val * 2);
|
||||
}
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteLeb128(uint64_t val) {
|
||||
bool success = true;
|
||||
do {
|
||||
uint8_t byte = static_cast<uint8_t>(val & 0x7f);
|
||||
val >>= 7;
|
||||
if (val > 0) {
|
||||
byte |= 0x80;
|
||||
}
|
||||
success &= WriteUInt8(byte);
|
||||
} while (val > 0);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool BitBufferWriter::WriteString(absl::string_view data) {
|
||||
bool success = true;
|
||||
for (char c : data) {
|
||||
success &= WriteUInt8(c);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
100
TMessagesProj/jni/voip/webrtc/rtc_base/bit_buffer.h
Normal file
100
TMessagesProj/jni/voip/webrtc/rtc_base/bit_buffer.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 RTC_BASE_BIT_BUFFER_H_
|
||||
#define RTC_BASE_BIT_BUFFER_H_
|
||||
|
||||
#include <stddef.h> // For size_t.
|
||||
#include <stdint.h> // For integer types.
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/units/data_size.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// A BitBuffer API for write operations. Supports symmetric write APIs to the
|
||||
// reading APIs of BitstreamReader.
|
||||
// Sizes/counts specify bits/bytes, for clarity.
|
||||
// Byte order is assumed big-endian/network.
|
||||
class BitBufferWriter {
|
||||
public:
|
||||
static constexpr webrtc::DataSize kMaxLeb128Length =
|
||||
webrtc::DataSize::Bytes(10);
|
||||
|
||||
// Constructs a bit buffer for the writable buffer of `bytes`.
|
||||
BitBufferWriter(uint8_t* bytes, size_t byte_count);
|
||||
|
||||
BitBufferWriter(const BitBufferWriter&) = delete;
|
||||
BitBufferWriter& operator=(const BitBufferWriter&) = delete;
|
||||
|
||||
// Gets the current offset, in bytes/bits, from the start of the buffer. The
|
||||
// bit offset is the offset into the current byte, in the range [0,7].
|
||||
void GetCurrentOffset(size_t* out_byte_offset, size_t* out_bit_offset);
|
||||
|
||||
// The remaining bits in the byte buffer.
|
||||
uint64_t RemainingBitCount() const;
|
||||
|
||||
// Moves current position `byte_count` bytes forward. Returns false if
|
||||
// there aren't enough bytes left in the buffer.
|
||||
bool ConsumeBytes(size_t byte_count);
|
||||
// Moves current position `bit_count` bits forward. Returns false if
|
||||
// there aren't enough bits left in the buffer.
|
||||
bool ConsumeBits(size_t bit_count);
|
||||
|
||||
// Sets the current offset to the provied byte/bit offsets. The bit
|
||||
// offset is from the given byte, in the range [0,7].
|
||||
bool Seek(size_t byte_offset, size_t bit_offset);
|
||||
|
||||
// Writes byte-sized values from the buffer. Returns false if there isn't
|
||||
// enough data left for the specified type.
|
||||
bool WriteUInt8(uint8_t val);
|
||||
bool WriteUInt16(uint16_t val);
|
||||
bool WriteUInt32(uint32_t val);
|
||||
|
||||
// Writes bit-sized values to the buffer. Returns false if there isn't enough
|
||||
// room left for the specified number of bits.
|
||||
bool WriteBits(uint64_t val, size_t bit_count);
|
||||
|
||||
// Writes value in range [0, num_values - 1]
|
||||
// See ReadNonSymmetric documentation for the format,
|
||||
// Call SizeNonSymmetricBits to get number of bits needed to store the value.
|
||||
// Returns false if there isn't enough room left for the value.
|
||||
bool WriteNonSymmetric(uint32_t val, uint32_t num_values);
|
||||
// Returns number of bits required to store `val` with NonSymmetric encoding.
|
||||
static size_t SizeNonSymmetricBits(uint32_t val, uint32_t num_values);
|
||||
|
||||
// Writes the exponential golomb encoded version of the supplied value.
|
||||
// Returns false if there isn't enough room left for the value.
|
||||
bool WriteExponentialGolomb(uint32_t val);
|
||||
// Writes the signed exponential golomb version of the supplied value.
|
||||
// Signed exponential golomb values are just the unsigned values mapped to the
|
||||
// sequence 0, 1, -1, 2, -2, etc. in order.
|
||||
bool WriteSignedExponentialGolomb(int32_t val);
|
||||
|
||||
// Writes the Leb128 encoded value.
|
||||
bool WriteLeb128(uint64_t val);
|
||||
|
||||
// Writes the string as bytes of data.
|
||||
bool WriteString(absl::string_view data);
|
||||
|
||||
private:
|
||||
// The buffer, as a writable array.
|
||||
uint8_t* const writable_bytes_;
|
||||
// The total size of `bytes_`.
|
||||
const size_t byte_count_;
|
||||
// The current offset, in bytes, from the start of `bytes_`.
|
||||
size_t byte_offset_;
|
||||
// The current offset, in bits, into the current byte.
|
||||
size_t bit_offset_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_BIT_BUFFER_H_
|
||||
38
TMessagesProj/jni/voip/webrtc/rtc_base/bitrate_tracker.cc
Normal file
38
TMessagesProj/jni/voip/webrtc/rtc_base/bitrate_tracker.cc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 "absl/types/optional.h"
|
||||
#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) {}
|
||||
|
||||
absl::optional<DataRate> BitrateTracker::Rate(Timestamp now) const {
|
||||
if (absl::optional<int64_t> rate = impl_.Rate(now.ms())) {
|
||||
return DataRate::BitsPerSec(*rate);
|
||||
}
|
||||
return absl::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
TMessagesProj/jni/voip/webrtc/rtc_base/bitrate_tracker.h
Normal file
64
TMessagesProj/jni/voip/webrtc/rtc_base/bitrate_tracker.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 "absl/types/optional.h"
|
||||
#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"
|
||||
#include "rtc_base/system/rtc_export.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 RTC_EXPORT 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.
|
||||
absl::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_
|
||||
167
TMessagesProj/jni/voip/webrtc/rtc_base/bitstream_reader.cc
Normal file
167
TMessagesProj/jni/voip/webrtc/rtc_base/bitstream_reader.cc
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/bitstream_reader.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "absl/numeric/bits.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
uint64_t BitstreamReader::ReadBits(int bits) {
|
||||
RTC_DCHECK_GE(bits, 0);
|
||||
RTC_DCHECK_LE(bits, 64);
|
||||
set_last_read_is_verified(false);
|
||||
|
||||
if (remaining_bits_ < bits) {
|
||||
remaining_bits_ -= bits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remaining_bits_in_first_byte = remaining_bits_ % 8;
|
||||
remaining_bits_ -= bits;
|
||||
if (bits < remaining_bits_in_first_byte) {
|
||||
// Reading fewer bits than what's left in the current byte, just
|
||||
// return the portion of this byte that is needed.
|
||||
int offset = (remaining_bits_in_first_byte - bits);
|
||||
return ((*bytes_) >> offset) & ((1 << bits) - 1);
|
||||
}
|
||||
|
||||
uint64_t result = 0;
|
||||
if (remaining_bits_in_first_byte > 0) {
|
||||
// Read all bits that were left in the current byte and consume that byte.
|
||||
bits -= remaining_bits_in_first_byte;
|
||||
uint8_t mask = (1 << remaining_bits_in_first_byte) - 1;
|
||||
result = static_cast<uint64_t>(*bytes_ & mask) << bits;
|
||||
++bytes_;
|
||||
}
|
||||
|
||||
// Read as many full bytes as we can.
|
||||
while (bits >= 8) {
|
||||
bits -= 8;
|
||||
result |= uint64_t{*bytes_} << bits;
|
||||
++bytes_;
|
||||
}
|
||||
// Whatever is left to read is smaller than a byte, so grab just the needed
|
||||
// bits and shift them into the lowest bits.
|
||||
if (bits > 0) {
|
||||
result |= (*bytes_ >> (8 - bits));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int BitstreamReader::ReadBit() {
|
||||
set_last_read_is_verified(false);
|
||||
--remaining_bits_;
|
||||
if (remaining_bits_ < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bit_position = remaining_bits_ % 8;
|
||||
if (bit_position == 0) {
|
||||
// Read the last bit from current byte and move to the next byte.
|
||||
return (*bytes_++) & 0x01;
|
||||
}
|
||||
|
||||
return (*bytes_ >> bit_position) & 0x01;
|
||||
}
|
||||
|
||||
void BitstreamReader::ConsumeBits(int bits) {
|
||||
RTC_DCHECK_GE(bits, 0);
|
||||
set_last_read_is_verified(false);
|
||||
if (remaining_bits_ < bits) {
|
||||
Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
int remaining_bytes = (remaining_bits_ + 7) / 8;
|
||||
remaining_bits_ -= bits;
|
||||
int new_remaining_bytes = (remaining_bits_ + 7) / 8;
|
||||
bytes_ += (remaining_bytes - new_remaining_bytes);
|
||||
}
|
||||
|
||||
uint32_t BitstreamReader::ReadNonSymmetric(uint32_t num_values) {
|
||||
RTC_DCHECK_GT(num_values, 0);
|
||||
RTC_DCHECK_LE(num_values, uint32_t{1} << 31);
|
||||
|
||||
int width = absl::bit_width(num_values);
|
||||
uint32_t num_min_bits_values = (uint32_t{1} << width) - num_values;
|
||||
|
||||
uint64_t val = ReadBits(width - 1);
|
||||
if (val < num_min_bits_values) {
|
||||
return val;
|
||||
}
|
||||
return (val << 1) + ReadBit() - num_min_bits_values;
|
||||
}
|
||||
|
||||
uint32_t BitstreamReader::ReadExponentialGolomb() {
|
||||
// Count the number of leading 0.
|
||||
int zero_bit_count = 0;
|
||||
while (ReadBit() == 0) {
|
||||
if (++zero_bit_count >= 32) {
|
||||
// Golob value won't fit into 32 bits of the return value. Fail the parse.
|
||||
Invalidate();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The bit count of the value is the number of zeros + 1.
|
||||
// However the first '1' was already read above.
|
||||
return (uint32_t{1} << zero_bit_count) +
|
||||
rtc::dchecked_cast<uint32_t>(ReadBits(zero_bit_count)) - 1;
|
||||
}
|
||||
|
||||
int BitstreamReader::ReadSignedExponentialGolomb() {
|
||||
uint32_t unsigned_val = ReadExponentialGolomb();
|
||||
if ((unsigned_val & 1) == 0) {
|
||||
return -static_cast<int>(unsigned_val / 2);
|
||||
} else {
|
||||
return (unsigned_val + 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t BitstreamReader::ReadLeb128() {
|
||||
uint64_t decoded = 0;
|
||||
size_t i = 0;
|
||||
uint8_t byte;
|
||||
// A LEB128 value can in theory be arbitrarily large, but for convenience sake
|
||||
// consider it invalid if it can't fit in an uint64_t.
|
||||
do {
|
||||
byte = Read<uint8_t>();
|
||||
decoded +=
|
||||
(static_cast<uint64_t>(byte & 0x7f) << static_cast<uint64_t>(7 * i));
|
||||
++i;
|
||||
} while (i < 10 && (byte & 0x80));
|
||||
|
||||
// The first 9 bytes represent the first 63 bits. The tenth byte can therefore
|
||||
// not be larger than 1 as it would overflow an uint64_t.
|
||||
if (i == 10 && byte > 1) {
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
return Ok() ? decoded : 0;
|
||||
}
|
||||
|
||||
std::string BitstreamReader::ReadString(int num_bytes) {
|
||||
std::string res;
|
||||
res.reserve(num_bytes);
|
||||
for (int i = 0; i < num_bytes; ++i) {
|
||||
res += Read<uint8_t>();
|
||||
}
|
||||
|
||||
return Ok() ? res : std::string();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
152
TMessagesProj/jni/voip/webrtc/rtc_base/bitstream_reader.h
Normal file
152
TMessagesProj/jni/voip/webrtc/rtc_base/bitstream_reader.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* 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_BITSTREAM_READER_H_
|
||||
#define RTC_BASE_BITSTREAM_READER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/array_view.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// A class to parse sequence of bits. Byte order is assumed big-endian/network.
|
||||
// This class is optimized for successful parsing and binary size.
|
||||
// Individual calls to `Read` and `ConsumeBits` never fail. Instead they may
|
||||
// change the class state into 'failure state'. User of this class should verify
|
||||
// parsing by checking if class is in that 'failure state' by calling `Ok`.
|
||||
// That verification can be done once after multiple reads.
|
||||
class BitstreamReader {
|
||||
public:
|
||||
explicit BitstreamReader(
|
||||
rtc::ArrayView<const uint8_t> bytes ABSL_ATTRIBUTE_LIFETIME_BOUND);
|
||||
explicit BitstreamReader(
|
||||
absl::string_view bytes ABSL_ATTRIBUTE_LIFETIME_BOUND);
|
||||
BitstreamReader(const BitstreamReader&) = default;
|
||||
BitstreamReader& operator=(const BitstreamReader&) = default;
|
||||
~BitstreamReader();
|
||||
|
||||
// Return number of unread bits in the buffer, or negative number if there
|
||||
// was a reading error.
|
||||
int RemainingBitCount() const;
|
||||
|
||||
// Returns `true` iff all calls to `Read` and `ConsumeBits` were successful.
|
||||
bool Ok() const { return RemainingBitCount() >= 0; }
|
||||
|
||||
// Sets `BitstreamReader` into the failure state.
|
||||
void Invalidate() { remaining_bits_ = -1; }
|
||||
|
||||
// Moves current read position forward. `bits` must be non-negative.
|
||||
void ConsumeBits(int bits);
|
||||
|
||||
// Reads single bit. Returns 0 or 1.
|
||||
ABSL_MUST_USE_RESULT int ReadBit();
|
||||
|
||||
// Reads `bits` from the bitstream. `bits` must be in range [0, 64].
|
||||
// Returns an unsigned integer in range [0, 2^bits - 1].
|
||||
// On failure sets `BitstreamReader` into the failure state and returns 0.
|
||||
ABSL_MUST_USE_RESULT uint64_t ReadBits(int bits);
|
||||
|
||||
// Reads unsigned integer of fixed width.
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_unsigned<T>::value &&
|
||||
!std::is_same<T, bool>::value &&
|
||||
sizeof(T) <= 8>::type* = nullptr>
|
||||
ABSL_MUST_USE_RESULT T Read() {
|
||||
return rtc::dchecked_cast<T>(ReadBits(sizeof(T) * 8));
|
||||
}
|
||||
|
||||
// Reads single bit as boolean.
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_same<T, bool>::value>::type* = nullptr>
|
||||
ABSL_MUST_USE_RESULT bool Read() {
|
||||
return ReadBit() != 0;
|
||||
}
|
||||
|
||||
// Reads value in range [0, `num_values` - 1].
|
||||
// This encoding is similar to ReadBits(val, Ceil(Log2(num_values)),
|
||||
// but reduces wastage incurred when encoding non-power of two value ranges
|
||||
// Non symmetric values are encoded as:
|
||||
// 1) n = bit_width(num_values)
|
||||
// 2) k = (1 << n) - num_values
|
||||
// Value v in range [0, k - 1] is encoded in (n-1) bits.
|
||||
// Value v in range [k, num_values - 1] is encoded as (v+k) in n bits.
|
||||
// https://aomediacodec.github.io/av1-spec/#nsn
|
||||
uint32_t ReadNonSymmetric(uint32_t num_values);
|
||||
|
||||
// Reads exponential golomb encoded value.
|
||||
// On failure sets `BitstreamReader` into the failure state and returns
|
||||
// unspecified value.
|
||||
// Exponential golomb values are encoded as:
|
||||
// 1) x = source val + 1
|
||||
// 2) In binary, write [bit_width(x) - 1] 0s, then x
|
||||
// To decode, we count the number of leading 0 bits, read that many + 1 bits,
|
||||
// and increment the result by 1.
|
||||
// Fails the parsing if the value wouldn't fit in a uint32_t.
|
||||
uint32_t ReadExponentialGolomb();
|
||||
|
||||
// Reads signed exponential golomb values at the current offset. Signed
|
||||
// exponential golomb values are just the unsigned values mapped to the
|
||||
// sequence 0, 1, -1, 2, -2, etc. in order.
|
||||
// On failure sets `BitstreamReader` into the failure state and returns
|
||||
// unspecified value.
|
||||
int ReadSignedExponentialGolomb();
|
||||
|
||||
// Reads a LEB128 encoded value. The value will be considered invalid if it
|
||||
// can't fit into a uint64_t.
|
||||
uint64_t ReadLeb128();
|
||||
|
||||
std::string ReadString(int num_bytes);
|
||||
|
||||
private:
|
||||
void set_last_read_is_verified(bool value) const;
|
||||
|
||||
// Next byte with at least one unread bit.
|
||||
const uint8_t* bytes_;
|
||||
|
||||
// Number of bits remained to read.
|
||||
int remaining_bits_;
|
||||
|
||||
// Unused in release mode.
|
||||
mutable bool last_read_is_verified_ = true;
|
||||
};
|
||||
|
||||
inline BitstreamReader::BitstreamReader(rtc::ArrayView<const uint8_t> bytes)
|
||||
: bytes_(bytes.data()),
|
||||
remaining_bits_(rtc::checked_cast<int>(bytes.size() * 8)) {}
|
||||
|
||||
inline BitstreamReader::BitstreamReader(absl::string_view bytes)
|
||||
: bytes_(reinterpret_cast<const uint8_t*>(bytes.data())),
|
||||
remaining_bits_(rtc::checked_cast<int>(bytes.size() * 8)) {}
|
||||
|
||||
inline BitstreamReader::~BitstreamReader() {
|
||||
RTC_DCHECK(last_read_is_verified_) << "Latest calls to Read or ConsumeBit "
|
||||
"were not checked with Ok function.";
|
||||
}
|
||||
|
||||
inline void BitstreamReader::set_last_read_is_verified(bool value) const {
|
||||
#ifdef RTC_DCHECK_IS_ON
|
||||
last_read_is_verified_ = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int BitstreamReader::RemainingBitCount() const {
|
||||
set_last_read_is_verified(true);
|
||||
return remaining_bits_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_BITSTREAM_READER_H_
|
||||
412
TMessagesProj/jni/voip/webrtc/rtc_base/boringssl_certificate.cc
Normal file
412
TMessagesProj/jni/voip/webrtc/rtc_base/boringssl_certificate.cc
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* 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/boringssl_certificate.h"
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
// Must be included first before openssl headers.
|
||||
#include "rtc_base/win32.h" // NOLINT
|
||||
#endif // WEBRTC_WIN
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/digest.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/pool.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/helpers.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/message_digest.h"
|
||||
#include "rtc_base/openssl_digest.h"
|
||||
#include "rtc_base/openssl_key_pair.h"
|
||||
#include "rtc_base/openssl_utility.h"
|
||||
|
||||
namespace rtc {
|
||||
namespace {
|
||||
|
||||
// List of OIDs of signature algorithms accepted by WebRTC.
|
||||
// Taken from openssl/nid.h.
|
||||
static const uint8_t kMD5WithRSA[] = {0x2b, 0x0e, 0x03, 0x02, 0x03};
|
||||
static const uint8_t kMD5WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x04};
|
||||
static const uint8_t kECDSAWithSHA1[] = {0x2a, 0x86, 0x48, 0xce,
|
||||
0x3d, 0x04, 0x01};
|
||||
static const uint8_t kDSAWithSHA1[] = {0x2a, 0x86, 0x48, 0xce,
|
||||
0x38, 0x04, 0x03};
|
||||
static const uint8_t kDSAWithSHA1_2[] = {0x2b, 0x0e, 0x03, 0x02, 0x1b};
|
||||
static const uint8_t kSHA1WithRSA[] = {0x2b, 0x0e, 0x03, 0x02, 0x1d};
|
||||
static const uint8_t kSHA1WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x05};
|
||||
static const uint8_t kECDSAWithSHA224[] = {0x2a, 0x86, 0x48, 0xce,
|
||||
0x3d, 0x04, 0x03, 0x01};
|
||||
static const uint8_t kSHA224WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x0e};
|
||||
static const uint8_t kDSAWithSHA224[] = {0x60, 0x86, 0x48, 0x01, 0x65,
|
||||
0x03, 0x04, 0x03, 0x01};
|
||||
static const uint8_t kECDSAWithSHA256[] = {0x2a, 0x86, 0x48, 0xce,
|
||||
0x3d, 0x04, 0x03, 0x02};
|
||||
static const uint8_t kSHA256WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x0b};
|
||||
static const uint8_t kDSAWithSHA256[] = {0x60, 0x86, 0x48, 0x01, 0x65,
|
||||
0x03, 0x04, 0x03, 0x02};
|
||||
static const uint8_t kECDSAWithSHA384[] = {0x2a, 0x86, 0x48, 0xce,
|
||||
0x3d, 0x04, 0x03, 0x03};
|
||||
static const uint8_t kSHA384WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x0c};
|
||||
static const uint8_t kECDSAWithSHA512[] = {0x2a, 0x86, 0x48, 0xce,
|
||||
0x3d, 0x04, 0x03, 0x04};
|
||||
static const uint8_t kSHA512WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x0d};
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
// Print a certificate to the log, for debugging.
|
||||
static void PrintCert(BoringSSLCertificate* cert) {
|
||||
// Since we're using CRYPTO_BUFFER, we can't use X509_print_ex, so we'll just
|
||||
// print the PEM string.
|
||||
RTC_DLOG(LS_VERBOSE) << "PEM representation of certificate:\n"
|
||||
<< cert->ToPEMString();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool AddSHA256SignatureAlgorithm(CBB* cbb, KeyType key_type) {
|
||||
// An AlgorithmIdentifier is described in RFC 5280, 4.1.1.2.
|
||||
CBB sequence, oid, params;
|
||||
if (!CBB_add_asn1(cbb, &sequence, CBS_ASN1_SEQUENCE) ||
|
||||
!CBB_add_asn1(&sequence, &oid, CBS_ASN1_OBJECT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (key_type) {
|
||||
case KT_RSA:
|
||||
if (!CBB_add_bytes(&oid, kSHA256WithRSAEncryption,
|
||||
sizeof(kSHA256WithRSAEncryption)) ||
|
||||
!CBB_add_asn1(&sequence, ¶ms, CBS_ASN1_NULL)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case KT_ECDSA:
|
||||
if (!CBB_add_bytes(&oid, kECDSAWithSHA256, sizeof(kECDSAWithSHA256))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
if (!CBB_flush(cbb)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adds an X.509 Common Name to `cbb`.
|
||||
bool AddCommonName(CBB* cbb, absl::string_view common_name) {
|
||||
// See RFC 4519.
|
||||
static const uint8_t kCommonName[] = {0x55, 0x04, 0x03};
|
||||
|
||||
if (common_name.empty()) {
|
||||
RTC_LOG(LS_ERROR) << "Common name cannot be empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// See RFC 5280, section 4.1.2.4.
|
||||
CBB rdns;
|
||||
if (!CBB_add_asn1(cbb, &rdns, CBS_ASN1_SEQUENCE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CBB rdn, attr, type, value;
|
||||
if (!CBB_add_asn1(&rdns, &rdn, CBS_ASN1_SET) ||
|
||||
!CBB_add_asn1(&rdn, &attr, CBS_ASN1_SEQUENCE) ||
|
||||
!CBB_add_asn1(&attr, &type, CBS_ASN1_OBJECT) ||
|
||||
!CBB_add_bytes(&type, kCommonName, sizeof(kCommonName)) ||
|
||||
!CBB_add_asn1(&attr, &value, CBS_ASN1_UTF8STRING) ||
|
||||
!CBB_add_bytes(&value,
|
||||
reinterpret_cast<const uint8_t*>(common_name.data()),
|
||||
common_name.size()) ||
|
||||
!CBB_flush(cbb)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddTime(CBB* cbb, time_t time) {
|
||||
bssl::UniquePtr<ASN1_TIME> asn1_time(ASN1_TIME_new());
|
||||
if (!asn1_time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ASN1_TIME_set(asn1_time.get(), time)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned tag;
|
||||
switch (asn1_time->type) {
|
||||
case V_ASN1_UTCTIME:
|
||||
tag = CBS_ASN1_UTCTIME;
|
||||
break;
|
||||
case V_ASN1_GENERALIZEDTIME:
|
||||
tag = CBS_ASN1_GENERALIZEDTIME;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
CBB child;
|
||||
if (!CBB_add_asn1(cbb, &child, tag) ||
|
||||
!CBB_add_bytes(&child, asn1_time->data, asn1_time->length) ||
|
||||
!CBB_flush(cbb)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate a self-signed certificate, with the public key from the
|
||||
// given key pair. Caller is responsible for freeing the returned object.
|
||||
static bssl::UniquePtr<CRYPTO_BUFFER> MakeCertificate(
|
||||
EVP_PKEY* pkey,
|
||||
const SSLIdentityParams& params) {
|
||||
RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name;
|
||||
|
||||
// See RFC 5280, section 4.1. First, construct the TBSCertificate.
|
||||
bssl::ScopedCBB cbb;
|
||||
CBB tbs_cert, version, validity;
|
||||
uint8_t* tbs_cert_bytes;
|
||||
size_t tbs_cert_len;
|
||||
uint64_t serial_number;
|
||||
if (!CBB_init(cbb.get(), 64) ||
|
||||
!CBB_add_asn1(cbb.get(), &tbs_cert, CBS_ASN1_SEQUENCE) ||
|
||||
!CBB_add_asn1(&tbs_cert, &version,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
|
||||
!CBB_add_asn1_uint64(&version, 2) ||
|
||||
!RAND_bytes(reinterpret_cast<uint8_t*>(&serial_number),
|
||||
sizeof(serial_number)) ||
|
||||
!CBB_add_asn1_uint64(&tbs_cert, serial_number) ||
|
||||
!AddSHA256SignatureAlgorithm(&tbs_cert, params.key_params.type()) ||
|
||||
!AddCommonName(&tbs_cert, params.common_name) || // issuer
|
||||
!CBB_add_asn1(&tbs_cert, &validity, CBS_ASN1_SEQUENCE) ||
|
||||
!AddTime(&validity, params.not_before) ||
|
||||
!AddTime(&validity, params.not_after) ||
|
||||
!AddCommonName(&tbs_cert, params.common_name) || // subject
|
||||
!EVP_marshal_public_key(&tbs_cert, pkey) || // subjectPublicKeyInfo
|
||||
!CBB_finish(cbb.get(), &tbs_cert_bytes, &tbs_cert_len)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<uint8_t> delete_tbs_cert_bytes(tbs_cert_bytes);
|
||||
|
||||
// Sign the TBSCertificate and write the entire certificate.
|
||||
CBB cert, signature;
|
||||
bssl::ScopedEVP_MD_CTX ctx;
|
||||
uint8_t* sig_out;
|
||||
size_t sig_len;
|
||||
uint8_t* cert_bytes;
|
||||
size_t cert_len;
|
||||
if (!CBB_init(cbb.get(), tbs_cert_len) ||
|
||||
!CBB_add_asn1(cbb.get(), &cert, CBS_ASN1_SEQUENCE) ||
|
||||
!CBB_add_bytes(&cert, tbs_cert_bytes, tbs_cert_len) ||
|
||||
!AddSHA256SignatureAlgorithm(&cert, params.key_params.type()) ||
|
||||
!CBB_add_asn1(&cert, &signature, CBS_ASN1_BITSTRING) ||
|
||||
!CBB_add_u8(&signature, 0 /* no unused bits */) ||
|
||||
!EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, pkey) ||
|
||||
// Compute the maximum signature length.
|
||||
!EVP_DigestSign(ctx.get(), nullptr, &sig_len, tbs_cert_bytes,
|
||||
tbs_cert_len) ||
|
||||
!CBB_reserve(&signature, &sig_out, sig_len) ||
|
||||
// Actually sign the TBSCertificate.
|
||||
!EVP_DigestSign(ctx.get(), sig_out, &sig_len, tbs_cert_bytes,
|
||||
tbs_cert_len) ||
|
||||
!CBB_did_write(&signature, sig_len) ||
|
||||
!CBB_finish(cbb.get(), &cert_bytes, &cert_len)) {
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> delete_cert_bytes(cert_bytes);
|
||||
|
||||
RTC_LOG(LS_INFO) << "Returning certificate";
|
||||
return bssl::UniquePtr<CRYPTO_BUFFER>(
|
||||
CRYPTO_BUFFER_new(cert_bytes, cert_len, openssl::GetBufferPool()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BoringSSLCertificate::BoringSSLCertificate(
|
||||
bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer)
|
||||
: cert_buffer_(std::move(cert_buffer)) {
|
||||
RTC_DCHECK(cert_buffer_ != nullptr);
|
||||
}
|
||||
|
||||
std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::Generate(
|
||||
OpenSSLKeyPair* key_pair,
|
||||
const SSLIdentityParams& params) {
|
||||
SSLIdentityParams actual_params(params);
|
||||
if (actual_params.common_name.empty()) {
|
||||
// Use a random string, arbitrarily 8 chars long.
|
||||
actual_params.common_name = CreateRandomString(8);
|
||||
}
|
||||
bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer =
|
||||
MakeCertificate(key_pair->pkey(), actual_params);
|
||||
if (!cert_buffer) {
|
||||
openssl::LogSSLErrors("Generating certificate");
|
||||
return nullptr;
|
||||
}
|
||||
auto ret = std::make_unique<BoringSSLCertificate>(std::move(cert_buffer));
|
||||
#if !defined(NDEBUG)
|
||||
PrintCert(ret.get());
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::FromPEMString(
|
||||
absl::string_view pem_string) {
|
||||
std::string der;
|
||||
if (!SSLIdentity::PemToDer(kPemTypeCertificate, pem_string, &der)) {
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer(
|
||||
CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(der.c_str()),
|
||||
der.length(), openssl::GetBufferPool()));
|
||||
if (!cert_buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<BoringSSLCertificate>(std::move(cert_buffer));
|
||||
}
|
||||
|
||||
#define OID_MATCHES(oid, oid_other) \
|
||||
(CBS_len(&oid) == sizeof(oid_other) && \
|
||||
0 == memcmp(CBS_data(&oid), oid_other, sizeof(oid_other)))
|
||||
|
||||
bool BoringSSLCertificate::GetSignatureDigestAlgorithm(
|
||||
std::string* algorithm) const {
|
||||
CBS oid;
|
||||
if (!openssl::ParseCertificate(cert_buffer_.get(), &oid, nullptr)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to parse certificate.";
|
||||
return false;
|
||||
}
|
||||
if (OID_MATCHES(oid, kMD5WithRSA) ||
|
||||
OID_MATCHES(oid, kMD5WithRSAEncryption)) {
|
||||
*algorithm = DIGEST_MD5;
|
||||
return true;
|
||||
}
|
||||
if (OID_MATCHES(oid, kECDSAWithSHA1) || OID_MATCHES(oid, kDSAWithSHA1) ||
|
||||
OID_MATCHES(oid, kDSAWithSHA1_2) || OID_MATCHES(oid, kSHA1WithRSA) ||
|
||||
OID_MATCHES(oid, kSHA1WithRSAEncryption)) {
|
||||
*algorithm = DIGEST_SHA_1;
|
||||
return true;
|
||||
}
|
||||
if (OID_MATCHES(oid, kECDSAWithSHA224) ||
|
||||
OID_MATCHES(oid, kSHA224WithRSAEncryption) ||
|
||||
OID_MATCHES(oid, kDSAWithSHA224)) {
|
||||
*algorithm = DIGEST_SHA_224;
|
||||
return true;
|
||||
}
|
||||
if (OID_MATCHES(oid, kECDSAWithSHA256) ||
|
||||
OID_MATCHES(oid, kSHA256WithRSAEncryption) ||
|
||||
OID_MATCHES(oid, kDSAWithSHA256)) {
|
||||
*algorithm = DIGEST_SHA_256;
|
||||
return true;
|
||||
}
|
||||
if (OID_MATCHES(oid, kECDSAWithSHA384) ||
|
||||
OID_MATCHES(oid, kSHA384WithRSAEncryption)) {
|
||||
*algorithm = DIGEST_SHA_384;
|
||||
return true;
|
||||
}
|
||||
if (OID_MATCHES(oid, kECDSAWithSHA512) ||
|
||||
OID_MATCHES(oid, kSHA512WithRSAEncryption)) {
|
||||
*algorithm = DIGEST_SHA_512;
|
||||
return true;
|
||||
}
|
||||
// Unknown algorithm. There are several unhandled options that are less
|
||||
// common and more complex.
|
||||
RTC_LOG(LS_ERROR) << "Unknown signature algorithm.";
|
||||
algorithm->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BoringSSLCertificate::ComputeDigest(absl::string_view algorithm,
|
||||
unsigned char* digest,
|
||||
size_t size,
|
||||
size_t* length) const {
|
||||
return ComputeDigest(cert_buffer_.get(), algorithm, digest, size, length);
|
||||
}
|
||||
|
||||
bool BoringSSLCertificate::ComputeDigest(const CRYPTO_BUFFER* cert_buffer,
|
||||
absl::string_view algorithm,
|
||||
unsigned char* digest,
|
||||
size_t size,
|
||||
size_t* length) {
|
||||
const EVP_MD* md = nullptr;
|
||||
unsigned int n = 0;
|
||||
if (!OpenSSLDigest::GetDigestEVP(algorithm, &md)) {
|
||||
return false;
|
||||
}
|
||||
if (size < static_cast<size_t>(EVP_MD_size(md))) {
|
||||
return false;
|
||||
}
|
||||
if (!EVP_Digest(CRYPTO_BUFFER_data(cert_buffer),
|
||||
CRYPTO_BUFFER_len(cert_buffer), digest, &n, md, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
*length = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
BoringSSLCertificate::~BoringSSLCertificate() {}
|
||||
|
||||
std::unique_ptr<SSLCertificate> BoringSSLCertificate::Clone() const {
|
||||
return std::make_unique<BoringSSLCertificate>(
|
||||
bssl::UpRef(cert_buffer_.get()));
|
||||
}
|
||||
|
||||
std::string BoringSSLCertificate::ToPEMString() const {
|
||||
return SSLIdentity::DerToPem(kPemTypeCertificate,
|
||||
CRYPTO_BUFFER_data(cert_buffer_.get()),
|
||||
CRYPTO_BUFFER_len(cert_buffer_.get()));
|
||||
}
|
||||
|
||||
void BoringSSLCertificate::ToDER(Buffer* der_buffer) const {
|
||||
der_buffer->SetData(CRYPTO_BUFFER_data(cert_buffer_.get()),
|
||||
CRYPTO_BUFFER_len(cert_buffer_.get()));
|
||||
}
|
||||
|
||||
bool BoringSSLCertificate::operator==(const BoringSSLCertificate& other) const {
|
||||
return CRYPTO_BUFFER_len(cert_buffer_.get()) ==
|
||||
CRYPTO_BUFFER_len(other.cert_buffer_.get()) &&
|
||||
0 == memcmp(CRYPTO_BUFFER_data(cert_buffer_.get()),
|
||||
CRYPTO_BUFFER_data(other.cert_buffer_.get()),
|
||||
CRYPTO_BUFFER_len(cert_buffer_.get()));
|
||||
}
|
||||
|
||||
bool BoringSSLCertificate::operator!=(const BoringSSLCertificate& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
int64_t BoringSSLCertificate::CertificateExpirationTime() const {
|
||||
int64_t ret;
|
||||
if (!openssl::ParseCertificate(cert_buffer_.get(), nullptr, &ret)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to parse certificate.";
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_BORINGSSL_CERTIFICATE_H_
|
||||
#define RTC_BASE_BORINGSSL_CERTIFICATE_H_
|
||||
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
#include "rtc_base/ssl_certificate.h"
|
||||
#include "rtc_base/ssl_identity.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class OpenSSLKeyPair;
|
||||
|
||||
// BoringSSLCertificate encapsulates a BoringSSL CRYPTO_BUFFER object holding a
|
||||
// certificate, which is also reference counted inside the BoringSSL library.
|
||||
// This offers binary size and memory improvements over the OpenSSL X509
|
||||
// object.
|
||||
class BoringSSLCertificate final : public SSLCertificate {
|
||||
public:
|
||||
explicit BoringSSLCertificate(bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer);
|
||||
|
||||
static std::unique_ptr<BoringSSLCertificate> Generate(
|
||||
OpenSSLKeyPair* key_pair,
|
||||
const SSLIdentityParams& params);
|
||||
static std::unique_ptr<BoringSSLCertificate> FromPEMString(
|
||||
absl::string_view pem_string);
|
||||
|
||||
~BoringSSLCertificate() override;
|
||||
|
||||
BoringSSLCertificate(const BoringSSLCertificate&) = delete;
|
||||
BoringSSLCertificate& operator=(const BoringSSLCertificate&) = delete;
|
||||
|
||||
std::unique_ptr<SSLCertificate> Clone() const override;
|
||||
|
||||
CRYPTO_BUFFER* cert_buffer() const { return cert_buffer_.get(); }
|
||||
|
||||
std::string ToPEMString() const override;
|
||||
void ToDER(Buffer* der_buffer) const override;
|
||||
bool operator==(const BoringSSLCertificate& other) const;
|
||||
bool operator!=(const BoringSSLCertificate& other) const;
|
||||
|
||||
// Compute the digest of the certificate given `algorithm`.
|
||||
bool ComputeDigest(absl::string_view algorithm,
|
||||
unsigned char* digest,
|
||||
size_t size,
|
||||
size_t* length) const override;
|
||||
|
||||
// Compute the digest of a certificate as a CRYPTO_BUFFER.
|
||||
static bool ComputeDigest(const CRYPTO_BUFFER* cert_buffer,
|
||||
absl::string_view algorithm,
|
||||
unsigned char* digest,
|
||||
size_t size,
|
||||
size_t* length);
|
||||
|
||||
bool GetSignatureDigestAlgorithm(std::string* algorithm) const override;
|
||||
|
||||
int64_t CertificateExpirationTime() const override;
|
||||
|
||||
private:
|
||||
// A handle to the DER encoded certificate data.
|
||||
bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_BORINGSSL_CERTIFICATE_H_
|
||||
216
TMessagesProj/jni/voip/webrtc/rtc_base/boringssl_identity.cc
Normal file
216
TMessagesProj/jni/voip/webrtc/rtc_base/boringssl_identity.cc
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* 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/boringssl_identity.h"
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
#include "rtc_base/openssl.h"
|
||||
#include "rtc_base/openssl_utility.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
BoringSSLIdentity::BoringSSLIdentity(
|
||||
std::unique_ptr<OpenSSLKeyPair> key_pair,
|
||||
std::unique_ptr<BoringSSLCertificate> certificate)
|
||||
: key_pair_(std::move(key_pair)) {
|
||||
RTC_DCHECK(key_pair_ != nullptr);
|
||||
RTC_DCHECK(certificate != nullptr);
|
||||
std::vector<std::unique_ptr<SSLCertificate>> certs;
|
||||
certs.push_back(std::move(certificate));
|
||||
cert_chain_.reset(new SSLCertChain(std::move(certs)));
|
||||
}
|
||||
|
||||
BoringSSLIdentity::BoringSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
|
||||
std::unique_ptr<SSLCertChain> cert_chain)
|
||||
: key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) {
|
||||
RTC_DCHECK(key_pair_ != nullptr);
|
||||
RTC_DCHECK(cert_chain_ != nullptr);
|
||||
}
|
||||
|
||||
BoringSSLIdentity::~BoringSSLIdentity() = default;
|
||||
|
||||
std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateInternal(
|
||||
const SSLIdentityParams& params) {
|
||||
auto key_pair = OpenSSLKeyPair::Generate(params.key_params);
|
||||
if (key_pair) {
|
||||
std::unique_ptr<BoringSSLCertificate> certificate(
|
||||
BoringSSLCertificate::Generate(key_pair.get(), params));
|
||||
if (certificate != nullptr) {
|
||||
return absl::WrapUnique(
|
||||
new BoringSSLIdentity(std::move(key_pair), std::move(certificate)));
|
||||
}
|
||||
}
|
||||
RTC_LOG(LS_ERROR) << "Identity generation failed.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateWithExpiration(
|
||||
absl::string_view common_name,
|
||||
const KeyParams& key_params,
|
||||
time_t certificate_lifetime) {
|
||||
SSLIdentityParams params;
|
||||
params.key_params = key_params;
|
||||
params.common_name = std::string(common_name);
|
||||
time_t now = time(nullptr);
|
||||
params.not_before = now + kCertificateWindowInSeconds;
|
||||
params.not_after = now + certificate_lifetime;
|
||||
if (params.not_before > params.not_after)
|
||||
return nullptr;
|
||||
return CreateInternal(params);
|
||||
}
|
||||
|
||||
std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateForTest(
|
||||
const SSLIdentityParams& params) {
|
||||
return CreateInternal(params);
|
||||
}
|
||||
|
||||
std::unique_ptr<SSLIdentity> BoringSSLIdentity::CreateFromPEMStrings(
|
||||
absl::string_view private_key,
|
||||
absl::string_view certificate) {
|
||||
std::unique_ptr<BoringSSLCertificate> cert(
|
||||
BoringSSLCertificate::FromPEMString(certificate));
|
||||
if (!cert) {
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< "Failed to create BoringSSLCertificate from PEM string.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
|
||||
if (!key_pair) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return absl::WrapUnique(
|
||||
new BoringSSLIdentity(std::move(key_pair), std::move(cert)));
|
||||
}
|
||||
|
||||
std::unique_ptr<SSLIdentity> BoringSSLIdentity::CreateFromPEMChainStrings(
|
||||
absl::string_view private_key,
|
||||
absl::string_view certificate_chain) {
|
||||
bssl::UniquePtr<BIO> bio(
|
||||
BIO_new_mem_buf(certificate_chain.data(),
|
||||
rtc::dchecked_cast<int>(certificate_chain.size())));
|
||||
if (!bio) {
|
||||
return nullptr;
|
||||
}
|
||||
BIO_set_mem_eof_return(bio.get(), 0);
|
||||
std::vector<std::unique_ptr<SSLCertificate>> certs;
|
||||
while (true) {
|
||||
char* name;
|
||||
char* header;
|
||||
unsigned char* data;
|
||||
long len; // NOLINT
|
||||
int ret = PEM_read_bio(bio.get(), &name, &header, &data, &len);
|
||||
if (ret == 0) {
|
||||
uint32_t err = ERR_peek_error();
|
||||
if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
|
||||
ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
|
||||
break;
|
||||
}
|
||||
RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string.";
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<char> owned_name(name);
|
||||
bssl::UniquePtr<char> owned_header(header);
|
||||
bssl::UniquePtr<unsigned char> owned_data(data);
|
||||
if (strcmp(owned_name.get(), PEM_STRING_X509) != 0) {
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< "Non-certificate found while parsing certificate chain: "
|
||||
<< owned_name.get();
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<CRYPTO_BUFFER> crypto_buffer(
|
||||
CRYPTO_BUFFER_new(data, len, openssl::GetBufferPool()));
|
||||
if (!crypto_buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
certs.emplace_back(new BoringSSLCertificate(std::move(crypto_buffer)));
|
||||
}
|
||||
if (certs.empty()) {
|
||||
RTC_LOG(LS_ERROR) << "Found no certificates in PEM string.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
|
||||
if (!key_pair) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return absl::WrapUnique(new BoringSSLIdentity(
|
||||
std::move(key_pair), std::make_unique<SSLCertChain>(std::move(certs))));
|
||||
}
|
||||
|
||||
const BoringSSLCertificate& BoringSSLIdentity::certificate() const {
|
||||
return *static_cast<const BoringSSLCertificate*>(&cert_chain_->Get(0));
|
||||
}
|
||||
|
||||
const SSLCertChain& BoringSSLIdentity::cert_chain() const {
|
||||
return *cert_chain_.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<SSLIdentity> BoringSSLIdentity::CloneInternal() const {
|
||||
// We cannot use std::make_unique here because the referenced
|
||||
// BoringSSLIdentity constructor is private.
|
||||
return absl::WrapUnique(
|
||||
new BoringSSLIdentity(key_pair_->Clone(), cert_chain_->Clone()));
|
||||
}
|
||||
|
||||
bool BoringSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
|
||||
std::vector<CRYPTO_BUFFER*> cert_buffers;
|
||||
for (size_t i = 0; i < cert_chain_->GetSize(); ++i) {
|
||||
cert_buffers.push_back(
|
||||
static_cast<const BoringSSLCertificate*>(&cert_chain_->Get(i))
|
||||
->cert_buffer());
|
||||
}
|
||||
// 1 is the documented success return code.
|
||||
if (1 != SSL_CTX_set_chain_and_key(ctx, &cert_buffers[0], cert_buffers.size(),
|
||||
key_pair_->pkey(), nullptr)) {
|
||||
openssl::LogSSLErrors("Configuring key and certificate");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string BoringSSLIdentity::PrivateKeyToPEMString() const {
|
||||
return key_pair_->PrivateKeyToPEMString();
|
||||
}
|
||||
|
||||
std::string BoringSSLIdentity::PublicKeyToPEMString() const {
|
||||
return key_pair_->PublicKeyToPEMString();
|
||||
}
|
||||
|
||||
bool BoringSSLIdentity::operator==(const BoringSSLIdentity& other) const {
|
||||
return *this->key_pair_ == *other.key_pair_ &&
|
||||
this->certificate() == other.certificate();
|
||||
}
|
||||
|
||||
bool BoringSSLIdentity::operator!=(const BoringSSLIdentity& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
77
TMessagesProj/jni/voip/webrtc/rtc_base/boringssl_identity.h
Normal file
77
TMessagesProj/jni/voip/webrtc/rtc_base/boringssl_identity.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_BORINGSSL_IDENTITY_H_
|
||||
#define RTC_BASE_BORINGSSL_IDENTITY_H_
|
||||
|
||||
#include <openssl/ossl_typ.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/boringssl_certificate.h"
|
||||
#include "rtc_base/openssl_key_pair.h"
|
||||
#include "rtc_base/ssl_certificate.h"
|
||||
#include "rtc_base/ssl_identity.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Holds a keypair and certificate together, and a method to generate them
|
||||
// consistently. Uses CRYPTO_BUFFER instead of X509, which offers binary size
|
||||
// and memory improvements.
|
||||
class BoringSSLIdentity final : public SSLIdentity {
|
||||
public:
|
||||
static std::unique_ptr<BoringSSLIdentity> CreateWithExpiration(
|
||||
absl::string_view common_name,
|
||||
const KeyParams& key_params,
|
||||
time_t certificate_lifetime);
|
||||
static std::unique_ptr<BoringSSLIdentity> CreateForTest(
|
||||
const SSLIdentityParams& params);
|
||||
static std::unique_ptr<SSLIdentity> CreateFromPEMStrings(
|
||||
absl::string_view private_key,
|
||||
absl::string_view certificate);
|
||||
static std::unique_ptr<SSLIdentity> CreateFromPEMChainStrings(
|
||||
absl::string_view private_key,
|
||||
absl::string_view certificate_chain);
|
||||
~BoringSSLIdentity() override;
|
||||
|
||||
BoringSSLIdentity(const BoringSSLIdentity&) = delete;
|
||||
BoringSSLIdentity& operator=(const BoringSSLIdentity&) = delete;
|
||||
|
||||
const BoringSSLCertificate& certificate() const override;
|
||||
const SSLCertChain& cert_chain() const override;
|
||||
|
||||
// Configure an SSL context object to use our key and certificate.
|
||||
bool ConfigureIdentity(SSL_CTX* ctx);
|
||||
|
||||
std::string PrivateKeyToPEMString() const override;
|
||||
std::string PublicKeyToPEMString() const override;
|
||||
bool operator==(const BoringSSLIdentity& other) const;
|
||||
bool operator!=(const BoringSSLIdentity& other) const;
|
||||
|
||||
private:
|
||||
BoringSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
|
||||
std::unique_ptr<BoringSSLCertificate> certificate);
|
||||
BoringSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
|
||||
std::unique_ptr<SSLCertChain> cert_chain);
|
||||
std::unique_ptr<SSLIdentity> CloneInternal() const override;
|
||||
|
||||
static std::unique_ptr<BoringSSLIdentity> CreateInternal(
|
||||
const SSLIdentityParams& params);
|
||||
|
||||
std::unique_ptr<OpenSSLKeyPair> key_pair_;
|
||||
std::unique_ptr<SSLCertChain> cert_chain_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_BORINGSSL_IDENTITY_H_
|
||||
155
TMessagesProj/jni/voip/webrtc/rtc_base/bounded_inline_vector.h
Normal file
155
TMessagesProj/jni/voip/webrtc/rtc_base/bounded_inline_vector.h
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_BOUNDED_INLINE_VECTOR_H_
|
||||
#define RTC_BASE_BOUNDED_INLINE_VECTOR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rtc_base/bounded_inline_vector_impl.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// A small std::vector-like type whose capacity is a compile-time constant. It
|
||||
// stores all data inline and never heap allocates (beyond what its element type
|
||||
// requires). Trying to grow it beyond its constant capacity is an error.
|
||||
//
|
||||
// TODO(bugs.webrtc.org/11391): Comparison operators.
|
||||
// TODO(bugs.webrtc.org/11391): Methods for adding and deleting elements.
|
||||
template <typename T, int fixed_capacity>
|
||||
class BoundedInlineVector {
|
||||
static_assert(!std::is_const<T>::value, "T may not be const");
|
||||
static_assert(fixed_capacity > 0, "Capacity must be strictly positive");
|
||||
|
||||
public:
|
||||
using size_type = int;
|
||||
using value_type = T;
|
||||
using const_iterator = const T*;
|
||||
|
||||
BoundedInlineVector() = default;
|
||||
BoundedInlineVector(const BoundedInlineVector&) = default;
|
||||
BoundedInlineVector(BoundedInlineVector&&) = default;
|
||||
BoundedInlineVector& operator=(const BoundedInlineVector&) = default;
|
||||
BoundedInlineVector& operator=(BoundedInlineVector&&) = default;
|
||||
~BoundedInlineVector() = default;
|
||||
|
||||
// This constructor is implicit, to make it possible to write e.g.
|
||||
//
|
||||
// BoundedInlineVector<double, 7> x = {2.72, 3.14};
|
||||
//
|
||||
// and
|
||||
//
|
||||
// BoundedInlineVector<double, 7> GetConstants() {
|
||||
// return {2.72, 3.14};
|
||||
// }
|
||||
template <typename... Ts,
|
||||
typename std::enable_if_t<
|
||||
bounded_inline_vector_impl::AllConvertible<T, Ts...>::value>* =
|
||||
nullptr>
|
||||
BoundedInlineVector(Ts&&... elements) // NOLINT(runtime/explicit)
|
||||
: storage_(std::forward<Ts>(elements)...) {
|
||||
static_assert(sizeof...(Ts) <= fixed_capacity, "");
|
||||
}
|
||||
|
||||
template <
|
||||
int other_capacity,
|
||||
typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr>
|
||||
BoundedInlineVector(const BoundedInlineVector<T, other_capacity>& other) {
|
||||
RTC_DCHECK_LE(other.size(), fixed_capacity);
|
||||
bounded_inline_vector_impl::CopyElements(other.data(), other.size(),
|
||||
storage_.data, &storage_.size);
|
||||
}
|
||||
|
||||
template <
|
||||
int other_capacity,
|
||||
typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr>
|
||||
BoundedInlineVector(BoundedInlineVector<T, other_capacity>&& other) {
|
||||
RTC_DCHECK_LE(other.size(), fixed_capacity);
|
||||
bounded_inline_vector_impl::MoveElements(other.data(), other.size(),
|
||||
storage_.data, &storage_.size);
|
||||
}
|
||||
|
||||
template <
|
||||
int other_capacity,
|
||||
typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr>
|
||||
BoundedInlineVector& operator=(
|
||||
const BoundedInlineVector<T, other_capacity>& other) {
|
||||
bounded_inline_vector_impl::DestroyElements(storage_.data, storage_.size);
|
||||
RTC_DCHECK_LE(other.size(), fixed_capacity);
|
||||
bounded_inline_vector_impl::CopyElements(other.data(), other.size(),
|
||||
storage_.data, &storage_.size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <
|
||||
int other_capacity,
|
||||
typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr>
|
||||
BoundedInlineVector& operator=(
|
||||
BoundedInlineVector<T, other_capacity>&& other) {
|
||||
bounded_inline_vector_impl::DestroyElements(storage_.data, storage_.size);
|
||||
RTC_DCHECK_LE(other.size(), fixed_capacity);
|
||||
bounded_inline_vector_impl::MoveElements(other.data(), other.size(),
|
||||
storage_.data, &storage_.size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const { return storage_.size == 0; }
|
||||
int size() const { return storage_.size; }
|
||||
constexpr int capacity() const { return fixed_capacity; }
|
||||
|
||||
// Resizes the BoundedInlineVector to the given size, which must not exceed
|
||||
// its constant capacity. If the size is increased, the added elements are
|
||||
// default constructed.
|
||||
void resize(int new_size) {
|
||||
RTC_DCHECK_GE(new_size, 0);
|
||||
RTC_DCHECK_LE(new_size, fixed_capacity);
|
||||
if (new_size > storage_.size) {
|
||||
bounded_inline_vector_impl::DefaultInitializeElements(
|
||||
storage_.data + storage_.size, new_size - storage_.size);
|
||||
} else if (new_size < storage_.size) {
|
||||
bounded_inline_vector_impl::DestroyElements(storage_.data + new_size,
|
||||
storage_.size - new_size);
|
||||
}
|
||||
storage_.size = new_size;
|
||||
}
|
||||
|
||||
const T* data() const { return storage_.data; }
|
||||
T* data() { return storage_.data; }
|
||||
|
||||
const T& operator[](int index) const {
|
||||
RTC_DCHECK_GE(index, 0);
|
||||
RTC_DCHECK_LT(index, storage_.size);
|
||||
return storage_.data[index];
|
||||
}
|
||||
T& operator[](int index) {
|
||||
RTC_DCHECK_GE(index, 0);
|
||||
RTC_DCHECK_LT(index, storage_.size);
|
||||
return storage_.data[index];
|
||||
}
|
||||
|
||||
T* begin() { return storage_.data; }
|
||||
T* end() { return storage_.data + storage_.size; }
|
||||
const T* begin() const { return storage_.data; }
|
||||
const T* end() const { return storage_.data + storage_.size; }
|
||||
const T* cbegin() const { return storage_.data; }
|
||||
const T* cend() const { return storage_.data + storage_.size; }
|
||||
|
||||
private:
|
||||
bounded_inline_vector_impl::Storage<T, fixed_capacity> storage_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_BOUNDED_INLINE_VECTOR_H_
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_BOUNDED_INLINE_VECTOR_IMPL_H_
|
||||
#define RTC_BASE_BOUNDED_INLINE_VECTOR_IMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace webrtc {
|
||||
namespace bounded_inline_vector_impl {
|
||||
|
||||
template <bool...>
|
||||
struct BoolPack;
|
||||
|
||||
// Tests if all its parameters (x0, x1, ..., xn) are true. The implementation
|
||||
// checks whether (x0, x1, ..., xn, true) == (true, x0, x1, ..., xn), which is
|
||||
// true iff true == x0 && x0 == x1 && x1 == x2 ... && xn-1 == xn && xn == true.
|
||||
template <bool... Bs>
|
||||
using AllTrue = std::is_same<BoolPack<Bs..., true>, BoolPack<true, Bs...>>;
|
||||
|
||||
template <typename To, typename... Froms>
|
||||
using AllConvertible = AllTrue<std::is_convertible<Froms, To>::value...>;
|
||||
|
||||
// Initializes part of an uninitialized array. Unlike normal array
|
||||
// initialization, does not zero the remaining array elements. Caller is
|
||||
// responsible for ensuring that there is enough space in `data`.
|
||||
template <typename T>
|
||||
void InitializeElements(T* data) {}
|
||||
template <typename T, typename U, typename... Us>
|
||||
void InitializeElements(T* data, U&& element, Us&&... elements) {
|
||||
// Placement new, because we construct a new object in uninitialized memory.
|
||||
::new (data) T(std::forward<U>(element));
|
||||
InitializeElements(data + 1, std::forward<Us>(elements)...);
|
||||
}
|
||||
|
||||
// Default initializes uninitialized array elements.
|
||||
// TODO(kwiberg): Replace with std::uninitialized_default_construct_n() (C++17).
|
||||
template <typename T>
|
||||
void DefaultInitializeElements(T* data, int size) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
// Placement new, because we construct a new object in uninitialized memory.
|
||||
::new (&data[i]) T;
|
||||
}
|
||||
}
|
||||
|
||||
// Copies from source to uninitialized destination. Caller is responsible for
|
||||
// ensuring that there is enough space in `dst_data`.
|
||||
template <typename T>
|
||||
void CopyElements(const T* src_data, int src_size, T* dst_data, int* dst_size) {
|
||||
if /*constexpr*/ (std::is_trivially_copy_constructible<T>::value) {
|
||||
std::memcpy(dst_data, src_data, src_size * sizeof(T));
|
||||
} else {
|
||||
std::uninitialized_copy_n(src_data, src_size, dst_data);
|
||||
}
|
||||
*dst_size = src_size;
|
||||
}
|
||||
|
||||
// Moves from source to uninitialized destination. Caller is responsible for
|
||||
// ensuring that there is enough space in `dst_data`.
|
||||
template <typename T>
|
||||
void MoveElements(T* src_data, int src_size, T* dst_data, int* dst_size) {
|
||||
if /*constexpr*/ (std::is_trivially_move_constructible<T>::value) {
|
||||
std::memcpy(dst_data, src_data, src_size * sizeof(T));
|
||||
} else {
|
||||
// TODO(kwiberg): Use std::uninitialized_move_n() instead (C++17).
|
||||
for (int i = 0; i < src_size; ++i) {
|
||||
// Placement new, because we create a new object in uninitialized
|
||||
// memory.
|
||||
::new (&dst_data[i]) T(std::move(src_data[i]));
|
||||
}
|
||||
}
|
||||
*dst_size = src_size;
|
||||
}
|
||||
|
||||
// Destroys elements, leaving them uninitialized.
|
||||
template <typename T>
|
||||
void DestroyElements(T* data, int size) {
|
||||
if /*constexpr*/ (!std::is_trivially_destructible<T>::value) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
data[i].~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If elements are trivial and the total capacity is at most this many bytes,
|
||||
// copy everything instead of just the elements that are in use; this is more
|
||||
// efficient, and makes BoundedInlineVector trivially copyable.
|
||||
static constexpr int kSmallSize = 64;
|
||||
|
||||
// Storage implementations.
|
||||
//
|
||||
// There are diferent Storage structs for diferent kinds of element types. The
|
||||
// common contract is the following:
|
||||
//
|
||||
// * They have public `size` variables and `data` array members.
|
||||
//
|
||||
// * Their owner is responsible for enforcing the invariant that the first
|
||||
// `size` elements in `data` are initialized, and the remaining elements are
|
||||
// not initialized.
|
||||
//
|
||||
// * They implement default construction, construction with one or more
|
||||
// elements, copy/move construction, copy/move assignment, and destruction;
|
||||
// the owner must ensure that the invariant holds whenever these operations
|
||||
// occur.
|
||||
|
||||
// Storage implementation for nontrivial element types.
|
||||
template <typename T,
|
||||
int fixed_capacity,
|
||||
bool is_trivial = std::is_trivial<T>::value,
|
||||
bool is_small = (sizeof(T) * fixed_capacity <= kSmallSize)>
|
||||
struct Storage {
|
||||
static_assert(!std::is_trivial<T>::value, "");
|
||||
|
||||
template <
|
||||
typename... Ts,
|
||||
typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr>
|
||||
explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) {
|
||||
InitializeElements(data, std::forward<Ts>(elements)...);
|
||||
}
|
||||
|
||||
Storage(const Storage& other) {
|
||||
CopyElements(other.data, other.size, data, &size);
|
||||
}
|
||||
|
||||
Storage(Storage&& other) {
|
||||
MoveElements(other.data, other.size, data, &size);
|
||||
}
|
||||
|
||||
Storage& operator=(const Storage& other) {
|
||||
if (this != &other) {
|
||||
DestroyElements(data, size);
|
||||
CopyElements(other.data, other.size, data, &size);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Storage& operator=(Storage&& other) {
|
||||
DestroyElements(data, size);
|
||||
size = 0; // Needed in case of self assignment.
|
||||
MoveElements(other.data, other.size, data, &size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Storage() { DestroyElements(data, size); }
|
||||
|
||||
int size;
|
||||
union {
|
||||
// Since this array is in a union, we get to construct and destroy it
|
||||
// manually.
|
||||
T data[fixed_capacity]; // NOLINT(runtime/arrays)
|
||||
};
|
||||
};
|
||||
|
||||
// Storage implementation for trivial element types when the capacity is small
|
||||
// enough that we can cheaply copy everything.
|
||||
template <typename T, int fixed_capacity>
|
||||
struct Storage<T, fixed_capacity, /*is_trivial=*/true, /*is_small=*/true> {
|
||||
static_assert(std::is_trivial<T>::value, "");
|
||||
static_assert(sizeof(T) * fixed_capacity <= kSmallSize, "");
|
||||
|
||||
template <
|
||||
typename... Ts,
|
||||
typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr>
|
||||
explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) {
|
||||
InitializeElements(data, std::forward<Ts>(elements)...);
|
||||
}
|
||||
|
||||
Storage(const Storage&) = default;
|
||||
Storage& operator=(const Storage&) = default;
|
||||
~Storage() = default;
|
||||
|
||||
int size;
|
||||
T data[fixed_capacity]; // NOLINT(runtime/arrays)
|
||||
};
|
||||
|
||||
// Storage implementation for trivial element types when the capacity is large
|
||||
// enough that we want to avoid copying uninitialized elements.
|
||||
template <typename T, int fixed_capacity>
|
||||
struct Storage<T, fixed_capacity, /*is_trivial=*/true, /*is_small=*/false> {
|
||||
static_assert(std::is_trivial<T>::value, "");
|
||||
static_assert(sizeof(T) * fixed_capacity > kSmallSize, "");
|
||||
|
||||
template <
|
||||
typename... Ts,
|
||||
typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr>
|
||||
explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) {
|
||||
InitializeElements(data, std::forward<Ts>(elements)...);
|
||||
}
|
||||
|
||||
Storage(const Storage& other) : size(other.size) {
|
||||
std::memcpy(data, other.data, other.size * sizeof(T));
|
||||
}
|
||||
|
||||
Storage& operator=(const Storage& other) {
|
||||
if (this != &other) {
|
||||
size = other.size;
|
||||
std::memcpy(data, other.data, other.size * sizeof(T));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Storage() = default;
|
||||
|
||||
int size;
|
||||
union {
|
||||
T data[fixed_capacity]; // NOLINT(runtime/arrays)
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace bounded_inline_vector_impl
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_BOUNDED_INLINE_VECTOR_IMPL_H_
|
||||
452
TMessagesProj/jni/voip/webrtc/rtc_base/buffer.h
Normal file
452
TMessagesProj/jni/voip/webrtc/rtc_base/buffer.h
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
/*
|
||||
* 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_BUFFER_H_
|
||||
#define RTC_BASE_BUFFER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/array_view.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/type_traits.h"
|
||||
#include "rtc_base/zero_memory.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// (Internal; please don't use outside this file.) Determines if elements of
|
||||
// type U are compatible with a BufferT<T>. For most types, we just ignore
|
||||
// top-level const and forbid top-level volatile and require T and U to be
|
||||
// otherwise equal, but all byte-sized integers (notably char, int8_t, and
|
||||
// uint8_t) are compatible with each other. (Note: We aim to get rid of this
|
||||
// behavior, and treat all types the same.)
|
||||
template <typename T, typename U>
|
||||
struct BufferCompat {
|
||||
static constexpr bool value =
|
||||
!std::is_volatile<U>::value &&
|
||||
((std::is_integral<T>::value && sizeof(T) == 1)
|
||||
? (std::is_integral<U>::value && sizeof(U) == 1)
|
||||
: (std::is_same<T, typename std::remove_const<U>::type>::value));
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Basic buffer class, can be grown and shrunk dynamically.
|
||||
// Unlike std::string/vector, does not initialize data when increasing size.
|
||||
// If "ZeroOnFree" is true, any memory is explicitly cleared before releasing.
|
||||
// The type alias "ZeroOnFreeBuffer" below should be used instead of setting
|
||||
// "ZeroOnFree" in the template manually to "true".
|
||||
template <typename T, bool ZeroOnFree = false>
|
||||
class BufferT {
|
||||
// We want T's destructor and default constructor to be trivial, i.e. perform
|
||||
// no action, so that we don't have to touch the memory we allocate and
|
||||
// deallocate. And we want T to be trivially copyable, so that we can copy T
|
||||
// instances with std::memcpy. This is precisely the definition of a trivial
|
||||
// type.
|
||||
static_assert(std::is_trivial<T>::value, "T must be a trivial type.");
|
||||
|
||||
// This class relies heavily on being able to mutate its data.
|
||||
static_assert(!std::is_const<T>::value, "T may not be const");
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using const_iterator = const T*;
|
||||
|
||||
// An empty BufferT.
|
||||
BufferT() : size_(0), capacity_(0), data_(nullptr) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
// Disable copy construction and copy assignment, since copying a buffer is
|
||||
// expensive enough that we want to force the user to be explicit about it.
|
||||
BufferT(const BufferT&) = delete;
|
||||
BufferT& operator=(const BufferT&) = delete;
|
||||
|
||||
BufferT(BufferT&& buf)
|
||||
: size_(buf.size()),
|
||||
capacity_(buf.capacity()),
|
||||
data_(std::move(buf.data_)) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
buf.OnMovedFrom();
|
||||
}
|
||||
|
||||
// Construct a buffer with the specified number of uninitialized elements.
|
||||
explicit BufferT(size_t size) : BufferT(size, size) {}
|
||||
|
||||
BufferT(size_t size, size_t capacity)
|
||||
: size_(size),
|
||||
capacity_(std::max(size, capacity)),
|
||||
data_(capacity_ > 0 ? new T[capacity_] : nullptr) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
// Construct a buffer and copy the specified number of elements into it.
|
||||
template <typename U,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
BufferT(const U* data, size_t size) : BufferT(data, size, size) {}
|
||||
|
||||
template <typename U,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
BufferT(U* data, size_t size, size_t capacity) : BufferT(size, capacity) {
|
||||
static_assert(sizeof(T) == sizeof(U), "");
|
||||
if (size > 0) {
|
||||
RTC_DCHECK(data);
|
||||
std::memcpy(data_.get(), data, size * sizeof(U));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a buffer from the contents of an array.
|
||||
template <typename U,
|
||||
size_t N,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
BufferT(U (&array)[N]) : BufferT(array, N) {}
|
||||
|
||||
~BufferT() { MaybeZeroCompleteBuffer(); }
|
||||
|
||||
// Implicit conversion to absl::string_view if T is compatible with char.
|
||||
template <typename U = T>
|
||||
operator typename std::enable_if<internal::BufferCompat<U, char>::value,
|
||||
absl::string_view>::type() const {
|
||||
return absl::string_view(data<char>(), size());
|
||||
}
|
||||
|
||||
// Get a pointer to the data. Just .data() will give you a (const) T*, but if
|
||||
// T is a byte-sized integer, you may also use .data<U>() for any other
|
||||
// byte-sized integer U.
|
||||
template <typename U = T,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
const U* data() const {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return reinterpret_cast<U*>(data_.get());
|
||||
}
|
||||
|
||||
template <typename U = T,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
U* data() {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return reinterpret_cast<U*>(data_.get());
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return size_;
|
||||
}
|
||||
|
||||
size_t capacity() const {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
BufferT& operator=(BufferT&& buf) {
|
||||
RTC_DCHECK(buf.IsConsistent());
|
||||
MaybeZeroCompleteBuffer();
|
||||
size_ = buf.size_;
|
||||
capacity_ = buf.capacity_;
|
||||
using std::swap;
|
||||
swap(data_, buf.data_);
|
||||
buf.data_.reset();
|
||||
buf.OnMovedFrom();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const BufferT& buf) const {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
if (size_ != buf.size_) {
|
||||
return false;
|
||||
}
|
||||
if (std::is_integral<T>::value) {
|
||||
// Optimization.
|
||||
return std::memcmp(data_.get(), buf.data_.get(), size_ * sizeof(T)) == 0;
|
||||
}
|
||||
for (size_t i = 0; i < size_; ++i) {
|
||||
if (data_[i] != buf.data_[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const BufferT& buf) const { return !(*this == buf); }
|
||||
|
||||
T& operator[](size_t index) {
|
||||
RTC_DCHECK_LT(index, size_);
|
||||
return data()[index];
|
||||
}
|
||||
|
||||
T operator[](size_t index) const {
|
||||
RTC_DCHECK_LT(index, size_);
|
||||
return data()[index];
|
||||
}
|
||||
|
||||
T* begin() { return data(); }
|
||||
T* end() { return data() + size(); }
|
||||
const T* begin() const { return data(); }
|
||||
const T* end() const { return data() + size(); }
|
||||
const T* cbegin() const { return data(); }
|
||||
const T* cend() const { return data() + size(); }
|
||||
|
||||
// The SetData functions replace the contents of the buffer. They accept the
|
||||
// same input types as the constructors.
|
||||
template <typename U,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
void SetData(const U* data, size_t size) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
const size_t old_size = size_;
|
||||
size_ = 0;
|
||||
AppendData(data, size);
|
||||
if (ZeroOnFree && size_ < old_size) {
|
||||
ZeroTrailingData(old_size - size_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
size_t N,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
void SetData(const U (&array)[N]) {
|
||||
SetData(array, N);
|
||||
}
|
||||
|
||||
template <typename W,
|
||||
typename std::enable_if<
|
||||
HasDataAndSize<const W, const T>::value>::type* = nullptr>
|
||||
void SetData(const W& w) {
|
||||
SetData(w.data(), w.size());
|
||||
}
|
||||
|
||||
// Replaces the data in the buffer with at most `max_elements` of data, using
|
||||
// the function `setter`, which should have the following signature:
|
||||
//
|
||||
// size_t setter(ArrayView<U> view)
|
||||
//
|
||||
// `setter` is given an appropriately typed ArrayView of length exactly
|
||||
// `max_elements` that describes the area where it should write the data; it
|
||||
// should return the number of elements actually written. (If it doesn't fill
|
||||
// the whole ArrayView, it should leave the unused space at the end.)
|
||||
template <typename U = T,
|
||||
typename F,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
size_t SetData(size_t max_elements, F&& setter) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
const size_t old_size = size_;
|
||||
size_ = 0;
|
||||
const size_t written = AppendData<U>(max_elements, std::forward<F>(setter));
|
||||
if (ZeroOnFree && size_ < old_size) {
|
||||
ZeroTrailingData(old_size - size_);
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
// The AppendData functions add data to the end of the buffer. They accept
|
||||
// the same input types as the constructors.
|
||||
template <typename U,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
void AppendData(const U* data, size_t size) {
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
RTC_DCHECK(data);
|
||||
RTC_DCHECK(IsConsistent());
|
||||
const size_t new_size = size_ + size;
|
||||
EnsureCapacityWithHeadroom(new_size, true);
|
||||
static_assert(sizeof(T) == sizeof(U), "");
|
||||
std::memcpy(data_.get() + size_, data, size * sizeof(U));
|
||||
size_ = new_size;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
size_t N,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
void AppendData(const U (&array)[N]) {
|
||||
AppendData(array, N);
|
||||
}
|
||||
|
||||
template <typename W,
|
||||
typename std::enable_if<
|
||||
HasDataAndSize<const W, const T>::value>::type* = nullptr>
|
||||
void AppendData(const W& w) {
|
||||
AppendData(w.data(), w.size());
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
void AppendData(const U& item) {
|
||||
AppendData(&item, 1);
|
||||
}
|
||||
|
||||
// Appends at most `max_elements` to the end of the buffer, using the function
|
||||
// `setter`, which should have the following signature:
|
||||
//
|
||||
// size_t setter(ArrayView<U> view)
|
||||
//
|
||||
// `setter` is given an appropriately typed ArrayView of length exactly
|
||||
// `max_elements` that describes the area where it should write the data; it
|
||||
// should return the number of elements actually written. (If it doesn't fill
|
||||
// the whole ArrayView, it should leave the unused space at the end.)
|
||||
template <typename U = T,
|
||||
typename F,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<T, U>::value>::type* = nullptr>
|
||||
size_t AppendData(size_t max_elements, F&& setter) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
const size_t old_size = size_;
|
||||
SetSize(old_size + max_elements);
|
||||
U* base_ptr = data<U>() + old_size;
|
||||
size_t written_elements = setter(rtc::ArrayView<U>(base_ptr, max_elements));
|
||||
|
||||
RTC_CHECK_LE(written_elements, max_elements);
|
||||
size_ = old_size + written_elements;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return written_elements;
|
||||
}
|
||||
|
||||
// Sets the size of the buffer. If the new size is smaller than the old, the
|
||||
// buffer contents will be kept but truncated; if the new size is greater,
|
||||
// the existing contents will be kept and the new space will be
|
||||
// uninitialized.
|
||||
void SetSize(size_t size) {
|
||||
const size_t old_size = size_;
|
||||
EnsureCapacityWithHeadroom(size, true);
|
||||
size_ = size;
|
||||
if (ZeroOnFree && size_ < old_size) {
|
||||
ZeroTrailingData(old_size - size_);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the buffer size can be increased to at least capacity without
|
||||
// further reallocation. (Of course, this operation might need to reallocate
|
||||
// the buffer.)
|
||||
void EnsureCapacity(size_t capacity) {
|
||||
// Don't allocate extra headroom, since the user is asking for a specific
|
||||
// capacity.
|
||||
EnsureCapacityWithHeadroom(capacity, false);
|
||||
}
|
||||
|
||||
// Resets the buffer to zero size without altering capacity. Works even if the
|
||||
// buffer has been moved from.
|
||||
void Clear() {
|
||||
MaybeZeroCompleteBuffer();
|
||||
size_ = 0;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
// Swaps two buffers. Also works for buffers that have been moved from.
|
||||
friend void swap(BufferT& a, BufferT& b) {
|
||||
using std::swap;
|
||||
swap(a.size_, b.size_);
|
||||
swap(a.capacity_, b.capacity_);
|
||||
swap(a.data_, b.data_);
|
||||
}
|
||||
|
||||
private:
|
||||
void EnsureCapacityWithHeadroom(size_t capacity, bool extra_headroom) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
if (capacity <= capacity_)
|
||||
return;
|
||||
|
||||
// If the caller asks for extra headroom, ensure that the new capacity is
|
||||
// >= 1.5 times the old capacity. Any constant > 1 is sufficient to prevent
|
||||
// quadratic behavior; as to why we pick 1.5 in particular, see
|
||||
// https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md and
|
||||
// http://www.gahcep.com/cpp-internals-stl-vector-part-1/.
|
||||
const size_t new_capacity =
|
||||
extra_headroom ? std::max(capacity, capacity_ + capacity_ / 2)
|
||||
: capacity;
|
||||
|
||||
std::unique_ptr<T[]> new_data(new T[new_capacity]);
|
||||
if (data_ != nullptr) {
|
||||
std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T));
|
||||
}
|
||||
MaybeZeroCompleteBuffer();
|
||||
data_ = std::move(new_data);
|
||||
capacity_ = new_capacity;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
// Zero the complete buffer if template argument "ZeroOnFree" is true.
|
||||
void MaybeZeroCompleteBuffer() {
|
||||
if (ZeroOnFree && capacity_ > 0) {
|
||||
// It would be sufficient to only zero "size_" elements, as all other
|
||||
// methods already ensure that the unused capacity contains no sensitive
|
||||
// data---but better safe than sorry.
|
||||
ExplicitZeroMemory(data_.get(), capacity_ * sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
// Zero the first "count" elements of unused capacity.
|
||||
void ZeroTrailingData(size_t count) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
RTC_DCHECK_LE(count, capacity_ - size_);
|
||||
ExplicitZeroMemory(data_.get() + size_, count * sizeof(T));
|
||||
}
|
||||
|
||||
// Precondition for all methods except Clear, operator= and the destructor.
|
||||
// Postcondition for all methods except move construction and move
|
||||
// assignment, which leave the moved-from object in a possibly inconsistent
|
||||
// state.
|
||||
bool IsConsistent() const {
|
||||
return (data_ || capacity_ == 0) && capacity_ >= size_;
|
||||
}
|
||||
|
||||
// Called when *this has been moved from. Conceptually it's a no-op, but we
|
||||
// can mutate the state slightly to help subsequent sanity checks catch bugs.
|
||||
void OnMovedFrom() {
|
||||
RTC_DCHECK(!data_); // Our heap block should have been stolen.
|
||||
#if RTC_DCHECK_IS_ON
|
||||
// Ensure that *this is always inconsistent, to provoke bugs.
|
||||
size_ = 1;
|
||||
capacity_ = 0;
|
||||
#else
|
||||
// Make *this consistent and empty. Shouldn't be necessary, but better safe
|
||||
// than sorry.
|
||||
size_ = 0;
|
||||
capacity_ = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t size_;
|
||||
size_t capacity_;
|
||||
std::unique_ptr<T[]> data_;
|
||||
};
|
||||
|
||||
// By far the most common sort of buffer.
|
||||
using Buffer = BufferT<uint8_t>;
|
||||
|
||||
// A buffer that zeros memory before releasing it.
|
||||
template <typename T>
|
||||
using ZeroOnFreeBuffer = BufferT<T, true>;
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_BUFFER_H_
|
||||
85
TMessagesProj/jni/voip/webrtc/rtc_base/buffer_queue.cc
Normal file
85
TMessagesProj/jni/voip/webrtc/rtc_base/buffer_queue.cc
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/buffer_queue.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
BufferQueue::BufferQueue(size_t capacity, size_t default_size)
|
||||
: capacity_(capacity), default_size_(default_size) {}
|
||||
|
||||
BufferQueue::~BufferQueue() {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
for (Buffer* buffer : queue_)
|
||||
delete buffer;
|
||||
for (Buffer* buffer : free_list_)
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
size_t BufferQueue::size() const {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
return queue_.size();
|
||||
}
|
||||
|
||||
void BufferQueue::Clear() {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
while (!queue_.empty()) {
|
||||
free_list_.push_back(queue_.front());
|
||||
queue_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
bool BufferQueue::ReadFront(void* buffer, size_t bytes, size_t* bytes_read) {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
if (queue_.empty())
|
||||
return false;
|
||||
|
||||
Buffer* packet = queue_.front();
|
||||
queue_.pop_front();
|
||||
|
||||
bytes = std::min(bytes, packet->size());
|
||||
memcpy(buffer, packet->data(), bytes);
|
||||
|
||||
if (bytes_read)
|
||||
*bytes_read = bytes;
|
||||
|
||||
free_list_.push_back(packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BufferQueue::WriteBack(const void* buffer,
|
||||
size_t bytes,
|
||||
size_t* bytes_written) {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
if (queue_.size() == capacity_)
|
||||
return false;
|
||||
|
||||
Buffer* packet;
|
||||
if (!free_list_.empty()) {
|
||||
packet = free_list_.back();
|
||||
free_list_.pop_back();
|
||||
} else {
|
||||
packet = new Buffer(bytes, default_size_);
|
||||
}
|
||||
|
||||
packet->SetData(static_cast<const uint8_t*>(buffer), bytes);
|
||||
if (bytes_written)
|
||||
*bytes_written = bytes;
|
||||
|
||||
queue_.push_back(packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
70
TMessagesProj/jni/voip/webrtc/rtc_base/buffer_queue.h
Normal file
70
TMessagesProj/jni/voip/webrtc/rtc_base/buffer_queue.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 RTC_BASE_BUFFER_QUEUE_H_
|
||||
#define RTC_BASE_BUFFER_QUEUE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "api/sequence_checker.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
#include "rtc_base/system/no_unique_address.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class BufferQueue final {
|
||||
public:
|
||||
// Creates a buffer queue with a given capacity and default buffer size.
|
||||
BufferQueue(size_t capacity, size_t default_size);
|
||||
~BufferQueue();
|
||||
|
||||
BufferQueue(const BufferQueue&) = delete;
|
||||
BufferQueue& operator=(const BufferQueue&) = delete;
|
||||
|
||||
// Return number of queued buffers.
|
||||
size_t size() const;
|
||||
|
||||
// Clear the BufferQueue by moving all Buffers from `queue_` to `free_list_`.
|
||||
void Clear();
|
||||
|
||||
// ReadFront will only read one buffer at a time and will truncate buffers
|
||||
// that don't fit in the passed memory.
|
||||
// Returns true unless no data could be returned.
|
||||
bool ReadFront(void* data, size_t bytes, size_t* bytes_read);
|
||||
|
||||
// WriteBack always writes either the complete memory or nothing.
|
||||
// Returns true unless no data could be written.
|
||||
bool WriteBack(const void* data, size_t bytes, size_t* bytes_written);
|
||||
|
||||
bool is_writable() const {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
return queue_.size() < capacity_;
|
||||
}
|
||||
|
||||
bool is_readable() const {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
return !queue_.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_;
|
||||
const size_t capacity_;
|
||||
const size_t default_size_;
|
||||
std::deque<Buffer*> queue_ RTC_GUARDED_BY(sequence_checker_);
|
||||
std::vector<Buffer*> free_list_ RTC_GUARDED_BY(sequence_checker_);
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_BUFFER_QUEUE_H_
|
||||
170
TMessagesProj/jni/voip/webrtc/rtc_base/byte_buffer.cc
Normal file
170
TMessagesProj/jni/voip/webrtc/rtc_base/byte_buffer.cc
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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/byte_buffer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
ByteBufferWriter::ByteBufferWriter() : ByteBufferWriterT() {}
|
||||
|
||||
ByteBufferWriter::ByteBufferWriter(const uint8_t* bytes, size_t len)
|
||||
: ByteBufferWriterT(bytes, len) {}
|
||||
|
||||
ByteBufferReader::ByteBufferReader(rtc::ArrayView<const uint8_t> bytes) {
|
||||
Construct(bytes.data(), bytes.size());
|
||||
}
|
||||
|
||||
ByteBufferReader::ByteBufferReader(const ByteBufferWriter& buf) {
|
||||
Construct(reinterpret_cast<const uint8_t*>(buf.Data()), buf.Length());
|
||||
}
|
||||
|
||||
void ByteBufferReader::Construct(const uint8_t* bytes, size_t len) {
|
||||
bytes_ = bytes;
|
||||
size_ = len;
|
||||
start_ = 0;
|
||||
end_ = len;
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadUInt8(uint8_t* val) {
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
return ReadBytes(val, 1);
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadUInt16(uint16_t* val) {
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
uint16_t v;
|
||||
if (!ReadBytes(reinterpret_cast<uint8_t*>(&v), 2)) {
|
||||
return false;
|
||||
} else {
|
||||
*val = NetworkToHost16(v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadUInt24(uint32_t* val) {
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
uint32_t v = 0;
|
||||
uint8_t* read_into = reinterpret_cast<uint8_t*>(&v);
|
||||
++read_into;
|
||||
|
||||
if (!ReadBytes(read_into, 3)) {
|
||||
return false;
|
||||
} else {
|
||||
*val = NetworkToHost32(v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadUInt32(uint32_t* val) {
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
uint32_t v;
|
||||
if (!ReadBytes(reinterpret_cast<uint8_t*>(&v), 4)) {
|
||||
return false;
|
||||
} else {
|
||||
*val = NetworkToHost32(v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadUInt64(uint64_t* val) {
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
uint64_t v;
|
||||
if (!ReadBytes(reinterpret_cast<uint8_t*>(&v), 8)) {
|
||||
return false;
|
||||
} else {
|
||||
*val = NetworkToHost64(v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadUVarint(uint64_t* val) {
|
||||
if (!val) {
|
||||
return false;
|
||||
}
|
||||
// Integers are deserialized 7 bits at a time, with each byte having a
|
||||
// continuation byte (msb=1) if there are more bytes to be read.
|
||||
uint64_t v = 0;
|
||||
for (int i = 0; i < 64; i += 7) {
|
||||
uint8_t byte;
|
||||
if (!ReadBytes(&byte, 1)) {
|
||||
return false;
|
||||
}
|
||||
// Read the first 7 bits of the byte, then offset by bits read so far.
|
||||
v |= (static_cast<uint64_t>(byte) & 0x7F) << i;
|
||||
// Return if the msb is not a continuation byte.
|
||||
if (byte < 0x80) {
|
||||
*val = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadString(std::string* val, size_t len) {
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
if (len > Length()) {
|
||||
return false;
|
||||
} else {
|
||||
val->append(reinterpret_cast<const char*>(bytes_ + start_), len);
|
||||
start_ += len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadStringView(absl::string_view* val, size_t len) {
|
||||
if (!val || len > Length())
|
||||
return false;
|
||||
*val = absl::string_view(reinterpret_cast<const char*>(bytes_ + start_), len);
|
||||
start_ += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ByteBufferReader::ReadBytes(rtc::ArrayView<uint8_t> val) {
|
||||
if (val.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
return ReadBytes(val.data(), val.size());
|
||||
}
|
||||
|
||||
// Private function supporting the other Read* functions.
|
||||
bool ByteBufferReader::ReadBytes(uint8_t* val, size_t len) {
|
||||
if (len > Length()) {
|
||||
return false;
|
||||
}
|
||||
if (len == 0) {
|
||||
return true;
|
||||
}
|
||||
memcpy(val, bytes_ + start_, len);
|
||||
start_ += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ByteBufferReader::Consume(size_t size) {
|
||||
if (size > Length())
|
||||
return false;
|
||||
start_ += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
203
TMessagesProj/jni/voip/webrtc/rtc_base/byte_buffer.h
Normal file
203
TMessagesProj/jni/voip/webrtc/rtc_base/byte_buffer.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* 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_BUFFER_H_
|
||||
#define RTC_BASE_BYTE_BUFFER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/array_view.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
#include "rtc_base/byte_order.h"
|
||||
|
||||
// Reads/Writes from/to buffer using network byte order (big endian)
|
||||
namespace rtc {
|
||||
|
||||
template <class BufferClassT>
|
||||
class ByteBufferWriterT {
|
||||
using value_type = typename BufferClassT::value_type;
|
||||
|
||||
public:
|
||||
ByteBufferWriterT() { Construct(nullptr, kDefaultCapacity); }
|
||||
ByteBufferWriterT(const value_type* bytes, size_t len) {
|
||||
Construct(bytes, len);
|
||||
}
|
||||
|
||||
ByteBufferWriterT(const ByteBufferWriterT&) = delete;
|
||||
ByteBufferWriterT& operator=(const ByteBufferWriterT&) = delete;
|
||||
|
||||
const value_type* Data() const { return buffer_.data(); }
|
||||
size_t Length() const { return buffer_.size(); }
|
||||
size_t Capacity() const { return buffer_.capacity(); }
|
||||
rtc::ArrayView<const value_type> DataView() const {
|
||||
return rtc::MakeArrayView(Data(), Length());
|
||||
}
|
||||
// Accessor that returns a string_view, independent of underlying type.
|
||||
// Intended to provide access for existing users that expect char*
|
||||
// when the underlying type changes to uint8_t.
|
||||
// TODO(bugs.webrtc.org/15665): Delete when users are converted.
|
||||
absl::string_view DataAsStringView() const {
|
||||
return absl::string_view(reinterpret_cast<const char*>(Data()), Length());
|
||||
}
|
||||
const char* DataAsCharPointer() const {
|
||||
return reinterpret_cast<const char*>(Data());
|
||||
}
|
||||
|
||||
// Write value to the buffer. Resizes the buffer when it is
|
||||
// neccessary.
|
||||
void WriteUInt8(uint8_t val) {
|
||||
WriteBytesInternal(reinterpret_cast<const value_type*>(&val), 1);
|
||||
}
|
||||
void WriteUInt16(uint16_t val) {
|
||||
uint16_t v = HostToNetwork16(val);
|
||||
WriteBytesInternal(reinterpret_cast<const value_type*>(&v), 2);
|
||||
}
|
||||
void WriteUInt24(uint32_t val) {
|
||||
uint32_t v = HostToNetwork32(val);
|
||||
value_type* start = reinterpret_cast<value_type*>(&v);
|
||||
++start;
|
||||
WriteBytesInternal(start, 3);
|
||||
}
|
||||
void WriteUInt32(uint32_t val) {
|
||||
uint32_t v = HostToNetwork32(val);
|
||||
WriteBytesInternal(reinterpret_cast<const value_type*>(&v), 4);
|
||||
}
|
||||
void WriteUInt64(uint64_t val) {
|
||||
uint64_t v = HostToNetwork64(val);
|
||||
WriteBytesInternal(reinterpret_cast<const value_type*>(&v), 8);
|
||||
}
|
||||
// Serializes an unsigned varint in the format described by
|
||||
// https://developers.google.com/protocol-buffers/docs/encoding#varints
|
||||
// with the caveat that integers are 64-bit, not 128-bit.
|
||||
void WriteUVarint(uint64_t val) {
|
||||
while (val >= 0x80) {
|
||||
// Write 7 bits at a time, then set the msb to a continuation byte
|
||||
// (msb=1).
|
||||
value_type byte = static_cast<value_type>(val) | 0x80;
|
||||
WriteBytesInternal(&byte, 1);
|
||||
val >>= 7;
|
||||
}
|
||||
value_type last_byte = static_cast<value_type>(val);
|
||||
WriteBytesInternal(&last_byte, 1);
|
||||
}
|
||||
void WriteString(absl::string_view val) {
|
||||
WriteBytesInternal(reinterpret_cast<const value_type*>(val.data()),
|
||||
val.size());
|
||||
}
|
||||
// Write an array of bytes (uint8_t)
|
||||
void WriteBytes(const uint8_t* val, size_t len) {
|
||||
WriteBytesInternal(reinterpret_cast<const value_type*>(val), len);
|
||||
}
|
||||
|
||||
// Reserves the given number of bytes and returns a value_type* that can be
|
||||
// written into. Useful for functions that require a value_type* buffer and
|
||||
// not a ByteBufferWriter.
|
||||
value_type* ReserveWriteBuffer(size_t len) {
|
||||
buffer_.SetSize(buffer_.size() + len);
|
||||
return buffer_.data();
|
||||
}
|
||||
|
||||
// Resize the buffer to the specified `size`.
|
||||
void Resize(size_t size) { buffer_.SetSize(size); }
|
||||
|
||||
// Clears the contents of the buffer. After this, Length() will be 0.
|
||||
void Clear() { buffer_.Clear(); }
|
||||
|
||||
private:
|
||||
static constexpr size_t kDefaultCapacity = 4096;
|
||||
|
||||
void Construct(const value_type* bytes, size_t size) {
|
||||
if (bytes) {
|
||||
buffer_.AppendData(bytes, size);
|
||||
} else {
|
||||
buffer_.EnsureCapacity(size);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteBytesInternal(const value_type* val, size_t len) {
|
||||
buffer_.AppendData(val, len);
|
||||
}
|
||||
|
||||
BufferClassT buffer_;
|
||||
|
||||
// There are sensible ways to define these, but they aren't needed in our code
|
||||
// base.
|
||||
};
|
||||
|
||||
class ByteBufferWriter : public ByteBufferWriterT<BufferT<uint8_t>> {
|
||||
public:
|
||||
ByteBufferWriter();
|
||||
ByteBufferWriter(const uint8_t* bytes, size_t len);
|
||||
|
||||
ByteBufferWriter(const ByteBufferWriter&) = delete;
|
||||
ByteBufferWriter& operator=(const ByteBufferWriter&) = delete;
|
||||
};
|
||||
|
||||
// The ByteBufferReader references the passed data, i.e. the pointer must be
|
||||
// valid during the lifetime of the reader.
|
||||
class ByteBufferReader {
|
||||
public:
|
||||
explicit ByteBufferReader(
|
||||
rtc::ArrayView<const uint8_t> bytes ABSL_ATTRIBUTE_LIFETIME_BOUND);
|
||||
|
||||
explicit ByteBufferReader(const ByteBufferWriter& buf);
|
||||
|
||||
ByteBufferReader(const ByteBufferReader&) = delete;
|
||||
ByteBufferReader& operator=(const ByteBufferReader&) = delete;
|
||||
|
||||
const uint8_t* Data() const { return bytes_ + start_; }
|
||||
// Returns number of unprocessed bytes.
|
||||
size_t Length() const { return end_ - start_; }
|
||||
// Returns a view of the unprocessed data. Does not move current position.
|
||||
rtc::ArrayView<const uint8_t> DataView() const {
|
||||
return rtc::ArrayView<const uint8_t>(bytes_ + start_, end_ - start_);
|
||||
}
|
||||
|
||||
// Read a next value from the buffer. Return false if there isn't
|
||||
// enough data left for the specified type.
|
||||
bool ReadUInt8(uint8_t* val);
|
||||
bool ReadUInt16(uint16_t* val);
|
||||
bool ReadUInt24(uint32_t* val);
|
||||
bool ReadUInt32(uint32_t* val);
|
||||
bool ReadUInt64(uint64_t* val);
|
||||
bool ReadUVarint(uint64_t* val);
|
||||
// Copies the val.size() next bytes into val.data().
|
||||
bool ReadBytes(rtc::ArrayView<uint8_t> val);
|
||||
// Appends next `len` bytes from the buffer to `val`. Returns false
|
||||
// if there is less than `len` bytes left.
|
||||
bool ReadString(std::string* val, size_t len);
|
||||
// Same as `ReadString` except that the returned string_view will point into
|
||||
// the internal buffer (no additional buffer allocation).
|
||||
bool ReadStringView(absl::string_view* val, size_t len);
|
||||
|
||||
// Moves current position `size` bytes forward. Returns false if
|
||||
// there is less than `size` bytes left in the buffer. Consume doesn't
|
||||
// permanently remove data, so remembered read positions are still valid
|
||||
// after this call.
|
||||
bool Consume(size_t size);
|
||||
|
||||
private:
|
||||
void Construct(const uint8_t* bytes, size_t size);
|
||||
bool ReadBytes(uint8_t* val, size_t len);
|
||||
|
||||
const uint8_t* bytes_;
|
||||
size_t size_;
|
||||
size_t start_;
|
||||
size_t end_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_BYTE_BUFFER_H_
|
||||
212
TMessagesProj/jni/voip/webrtc/rtc_base/byte_order.h
Normal file
212
TMessagesProj/jni/voip/webrtc/rtc_base/byte_order.h
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* 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(WEBRTC_POSIX) && !defined(__native_client__)
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "rtc_base/system/arch.h"
|
||||
|
||||
#if defined(WEBRTC_MAC)
|
||||
#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(WEBRTC_WIN) || defined(__native_client__)
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
#include <stdlib.h>
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#endif // defined(WEBRTC_WIN)
|
||||
|
||||
#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(WEBRTC_WIN)
|
||||
#define htobe64(v) _byteswap_uint64(v)
|
||||
#define be64toh(v) _byteswap_uint64(v)
|
||||
#endif // defined(WEBRTC_WIN)
|
||||
#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(WEBRTC_WIN)
|
||||
#define htobe64(v) (v)
|
||||
#define be64toh(v) (v)
|
||||
#endif // defined(WEBRTC_WIN)
|
||||
#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(WEBRTC_POSIX)
|
||||
#include <endian.h>
|
||||
#else
|
||||
#error "Missing byte order functions for this arch."
|
||||
#endif // defined(WEBRTC_MAC)
|
||||
|
||||
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_
|
||||
121
TMessagesProj/jni/voip/webrtc/rtc_base/callback_list.cc
Normal file
121
TMessagesProj/jni/voip/webrtc/rtc_base/callback_list.cc
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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/callback_list.h"
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace callback_list_impl {
|
||||
|
||||
CallbackListReceivers::CallbackListReceivers() = default;
|
||||
|
||||
CallbackListReceivers::~CallbackListReceivers() {
|
||||
RTC_CHECK(!send_in_progress_);
|
||||
}
|
||||
|
||||
void CallbackListReceivers::RemoveReceivers(const void* removal_tag) {
|
||||
RTC_DCHECK(removal_tag);
|
||||
|
||||
// We divide the receivers_ vector into three regions: from right to left, the
|
||||
// "keep" region, the "todo" region, and the "remove" region. The "todo"
|
||||
// region initially covers the whole vector.
|
||||
size_t first_todo = 0; // First element of the "todo"
|
||||
// region.
|
||||
size_t first_remove = receivers_.size(); // First element of the "remove"
|
||||
// region.
|
||||
|
||||
// Loop until the "todo" region is empty.
|
||||
while (first_todo != first_remove) {
|
||||
if (receivers_[first_todo].removal_tag != removal_tag) {
|
||||
// The first element of the "todo" region should be kept. Move the
|
||||
// "keep"/"todo" boundary.
|
||||
++first_todo;
|
||||
} else if (receivers_[first_remove - 1].removal_tag == removal_tag) {
|
||||
// The last element of the "todo" region should be removed. Move the
|
||||
// "todo"/"remove" boundary.
|
||||
if (send_in_progress_) {
|
||||
// Tag this receiver for removal, which will be done when `ForEach`
|
||||
// has completed.
|
||||
receivers_[first_remove - 1].removal_tag = pending_removal_tag();
|
||||
}
|
||||
--first_remove;
|
||||
} else if (!send_in_progress_) {
|
||||
// The first element of the "todo" region should be removed, and the last
|
||||
// element of the "todo" region should be kept. Swap them, and then shrink
|
||||
// the "todo" region from both ends.
|
||||
RTC_DCHECK_NE(first_todo, first_remove - 1);
|
||||
using std::swap;
|
||||
swap(receivers_[first_todo], receivers_[first_remove - 1]);
|
||||
RTC_DCHECK_NE(receivers_[first_todo].removal_tag, removal_tag);
|
||||
++first_todo;
|
||||
RTC_DCHECK_EQ(receivers_[first_remove - 1].removal_tag, removal_tag);
|
||||
--first_remove;
|
||||
}
|
||||
}
|
||||
|
||||
if (!send_in_progress_) {
|
||||
// Discard the remove region.
|
||||
receivers_.resize(first_remove);
|
||||
}
|
||||
}
|
||||
|
||||
void CallbackListReceivers::Foreach(
|
||||
rtc::FunctionView<void(UntypedFunction&)> fv) {
|
||||
RTC_CHECK(!send_in_progress_);
|
||||
bool removals_detected = false;
|
||||
send_in_progress_ = true;
|
||||
for (auto& r : receivers_) {
|
||||
RTC_DCHECK_NE(r.removal_tag, pending_removal_tag());
|
||||
fv(r.function);
|
||||
if (r.removal_tag == pending_removal_tag()) {
|
||||
removals_detected = true;
|
||||
}
|
||||
}
|
||||
send_in_progress_ = false;
|
||||
if (removals_detected) {
|
||||
RemoveReceivers(pending_removal_tag());
|
||||
}
|
||||
}
|
||||
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<1>);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<2>);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<3>);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<4>);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::NontrivialUntypedFunctionArgs);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::FunctionPointerUntypedFunctionArgs);
|
||||
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<1>);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<2>);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<3>);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<4>);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::NontrivialUntypedFunctionArgs);
|
||||
template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::FunctionPointerUntypedFunctionArgs);
|
||||
|
||||
} // namespace callback_list_impl
|
||||
} // namespace webrtc
|
||||
223
TMessagesProj/jni/voip/webrtc/rtc_base/callback_list.h
Normal file
223
TMessagesProj/jni/voip/webrtc/rtc_base/callback_list.h
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_CALLBACK_LIST_H_
|
||||
#define RTC_BASE_CALLBACK_LIST_H_
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "api/function_view.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/system/assume.h"
|
||||
#include "rtc_base/system/inline.h"
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
#include "rtc_base/untyped_function.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace callback_list_impl {
|
||||
|
||||
class RTC_EXPORT CallbackListReceivers {
|
||||
public:
|
||||
CallbackListReceivers();
|
||||
CallbackListReceivers(const CallbackListReceivers&) = delete;
|
||||
CallbackListReceivers& operator=(const CallbackListReceivers&) = delete;
|
||||
CallbackListReceivers(CallbackListReceivers&&) = delete;
|
||||
CallbackListReceivers& operator=(CallbackListReceivers&&) = delete;
|
||||
~CallbackListReceivers();
|
||||
|
||||
template <typename UntypedFunctionArgsT>
|
||||
RTC_NO_INLINE void AddReceiver(const void* removal_tag,
|
||||
UntypedFunctionArgsT args) {
|
||||
RTC_CHECK(!send_in_progress_);
|
||||
RTC_DCHECK(removal_tag != nullptr);
|
||||
receivers_.push_back({removal_tag, UntypedFunction::Create(args)});
|
||||
}
|
||||
|
||||
template <typename UntypedFunctionArgsT>
|
||||
RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
|
||||
RTC_CHECK(!send_in_progress_);
|
||||
receivers_.push_back({nullptr, UntypedFunction::Create(args)});
|
||||
}
|
||||
|
||||
void RemoveReceivers(const void* removal_tag);
|
||||
|
||||
void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv);
|
||||
|
||||
private:
|
||||
// Special protected pointer value that's used as a removal_tag for
|
||||
// receivers that want to unsubscribe from within a callback.
|
||||
// Note we could use `&receivers_` too, but since it's the first member
|
||||
// variable of the class, its address will be the same as the instance
|
||||
// CallbackList instance, so we take an extra step to avoid collision.
|
||||
const void* pending_removal_tag() const { return &send_in_progress_; }
|
||||
|
||||
struct Callback {
|
||||
const void* removal_tag;
|
||||
UntypedFunction function;
|
||||
};
|
||||
|
||||
std::vector<Callback> receivers_;
|
||||
bool send_in_progress_ = false;
|
||||
};
|
||||
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<1>);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<2>);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<3>);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<4>);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::NontrivialUntypedFunctionArgs);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
const void*,
|
||||
UntypedFunction::FunctionPointerUntypedFunctionArgs);
|
||||
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<1>);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<2>);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<3>);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::TrivialUntypedFunctionArgs<4>);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::NontrivialUntypedFunctionArgs);
|
||||
extern template void CallbackListReceivers::AddReceiver(
|
||||
UntypedFunction::FunctionPointerUntypedFunctionArgs);
|
||||
|
||||
} // namespace callback_list_impl
|
||||
|
||||
// A collection of receivers (callable objects) that can be called all at once.
|
||||
// Optimized for minimal binary size. The template arguments dictate what
|
||||
// signature the callbacks must have; for example, a CallbackList<int, float>
|
||||
// will require callbacks with signature void(int, float).
|
||||
//
|
||||
// CallbackList is neither copyable nor movable (could easily be made movable if
|
||||
// necessary). Callbacks must be movable, but need not be copyable.
|
||||
//
|
||||
// Usage example:
|
||||
//
|
||||
// // Declaration (usually a member variable).
|
||||
// CallbackList<int, float> foo_;
|
||||
//
|
||||
// // Register callbacks. This can be done zero or more times. The
|
||||
// // callbacks must accept the arguments types listed in the CallbackList's
|
||||
// // template argument list, and must return void.
|
||||
// foo_.AddReceiver([...](int a, float b) {...}); // Lambda.
|
||||
// foo_.AddReceiver(SomeFunction); // Function pointer.
|
||||
//
|
||||
// // Call the zero or more receivers, one after the other.
|
||||
// foo_.Send(17, 3.14);
|
||||
//
|
||||
// Callback lifetime considerations
|
||||
// --------------------------------
|
||||
//
|
||||
// CallbackList::AddReceiver() takes ownership of the given callback by moving
|
||||
// it in place. The callback can be any callable object; in particular, it may
|
||||
// have a nontrivial destructor, which will be run when the CallbackList is
|
||||
// destroyed. The callback may thus access data via any type of smart pointer,
|
||||
// expressing e.g. unique, shared, or weak ownership. Of course, if the data is
|
||||
// guaranteed to outlive the callback, a plain raw pointer can be used.
|
||||
//
|
||||
// Take care when trying to have the callback own reference-counted data. The
|
||||
// CallbackList will keep the callback alive, and the callback will keep its
|
||||
// data alive, so as usual with reference-counted ownership, keep an eye out for
|
||||
// cycles!
|
||||
//
|
||||
// Thread safety
|
||||
// -------------
|
||||
//
|
||||
// Like most C++ types, CallbackList is thread compatible: it's not safe to
|
||||
// access it concurrently from multiple threads, but it can be made safe if it
|
||||
// is protected by a mutex, for example.
|
||||
//
|
||||
// Excercise some care when deciding what mutexes to hold when you call
|
||||
// CallbackList::Send(). In particular, do not hold mutexes that callbacks may
|
||||
// need to grab. If a larger object has a CallbackList member and a single mutex
|
||||
// that protects all of its data members, this may e.g. make it necessary to
|
||||
// protect its CallbackList with a separate mutex; otherwise, there will be a
|
||||
// deadlock if the callbacks try to access the object.
|
||||
//
|
||||
// CallbackList as a class data member
|
||||
// -----------------------------------
|
||||
//
|
||||
// CallbackList is a normal C++ data type, and should be private when it is a
|
||||
// data member of a class. For thread safety reasons (see above), it is likely
|
||||
// best to not have an accessor for the entire CallbackList, and instead only
|
||||
// allow callers to add callbacks:
|
||||
//
|
||||
// template <typename F>
|
||||
// void AddFooCallback(F&& callback) {
|
||||
// // Maybe grab a mutex here?
|
||||
// foo_callbacks_.AddReceiver(std::forward<F>(callback));
|
||||
// }
|
||||
//
|
||||
template <typename... ArgT>
|
||||
class CallbackList {
|
||||
public:
|
||||
CallbackList() = default;
|
||||
CallbackList(const CallbackList&) = delete;
|
||||
CallbackList& operator=(const CallbackList&) = delete;
|
||||
CallbackList(CallbackList&&) = delete;
|
||||
CallbackList& operator=(CallbackList&&) = delete;
|
||||
|
||||
// Adds a new receiver. The receiver (a callable object or a function pointer)
|
||||
// must be movable, but need not be copyable. Its call signature should be
|
||||
// `void(ArgT...)`. The removal tag is a pointer to an arbitrary object that
|
||||
// you own, and that will stay alive until the CallbackList is gone, or until
|
||||
// all receivers using it as a removal tag have been removed; you can use it
|
||||
// to remove the receiver.
|
||||
template <typename F>
|
||||
void AddReceiver(const void* removal_tag, F&& f) {
|
||||
receivers_.AddReceiver(
|
||||
removal_tag,
|
||||
UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
|
||||
}
|
||||
|
||||
// Adds a new receiver with no removal tag.
|
||||
template <typename F>
|
||||
void AddReceiver(F&& f) {
|
||||
receivers_.AddReceiver(
|
||||
UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
|
||||
}
|
||||
|
||||
// Removes all receivers that were added with the given removal tag.
|
||||
void RemoveReceivers(const void* removal_tag) {
|
||||
receivers_.RemoveReceivers(removal_tag);
|
||||
}
|
||||
|
||||
// Calls all receivers with the given arguments. While the Send is in
|
||||
// progress, no method calls are allowed; specifically, this means that the
|
||||
// callbacks may not do anything with this CallbackList instance.
|
||||
//
|
||||
// Note: Receivers are called serially, but not necessarily in the same order
|
||||
// they were added.
|
||||
template <typename... ArgU>
|
||||
void Send(ArgU&&... args) {
|
||||
receivers_.Foreach([&](UntypedFunction& f) {
|
||||
f.Call<void(ArgT...)>(std::forward<ArgU>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
callback_list_impl::CallbackListReceivers receivers_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_CALLBACK_LIST_H_
|
||||
240
TMessagesProj/jni/voip/webrtc/rtc_base/checks.cc
Normal file
240
TMessagesProj/jni/voip/webrtc/rtc_base/checks.cc
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* Copyright 2006 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Most of this was borrowed (with minor modifications) from V8's and Chromium's
|
||||
// src/base/logging.cc.
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
#if defined(WEBRTC_ANDROID)
|
||||
#define RTC_LOG_TAG_ANDROID "rtc"
|
||||
#include <android/log.h> // NOLINT
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
#define LAST_SYSTEM_ERROR (::GetLastError())
|
||||
#elif defined(__native_client__) && __native_client__
|
||||
#define LAST_SYSTEM_ERROR (0)
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#include <errno.h>
|
||||
#define LAST_SYSTEM_ERROR (errno)
|
||||
#endif // WEBRTC_WIN
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__format__(__printf__, 2, 3)))
|
||||
#endif
|
||||
void AppendFormat(std::string* s, const char* fmt, ...) {
|
||||
va_list args, copy;
|
||||
va_start(args, fmt);
|
||||
va_copy(copy, args);
|
||||
const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
|
||||
va_end(copy);
|
||||
|
||||
if (predicted_length > 0) {
|
||||
const size_t size = s->size();
|
||||
s->resize(size + predicted_length);
|
||||
// Pass "+ 1" to vsnprintf to include space for the '\0'.
|
||||
std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace rtc {
|
||||
namespace webrtc_checks_impl {
|
||||
|
||||
#if !defined(WEBRTC_CHROMIUM_BUILD)
|
||||
RTC_NORETURN void WriteFatalLog(absl::string_view output) {
|
||||
#if defined(WEBRTC_ANDROID)
|
||||
std::string output_str(output);
|
||||
__android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n",
|
||||
output_str.c_str());
|
||||
#endif
|
||||
fflush(stdout);
|
||||
fwrite(output.data(), output.size(), 1, stderr);
|
||||
fflush(stderr);
|
||||
#if defined(WEBRTC_WIN)
|
||||
DebugBreak();
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
RTC_NORETURN void WriteFatalLog(const char* file,
|
||||
int line,
|
||||
absl::string_view output) {
|
||||
WriteFatalLog(output);
|
||||
}
|
||||
|
||||
#endif // !defined(WEBRTC_CHROMIUM_BUILD)
|
||||
|
||||
#if RTC_CHECK_MSG_ENABLED
|
||||
// Reads one argument from args, appends it to s and advances fmt.
|
||||
// Returns true iff an argument was sucessfully parsed.
|
||||
bool ParseArg(va_list* args, const CheckArgType** fmt, std::string* s) {
|
||||
if (**fmt == CheckArgType::kEnd)
|
||||
return false;
|
||||
|
||||
switch (**fmt) {
|
||||
case CheckArgType::kInt:
|
||||
AppendFormat(s, "%d", va_arg(*args, int));
|
||||
break;
|
||||
case CheckArgType::kLong:
|
||||
AppendFormat(s, "%ld", va_arg(*args, long));
|
||||
break;
|
||||
case CheckArgType::kLongLong:
|
||||
AppendFormat(s, "%lld", va_arg(*args, long long));
|
||||
break;
|
||||
case CheckArgType::kUInt:
|
||||
AppendFormat(s, "%u", va_arg(*args, unsigned));
|
||||
break;
|
||||
case CheckArgType::kULong:
|
||||
AppendFormat(s, "%lu", va_arg(*args, unsigned long));
|
||||
break;
|
||||
case CheckArgType::kULongLong:
|
||||
AppendFormat(s, "%llu", va_arg(*args, unsigned long long));
|
||||
break;
|
||||
case CheckArgType::kDouble:
|
||||
AppendFormat(s, "%g", va_arg(*args, double));
|
||||
break;
|
||||
case CheckArgType::kLongDouble:
|
||||
AppendFormat(s, "%Lg", va_arg(*args, long double));
|
||||
break;
|
||||
case CheckArgType::kCharP:
|
||||
s->append(va_arg(*args, const char*));
|
||||
break;
|
||||
case CheckArgType::kStdString:
|
||||
s->append(*va_arg(*args, const std::string*));
|
||||
break;
|
||||
case CheckArgType::kStringView: {
|
||||
const absl::string_view sv = *va_arg(*args, const absl::string_view*);
|
||||
s->append(sv.data(), sv.size());
|
||||
break;
|
||||
}
|
||||
case CheckArgType::kVoidP:
|
||||
AppendFormat(s, "%p", va_arg(*args, const void*));
|
||||
break;
|
||||
default:
|
||||
s->append("[Invalid CheckArgType]");
|
||||
return false;
|
||||
}
|
||||
(*fmt)++;
|
||||
return true;
|
||||
}
|
||||
|
||||
RTC_NORETURN void FatalLog(const char* file,
|
||||
int line,
|
||||
const char* message,
|
||||
const CheckArgType* fmt,
|
||||
...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
std::string s;
|
||||
AppendFormat(&s,
|
||||
"\n\n"
|
||||
"#\n"
|
||||
"# Fatal error in: %s, line %d\n"
|
||||
"# last system error: %u\n"
|
||||
"# Check failed: %s",
|
||||
file, line, LAST_SYSTEM_ERROR, message);
|
||||
|
||||
if (*fmt == CheckArgType::kCheckOp) {
|
||||
// This log message was generated by RTC_CHECK_OP, so we have to complete
|
||||
// the error message using the operands that have been passed as the first
|
||||
// two arguments.
|
||||
fmt++;
|
||||
|
||||
std::string s1, s2;
|
||||
if (ParseArg(&args, &fmt, &s1) && ParseArg(&args, &fmt, &s2))
|
||||
AppendFormat(&s, " (%s vs. %s)\n# ", s1.c_str(), s2.c_str());
|
||||
} else {
|
||||
s.append("\n# ");
|
||||
}
|
||||
|
||||
// Append all the user-supplied arguments to the message.
|
||||
while (ParseArg(&args, &fmt, &s))
|
||||
;
|
||||
|
||||
va_end(args);
|
||||
|
||||
WriteFatalLog(file, line, s);
|
||||
}
|
||||
#else // RTC_CHECK_MSG_ENABLED
|
||||
RTC_NORETURN void FatalLog(const char* file, int line) {
|
||||
std::string s;
|
||||
AppendFormat(&s,
|
||||
"\n\n"
|
||||
"#\n"
|
||||
"# Fatal error in: %s, line %d\n"
|
||||
"# last system error: %u\n"
|
||||
"# Check failed.\n"
|
||||
"# ",
|
||||
file, line, LAST_SYSTEM_ERROR);
|
||||
WriteFatalLog(file, line, s);
|
||||
}
|
||||
#endif // RTC_CHECK_MSG_ENABLED
|
||||
|
||||
#if RTC_DCHECK_IS_ON
|
||||
|
||||
RTC_NORETURN void UnreachableCodeReached(const char* file, int line) {
|
||||
std::string s;
|
||||
AppendFormat(&s,
|
||||
"\n\n"
|
||||
"#\n"
|
||||
"# Unreachable code reached: %s, line %d\n"
|
||||
"# last system error: %u\n"
|
||||
"# ",
|
||||
file, line, LAST_SYSTEM_ERROR);
|
||||
WriteFatalLog(file, line, s);
|
||||
}
|
||||
|
||||
#else // !RTC_DCHECK_IS_ON
|
||||
|
||||
RTC_NORETURN void UnreachableCodeReached() {
|
||||
std::string s;
|
||||
AppendFormat(&s,
|
||||
"\n\n"
|
||||
"#\n"
|
||||
"# Unreachable code reached (file and line unknown)\n"
|
||||
"# last system error: %u\n"
|
||||
"# ",
|
||||
LAST_SYSTEM_ERROR);
|
||||
WriteFatalLog(s);
|
||||
}
|
||||
|
||||
#endif // !RTC_DCHECK_IS_ON
|
||||
|
||||
} // namespace webrtc_checks_impl
|
||||
} // namespace rtc
|
||||
|
||||
// Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros.
|
||||
RTC_NORETURN void rtc_FatalMessage(const char* file,
|
||||
int line,
|
||||
const char* msg) {
|
||||
#if RTC_CHECK_MSG_ENABLED
|
||||
static constexpr rtc::webrtc_checks_impl::CheckArgType t[] = {
|
||||
rtc::webrtc_checks_impl::CheckArgType::kEnd};
|
||||
rtc::webrtc_checks_impl::FatalLog(file, line, msg, t);
|
||||
#else
|
||||
rtc::webrtc_checks_impl::FatalLog(file, line);
|
||||
#endif
|
||||
}
|
||||
520
TMessagesProj/jni/voip/webrtc/rtc_base/checks.h
Normal file
520
TMessagesProj/jni/voip/webrtc/rtc_base/checks.h
Normal file
|
|
@ -0,0 +1,520 @@
|
|||
/*
|
||||
* Copyright 2006 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can 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_CHECKS_H_
|
||||
#define RTC_BASE_CHECKS_H_
|
||||
|
||||
// If you for some reson need to know if DCHECKs are on, test the value of
|
||||
// RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be
|
||||
// defined, to either a true or a false value.)
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
#define RTC_DCHECK_IS_ON 1
|
||||
#else
|
||||
#define RTC_DCHECK_IS_ON 0
|
||||
#endif
|
||||
|
||||
// Annotate a function that will not return control flow to the caller.
|
||||
#if defined(_MSC_VER)
|
||||
#define RTC_NORETURN __declspec(noreturn)
|
||||
#elif defined(__GNUC__)
|
||||
#define RTC_NORETURN __attribute__((__noreturn__))
|
||||
#else
|
||||
#define RTC_NORETURN
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef RTC_DISABLE_CHECK_MSG
|
||||
#define RTC_CHECK_MSG_ENABLED 0
|
||||
#else
|
||||
#define RTC_CHECK_MSG_ENABLED 1
|
||||
#endif
|
||||
|
||||
#if RTC_CHECK_MSG_ENABLED
|
||||
#define RTC_CHECK_EVAL_MESSAGE(message) message
|
||||
#else
|
||||
#define RTC_CHECK_EVAL_MESSAGE(message) ""
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
// C++ version.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "rtc_base/numerics/safe_compare.h"
|
||||
#include "rtc_base/system/inline.h"
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
|
||||
// The macros here print a message to stderr and abort under various
|
||||
// conditions. All will accept additional stream messages. For example:
|
||||
// RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar.";
|
||||
//
|
||||
// - RTC_CHECK(x) is an assertion that x is always true, and that if it isn't,
|
||||
// it's better to terminate the process than to continue. During development,
|
||||
// the reason that it's better to terminate might simply be that the error
|
||||
// handling code isn't in place yet; in production, the reason might be that
|
||||
// the author of the code truly believes that x will always be true, but that
|
||||
// they recognizes that if they are wrong, abrupt and unpleasant process
|
||||
// termination is still better than carrying on with the assumption violated.
|
||||
//
|
||||
// RTC_CHECK always evaluates its argument, so it's OK for x to have side
|
||||
// effects.
|
||||
//
|
||||
// - RTC_DCHECK(x) is the same as RTC_CHECK(x)---an assertion that x is always
|
||||
// true---except that x will only be evaluated in debug builds; in production
|
||||
// builds, x is simply assumed to be true. This is useful if evaluating x is
|
||||
// expensive and the expected cost of failing to detect the violated
|
||||
// assumption is acceptable. You should not handle cases where a production
|
||||
// build fails to spot a violated condition, even those that would result in
|
||||
// crashes. If the code needs to cope with the error, make it cope, but don't
|
||||
// call RTC_DCHECK; if the condition really can't occur, but you'd sleep
|
||||
// better at night knowing that the process will suicide instead of carrying
|
||||
// on in case you were wrong, use RTC_CHECK instead of RTC_DCHECK.
|
||||
//
|
||||
// RTC_DCHECK only evaluates its argument in debug builds, so if x has visible
|
||||
// side effects, you need to write e.g.
|
||||
// bool w = x; RTC_DCHECK(w);
|
||||
//
|
||||
// - RTC_CHECK_EQ, _NE, _GT, ..., and RTC_DCHECK_EQ, _NE, _GT, ... are
|
||||
// specialized variants of RTC_CHECK and RTC_DCHECK that print prettier
|
||||
// messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and
|
||||
// RTC_DCHECK.
|
||||
//
|
||||
// - RTC_FATAL() aborts unconditionally.
|
||||
|
||||
namespace rtc {
|
||||
namespace webrtc_checks_impl {
|
||||
enum class CheckArgType : int8_t {
|
||||
kEnd = 0,
|
||||
kInt,
|
||||
kLong,
|
||||
kLongLong,
|
||||
kUInt,
|
||||
kULong,
|
||||
kULongLong,
|
||||
kDouble,
|
||||
kLongDouble,
|
||||
kCharP,
|
||||
kStdString,
|
||||
kStringView,
|
||||
kVoidP,
|
||||
|
||||
// kCheckOp doesn't represent an argument type. Instead, it is sent as the
|
||||
// first argument from RTC_CHECK_OP to make FatalLog use the next two
|
||||
// arguments to build the special CHECK_OP error message
|
||||
// (the "a == b (1 vs. 2)" bit).
|
||||
kCheckOp,
|
||||
};
|
||||
|
||||
// These two functions are public so they can be overridden from
|
||||
// webrtc_overrides in chromium.
|
||||
RTC_NORETURN void WriteFatalLog(const char* file,
|
||||
int line,
|
||||
absl::string_view output);
|
||||
RTC_NORETURN void WriteFatalLog(absl::string_view output);
|
||||
|
||||
#if RTC_CHECK_MSG_ENABLED
|
||||
RTC_NORETURN RTC_EXPORT void FatalLog(const char* file,
|
||||
int line,
|
||||
const char* message,
|
||||
const CheckArgType* fmt,
|
||||
...);
|
||||
#else
|
||||
RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, int line);
|
||||
#endif
|
||||
|
||||
// Wrapper for log arguments. Only ever make values of this type with the
|
||||
// MakeVal() functions.
|
||||
template <CheckArgType N, typename T>
|
||||
struct Val {
|
||||
static constexpr CheckArgType Type() { return N; }
|
||||
T GetVal() const { return val; }
|
||||
T val;
|
||||
};
|
||||
|
||||
// Case for when we need to construct a temp string and then print that.
|
||||
// (We can't use Val<CheckArgType::kStdString, const std::string*>
|
||||
// because we need somewhere to store the temp string.)
|
||||
struct ToStringVal {
|
||||
static constexpr CheckArgType Type() { return CheckArgType::kStdString; }
|
||||
const std::string* GetVal() const { return &val; }
|
||||
std::string val;
|
||||
};
|
||||
|
||||
inline Val<CheckArgType::kInt, int> MakeVal(int x) {
|
||||
return {x};
|
||||
}
|
||||
inline Val<CheckArgType::kLong, long> MakeVal(long x) {
|
||||
return {x};
|
||||
}
|
||||
inline Val<CheckArgType::kLongLong, long long> MakeVal(long long x) {
|
||||
return {x};
|
||||
}
|
||||
inline Val<CheckArgType::kUInt, unsigned int> MakeVal(unsigned int x) {
|
||||
return {x};
|
||||
}
|
||||
inline Val<CheckArgType::kULong, unsigned long> MakeVal(unsigned long x) {
|
||||
return {x};
|
||||
}
|
||||
inline Val<CheckArgType::kULongLong, unsigned long long> MakeVal(
|
||||
unsigned long long x) {
|
||||
return {x};
|
||||
}
|
||||
|
||||
inline Val<CheckArgType::kDouble, double> MakeVal(double x) {
|
||||
return {x};
|
||||
}
|
||||
inline Val<CheckArgType::kLongDouble, long double> MakeVal(long double x) {
|
||||
return {x};
|
||||
}
|
||||
|
||||
inline Val<CheckArgType::kCharP, const char*> MakeVal(const char* x) {
|
||||
return {x};
|
||||
}
|
||||
inline Val<CheckArgType::kStdString, const std::string*> MakeVal(
|
||||
const std::string& x) {
|
||||
return {&x};
|
||||
}
|
||||
inline Val<CheckArgType::kStringView, const absl::string_view*> MakeVal(
|
||||
const absl::string_view& x) {
|
||||
return {&x};
|
||||
}
|
||||
|
||||
inline Val<CheckArgType::kVoidP, const void*> MakeVal(const void* x) {
|
||||
return {x};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Val<CheckArgType::kVoidP, const void*> MakeVal(
|
||||
const rtc::scoped_refptr<T>& p) {
|
||||
return {p.get()};
|
||||
}
|
||||
|
||||
// The enum class types are not implicitly convertible to arithmetic types.
|
||||
template <typename T,
|
||||
absl::enable_if_t<std::is_enum<T>::value &&
|
||||
!std::is_arithmetic<T>::value>* = nullptr>
|
||||
inline decltype(MakeVal(std::declval<absl::underlying_type_t<T>>())) MakeVal(
|
||||
T x) {
|
||||
return {static_cast<absl::underlying_type_t<T>>(x)};
|
||||
}
|
||||
|
||||
template <typename T, decltype(ToLogString(std::declval<T>()))* = nullptr>
|
||||
ToStringVal MakeVal(const T& x) {
|
||||
return {ToLogString(x)};
|
||||
}
|
||||
|
||||
// Ephemeral type that represents the result of the logging << operator.
|
||||
template <typename... Ts>
|
||||
class LogStreamer;
|
||||
|
||||
// Base case: Before the first << argument.
|
||||
template <>
|
||||
class LogStreamer<> final {
|
||||
public:
|
||||
template <typename U,
|
||||
typename V = decltype(MakeVal(std::declval<U>())),
|
||||
absl::enable_if_t<std::is_arithmetic<U>::value ||
|
||||
std::is_enum<U>::value>* = nullptr>
|
||||
RTC_FORCE_INLINE LogStreamer<V> operator<<(U arg) const {
|
||||
return LogStreamer<V>(MakeVal(arg), this);
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
typename V = decltype(MakeVal(std::declval<U>())),
|
||||
absl::enable_if_t<!std::is_arithmetic<U>::value &&
|
||||
!std::is_enum<U>::value>* = nullptr>
|
||||
RTC_FORCE_INLINE LogStreamer<V> operator<<(const U& arg) const {
|
||||
return LogStreamer<V>(MakeVal(arg), this);
|
||||
}
|
||||
|
||||
#if RTC_CHECK_MSG_ENABLED
|
||||
template <typename... Us>
|
||||
RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file,
|
||||
const int line,
|
||||
const char* message,
|
||||
const Us&... args) {
|
||||
static constexpr CheckArgType t[] = {Us::Type()..., CheckArgType::kEnd};
|
||||
FatalLog(file, line, message, t, args.GetVal()...);
|
||||
}
|
||||
|
||||
template <typename... Us>
|
||||
RTC_NORETURN RTC_FORCE_INLINE static void CallCheckOp(const char* file,
|
||||
const int line,
|
||||
const char* message,
|
||||
const Us&... args) {
|
||||
static constexpr CheckArgType t[] = {CheckArgType::kCheckOp, Us::Type()...,
|
||||
CheckArgType::kEnd};
|
||||
FatalLog(file, line, message, t, args.GetVal()...);
|
||||
}
|
||||
#else
|
||||
template <typename... Us>
|
||||
RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file,
|
||||
const int line) {
|
||||
FatalLog(file, line);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// Inductive case: We've already seen at least one << argument. The most recent
|
||||
// one had type `T`, and the earlier ones had types `Ts`.
|
||||
template <typename T, typename... Ts>
|
||||
class LogStreamer<T, Ts...> final {
|
||||
public:
|
||||
RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
|
||||
: arg_(arg), prior_(prior) {}
|
||||
|
||||
template <typename U,
|
||||
typename V = decltype(MakeVal(std::declval<U>())),
|
||||
absl::enable_if_t<std::is_arithmetic<U>::value ||
|
||||
std::is_enum<U>::value>* = nullptr>
|
||||
RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(U arg) const {
|
||||
return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
typename V = decltype(MakeVal(std::declval<U>())),
|
||||
absl::enable_if_t<!std::is_arithmetic<U>::value &&
|
||||
!std::is_enum<U>::value>* = nullptr>
|
||||
RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(const U& arg) const {
|
||||
return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
|
||||
}
|
||||
|
||||
#if RTC_CHECK_MSG_ENABLED
|
||||
template <typename... Us>
|
||||
RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file,
|
||||
const int line,
|
||||
const char* message,
|
||||
const Us&... args) const {
|
||||
prior_->Call(file, line, message, arg_, args...);
|
||||
}
|
||||
|
||||
template <typename... Us>
|
||||
RTC_NORETURN RTC_FORCE_INLINE void CallCheckOp(const char* file,
|
||||
const int line,
|
||||
const char* message,
|
||||
const Us&... args) const {
|
||||
prior_->CallCheckOp(file, line, message, arg_, args...);
|
||||
}
|
||||
#else
|
||||
template <typename... Us>
|
||||
RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file,
|
||||
const int line) const {
|
||||
prior_->Call(file, line);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
// The most recent argument.
|
||||
T arg_;
|
||||
|
||||
// Earlier arguments.
|
||||
const LogStreamer<Ts...>* prior_;
|
||||
};
|
||||
|
||||
template <bool isCheckOp>
|
||||
class FatalLogCall final {
|
||||
public:
|
||||
FatalLogCall(const char* file, int line, const char* message)
|
||||
: file_(file), line_(line), message_(message) {}
|
||||
|
||||
// This can be any binary operator with precedence lower than <<.
|
||||
template <typename... Ts>
|
||||
RTC_NORETURN RTC_FORCE_INLINE void operator&(
|
||||
const LogStreamer<Ts...>& streamer) {
|
||||
#if RTC_CHECK_MSG_ENABLED
|
||||
isCheckOp ? streamer.CallCheckOp(file_, line_, message_)
|
||||
: streamer.Call(file_, line_, message_);
|
||||
#else
|
||||
streamer.Call(file_, line_);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
const char* file_;
|
||||
int line_;
|
||||
const char* message_;
|
||||
};
|
||||
|
||||
#if RTC_DCHECK_IS_ON
|
||||
|
||||
// Be helpful, and include file and line in the RTC_CHECK_NOTREACHED error
|
||||
// message.
|
||||
#define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS __FILE__, __LINE__
|
||||
RTC_NORETURN RTC_EXPORT void UnreachableCodeReached(const char* file, int line);
|
||||
|
||||
#else
|
||||
|
||||
// Be mindful of binary size, and don't include file and line in the
|
||||
// RTC_CHECK_NOTREACHED error message.
|
||||
#define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS
|
||||
RTC_NORETURN RTC_EXPORT void UnreachableCodeReached();
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace webrtc_checks_impl
|
||||
|
||||
// The actual stream used isn't important. We reference `ignored` in the code
|
||||
// but don't evaluate it; this is to avoid "unused variable" warnings (we do so
|
||||
// in a particularly convoluted way with an extra ?: because that appears to be
|
||||
// the simplest construct that keeps Visual Studio from complaining about
|
||||
// condition being unused).
|
||||
#define RTC_EAT_STREAM_PARAMETERS(ignored) \
|
||||
(true ? true : ((void)(ignored), true)) \
|
||||
? static_cast<void>(0) \
|
||||
: ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
|
||||
::rtc::webrtc_checks_impl::LogStreamer<>()
|
||||
|
||||
// Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if
|
||||
// values of the same types as `a` and `b` can't be compared with the given
|
||||
// operation, and that would evaluate `a` and `b` if evaluated.
|
||||
#define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \
|
||||
RTC_EAT_STREAM_PARAMETERS(((void)::rtc::Safe##op(a, b)))
|
||||
|
||||
// RTC_CHECK dies with a fatal error if condition is not true. It is *not*
|
||||
// controlled by NDEBUG or anything else, so the check will be executed
|
||||
// regardless of compilation mode.
|
||||
//
|
||||
// We make sure RTC_CHECK et al. always evaluates `condition`, as
|
||||
// doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom.
|
||||
//
|
||||
// RTC_CHECK_OP is a helper macro for binary operators.
|
||||
// Don't use this macro directly in your code, use RTC_CHECK_EQ et al below.
|
||||
#if RTC_CHECK_MSG_ENABLED
|
||||
#define RTC_CHECK(condition) \
|
||||
(condition) ? static_cast<void>(0) \
|
||||
: ::rtc::webrtc_checks_impl::FatalLogCall<false>( \
|
||||
__FILE__, __LINE__, #condition) & \
|
||||
::rtc::webrtc_checks_impl::LogStreamer<>()
|
||||
|
||||
#define RTC_CHECK_OP(name, op, val1, val2) \
|
||||
::rtc::Safe##name((val1), (val2)) \
|
||||
? static_cast<void>(0) \
|
||||
: ::rtc::webrtc_checks_impl::FatalLogCall<true>( \
|
||||
__FILE__, __LINE__, #val1 " " #op " " #val2) & \
|
||||
::rtc::webrtc_checks_impl::LogStreamer<>() << (val1) << (val2)
|
||||
#else
|
||||
#define RTC_CHECK(condition) \
|
||||
(condition) ? static_cast<void>(0) \
|
||||
: true ? ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \
|
||||
"") & \
|
||||
::rtc::webrtc_checks_impl::LogStreamer<>() \
|
||||
: ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
|
||||
::rtc::webrtc_checks_impl::LogStreamer<>()
|
||||
|
||||
#define RTC_CHECK_OP(name, op, val1, val2) \
|
||||
::rtc::Safe##name((val1), (val2)) ? static_cast<void>(0) \
|
||||
: true ? ::rtc::webrtc_checks_impl::FatalLogCall<true>(__FILE__, __LINE__, \
|
||||
"") & \
|
||||
::rtc::webrtc_checks_impl::LogStreamer<>() \
|
||||
: ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
|
||||
::rtc::webrtc_checks_impl::LogStreamer<>()
|
||||
#endif
|
||||
|
||||
#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2)
|
||||
#define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(Ne, !=, val1, val2)
|
||||
#define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(Le, <=, val1, val2)
|
||||
#define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(Lt, <, val1, val2)
|
||||
#define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(Ge, >=, val1, val2)
|
||||
#define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(Gt, >, val1, val2)
|
||||
|
||||
// The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates
|
||||
// code in debug builds. It does reference the condition parameter in all cases,
|
||||
// though, so callers won't risk getting warnings about unused variables.
|
||||
#if RTC_DCHECK_IS_ON
|
||||
#define RTC_DCHECK(condition) RTC_CHECK(condition)
|
||||
#define RTC_DCHECK_EQ(v1, v2) RTC_CHECK_EQ(v1, v2)
|
||||
#define RTC_DCHECK_NE(v1, v2) RTC_CHECK_NE(v1, v2)
|
||||
#define RTC_DCHECK_LE(v1, v2) RTC_CHECK_LE(v1, v2)
|
||||
#define RTC_DCHECK_LT(v1, v2) RTC_CHECK_LT(v1, v2)
|
||||
#define RTC_DCHECK_GE(v1, v2) RTC_CHECK_GE(v1, v2)
|
||||
#define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2)
|
||||
#else
|
||||
#define RTC_DCHECK(condition) RTC_EAT_STREAM_PARAMETERS(condition)
|
||||
#define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Eq, v1, v2)
|
||||
#define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ne, v1, v2)
|
||||
#define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Le, v1, v2)
|
||||
#define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Lt, v1, v2)
|
||||
#define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ge, v1, v2)
|
||||
#define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Gt, v1, v2)
|
||||
#endif
|
||||
|
||||
#define RTC_UNREACHABLE_CODE_HIT false
|
||||
#define RTC_DCHECK_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)
|
||||
|
||||
// Kills the process with an error message. Never returns. Use when you wish to
|
||||
// assert that a point in the code is never reached.
|
||||
#define RTC_CHECK_NOTREACHED() \
|
||||
do { \
|
||||
::rtc::webrtc_checks_impl::UnreachableCodeReached( \
|
||||
RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS); \
|
||||
} while (0)
|
||||
|
||||
#define RTC_FATAL() \
|
||||
::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \
|
||||
"FATAL()") & \
|
||||
::rtc::webrtc_checks_impl::LogStreamer<>()
|
||||
|
||||
// Performs the integer division a/b and returns the result. CHECKs that the
|
||||
// remainder is zero.
|
||||
template <typename T>
|
||||
inline T CheckedDivExact(T a, T b) {
|
||||
RTC_CHECK_EQ(a % b, 0) << a << " is not evenly divisible by " << b;
|
||||
return a / b;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#else // __cplusplus not defined
|
||||
// C version. Lacks many features compared to the C++ version, but usage
|
||||
// guidelines are the same.
|
||||
|
||||
#define RTC_CHECK(condition) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
rtc_FatalMessage(__FILE__, __LINE__, \
|
||||
RTC_CHECK_EVAL_MESSAGE("CHECK failed: " #condition)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RTC_CHECK_EQ(a, b) RTC_CHECK((a) == (b))
|
||||
#define RTC_CHECK_NE(a, b) RTC_CHECK((a) != (b))
|
||||
#define RTC_CHECK_LE(a, b) RTC_CHECK((a) <= (b))
|
||||
#define RTC_CHECK_LT(a, b) RTC_CHECK((a) < (b))
|
||||
#define RTC_CHECK_GE(a, b) RTC_CHECK((a) >= (b))
|
||||
#define RTC_CHECK_GT(a, b) RTC_CHECK((a) > (b))
|
||||
|
||||
#define RTC_DCHECK(condition) \
|
||||
do { \
|
||||
if (RTC_DCHECK_IS_ON && !(condition)) { \
|
||||
rtc_FatalMessage(__FILE__, __LINE__, \
|
||||
RTC_CHECK_EVAL_MESSAGE("DCHECK failed: " #condition)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RTC_DCHECK_EQ(a, b) RTC_DCHECK((a) == (b))
|
||||
#define RTC_DCHECK_NE(a, b) RTC_DCHECK((a) != (b))
|
||||
#define RTC_DCHECK_LE(a, b) RTC_DCHECK((a) <= (b))
|
||||
#define RTC_DCHECK_LT(a, b) RTC_DCHECK((a) < (b))
|
||||
#define RTC_DCHECK_GE(a, b) RTC_DCHECK((a) >= (b))
|
||||
#define RTC_DCHECK_GT(a, b) RTC_DCHECK((a) > (b))
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // RTC_BASE_CHECKS_H_
|
||||
25
TMessagesProj/jni/voip/webrtc/rtc_base/compile_assert_c.h
Normal file
25
TMessagesProj/jni/voip/webrtc/rtc_base/compile_assert_c.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 RTC_BASE_COMPILE_ASSERT_C_H_
|
||||
#define RTC_BASE_COMPILE_ASSERT_C_H_
|
||||
|
||||
// Use this macro to verify at compile time that certain restrictions are met.
|
||||
// The argument is the boolean expression to evaluate.
|
||||
// Example:
|
||||
// RTC_COMPILE_ASSERT(sizeof(foo) < 128);
|
||||
// Note: In C++, use static_assert instead!
|
||||
#define RTC_COMPILE_ASSERT(expression) \
|
||||
switch (0) { \
|
||||
case 0: \
|
||||
case expression:; \
|
||||
}
|
||||
|
||||
#endif // RTC_BASE_COMPILE_ASSERT_C_H_
|
||||
374
TMessagesProj/jni/voip/webrtc/rtc_base/containers/flat_map.h
Normal file
374
TMessagesProj/jni/voip/webrtc/rtc_base/containers/flat_map.h
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
// This implementation is borrowed from Chromium.
|
||||
|
||||
#ifndef RTC_BASE_CONTAINERS_FLAT_MAP_H_
|
||||
#define RTC_BASE_CONTAINERS_FLAT_MAP_H_
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/containers/flat_tree.h" // IWYU pragma: export
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace flat_containers_internal {
|
||||
|
||||
// An implementation of the flat_tree GetKeyFromValue template parameter that
|
||||
// extracts the key as the first element of a pair.
|
||||
struct GetFirst {
|
||||
template <class Key, class Mapped>
|
||||
constexpr const Key& operator()(const std::pair<Key, Mapped>& p) const {
|
||||
return p.first;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace flat_containers_internal
|
||||
|
||||
// flat_map is a container with a std::map-like interface that stores its
|
||||
// contents in a sorted container, by default a vector.
|
||||
//
|
||||
// Its implementation mostly tracks the corresponding standardization proposal
|
||||
// https://wg21.link/P0429, except that the storage of keys and values is not
|
||||
// split.
|
||||
//
|
||||
// PROS
|
||||
//
|
||||
// - Good memory locality.
|
||||
// - Low overhead, especially for smaller maps.
|
||||
// - Performance is good for more workloads than you might expect (see
|
||||
// //base/containers/README.md in Chromium repository)
|
||||
// - Supports C++14 map interface.
|
||||
//
|
||||
// CONS
|
||||
//
|
||||
// - Inserts and removals are O(n).
|
||||
//
|
||||
// IMPORTANT NOTES
|
||||
//
|
||||
// - Iterators are invalidated across mutations. This means that the following
|
||||
// line of code has undefined behavior since adding a new element could
|
||||
// resize the container, invalidating all iterators:
|
||||
// container["new element"] = it.second;
|
||||
// - If possible, construct a flat_map in one operation by inserting into
|
||||
// a container and moving that container into the flat_map constructor.
|
||||
//
|
||||
// QUICK REFERENCE
|
||||
//
|
||||
// Most of the core functionality is inherited from flat_tree. Please see
|
||||
// flat_tree.h for more details for most of these functions. As a quick
|
||||
// reference, the functions available are:
|
||||
//
|
||||
// Constructors (inputs need not be sorted):
|
||||
// flat_map(const flat_map&);
|
||||
// flat_map(flat_map&&);
|
||||
// flat_map(InputIterator first, InputIterator last,
|
||||
// const Compare& compare = Compare());
|
||||
// flat_map(const container_type& items,
|
||||
// const Compare& compare = Compare());
|
||||
// flat_map(container_type&& items,
|
||||
// const Compare& compare = Compare()); // Re-use storage.
|
||||
// flat_map(std::initializer_list<value_type> ilist,
|
||||
// const Compare& comp = Compare());
|
||||
//
|
||||
// Constructors (inputs need to be sorted):
|
||||
// flat_map(sorted_unique_t,
|
||||
// InputIterator first, InputIterator last,
|
||||
// const Compare& compare = Compare());
|
||||
// flat_map(sorted_unique_t,
|
||||
// const container_type& items,
|
||||
// const Compare& compare = Compare());
|
||||
// flat_map(sorted_unique_t,
|
||||
// container_type&& items,
|
||||
// const Compare& compare = Compare()); // Re-use storage.
|
||||
// flat_map(sorted_unique_t,
|
||||
// std::initializer_list<value_type> ilist,
|
||||
// const Compare& comp = Compare());
|
||||
//
|
||||
// Assignment functions:
|
||||
// flat_map& operator=(const flat_map&);
|
||||
// flat_map& operator=(flat_map&&);
|
||||
// flat_map& operator=(initializer_list<value_type>);
|
||||
//
|
||||
// Memory management functions:
|
||||
// void reserve(size_t);
|
||||
// size_t capacity() const;
|
||||
// void shrink_to_fit();
|
||||
//
|
||||
// Size management functions:
|
||||
// void clear();
|
||||
// size_t size() const;
|
||||
// size_t max_size() const;
|
||||
// bool empty() const;
|
||||
//
|
||||
// Iterator functions:
|
||||
// iterator begin();
|
||||
// const_iterator begin() const;
|
||||
// const_iterator cbegin() const;
|
||||
// iterator end();
|
||||
// const_iterator end() const;
|
||||
// const_iterator cend() const;
|
||||
// reverse_iterator rbegin();
|
||||
// const reverse_iterator rbegin() const;
|
||||
// const_reverse_iterator crbegin() const;
|
||||
// reverse_iterator rend();
|
||||
// const_reverse_iterator rend() const;
|
||||
// const_reverse_iterator crend() const;
|
||||
//
|
||||
// Insert and accessor functions:
|
||||
// mapped_type& operator[](const key_type&);
|
||||
// mapped_type& operator[](key_type&&);
|
||||
// mapped_type& at(const K&);
|
||||
// const mapped_type& at(const K&) const;
|
||||
// pair<iterator, bool> insert(const value_type&);
|
||||
// pair<iterator, bool> insert(value_type&&);
|
||||
// iterator insert(const_iterator hint, const value_type&);
|
||||
// iterator insert(const_iterator hint, value_type&&);
|
||||
// void insert(InputIterator first, InputIterator last);
|
||||
// pair<iterator, bool> insert_or_assign(K&&, M&&);
|
||||
// iterator insert_or_assign(const_iterator hint, K&&, M&&);
|
||||
// pair<iterator, bool> emplace(Args&&...);
|
||||
// iterator emplace_hint(const_iterator, Args&&...);
|
||||
// pair<iterator, bool> try_emplace(K&&, Args&&...);
|
||||
// iterator try_emplace(const_iterator hint, K&&, Args&&...);
|
||||
|
||||
// Underlying type functions:
|
||||
// container_type extract() &&;
|
||||
// void replace(container_type&&);
|
||||
//
|
||||
// Erase functions:
|
||||
// iterator erase(iterator);
|
||||
// iterator erase(const_iterator);
|
||||
// iterator erase(const_iterator first, const_iterator& last);
|
||||
// template <class K> size_t erase(const K& key);
|
||||
//
|
||||
// Comparators (see std::map documentation).
|
||||
// key_compare key_comp() const;
|
||||
// value_compare value_comp() const;
|
||||
//
|
||||
// Search functions:
|
||||
// template <typename K> size_t count(const K&) const;
|
||||
// template <typename K> iterator find(const K&);
|
||||
// template <typename K> const_iterator find(const K&) const;
|
||||
// template <typename K> bool contains(const K&) const;
|
||||
// template <typename K> pair<iterator, iterator> equal_range(const K&);
|
||||
// template <typename K> iterator lower_bound(const K&);
|
||||
// template <typename K> const_iterator lower_bound(const K&) const;
|
||||
// template <typename K> iterator upper_bound(const K&);
|
||||
// template <typename K> const_iterator upper_bound(const K&) const;
|
||||
//
|
||||
// General functions:
|
||||
// void swap(flat_map&);
|
||||
//
|
||||
// Non-member operators:
|
||||
// bool operator==(const flat_map&, const flat_map);
|
||||
// bool operator!=(const flat_map&, const flat_map);
|
||||
// bool operator<(const flat_map&, const flat_map);
|
||||
// bool operator>(const flat_map&, const flat_map);
|
||||
// bool operator>=(const flat_map&, const flat_map);
|
||||
// bool operator<=(const flat_map&, const flat_map);
|
||||
//
|
||||
template <class Key,
|
||||
class Mapped,
|
||||
class Compare = std::less<>,
|
||||
class Container = std::vector<std::pair<Key, Mapped>>>
|
||||
class flat_map : public ::webrtc::flat_containers_internal::flat_tree<
|
||||
Key,
|
||||
flat_containers_internal::GetFirst,
|
||||
Compare,
|
||||
Container> {
|
||||
private:
|
||||
using tree = typename ::webrtc::flat_containers_internal::
|
||||
flat_tree<Key, flat_containers_internal::GetFirst, Compare, Container>;
|
||||
|
||||
public:
|
||||
using key_type = typename tree::key_type;
|
||||
using mapped_type = Mapped;
|
||||
using value_type = typename tree::value_type;
|
||||
using reference = typename Container::reference;
|
||||
using const_reference = typename Container::const_reference;
|
||||
using size_type = typename Container::size_type;
|
||||
using difference_type = typename Container::difference_type;
|
||||
using iterator = typename tree::iterator;
|
||||
using const_iterator = typename tree::const_iterator;
|
||||
using reverse_iterator = typename tree::reverse_iterator;
|
||||
using const_reverse_iterator = typename tree::const_reverse_iterator;
|
||||
using container_type = typename tree::container_type;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Lifetime and assignments.
|
||||
//
|
||||
// Note: we explicitly bring operator= in because otherwise
|
||||
// flat_map<...> x;
|
||||
// x = {...};
|
||||
// Would first create a flat_map and then move assign it. This most likely
|
||||
// would be optimized away but still affects our debug builds.
|
||||
|
||||
using tree::tree;
|
||||
using tree::operator=;
|
||||
|
||||
// Out-of-bound calls to at() will CHECK.
|
||||
template <class K>
|
||||
mapped_type& at(const K& key);
|
||||
template <class K>
|
||||
const mapped_type& at(const K& key) const;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Map-specific insert operations.
|
||||
//
|
||||
// Normal insert() functions are inherited from flat_tree.
|
||||
//
|
||||
// Assume that every operation invalidates iterators and references.
|
||||
// Insertion of one element can take O(size).
|
||||
|
||||
mapped_type& operator[](const key_type& key);
|
||||
mapped_type& operator[](key_type&& key);
|
||||
|
||||
template <class K, class M>
|
||||
std::pair<iterator, bool> insert_or_assign(K&& key, M&& obj);
|
||||
template <class K, class M>
|
||||
iterator insert_or_assign(const_iterator hint, K&& key, M&& obj);
|
||||
|
||||
template <class K, class... Args>
|
||||
std::enable_if_t<std::is_constructible<key_type, K&&>::value,
|
||||
std::pair<iterator, bool>>
|
||||
try_emplace(K&& key, Args&&... args);
|
||||
|
||||
template <class K, class... Args>
|
||||
std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator>
|
||||
try_emplace(const_iterator hint, K&& key, Args&&... args);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// General operations.
|
||||
//
|
||||
// Assume that swap invalidates iterators and references.
|
||||
|
||||
void swap(flat_map& other) noexcept;
|
||||
|
||||
friend void swap(flat_map& lhs, flat_map& rhs) noexcept { lhs.swap(rhs); }
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Lookups.
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
template <class K>
|
||||
auto flat_map<Key, Mapped, Compare, Container>::at(const K& key)
|
||||
-> mapped_type& {
|
||||
iterator found = tree::find(key);
|
||||
RTC_CHECK(found != tree::end());
|
||||
return found->second;
|
||||
}
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
template <class K>
|
||||
auto flat_map<Key, Mapped, Compare, Container>::at(const K& key) const
|
||||
-> const mapped_type& {
|
||||
const_iterator found = tree::find(key);
|
||||
RTC_CHECK(found != tree::cend());
|
||||
return found->second;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Insert operations.
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
auto flat_map<Key, Mapped, Compare, Container>::operator[](const key_type& key)
|
||||
-> mapped_type& {
|
||||
iterator found = tree::lower_bound(key);
|
||||
if (found == tree::end() || tree::key_comp()(key, found->first))
|
||||
found = tree::unsafe_emplace(found, key, mapped_type());
|
||||
return found->second;
|
||||
}
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
auto flat_map<Key, Mapped, Compare, Container>::operator[](key_type&& key)
|
||||
-> mapped_type& {
|
||||
iterator found = tree::lower_bound(key);
|
||||
if (found == tree::end() || tree::key_comp()(key, found->first))
|
||||
found = tree::unsafe_emplace(found, std::move(key), mapped_type());
|
||||
return found->second;
|
||||
}
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
template <class K, class M>
|
||||
auto flat_map<Key, Mapped, Compare, Container>::insert_or_assign(K&& key,
|
||||
M&& obj)
|
||||
-> std::pair<iterator, bool> {
|
||||
auto result =
|
||||
tree::emplace_key_args(key, std::forward<K>(key), std::forward<M>(obj));
|
||||
if (!result.second)
|
||||
result.first->second = std::forward<M>(obj);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
template <class K, class M>
|
||||
auto flat_map<Key, Mapped, Compare, Container>::insert_or_assign(
|
||||
const_iterator hint,
|
||||
K&& key,
|
||||
M&& obj) -> iterator {
|
||||
auto result = tree::emplace_hint_key_args(hint, key, std::forward<K>(key),
|
||||
std::forward<M>(obj));
|
||||
if (!result.second)
|
||||
result.first->second = std::forward<M>(obj);
|
||||
return result.first;
|
||||
}
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
template <class K, class... Args>
|
||||
auto flat_map<Key, Mapped, Compare, Container>::try_emplace(K&& key,
|
||||
Args&&... args)
|
||||
-> std::enable_if_t<std::is_constructible<key_type, K&&>::value,
|
||||
std::pair<iterator, bool>> {
|
||||
return tree::emplace_key_args(
|
||||
key, std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<K>(key)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
template <class K, class... Args>
|
||||
auto flat_map<Key, Mapped, Compare, Container>::try_emplace(const_iterator hint,
|
||||
K&& key,
|
||||
Args&&... args)
|
||||
-> std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator> {
|
||||
return tree::emplace_hint_key_args(
|
||||
hint, key, std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<K>(key)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
.first;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// General operations.
|
||||
|
||||
template <class Key, class Mapped, class Compare, class Container>
|
||||
void flat_map<Key, Mapped, Compare, Container>::swap(flat_map& other) noexcept {
|
||||
tree::swap(other);
|
||||
}
|
||||
|
||||
// Erases all elements that match predicate. It has O(size) complexity.
|
||||
//
|
||||
// flat_map<int, Timestamp> last_times;
|
||||
// ...
|
||||
// EraseIf(last_times,
|
||||
// [&](const auto& element) { return now - element.second > kLimit; });
|
||||
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls)
|
||||
using ::webrtc::flat_containers_internal::EraseIf;
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_CONTAINERS_FLAT_MAP_H_
|
||||
178
TMessagesProj/jni/voip/webrtc/rtc_base/containers/flat_set.h
Normal file
178
TMessagesProj/jni/voip/webrtc/rtc_base/containers/flat_set.h
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
// This implementation is borrowed from Chromium.
|
||||
|
||||
#ifndef RTC_BASE_CONTAINERS_FLAT_SET_H_
|
||||
#define RTC_BASE_CONTAINERS_FLAT_SET_H_
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "rtc_base/containers/flat_tree.h" // IWYU pragma: export
|
||||
#include "rtc_base/containers/identity.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// flat_set is a container with a std::set-like interface that stores its
|
||||
// contents in a sorted container, by default a vector.
|
||||
//
|
||||
// Its implementation mostly tracks the corresponding standardization proposal
|
||||
// https://wg21.link/P1222.
|
||||
//
|
||||
//
|
||||
// PROS
|
||||
//
|
||||
// - Good memory locality.
|
||||
// - Low overhead, especially for smaller sets.
|
||||
// - Performance is good for more workloads than you might expect (see
|
||||
// //base/containers/README.md in Chromium repository)
|
||||
// - Supports C++14 set interface.
|
||||
//
|
||||
// CONS
|
||||
//
|
||||
// - Inserts and removals are O(n).
|
||||
//
|
||||
// IMPORTANT NOTES
|
||||
//
|
||||
// - Iterators are invalidated across mutations.
|
||||
// - If possible, construct a flat_set in one operation by inserting into
|
||||
// a container and moving that container into the flat_set constructor.
|
||||
// - For multiple removals use base::EraseIf() which is O(n) rather than
|
||||
// O(n * removed_items).
|
||||
//
|
||||
// QUICK REFERENCE
|
||||
//
|
||||
// Most of the core functionality is inherited from flat_tree. Please see
|
||||
// flat_tree.h for more details for most of these functions. As a quick
|
||||
// reference, the functions available are:
|
||||
//
|
||||
// Constructors (inputs need not be sorted):
|
||||
// flat_set(const flat_set&);
|
||||
// flat_set(flat_set&&);
|
||||
// flat_set(InputIterator first, InputIterator last,
|
||||
// const Compare& compare = Compare());
|
||||
// flat_set(const container_type& items,
|
||||
// const Compare& compare = Compare());
|
||||
// flat_set(container_type&& items,
|
||||
// const Compare& compare = Compare()); // Re-use storage.
|
||||
// flat_set(std::initializer_list<value_type> ilist,
|
||||
// const Compare& comp = Compare());
|
||||
//
|
||||
// Constructors (inputs need to be sorted):
|
||||
// flat_set(sorted_unique_t,
|
||||
// InputIterator first, InputIterator last,
|
||||
// const Compare& compare = Compare());
|
||||
// flat_set(sorted_unique_t,
|
||||
// const container_type& items,
|
||||
// const Compare& compare = Compare());
|
||||
// flat_set(sorted_unique_t,
|
||||
// container_type&& items,
|
||||
// const Compare& compare = Compare()); // Re-use storage.
|
||||
// flat_set(sorted_unique_t,
|
||||
// std::initializer_list<value_type> ilist,
|
||||
// const Compare& comp = Compare());
|
||||
//
|
||||
// Assignment functions:
|
||||
// flat_set& operator=(const flat_set&);
|
||||
// flat_set& operator=(flat_set&&);
|
||||
// flat_set& operator=(initializer_list<Key>);
|
||||
//
|
||||
// Memory management functions:
|
||||
// void reserve(size_t);
|
||||
// size_t capacity() const;
|
||||
// void shrink_to_fit();
|
||||
//
|
||||
// Size management functions:
|
||||
// void clear();
|
||||
// size_t size() const;
|
||||
// size_t max_size() const;
|
||||
// bool empty() const;
|
||||
//
|
||||
// Iterator functions:
|
||||
// iterator begin();
|
||||
// const_iterator begin() const;
|
||||
// const_iterator cbegin() const;
|
||||
// iterator end();
|
||||
// const_iterator end() const;
|
||||
// const_iterator cend() const;
|
||||
// reverse_iterator rbegin();
|
||||
// const reverse_iterator rbegin() const;
|
||||
// const_reverse_iterator crbegin() const;
|
||||
// reverse_iterator rend();
|
||||
// const_reverse_iterator rend() const;
|
||||
// const_reverse_iterator crend() const;
|
||||
//
|
||||
// Insert and accessor functions:
|
||||
// pair<iterator, bool> insert(const key_type&);
|
||||
// pair<iterator, bool> insert(key_type&&);
|
||||
// void insert(InputIterator first, InputIterator last);
|
||||
// iterator insert(const_iterator hint, const key_type&);
|
||||
// iterator insert(const_iterator hint, key_type&&);
|
||||
// pair<iterator, bool> emplace(Args&&...);
|
||||
// iterator emplace_hint(const_iterator, Args&&...);
|
||||
//
|
||||
// Underlying type functions:
|
||||
// container_type extract() &&;
|
||||
// void replace(container_type&&);
|
||||
//
|
||||
// Erase functions:
|
||||
// iterator erase(iterator);
|
||||
// iterator erase(const_iterator);
|
||||
// iterator erase(const_iterator first, const_iterator& last);
|
||||
// template <typename K> size_t erase(const K& key);
|
||||
//
|
||||
// Comparators (see std::set documentation).
|
||||
// key_compare key_comp() const;
|
||||
// value_compare value_comp() const;
|
||||
//
|
||||
// Search functions:
|
||||
// template <typename K> size_t count(const K&) const;
|
||||
// template <typename K> iterator find(const K&);
|
||||
// template <typename K> const_iterator find(const K&) const;
|
||||
// template <typename K> bool contains(const K&) const;
|
||||
// template <typename K> pair<iterator, iterator> equal_range(K&);
|
||||
// template <typename K> iterator lower_bound(const K&);
|
||||
// template <typename K> const_iterator lower_bound(const K&) const;
|
||||
// template <typename K> iterator upper_bound(const K&);
|
||||
// template <typename K> const_iterator upper_bound(const K&) const;
|
||||
//
|
||||
// General functions:
|
||||
// void swap(flat_set&);
|
||||
//
|
||||
// Non-member operators:
|
||||
// bool operator==(const flat_set&, const flat_set);
|
||||
// bool operator!=(const flat_set&, const flat_set);
|
||||
// bool operator<(const flat_set&, const flat_set);
|
||||
// bool operator>(const flat_set&, const flat_set);
|
||||
// bool operator>=(const flat_set&, const flat_set);
|
||||
// bool operator<=(const flat_set&, const flat_set);
|
||||
//
|
||||
template <class Key,
|
||||
class Compare = std::less<>,
|
||||
class Container = std::vector<Key>>
|
||||
using flat_set = typename ::webrtc::flat_containers_internal::
|
||||
flat_tree<Key, webrtc::identity, Compare, Container>;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// General operations.
|
||||
|
||||
// Erases all elements that match predicate. It has O(size) complexity.
|
||||
//
|
||||
// flat_set<int> numbers;
|
||||
// ...
|
||||
// EraseIf(numbers, [](int number) { return number % 2 == 1; });
|
||||
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls)
|
||||
using ::webrtc::flat_containers_internal::EraseIf;
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_CONTAINERS_FLAT_SET_H_
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
// This implementation is borrowed from Chromium.
|
||||
|
||||
#include "rtc_base/containers/flat_tree.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
sorted_unique_t sorted_unique;
|
||||
|
||||
} // namespace webrtc
|
||||
1099
TMessagesProj/jni/voip/webrtc/rtc_base/containers/flat_tree.h
Normal file
1099
TMessagesProj/jni/voip/webrtc/rtc_base/containers/flat_tree.h
Normal file
File diff suppressed because it is too large
Load diff
36
TMessagesProj/jni/voip/webrtc/rtc_base/containers/identity.h
Normal file
36
TMessagesProj/jni/voip/webrtc/rtc_base/containers/identity.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
// This implementation is borrowed from Chromium.
|
||||
|
||||
#ifndef RTC_BASE_CONTAINERS_IDENTITY_H_
|
||||
#define RTC_BASE_CONTAINERS_IDENTITY_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Implementation of C++20's std::identity.
|
||||
//
|
||||
// Reference:
|
||||
// - https://en.cppreference.com/w/cpp/utility/functional/identity
|
||||
// - https://wg21.link/func.identity
|
||||
struct identity {
|
||||
template <typename T>
|
||||
constexpr T&& operator()(T&& t) const noexcept {
|
||||
return std::forward<T>(t);
|
||||
}
|
||||
|
||||
using is_transparent = void;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_CONTAINERS_IDENTITY_H_
|
||||
162
TMessagesProj/jni/voip/webrtc/rtc_base/containers/invoke.h
Normal file
162
TMessagesProj/jni/voip/webrtc/rtc_base/containers/invoke.h
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
// This implementation is borrowed from Chromium.
|
||||
|
||||
#ifndef RTC_BASE_CONTAINERS_INVOKE_H_
|
||||
#define RTC_BASE_CONTAINERS_INVOKE_H_
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace invoke_internal {
|
||||
|
||||
// Helper struct and alias to deduce the class type from a member function
|
||||
// pointer or member object pointer.
|
||||
template <typename DecayedF>
|
||||
struct member_pointer_class {};
|
||||
|
||||
template <typename ReturnT, typename ClassT>
|
||||
struct member_pointer_class<ReturnT ClassT::*> {
|
||||
using type = ClassT;
|
||||
};
|
||||
|
||||
template <typename DecayedF>
|
||||
using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
|
||||
|
||||
// Utility struct to detect specializations of std::reference_wrapper.
|
||||
template <typename T>
|
||||
struct is_reference_wrapper : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||
|
||||
// Small helpers used below in invoke_internal::invoke to make the SFINAE more
|
||||
// concise.
|
||||
template <typename F>
|
||||
const bool& IsMemFunPtr =
|
||||
std::is_member_function_pointer<std::decay_t<F>>::value;
|
||||
|
||||
template <typename F>
|
||||
const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
|
||||
|
||||
template <typename F,
|
||||
typename T,
|
||||
typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
|
||||
const bool& IsMemPtrToBaseOf =
|
||||
std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
|
||||
|
||||
template <typename T>
|
||||
const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
|
||||
|
||||
template <bool B>
|
||||
using EnableIf = std::enable_if_t<B, bool>;
|
||||
|
||||
// Invokes a member function pointer on a reference to an object of a suitable
|
||||
// type. Covers bullet 1 of the INVOKE definition.
|
||||
//
|
||||
// Reference: https://wg21.link/func.require#1.1
|
||||
template <typename F,
|
||||
typename T1,
|
||||
typename... Args,
|
||||
EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
|
||||
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
|
||||
return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Invokes a member function pointer on a std::reference_wrapper to an object of
|
||||
// a suitable type. Covers bullet 2 of the INVOKE definition.
|
||||
//
|
||||
// Reference: https://wg21.link/func.require#1.2
|
||||
template <typename F,
|
||||
typename T1,
|
||||
typename... Args,
|
||||
EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
|
||||
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
|
||||
return (t1.get().*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Invokes a member function pointer on a pointer-like type to an object of a
|
||||
// suitable type. Covers bullet 3 of the INVOKE definition.
|
||||
//
|
||||
// Reference: https://wg21.link/func.require#1.3
|
||||
template <typename F,
|
||||
typename T1,
|
||||
typename... Args,
|
||||
EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
|
||||
!IsRefWrapper<T1>> = true>
|
||||
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
|
||||
return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Invokes a member object pointer on a reference to an object of a suitable
|
||||
// type. Covers bullet 4 of the INVOKE definition.
|
||||
//
|
||||
// Reference: https://wg21.link/func.require#1.4
|
||||
template <typename F,
|
||||
typename T1,
|
||||
EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
|
||||
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
|
||||
return std::forward<T1>(t1).*f;
|
||||
}
|
||||
|
||||
// Invokes a member object pointer on a std::reference_wrapper to an object of
|
||||
// a suitable type. Covers bullet 5 of the INVOKE definition.
|
||||
//
|
||||
// Reference: https://wg21.link/func.require#1.5
|
||||
template <typename F,
|
||||
typename T1,
|
||||
EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
|
||||
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
|
||||
return t1.get().*f;
|
||||
}
|
||||
|
||||
// Invokes a member object pointer on a pointer-like type to an object of a
|
||||
// suitable type. Covers bullet 6 of the INVOKE definition.
|
||||
//
|
||||
// Reference: https://wg21.link/func.require#1.6
|
||||
template <typename F,
|
||||
typename T1,
|
||||
EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
|
||||
!IsRefWrapper<T1>> = true>
|
||||
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
|
||||
return (*std::forward<T1>(t1)).*f;
|
||||
}
|
||||
|
||||
// Invokes a regular function or function object. Covers bullet 7 of the INVOKE
|
||||
// definition.
|
||||
//
|
||||
// Reference: https://wg21.link/func.require#1.7
|
||||
template <typename F, typename... Args>
|
||||
constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
|
||||
return std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace invoke_internal
|
||||
|
||||
// Implementation of C++17's std::invoke. This is not based on implementation
|
||||
// referenced in original std::invoke proposal, but rather a manual
|
||||
// implementation, so that it can be constexpr.
|
||||
//
|
||||
// References:
|
||||
// - https://wg21.link/n4169#implementability
|
||||
// - https://en.cppreference.com/w/cpp/utility/functional/invoke
|
||||
// - https://wg21.link/func.invoke
|
||||
template <typename F, typename... Args>
|
||||
constexpr decltype(auto) invoke(F&& f, Args&&... args) {
|
||||
return invoke_internal::InvokeImpl(std::forward<F>(f),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_CONTAINERS_INVOKE_H_
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
// This implementation is borrowed from Chromium.
|
||||
|
||||
#ifndef RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_
|
||||
#define RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// A move-only class that holds an integer. This is designed for testing
|
||||
// containers. See also CopyOnlyInt.
|
||||
class MoveOnlyInt {
|
||||
public:
|
||||
explicit MoveOnlyInt(int data = 1) : data_(data) {}
|
||||
MoveOnlyInt(const MoveOnlyInt& other) = delete;
|
||||
MoveOnlyInt& operator=(const MoveOnlyInt& other) = delete;
|
||||
MoveOnlyInt(MoveOnlyInt&& other) : data_(other.data_) { other.data_ = 0; }
|
||||
~MoveOnlyInt() { data_ = 0; }
|
||||
|
||||
MoveOnlyInt& operator=(MoveOnlyInt&& other) {
|
||||
data_ = other.data_;
|
||||
other.data_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator==(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
|
||||
return lhs.data_ == rhs.data_;
|
||||
}
|
||||
|
||||
friend bool operator!=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
friend bool operator<(const MoveOnlyInt& lhs, int rhs) {
|
||||
return lhs.data_ < rhs;
|
||||
}
|
||||
|
||||
friend bool operator<(int lhs, const MoveOnlyInt& rhs) {
|
||||
return lhs < rhs.data_;
|
||||
}
|
||||
|
||||
friend bool operator<(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
|
||||
return lhs.data_ < rhs.data_;
|
||||
}
|
||||
|
||||
friend bool operator>(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
friend bool operator<=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
friend bool operator>=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
int data() const { return data_; }
|
||||
|
||||
private:
|
||||
volatile int data_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_
|
||||
127
TMessagesProj/jni/voip/webrtc/rtc_base/copy_on_write_buffer.cc
Normal file
127
TMessagesProj/jni/voip/webrtc/rtc_base/copy_on_write_buffer.cc
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/copy_on_write_buffer.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
CopyOnWriteBuffer::CopyOnWriteBuffer() : offset_(0), size_(0) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
CopyOnWriteBuffer::CopyOnWriteBuffer(const CopyOnWriteBuffer& buf)
|
||||
: buffer_(buf.buffer_), offset_(buf.offset_), size_(buf.size_) {}
|
||||
|
||||
CopyOnWriteBuffer::CopyOnWriteBuffer(CopyOnWriteBuffer&& buf) noexcept
|
||||
: buffer_(std::move(buf.buffer_)), offset_(buf.offset_), size_(buf.size_) {
|
||||
buf.offset_ = 0;
|
||||
buf.size_ = 0;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
CopyOnWriteBuffer::CopyOnWriteBuffer(absl::string_view s)
|
||||
: CopyOnWriteBuffer(s.data(), s.length()) {}
|
||||
|
||||
CopyOnWriteBuffer::CopyOnWriteBuffer(size_t size)
|
||||
: buffer_(size > 0 ? new RefCountedBuffer(size) : nullptr),
|
||||
offset_(0),
|
||||
size_(size) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
CopyOnWriteBuffer::CopyOnWriteBuffer(size_t size, size_t capacity)
|
||||
: buffer_(size > 0 || capacity > 0 ? new RefCountedBuffer(size, capacity)
|
||||
: nullptr),
|
||||
offset_(0),
|
||||
size_(size) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
CopyOnWriteBuffer::~CopyOnWriteBuffer() = default;
|
||||
|
||||
bool CopyOnWriteBuffer::operator==(const CopyOnWriteBuffer& buf) const {
|
||||
// Must either be the same view of the same buffer or have the same contents.
|
||||
RTC_DCHECK(IsConsistent());
|
||||
RTC_DCHECK(buf.IsConsistent());
|
||||
return size_ == buf.size_ &&
|
||||
(cdata() == buf.cdata() || memcmp(cdata(), buf.cdata(), size_) == 0);
|
||||
}
|
||||
|
||||
void CopyOnWriteBuffer::SetSize(size_t size) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
if (!buffer_) {
|
||||
if (size > 0) {
|
||||
buffer_ = new RefCountedBuffer(size);
|
||||
offset_ = 0;
|
||||
size_ = size;
|
||||
}
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return;
|
||||
}
|
||||
|
||||
if (size <= size_) {
|
||||
size_ = size;
|
||||
return;
|
||||
}
|
||||
|
||||
UnshareAndEnsureCapacity(std::max(capacity(), size));
|
||||
buffer_->SetSize(size + offset_);
|
||||
size_ = size;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
void CopyOnWriteBuffer::EnsureCapacity(size_t new_capacity) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
if (!buffer_) {
|
||||
if (new_capacity > 0) {
|
||||
buffer_ = new RefCountedBuffer(0, new_capacity);
|
||||
offset_ = 0;
|
||||
size_ = 0;
|
||||
}
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return;
|
||||
} else if (new_capacity <= capacity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UnshareAndEnsureCapacity(new_capacity);
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
void CopyOnWriteBuffer::Clear() {
|
||||
if (!buffer_)
|
||||
return;
|
||||
|
||||
if (buffer_->HasOneRef()) {
|
||||
buffer_->Clear();
|
||||
} else {
|
||||
buffer_ = new RefCountedBuffer(0, capacity());
|
||||
}
|
||||
offset_ = 0;
|
||||
size_ = 0;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
void CopyOnWriteBuffer::UnshareAndEnsureCapacity(size_t new_capacity) {
|
||||
if (buffer_->HasOneRef() && new_capacity <= capacity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_ =
|
||||
new RefCountedBuffer(buffer_->data() + offset_, size_, new_capacity);
|
||||
offset_ = 0;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
318
TMessagesProj/jni/voip/webrtc/rtc_base/copy_on_write_buffer.h
Normal file
318
TMessagesProj/jni/voip/webrtc/rtc_base/copy_on_write_buffer.h
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* 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_COPY_ON_WRITE_BUFFER_H_
|
||||
#define RTC_BASE_COPY_ON_WRITE_BUFFER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
#include "rtc_base/type_traits.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class RTC_EXPORT CopyOnWriteBuffer {
|
||||
public:
|
||||
// An empty buffer.
|
||||
CopyOnWriteBuffer();
|
||||
// Share the data with an existing buffer.
|
||||
CopyOnWriteBuffer(const CopyOnWriteBuffer& buf);
|
||||
// Move contents from an existing buffer.
|
||||
CopyOnWriteBuffer(CopyOnWriteBuffer&& buf) noexcept;
|
||||
|
||||
// Construct a buffer from a string, convenient for unittests.
|
||||
explicit CopyOnWriteBuffer(absl::string_view s);
|
||||
|
||||
// Construct a buffer with the specified number of uninitialized bytes.
|
||||
explicit CopyOnWriteBuffer(size_t size);
|
||||
CopyOnWriteBuffer(size_t size, size_t capacity);
|
||||
|
||||
// Construct a buffer and copy the specified number of bytes into it. The
|
||||
// source array may be (const) uint8_t*, int8_t*, or char*.
|
||||
template <typename T,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
CopyOnWriteBuffer(const T* data, size_t size)
|
||||
: CopyOnWriteBuffer(data, size, size) {}
|
||||
template <typename T,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
CopyOnWriteBuffer(const T* data, size_t size, size_t capacity)
|
||||
: CopyOnWriteBuffer(size, capacity) {
|
||||
if (buffer_) {
|
||||
std::memcpy(buffer_->data(), data, size);
|
||||
offset_ = 0;
|
||||
size_ = size;
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a buffer from the contents of an array.
|
||||
template <typename T,
|
||||
size_t N,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
CopyOnWriteBuffer(const T (&array)[N]) // NOLINT: runtime/explicit
|
||||
: CopyOnWriteBuffer(array, N) {}
|
||||
|
||||
// Construct a buffer from a vector like type.
|
||||
template <typename VecT,
|
||||
typename ElemT = typename std::remove_pointer_t<
|
||||
decltype(std::declval<VecT>().data())>,
|
||||
typename std::enable_if_t<
|
||||
!std::is_same<VecT, CopyOnWriteBuffer>::value &&
|
||||
HasDataAndSize<VecT, ElemT>::value &&
|
||||
internal::BufferCompat<uint8_t, ElemT>::value>* = nullptr>
|
||||
explicit CopyOnWriteBuffer(const VecT& v)
|
||||
: CopyOnWriteBuffer(v.data(), v.size()) {}
|
||||
|
||||
// Construct a buffer from a vector like type and a capacity argument
|
||||
template <typename VecT,
|
||||
typename ElemT = typename std::remove_pointer_t<
|
||||
decltype(std::declval<VecT>().data())>,
|
||||
typename std::enable_if_t<
|
||||
!std::is_same<VecT, CopyOnWriteBuffer>::value &&
|
||||
HasDataAndSize<VecT, ElemT>::value &&
|
||||
internal::BufferCompat<uint8_t, ElemT>::value>* = nullptr>
|
||||
explicit CopyOnWriteBuffer(const VecT& v, size_t capacity)
|
||||
: CopyOnWriteBuffer(v.data(), v.size(), capacity) {}
|
||||
|
||||
~CopyOnWriteBuffer();
|
||||
|
||||
// Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
|
||||
// but you may also use .data<int8_t>() and .data<char>().
|
||||
template <typename T = uint8_t,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
const T* data() const {
|
||||
return cdata<T>();
|
||||
}
|
||||
|
||||
// Get writable pointer to the data. This will create a copy of the underlying
|
||||
// data if it is shared with other buffers.
|
||||
template <typename T = uint8_t,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
T* MutableData() {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
if (!buffer_) {
|
||||
return nullptr;
|
||||
}
|
||||
UnshareAndEnsureCapacity(capacity());
|
||||
return buffer_->data<T>() + offset_;
|
||||
}
|
||||
|
||||
// Get const pointer to the data. This will not create a copy of the
|
||||
// underlying data if it is shared with other buffers.
|
||||
template <typename T = uint8_t,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
const T* cdata() const {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
if (!buffer_) {
|
||||
return nullptr;
|
||||
}
|
||||
return buffer_->data<T>() + offset_;
|
||||
}
|
||||
|
||||
bool empty() const { return size_ == 0; }
|
||||
|
||||
size_t size() const {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return size_;
|
||||
}
|
||||
|
||||
size_t capacity() const {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return buffer_ ? buffer_->capacity() - offset_ : 0;
|
||||
}
|
||||
|
||||
CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
RTC_DCHECK(buf.IsConsistent());
|
||||
if (&buf != this) {
|
||||
buffer_ = buf.buffer_;
|
||||
offset_ = buf.offset_;
|
||||
size_ = buf.size_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& buf) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
RTC_DCHECK(buf.IsConsistent());
|
||||
buffer_ = std::move(buf.buffer_);
|
||||
offset_ = buf.offset_;
|
||||
size_ = buf.size_;
|
||||
buf.offset_ = 0;
|
||||
buf.size_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const CopyOnWriteBuffer& buf) const;
|
||||
|
||||
bool operator!=(const CopyOnWriteBuffer& buf) const {
|
||||
return !(*this == buf);
|
||||
}
|
||||
|
||||
uint8_t operator[](size_t index) const {
|
||||
RTC_DCHECK_LT(index, size());
|
||||
return cdata()[index];
|
||||
}
|
||||
|
||||
// Replace the contents of the buffer. Accepts the same types as the
|
||||
// constructors.
|
||||
template <typename T,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
void SetData(const T* data, size_t size) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
if (!buffer_) {
|
||||
buffer_ = size > 0 ? new RefCountedBuffer(data, size) : nullptr;
|
||||
} else if (!buffer_->HasOneRef()) {
|
||||
buffer_ = new RefCountedBuffer(data, size, capacity());
|
||||
} else {
|
||||
buffer_->SetData(data, size);
|
||||
}
|
||||
offset_ = 0;
|
||||
size_ = size;
|
||||
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
size_t N,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
void SetData(const T (&array)[N]) {
|
||||
SetData(array, N);
|
||||
}
|
||||
|
||||
void SetData(const CopyOnWriteBuffer& buf) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
RTC_DCHECK(buf.IsConsistent());
|
||||
if (&buf != this) {
|
||||
buffer_ = buf.buffer_;
|
||||
offset_ = buf.offset_;
|
||||
size_ = buf.size_;
|
||||
}
|
||||
}
|
||||
|
||||
// Append data to the buffer. Accepts the same types as the constructors.
|
||||
template <typename T,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
void AppendData(const T* data, size_t size) {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
if (!buffer_) {
|
||||
buffer_ = new RefCountedBuffer(data, size);
|
||||
offset_ = 0;
|
||||
size_ = size;
|
||||
RTC_DCHECK(IsConsistent());
|
||||
return;
|
||||
}
|
||||
|
||||
UnshareAndEnsureCapacity(std::max(capacity(), size_ + size));
|
||||
|
||||
buffer_->SetSize(offset_ +
|
||||
size_); // Remove data to the right of the slice.
|
||||
buffer_->AppendData(data, size);
|
||||
size_ += size;
|
||||
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
size_t N,
|
||||
typename std::enable_if<
|
||||
internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
|
||||
void AppendData(const T (&array)[N]) {
|
||||
AppendData(array, N);
|
||||
}
|
||||
|
||||
template <typename VecT,
|
||||
typename ElemT = typename std::remove_pointer_t<
|
||||
decltype(std::declval<VecT>().data())>,
|
||||
typename std::enable_if_t<
|
||||
HasDataAndSize<VecT, ElemT>::value &&
|
||||
internal::BufferCompat<uint8_t, ElemT>::value>* = nullptr>
|
||||
void AppendData(const VecT& v) {
|
||||
AppendData(v.data(), v.size());
|
||||
}
|
||||
|
||||
// Sets the size of the buffer. If the new size is smaller than the old, the
|
||||
// buffer contents will be kept but truncated; if the new size is greater,
|
||||
// the existing contents will be kept and the new space will be
|
||||
// uninitialized.
|
||||
void SetSize(size_t size);
|
||||
|
||||
// Ensure that the buffer size can be increased to at least capacity without
|
||||
// further reallocation. (Of course, this operation might need to reallocate
|
||||
// the buffer.)
|
||||
void EnsureCapacity(size_t capacity);
|
||||
|
||||
// Resets the buffer to zero size without altering capacity. Works even if the
|
||||
// buffer has been moved from.
|
||||
void Clear();
|
||||
|
||||
// Swaps two buffers.
|
||||
friend void swap(CopyOnWriteBuffer& a, CopyOnWriteBuffer& b) {
|
||||
a.buffer_.swap(b.buffer_);
|
||||
std::swap(a.offset_, b.offset_);
|
||||
std::swap(a.size_, b.size_);
|
||||
}
|
||||
|
||||
CopyOnWriteBuffer Slice(size_t offset, size_t length) const {
|
||||
CopyOnWriteBuffer slice(*this);
|
||||
RTC_DCHECK_LE(offset, size_);
|
||||
RTC_DCHECK_LE(length + offset, size_);
|
||||
slice.offset_ += offset;
|
||||
slice.size_ = length;
|
||||
return slice;
|
||||
}
|
||||
|
||||
private:
|
||||
using RefCountedBuffer = FinalRefCountedObject<Buffer>;
|
||||
// Create a copy of the underlying data if it is referenced from other Buffer
|
||||
// objects or there is not enough capacity.
|
||||
void UnshareAndEnsureCapacity(size_t new_capacity);
|
||||
|
||||
// Pre- and postcondition of all methods.
|
||||
bool IsConsistent() const {
|
||||
if (buffer_) {
|
||||
return buffer_->capacity() > 0 && offset_ <= buffer_->size() &&
|
||||
offset_ + size_ <= buffer_->size();
|
||||
} else {
|
||||
return size_ == 0 && offset_ == 0;
|
||||
}
|
||||
}
|
||||
|
||||
// buffer_ is either null, or points to an rtc::Buffer with capacity > 0.
|
||||
scoped_refptr<RefCountedBuffer> buffer_;
|
||||
// This buffer may represent a slice of a original data.
|
||||
size_t offset_; // Offset of a current slice in the original data in buffer_.
|
||||
// Should be 0 if the buffer_ is empty.
|
||||
size_t size_; // Size of a current slice in the original data in buffer_.
|
||||
// Should be 0 if the buffer_ is empty.
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_COPY_ON_WRITE_BUFFER_H_
|
||||
145
TMessagesProj/jni/voip/webrtc/rtc_base/cpu_time.cc
Normal file
145
TMessagesProj/jni/voip/webrtc/rtc_base/cpu_time.cc
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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/cpu_time.h"
|
||||
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
#if defined(WEBRTC_LINUX)
|
||||
#include <time.h>
|
||||
#elif defined(WEBRTC_MAC)
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/mach_port.h>
|
||||
#include <mach/thread_act.h>
|
||||
#include <mach/thread_info.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(WEBRTC_WIN)
|
||||
#include <windows.h>
|
||||
#elif defined(WEBRTC_FUCHSIA)
|
||||
#include <lib/zx/process.h>
|
||||
#include <lib/zx/thread.h>
|
||||
#include <zircon/status.h>
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
namespace {
|
||||
// FILETIME resolution is 100 nanosecs.
|
||||
const int64_t kNanosecsPerFiletime = 100;
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
namespace rtc {
|
||||
|
||||
int64_t GetProcessCpuTimeNanos() {
|
||||
#if defined(WEBRTC_FUCHSIA)
|
||||
zx_info_task_runtime_t runtime_info;
|
||||
zx_status_t status =
|
||||
zx::process::self()->get_info(ZX_INFO_TASK_RUNTIME, &runtime_info,
|
||||
sizeof(runtime_info), nullptr, nullptr);
|
||||
if (status == ZX_OK) {
|
||||
return runtime_info.cpu_time;
|
||||
} else {
|
||||
RTC_LOG_ERR(LS_ERROR) << "get_info() failed: "
|
||||
<< zx_status_get_string(status);
|
||||
}
|
||||
#elif defined(WEBRTC_LINUX)
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) {
|
||||
return ts.tv_sec * kNumNanosecsPerSec + ts.tv_nsec;
|
||||
} else {
|
||||
RTC_LOG_ERR(LS_ERROR) << "clock_gettime() failed.";
|
||||
}
|
||||
#elif defined(WEBRTC_MAC)
|
||||
struct rusage rusage;
|
||||
if (getrusage(RUSAGE_SELF, &rusage) == 0) {
|
||||
return rusage.ru_utime.tv_sec * kNumNanosecsPerSec +
|
||||
rusage.ru_utime.tv_usec * kNumNanosecsPerMicrosec;
|
||||
} else {
|
||||
RTC_LOG_ERR(LS_ERROR) << "getrusage() failed.";
|
||||
}
|
||||
#elif defined(WEBRTC_WIN)
|
||||
FILETIME createTime;
|
||||
FILETIME exitTime;
|
||||
FILETIME kernelTime;
|
||||
FILETIME userTime;
|
||||
if (GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime,
|
||||
&userTime) != 0) {
|
||||
return ((static_cast<uint64_t>(userTime.dwHighDateTime) << 32) +
|
||||
userTime.dwLowDateTime) *
|
||||
kNanosecsPerFiletime;
|
||||
} else {
|
||||
RTC_LOG_ERR(LS_ERROR) << "GetProcessTimes() failed.";
|
||||
}
|
||||
#else
|
||||
// Not implemented yet.
|
||||
static_assert(
|
||||
false, "GetProcessCpuTimeNanos() platform support not yet implemented.");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t GetThreadCpuTimeNanos() {
|
||||
#if defined(WEBRTC_FUCHSIA)
|
||||
zx_info_task_runtime_t runtime_info;
|
||||
zx_status_t status =
|
||||
zx::thread::self()->get_info(ZX_INFO_TASK_RUNTIME, &runtime_info,
|
||||
sizeof(runtime_info), nullptr, nullptr);
|
||||
if (status == ZX_OK) {
|
||||
return runtime_info.cpu_time;
|
||||
} else {
|
||||
RTC_LOG_ERR(LS_ERROR) << "get_info() failed: "
|
||||
<< zx_status_get_string(status);
|
||||
}
|
||||
#elif defined(WEBRTC_LINUX)
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) {
|
||||
return ts.tv_sec * kNumNanosecsPerSec + ts.tv_nsec;
|
||||
} else {
|
||||
RTC_LOG_ERR(LS_ERROR) << "clock_gettime() failed.";
|
||||
}
|
||||
#elif defined(WEBRTC_MAC)
|
||||
mach_port_t thread_port = mach_thread_self();
|
||||
thread_basic_info_data_t info;
|
||||
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
||||
kern_return_t kr =
|
||||
thread_info(thread_port, THREAD_BASIC_INFO, (thread_info_t)&info, &count);
|
||||
mach_port_deallocate(mach_task_self(), thread_port);
|
||||
if (kr == KERN_SUCCESS) {
|
||||
return info.user_time.seconds * kNumNanosecsPerSec +
|
||||
info.user_time.microseconds * kNumNanosecsPerMicrosec;
|
||||
} else {
|
||||
RTC_LOG_ERR(LS_ERROR) << "thread_info() failed.";
|
||||
}
|
||||
#elif defined(WEBRTC_WIN)
|
||||
FILETIME createTime;
|
||||
FILETIME exitTime;
|
||||
FILETIME kernelTime;
|
||||
FILETIME userTime;
|
||||
if (GetThreadTimes(GetCurrentThread(), &createTime, &exitTime, &kernelTime,
|
||||
&userTime) != 0) {
|
||||
return ((static_cast<uint64_t>(userTime.dwHighDateTime) << 32) +
|
||||
userTime.dwLowDateTime) *
|
||||
kNanosecsPerFiletime;
|
||||
} else {
|
||||
RTC_LOG_ERR(LS_ERROR) << "GetThreadTimes() failed.";
|
||||
}
|
||||
#else
|
||||
// Not implemented yet.
|
||||
static_assert(
|
||||
false, "GetThreadCpuTimeNanos() platform support not yet implemented.");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
28
TMessagesProj/jni/voip/webrtc/rtc_base/cpu_time.h
Normal file
28
TMessagesProj/jni/voip/webrtc/rtc_base/cpu_time.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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_CPU_TIME_H_
|
||||
#define RTC_BASE_CPU_TIME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Returns total CPU time of a current process in nanoseconds.
|
||||
// Time base is unknown, therefore use only to calculate deltas.
|
||||
int64_t GetProcessCpuTimeNanos();
|
||||
|
||||
// Returns total CPU time of a current thread in nanoseconds.
|
||||
// Time base is unknown, therefore use only to calculate deltas.
|
||||
int64_t GetThreadCpuTimeNanos();
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_CPU_TIME_H_
|
||||
50
TMessagesProj/jni/voip/webrtc/rtc_base/crc32.cc
Normal file
50
TMessagesProj/jni/voip/webrtc/rtc_base/crc32.cc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2012 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "rtc_base/crc32.h"
|
||||
|
||||
#include "rtc_base/arraysize.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// This implementation is based on the sample implementation in RFC 1952.
|
||||
|
||||
// CRC32 polynomial, in reversed form.
|
||||
// See RFC 1952, or http://en.wikipedia.org/wiki/Cyclic_redundancy_check
|
||||
static const uint32_t kCrc32Polynomial = 0xEDB88320;
|
||||
|
||||
static uint32_t* LoadCrc32Table() {
|
||||
static uint32_t kCrc32Table[256];
|
||||
for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) {
|
||||
uint32_t c = i;
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
if (c & 1) {
|
||||
c = kCrc32Polynomial ^ (c >> 1);
|
||||
} else {
|
||||
c >>= 1;
|
||||
}
|
||||
}
|
||||
kCrc32Table[i] = c;
|
||||
}
|
||||
return kCrc32Table;
|
||||
}
|
||||
|
||||
uint32_t UpdateCrc32(uint32_t start, const void* buf, size_t len) {
|
||||
static uint32_t* kCrc32Table = LoadCrc32Table();
|
||||
|
||||
uint32_t c = start ^ 0xFFFFFFFF;
|
||||
const uint8_t* u = static_cast<const uint8_t*>(buf);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8);
|
||||
}
|
||||
return c ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
37
TMessagesProj/jni/voip/webrtc/rtc_base/crc32.h
Normal file
37
TMessagesProj/jni/voip/webrtc/rtc_base/crc32.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 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 RTC_BASE_CRC32_H_
|
||||
#define RTC_BASE_CRC32_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Updates a CRC32 checksum with `len` bytes from `buf`. `initial` holds the
|
||||
// checksum result from the previous update; for the first call, it should be 0.
|
||||
uint32_t UpdateCrc32(uint32_t initial, const void* buf, size_t len);
|
||||
|
||||
// Computes a CRC32 checksum using `len` bytes from `buf`.
|
||||
inline uint32_t ComputeCrc32(const void* buf, size_t len) {
|
||||
return UpdateCrc32(0, buf, len);
|
||||
}
|
||||
inline uint32_t ComputeCrc32(absl::string_view str) {
|
||||
return ComputeCrc32(str.data(), str.size());
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_CRC32_H_
|
||||
46
TMessagesProj/jni/voip/webrtc/rtc_base/crypt_string.cc
Normal file
46
TMessagesProj/jni/voip/webrtc/rtc_base/crypt_string.cc
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/crypt_string.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
size_t EmptyCryptStringImpl::GetLength() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EmptyCryptStringImpl::CopyTo(char* dest, bool nullterminate) const {
|
||||
if (nullterminate) {
|
||||
*dest = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
std::string EmptyCryptStringImpl::UrlEncode() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
CryptStringImpl* EmptyCryptStringImpl::Copy() const {
|
||||
return new EmptyCryptStringImpl();
|
||||
}
|
||||
|
||||
void EmptyCryptStringImpl::CopyRawTo(std::vector<unsigned char>* dest) const {
|
||||
dest->clear();
|
||||
}
|
||||
|
||||
CryptString::CryptString() : impl_(new EmptyCryptStringImpl()) {}
|
||||
|
||||
CryptString::CryptString(const CryptString& other)
|
||||
: impl_(other.impl_->Copy()) {}
|
||||
|
||||
CryptString::CryptString(const CryptStringImpl& impl) : impl_(impl.Copy()) {}
|
||||
|
||||
CryptString::~CryptString() = default;
|
||||
|
||||
} // namespace rtc
|
||||
70
TMessagesProj/jni/voip/webrtc/rtc_base/crypt_string.h
Normal file
70
TMessagesProj/jni/voip/webrtc/rtc_base/crypt_string.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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_CRYPT_STRING_H_
|
||||
#define RTC_BASE_CRYPT_STRING_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class CryptStringImpl {
|
||||
public:
|
||||
virtual ~CryptStringImpl() {}
|
||||
virtual size_t GetLength() const = 0;
|
||||
virtual void CopyTo(char* dest, bool nullterminate) const = 0;
|
||||
virtual std::string UrlEncode() const = 0;
|
||||
virtual CryptStringImpl* Copy() const = 0;
|
||||
virtual void CopyRawTo(std::vector<unsigned char>* dest) const = 0;
|
||||
};
|
||||
|
||||
class EmptyCryptStringImpl : public CryptStringImpl {
|
||||
public:
|
||||
~EmptyCryptStringImpl() override {}
|
||||
size_t GetLength() const override;
|
||||
void CopyTo(char* dest, bool nullterminate) const override;
|
||||
std::string UrlEncode() const override;
|
||||
CryptStringImpl* Copy() const override;
|
||||
void CopyRawTo(std::vector<unsigned char>* dest) const override;
|
||||
};
|
||||
|
||||
class CryptString {
|
||||
public:
|
||||
CryptString();
|
||||
size_t GetLength() const { return impl_->GetLength(); }
|
||||
void CopyTo(char* dest, bool nullterminate) const {
|
||||
impl_->CopyTo(dest, nullterminate);
|
||||
}
|
||||
CryptString(const CryptString& other);
|
||||
explicit CryptString(const CryptStringImpl& impl);
|
||||
~CryptString();
|
||||
CryptString& operator=(const CryptString& other) {
|
||||
if (this != &other) {
|
||||
impl_.reset(other.impl_->Copy());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void Clear() { impl_.reset(new EmptyCryptStringImpl()); }
|
||||
std::string UrlEncode() const { return impl_->UrlEncode(); }
|
||||
void CopyRawTo(std::vector<unsigned char>* dest) const {
|
||||
return impl_->CopyRawTo(dest);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<const CryptStringImpl> impl_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_CRYPT_STRING_H_
|
||||
29
TMessagesProj/jni/voip/webrtc/rtc_base/data_rate_limiter.cc
Normal file
29
TMessagesProj/jni/voip/webrtc/rtc_base/data_rate_limiter.cc
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2012 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "rtc_base/data_rate_limiter.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
bool DataRateLimiter::CanUse(size_t desired, double time) {
|
||||
return ((time > period_end_ && desired <= max_per_period_) ||
|
||||
(used_in_period_ + desired) <= max_per_period_);
|
||||
}
|
||||
|
||||
void DataRateLimiter::Use(size_t used, double time) {
|
||||
if (time > period_end_) {
|
||||
period_start_ = time;
|
||||
period_end_ = time + period_length_;
|
||||
used_in_period_ = 0;
|
||||
}
|
||||
used_in_period_ += used;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
58
TMessagesProj/jni/voip/webrtc/rtc_base/data_rate_limiter.h
Normal file
58
TMessagesProj/jni/voip/webrtc/rtc_base/data_rate_limiter.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 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 RTC_BASE_DATA_RATE_LIMITER_H_
|
||||
#define RTC_BASE_DATA_RATE_LIMITER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Limits the rate of use to a certain maximum quantity per period of
|
||||
// time. Use, for example, for simple bandwidth throttling.
|
||||
//
|
||||
// It's implemented like a diet plan: You have so many calories per
|
||||
// day. If you hit the limit, you can't eat any more until the next
|
||||
// day.
|
||||
class RTC_EXPORT DataRateLimiter {
|
||||
public:
|
||||
// For example, 100kb per second.
|
||||
DataRateLimiter(size_t max, double period)
|
||||
: max_per_period_(max),
|
||||
period_length_(period),
|
||||
used_in_period_(0),
|
||||
period_start_(0.0),
|
||||
period_end_(period) {}
|
||||
virtual ~DataRateLimiter() {}
|
||||
|
||||
// Returns true if if the desired quantity is available in the
|
||||
// current period (< (max - used)). Once the given time passes the
|
||||
// end of the period, used is set to zero and more use is available.
|
||||
bool CanUse(size_t desired, double time);
|
||||
// Increment the quantity used this period. If past the end of a
|
||||
// period, a new period is started.
|
||||
void Use(size_t used, double time);
|
||||
|
||||
size_t used_in_period() const { return used_in_period_; }
|
||||
|
||||
size_t max_per_period() const { return max_per_period_; }
|
||||
|
||||
private:
|
||||
size_t max_per_period_;
|
||||
double period_length_;
|
||||
size_t used_in_period_;
|
||||
double period_start_;
|
||||
double period_end_;
|
||||
};
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_DATA_RATE_LIMITER_H_
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/deprecated/recursive_critical_section.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/platform_thread_types.h"
|
||||
#include "rtc_base/synchronization/yield.h"
|
||||
#include "rtc_base/system/unused.h"
|
||||
|
||||
#if RTC_DCHECK_IS_ON
|
||||
#define RTC_CS_DEBUG_CODE(x) x
|
||||
#else // !RTC_DCHECK_IS_ON
|
||||
#define RTC_CS_DEBUG_CODE(x)
|
||||
#endif // !RTC_DCHECK_IS_ON
|
||||
|
||||
namespace rtc {
|
||||
|
||||
RecursiveCriticalSection::RecursiveCriticalSection() {
|
||||
#if defined(WEBRTC_WIN)
|
||||
InitializeCriticalSection(&crit_);
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
|
||||
lock_queue_ = 0;
|
||||
owning_thread_ = 0;
|
||||
recursion_ = 0;
|
||||
semaphore_ = dispatch_semaphore_create(0);
|
||||
#else
|
||||
pthread_mutexattr_t mutex_attribute;
|
||||
pthread_mutexattr_init(&mutex_attribute);
|
||||
pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
|
||||
#if defined(WEBRTC_MAC)
|
||||
pthread_mutexattr_setpolicy_np(&mutex_attribute,
|
||||
_PTHREAD_MUTEX_POLICY_FIRSTFIT);
|
||||
#endif
|
||||
pthread_mutex_init(&mutex_, &mutex_attribute);
|
||||
pthread_mutexattr_destroy(&mutex_attribute);
|
||||
#endif
|
||||
RTC_CS_DEBUG_CODE(thread_ = 0);
|
||||
RTC_CS_DEBUG_CODE(recursion_count_ = 0);
|
||||
RTC_UNUSED(thread_);
|
||||
RTC_UNUSED(recursion_count_);
|
||||
#else
|
||||
#error Unsupported platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
RecursiveCriticalSection::~RecursiveCriticalSection() {
|
||||
#if defined(WEBRTC_WIN)
|
||||
DeleteCriticalSection(&crit_);
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
|
||||
dispatch_release(semaphore_);
|
||||
#else
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
void RecursiveCriticalSection::Enter() const RTC_EXCLUSIVE_LOCK_FUNCTION() {
|
||||
#if defined(WEBRTC_WIN)
|
||||
EnterCriticalSection(&crit_);
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
|
||||
int spin = 3000;
|
||||
PlatformThreadRef self = CurrentThreadRef();
|
||||
bool have_lock = false;
|
||||
do {
|
||||
// Instead of calling TryEnter() in this loop, we do two interlocked
|
||||
// operations, first a read-only one in order to avoid affecting the lock
|
||||
// cache-line while spinning, in case another thread is using the lock.
|
||||
if (!IsThreadRefEqual(owning_thread_, self)) {
|
||||
if (AtomicOps::AcquireLoad(&lock_queue_) == 0) {
|
||||
if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) {
|
||||
have_lock = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AtomicOps::Increment(&lock_queue_);
|
||||
have_lock = true;
|
||||
break;
|
||||
}
|
||||
|
||||
sched_yield();
|
||||
} while (--spin);
|
||||
|
||||
if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) {
|
||||
// Owning thread cannot be the current thread since TryEnter() would
|
||||
// have succeeded.
|
||||
RTC_DCHECK(!IsThreadRefEqual(owning_thread_, self));
|
||||
// Wait for the lock to become available.
|
||||
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
|
||||
RTC_DCHECK(owning_thread_ == 0);
|
||||
RTC_DCHECK(!recursion_);
|
||||
}
|
||||
|
||||
owning_thread_ = self;
|
||||
++recursion_;
|
||||
|
||||
#else
|
||||
pthread_mutex_lock(&mutex_);
|
||||
#endif
|
||||
|
||||
#if RTC_DCHECK_IS_ON
|
||||
if (!recursion_count_) {
|
||||
RTC_DCHECK(!thread_);
|
||||
thread_ = CurrentThreadRef();
|
||||
} else {
|
||||
RTC_DCHECK(CurrentThreadIsOwner());
|
||||
}
|
||||
++recursion_count_;
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RecursiveCriticalSection::TryEnter() const
|
||||
RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
|
||||
#if defined(WEBRTC_WIN)
|
||||
return TryEnterCriticalSection(&crit_) != FALSE;
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
|
||||
if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) {
|
||||
if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0)
|
||||
return false;
|
||||
owning_thread_ = CurrentThreadRef();
|
||||
RTC_DCHECK(!recursion_);
|
||||
} else {
|
||||
AtomicOps::Increment(&lock_queue_);
|
||||
}
|
||||
++recursion_;
|
||||
#else
|
||||
if (pthread_mutex_trylock(&mutex_) != 0)
|
||||
return false;
|
||||
#endif
|
||||
#if RTC_DCHECK_IS_ON
|
||||
if (!recursion_count_) {
|
||||
RTC_DCHECK(!thread_);
|
||||
thread_ = CurrentThreadRef();
|
||||
} else {
|
||||
RTC_DCHECK(CurrentThreadIsOwner());
|
||||
}
|
||||
++recursion_count_;
|
||||
#endif
|
||||
return true;
|
||||
#else
|
||||
#error Unsupported platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
void RecursiveCriticalSection::Leave() const RTC_UNLOCK_FUNCTION() {
|
||||
RTC_DCHECK(CurrentThreadIsOwner());
|
||||
#if defined(WEBRTC_WIN)
|
||||
LeaveCriticalSection(&crit_);
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#if RTC_DCHECK_IS_ON
|
||||
--recursion_count_;
|
||||
RTC_DCHECK(recursion_count_ >= 0);
|
||||
if (!recursion_count_)
|
||||
thread_ = 0;
|
||||
#endif
|
||||
#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
|
||||
RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef()));
|
||||
RTC_DCHECK_GE(recursion_, 0);
|
||||
--recursion_;
|
||||
if (!recursion_)
|
||||
owning_thread_ = 0;
|
||||
|
||||
if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_)
|
||||
dispatch_semaphore_signal(semaphore_);
|
||||
#else
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RecursiveCriticalSection::CurrentThreadIsOwner() const {
|
||||
#if defined(WEBRTC_WIN)
|
||||
// OwningThread has type HANDLE but actually contains the Thread ID:
|
||||
// http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-of-critical-section-of-type-handle-when-it-is-de
|
||||
// Converting through size_t avoids the VS 2015 warning C4312: conversion from
|
||||
// 'type1' to 'type2' of greater size
|
||||
return crit_.OwningThread ==
|
||||
reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId()));
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#if RTC_DCHECK_IS_ON
|
||||
return IsThreadRefEqual(thread_, CurrentThreadRef());
|
||||
#else
|
||||
return true;
|
||||
#endif // RTC_DCHECK_IS_ON
|
||||
#else
|
||||
#error Unsupported platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
CritScope::CritScope(const RecursiveCriticalSection* cs) : cs_(cs) {
|
||||
cs_->Enter();
|
||||
}
|
||||
CritScope::~CritScope() {
|
||||
cs_->Leave();
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_
|
||||
#define RTC_BASE_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "rtc_base/platform_thread_types.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
// clang-format off
|
||||
// clang formating would change include order.
|
||||
|
||||
// Include winsock2.h before including <windows.h> to maintain consistency with
|
||||
// win32.h. To include win32.h directly, it must be broken out into its own
|
||||
// build target.
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <sal.h> // must come after windows headers.
|
||||
// clang-format on
|
||||
#endif // defined(WEBRTC_WIN)
|
||||
|
||||
#if defined(WEBRTC_POSIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
// See notes in the 'Performance' unit test for the effects of this flag.
|
||||
#define RTC_USE_NATIVE_MUTEX_ON_MAC 1
|
||||
|
||||
#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
|
||||
#include <dispatch/dispatch.h>
|
||||
#endif
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// NOTE: This class is deprecated. Please use webrtc::Mutex instead!
|
||||
// Search using https://www.google.com/?q=recursive+lock+considered+harmful
|
||||
// to find the reasons.
|
||||
//
|
||||
// Locking methods (Enter, TryEnter, Leave)are const to permit protecting
|
||||
// members inside a const context without requiring mutable
|
||||
// RecursiveCriticalSections everywhere. RecursiveCriticalSection is
|
||||
// reentrant lock.
|
||||
class RTC_LOCKABLE RecursiveCriticalSection {
|
||||
public:
|
||||
RecursiveCriticalSection();
|
||||
~RecursiveCriticalSection();
|
||||
|
||||
void Enter() const RTC_EXCLUSIVE_LOCK_FUNCTION();
|
||||
bool TryEnter() const RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true);
|
||||
void Leave() const RTC_UNLOCK_FUNCTION();
|
||||
|
||||
private:
|
||||
// Use only for RTC_DCHECKing.
|
||||
bool CurrentThreadIsOwner() const;
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
mutable CRITICAL_SECTION crit_;
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
|
||||
// Number of times the lock has been locked + number of threads waiting.
|
||||
// TODO(tommi): We could use this number and subtract the recursion count
|
||||
// to find places where we have multiple threads contending on the same lock.
|
||||
mutable std::atomic<int> lock_queue_;
|
||||
// `recursion_` represents the recursion count + 1 for the thread that owns
|
||||
// the lock. Only modified by the thread that owns the lock.
|
||||
mutable int recursion_;
|
||||
// Used to signal a single waiting thread when the lock becomes available.
|
||||
mutable dispatch_semaphore_t semaphore_;
|
||||
// The thread that currently holds the lock. Required to handle recursion.
|
||||
mutable PlatformThreadRef owning_thread_;
|
||||
#else
|
||||
mutable pthread_mutex_t mutex_;
|
||||
#endif
|
||||
mutable PlatformThreadRef thread_; // Only used by RTC_DCHECKs.
|
||||
mutable int recursion_count_; // Only used by RTC_DCHECKs.
|
||||
#else // !defined(WEBRTC_WIN) && !defined(WEBRTC_POSIX)
|
||||
#error Unsupported platform.
|
||||
#endif
|
||||
};
|
||||
|
||||
// CritScope, for serializing execution through a scope.
|
||||
class RTC_SCOPED_LOCKABLE CritScope {
|
||||
public:
|
||||
explicit CritScope(const RecursiveCriticalSection* cs)
|
||||
RTC_EXCLUSIVE_LOCK_FUNCTION(cs);
|
||||
~CritScope() RTC_UNLOCK_FUNCTION();
|
||||
|
||||
CritScope(const CritScope&) = delete;
|
||||
CritScope& operator=(const CritScope&) = delete;
|
||||
|
||||
private:
|
||||
const RecursiveCriticalSection* const cs_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_
|
||||
45
TMessagesProj/jni/voip/webrtc/rtc_base/dscp.h
Normal file
45
TMessagesProj/jni/voip/webrtc/rtc_base/dscp.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 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_DSCP_H_
|
||||
#define RTC_BASE_DSCP_H_
|
||||
|
||||
namespace rtc {
|
||||
// Differentiated Services Code Point.
|
||||
// See http://tools.ietf.org/html/rfc2474 for details.
|
||||
enum DiffServCodePoint {
|
||||
DSCP_NO_CHANGE = -1,
|
||||
DSCP_DEFAULT = 0, // Same as DSCP_CS0
|
||||
DSCP_CS0 = 0, // The default
|
||||
DSCP_CS1 = 8, // Bulk/background traffic
|
||||
DSCP_AF11 = 10,
|
||||
DSCP_AF12 = 12,
|
||||
DSCP_AF13 = 14,
|
||||
DSCP_CS2 = 16,
|
||||
DSCP_AF21 = 18,
|
||||
DSCP_AF22 = 20,
|
||||
DSCP_AF23 = 22,
|
||||
DSCP_CS3 = 24,
|
||||
DSCP_AF31 = 26,
|
||||
DSCP_AF32 = 28,
|
||||
DSCP_AF33 = 30,
|
||||
DSCP_CS4 = 32,
|
||||
DSCP_AF41 = 34, // Video
|
||||
DSCP_AF42 = 36, // Video
|
||||
DSCP_AF43 = 38, // Video
|
||||
DSCP_CS5 = 40, // Video
|
||||
DSCP_EF = 46, // Voice
|
||||
DSCP_CS6 = 48, // Voice
|
||||
DSCP_CS7 = 56, // Control messages
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_DSCP_H_
|
||||
210
TMessagesProj/jni/voip/webrtc/rtc_base/event.cc
Normal file
210
TMessagesProj/jni/voip/webrtc/rtc_base/event.cc
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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/event.h"
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
#include <windows.h>
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#else
|
||||
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
|
||||
#endif
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/synchronization/yield_policy.h"
|
||||
#include "rtc_base/system/warn_current_thread_is_deadlocked.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
using ::webrtc::TimeDelta;
|
||||
|
||||
Event::Event() : Event(false, false) {}
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
|
||||
Event::Event(bool manual_reset, bool initially_signaled) {
|
||||
event_handle_ = ::CreateEvent(nullptr, // Security attributes.
|
||||
manual_reset, initially_signaled,
|
||||
nullptr); // Name.
|
||||
RTC_CHECK(event_handle_);
|
||||
}
|
||||
|
||||
Event::~Event() {
|
||||
CloseHandle(event_handle_);
|
||||
}
|
||||
|
||||
void Event::Set() {
|
||||
SetEvent(event_handle_);
|
||||
}
|
||||
|
||||
void Event::Reset() {
|
||||
ResetEvent(event_handle_);
|
||||
}
|
||||
|
||||
bool Event::Wait(TimeDelta give_up_after, TimeDelta /*warn_after*/) {
|
||||
ScopedYieldPolicy::YieldExecution();
|
||||
const DWORD ms =
|
||||
give_up_after.IsPlusInfinity()
|
||||
? INFINITE
|
||||
: give_up_after.RoundUpTo(webrtc::TimeDelta::Millis(1)).ms();
|
||||
return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
|
||||
// On MacOS, clock_gettime is available from version 10.12, and on
|
||||
// iOS, from version 10.0. So we can't use it yet.
|
||||
#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
|
||||
#define USE_CLOCK_GETTIME 0
|
||||
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
|
||||
// On Android, pthread_condattr_setclock is available from version 21. By
|
||||
// default, we target a new enough version for 64-bit platforms but not for
|
||||
// 32-bit platforms. For older versions, use
|
||||
// pthread_cond_timedwait_monotonic_np.
|
||||
#elif defined(WEBRTC_ANDROID) && (__ANDROID_API__ < 21)
|
||||
#define USE_CLOCK_GETTIME 1
|
||||
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 1
|
||||
#else
|
||||
#define USE_CLOCK_GETTIME 1
|
||||
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
|
||||
#endif
|
||||
|
||||
Event::Event(bool manual_reset, bool initially_signaled)
|
||||
: is_manual_reset_(manual_reset), event_status_(initially_signaled) {
|
||||
RTC_CHECK(pthread_mutex_init(&event_mutex_, nullptr) == 0);
|
||||
pthread_condattr_t cond_attr;
|
||||
RTC_CHECK(pthread_condattr_init(&cond_attr) == 0);
|
||||
#if USE_CLOCK_GETTIME && !USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
|
||||
RTC_CHECK(pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC) == 0);
|
||||
#endif
|
||||
RTC_CHECK(pthread_cond_init(&event_cond_, &cond_attr) == 0);
|
||||
pthread_condattr_destroy(&cond_attr);
|
||||
}
|
||||
|
||||
Event::~Event() {
|
||||
pthread_mutex_destroy(&event_mutex_);
|
||||
pthread_cond_destroy(&event_cond_);
|
||||
}
|
||||
|
||||
void Event::Set() {
|
||||
pthread_mutex_lock(&event_mutex_);
|
||||
event_status_ = true;
|
||||
pthread_cond_broadcast(&event_cond_);
|
||||
pthread_mutex_unlock(&event_mutex_);
|
||||
}
|
||||
|
||||
void Event::Reset() {
|
||||
pthread_mutex_lock(&event_mutex_);
|
||||
event_status_ = false;
|
||||
pthread_mutex_unlock(&event_mutex_);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
timespec GetTimespec(TimeDelta duration_from_now) {
|
||||
timespec ts;
|
||||
|
||||
// Get the current time.
|
||||
#if USE_CLOCK_GETTIME
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * kNumNanosecsPerMicrosec;
|
||||
#endif
|
||||
|
||||
// Add the specified number of milliseconds to it.
|
||||
int64_t microsecs_from_now = duration_from_now.us();
|
||||
ts.tv_sec += microsecs_from_now / kNumMicrosecsPerSec;
|
||||
ts.tv_nsec +=
|
||||
(microsecs_from_now % kNumMicrosecsPerSec) * kNumNanosecsPerMicrosec;
|
||||
|
||||
// Normalize.
|
||||
if (ts.tv_nsec >= kNumNanosecsPerSec) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= kNumNanosecsPerSec;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Event::Wait(TimeDelta give_up_after, TimeDelta warn_after) {
|
||||
// Instant when we'll log a warning message (because we've been waiting so
|
||||
// long it might be a bug), but not yet give up waiting. nullopt if we
|
||||
// shouldn't log a warning.
|
||||
const absl::optional<timespec> warn_ts =
|
||||
warn_after >= give_up_after
|
||||
? absl::nullopt
|
||||
: absl::make_optional(GetTimespec(warn_after));
|
||||
|
||||
// Instant when we'll stop waiting and return an error. nullopt if we should
|
||||
// never give up.
|
||||
const absl::optional<timespec> give_up_ts =
|
||||
give_up_after.IsPlusInfinity()
|
||||
? absl::nullopt
|
||||
: absl::make_optional(GetTimespec(give_up_after));
|
||||
|
||||
ScopedYieldPolicy::YieldExecution();
|
||||
pthread_mutex_lock(&event_mutex_);
|
||||
|
||||
// Wait for `event_cond_` to trigger and `event_status_` to be set, with the
|
||||
// given timeout (or without a timeout if none is given).
|
||||
const auto wait = [&](const absl::optional<timespec> timeout_ts) {
|
||||
int error = 0;
|
||||
while (!event_status_ && error == 0) {
|
||||
if (timeout_ts == absl::nullopt) {
|
||||
error = pthread_cond_wait(&event_cond_, &event_mutex_);
|
||||
} else {
|
||||
#if USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
|
||||
error = pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_,
|
||||
&*timeout_ts);
|
||||
#else
|
||||
error =
|
||||
pthread_cond_timedwait(&event_cond_, &event_mutex_, &*timeout_ts);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
int error;
|
||||
if (warn_ts == absl::nullopt) {
|
||||
error = wait(give_up_ts);
|
||||
} else {
|
||||
error = wait(warn_ts);
|
||||
if (error == ETIMEDOUT) {
|
||||
webrtc::WarnThatTheCurrentThreadIsProbablyDeadlocked();
|
||||
error = wait(give_up_ts);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(liulk): Exactly one thread will auto-reset this event. All
|
||||
// the other threads will think it's unsignaled. This seems to be
|
||||
// consistent with auto-reset events in WEBRTC_WIN
|
||||
if (error == 0 && !is_manual_reset_)
|
||||
event_status_ = false;
|
||||
|
||||
pthread_mutex_unlock(&event_mutex_);
|
||||
|
||||
return (error == 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace rtc
|
||||
137
TMessagesProj/jni/voip/webrtc/rtc_base/event.h
Normal file
137
TMessagesProj/jni/voip/webrtc/rtc_base/event.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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_EVENT_H_
|
||||
#define RTC_BASE_EVENT_H_
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
#include <windows.h>
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
|
||||
#endif
|
||||
|
||||
#include "rtc_base/synchronization/yield_policy.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// RTC_DISALLOW_WAIT() utility
|
||||
//
|
||||
// Sets a stack-scoped flag that disallows use of `rtc::Event::Wait` by means
|
||||
// of raising a DCHECK when a call to `rtc::Event::Wait()` is made..
|
||||
// This is useful to guard synchronization-free scopes against regressions.
|
||||
//
|
||||
// Example of what this would catch (`ScopeToProtect` calls `Foo`):
|
||||
//
|
||||
// void Foo(TaskQueue* tq) {
|
||||
// Event event;
|
||||
// tq->PostTask([&event]() {
|
||||
// event.Set();
|
||||
// });
|
||||
// event.Wait(Event::kForever); // <- Will trigger a DCHECK.
|
||||
// }
|
||||
//
|
||||
// void ScopeToProtect() {
|
||||
// TaskQueue* tq = GetSomeTaskQueue();
|
||||
// RTC_DISALLOW_WAIT(); // Policy takes effect.
|
||||
// Foo(tq);
|
||||
// }
|
||||
//
|
||||
#if RTC_DCHECK_IS_ON
|
||||
#define RTC_DISALLOW_WAIT() ScopedDisallowWait disallow_wait_##__LINE__
|
||||
#else
|
||||
#define RTC_DISALLOW_WAIT()
|
||||
#endif
|
||||
|
||||
class Event {
|
||||
public:
|
||||
// TODO(bugs.webrtc.org/14366): Consider removing this redundant alias.
|
||||
static constexpr webrtc::TimeDelta kForever =
|
||||
webrtc::TimeDelta::PlusInfinity();
|
||||
|
||||
Event();
|
||||
Event(bool manual_reset, bool initially_signaled);
|
||||
Event(const Event&) = delete;
|
||||
Event& operator=(const Event&) = delete;
|
||||
~Event();
|
||||
|
||||
void Set();
|
||||
void Reset();
|
||||
|
||||
// Waits for the event to become signaled, but logs a warning if it takes more
|
||||
// than `warn_after`, and gives up completely if it takes more than
|
||||
// `give_up_after`. (If `warn_after >= give_up_after`, no warning will be
|
||||
// logged.) Either or both may be `kForever`, which means wait indefinitely.
|
||||
//
|
||||
// Care is taken so that the underlying OS wait call isn't requested to sleep
|
||||
// shorter than `give_up_after`.
|
||||
//
|
||||
// Returns true if the event was signaled, false if there was a timeout or
|
||||
// some other error.
|
||||
bool Wait(webrtc::TimeDelta give_up_after, webrtc::TimeDelta warn_after);
|
||||
|
||||
// Waits with the given timeout and a reasonable default warning timeout.
|
||||
bool Wait(webrtc::TimeDelta give_up_after) {
|
||||
return Wait(give_up_after, give_up_after.IsPlusInfinity()
|
||||
? webrtc::TimeDelta::Seconds(3)
|
||||
: kForever);
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(WEBRTC_WIN)
|
||||
HANDLE event_handle_;
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
pthread_mutex_t event_mutex_;
|
||||
pthread_cond_t event_cond_;
|
||||
const bool is_manual_reset_;
|
||||
bool event_status_;
|
||||
#endif
|
||||
};
|
||||
|
||||
// These classes are provided for compatibility with Chromium.
|
||||
// The rtc::Event implementation is overriden inside of Chromium for the
|
||||
// purposes of detecting when threads are blocked that shouldn't be as well as
|
||||
// to use the more accurate event implementation that's there than is provided
|
||||
// by default on some platforms (e.g. Windows).
|
||||
// When building with standalone WebRTC, this class is a noop.
|
||||
// For further information, please see the
|
||||
// ScopedAllowBaseSyncPrimitives(ForTesting) classes in Chromium.
|
||||
class ScopedAllowBaseSyncPrimitives {
|
||||
public:
|
||||
ScopedAllowBaseSyncPrimitives() {}
|
||||
~ScopedAllowBaseSyncPrimitives() {}
|
||||
};
|
||||
|
||||
class ScopedAllowBaseSyncPrimitivesForTesting {
|
||||
public:
|
||||
ScopedAllowBaseSyncPrimitivesForTesting() {}
|
||||
~ScopedAllowBaseSyncPrimitivesForTesting() {}
|
||||
};
|
||||
|
||||
#if RTC_DCHECK_IS_ON
|
||||
class ScopedDisallowWait {
|
||||
public:
|
||||
ScopedDisallowWait() = default;
|
||||
|
||||
private:
|
||||
class DisallowYieldHandler : public YieldInterface {
|
||||
public:
|
||||
void YieldExecution() override { RTC_DCHECK_NOTREACHED(); }
|
||||
} handler_;
|
||||
rtc::ScopedYieldPolicy policy{&handler_};
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_EVENT_H_
|
||||
412
TMessagesProj/jni/voip/webrtc/rtc_base/event_tracer.cc
Normal file
412
TMessagesProj/jni/voip/webrtc/rtc_base/event_tracer.cc
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include "rtc_base/event_tracer.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/sequence_checker.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/event.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/platform_thread.h"
|
||||
#include "rtc_base/platform_thread_types.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
#include "rtc_base/trace_event.h"
|
||||
|
||||
// This is a guesstimate that should be enough in most cases.
|
||||
static const size_t kEventLoggerArgsStrBufferInitialSize = 256;
|
||||
static const size_t kTraceArgBufferLength = 32;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr;
|
||||
AddTraceEventPtr g_add_trace_event_ptr = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
|
||||
AddTraceEventPtr add_trace_event_ptr) {
|
||||
g_get_category_enabled_ptr = get_category_enabled_ptr;
|
||||
g_add_trace_event_ptr = add_trace_event_ptr;
|
||||
}
|
||||
|
||||
const unsigned char* EventTracer::GetCategoryEnabled(const char* name) {
|
||||
if (g_get_category_enabled_ptr)
|
||||
return g_get_category_enabled_ptr(name);
|
||||
|
||||
// A string with null terminator means category is disabled.
|
||||
return reinterpret_cast<const unsigned char*>("\0");
|
||||
}
|
||||
|
||||
// Arguments to this function (phase, etc.) are as defined in
|
||||
// webrtc/rtc_base/trace_event.h.
|
||||
void EventTracer::AddTraceEvent(char phase,
|
||||
const unsigned char* category_enabled,
|
||||
const char* name,
|
||||
unsigned long long id,
|
||||
int num_args,
|
||||
const char** arg_names,
|
||||
const unsigned char* arg_types,
|
||||
const unsigned long long* arg_values,
|
||||
unsigned char flags) {
|
||||
if (g_add_trace_event_ptr) {
|
||||
g_add_trace_event_ptr(phase, category_enabled, name, id, num_args,
|
||||
arg_names, arg_types, arg_values, flags);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
namespace rtc {
|
||||
namespace tracing {
|
||||
namespace {
|
||||
|
||||
// Atomic-int fast path for avoiding logging when disabled.
|
||||
static std::atomic<int> g_event_logging_active(0);
|
||||
|
||||
// TODO(pbos): Log metadata for all threads, etc.
|
||||
class EventLogger final {
|
||||
public:
|
||||
~EventLogger() { RTC_DCHECK(thread_checker_.IsCurrent()); }
|
||||
|
||||
void AddTraceEvent(const char* name,
|
||||
const unsigned char* category_enabled,
|
||||
char phase,
|
||||
int num_args,
|
||||
const char** arg_names,
|
||||
const unsigned char* arg_types,
|
||||
const unsigned long long* arg_values,
|
||||
uint64_t timestamp,
|
||||
int pid,
|
||||
rtc::PlatformThreadId thread_id) {
|
||||
std::vector<TraceArg> args(num_args);
|
||||
for (int i = 0; i < num_args; ++i) {
|
||||
TraceArg& arg = args[i];
|
||||
arg.name = arg_names[i];
|
||||
arg.type = arg_types[i];
|
||||
arg.value.as_uint = arg_values[i];
|
||||
|
||||
// Value is a pointer to a temporary string, so we have to make a copy.
|
||||
if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
|
||||
// Space for the string and for the terminating null character.
|
||||
size_t str_length = strlen(arg.value.as_string) + 1;
|
||||
char* str_copy = new char[str_length];
|
||||
memcpy(str_copy, arg.value.as_string, str_length);
|
||||
arg.value.as_string = str_copy;
|
||||
}
|
||||
}
|
||||
webrtc::MutexLock lock(&mutex_);
|
||||
trace_events_.push_back(
|
||||
{name, category_enabled, phase, args, timestamp, 1, thread_id});
|
||||
}
|
||||
|
||||
// The TraceEvent format is documented here:
|
||||
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
|
||||
void Log() {
|
||||
RTC_DCHECK(output_file_);
|
||||
static constexpr webrtc::TimeDelta kLoggingInterval =
|
||||
webrtc::TimeDelta::Millis(100);
|
||||
fprintf(output_file_, "{ \"traceEvents\": [\n");
|
||||
bool has_logged_event = false;
|
||||
while (true) {
|
||||
bool shutting_down = shutdown_event_.Wait(kLoggingInterval);
|
||||
std::vector<TraceEvent> events;
|
||||
{
|
||||
webrtc::MutexLock lock(&mutex_);
|
||||
trace_events_.swap(events);
|
||||
}
|
||||
std::string args_str;
|
||||
args_str.reserve(kEventLoggerArgsStrBufferInitialSize);
|
||||
for (TraceEvent& e : events) {
|
||||
args_str.clear();
|
||||
if (!e.args.empty()) {
|
||||
args_str += ", \"args\": {";
|
||||
bool is_first_argument = true;
|
||||
for (TraceArg& arg : e.args) {
|
||||
if (!is_first_argument)
|
||||
args_str += ",";
|
||||
is_first_argument = false;
|
||||
args_str += " \"";
|
||||
args_str += arg.name;
|
||||
args_str += "\": ";
|
||||
args_str += TraceArgValueAsString(arg);
|
||||
|
||||
// Delete our copy of the string.
|
||||
if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
|
||||
delete[] arg.value.as_string;
|
||||
arg.value.as_string = nullptr;
|
||||
}
|
||||
}
|
||||
args_str += " }";
|
||||
}
|
||||
fprintf(output_file_,
|
||||
"%s{ \"name\": \"%s\""
|
||||
", \"cat\": \"%s\""
|
||||
", \"ph\": \"%c\""
|
||||
", \"ts\": %" PRIu64
|
||||
", \"pid\": %d"
|
||||
#if defined(WEBRTC_WIN)
|
||||
", \"tid\": %lu"
|
||||
#else
|
||||
", \"tid\": %d"
|
||||
#endif // defined(WEBRTC_WIN)
|
||||
"%s"
|
||||
"}\n",
|
||||
has_logged_event ? "," : " ", e.name, e.category_enabled,
|
||||
e.phase, e.timestamp, e.pid, e.tid, args_str.c_str());
|
||||
has_logged_event = true;
|
||||
}
|
||||
if (shutting_down)
|
||||
break;
|
||||
}
|
||||
fprintf(output_file_, "]}\n");
|
||||
if (output_file_owned_)
|
||||
fclose(output_file_);
|
||||
output_file_ = nullptr;
|
||||
}
|
||||
|
||||
void Start(FILE* file, bool owned) {
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
RTC_DCHECK(file);
|
||||
RTC_DCHECK(!output_file_);
|
||||
output_file_ = file;
|
||||
output_file_owned_ = owned;
|
||||
{
|
||||
webrtc::MutexLock lock(&mutex_);
|
||||
// Since the atomic fast-path for adding events to the queue can be
|
||||
// bypassed while the logging thread is shutting down there may be some
|
||||
// stale events in the queue, hence the vector needs to be cleared to not
|
||||
// log events from a previous logging session (which may be days old).
|
||||
trace_events_.clear();
|
||||
}
|
||||
// Enable event logging (fast-path). This should be disabled since starting
|
||||
// shouldn't be done twice.
|
||||
int zero = 0;
|
||||
RTC_CHECK(g_event_logging_active.compare_exchange_strong(zero, 1));
|
||||
|
||||
// Finally start, everything should be set up now.
|
||||
logging_thread_ =
|
||||
PlatformThread::SpawnJoinable([this] { Log(); }, "EventTracingThread");
|
||||
TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Start");
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Stop");
|
||||
// Try to stop. Abort if we're not currently logging.
|
||||
int one = 1;
|
||||
if (g_event_logging_active.compare_exchange_strong(one, 0))
|
||||
return;
|
||||
|
||||
// Wake up logging thread to finish writing.
|
||||
shutdown_event_.Set();
|
||||
// Join the logging thread.
|
||||
logging_thread_.Finalize();
|
||||
}
|
||||
|
||||
private:
|
||||
struct TraceArg {
|
||||
const char* name;
|
||||
unsigned char type;
|
||||
// Copied from webrtc/rtc_base/trace_event.h TraceValueUnion.
|
||||
union TraceArgValue {
|
||||
bool as_bool;
|
||||
unsigned long long as_uint;
|
||||
long long as_int;
|
||||
double as_double;
|
||||
const void* as_pointer;
|
||||
const char* as_string;
|
||||
} value;
|
||||
|
||||
// Assert that the size of the union is equal to the size of the as_uint
|
||||
// field since we are assigning to arbitrary types using it.
|
||||
static_assert(sizeof(TraceArgValue) == sizeof(unsigned long long),
|
||||
"Size of TraceArg value union is not equal to the size of "
|
||||
"the uint field of that union.");
|
||||
};
|
||||
|
||||
struct TraceEvent {
|
||||
const char* name;
|
||||
const unsigned char* category_enabled;
|
||||
char phase;
|
||||
std::vector<TraceArg> args;
|
||||
uint64_t timestamp;
|
||||
int pid;
|
||||
rtc::PlatformThreadId tid;
|
||||
};
|
||||
|
||||
static std::string TraceArgValueAsString(TraceArg arg) {
|
||||
std::string output;
|
||||
|
||||
if (arg.type == TRACE_VALUE_TYPE_STRING ||
|
||||
arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
|
||||
// Space for every character to be an espaced character + two for
|
||||
// quatation marks.
|
||||
output.reserve(strlen(arg.value.as_string) * 2 + 2);
|
||||
output += '\"';
|
||||
const char* c = arg.value.as_string;
|
||||
do {
|
||||
if (*c == '"' || *c == '\\') {
|
||||
output += '\\';
|
||||
output += *c;
|
||||
} else {
|
||||
output += *c;
|
||||
}
|
||||
} while (*++c);
|
||||
output += '\"';
|
||||
} else {
|
||||
output.resize(kTraceArgBufferLength);
|
||||
size_t print_length = 0;
|
||||
switch (arg.type) {
|
||||
case TRACE_VALUE_TYPE_BOOL:
|
||||
if (arg.value.as_bool) {
|
||||
strcpy(&output[0], "true");
|
||||
print_length = 4;
|
||||
} else {
|
||||
strcpy(&output[0], "false");
|
||||
print_length = 5;
|
||||
}
|
||||
break;
|
||||
case TRACE_VALUE_TYPE_UINT:
|
||||
print_length = snprintf(&output[0], kTraceArgBufferLength, "%llu",
|
||||
arg.value.as_uint);
|
||||
break;
|
||||
case TRACE_VALUE_TYPE_INT:
|
||||
print_length = snprintf(&output[0], kTraceArgBufferLength, "%lld",
|
||||
arg.value.as_int);
|
||||
break;
|
||||
case TRACE_VALUE_TYPE_DOUBLE:
|
||||
print_length = snprintf(&output[0], kTraceArgBufferLength, "%f",
|
||||
arg.value.as_double);
|
||||
break;
|
||||
case TRACE_VALUE_TYPE_POINTER:
|
||||
print_length = snprintf(&output[0], kTraceArgBufferLength, "\"%p\"",
|
||||
arg.value.as_pointer);
|
||||
break;
|
||||
}
|
||||
size_t output_length = print_length < kTraceArgBufferLength
|
||||
? print_length
|
||||
: kTraceArgBufferLength - 1;
|
||||
// This will hopefully be very close to nop. On most implementations, it
|
||||
// just writes null byte and sets the length field of the string.
|
||||
output.resize(output_length);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
webrtc::Mutex mutex_;
|
||||
std::vector<TraceEvent> trace_events_ RTC_GUARDED_BY(mutex_);
|
||||
rtc::PlatformThread logging_thread_;
|
||||
rtc::Event shutdown_event_;
|
||||
webrtc::SequenceChecker thread_checker_;
|
||||
FILE* output_file_ = nullptr;
|
||||
bool output_file_owned_ = false;
|
||||
};
|
||||
|
||||
static std::atomic<EventLogger*> g_event_logger(nullptr);
|
||||
static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT("");
|
||||
const unsigned char* InternalGetCategoryEnabled(const char* name) {
|
||||
const char* prefix_ptr = &kDisabledTracePrefix[0];
|
||||
const char* name_ptr = name;
|
||||
// Check whether name contains the default-disabled prefix.
|
||||
while (*prefix_ptr == *name_ptr && *prefix_ptr != '\0') {
|
||||
++prefix_ptr;
|
||||
++name_ptr;
|
||||
}
|
||||
return reinterpret_cast<const unsigned char*>(*prefix_ptr == '\0' ? ""
|
||||
: name);
|
||||
}
|
||||
|
||||
const unsigned char* InternalEnableAllCategories(const char* name) {
|
||||
return reinterpret_cast<const unsigned char*>(name);
|
||||
}
|
||||
|
||||
void InternalAddTraceEvent(char phase,
|
||||
const unsigned char* category_enabled,
|
||||
const char* name,
|
||||
unsigned long long id,
|
||||
int num_args,
|
||||
const char** arg_names,
|
||||
const unsigned char* arg_types,
|
||||
const unsigned long long* arg_values,
|
||||
unsigned char flags) {
|
||||
// Fast path for when event tracing is inactive.
|
||||
if (g_event_logging_active.load() == 0)
|
||||
return;
|
||||
|
||||
g_event_logger.load()->AddTraceEvent(
|
||||
name, category_enabled, phase, num_args, arg_names, arg_types, arg_values,
|
||||
rtc::TimeMicros(), 1, rtc::CurrentThreadId());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SetupInternalTracer(bool enable_all_categories) {
|
||||
EventLogger* null_logger = nullptr;
|
||||
RTC_CHECK(
|
||||
g_event_logger.compare_exchange_strong(null_logger, new EventLogger()));
|
||||
webrtc::SetupEventTracer(enable_all_categories ? InternalEnableAllCategories
|
||||
: InternalGetCategoryEnabled,
|
||||
InternalAddTraceEvent);
|
||||
}
|
||||
|
||||
void StartInternalCaptureToFile(FILE* file) {
|
||||
EventLogger* event_logger = g_event_logger.load();
|
||||
if (event_logger) {
|
||||
event_logger->Start(file, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool StartInternalCapture(absl::string_view filename) {
|
||||
EventLogger* event_logger = g_event_logger.load();
|
||||
if (!event_logger)
|
||||
return false;
|
||||
|
||||
FILE* file = fopen(std::string(filename).c_str(), "w");
|
||||
if (!file) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to open trace file '" << filename
|
||||
<< "' for writing.";
|
||||
return false;
|
||||
}
|
||||
event_logger->Start(file, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void StopInternalCapture() {
|
||||
EventLogger* event_logger = g_event_logger.load();
|
||||
if (event_logger) {
|
||||
event_logger->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownInternalTracer() {
|
||||
StopInternalCapture();
|
||||
EventLogger* old_logger = g_event_logger.load(std::memory_order_acquire);
|
||||
RTC_DCHECK(old_logger);
|
||||
RTC_CHECK(g_event_logger.compare_exchange_strong(old_logger, nullptr));
|
||||
delete old_logger;
|
||||
webrtc::SetupEventTracer(nullptr, nullptr);
|
||||
}
|
||||
|
||||
} // namespace tracing
|
||||
} // namespace rtc
|
||||
85
TMessagesProj/jni/voip/webrtc/rtc_base/event_tracer.h
Normal file
85
TMessagesProj/jni/voip/webrtc/rtc_base/event_tracer.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// This file defines the interface for event tracing in WebRTC.
|
||||
//
|
||||
// Event log handlers are set through SetupEventTracer(). User of this API will
|
||||
// provide two function pointers to handle event tracing calls.
|
||||
//
|
||||
// * GetCategoryEnabledPtr
|
||||
// Event tracing system calls this function to determine if a particular
|
||||
// event category is enabled.
|
||||
//
|
||||
// * AddTraceEventPtr
|
||||
// Adds a tracing event. It is the user's responsibility to log the data
|
||||
// provided.
|
||||
//
|
||||
// Parameters for the above two functions are described in trace_event.h.
|
||||
|
||||
#ifndef RTC_BASE_EVENT_TRACER_H_
|
||||
#define RTC_BASE_EVENT_TRACER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name);
|
||||
typedef void (*AddTraceEventPtr)(char phase,
|
||||
const unsigned char* category_enabled,
|
||||
const char* name,
|
||||
unsigned long long id,
|
||||
int num_args,
|
||||
const char** arg_names,
|
||||
const unsigned char* arg_types,
|
||||
const unsigned long long* arg_values,
|
||||
unsigned char flags);
|
||||
|
||||
// User of WebRTC can call this method to setup event tracing.
|
||||
//
|
||||
// This method must be called before any WebRTC methods. Functions
|
||||
// provided should be thread-safe.
|
||||
void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
|
||||
AddTraceEventPtr add_trace_event_ptr);
|
||||
|
||||
// This class defines interface for the event tracing system to call
|
||||
// internally. Do not call these methods directly.
|
||||
class EventTracer {
|
||||
public:
|
||||
static const unsigned char* GetCategoryEnabled(const char* name);
|
||||
|
||||
static void AddTraceEvent(char phase,
|
||||
const unsigned char* category_enabled,
|
||||
const char* name,
|
||||
unsigned long long id,
|
||||
int num_args,
|
||||
const char** arg_names,
|
||||
const unsigned char* arg_types,
|
||||
const unsigned long long* arg_values,
|
||||
unsigned char flags);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
namespace rtc {
|
||||
namespace tracing {
|
||||
// Set up internal event tracer.
|
||||
RTC_EXPORT void SetupInternalTracer(bool enable_all_categories = true);
|
||||
RTC_EXPORT bool StartInternalCapture(absl::string_view filename);
|
||||
RTC_EXPORT void StartInternalCaptureToFile(FILE* file);
|
||||
RTC_EXPORT void StopInternalCapture();
|
||||
// Make sure we run this, this will tear down the internal tracing.
|
||||
RTC_EXPORT void ShutdownInternalTracer();
|
||||
} // namespace tracing
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_EVENT_TRACER_H_
|
||||
115
TMessagesProj/jni/voip/webrtc/rtc_base/event_unittest.cc
Normal file
115
TMessagesProj/jni/voip/webrtc/rtc_base/event_unittest.cc
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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/event.h"
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/platform_thread.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
TEST(EventTest, InitiallySignaled) {
|
||||
Event event(false, true);
|
||||
ASSERT_TRUE(event.Wait(webrtc::TimeDelta::Zero()));
|
||||
}
|
||||
|
||||
TEST(EventTest, ManualReset) {
|
||||
Event event(true, false);
|
||||
ASSERT_FALSE(event.Wait(webrtc::TimeDelta::Zero()));
|
||||
|
||||
event.Set();
|
||||
ASSERT_TRUE(event.Wait(webrtc::TimeDelta::Zero()));
|
||||
ASSERT_TRUE(event.Wait(webrtc::TimeDelta::Zero()));
|
||||
|
||||
event.Reset();
|
||||
ASSERT_FALSE(event.Wait(webrtc::TimeDelta::Zero()));
|
||||
}
|
||||
|
||||
TEST(EventTest, AutoReset) {
|
||||
Event event;
|
||||
ASSERT_FALSE(event.Wait(webrtc::TimeDelta::Zero()));
|
||||
|
||||
event.Set();
|
||||
ASSERT_TRUE(event.Wait(webrtc::TimeDelta::Zero()));
|
||||
ASSERT_FALSE(event.Wait(webrtc::TimeDelta::Zero()));
|
||||
}
|
||||
|
||||
class SignalerThread {
|
||||
public:
|
||||
void Start(Event* writer, Event* reader) {
|
||||
writer_ = writer;
|
||||
reader_ = reader;
|
||||
thread_ = PlatformThread::SpawnJoinable(
|
||||
[this] {
|
||||
while (!stop_event_.Wait(webrtc::TimeDelta::Zero())) {
|
||||
writer_->Set();
|
||||
reader_->Wait(Event::kForever);
|
||||
}
|
||||
},
|
||||
"EventPerf");
|
||||
}
|
||||
void Stop() {
|
||||
stop_event_.Set();
|
||||
thread_.Finalize();
|
||||
}
|
||||
Event stop_event_;
|
||||
Event* writer_;
|
||||
Event* reader_;
|
||||
PlatformThread thread_;
|
||||
};
|
||||
|
||||
TEST(EventTest, UnsignaledWaitDoesNotReturnBeforeTimeout) {
|
||||
constexpr webrtc::TimeDelta kDuration = webrtc::TimeDelta::Micros(10'499);
|
||||
Event event;
|
||||
auto begin = webrtc::Clock::GetRealTimeClock()->CurrentTime();
|
||||
EXPECT_FALSE(event.Wait(kDuration));
|
||||
EXPECT_GE(webrtc::Clock::GetRealTimeClock()->CurrentTime(),
|
||||
begin + kDuration);
|
||||
}
|
||||
|
||||
// These tests are disabled by default and only intended to be run manually.
|
||||
TEST(EventTest, DISABLED_PerformanceSingleThread) {
|
||||
static const int kNumIterations = 10000000;
|
||||
Event event;
|
||||
for (int i = 0; i < kNumIterations; ++i) {
|
||||
event.Set();
|
||||
event.Wait(webrtc::TimeDelta::Zero());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EventTest, DISABLED_PerformanceMultiThread) {
|
||||
static const int kNumIterations = 10000;
|
||||
Event read;
|
||||
Event write;
|
||||
SignalerThread thread;
|
||||
thread.Start(&read, &write);
|
||||
|
||||
for (int i = 0; i < kNumIterations; ++i) {
|
||||
write.Set();
|
||||
read.Wait(Event::kForever);
|
||||
}
|
||||
write.Set();
|
||||
|
||||
thread.Stop();
|
||||
}
|
||||
|
||||
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||
// Tests that we crash if we attempt to call rtc::Event::Wait while we're
|
||||
// not allowed to (as per `RTC_DISALLOW_WAIT()`).
|
||||
TEST(EventTestDeathTest, DisallowEventWait) {
|
||||
Event event;
|
||||
RTC_DISALLOW_WAIT();
|
||||
EXPECT_DEATH(event.Wait(Event::kForever), "");
|
||||
}
|
||||
#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||
|
||||
} // namespace rtc
|
||||
13
TMessagesProj/jni/voip/webrtc/rtc_base/experiments/OWNERS
Normal file
13
TMessagesProj/jni/voip/webrtc/rtc_base/experiments/OWNERS
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
asapersson@webrtc.org
|
||||
sprang@webrtc.org
|
||||
srte@webrtc.org
|
||||
|
||||
per-file audio_allocation_settings*=srte@webrtc.org
|
||||
per-file congestion_controller_experiment*=srte@webrtc.org
|
||||
per-file cpu_speed_experiment*=asapersson@webrtc.org
|
||||
per-file field_trial*=srte@webrtc.org
|
||||
per-file keyframe_interval_settings*=brandtr@webrtc.org
|
||||
per-file normalize_simulcast_size_experiment*=asapersson@webrtc.org
|
||||
per-file quality_scaling_experiment*=asapersson@webrtc.org
|
||||
per-file rtt_mult_experiment*=mhoro@webrtc.org
|
||||
per-file rate_control_settings*=srte@webrtc.org
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/alr_experiment.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr absl::string_view kDefaultProbingScreenshareBweSettings =
|
||||
"1.0,2875,80,40,-60,3";
|
||||
|
||||
} // namespace
|
||||
|
||||
bool AlrExperimentSettings::MaxOneFieldTrialEnabled(
|
||||
const FieldTrialsView& key_value_config) {
|
||||
return key_value_config.Lookup(kStrictPacingAndProbingExperimentName)
|
||||
.empty() ||
|
||||
key_value_config.Lookup(kScreenshareProbingBweExperimentName).empty();
|
||||
}
|
||||
|
||||
absl::optional<AlrExperimentSettings>
|
||||
AlrExperimentSettings::CreateFromFieldTrial(
|
||||
const FieldTrialsView& key_value_config,
|
||||
absl::string_view experiment_name) {
|
||||
absl::optional<AlrExperimentSettings> ret;
|
||||
std::string group_name = key_value_config.Lookup(experiment_name);
|
||||
|
||||
const std::string kIgnoredSuffix = "_Dogfood";
|
||||
std::string::size_type suffix_pos = group_name.rfind(kIgnoredSuffix);
|
||||
if (suffix_pos != std::string::npos &&
|
||||
suffix_pos == group_name.length() - kIgnoredSuffix.length()) {
|
||||
group_name.resize(group_name.length() - kIgnoredSuffix.length());
|
||||
}
|
||||
|
||||
if (group_name.empty()) {
|
||||
if (experiment_name == kScreenshareProbingBweExperimentName) {
|
||||
// This experiment is now default-on with fixed settings.
|
||||
// TODO(sprang): Remove this kill-switch and clean up experiment code.
|
||||
group_name = kDefaultProbingScreenshareBweSettings;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
AlrExperimentSettings settings;
|
||||
if (sscanf(group_name.c_str(), "%f,%" PRId64 ",%d,%d,%d,%d",
|
||||
&settings.pacing_factor, &settings.max_paced_queue_time,
|
||||
&settings.alr_bandwidth_usage_percent,
|
||||
&settings.alr_start_budget_level_percent,
|
||||
&settings.alr_stop_budget_level_percent,
|
||||
&settings.group_id) == 6) {
|
||||
ret.emplace(settings);
|
||||
RTC_LOG(LS_INFO) << "Using ALR experiment settings: "
|
||||
"pacing factor: "
|
||||
<< settings.pacing_factor << ", max pacer queue length: "
|
||||
<< settings.max_paced_queue_time
|
||||
<< ", ALR bandwidth usage percent: "
|
||||
<< settings.alr_bandwidth_usage_percent
|
||||
<< ", ALR start budget level percent: "
|
||||
<< settings.alr_start_budget_level_percent
|
||||
<< ", ALR end budget level percent: "
|
||||
<< settings.alr_stop_budget_level_percent
|
||||
<< ", ALR experiment group ID: " << settings.group_id;
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << "Failed to parse ALR experiment: " << experiment_name;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
|
||||
namespace webrtc {
|
||||
struct AlrExperimentSettings {
|
||||
public:
|
||||
float pacing_factor;
|
||||
int64_t max_paced_queue_time;
|
||||
int alr_bandwidth_usage_percent;
|
||||
int alr_start_budget_level_percent;
|
||||
int alr_stop_budget_level_percent;
|
||||
// Will be sent to the receive side for stats slicing.
|
||||
// Can be 0..6, because it's sent as a 3 bits value and there's also
|
||||
// reserved value to indicate absence of experiment.
|
||||
int group_id;
|
||||
|
||||
static constexpr absl::string_view kScreenshareProbingBweExperimentName =
|
||||
"WebRTC-ProbingScreenshareBwe";
|
||||
static constexpr absl::string_view kStrictPacingAndProbingExperimentName =
|
||||
"WebRTC-StrictPacingAndProbing";
|
||||
|
||||
static absl::optional<AlrExperimentSettings> CreateFromFieldTrial(
|
||||
const FieldTrialsView& key_value_config,
|
||||
absl::string_view experiment_name);
|
||||
static bool MaxOneFieldTrialEnabled(const FieldTrialsView& key_value_config);
|
||||
|
||||
private:
|
||||
AlrExperimentSettings() = default;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,487 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/balanced_degradation_settings.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "rtc_base/experiments/field_trial_list.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrial[] = "WebRTC-Video-BalancedDegradationSettings";
|
||||
constexpr int kMinFps = 1;
|
||||
constexpr int kMaxFps = 100; // 100 means unlimited fps.
|
||||
|
||||
std::vector<BalancedDegradationSettings::Config> DefaultConfigs() {
|
||||
return {{320 * 240,
|
||||
7,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0}},
|
||||
{480 * 360,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0}},
|
||||
{640 * 480,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0}}};
|
||||
}
|
||||
|
||||
bool IsValidConfig(
|
||||
const BalancedDegradationSettings::CodecTypeSpecific& config) {
|
||||
if (config.GetQpLow().has_value() != config.GetQpHigh().has_value()) {
|
||||
RTC_LOG(LS_WARNING) << "Neither or both thresholds should be set.";
|
||||
return false;
|
||||
}
|
||||
if (config.GetQpLow().has_value() && config.GetQpHigh().has_value() &&
|
||||
config.GetQpLow().value() >= config.GetQpHigh().value()) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid threshold value, low >= high threshold.";
|
||||
return false;
|
||||
}
|
||||
if (config.GetFps().has_value() && (config.GetFps().value() < kMinFps ||
|
||||
config.GetFps().value() > kMaxFps)) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValid(const BalancedDegradationSettings::CodecTypeSpecific& config1,
|
||||
const BalancedDegradationSettings::CodecTypeSpecific& config2) {
|
||||
bool both_or_none_set = ((config1.qp_low > 0) == (config2.qp_low > 0) &&
|
||||
(config1.qp_high > 0) == (config2.qp_high > 0) &&
|
||||
(config1.fps > 0) == (config2.fps > 0));
|
||||
if (!both_or_none_set) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid value, all/none should be set.";
|
||||
return false;
|
||||
}
|
||||
if (config1.fps > 0 && config1.fps < config2.fps) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValid(const std::vector<BalancedDegradationSettings::Config>& configs) {
|
||||
if (configs.size() <= 1) {
|
||||
if (configs.size() == 1)
|
||||
RTC_LOG(LS_WARNING) << "Unsupported size, value ignored.";
|
||||
return false;
|
||||
}
|
||||
for (const auto& config : configs) {
|
||||
if (config.fps < kMinFps || config.fps > kMaxFps) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int last_kbps = configs[0].kbps;
|
||||
for (size_t i = 1; i < configs.size(); ++i) {
|
||||
if (configs[i].kbps > 0) {
|
||||
if (configs[i].kbps < last_kbps) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid bitrate value provided.";
|
||||
return false;
|
||||
}
|
||||
last_kbps = configs[i].kbps;
|
||||
}
|
||||
}
|
||||
for (size_t i = 1; i < configs.size(); ++i) {
|
||||
if (configs[i].pixels < configs[i - 1].pixels ||
|
||||
configs[i].fps < configs[i - 1].fps) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided.";
|
||||
return false;
|
||||
}
|
||||
if (!IsValid(configs[i].vp8, configs[i - 1].vp8) ||
|
||||
!IsValid(configs[i].vp9, configs[i - 1].vp9) ||
|
||||
!IsValid(configs[i].h264, configs[i - 1].h264) ||
|
||||
!IsValid(configs[i].av1, configs[i - 1].av1) ||
|
||||
!IsValid(configs[i].generic, configs[i - 1].generic)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& config : configs) {
|
||||
if (!IsValidConfig(config.vp8) || !IsValidConfig(config.vp9) ||
|
||||
!IsValidConfig(config.h264) || !IsValidConfig(config.av1) ||
|
||||
!IsValidConfig(config.generic)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<BalancedDegradationSettings::Config> GetValidOrDefault(
|
||||
const std::vector<BalancedDegradationSettings::Config>& configs) {
|
||||
if (IsValid(configs)) {
|
||||
return configs;
|
||||
}
|
||||
return DefaultConfigs();
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::QpThresholds> GetThresholds(
|
||||
VideoCodecType type,
|
||||
const BalancedDegradationSettings::Config& config) {
|
||||
absl::optional<int> low;
|
||||
absl::optional<int> high;
|
||||
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
low = config.vp8.GetQpLow();
|
||||
high = config.vp8.GetQpHigh();
|
||||
break;
|
||||
case kVideoCodecVP9:
|
||||
low = config.vp9.GetQpLow();
|
||||
high = config.vp9.GetQpHigh();
|
||||
break;
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
|
||||
case kVideoCodecH264:
|
||||
low = config.h264.GetQpLow();
|
||||
high = config.h264.GetQpHigh();
|
||||
break;
|
||||
case kVideoCodecAV1:
|
||||
low = config.av1.GetQpLow();
|
||||
high = config.av1.GetQpHigh();
|
||||
break;
|
||||
case kVideoCodecGeneric:
|
||||
low = config.generic.GetQpLow();
|
||||
high = config.generic.GetQpHigh();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (low && high) {
|
||||
RTC_LOG(LS_INFO) << "QP thresholds: low: " << *low << ", high: " << *high;
|
||||
return absl::optional<VideoEncoder::QpThresholds>(
|
||||
VideoEncoder::QpThresholds(*low, *high));
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int GetFps(VideoCodecType type,
|
||||
const absl::optional<BalancedDegradationSettings::Config>& config) {
|
||||
if (!config.has_value()) {
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
absl::optional<int> fps;
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
fps = config->vp8.GetFps();
|
||||
break;
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
|
||||
case kVideoCodecVP9:
|
||||
fps = config->vp9.GetFps();
|
||||
break;
|
||||
case kVideoCodecH264:
|
||||
fps = config->h264.GetFps();
|
||||
break;
|
||||
case kVideoCodecAV1:
|
||||
fps = config->av1.GetFps();
|
||||
break;
|
||||
case kVideoCodecGeneric:
|
||||
fps = config->generic.GetFps();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const int framerate = fps.value_or(config->fps);
|
||||
|
||||
return (framerate == kMaxFps) ? std::numeric_limits<int>::max() : framerate;
|
||||
}
|
||||
|
||||
absl::optional<int> GetKbps(
|
||||
VideoCodecType type,
|
||||
const absl::optional<BalancedDegradationSettings::Config>& config) {
|
||||
if (!config.has_value())
|
||||
return absl::nullopt;
|
||||
|
||||
absl::optional<int> kbps;
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
kbps = config->vp8.GetKbps();
|
||||
break;
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
|
||||
case kVideoCodecVP9:
|
||||
kbps = config->vp9.GetKbps();
|
||||
break;
|
||||
case kVideoCodecH264:
|
||||
kbps = config->h264.GetKbps();
|
||||
break;
|
||||
case kVideoCodecAV1:
|
||||
kbps = config->av1.GetKbps();
|
||||
break;
|
||||
case kVideoCodecGeneric:
|
||||
kbps = config->generic.GetKbps();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (kbps.has_value())
|
||||
return kbps;
|
||||
|
||||
return config->kbps > 0 ? absl::optional<int>(config->kbps) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> GetKbpsRes(
|
||||
VideoCodecType type,
|
||||
const absl::optional<BalancedDegradationSettings::Config>& config) {
|
||||
if (!config.has_value())
|
||||
return absl::nullopt;
|
||||
|
||||
absl::optional<int> kbps_res;
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
kbps_res = config->vp8.GetKbpsRes();
|
||||
break;
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
|
||||
case kVideoCodecVP9:
|
||||
kbps_res = config->vp9.GetKbpsRes();
|
||||
break;
|
||||
case kVideoCodecH264:
|
||||
kbps_res = config->h264.GetKbpsRes();
|
||||
break;
|
||||
case kVideoCodecAV1:
|
||||
kbps_res = config->av1.GetKbpsRes();
|
||||
break;
|
||||
case kVideoCodecGeneric:
|
||||
kbps_res = config->generic.GetKbpsRes();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (kbps_res.has_value())
|
||||
return kbps_res;
|
||||
|
||||
return config->kbps_res > 0 ? absl::optional<int>(config->kbps_res)
|
||||
: absl::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetQpLow()
|
||||
const {
|
||||
return (qp_low > 0) ? absl::optional<int>(qp_low) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetQpHigh()
|
||||
const {
|
||||
return (qp_high > 0) ? absl::optional<int>(qp_high) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetFps()
|
||||
const {
|
||||
return (fps > 0) ? absl::optional<int>(fps) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetKbps()
|
||||
const {
|
||||
return (kbps > 0) ? absl::optional<int>(kbps) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetKbpsRes()
|
||||
const {
|
||||
return (kbps_res > 0) ? absl::optional<int>(kbps_res) : absl::nullopt;
|
||||
}
|
||||
|
||||
BalancedDegradationSettings::Config::Config() = default;
|
||||
|
||||
BalancedDegradationSettings::Config::Config(int pixels,
|
||||
int fps,
|
||||
int kbps,
|
||||
int kbps_res,
|
||||
int fps_diff,
|
||||
CodecTypeSpecific vp8,
|
||||
CodecTypeSpecific vp9,
|
||||
CodecTypeSpecific h264,
|
||||
CodecTypeSpecific av1,
|
||||
CodecTypeSpecific generic)
|
||||
: pixels(pixels),
|
||||
fps(fps),
|
||||
kbps(kbps),
|
||||
kbps_res(kbps_res),
|
||||
fps_diff(fps_diff),
|
||||
vp8(vp8),
|
||||
vp9(vp9),
|
||||
h264(h264),
|
||||
av1(av1),
|
||||
generic(generic) {}
|
||||
|
||||
BalancedDegradationSettings::BalancedDegradationSettings(
|
||||
const FieldTrialsView& field_trials) {
|
||||
FieldTrialStructList<Config> configs(
|
||||
{FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
|
||||
FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }),
|
||||
FieldTrialStructMember("kbps", [](Config* c) { return &c->kbps; }),
|
||||
FieldTrialStructMember("kbps_res",
|
||||
[](Config* c) { return &c->kbps_res; }),
|
||||
FieldTrialStructMember("fps_diff",
|
||||
[](Config* c) { return &c->fps_diff; }),
|
||||
FieldTrialStructMember("vp8_qp_low",
|
||||
[](Config* c) { return &c->vp8.qp_low; }),
|
||||
FieldTrialStructMember("vp8_qp_high",
|
||||
[](Config* c) { return &c->vp8.qp_high; }),
|
||||
FieldTrialStructMember("vp8_fps", [](Config* c) { return &c->vp8.fps; }),
|
||||
FieldTrialStructMember("vp8_kbps",
|
||||
[](Config* c) { return &c->vp8.kbps; }),
|
||||
FieldTrialStructMember("vp8_kbps_res",
|
||||
[](Config* c) { return &c->vp8.kbps_res; }),
|
||||
FieldTrialStructMember("vp9_qp_low",
|
||||
[](Config* c) { return &c->vp9.qp_low; }),
|
||||
FieldTrialStructMember("vp9_qp_high",
|
||||
[](Config* c) { return &c->vp9.qp_high; }),
|
||||
FieldTrialStructMember("vp9_fps", [](Config* c) { return &c->vp9.fps; }),
|
||||
FieldTrialStructMember("vp9_kbps",
|
||||
[](Config* c) { return &c->vp9.kbps; }),
|
||||
FieldTrialStructMember("vp9_kbps_res",
|
||||
[](Config* c) { return &c->vp9.kbps_res; }),
|
||||
FieldTrialStructMember("h264_qp_low",
|
||||
[](Config* c) { return &c->h264.qp_low; }),
|
||||
FieldTrialStructMember("h264_qp_high",
|
||||
[](Config* c) { return &c->h264.qp_high; }),
|
||||
FieldTrialStructMember("h264_fps",
|
||||
[](Config* c) { return &c->h264.fps; }),
|
||||
FieldTrialStructMember("h264_kbps",
|
||||
[](Config* c) { return &c->h264.kbps; }),
|
||||
FieldTrialStructMember("h264_kbps_res",
|
||||
[](Config* c) { return &c->h264.kbps_res; }),
|
||||
FieldTrialStructMember("av1_qp_low",
|
||||
[](Config* c) { return &c->av1.qp_low; }),
|
||||
FieldTrialStructMember("av1_qp_high",
|
||||
[](Config* c) { return &c->av1.qp_high; }),
|
||||
FieldTrialStructMember("av1_fps", [](Config* c) { return &c->av1.fps; }),
|
||||
FieldTrialStructMember("av1_kbps",
|
||||
[](Config* c) { return &c->av1.kbps; }),
|
||||
FieldTrialStructMember("av1_kbps_res",
|
||||
[](Config* c) { return &c->av1.kbps_res; }),
|
||||
FieldTrialStructMember("generic_qp_low",
|
||||
[](Config* c) { return &c->generic.qp_low; }),
|
||||
FieldTrialStructMember("generic_qp_high",
|
||||
[](Config* c) { return &c->generic.qp_high; }),
|
||||
FieldTrialStructMember("generic_fps",
|
||||
[](Config* c) { return &c->generic.fps; }),
|
||||
FieldTrialStructMember("generic_kbps",
|
||||
[](Config* c) { return &c->generic.kbps; }),
|
||||
FieldTrialStructMember("generic_kbps_res",
|
||||
[](Config* c) { return &c->generic.kbps_res; })},
|
||||
{});
|
||||
|
||||
ParseFieldTrial({&configs}, field_trials.Lookup(kFieldTrial));
|
||||
|
||||
configs_ = GetValidOrDefault(configs.Get());
|
||||
RTC_DCHECK_GT(configs_.size(), 1);
|
||||
}
|
||||
|
||||
BalancedDegradationSettings::~BalancedDegradationSettings() {}
|
||||
|
||||
std::vector<BalancedDegradationSettings::Config>
|
||||
BalancedDegradationSettings::GetConfigs() const {
|
||||
return configs_;
|
||||
}
|
||||
|
||||
int BalancedDegradationSettings::MinFps(VideoCodecType type, int pixels) const {
|
||||
return GetFps(type, GetMinFpsConfig(pixels));
|
||||
}
|
||||
|
||||
absl::optional<BalancedDegradationSettings::Config>
|
||||
BalancedDegradationSettings::GetMinFpsConfig(int pixels) const {
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels)
|
||||
return config;
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int BalancedDegradationSettings::MaxFps(VideoCodecType type, int pixels) const {
|
||||
return GetFps(type, GetMaxFpsConfig(pixels));
|
||||
}
|
||||
|
||||
absl::optional<BalancedDegradationSettings::Config>
|
||||
BalancedDegradationSettings::GetMaxFpsConfig(int pixels) const {
|
||||
for (size_t i = 0; i < configs_.size() - 1; ++i) {
|
||||
if (pixels <= configs_[i].pixels)
|
||||
return configs_[i + 1];
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
bool BalancedDegradationSettings::CanAdaptUp(VideoCodecType type,
|
||||
int pixels,
|
||||
uint32_t bitrate_bps) const {
|
||||
absl::optional<int> min_kbps = GetKbps(type, GetMaxFpsConfig(pixels));
|
||||
if (!min_kbps.has_value() || bitrate_bps == 0) {
|
||||
return true; // No limit configured or bitrate provided.
|
||||
}
|
||||
return bitrate_bps >= static_cast<uint32_t>(min_kbps.value() * 1000);
|
||||
}
|
||||
|
||||
bool BalancedDegradationSettings::CanAdaptUpResolution(
|
||||
VideoCodecType type,
|
||||
int pixels,
|
||||
uint32_t bitrate_bps) const {
|
||||
absl::optional<int> min_kbps = GetKbpsRes(type, GetMaxFpsConfig(pixels));
|
||||
if (!min_kbps.has_value() || bitrate_bps == 0) {
|
||||
return true; // No limit configured or bitrate provided.
|
||||
}
|
||||
return bitrate_bps >= static_cast<uint32_t>(min_kbps.value() * 1000);
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::MinFpsDiff(int pixels) const {
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels) {
|
||||
return (config.fps_diff > kNoFpsDiff)
|
||||
? absl::optional<int>(config.fps_diff)
|
||||
: absl::nullopt;
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::QpThresholds>
|
||||
BalancedDegradationSettings::GetQpThresholds(VideoCodecType type,
|
||||
int pixels) const {
|
||||
return GetThresholds(type, GetConfig(pixels));
|
||||
}
|
||||
|
||||
BalancedDegradationSettings::Config BalancedDegradationSettings::GetConfig(
|
||||
int pixels) const {
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels)
|
||||
return config;
|
||||
}
|
||||
return configs_.back(); // Use last above highest pixels.
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class BalancedDegradationSettings {
|
||||
public:
|
||||
static constexpr int kNoFpsDiff = -100;
|
||||
|
||||
BalancedDegradationSettings(const FieldTrialsView& field_trials);
|
||||
~BalancedDegradationSettings();
|
||||
|
||||
struct CodecTypeSpecific {
|
||||
CodecTypeSpecific() {}
|
||||
CodecTypeSpecific(int qp_low, int qp_high, int fps, int kbps, int kbps_res)
|
||||
: qp_low(qp_low),
|
||||
qp_high(qp_high),
|
||||
fps(fps),
|
||||
kbps(kbps),
|
||||
kbps_res(kbps_res) {}
|
||||
|
||||
bool operator==(const CodecTypeSpecific& o) const {
|
||||
return qp_low == o.qp_low && qp_high == o.qp_high && fps == o.fps &&
|
||||
kbps == o.kbps && kbps_res == o.kbps_res;
|
||||
}
|
||||
|
||||
absl::optional<int> GetQpLow() const;
|
||||
absl::optional<int> GetQpHigh() const;
|
||||
absl::optional<int> GetFps() const;
|
||||
absl::optional<int> GetKbps() const;
|
||||
absl::optional<int> GetKbpsRes() const;
|
||||
|
||||
// Optional settings.
|
||||
int qp_low = 0;
|
||||
int qp_high = 0;
|
||||
int fps = 0; // If unset, defaults to `fps` in Config.
|
||||
int kbps = 0; // If unset, defaults to `kbps` in Config.
|
||||
int kbps_res = 0; // If unset, defaults to `kbps_res` in Config.
|
||||
};
|
||||
|
||||
struct Config {
|
||||
Config();
|
||||
Config(int pixels,
|
||||
int fps,
|
||||
int kbps,
|
||||
int kbps_res,
|
||||
int fps_diff,
|
||||
CodecTypeSpecific vp8,
|
||||
CodecTypeSpecific vp9,
|
||||
CodecTypeSpecific h264,
|
||||
CodecTypeSpecific av1,
|
||||
CodecTypeSpecific generic);
|
||||
|
||||
bool operator==(const Config& o) const {
|
||||
return pixels == o.pixels && fps == o.fps && kbps == o.kbps &&
|
||||
kbps_res == o.kbps_res && fps_diff == o.fps_diff && vp8 == o.vp8 &&
|
||||
vp9 == o.vp9 && h264 == o.h264 && av1 == o.av1 &&
|
||||
generic == o.generic;
|
||||
}
|
||||
|
||||
// Example:
|
||||
// WebRTC-Video-BalancedDegradationSettings/pixels:100|200|300,fps:5|15|25/
|
||||
// pixels <= 100 -> min framerate: 5 fps
|
||||
// pixels <= 200 -> min framerate: 15 fps
|
||||
// pixels <= 300 -> min framerate: 25 fps
|
||||
//
|
||||
// WebRTC-Video-BalancedDegradationSettings/pixels:100|200|300,
|
||||
// fps:5|15|25, // Min framerate.
|
||||
// kbps:0|60|70, // Min bitrate needed to adapt up.
|
||||
// kbps_res:0|65|75/ // Min bitrate needed to adapt up in resolution.
|
||||
//
|
||||
// pixels: fps: kbps: kbps_res:
|
||||
// 300 30 - -
|
||||
// 300 25 70 kbps 75 kbps
|
||||
// 200 25 70 kbps -
|
||||
// 200 15 60 kbps 65 kbps
|
||||
// 100 15 60 kbps -
|
||||
// 100 5
|
||||
// optional optional
|
||||
|
||||
int pixels = 0; // Video frame size.
|
||||
// If the frame size is less than or equal to `pixels`:
|
||||
int fps = 0; // Min framerate to be used.
|
||||
int kbps = 0; // Min bitrate needed to adapt up (resolution/fps).
|
||||
int kbps_res = 0; // Min bitrate needed to adapt up in resolution.
|
||||
int fps_diff = kNoFpsDiff; // Min fps reduction needed (input fps - `fps`)
|
||||
// w/o triggering a new subsequent downgrade
|
||||
// check.
|
||||
CodecTypeSpecific vp8;
|
||||
CodecTypeSpecific vp9;
|
||||
CodecTypeSpecific h264;
|
||||
CodecTypeSpecific av1;
|
||||
CodecTypeSpecific generic;
|
||||
};
|
||||
|
||||
// Returns configurations from field trial on success (default on failure).
|
||||
std::vector<Config> GetConfigs() const;
|
||||
|
||||
// Gets the min/max framerate from `configs_` based on `pixels`.
|
||||
int MinFps(VideoCodecType type, int pixels) const;
|
||||
int MaxFps(VideoCodecType type, int pixels) const;
|
||||
|
||||
// Checks if quality can be increased based on `pixels` and `bitrate_bps`.
|
||||
bool CanAdaptUp(VideoCodecType type, int pixels, uint32_t bitrate_bps) const;
|
||||
bool CanAdaptUpResolution(VideoCodecType type,
|
||||
int pixels,
|
||||
uint32_t bitrate_bps) const;
|
||||
|
||||
// Gets the min framerate diff from `configs_` based on `pixels`.
|
||||
absl::optional<int> MinFpsDiff(int pixels) const;
|
||||
|
||||
// Gets QpThresholds for the codec `type` based on `pixels`.
|
||||
absl::optional<VideoEncoder::QpThresholds> GetQpThresholds(
|
||||
VideoCodecType type,
|
||||
int pixels) const;
|
||||
|
||||
private:
|
||||
absl::optional<Config> GetMinFpsConfig(int pixels) const;
|
||||
absl::optional<Config> GetMaxFpsConfig(int pixels) const;
|
||||
Config GetConfig(int pixels) const;
|
||||
|
||||
std::vector<Config> configs_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/experiments/bandwidth_quality_scaler_settings.h"
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
BandwidthQualityScalerSettings::BandwidthQualityScalerSettings(
|
||||
const FieldTrialsView* const key_value_config)
|
||||
: bitrate_state_update_interval_s_("bitrate_state_update_interval_s_") {
|
||||
ParseFieldTrial(
|
||||
{&bitrate_state_update_interval_s_},
|
||||
key_value_config->Lookup("WebRTC-Video-BandwidthQualityScalerSettings"));
|
||||
}
|
||||
|
||||
BandwidthQualityScalerSettings
|
||||
BandwidthQualityScalerSettings::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return BandwidthQualityScalerSettings(&field_trial_config);
|
||||
}
|
||||
|
||||
absl::optional<uint32_t>
|
||||
BandwidthQualityScalerSettings::BitrateStateUpdateInterval() const {
|
||||
if (bitrate_state_update_interval_s_ &&
|
||||
bitrate_state_update_interval_s_.Value() <= 0) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Unsupported bitrate_state_update_interval_s_ value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return bitrate_state_update_interval_s_.GetOptional();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 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_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class BandwidthQualityScalerSettings final {
|
||||
public:
|
||||
static BandwidthQualityScalerSettings ParseFromFieldTrials();
|
||||
|
||||
absl::optional<uint32_t> BitrateStateUpdateInterval() const;
|
||||
|
||||
private:
|
||||
explicit BandwidthQualityScalerSettings(
|
||||
const FieldTrialsView* const key_value_config);
|
||||
|
||||
FieldTrialOptional<uint32_t> bitrate_state_update_interval_s_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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/experiments/cpu_speed_experiment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rtc_base/experiments/field_trial_list.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrial[] = "WebRTC-VP8-CpuSpeed-Arm";
|
||||
constexpr int kMinSetting = -16;
|
||||
constexpr int kMaxSetting = -1;
|
||||
|
||||
std::vector<CpuSpeedExperiment::Config> GetValidOrEmpty(
|
||||
const std::vector<CpuSpeedExperiment::Config>& configs) {
|
||||
if (configs.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (const auto& config : configs) {
|
||||
if (config.cpu_speed < kMinSetting || config.cpu_speed > kMaxSetting) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported cpu speed setting, value ignored.";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < configs.size(); ++i) {
|
||||
if (configs[i].pixels < configs[i - 1].pixels ||
|
||||
configs[i].cpu_speed > configs[i - 1].cpu_speed) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid parameter value provided.";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
bool HasLeCores(const std::vector<CpuSpeedExperiment::Config>& configs) {
|
||||
for (const auto& config : configs) {
|
||||
if (config.cpu_speed_le_cores == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CpuSpeedExperiment::CpuSpeedExperiment() : cores_("cores") {
|
||||
FieldTrialStructList<Config> configs(
|
||||
{FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
|
||||
FieldTrialStructMember("cpu_speed",
|
||||
[](Config* c) { return &c->cpu_speed; }),
|
||||
FieldTrialStructMember(
|
||||
"cpu_speed_le_cores",
|
||||
[](Config* c) { return &c->cpu_speed_le_cores; })},
|
||||
{});
|
||||
ParseFieldTrial({&configs, &cores_}, field_trial::FindFullName(kFieldTrial));
|
||||
|
||||
configs_ = GetValidOrEmpty(configs.Get());
|
||||
}
|
||||
|
||||
CpuSpeedExperiment::~CpuSpeedExperiment() {}
|
||||
|
||||
absl::optional<int> CpuSpeedExperiment::GetValue(int pixels,
|
||||
int num_cores) const {
|
||||
if (configs_.empty())
|
||||
return absl::nullopt;
|
||||
|
||||
bool use_le = HasLeCores(configs_) && cores_ && num_cores <= cores_.Value();
|
||||
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels)
|
||||
return use_le ? absl::optional<int>(config.cpu_speed_le_cores)
|
||||
: absl::optional<int>(config.cpu_speed);
|
||||
}
|
||||
return absl::optional<int>(kMinSetting);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class CpuSpeedExperiment {
|
||||
public:
|
||||
CpuSpeedExperiment();
|
||||
~CpuSpeedExperiment();
|
||||
|
||||
// Example:
|
||||
// WebRTC-VP8-CpuSpeed-Arm/pixels:100|200|300,cpu_speed:-1|-2|-3/
|
||||
// pixels <= 100 -> cpu speed: -1
|
||||
// pixels <= 200 -> cpu speed: -2
|
||||
// pixels <= 300 -> cpu speed: -3
|
||||
|
||||
// WebRTC-VP8-CpuSpeed-Arm/pixels:100|200|300,cpu_speed:-1|-2|-3/,
|
||||
// cpu_speed_le_cores:-4|-5|-6,cores:3/
|
||||
// If `num_cores` > 3
|
||||
// pixels <= 100 -> cpu speed: -1
|
||||
// pixels <= 200 -> cpu speed: -2
|
||||
// pixels <= 300 -> cpu speed: -3
|
||||
// else
|
||||
// pixels <= 100 -> cpu speed: -4
|
||||
// pixels <= 200 -> cpu speed: -5
|
||||
// pixels <= 300 -> cpu speed: -6
|
||||
|
||||
struct Config {
|
||||
int pixels = 0; // The video frame size.
|
||||
int cpu_speed = 0; // The `cpu_speed` to be used if the frame size is less
|
||||
// than or equal to `pixels`.
|
||||
// Optional.
|
||||
int cpu_speed_le_cores = 0; // Same as `cpu_speed` above but only used if
|
||||
// `num_cores` <= `cores_`.
|
||||
};
|
||||
|
||||
// Gets the cpu speed based on `pixels` and `num_cores`.
|
||||
absl::optional<int> GetValue(int pixels, int num_cores) const;
|
||||
|
||||
private:
|
||||
std::vector<Config> configs_;
|
||||
|
||||
// Threshold for when to use `cpu_speed_le_cores`.
|
||||
FieldTrialOptional<int> cores_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/experiments/encoder_info_settings.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/experiments/field_trial_list.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> ToResolutionBitrateLimits(
|
||||
const std::vector<EncoderInfoSettings::BitrateLimit>& limits) {
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> result;
|
||||
for (const auto& limit : limits) {
|
||||
result.push_back(VideoEncoder::ResolutionBitrateLimits(
|
||||
limit.frame_size_pixels, limit.min_start_bitrate_bps,
|
||||
limit.min_bitrate_bps, limit.max_bitrate_bps));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
constexpr float kDefaultMinBitratebps = 30000;
|
||||
} // namespace
|
||||
|
||||
// Default bitrate limits for simulcast with one active stream:
|
||||
// {frame_size_pixels, min_start_bitrate_bps, min_bitrate_bps, max_bitrate_bps}.
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits>
|
||||
EncoderInfoSettings::GetDefaultSinglecastBitrateLimits(
|
||||
VideoCodecType codec_type) {
|
||||
if (codec_type == kVideoCodecAV1) {
|
||||
// AV1 singlecast max bitrate limits are higher than AV1 SVC max limits.
|
||||
// This is because in singlecast we normally have just one receiver, BWE is
|
||||
// known end-to-end and the encode target bitrate guarantees delivery of
|
||||
// video.
|
||||
// The min bitrate limits are not used in singlecast (used in SVC/simulcast
|
||||
// to de-/activate spatial layers) and are set to zero. Send resolution in
|
||||
// singlecast is assumed to be regulated by QP-based quality scaler.
|
||||
return {{320 * 180, 0, 0, 256000},
|
||||
{480 * 270, 176000, 0, 384000},
|
||||
{640 * 360, 256000, 0, 512000},
|
||||
{960 * 540, 384000, 0, 1024000},
|
||||
{1280 * 720, 576000, 0, 1536000}};
|
||||
}
|
||||
|
||||
if (codec_type == kVideoCodecVP9) {
|
||||
// VP9 singlecast bitrate limits are derived ~directly from VP9 SVC bitrate
|
||||
// limits. The current max limits are unnecessarily too strict for
|
||||
// singlecast, where BWE is known end-to-end, especially for low
|
||||
// resolutions.
|
||||
return {{320 * 180, 0, 30000, 150000},
|
||||
{480 * 270, 120000, 30000, 300000},
|
||||
{640 * 360, 190000, 30000, 420000},
|
||||
{960 * 540, 350000, 30000, 1000000},
|
||||
{1280 * 720, 480000, 30000, 1500000}};
|
||||
}
|
||||
|
||||
// VP8 and other codecs.
|
||||
return {{320 * 180, 0, 30000, 300000},
|
||||
{480 * 270, 200000, 30000, 500000},
|
||||
{640 * 360, 300000, 30000, 800000},
|
||||
{960 * 540, 500000, 30000, 1500000},
|
||||
{1280 * 720, 900000, 30000, 2500000}};
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::ResolutionBitrateLimits>
|
||||
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution(
|
||||
VideoCodecType codec_type,
|
||||
int frame_size_pixels) {
|
||||
VideoEncoder::EncoderInfo info;
|
||||
info.resolution_bitrate_limits =
|
||||
GetDefaultSinglecastBitrateLimits(codec_type);
|
||||
return info.GetEncoderBitrateLimitsForResolution(frame_size_pixels);
|
||||
}
|
||||
|
||||
// Return the suitable bitrate limits for specified resolution when qp is
|
||||
// untrusted, they are experimental values.
|
||||
// TODO(bugs.webrtc.org/12942): Maybe we need to add other codecs(VP8/VP9)
|
||||
// experimental values.
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits>
|
||||
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted() {
|
||||
// Specific limits for H264/AVC
|
||||
return {{0 * 0, 0, 0, 0},
|
||||
{320 * 180, 0, 30000, 300000},
|
||||
{480 * 270, 300000, 30000, 500000},
|
||||
{640 * 360, 500000, 30000, 800000},
|
||||
{960 * 540, 800000, 30000, 1500000},
|
||||
{1280 * 720, 1500000, 30000, 2500000},
|
||||
{1920 * 1080, 2500000, 30000, 4000000}};
|
||||
}
|
||||
|
||||
// Through linear interpolation, return the bitrate limit corresponding to the
|
||||
// specified |frame_size_pixels|.
|
||||
absl::optional<VideoEncoder::ResolutionBitrateLimits>
|
||||
EncoderInfoSettings::GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted(
|
||||
absl::optional<int> frame_size_pixels,
|
||||
const std::vector<VideoEncoder::ResolutionBitrateLimits>&
|
||||
resolution_bitrate_limits) {
|
||||
if (!frame_size_pixels.has_value() || frame_size_pixels.value() <= 0) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> bitrate_limits =
|
||||
resolution_bitrate_limits;
|
||||
|
||||
// Sort the list of bitrate limits by resolution.
|
||||
sort(bitrate_limits.begin(), bitrate_limits.end(),
|
||||
[](const VideoEncoder::ResolutionBitrateLimits& lhs,
|
||||
const VideoEncoder::ResolutionBitrateLimits& rhs) {
|
||||
return lhs.frame_size_pixels < rhs.frame_size_pixels;
|
||||
});
|
||||
|
||||
if (bitrate_limits.empty()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int interpolation_index = -1;
|
||||
for (size_t i = 0; i < bitrate_limits.size(); ++i) {
|
||||
if (bitrate_limits[i].frame_size_pixels >= frame_size_pixels.value()) {
|
||||
interpolation_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -1 means that the maximum resolution is exceeded, we will select the
|
||||
// largest data as the return result.
|
||||
if (interpolation_index == -1) {
|
||||
return *bitrate_limits.rbegin();
|
||||
}
|
||||
|
||||
// If we have a matching resolution, return directly without interpolation.
|
||||
if (bitrate_limits[interpolation_index].frame_size_pixels ==
|
||||
frame_size_pixels.value()) {
|
||||
return bitrate_limits[interpolation_index];
|
||||
}
|
||||
|
||||
// No matching resolution, do a linear interpolate.
|
||||
int lower_pixel_count =
|
||||
bitrate_limits[interpolation_index - 1].frame_size_pixels;
|
||||
int upper_pixel_count = bitrate_limits[interpolation_index].frame_size_pixels;
|
||||
float alpha = (frame_size_pixels.value() - lower_pixel_count) * 1.0 /
|
||||
(upper_pixel_count - lower_pixel_count);
|
||||
int min_start_bitrate_bps = static_cast<int>(
|
||||
bitrate_limits[interpolation_index].min_start_bitrate_bps * alpha +
|
||||
bitrate_limits[interpolation_index - 1].min_start_bitrate_bps *
|
||||
(1.0 - alpha));
|
||||
int max_bitrate_bps = static_cast<int>(
|
||||
bitrate_limits[interpolation_index].max_bitrate_bps * alpha +
|
||||
bitrate_limits[interpolation_index - 1].max_bitrate_bps * (1.0 - alpha));
|
||||
|
||||
if (max_bitrate_bps >= min_start_bitrate_bps) {
|
||||
return VideoEncoder::ResolutionBitrateLimits(
|
||||
frame_size_pixels.value(), min_start_bitrate_bps, kDefaultMinBitratebps,
|
||||
max_bitrate_bps);
|
||||
} else {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "BitRate interpolation calculating result is abnormal. "
|
||||
<< " lower_pixel_count = " << lower_pixel_count
|
||||
<< " upper_pixel_count = " << upper_pixel_count
|
||||
<< " frame_size_pixels = " << frame_size_pixels.value()
|
||||
<< " min_start_bitrate_bps = " << min_start_bitrate_bps
|
||||
<< " min_bitrate_bps = " << kDefaultMinBitratebps
|
||||
<< " max_bitrate_bps = " << max_bitrate_bps;
|
||||
return absl::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
EncoderInfoSettings::EncoderInfoSettings(absl::string_view name)
|
||||
: requested_resolution_alignment_("requested_resolution_alignment"),
|
||||
apply_alignment_to_all_simulcast_layers_(
|
||||
"apply_alignment_to_all_simulcast_layers") {
|
||||
FieldTrialStructList<BitrateLimit> bitrate_limits(
|
||||
{FieldTrialStructMember(
|
||||
"frame_size_pixels",
|
||||
[](BitrateLimit* b) { return &b->frame_size_pixels; }),
|
||||
FieldTrialStructMember(
|
||||
"min_start_bitrate_bps",
|
||||
[](BitrateLimit* b) { return &b->min_start_bitrate_bps; }),
|
||||
FieldTrialStructMember(
|
||||
"min_bitrate_bps",
|
||||
[](BitrateLimit* b) { return &b->min_bitrate_bps; }),
|
||||
FieldTrialStructMember(
|
||||
"max_bitrate_bps",
|
||||
[](BitrateLimit* b) { return &b->max_bitrate_bps; })},
|
||||
{});
|
||||
|
||||
std::string name_str(name);
|
||||
if (field_trial::FindFullName(name_str).empty()) {
|
||||
// Encoder name not found, use common string applying to all encoders.
|
||||
name_str = "WebRTC-GetEncoderInfoOverride";
|
||||
}
|
||||
|
||||
ParseFieldTrial({&bitrate_limits, &requested_resolution_alignment_,
|
||||
&apply_alignment_to_all_simulcast_layers_},
|
||||
field_trial::FindFullName(name_str));
|
||||
|
||||
resolution_bitrate_limits_ = ToResolutionBitrateLimits(bitrate_limits.Get());
|
||||
}
|
||||
|
||||
absl::optional<uint32_t> EncoderInfoSettings::requested_resolution_alignment()
|
||||
const {
|
||||
if (requested_resolution_alignment_ &&
|
||||
requested_resolution_alignment_.Value() < 1) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported alignment value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return requested_resolution_alignment_.GetOptional();
|
||||
}
|
||||
|
||||
EncoderInfoSettings::~EncoderInfoSettings() {}
|
||||
|
||||
SimulcastEncoderAdapterEncoderInfoSettings::
|
||||
SimulcastEncoderAdapterEncoderInfoSettings()
|
||||
: EncoderInfoSettings(
|
||||
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride") {}
|
||||
|
||||
LibvpxVp8EncoderInfoSettings::LibvpxVp8EncoderInfoSettings()
|
||||
: EncoderInfoSettings("WebRTC-VP8-GetEncoderInfoOverride") {}
|
||||
|
||||
LibvpxVp9EncoderInfoSettings::LibvpxVp9EncoderInfoSettings()
|
||||
: EncoderInfoSettings("WebRTC-VP9-GetEncoderInfoOverride") {}
|
||||
|
||||
LibaomAv1EncoderInfoSettings::LibaomAv1EncoderInfoSettings()
|
||||
: EncoderInfoSettings("WebRTC-Av1-GetEncoderInfoOverride") {}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class EncoderInfoSettings {
|
||||
public:
|
||||
virtual ~EncoderInfoSettings();
|
||||
|
||||
// Bitrate limits per resolution.
|
||||
struct BitrateLimit {
|
||||
int frame_size_pixels = 0; // The video frame size.
|
||||
int min_start_bitrate_bps = 0; // The minimum bitrate to start encoding.
|
||||
int min_bitrate_bps = 0; // The minimum bitrate.
|
||||
int max_bitrate_bps = 0; // The maximum bitrate.
|
||||
};
|
||||
|
||||
absl::optional<uint32_t> requested_resolution_alignment() const;
|
||||
bool apply_alignment_to_all_simulcast_layers() const {
|
||||
return apply_alignment_to_all_simulcast_layers_.Get();
|
||||
}
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> resolution_bitrate_limits()
|
||||
const {
|
||||
return resolution_bitrate_limits_;
|
||||
}
|
||||
|
||||
static std::vector<VideoEncoder::ResolutionBitrateLimits>
|
||||
GetDefaultSinglecastBitrateLimits(VideoCodecType codec_type);
|
||||
|
||||
static absl::optional<VideoEncoder::ResolutionBitrateLimits>
|
||||
GetDefaultSinglecastBitrateLimitsForResolution(VideoCodecType codec_type,
|
||||
int frame_size_pixels);
|
||||
|
||||
static std::vector<VideoEncoder::ResolutionBitrateLimits>
|
||||
GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted();
|
||||
|
||||
static absl::optional<VideoEncoder::ResolutionBitrateLimits>
|
||||
GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted(
|
||||
absl::optional<int> frame_size_pixels,
|
||||
const std::vector<VideoEncoder::ResolutionBitrateLimits>&
|
||||
resolution_bitrate_limits);
|
||||
|
||||
protected:
|
||||
explicit EncoderInfoSettings(absl::string_view name);
|
||||
|
||||
private:
|
||||
FieldTrialOptional<uint32_t> requested_resolution_alignment_;
|
||||
FieldTrialFlag apply_alignment_to_all_simulcast_layers_;
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> resolution_bitrate_limits_;
|
||||
};
|
||||
|
||||
// EncoderInfo settings for SimulcastEncoderAdapter.
|
||||
class SimulcastEncoderAdapterEncoderInfoSettings : public EncoderInfoSettings {
|
||||
public:
|
||||
SimulcastEncoderAdapterEncoderInfoSettings();
|
||||
~SimulcastEncoderAdapterEncoderInfoSettings() override {}
|
||||
};
|
||||
|
||||
// EncoderInfo settings for LibvpxVp8Encoder.
|
||||
class LibvpxVp8EncoderInfoSettings : public EncoderInfoSettings {
|
||||
public:
|
||||
LibvpxVp8EncoderInfoSettings();
|
||||
~LibvpxVp8EncoderInfoSettings() override {}
|
||||
};
|
||||
|
||||
// EncoderInfo settings for LibvpxVp9Encoder.
|
||||
class LibvpxVp9EncoderInfoSettings : public EncoderInfoSettings {
|
||||
public:
|
||||
LibvpxVp9EncoderInfoSettings();
|
||||
~LibvpxVp9EncoderInfoSettings() override {}
|
||||
};
|
||||
|
||||
// EncoderInfo settings for LibaomAv1Encoder.
|
||||
class LibaomAv1EncoderInfoSettings : public EncoderInfoSettings {
|
||||
public:
|
||||
LibaomAv1EncoderInfoSettings();
|
||||
~LibaomAv1EncoderInfoSettings() override {}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/field_trial_list.h"
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
FieldTrialListBase::FieldTrialListBase(absl::string_view key)
|
||||
: FieldTrialParameterInterface(key),
|
||||
failed_(false),
|
||||
parse_got_called_(false) {}
|
||||
|
||||
bool FieldTrialListBase::Failed() const {
|
||||
return failed_;
|
||||
}
|
||||
bool FieldTrialListBase::Used() const {
|
||||
return parse_got_called_;
|
||||
}
|
||||
|
||||
int FieldTrialListWrapper::Length() {
|
||||
return GetList()->Size();
|
||||
}
|
||||
bool FieldTrialListWrapper::Failed() {
|
||||
return GetList()->Failed();
|
||||
}
|
||||
bool FieldTrialListWrapper::Used() {
|
||||
return GetList()->Used();
|
||||
}
|
||||
|
||||
bool FieldTrialStructListBase::Parse(absl::optional<std::string> str_value) {
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return true;
|
||||
}
|
||||
|
||||
int FieldTrialStructListBase::ValidateAndGetLength() {
|
||||
int length = -1;
|
||||
for (std::unique_ptr<FieldTrialListWrapper>& list : sub_lists_) {
|
||||
if (list->Failed())
|
||||
return -1;
|
||||
else if (!list->Used())
|
||||
continue;
|
||||
else if (length == -1)
|
||||
length = list->Length();
|
||||
else if (length != list->Length())
|
||||
return -1;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_FIELD_TRIAL_LIST_H_
|
||||
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/string_encode.h"
|
||||
|
||||
// List support for field trial strings. FieldTrialList and FieldTrialStructList
|
||||
// are used similarly to the other FieldTrialParameters, but take a variable
|
||||
// number of parameters. A FieldTrialList<T> parses a |-delimeted string into a
|
||||
// list of T, using ParseTypedParameter to parse the individual tokens.
|
||||
// Example string: "my_list:1|2|3,empty_list,other_list:aardvark".
|
||||
|
||||
// A FieldTrialStructList combines multiple lists into a list-of-structs. It
|
||||
// ensures that all its sublists parse correctly and have the same length, then
|
||||
// uses user-supplied accessor functions to write those elements into structs of
|
||||
// a user-supplied type.
|
||||
|
||||
// See the unit test for usage and behavior.
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FieldTrialListBase : public FieldTrialParameterInterface {
|
||||
protected:
|
||||
friend class FieldTrialListWrapper;
|
||||
explicit FieldTrialListBase(absl::string_view key);
|
||||
|
||||
bool Failed() const;
|
||||
bool Used() const;
|
||||
|
||||
virtual int Size() = 0;
|
||||
|
||||
bool failed_;
|
||||
bool parse_got_called_;
|
||||
};
|
||||
|
||||
// This class represents a vector of type T. The elements are separated by a |
|
||||
// and parsed using ParseTypedParameter.
|
||||
template <typename T>
|
||||
class FieldTrialList : public FieldTrialListBase {
|
||||
public:
|
||||
explicit FieldTrialList(absl::string_view key) : FieldTrialList(key, {}) {}
|
||||
FieldTrialList(absl::string_view key, std::initializer_list<T> default_values)
|
||||
: FieldTrialListBase(key), values_(default_values) {}
|
||||
|
||||
std::vector<T> Get() const { return values_; }
|
||||
operator std::vector<T>() const { return Get(); }
|
||||
typename std::vector<T>::const_reference operator[](size_t index) const {
|
||||
return values_[index];
|
||||
}
|
||||
const std::vector<T>* operator->() const { return &values_; }
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override {
|
||||
parse_got_called_ = true;
|
||||
|
||||
if (!str_value) {
|
||||
values_.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<T> new_values_;
|
||||
|
||||
for (const absl::string_view token : rtc::split(str_value.value(), '|')) {
|
||||
absl::optional<T> value = ParseTypedParameter<T>(token);
|
||||
if (value) {
|
||||
new_values_.push_back(*value);
|
||||
} else {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
values_.swap(new_values_);
|
||||
return true;
|
||||
}
|
||||
|
||||
int Size() override { return values_.size(); }
|
||||
|
||||
private:
|
||||
std::vector<T> values_;
|
||||
};
|
||||
|
||||
class FieldTrialListWrapper {
|
||||
public:
|
||||
virtual ~FieldTrialListWrapper() = default;
|
||||
|
||||
// Takes the element at the given index in the wrapped list and writes it to
|
||||
// the given struct.
|
||||
virtual void WriteElement(void* struct_to_write, int index) = 0;
|
||||
|
||||
virtual FieldTrialListBase* GetList() = 0;
|
||||
|
||||
int Length();
|
||||
|
||||
// Returns true iff the wrapped list has failed to parse at least one token.
|
||||
bool Failed();
|
||||
|
||||
bool Used();
|
||||
|
||||
protected:
|
||||
FieldTrialListWrapper() = default;
|
||||
};
|
||||
|
||||
namespace field_trial_list_impl {
|
||||
// The LambdaTypeTraits struct provides type information about lambdas in the
|
||||
// template expressions below.
|
||||
template <typename T>
|
||||
struct LambdaTypeTraits : public LambdaTypeTraits<decltype(&T::operator())> {};
|
||||
|
||||
template <typename ClassType, typename RetType, typename SourceType>
|
||||
struct LambdaTypeTraits<RetType* (ClassType::*)(SourceType*) const> {
|
||||
using ret = RetType;
|
||||
using src = SourceType;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TypedFieldTrialListWrapper : FieldTrialListWrapper {
|
||||
public:
|
||||
TypedFieldTrialListWrapper(absl::string_view key,
|
||||
std::function<void(void*, T)> sink)
|
||||
: list_(key), sink_(sink) {}
|
||||
|
||||
void WriteElement(void* struct_to_write, int index) override {
|
||||
sink_(struct_to_write, list_[index]);
|
||||
}
|
||||
|
||||
FieldTrialListBase* GetList() override { return &list_; }
|
||||
|
||||
private:
|
||||
FieldTrialList<T> list_;
|
||||
std::function<void(void*, T)> sink_;
|
||||
};
|
||||
|
||||
} // namespace field_trial_list_impl
|
||||
|
||||
template <typename F,
|
||||
typename Traits = typename field_trial_list_impl::LambdaTypeTraits<F>>
|
||||
FieldTrialListWrapper* FieldTrialStructMember(absl::string_view key,
|
||||
F accessor) {
|
||||
return new field_trial_list_impl::TypedFieldTrialListWrapper<
|
||||
typename Traits::ret>(key, [accessor](void* s, typename Traits::ret t) {
|
||||
*accessor(static_cast<typename Traits::src*>(s)) = t;
|
||||
});
|
||||
}
|
||||
|
||||
// This base class is here to reduce the amount of code we have to generate for
|
||||
// each type of FieldTrialStructList.
|
||||
class FieldTrialStructListBase : public FieldTrialParameterInterface {
|
||||
protected:
|
||||
FieldTrialStructListBase(
|
||||
std::initializer_list<FieldTrialListWrapper*> sub_lists)
|
||||
: FieldTrialParameterInterface(""), sub_lists_() {
|
||||
// Take ownership of the list wrappers generated by FieldTrialStructMember
|
||||
// on the call site.
|
||||
for (FieldTrialListWrapper* const* it = sub_lists.begin();
|
||||
it != sub_lists.end(); it++) {
|
||||
sub_parameters_.push_back((*it)->GetList());
|
||||
sub_lists_.push_back(std::unique_ptr<FieldTrialListWrapper>(*it));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all of our sublists that were in the field trial string had the
|
||||
// same number of elements. If they do, we return that length. If they had
|
||||
// different lengths, any sublist had parse failures or no sublists had
|
||||
// user-supplied values, we return -1.
|
||||
int ValidateAndGetLength();
|
||||
|
||||
bool Parse(absl::optional<std::string> str_value) override;
|
||||
|
||||
std::vector<std::unique_ptr<FieldTrialListWrapper>> sub_lists_;
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
class FieldTrialStructList : public FieldTrialStructListBase {
|
||||
public:
|
||||
FieldTrialStructList(std::initializer_list<FieldTrialListWrapper*> l,
|
||||
std::initializer_list<S> default_list)
|
||||
: FieldTrialStructListBase(l), values_(default_list) {}
|
||||
|
||||
std::vector<S> Get() const { return values_; }
|
||||
operator std::vector<S>() const { return Get(); }
|
||||
const S& operator[](size_t index) const { return values_[index]; }
|
||||
const std::vector<S>* operator->() const { return &values_; }
|
||||
|
||||
protected:
|
||||
void ParseDone() override {
|
||||
int length = ValidateAndGetLength();
|
||||
|
||||
if (length == -1)
|
||||
return;
|
||||
|
||||
std::vector<S> new_values(length, S());
|
||||
|
||||
for (std::unique_ptr<FieldTrialListWrapper>& li : sub_lists_) {
|
||||
if (li->Used()) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
li->WriteElement(&new_values[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
values_.swap(new_values);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<S> values_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
FieldTrialParameterInterface::FieldTrialParameterInterface(
|
||||
absl::string_view key)
|
||||
: key_(key) {}
|
||||
FieldTrialParameterInterface::~FieldTrialParameterInterface() {
|
||||
RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_
|
||||
<< "' never used.";
|
||||
}
|
||||
|
||||
void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
absl::string_view trial_string) {
|
||||
std::map<absl::string_view, FieldTrialParameterInterface*> field_map;
|
||||
FieldTrialParameterInterface* keyless_field = nullptr;
|
||||
for (FieldTrialParameterInterface* field : fields) {
|
||||
field->MarkAsUsed();
|
||||
if (!field->sub_parameters_.empty()) {
|
||||
for (FieldTrialParameterInterface* sub_field : field->sub_parameters_) {
|
||||
RTC_DCHECK(!sub_field->key_.empty());
|
||||
sub_field->MarkAsUsed();
|
||||
field_map[sub_field->key_] = sub_field;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field->key_.empty()) {
|
||||
RTC_DCHECK(!keyless_field);
|
||||
keyless_field = field;
|
||||
} else {
|
||||
field_map[field->key_] = field;
|
||||
}
|
||||
}
|
||||
bool logged_unknown_key = false;
|
||||
|
||||
absl::string_view tail = trial_string;
|
||||
while (!tail.empty()) {
|
||||
size_t key_end = tail.find_first_of(",:");
|
||||
absl::string_view key = tail.substr(0, key_end);
|
||||
absl::optional<std::string> opt_value;
|
||||
if (key_end == absl::string_view::npos) {
|
||||
tail = "";
|
||||
} else if (tail[key_end] == ':') {
|
||||
tail = tail.substr(key_end + 1);
|
||||
size_t value_end = tail.find(',');
|
||||
opt_value.emplace(tail.substr(0, value_end));
|
||||
if (value_end == absl::string_view::npos) {
|
||||
tail = "";
|
||||
} else {
|
||||
tail = tail.substr(value_end + 1);
|
||||
}
|
||||
} else {
|
||||
RTC_DCHECK_EQ(tail[key_end], ',');
|
||||
tail = tail.substr(key_end + 1);
|
||||
}
|
||||
|
||||
auto field = field_map.find(key);
|
||||
if (field != field_map.end()) {
|
||||
if (!field->second->Parse(std::move(opt_value))) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
|
||||
<< "' in trial: \"" << trial_string << "\"";
|
||||
}
|
||||
} else if (!opt_value && keyless_field && !key.empty()) {
|
||||
if (!keyless_field->Parse(std::string(key))) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '"
|
||||
<< key << "' in trial: \"" << trial_string << "\"";
|
||||
}
|
||||
} else if (key.empty() || key[0] != '_') {
|
||||
// "_" is be used to prefix keys that are part of the string for
|
||||
// debugging purposes but not neccessarily used.
|
||||
// e.g. WebRTC-Experiment/param: value, _DebuggingString
|
||||
if (!logged_unknown_key) {
|
||||
RTC_LOG(LS_INFO) << "No field with key: '" << key
|
||||
<< "' (found in trial: \"" << trial_string << "\")";
|
||||
std::string valid_keys;
|
||||
for (const auto& f : field_map) {
|
||||
valid_keys.append(f.first.data(), f.first.size());
|
||||
valid_keys += ", ";
|
||||
}
|
||||
RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys;
|
||||
logged_unknown_key = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (FieldTrialParameterInterface* field : fields) {
|
||||
field->ParseDone();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str) {
|
||||
if (str == "true" || str == "1") {
|
||||
return true;
|
||||
} else if (str == "false" || str == "0") {
|
||||
return false;
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<double> ParseTypedParameter<double>(absl::string_view str) {
|
||||
double value;
|
||||
char unit[2]{0, 0};
|
||||
if (sscanf(std::string(str).c_str(), "%lf%1s", &value, unit) >= 1) {
|
||||
if (unit[0] == '%')
|
||||
return value / 100;
|
||||
return value;
|
||||
} else {
|
||||
return absl::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<int> ParseTypedParameter<int>(absl::string_view str) {
|
||||
int64_t value;
|
||||
if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) {
|
||||
if (rtc::IsValueInRangeForNumericType<int, int64_t>(value)) {
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str) {
|
||||
int64_t value;
|
||||
if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) {
|
||||
if (rtc::IsValueInRangeForNumericType<unsigned, int64_t>(value)) {
|
||||
return static_cast<unsigned>(value);
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<std::string> ParseTypedParameter<std::string>(
|
||||
absl::string_view str) {
|
||||
return std::string(str);
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
|
||||
absl::string_view str) {
|
||||
return ParseOptionalParameter<bool>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
|
||||
absl::string_view str) {
|
||||
return ParseOptionalParameter<int>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<unsigned>>
|
||||
ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<unsigned>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<double>>
|
||||
ParseTypedParameter<absl::optional<double>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<double>(str);
|
||||
}
|
||||
|
||||
FieldTrialFlag::FieldTrialFlag(absl::string_view key)
|
||||
: FieldTrialFlag(key, false) {}
|
||||
|
||||
FieldTrialFlag::FieldTrialFlag(absl::string_view key, bool default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
|
||||
bool FieldTrialFlag::Get() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
webrtc::FieldTrialFlag::operator bool() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) {
|
||||
// Only set the flag if there is no argument provided.
|
||||
if (str_value) {
|
||||
absl::optional<bool> opt_value = ParseTypedParameter<bool>(*str_value);
|
||||
if (!opt_value)
|
||||
return false;
|
||||
value_ = *opt_value;
|
||||
} else {
|
||||
value_ = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFieldTrialEnum::AbstractFieldTrialEnum(
|
||||
absl::string_view key,
|
||||
int default_value,
|
||||
std::map<std::string, int> mapping)
|
||||
: FieldTrialParameterInterface(key),
|
||||
value_(default_value),
|
||||
enum_mapping_(mapping) {
|
||||
for (auto& key_val : enum_mapping_)
|
||||
valid_values_.insert(key_val.second);
|
||||
}
|
||||
AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) =
|
||||
default;
|
||||
AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default;
|
||||
|
||||
bool AbstractFieldTrialEnum::Parse(absl::optional<std::string> str_value) {
|
||||
if (str_value) {
|
||||
auto it = enum_mapping_.find(*str_value);
|
||||
if (it != enum_mapping_.end()) {
|
||||
value_ = it->second;
|
||||
return true;
|
||||
}
|
||||
absl::optional<int> value = ParseTypedParameter<int>(*str_value);
|
||||
if (value.has_value() &&
|
||||
(valid_values_.find(*value) != valid_values_.end())) {
|
||||
value_ = *value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template class FieldTrialParameter<bool>;
|
||||
template class FieldTrialParameter<double>;
|
||||
template class FieldTrialParameter<int>;
|
||||
template class FieldTrialParameter<unsigned>;
|
||||
template class FieldTrialParameter<std::string>;
|
||||
|
||||
template class FieldTrialConstrained<double>;
|
||||
template class FieldTrialConstrained<int>;
|
||||
template class FieldTrialConstrained<unsigned>;
|
||||
|
||||
template class FieldTrialOptional<double>;
|
||||
template class FieldTrialOptional<int>;
|
||||
template class FieldTrialOptional<unsigned>;
|
||||
template class FieldTrialOptional<bool>;
|
||||
template class FieldTrialOptional<std::string>;
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||||
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
// Field trial parser functionality. Provides funcitonality to parse field trial
|
||||
// argument strings in key:value format. Each parameter is described using
|
||||
// key:value, parameters are separated with a ,. Values can't include the comma
|
||||
// character, since there's no quote facility. For most types, white space is
|
||||
// ignored. Parameters are declared with a given type for which an
|
||||
// implementation of ParseTypedParameter should be provided. The
|
||||
// ParseTypedParameter implementation is given whatever is between the : and the
|
||||
// ,. If the key is provided without : a FieldTrialOptional will use nullopt.
|
||||
|
||||
// Example string: "my_optional,my_int:3,my_string:hello"
|
||||
|
||||
// For further description of usage and behavior, see the examples in the unit
|
||||
// tests.
|
||||
|
||||
namespace webrtc {
|
||||
class FieldTrialParameterInterface {
|
||||
public:
|
||||
virtual ~FieldTrialParameterInterface();
|
||||
std::string key() const { return key_; }
|
||||
|
||||
protected:
|
||||
// Protected to allow implementations to provide assignment and copy.
|
||||
FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
|
||||
FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
|
||||
default;
|
||||
explicit FieldTrialParameterInterface(absl::string_view key);
|
||||
friend void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
absl::string_view trial_string);
|
||||
void MarkAsUsed() { used_ = true; }
|
||||
virtual bool Parse(absl::optional<std::string> str_value) = 0;
|
||||
|
||||
virtual void ParseDone() {}
|
||||
|
||||
std::vector<FieldTrialParameterInterface*> sub_parameters_;
|
||||
|
||||
private:
|
||||
std::string key_;
|
||||
bool used_ = false;
|
||||
};
|
||||
|
||||
// ParseFieldTrial function parses the given string and fills the given fields
|
||||
// with extracted values if available.
|
||||
void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
absl::string_view trial_string);
|
||||
|
||||
// Specialize this in code file for custom types. Should return absl::nullopt if
|
||||
// the given string cannot be properly parsed.
|
||||
template <typename T>
|
||||
absl::optional<T> ParseTypedParameter(absl::string_view);
|
||||
|
||||
// This class uses the ParseTypedParameter function to implement a parameter
|
||||
// implementation with an enforced default value.
|
||||
template <typename T>
|
||||
class FieldTrialParameter : public FieldTrialParameterInterface {
|
||||
public:
|
||||
FieldTrialParameter(absl::string_view key, T default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
T Get() const { return value_; }
|
||||
operator T() const { return Get(); }
|
||||
const T* operator->() const { return &value_; }
|
||||
|
||||
void SetForTest(T value) { value_ = value; }
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override {
|
||||
if (str_value) {
|
||||
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||||
if (value.has_value()) {
|
||||
value_ = value.value();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
// This class uses the ParseTypedParameter function to implement a parameter
|
||||
// implementation with an enforced default value and a range constraint. Values
|
||||
// outside the configured range will be ignored.
|
||||
template <typename T>
|
||||
class FieldTrialConstrained : public FieldTrialParameterInterface {
|
||||
public:
|
||||
FieldTrialConstrained(absl::string_view key,
|
||||
T default_value,
|
||||
absl::optional<T> lower_limit,
|
||||
absl::optional<T> upper_limit)
|
||||
: FieldTrialParameterInterface(key),
|
||||
value_(default_value),
|
||||
lower_limit_(lower_limit),
|
||||
upper_limit_(upper_limit) {}
|
||||
T Get() const { return value_; }
|
||||
operator T() const { return Get(); }
|
||||
const T* operator->() const { return &value_; }
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override {
|
||||
if (str_value) {
|
||||
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||||
if (value && (!lower_limit_ || *value >= *lower_limit_) &&
|
||||
(!upper_limit_ || *value <= *upper_limit_)) {
|
||||
value_ = *value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
absl::optional<T> lower_limit_;
|
||||
absl::optional<T> upper_limit_;
|
||||
};
|
||||
|
||||
class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
|
||||
public:
|
||||
AbstractFieldTrialEnum(absl::string_view key,
|
||||
int default_value,
|
||||
std::map<std::string, int> mapping);
|
||||
~AbstractFieldTrialEnum() override;
|
||||
AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override;
|
||||
|
||||
protected:
|
||||
int value_;
|
||||
std::map<std::string, int> enum_mapping_;
|
||||
std::set<int> valid_values_;
|
||||
};
|
||||
|
||||
// The FieldTrialEnum class can be used to quickly define a parser for a
|
||||
// specific enum. It handles values provided as integers and as strings if a
|
||||
// mapping is provided.
|
||||
template <typename T>
|
||||
class FieldTrialEnum : public AbstractFieldTrialEnum {
|
||||
public:
|
||||
FieldTrialEnum(absl::string_view key,
|
||||
T default_value,
|
||||
std::map<std::string, T> mapping)
|
||||
: AbstractFieldTrialEnum(key,
|
||||
static_cast<int>(default_value),
|
||||
ToIntMap(mapping)) {}
|
||||
T Get() const { return static_cast<T>(value_); }
|
||||
operator T() const { return Get(); }
|
||||
|
||||
private:
|
||||
static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
|
||||
std::map<std::string, int> res;
|
||||
for (const auto& it : mapping)
|
||||
res[it.first] = static_cast<int>(it.second);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
// This class uses the ParseTypedParameter function to implement an optional
|
||||
// parameter implementation that can default to absl::nullopt.
|
||||
template <typename T>
|
||||
class FieldTrialOptional : public FieldTrialParameterInterface {
|
||||
public:
|
||||
explicit FieldTrialOptional(absl::string_view key)
|
||||
: FieldTrialParameterInterface(key) {}
|
||||
FieldTrialOptional(absl::string_view key, absl::optional<T> default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
absl::optional<T> GetOptional() const { return value_; }
|
||||
const T& Value() const { return value_.value(); }
|
||||
const T& operator*() const { return value_.value(); }
|
||||
const T* operator->() const { return &value_.value(); }
|
||||
explicit operator bool() const { return value_.has_value(); }
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override {
|
||||
if (str_value) {
|
||||
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||||
if (!value.has_value())
|
||||
return false;
|
||||
value_ = value.value();
|
||||
} else {
|
||||
value_ = absl::nullopt;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
absl::optional<T> value_;
|
||||
};
|
||||
|
||||
// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
|
||||
// are present. If key is missing, evaluates to false. If key is present, but no
|
||||
// explicit value is provided, the flag evaluates to true.
|
||||
class FieldTrialFlag : public FieldTrialParameterInterface {
|
||||
public:
|
||||
explicit FieldTrialFlag(absl::string_view key);
|
||||
FieldTrialFlag(absl::string_view key, bool default_value);
|
||||
bool Get() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override;
|
||||
|
||||
private:
|
||||
bool value_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
absl::optional<absl::optional<T>> ParseOptionalParameter(
|
||||
absl::string_view str) {
|
||||
if (str.empty())
|
||||
return absl::optional<T>();
|
||||
auto parsed = ParseTypedParameter<T>(str);
|
||||
if (parsed.has_value())
|
||||
return parsed;
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<double> ParseTypedParameter<double>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<int> ParseTypedParameter<int>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<std::string> ParseTypedParameter<std::string>(
|
||||
absl::string_view str);
|
||||
|
||||
template <>
|
||||
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
|
||||
absl::string_view str);
|
||||
template <>
|
||||
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
|
||||
absl::string_view str);
|
||||
template <>
|
||||
absl::optional<absl::optional<unsigned>>
|
||||
ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<absl::optional<double>>
|
||||
ParseTypedParameter<absl::optional<double>>(absl::string_view str);
|
||||
|
||||
// Accepts true, false, else parsed with sscanf %i, true if != 0.
|
||||
extern template class FieldTrialParameter<bool>;
|
||||
// Interpreted using sscanf %lf.
|
||||
extern template class FieldTrialParameter<double>;
|
||||
// Interpreted using sscanf %i.
|
||||
extern template class FieldTrialParameter<int>;
|
||||
// Interpreted using sscanf %u.
|
||||
extern template class FieldTrialParameter<unsigned>;
|
||||
// Using the given value as is.
|
||||
extern template class FieldTrialParameter<std::string>;
|
||||
|
||||
extern template class FieldTrialConstrained<double>;
|
||||
extern template class FieldTrialConstrained<int>;
|
||||
extern template class FieldTrialConstrained<unsigned>;
|
||||
|
||||
extern template class FieldTrialOptional<double>;
|
||||
extern template class FieldTrialOptional<int>;
|
||||
extern template class FieldTrialOptional<unsigned>;
|
||||
extern template class FieldTrialOptional<bool>;
|
||||
extern template class FieldTrialOptional<std::string>;
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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/experiments/field_trial_units.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
// Large enough to fit "seconds", the longest supported unit name.
|
||||
#define RTC_TRIAL_UNIT_LENGTH_STR "7"
|
||||
#define RTC_TRIAL_UNIT_SIZE 8
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
struct ValueWithUnit {
|
||||
double value;
|
||||
std::string unit;
|
||||
};
|
||||
|
||||
absl::optional<ValueWithUnit> ParseValueWithUnit(absl::string_view str) {
|
||||
if (str == "inf") {
|
||||
return ValueWithUnit{std::numeric_limits<double>::infinity(), ""};
|
||||
} else if (str == "-inf") {
|
||||
return ValueWithUnit{-std::numeric_limits<double>::infinity(), ""};
|
||||
} else {
|
||||
double double_val;
|
||||
char unit_char[RTC_TRIAL_UNIT_SIZE];
|
||||
unit_char[0] = 0;
|
||||
if (sscanf(std::string(str).c_str(), "%lf%" RTC_TRIAL_UNIT_LENGTH_STR "s",
|
||||
&double_val, unit_char) >= 1) {
|
||||
return ValueWithUnit{double_val, unit_char};
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
absl::optional<DataRate> ParseTypedParameter<DataRate>(absl::string_view str) {
|
||||
absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit.empty() || result->unit == "kbps") {
|
||||
return DataRate::KilobitsPerSec(result->value);
|
||||
} else if (result->unit == "bps") {
|
||||
return DataRate::BitsPerSec(result->value);
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<DataSize> ParseTypedParameter<DataSize>(absl::string_view str) {
|
||||
absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit.empty() || result->unit == "bytes")
|
||||
return DataSize::Bytes(result->value);
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<TimeDelta> ParseTypedParameter<TimeDelta>(
|
||||
absl::string_view str) {
|
||||
absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit == "s" || result->unit == "seconds") {
|
||||
return TimeDelta::Seconds(result->value);
|
||||
} else if (result->unit == "us") {
|
||||
return TimeDelta::Micros(result->value);
|
||||
} else if (result->unit.empty() || result->unit == "ms") {
|
||||
return TimeDelta::Millis(result->value);
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<absl::optional<DataRate>>
|
||||
ParseTypedParameter<absl::optional<DataRate>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<DataRate>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<DataSize>>
|
||||
ParseTypedParameter<absl::optional<DataSize>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<DataSize>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<TimeDelta>>
|
||||
ParseTypedParameter<absl::optional<TimeDelta>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<TimeDelta>(str);
|
||||
}
|
||||
|
||||
template class FieldTrialParameter<DataRate>;
|
||||
template class FieldTrialParameter<DataSize>;
|
||||
template class FieldTrialParameter<TimeDelta>;
|
||||
|
||||
template class FieldTrialConstrained<DataRate>;
|
||||
template class FieldTrialConstrained<DataSize>;
|
||||
template class FieldTrialConstrained<TimeDelta>;
|
||||
|
||||
template class FieldTrialOptional<DataRate>;
|
||||
template class FieldTrialOptional<DataSize>;
|
||||
template class FieldTrialOptional<TimeDelta>;
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <>
|
||||
absl::optional<DataRate> ParseTypedParameter<DataRate>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<DataSize> ParseTypedParameter<DataSize>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<TimeDelta> ParseTypedParameter<TimeDelta>(absl::string_view str);
|
||||
|
||||
extern template class FieldTrialParameter<DataRate>;
|
||||
extern template class FieldTrialParameter<DataSize>;
|
||||
extern template class FieldTrialParameter<TimeDelta>;
|
||||
|
||||
extern template class FieldTrialConstrained<DataRate>;
|
||||
extern template class FieldTrialConstrained<DataSize>;
|
||||
extern template class FieldTrialConstrained<TimeDelta>;
|
||||
|
||||
extern template class FieldTrialOptional<DataRate>;
|
||||
extern template class FieldTrialOptional<DataSize>;
|
||||
extern template class FieldTrialOptional<TimeDelta>;
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/keyframe_interval_settings.h"
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kFieldTrialName[] = "WebRTC-KeyframeInterval";
|
||||
|
||||
} // namespace
|
||||
|
||||
KeyframeIntervalSettings::KeyframeIntervalSettings(
|
||||
const FieldTrialsView* const key_value_config)
|
||||
: min_keyframe_send_interval_ms_("min_keyframe_send_interval_ms") {
|
||||
ParseFieldTrial({&min_keyframe_send_interval_ms_},
|
||||
key_value_config->Lookup(kFieldTrialName));
|
||||
}
|
||||
|
||||
KeyframeIntervalSettings KeyframeIntervalSettings::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return KeyframeIntervalSettings(&field_trial_config);
|
||||
}
|
||||
|
||||
absl::optional<int> KeyframeIntervalSettings::MinKeyframeSendIntervalMs()
|
||||
const {
|
||||
return min_keyframe_send_interval_ms_.GetOptional();
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// TODO(bugs.webrtc.org/10427): Remove and replace with proper configuration
|
||||
// parameter, or move to using FIR if intent is to avoid triggering multiple
|
||||
// times to PLIs corresponding to the same request when RTT is large.
|
||||
class KeyframeIntervalSettings final {
|
||||
public:
|
||||
static KeyframeIntervalSettings ParseFromFieldTrials();
|
||||
|
||||
// Sender side.
|
||||
// The encoded keyframe send rate is <= 1/MinKeyframeSendIntervalMs().
|
||||
absl::optional<int> MinKeyframeSendIntervalMs() const;
|
||||
|
||||
private:
|
||||
explicit KeyframeIntervalSettings(const FieldTrialsView* key_value_config);
|
||||
|
||||
FieldTrialOptional<int> min_keyframe_send_interval_ms_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/min_video_bitrate_experiment.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const int kDefaultMinVideoBitrateBps = 30000;
|
||||
|
||||
namespace {
|
||||
const char kForcedFallbackFieldTrial[] =
|
||||
"WebRTC-VP8-Forced-Fallback-Encoder-v2";
|
||||
const char kMinVideoBitrateExperiment[] = "WebRTC-Video-MinVideoBitrate";
|
||||
|
||||
absl::optional<int> GetFallbackMinBpsFromFieldTrial(VideoCodecType type) {
|
||||
if (type != kVideoCodecVP8) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
const std::string group =
|
||||
webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial);
|
||||
if (group.empty()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int min_pixels; // Ignored.
|
||||
int max_pixels; // Ignored.
|
||||
int min_bps;
|
||||
if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels,
|
||||
&min_bps) != 3) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
if (min_bps <= 0) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
return min_bps;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
absl::optional<DataRate> GetExperimentalMinVideoBitrate(VideoCodecType type) {
|
||||
const absl::optional<int> fallback_min_bitrate_bps =
|
||||
GetFallbackMinBpsFromFieldTrial(type);
|
||||
if (fallback_min_bitrate_bps) {
|
||||
return DataRate::BitsPerSec(*fallback_min_bitrate_bps);
|
||||
}
|
||||
|
||||
if (webrtc::field_trial::IsEnabled(kMinVideoBitrateExperiment)) {
|
||||
webrtc::FieldTrialFlag enabled("Enabled");
|
||||
|
||||
// Backwards-compatibility with an old experiment - a generic minimum which,
|
||||
// if set, applies to all codecs.
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_video_bitrate("br");
|
||||
|
||||
// New experiment - per-codec minimum bitrate.
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_vp8("vp8_br");
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_vp9("vp9_br");
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_av1("av1_br");
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_h264("h264_br");
|
||||
|
||||
webrtc::ParseFieldTrial(
|
||||
{&enabled, &min_video_bitrate, &min_bitrate_vp8, &min_bitrate_vp9,
|
||||
&min_bitrate_av1, &min_bitrate_h264},
|
||||
webrtc::field_trial::FindFullName(kMinVideoBitrateExperiment));
|
||||
|
||||
if (min_video_bitrate) {
|
||||
if (min_bitrate_vp8 || min_bitrate_vp9 || min_bitrate_av1 ||
|
||||
min_bitrate_h264) {
|
||||
// "br" is mutually-exclusive with the other configuration possibilites.
|
||||
RTC_LOG(LS_WARNING) << "Self-contradictory experiment config.";
|
||||
}
|
||||
return *min_video_bitrate;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
return min_bitrate_vp8.GetOptional();
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
|
||||
case kVideoCodecVP9:
|
||||
return min_bitrate_vp9.GetOptional();
|
||||
case kVideoCodecAV1:
|
||||
return min_bitrate_av1.GetOptional();
|
||||
case kVideoCodecH264:
|
||||
return min_bitrate_h264.GetOptional();
|
||||
case kVideoCodecGeneric:
|
||||
case kVideoCodecMultiplex:
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/video/video_codec_type.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
extern const int kDefaultMinVideoBitrateBps;
|
||||
|
||||
// Return the experiment-driven minimum video bitrate.
|
||||
// If no experiment is effective, returns nullopt.
|
||||
absl::optional<DataRate> GetExperimentalMinVideoBitrate(VideoCodecType type);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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/experiments/normalize_simulcast_size_experiment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrial[] = "WebRTC-NormalizeSimulcastResolution";
|
||||
constexpr int kMinSetting = 0;
|
||||
constexpr int kMaxSetting = 5;
|
||||
} // namespace
|
||||
|
||||
absl::optional<int> NormalizeSimulcastSizeExperiment::GetBase2Exponent() {
|
||||
if (!webrtc::field_trial::IsEnabled(kFieldTrial))
|
||||
return absl::nullopt;
|
||||
|
||||
const std::string group = webrtc::field_trial::FindFullName(kFieldTrial);
|
||||
if (group.empty())
|
||||
return absl::nullopt;
|
||||
|
||||
int exponent;
|
||||
if (sscanf(group.c_str(), "Enabled-%d", &exponent) != 1) {
|
||||
RTC_LOG(LS_WARNING) << "No parameter provided.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
if (exponent < kMinSetting || exponent > kMaxSetting) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported exp value provided, value ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
return absl::optional<int>(exponent);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace webrtc {
|
||||
class NormalizeSimulcastSizeExperiment {
|
||||
public:
|
||||
// Returns the base two exponent from field trial.
|
||||
static absl::optional<int> GetBase2Exponent();
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/quality_rampup_experiment.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
QualityRampupExperiment::QualityRampupExperiment(
|
||||
const FieldTrialsView* const key_value_config)
|
||||
: min_pixels_("min_pixels"),
|
||||
min_duration_ms_("min_duration_ms"),
|
||||
max_bitrate_factor_("max_bitrate_factor") {
|
||||
ParseFieldTrial(
|
||||
{&min_pixels_, &min_duration_ms_, &max_bitrate_factor_},
|
||||
key_value_config->Lookup("WebRTC-Video-QualityRampupSettings"));
|
||||
}
|
||||
|
||||
QualityRampupExperiment QualityRampupExperiment::ParseSettings() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return QualityRampupExperiment(&field_trial_config);
|
||||
}
|
||||
|
||||
absl::optional<int> QualityRampupExperiment::MinPixels() const {
|
||||
return min_pixels_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<int> QualityRampupExperiment::MinDurationMs() const {
|
||||
return min_duration_ms_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<double> QualityRampupExperiment::MaxBitrateFactor() const {
|
||||
return max_bitrate_factor_.GetOptional();
|
||||
}
|
||||
|
||||
void QualityRampupExperiment::SetMaxBitrate(int pixels,
|
||||
uint32_t max_bitrate_kbps) {
|
||||
if (!min_pixels_ || pixels < min_pixels_.Value() || max_bitrate_kbps == 0) {
|
||||
return;
|
||||
}
|
||||
max_bitrate_kbps_ = std::max(max_bitrate_kbps_.value_or(0), max_bitrate_kbps);
|
||||
}
|
||||
|
||||
bool QualityRampupExperiment::BwHigh(int64_t now_ms,
|
||||
uint32_t available_bw_kbps) {
|
||||
if (!min_pixels_ || !min_duration_ms_ || !max_bitrate_kbps_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (available_bw_kbps <
|
||||
max_bitrate_kbps_.value() * MaxBitrateFactor().value_or(1)) {
|
||||
start_ms_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!start_ms_)
|
||||
start_ms_ = now_ms;
|
||||
|
||||
return (now_ms - *start_ms_) >= min_duration_ms_.Value();
|
||||
}
|
||||
|
||||
void QualityRampupExperiment::Reset() {
|
||||
start_ms_.reset();
|
||||
max_bitrate_kbps_.reset();
|
||||
}
|
||||
|
||||
bool QualityRampupExperiment::Enabled() const {
|
||||
return min_pixels_ && min_duration_ms_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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 RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class QualityRampupExperiment final {
|
||||
public:
|
||||
static QualityRampupExperiment ParseSettings();
|
||||
|
||||
absl::optional<int> MinPixels() const;
|
||||
absl::optional<int> MinDurationMs() const;
|
||||
absl::optional<double> MaxBitrateFactor() const;
|
||||
|
||||
// Sets the max bitrate and the frame size.
|
||||
// The call has no effect if the frame size is less than `min_pixels_`.
|
||||
void SetMaxBitrate(int pixels, uint32_t max_bitrate_kbps);
|
||||
|
||||
// Returns true if the available bandwidth is a certain percentage
|
||||
// (max_bitrate_factor_) above `max_bitrate_kbps_` for `min_duration_ms_`.
|
||||
bool BwHigh(int64_t now_ms, uint32_t available_bw_kbps);
|
||||
|
||||
void Reset();
|
||||
bool Enabled() const;
|
||||
|
||||
private:
|
||||
explicit QualityRampupExperiment(
|
||||
const FieldTrialsView* const key_value_config);
|
||||
|
||||
FieldTrialOptional<int> min_pixels_;
|
||||
FieldTrialOptional<int> min_duration_ms_;
|
||||
FieldTrialOptional<double> max_bitrate_factor_;
|
||||
|
||||
absl::optional<int64_t> start_ms_;
|
||||
absl::optional<uint32_t> max_bitrate_kbps_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/quality_scaler_settings.h"
|
||||
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
const int kMinFrames = 10;
|
||||
const double kMinScaleFactor = 0.01;
|
||||
} // namespace
|
||||
|
||||
QualityScalerSettings::QualityScalerSettings(
|
||||
const FieldTrialsView& field_trials)
|
||||
: sampling_period_ms_("sampling_period_ms"),
|
||||
average_qp_window_("average_qp_window"),
|
||||
min_frames_("min_frames"),
|
||||
initial_scale_factor_("initial_scale_factor"),
|
||||
scale_factor_("scale_factor"),
|
||||
initial_bitrate_interval_ms_("initial_bitrate_interval_ms"),
|
||||
initial_bitrate_factor_("initial_bitrate_factor") {
|
||||
ParseFieldTrial({&sampling_period_ms_, &average_qp_window_, &min_frames_,
|
||||
&initial_scale_factor_, &scale_factor_,
|
||||
&initial_bitrate_interval_ms_, &initial_bitrate_factor_},
|
||||
field_trials.Lookup("WebRTC-Video-QualityScalerSettings"));
|
||||
}
|
||||
|
||||
absl::optional<int> QualityScalerSettings::SamplingPeriodMs() const {
|
||||
if (sampling_period_ms_ && sampling_period_ms_.Value() <= 0) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported sampling_period_ms value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return sampling_period_ms_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<int> QualityScalerSettings::AverageQpWindow() const {
|
||||
if (average_qp_window_ && average_qp_window_.Value() <= 0) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported average_qp_window value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return average_qp_window_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<int> QualityScalerSettings::MinFrames() const {
|
||||
if (min_frames_ && min_frames_.Value() < kMinFrames) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported min_frames value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return min_frames_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<double> QualityScalerSettings::InitialScaleFactor() const {
|
||||
if (initial_scale_factor_ &&
|
||||
initial_scale_factor_.Value() < kMinScaleFactor) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported initial_scale_factor value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return initial_scale_factor_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<double> QualityScalerSettings::ScaleFactor() const {
|
||||
if (scale_factor_ && scale_factor_.Value() < kMinScaleFactor) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported scale_factor value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return scale_factor_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<int> QualityScalerSettings::InitialBitrateIntervalMs() const {
|
||||
if (initial_bitrate_interval_ms_ &&
|
||||
initial_bitrate_interval_ms_.Value() < 0) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported bitrate_interval value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return initial_bitrate_interval_ms_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<double> QualityScalerSettings::InitialBitrateFactor() const {
|
||||
if (initial_bitrate_factor_ &&
|
||||
initial_bitrate_factor_.Value() < kMinScaleFactor) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported initial_bitrate_factor value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return initial_bitrate_factor_.GetOptional();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class QualityScalerSettings final {
|
||||
public:
|
||||
explicit QualityScalerSettings(const FieldTrialsView& field_trials);
|
||||
|
||||
absl::optional<int> SamplingPeriodMs() const;
|
||||
absl::optional<int> AverageQpWindow() const;
|
||||
absl::optional<int> MinFrames() const;
|
||||
absl::optional<double> InitialScaleFactor() const;
|
||||
absl::optional<double> ScaleFactor() const;
|
||||
absl::optional<int> InitialBitrateIntervalMs() const;
|
||||
absl::optional<double> InitialBitrateFactor() const;
|
||||
|
||||
private:
|
||||
FieldTrialOptional<int> sampling_period_ms_;
|
||||
FieldTrialOptional<int> average_qp_window_;
|
||||
FieldTrialOptional<int> min_frames_;
|
||||
FieldTrialOptional<double> initial_scale_factor_;
|
||||
FieldTrialOptional<double> scale_factor_;
|
||||
FieldTrialOptional<int> initial_bitrate_interval_ms_;
|
||||
FieldTrialOptional<double> initial_bitrate_factor_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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/experiments/quality_scaling_experiment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrial[] = "WebRTC-Video-QualityScaling";
|
||||
constexpr int kMinQp = 1;
|
||||
constexpr int kMaxVp8Qp = 127;
|
||||
constexpr int kMaxVp9Qp = 255;
|
||||
constexpr int kMaxH264Qp = 51;
|
||||
constexpr int kMaxGenericQp = 255;
|
||||
|
||||
#if !defined(WEBRTC_IOS)
|
||||
constexpr char kDefaultQualityScalingSetttings[] =
|
||||
"Enabled-29,95,149,205,24,37,26,36,0.9995,0.9999,1";
|
||||
#endif
|
||||
|
||||
absl::optional<VideoEncoder::QpThresholds> GetThresholds(int low,
|
||||
int high,
|
||||
int max) {
|
||||
if (low < kMinQp || high > max || high < low)
|
||||
return absl::nullopt;
|
||||
|
||||
RTC_LOG(LS_INFO) << "QP thresholds: low: " << low << ", high: " << high;
|
||||
return absl::optional<VideoEncoder::QpThresholds>(
|
||||
VideoEncoder::QpThresholds(low, high));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool QualityScalingExperiment::Enabled(const FieldTrialsView& field_trials) {
|
||||
#if defined(WEBRTC_IOS)
|
||||
return absl::StartsWith(field_trials.Lookup(kFieldTrial), "Enabled");
|
||||
#else
|
||||
return !absl::StartsWith(field_trials.Lookup(kFieldTrial), "Disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
absl::optional<QualityScalingExperiment::Settings>
|
||||
QualityScalingExperiment::ParseSettings(const FieldTrialsView& field_trials) {
|
||||
std::string group = field_trials.Lookup(kFieldTrial);
|
||||
// TODO(http://crbug.com/webrtc/12401): Completely remove the experiment code
|
||||
// after few releases.
|
||||
#if !defined(WEBRTC_IOS)
|
||||
if (group.empty())
|
||||
group = kDefaultQualityScalingSetttings;
|
||||
#endif
|
||||
Settings s;
|
||||
if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%d",
|
||||
&s.vp8_low, &s.vp8_high, &s.vp9_low, &s.vp9_high, &s.h264_low,
|
||||
&s.h264_high, &s.generic_low, &s.generic_high, &s.alpha_high,
|
||||
&s.alpha_low, &s.drop) != 11) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid number of parameters provided.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::QpThresholds>
|
||||
QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type,
|
||||
const FieldTrialsView& field_trials) {
|
||||
const auto settings = ParseSettings(field_trials);
|
||||
if (!settings)
|
||||
return absl::nullopt;
|
||||
|
||||
switch (codec_type) {
|
||||
case kVideoCodecVP8:
|
||||
return GetThresholds(settings->vp8_low, settings->vp8_high, kMaxVp8Qp);
|
||||
case kVideoCodecVP9:
|
||||
return GetThresholds(settings->vp9_low, settings->vp9_high, kMaxVp9Qp);
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
|
||||
case kVideoCodecH264:
|
||||
return GetThresholds(settings->h264_low, settings->h264_high, kMaxH264Qp);
|
||||
case kVideoCodecGeneric:
|
||||
return GetThresholds(settings->generic_low, settings->generic_high,
|
||||
kMaxGenericQp);
|
||||
default:
|
||||
return absl::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
QualityScalingExperiment::Config QualityScalingExperiment::GetConfig(
|
||||
const FieldTrialsView& field_trials) {
|
||||
const auto settings = ParseSettings(field_trials);
|
||||
if (!settings)
|
||||
return Config();
|
||||
|
||||
Config config;
|
||||
config.use_all_drop_reasons = settings->drop > 0;
|
||||
|
||||
if (settings->alpha_high < 0 || settings->alpha_low < settings->alpha_high) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid alpha value provided, using default.";
|
||||
return config;
|
||||
}
|
||||
config.alpha_high = settings->alpha_high;
|
||||
config.alpha_low = settings->alpha_low;
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
class QualityScalingExperiment {
|
||||
public:
|
||||
struct Settings {
|
||||
int vp8_low; // VP8: low QP threshold.
|
||||
int vp8_high; // VP8: high QP threshold.
|
||||
int vp9_low; // VP9: low QP threshold.
|
||||
int vp9_high; // VP9: high QP threshold.
|
||||
int h264_low; // H264: low QP threshold.
|
||||
int h264_high; // H264: high QP threshold.
|
||||
int generic_low; // Generic: low QP threshold.
|
||||
int generic_high; // Generic: high QP threshold.
|
||||
float alpha_high; // `alpha_` for ExpFilter used when checking high QP.
|
||||
float alpha_low; // `alpha_` for ExpFilter used when checking low QP.
|
||||
int drop; // >0 sets `use_all_drop_reasons` to true.
|
||||
};
|
||||
|
||||
// Used by QualityScaler.
|
||||
struct Config {
|
||||
float alpha_high = 0.9995f;
|
||||
float alpha_low = 0.9999f;
|
||||
// If set, all type of dropped frames are used.
|
||||
// Otherwise only dropped frames by MediaOptimization are used.
|
||||
bool use_all_drop_reasons = false;
|
||||
};
|
||||
|
||||
// Returns true if the experiment is enabled.
|
||||
static bool Enabled(const FieldTrialsView& field_trials);
|
||||
|
||||
// Returns settings from field trial.
|
||||
static absl::optional<Settings> ParseSettings(
|
||||
const FieldTrialsView& field_trials);
|
||||
|
||||
// Returns QpThresholds for the `codec_type`.
|
||||
static absl::optional<VideoEncoder::QpThresholds> GetQpThresholds(
|
||||
VideoCodecType codec_type,
|
||||
const FieldTrialsView& field_trials);
|
||||
|
||||
// Returns parsed values. If the parsing fails, default values are returned.
|
||||
static Config GetConfig(const FieldTrialsView& field_trials);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/rate_control_settings.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kDefaultAcceptedQueueMs = 350;
|
||||
|
||||
const int kDefaultMinPushbackTargetBitrateBps = 30000;
|
||||
|
||||
const char kCongestionWindowDefaultFieldTrialString[] =
|
||||
"QueueSize:350,MinBitrate:30000,DropFrame:true";
|
||||
|
||||
const char kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName[] =
|
||||
"WebRTC-UseBaseHeavyVP8TL3RateAllocation";
|
||||
|
||||
bool IsEnabled(const FieldTrialsView* const key_value_config,
|
||||
absl::string_view key) {
|
||||
return absl::StartsWith(key_value_config->Lookup(key), "Enabled");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
constexpr char CongestionWindowConfig::kKey[];
|
||||
|
||||
std::unique_ptr<StructParametersParser> CongestionWindowConfig::Parser() {
|
||||
return StructParametersParser::Create("QueueSize", &queue_size_ms, //
|
||||
"MinBitrate", &min_bitrate_bps,
|
||||
"InitWin", &initial_data_window,
|
||||
"DropFrame", &drop_frame_only);
|
||||
}
|
||||
|
||||
// static
|
||||
CongestionWindowConfig CongestionWindowConfig::Parse(absl::string_view config) {
|
||||
CongestionWindowConfig res;
|
||||
res.Parser()->Parse(config);
|
||||
return res;
|
||||
}
|
||||
|
||||
constexpr char VideoRateControlConfig::kKey[];
|
||||
|
||||
std::unique_ptr<StructParametersParser> VideoRateControlConfig::Parser() {
|
||||
// The empty comments ensures that each pair is on a separate line.
|
||||
return StructParametersParser::Create(
|
||||
"pacing_factor", &pacing_factor, //
|
||||
"alr_probing", &alr_probing, //
|
||||
"vp8_qp_max", &vp8_qp_max, //
|
||||
"vp8_min_pixels", &vp8_min_pixels, //
|
||||
"trust_vp8", &trust_vp8, //
|
||||
"trust_vp9", &trust_vp9, //
|
||||
"bitrate_adjuster", &bitrate_adjuster, //
|
||||
"adjuster_use_headroom", &adjuster_use_headroom, //
|
||||
"vp8_s0_boost", &vp8_s0_boost, //
|
||||
"vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc);
|
||||
}
|
||||
|
||||
RateControlSettings::RateControlSettings(
|
||||
const FieldTrialsView* const key_value_config) {
|
||||
std::string congestion_window_config =
|
||||
key_value_config->Lookup(CongestionWindowConfig::kKey).empty()
|
||||
? kCongestionWindowDefaultFieldTrialString
|
||||
: key_value_config->Lookup(CongestionWindowConfig::kKey);
|
||||
congestion_window_config_ =
|
||||
CongestionWindowConfig::Parse(congestion_window_config);
|
||||
video_config_.vp8_base_heavy_tl3_alloc = IsEnabled(
|
||||
key_value_config, kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName);
|
||||
video_config_.Parser()->Parse(
|
||||
key_value_config->Lookup(VideoRateControlConfig::kKey));
|
||||
}
|
||||
|
||||
RateControlSettings::~RateControlSettings() = default;
|
||||
RateControlSettings::RateControlSettings(RateControlSettings&&) = default;
|
||||
|
||||
RateControlSettings RateControlSettings::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return RateControlSettings(&field_trial_config);
|
||||
}
|
||||
|
||||
RateControlSettings RateControlSettings::ParseFromKeyValueConfig(
|
||||
const FieldTrialsView* const key_value_config) {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return RateControlSettings(key_value_config ? key_value_config
|
||||
: &field_trial_config);
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseCongestionWindow() const {
|
||||
return static_cast<bool>(congestion_window_config_.queue_size_ms);
|
||||
}
|
||||
|
||||
int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const {
|
||||
return congestion_window_config_.queue_size_ms.value_or(
|
||||
kDefaultAcceptedQueueMs);
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseCongestionWindowPushback() const {
|
||||
return congestion_window_config_.queue_size_ms &&
|
||||
congestion_window_config_.min_bitrate_bps;
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseCongestionWindowDropFrameOnly() const {
|
||||
return congestion_window_config_.drop_frame_only;
|
||||
}
|
||||
|
||||
uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps()
|
||||
const {
|
||||
return congestion_window_config_.min_bitrate_bps.value_or(
|
||||
kDefaultMinPushbackTargetBitrateBps);
|
||||
}
|
||||
|
||||
absl::optional<DataSize>
|
||||
RateControlSettings::CongestionWindowInitialDataWindow() const {
|
||||
return congestion_window_config_.initial_data_window;
|
||||
}
|
||||
|
||||
absl::optional<double> RateControlSettings::GetPacingFactor() const {
|
||||
return video_config_.pacing_factor;
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseAlrProbing() const {
|
||||
return video_config_.alr_probing;
|
||||
}
|
||||
|
||||
absl::optional<int> RateControlSettings::LibvpxVp8QpMax() const {
|
||||
if (video_config_.vp8_qp_max &&
|
||||
(*video_config_.vp8_qp_max < 0 || *video_config_.vp8_qp_max > 63)) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported vp8_qp_max_ value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return video_config_.vp8_qp_max;
|
||||
}
|
||||
|
||||
absl::optional<int> RateControlSettings::LibvpxVp8MinPixels() const {
|
||||
if (video_config_.vp8_min_pixels && *video_config_.vp8_min_pixels < 1) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return video_config_.vp8_min_pixels;
|
||||
}
|
||||
|
||||
bool RateControlSettings::LibvpxVp8TrustedRateController() const {
|
||||
return video_config_.trust_vp8;
|
||||
}
|
||||
|
||||
bool RateControlSettings::Vp8BoostBaseLayerQuality() const {
|
||||
return video_config_.vp8_s0_boost;
|
||||
}
|
||||
|
||||
bool RateControlSettings::LibvpxVp9TrustedRateController() const {
|
||||
return video_config_.trust_vp9;
|
||||
}
|
||||
|
||||
bool RateControlSettings::Vp8BaseHeavyTl3RateAllocation() const {
|
||||
return video_config_.vp8_base_heavy_tl3_alloc;
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseEncoderBitrateAdjuster() const {
|
||||
return video_config_.bitrate_adjuster;
|
||||
}
|
||||
|
||||
bool RateControlSettings::BitrateAdjusterCanUseNetworkHeadroom() const {
|
||||
return video_config_.adjuster_use_headroom;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/video_codecs/video_codec.h"
|
||||
#include "rtc_base/experiments/struct_parameters_parser.h"
|
||||
#include "video/config/video_encoder_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
struct CongestionWindowConfig {
|
||||
static constexpr char kKey[] = "WebRTC-CongestionWindow";
|
||||
absl::optional<int> queue_size_ms;
|
||||
absl::optional<int> min_bitrate_bps;
|
||||
absl::optional<DataSize> initial_data_window;
|
||||
bool drop_frame_only = false;
|
||||
std::unique_ptr<StructParametersParser> Parser();
|
||||
static CongestionWindowConfig Parse(absl::string_view config);
|
||||
};
|
||||
|
||||
struct VideoRateControlConfig {
|
||||
static constexpr char kKey[] = "WebRTC-VideoRateControl";
|
||||
absl::optional<double> pacing_factor;
|
||||
bool alr_probing = false;
|
||||
absl::optional<int> vp8_qp_max;
|
||||
absl::optional<int> vp8_min_pixels;
|
||||
bool trust_vp8 = true;
|
||||
bool trust_vp9 = true;
|
||||
bool bitrate_adjuster = true;
|
||||
bool adjuster_use_headroom = true;
|
||||
bool vp8_s0_boost = false;
|
||||
bool vp8_base_heavy_tl3_alloc = false;
|
||||
|
||||
std::unique_ptr<StructParametersParser> Parser();
|
||||
};
|
||||
|
||||
class RateControlSettings final {
|
||||
public:
|
||||
~RateControlSettings();
|
||||
RateControlSettings(RateControlSettings&&);
|
||||
|
||||
static RateControlSettings ParseFromFieldTrials();
|
||||
static RateControlSettings ParseFromKeyValueConfig(
|
||||
const FieldTrialsView* const key_value_config);
|
||||
|
||||
// When CongestionWindowPushback is enabled, the pacer is oblivious to
|
||||
// the congestion window. The relation between outstanding data and
|
||||
// the congestion window affects encoder allocations directly.
|
||||
bool UseCongestionWindow() const;
|
||||
int64_t GetCongestionWindowAdditionalTimeMs() const;
|
||||
bool UseCongestionWindowPushback() const;
|
||||
bool UseCongestionWindowDropFrameOnly() const;
|
||||
uint32_t CongestionWindowMinPushbackTargetBitrateBps() const;
|
||||
absl::optional<DataSize> CongestionWindowInitialDataWindow() const;
|
||||
|
||||
absl::optional<double> GetPacingFactor() const;
|
||||
bool UseAlrProbing() const;
|
||||
|
||||
absl::optional<int> LibvpxVp8QpMax() const;
|
||||
absl::optional<int> LibvpxVp8MinPixels() const;
|
||||
bool LibvpxVp8TrustedRateController() const;
|
||||
bool Vp8BoostBaseLayerQuality() const;
|
||||
bool Vp8DynamicRateSettings() const;
|
||||
bool LibvpxVp9TrustedRateController() const;
|
||||
bool Vp9DynamicRateSettings() const;
|
||||
|
||||
bool Vp8BaseHeavyTl3RateAllocation() const;
|
||||
|
||||
bool UseEncoderBitrateAdjuster() const;
|
||||
bool BitrateAdjusterCanUseNetworkHeadroom() const;
|
||||
|
||||
private:
|
||||
explicit RateControlSettings(const FieldTrialsView* const key_value_config);
|
||||
|
||||
CongestionWindowConfig congestion_window_config_;
|
||||
VideoRateControlConfig video_config_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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/experiments/rtt_mult_experiment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
const char kRttMultExperiment[] = "WebRTC-RttMult";
|
||||
} // namespace
|
||||
|
||||
bool RttMultExperiment::RttMultEnabled() {
|
||||
return !field_trial::IsDisabled(kRttMultExperiment);
|
||||
}
|
||||
|
||||
absl::optional<RttMultExperiment::Settings>
|
||||
RttMultExperiment::GetRttMultValue() {
|
||||
if (!RttMultExperiment::RttMultEnabled()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return RttMultExperiment::Settings{.rtt_mult_setting = 0.9,
|
||||
.rtt_mult_add_cap_ms = 200.0};
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_RTT_MULT_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_RTT_MULT_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RttMultExperiment {
|
||||
public:
|
||||
struct Settings {
|
||||
float rtt_mult_setting; // Jitter buffer size is increased by this factor
|
||||
// times the estimated RTT.
|
||||
float rtt_mult_add_cap_ms; // Jitter buffer size increase is capped by this
|
||||
// value.
|
||||
};
|
||||
|
||||
// Returns true if the experiment is enabled.
|
||||
static bool RttMultEnabled();
|
||||
|
||||
// Returns rtt_mult value and rtt_mult addition cap value from field trial.
|
||||
static absl::optional<RttMultExperiment::Settings> GetRttMultValue();
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_RTT_MULT_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/stable_target_rate_experiment.h"
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrialName[] = "WebRTC-StableTargetRate";
|
||||
} // namespace
|
||||
|
||||
StableTargetRateExperiment::StableTargetRateExperiment(
|
||||
const FieldTrialsView* const key_value_config,
|
||||
double default_video_hysteresis,
|
||||
double default_screenshare_hysteresis)
|
||||
: enabled_("enabled", false),
|
||||
video_hysteresis_factor_("video_hysteresis_factor",
|
||||
default_video_hysteresis),
|
||||
screenshare_hysteresis_factor_("screenshare_hysteresis_factor",
|
||||
default_screenshare_hysteresis) {
|
||||
ParseFieldTrial(
|
||||
{&enabled_, &video_hysteresis_factor_, &screenshare_hysteresis_factor_},
|
||||
key_value_config->Lookup(kFieldTrialName));
|
||||
}
|
||||
|
||||
StableTargetRateExperiment::StableTargetRateExperiment(
|
||||
const StableTargetRateExperiment&) = default;
|
||||
StableTargetRateExperiment::StableTargetRateExperiment(
|
||||
StableTargetRateExperiment&&) = default;
|
||||
|
||||
StableTargetRateExperiment StableTargetRateExperiment::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig config;
|
||||
return ParseFromKeyValueConfig(&config);
|
||||
}
|
||||
|
||||
StableTargetRateExperiment StableTargetRateExperiment::ParseFromKeyValueConfig(
|
||||
const FieldTrialsView* const key_value_config) {
|
||||
return StableTargetRateExperiment(key_value_config,
|
||||
/*default_video_hysteresis=*/1.2,
|
||||
/*default_screenshare_hysteresis=*/1.35);
|
||||
}
|
||||
|
||||
bool StableTargetRateExperiment::IsEnabled() const {
|
||||
return enabled_.Get();
|
||||
}
|
||||
|
||||
double StableTargetRateExperiment::GetVideoHysteresisFactor() const {
|
||||
return video_hysteresis_factor_.Get();
|
||||
}
|
||||
|
||||
double StableTargetRateExperiment::GetScreenshareHysteresisFactor() const {
|
||||
return screenshare_hysteresis_factor_.Get();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_
|
||||
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class StableTargetRateExperiment {
|
||||
public:
|
||||
StableTargetRateExperiment(const StableTargetRateExperiment&);
|
||||
StableTargetRateExperiment(StableTargetRateExperiment&&);
|
||||
static StableTargetRateExperiment ParseFromFieldTrials();
|
||||
static StableTargetRateExperiment ParseFromKeyValueConfig(
|
||||
const FieldTrialsView* const key_value_config);
|
||||
|
||||
bool IsEnabled() const;
|
||||
double GetVideoHysteresisFactor() const;
|
||||
double GetScreenshareHysteresisFactor() const;
|
||||
|
||||
private:
|
||||
explicit StableTargetRateExperiment(
|
||||
const FieldTrialsView* const key_value_config,
|
||||
double default_video_hysteresis,
|
||||
double default_screenshare_hysteresis);
|
||||
|
||||
FieldTrialParameter<bool> enabled_;
|
||||
FieldTrialParameter<double> video_hysteresis_factor_;
|
||||
FieldTrialParameter<double> screenshare_hysteresis_factor_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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 "rtc_base/experiments/struct_parameters_parser.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
size_t FindOrEnd(absl::string_view str, size_t start, char delimiter) {
|
||||
size_t pos = str.find(delimiter, start);
|
||||
pos = (pos == absl::string_view::npos) ? str.length() : pos;
|
||||
return pos;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace struct_parser_impl {
|
||||
namespace {
|
||||
inline void StringEncode(std::string* target, bool val) {
|
||||
*target += rtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, double val) {
|
||||
*target += rtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, int val) {
|
||||
*target += rtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, unsigned val) {
|
||||
*target += rtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, DataRate val) {
|
||||
*target += webrtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, DataSize val) {
|
||||
*target += webrtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, TimeDelta val) {
|
||||
*target += webrtc::ToString(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void StringEncode(std::string* sb, absl::optional<T> val) {
|
||||
if (val)
|
||||
StringEncode(sb, *val);
|
||||
}
|
||||
} // namespace
|
||||
template <typename T>
|
||||
bool TypedParser<T>::Parse(absl::string_view src, void* target) {
|
||||
auto parsed = ParseTypedParameter<T>(std::string(src));
|
||||
if (parsed.has_value())
|
||||
*reinterpret_cast<T*>(target) = *parsed;
|
||||
return parsed.has_value();
|
||||
}
|
||||
template <typename T>
|
||||
void TypedParser<T>::Encode(const void* src, std::string* target) {
|
||||
StringEncode(target, *reinterpret_cast<const T*>(src));
|
||||
}
|
||||
|
||||
template class TypedParser<bool>;
|
||||
template class TypedParser<double>;
|
||||
template class TypedParser<int>;
|
||||
template class TypedParser<unsigned>;
|
||||
template class TypedParser<absl::optional<double>>;
|
||||
template class TypedParser<absl::optional<int>>;
|
||||
template class TypedParser<absl::optional<unsigned>>;
|
||||
|
||||
template class TypedParser<DataRate>;
|
||||
template class TypedParser<DataSize>;
|
||||
template class TypedParser<TimeDelta>;
|
||||
template class TypedParser<absl::optional<DataRate>>;
|
||||
template class TypedParser<absl::optional<DataSize>>;
|
||||
template class TypedParser<absl::optional<TimeDelta>>;
|
||||
} // namespace struct_parser_impl
|
||||
|
||||
StructParametersParser::StructParametersParser(
|
||||
std::vector<struct_parser_impl::MemberParameter> members)
|
||||
: members_(std::move(members)) {}
|
||||
|
||||
void StructParametersParser::Parse(absl::string_view src) {
|
||||
size_t i = 0;
|
||||
while (i < src.length()) {
|
||||
size_t val_end = FindOrEnd(src, i, ',');
|
||||
size_t colon_pos = FindOrEnd(src, i, ':');
|
||||
size_t key_end = std::min(val_end, colon_pos);
|
||||
size_t val_begin = key_end + 1u;
|
||||
absl::string_view key(src.substr(i, key_end - i));
|
||||
absl::string_view opt_value;
|
||||
if (val_end >= val_begin)
|
||||
opt_value = src.substr(val_begin, val_end - val_begin);
|
||||
i = val_end + 1u;
|
||||
bool found = false;
|
||||
for (auto& member : members_) {
|
||||
if (key == member.key) {
|
||||
found = true;
|
||||
if (!member.parser.parse(opt_value, member.member_ptr)) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
|
||||
<< "' in trial: \"" << src << "\"";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// "_" is be used to prefix keys that are part of the string for
|
||||
// debugging purposes but not neccessarily used.
|
||||
// e.g. WebRTC-Experiment/param: value, _DebuggingString
|
||||
if (!found && (key.empty() || key[0] != '_')) {
|
||||
RTC_LOG(LS_INFO) << "No field with key: '" << key
|
||||
<< "' (found in trial: \"" << src << "\")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string StructParametersParser::Encode() const {
|
||||
std::string res;
|
||||
bool first = true;
|
||||
for (const auto& member : members_) {
|
||||
if (!first)
|
||||
res += ",";
|
||||
res += member.key;
|
||||
res += ":";
|
||||
member.parser.encode(member.member_ptr, &res);
|
||||
first = false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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 RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_
|
||||
#define RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/experiments/field_trial_units.h"
|
||||
#include "rtc_base/string_encode.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace struct_parser_impl {
|
||||
struct TypedMemberParser {
|
||||
public:
|
||||
bool (*parse)(absl::string_view src, void* target);
|
||||
void (*encode)(const void* src, std::string* target);
|
||||
};
|
||||
|
||||
struct MemberParameter {
|
||||
const char* key;
|
||||
void* member_ptr;
|
||||
TypedMemberParser parser;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedParser {
|
||||
public:
|
||||
static bool Parse(absl::string_view src, void* target);
|
||||
static void Encode(const void* src, std::string* target);
|
||||
};
|
||||
|
||||
// Instantiated in cc file to avoid duplication during compile. Add additional
|
||||
// parsers as needed. Generally, try to use these suggested types even if the
|
||||
// context where the value is used might require a different type. For instance,
|
||||
// a size_t representing a packet size should use an int parameter as there's no
|
||||
// need to support packet sizes larger than INT32_MAX.
|
||||
extern template class TypedParser<bool>;
|
||||
extern template class TypedParser<double>;
|
||||
extern template class TypedParser<int>;
|
||||
extern template class TypedParser<unsigned>;
|
||||
extern template class TypedParser<absl::optional<double>>;
|
||||
extern template class TypedParser<absl::optional<int>>;
|
||||
extern template class TypedParser<absl::optional<unsigned>>;
|
||||
|
||||
extern template class TypedParser<DataRate>;
|
||||
extern template class TypedParser<DataSize>;
|
||||
extern template class TypedParser<TimeDelta>;
|
||||
extern template class TypedParser<absl::optional<DataRate>>;
|
||||
extern template class TypedParser<absl::optional<DataSize>>;
|
||||
extern template class TypedParser<absl::optional<TimeDelta>>;
|
||||
|
||||
template <typename T>
|
||||
void AddMembers(MemberParameter* out, const char* key, T* member) {
|
||||
*out = MemberParameter{
|
||||
key, member,
|
||||
TypedMemberParser{&TypedParser<T>::Parse, &TypedParser<T>::Encode}};
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void AddMembers(MemberParameter* out,
|
||||
const char* key,
|
||||
T* member,
|
||||
Args... args) {
|
||||
AddMembers(out, key, member);
|
||||
AddMembers(++out, args...);
|
||||
}
|
||||
} // namespace struct_parser_impl
|
||||
|
||||
class StructParametersParser {
|
||||
public:
|
||||
template <typename T, typename... Args>
|
||||
static std::unique_ptr<StructParametersParser> Create(const char* first_key,
|
||||
T* first_member,
|
||||
Args... args) {
|
||||
std::vector<struct_parser_impl::MemberParameter> members(
|
||||
sizeof...(args) / 2 + 1);
|
||||
struct_parser_impl::AddMembers(&members.front(), std::move(first_key),
|
||||
first_member, args...);
|
||||
return absl::WrapUnique(new StructParametersParser(std::move(members)));
|
||||
}
|
||||
|
||||
void Parse(absl::string_view src);
|
||||
std::string Encode() const;
|
||||
|
||||
private:
|
||||
explicit StructParametersParser(
|
||||
std::vector<struct_parser_impl::MemberParameter> members);
|
||||
|
||||
std::vector<struct_parser_impl::MemberParameter> members_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_
|
||||
62
TMessagesProj/jni/voip/webrtc/rtc_base/fake_clock.cc
Normal file
62
TMessagesProj/jni/voip/webrtc/rtc_base/fake_clock.cc
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/fake_clock.h"
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/thread.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
int64_t FakeClock::TimeNanos() const {
|
||||
webrtc::MutexLock lock(&lock_);
|
||||
return time_ns_;
|
||||
}
|
||||
|
||||
void FakeClock::SetTime(webrtc::Timestamp new_time) {
|
||||
webrtc::MutexLock lock(&lock_);
|
||||
RTC_DCHECK(new_time.us() * 1000 >= time_ns_);
|
||||
time_ns_ = new_time.us() * 1000;
|
||||
}
|
||||
|
||||
void FakeClock::AdvanceTime(webrtc::TimeDelta delta) {
|
||||
webrtc::MutexLock lock(&lock_);
|
||||
time_ns_ += delta.ns();
|
||||
}
|
||||
|
||||
void ThreadProcessingFakeClock::SetTime(webrtc::Timestamp time) {
|
||||
clock_.SetTime(time);
|
||||
// If message queues are waiting in a socket select() with a timeout provided
|
||||
// by the OS, they should wake up and dispatch all messages that are ready.
|
||||
ThreadManager::ProcessAllMessageQueuesForTesting();
|
||||
}
|
||||
|
||||
void ThreadProcessingFakeClock::AdvanceTime(webrtc::TimeDelta delta) {
|
||||
clock_.AdvanceTime(delta);
|
||||
ThreadManager::ProcessAllMessageQueuesForTesting();
|
||||
}
|
||||
|
||||
ScopedBaseFakeClock::ScopedBaseFakeClock() {
|
||||
prev_clock_ = SetClockForTesting(this);
|
||||
}
|
||||
|
||||
ScopedBaseFakeClock::~ScopedBaseFakeClock() {
|
||||
SetClockForTesting(prev_clock_);
|
||||
}
|
||||
|
||||
ScopedFakeClock::ScopedFakeClock() {
|
||||
prev_clock_ = SetClockForTesting(this);
|
||||
}
|
||||
|
||||
ScopedFakeClock::~ScopedFakeClock() {
|
||||
SetClockForTesting(prev_clock_);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
83
TMessagesProj/jni/voip/webrtc/rtc_base/fake_clock.h
Normal file
83
TMessagesProj/jni/voip/webrtc/rtc_base/fake_clock.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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_FAKE_CLOCK_H_
|
||||
#define RTC_BASE_FAKE_CLOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Fake clock for use with unit tests, which does not tick on its own.
|
||||
// Starts at time 0.
|
||||
//
|
||||
// TODO(deadbeef): Unify with webrtc::SimulatedClock.
|
||||
class FakeClock : public ClockInterface {
|
||||
public:
|
||||
FakeClock() = default;
|
||||
FakeClock(const FakeClock&) = delete;
|
||||
FakeClock& operator=(const FakeClock&) = delete;
|
||||
~FakeClock() override = default;
|
||||
|
||||
// ClockInterface implementation.
|
||||
int64_t TimeNanos() const override;
|
||||
|
||||
// Methods that can be used by the test to control the time.
|
||||
|
||||
// Should only be used to set a time in the future.
|
||||
void SetTime(webrtc::Timestamp new_time);
|
||||
|
||||
void AdvanceTime(webrtc::TimeDelta delta);
|
||||
|
||||
private:
|
||||
mutable webrtc::Mutex lock_;
|
||||
int64_t time_ns_ RTC_GUARDED_BY(lock_) = 0;
|
||||
};
|
||||
|
||||
class ThreadProcessingFakeClock : public ClockInterface {
|
||||
public:
|
||||
int64_t TimeNanos() const override { return clock_.TimeNanos(); }
|
||||
void SetTime(webrtc::Timestamp time);
|
||||
void AdvanceTime(webrtc::TimeDelta delta);
|
||||
|
||||
private:
|
||||
FakeClock clock_;
|
||||
};
|
||||
|
||||
// Helper class that sets itself as the global clock in its constructor and
|
||||
// unsets it in its destructor.
|
||||
class ScopedBaseFakeClock : public FakeClock {
|
||||
public:
|
||||
ScopedBaseFakeClock();
|
||||
~ScopedBaseFakeClock() override;
|
||||
|
||||
private:
|
||||
ClockInterface* prev_clock_;
|
||||
};
|
||||
|
||||
// TODO(srte): Rename this to reflect that it also does thread processing.
|
||||
class ScopedFakeClock : public ThreadProcessingFakeClock {
|
||||
public:
|
||||
ScopedFakeClock();
|
||||
~ScopedFakeClock() override;
|
||||
|
||||
private:
|
||||
ClockInterface* prev_clock_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_FAKE_CLOCK_H_
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue