Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 14:04:28 +01:00
parent 81b91f4139
commit f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/memory/aligned_malloc.h"
#include <stdlib.h> // for free, malloc
#include <string.h> // for memcpy
#include "rtc_base/checks.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <stdint.h>
#endif
// Reference on memory alignment:
// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
namespace webrtc {
uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
// The pointer should be aligned with `alignment` bytes. The - 1 guarantees
// that it is aligned towards the closest higher (right) address.
return (start_pos + alignment - 1) & ~(alignment - 1);
}
// Alignment must be an integer power of two.
bool ValidAlignment(size_t alignment) {
if (!alignment) {
return false;
}
return (alignment & (alignment - 1)) == 0;
}
void* GetRightAlign(const void* pointer, size_t alignment) {
if (!pointer) {
return NULL;
}
if (!ValidAlignment(alignment)) {
return NULL;
}
uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
}
void* AlignedMalloc(size_t size, size_t alignment) {
if (size == 0) {
return NULL;
}
if (!ValidAlignment(alignment)) {
return NULL;
}
// The memory is aligned towards the lowest address that so only
// alignment - 1 bytes needs to be allocated.
// A pointer to the start of the memory must be stored so that it can be
// retreived for deletion, ergo the sizeof(uintptr_t).
void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
RTC_CHECK(memory_pointer) << "Couldn't allocate memory in AlignedMalloc";
// Aligning after the sizeof(uintptr_t) bytes will leave room for the header
// in the same memory block.
uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
align_start_pos += sizeof(uintptr_t);
uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
// Store the address to the beginning of the memory just before the aligned
// memory.
uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
void* header_pointer = reinterpret_cast<void*>(header_pos);
uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
return aligned_pointer;
}
void AlignedFree(void* mem_block) {
if (mem_block == NULL) {
return;
}
uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
// Read out the address of the AlignedMemory struct from the header.
uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
void* memory_start = reinterpret_cast<void*>(memory_start_pos);
free(memory_start);
}
} // namespace webrtc

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
#define RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
// The functions declared here
// 1) Allocates block of aligned memory.
// 2) Re-calculates a pointer such that it is aligned to a higher or equal
// address.
// Note: alignment must be a power of two. The alignment is in bytes.
#include <stddef.h>
namespace webrtc {
// Returns a pointer to the first boundry of `alignment` bytes following the
// address of `ptr`.
// Note that there is no guarantee that the memory in question is available.
// `ptr` has no requirements other than it can't be NULL.
void* GetRightAlign(const void* ptr, size_t alignment);
// Allocates memory of `size` bytes aligned on an `alignment` boundry.
// The return value is a pointer to the memory. Note that the memory must
// be de-allocated using AlignedFree.
void* AlignedMalloc(size_t size, size_t alignment);
// De-allocates memory created using the AlignedMalloc() API.
void AlignedFree(void* mem_block);
// Templated versions to facilitate usage of aligned malloc without casting
// to and from void*.
template <typename T>
T* GetRightAlign(const T* ptr, size_t alignment) {
return reinterpret_cast<T*>(
GetRightAlign(reinterpret_cast<const void*>(ptr), alignment));
}
template <typename T>
T* AlignedMalloc(size_t size, size_t alignment) {
return reinterpret_cast<T*>(AlignedMalloc(size, alignment));
}
// Deleter for use with unique_ptr. E.g., use as
// std::unique_ptr<Foo, AlignedFreeDeleter> foo;
struct AlignedFreeDeleter {
inline void operator()(void* ptr) const { AlignedFree(ptr); }
};
} // namespace webrtc
#endif // RTC_BASE_MEMORY_ALIGNED_MALLOC_H_

View file

@ -0,0 +1,248 @@
/*
* Copyright 2022 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_
#define RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_
#include <memory>
#include <utility>
#include "rtc_base/checks.h"
namespace webrtc {
// This template allows the instantiation of a pointer to Interface in such a
// way that if it is passed a null pointer, an object of class Default will be
// created, which will be deallocated when the pointer is deleted.
template <typename Interface, typename Default = Interface>
class AlwaysValidPointer {
public:
explicit AlwaysValidPointer(Interface* pointer)
: owned_instance_(pointer ? nullptr : std::make_unique<Default>()),
pointer_(pointer ? pointer : owned_instance_.get()) {
RTC_DCHECK(pointer_);
}
template <typename Arg,
typename std::enable_if<!(std::is_invocable<Arg>::value),
bool>::type = true>
AlwaysValidPointer(Interface* pointer, Arg arg)
: owned_instance_(pointer ? nullptr
: std::make_unique<Default>(std::move(arg))),
pointer_(pointer ? pointer : owned_instance_.get()) {
RTC_DCHECK(pointer_);
}
// Multiple arguments
template <typename Arg1, typename... Args>
AlwaysValidPointer(Interface* pointer, Arg1 arg1, Args... args)
: owned_instance_(pointer
? nullptr
: std::make_unique<Default>(std::move(arg1),
std::move(args...))),
pointer_(pointer ? pointer : owned_instance_.get()) {
RTC_DCHECK(pointer_);
}
// Create a pointer by
// a) using |pointer|, without taking ownership
// b) calling |function| and taking ownership of the result
template <typename Func,
typename std::enable_if<std::is_invocable<Func>::value,
bool>::type = true>
AlwaysValidPointer(Interface* pointer, Func function)
: owned_instance_(pointer ? nullptr : function()),
pointer_(owned_instance_ ? owned_instance_.get() : pointer) {
RTC_DCHECK(pointer_);
}
// Create a pointer by
// a) taking over ownership of |instance|
// b) or fallback to |pointer|, without taking ownership.
// c) or Default.
AlwaysValidPointer(std::unique_ptr<Interface>&& instance, Interface* pointer)
: owned_instance_(
instance
? std::move(instance)
: (pointer == nullptr ? std::make_unique<Default>() : nullptr)),
pointer_(owned_instance_ ? owned_instance_.get() : pointer) {
RTC_DCHECK(pointer_);
}
// Create a pointer by
// a) taking over ownership of |instance|
// b) or fallback to |pointer|, without taking ownership.
// c) or Default (with forwarded args).
template <typename... Args>
AlwaysValidPointer(std::unique_ptr<Interface>&& instance,
Interface* pointer,
Args... args)
: owned_instance_(
instance ? std::move(instance)
: (pointer == nullptr
? std::make_unique<Default>(std::move(args...))
: nullptr)),
pointer_(owned_instance_ ? owned_instance_.get() : pointer) {
RTC_DCHECK(pointer_);
}
Interface* get() { return pointer_; }
Interface* operator->() { return pointer_; }
Interface& operator*() { return *pointer_; }
Interface* get() const { return pointer_; }
Interface* operator->() const { return pointer_; }
Interface& operator*() const { return *pointer_; }
private:
const std::unique_ptr<Interface> owned_instance_;
Interface* const pointer_;
};
// This class is similar to AlwaysValidPointer, but it does not create
// a default object and crashes if none of the input pointers are non-null.
template <typename Interface>
class AlwaysValidPointerNoDefault {
public:
explicit AlwaysValidPointerNoDefault(Interface* pointer) : pointer_(pointer) {
RTC_CHECK(pointer_);
}
// Create a pointer by
// a) taking over ownership of |instance|
// b) or fallback to |pointer|, without taking ownership.
// At least one of the arguments must be non-null.
explicit AlwaysValidPointerNoDefault(std::unique_ptr<Interface> instance,
Interface* pointer = nullptr)
: owned_instance_(std::move(instance)),
pointer_(owned_instance_ ? owned_instance_.get() : pointer) {
RTC_CHECK(pointer_);
}
Interface* get() { return pointer_; }
Interface* operator->() { return pointer_; }
Interface& operator*() { return *pointer_; }
Interface* get() const { return pointer_; }
Interface* operator->() const { return pointer_; }
Interface& operator*() const { return *pointer_; }
private:
const std::unique_ptr<Interface> owned_instance_;
Interface* const pointer_;
};
template <typename T, typename U, typename V, typename W>
bool operator==(const AlwaysValidPointer<T, U>& a,
const AlwaysValidPointer<V, W>& b) {
return a.get() == b.get();
}
template <typename T, typename U, typename V, typename W>
bool operator!=(const AlwaysValidPointer<T, U>& a,
const AlwaysValidPointer<V, W>& b) {
return !(a == b);
}
template <typename T, typename U>
bool operator==(const AlwaysValidPointer<T, U>& a, std::nullptr_t) {
return a.get() == nullptr;
}
template <typename T, typename U>
bool operator!=(const AlwaysValidPointer<T, U>& a, std::nullptr_t) {
return !(a == nullptr);
}
template <typename T, typename U>
bool operator==(std::nullptr_t, const AlwaysValidPointer<T, U>& a) {
return a.get() == nullptr;
}
template <typename T, typename U>
bool operator!=(std::nullptr_t, const AlwaysValidPointer<T, U>& a) {
return !(a == nullptr);
}
template <typename T, typename U>
bool operator==(const AlwaysValidPointerNoDefault<T>& a,
const AlwaysValidPointerNoDefault<U>& b) {
return a.get() == b.get();
}
template <typename T, typename U>
bool operator!=(const AlwaysValidPointerNoDefault<T>& a,
const AlwaysValidPointerNoDefault<U>& b) {
return !(a == b);
}
template <typename T>
bool operator==(const AlwaysValidPointerNoDefault<T>& a, std::nullptr_t) {
return a.get() == nullptr;
}
template <typename T>
bool operator!=(const AlwaysValidPointerNoDefault<T>& a, std::nullptr_t) {
return !(a == nullptr);
}
template <typename T>
bool operator==(std::nullptr_t, const AlwaysValidPointerNoDefault<T>& a) {
return a.get() == nullptr;
}
template <typename T>
bool operator!=(std::nullptr_t, const AlwaysValidPointerNoDefault<T>& a) {
return !(a == nullptr);
}
// Comparison with raw pointer.
template <typename T, typename U, typename V>
bool operator==(const AlwaysValidPointer<T, U>& a, const V* b) {
return a.get() == b;
}
template <typename T, typename U, typename V>
bool operator!=(const AlwaysValidPointer<T, U>& a, const V* b) {
return !(a == b);
}
template <typename T, typename U, typename V>
bool operator==(const T* a, const AlwaysValidPointer<U, V>& b) {
return a == b.get();
}
template <typename T, typename U, typename V>
bool operator!=(const T* a, const AlwaysValidPointer<U, V>& b) {
return !(a == b);
}
template <typename T, typename U>
bool operator==(const AlwaysValidPointerNoDefault<T>& a, const U* b) {
return a.get() == b;
}
template <typename T, typename U>
bool operator!=(const AlwaysValidPointerNoDefault<T>& a, const U* b) {
return !(a == b);
}
template <typename T, typename U>
bool operator==(const T* a, const AlwaysValidPointerNoDefault<U>& b) {
return a == b.get();
}
template <typename T, typename U>
bool operator!=(const T* a, const AlwaysValidPointerNoDefault<U>& b) {
return !(a == b);
}
} // namespace webrtc
#endif // RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_

View file

@ -0,0 +1,197 @@
/*
* 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/memory/fifo_buffer.h"
#include <algorithm>
#include "rtc_base/thread.h"
namespace rtc {
FifoBuffer::FifoBuffer(size_t size)
: state_(SS_OPEN),
buffer_(new char[size]),
buffer_length_(size),
data_length_(0),
read_position_(0),
owner_(Thread::Current()) {
// all events are done on the owner_ thread
}
FifoBuffer::FifoBuffer(size_t size, Thread* owner)
: state_(SS_OPEN),
buffer_(new char[size]),
buffer_length_(size),
data_length_(0),
read_position_(0),
owner_(owner) {
// all events are done on the owner_ thread
}
FifoBuffer::~FifoBuffer() {}
bool FifoBuffer::GetBuffered(size_t* size) const {
webrtc::MutexLock lock(&mutex_);
*size = data_length_;
return true;
}
StreamState FifoBuffer::GetState() const {
webrtc::MutexLock lock(&mutex_);
return state_;
}
StreamResult FifoBuffer::Read(rtc::ArrayView<uint8_t> buffer,
size_t& bytes_read,
int& error) {
webrtc::MutexLock lock(&mutex_);
const bool was_writable = data_length_ < buffer_length_;
size_t copy = 0;
StreamResult result = ReadLocked(buffer.data(), buffer.size(), &copy);
if (result == SR_SUCCESS) {
// If read was successful then adjust the read position and number of
// bytes buffered.
read_position_ = (read_position_ + copy) % buffer_length_;
data_length_ -= copy;
bytes_read = copy;
// if we were full before, and now we're not, post an event
if (!was_writable && copy > 0) {
PostEvent(SE_WRITE, 0);
}
}
return result;
}
StreamResult FifoBuffer::Write(rtc::ArrayView<const uint8_t> buffer,
size_t& bytes_written,
int& error) {
webrtc::MutexLock lock(&mutex_);
const bool was_readable = (data_length_ > 0);
size_t copy = 0;
StreamResult result = WriteLocked(buffer.data(), buffer.size(), &copy);
if (result == SR_SUCCESS) {
// If write was successful then adjust the number of readable bytes.
data_length_ += copy;
bytes_written = copy;
// if we didn't have any data to read before, and now we do, post an event
if (!was_readable && copy > 0) {
PostEvent(SE_READ, 0);
}
}
return result;
}
void FifoBuffer::Close() {
webrtc::MutexLock lock(&mutex_);
state_ = SS_CLOSED;
}
const void* FifoBuffer::GetReadData(size_t* size) {
webrtc::MutexLock lock(&mutex_);
*size = (read_position_ + data_length_ <= buffer_length_)
? data_length_
: buffer_length_ - read_position_;
return &buffer_[read_position_];
}
void FifoBuffer::ConsumeReadData(size_t size) {
webrtc::MutexLock lock(&mutex_);
RTC_DCHECK(size <= data_length_);
const bool was_writable = data_length_ < buffer_length_;
read_position_ = (read_position_ + size) % buffer_length_;
data_length_ -= size;
if (!was_writable && size > 0) {
PostEvent(SE_WRITE, 0);
}
}
void* FifoBuffer::GetWriteBuffer(size_t* size) {
webrtc::MutexLock lock(&mutex_);
if (state_ == SS_CLOSED) {
return nullptr;
}
// if empty, reset the write position to the beginning, so we can get
// the biggest possible block
if (data_length_ == 0) {
read_position_ = 0;
}
const size_t write_position =
(read_position_ + data_length_) % buffer_length_;
*size = (write_position > read_position_ || data_length_ == 0)
? buffer_length_ - write_position
: read_position_ - write_position;
return &buffer_[write_position];
}
void FifoBuffer::ConsumeWriteBuffer(size_t size) {
webrtc::MutexLock lock(&mutex_);
RTC_DCHECK(size <= buffer_length_ - data_length_);
const bool was_readable = (data_length_ > 0);
data_length_ += size;
if (!was_readable && size > 0) {
PostEvent(SE_READ, 0);
}
}
StreamResult FifoBuffer::ReadLocked(void* buffer,
size_t bytes,
size_t* bytes_read) {
if (data_length_ == 0) {
return (state_ != SS_CLOSED) ? SR_BLOCK : SR_EOS;
}
const size_t available = data_length_;
const size_t read_position = read_position_ % buffer_length_;
const size_t copy = std::min(bytes, available);
const size_t tail_copy = std::min(copy, buffer_length_ - read_position);
char* const p = static_cast<char*>(buffer);
memcpy(p, &buffer_[read_position], tail_copy);
memcpy(p + tail_copy, &buffer_[0], copy - tail_copy);
if (bytes_read) {
*bytes_read = copy;
}
return SR_SUCCESS;
}
StreamResult FifoBuffer::WriteLocked(const void* buffer,
size_t bytes,
size_t* bytes_written) {
if (state_ == SS_CLOSED) {
return SR_EOS;
}
if (data_length_ >= buffer_length_) {
return SR_BLOCK;
}
const size_t available = buffer_length_ - data_length_;
const size_t write_position =
(read_position_ + data_length_) % buffer_length_;
const size_t copy = std::min(bytes, available);
const size_t tail_copy = std::min(copy, buffer_length_ - write_position);
const char* const p = static_cast<const char*>(buffer);
memcpy(&buffer_[write_position], p, tail_copy);
memcpy(&buffer_[0], p + tail_copy, copy - tail_copy);
if (bytes_written) {
*bytes_written = copy;
}
return SR_SUCCESS;
}
} // namespace rtc

View file

@ -0,0 +1,118 @@
/*
* 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_MEMORY_FIFO_BUFFER_H_
#define RTC_BASE_MEMORY_FIFO_BUFFER_H_
#include <memory>
#include "api/task_queue/pending_task_safety_flag.h"
#include "rtc_base/stream.h"
#include "rtc_base/synchronization/mutex.h"
namespace rtc {
// FifoBuffer allows for efficient, thread-safe buffering of data between
// writer and reader.
class FifoBuffer final : public StreamInterface {
public:
// Creates a FIFO buffer with the specified capacity.
explicit FifoBuffer(size_t length);
// Creates a FIFO buffer with the specified capacity and owner
FifoBuffer(size_t length, Thread* owner);
~FifoBuffer() override;
FifoBuffer(const FifoBuffer&) = delete;
FifoBuffer& operator=(const FifoBuffer&) = delete;
// Gets the amount of data currently readable from the buffer.
bool GetBuffered(size_t* data_len) const;
// StreamInterface methods
StreamState GetState() const override;
StreamResult Read(rtc::ArrayView<uint8_t> buffer,
size_t& bytes_read,
int& error) override;
StreamResult Write(rtc::ArrayView<const uint8_t> buffer,
size_t& bytes_written,
int& error) override;
void Close() override;
// Seek to a byte offset from the beginning of the stream. Returns false if
// the stream does not support seeking, or cannot seek to the specified
// position.
bool SetPosition(size_t position);
// Get the byte offset of the current position from the start of the stream.
// Returns false if the position is not known.
bool GetPosition(size_t* position) const;
// Seek to the start of the stream.
bool Rewind() { return SetPosition(0); }
// GetReadData returns a pointer to a buffer which is owned by the stream.
// The buffer contains data_len bytes. null is returned if no data is
// available, or if the method fails. If the caller processes the data, it
// must call ConsumeReadData with the number of processed bytes. GetReadData
// does not require a matching call to ConsumeReadData if the data is not
// processed. Read and ConsumeReadData invalidate the buffer returned by
// GetReadData.
const void* GetReadData(size_t* data_len);
void ConsumeReadData(size_t used);
// GetWriteBuffer returns a pointer to a buffer which is owned by the stream.
// The buffer has a capacity of buf_len bytes. null is returned if there is
// no buffer available, or if the method fails. The call may write data to
// the buffer, and then call ConsumeWriteBuffer with the number of bytes
// written. GetWriteBuffer does not require a matching call to
// ConsumeWriteData if no data is written. Write and
// ConsumeWriteData invalidate the buffer returned by GetWriteBuffer.
void* GetWriteBuffer(size_t* buf_len);
void ConsumeWriteBuffer(size_t used);
private:
void PostEvent(int events, int err) {
owner_->PostTask(webrtc::SafeTask(
task_safety_.flag(),
[this, events, err]() { SignalEvent(this, events, err); }));
}
// Helper method that implements Read. Caller must acquire a lock
// when calling this method.
StreamResult ReadLocked(void* buffer, size_t bytes, size_t* bytes_read)
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Helper method that implements Write. Caller must acquire a lock
// when calling this method.
StreamResult WriteLocked(const void* buffer,
size_t bytes,
size_t* bytes_written)
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
webrtc::ScopedTaskSafety task_safety_;
// keeps the opened/closed state of the stream
StreamState state_ RTC_GUARDED_BY(mutex_);
// the allocated buffer
std::unique_ptr<char[]> buffer_ RTC_GUARDED_BY(mutex_);
// size of the allocated buffer
const size_t buffer_length_;
// amount of readable data in the buffer
size_t data_length_ RTC_GUARDED_BY(mutex_);
// offset to the readable data
size_t read_position_ RTC_GUARDED_BY(mutex_);
// stream callbacks are dispatched on this thread
Thread* const owner_;
// object lock
mutable webrtc::Mutex mutex_;
};
} // namespace rtc
#endif // RTC_BASE_MEMORY_FIFO_BUFFER_H_