Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 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 "logging/rtc_event_log/encoder/bit_writer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
size_t BitsToBytes(size_t bits) {
|
||||
return (bits / 8) + (bits % 8 > 0 ? 1 : 0);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void BitWriter::WriteBits(uint64_t val, size_t bit_count) {
|
||||
RTC_DCHECK(valid_);
|
||||
const bool success = bit_writer_.WriteBits(val, bit_count);
|
||||
RTC_DCHECK(success);
|
||||
written_bits_ += bit_count;
|
||||
}
|
||||
|
||||
void BitWriter::WriteBits(absl::string_view input) {
|
||||
RTC_DCHECK(valid_);
|
||||
for (char c : input) {
|
||||
WriteBits(static_cast<unsigned char>(c), CHAR_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns everything that was written so far.
|
||||
// Nothing more may be written after this is called.
|
||||
std::string BitWriter::GetString() {
|
||||
RTC_DCHECK(valid_);
|
||||
valid_ = false;
|
||||
|
||||
buffer_.resize(BitsToBytes(written_bits_));
|
||||
written_bits_ = 0;
|
||||
|
||||
std::string result;
|
||||
std::swap(buffer_, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 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 LOGGING_RTC_EVENT_LOG_ENCODER_BIT_WRITER_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_BIT_WRITER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/bit_buffer.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Wrap BitBufferWriter and extend its functionality by (1) keeping track of
|
||||
// the number of bits written and (2) owning its buffer.
|
||||
class BitWriter final {
|
||||
public:
|
||||
explicit BitWriter(size_t byte_count)
|
||||
: buffer_(byte_count, '\0'),
|
||||
bit_writer_(reinterpret_cast<uint8_t*>(&buffer_[0]), buffer_.size()),
|
||||
written_bits_(0),
|
||||
valid_(true) {
|
||||
RTC_DCHECK_GT(byte_count, 0);
|
||||
}
|
||||
|
||||
BitWriter(const BitWriter&) = delete;
|
||||
BitWriter& operator=(const BitWriter&) = delete;
|
||||
|
||||
void WriteBits(uint64_t val, size_t bit_count);
|
||||
|
||||
void WriteBits(absl::string_view input);
|
||||
|
||||
// Returns everything that was written so far.
|
||||
// Nothing more may be written after this is called.
|
||||
std::string GetString();
|
||||
|
||||
private:
|
||||
std::string buffer_;
|
||||
rtc::BitBufferWriter bit_writer_;
|
||||
// Note: Counting bits instead of bytes wraps around earlier than it has to,
|
||||
// which means the maximum length is lower than it could be. We don't expect
|
||||
// to go anywhere near the limit, though, so this is good enough.
|
||||
size_t written_bits_;
|
||||
bool valid_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_BIT_WRITER_H_
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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 "logging/rtc_event_log/encoder/blob_encoding.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "logging/rtc_event_log/encoder/var_int.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
std::string EncodeBlobs(const std::vector<std::string>& blobs) {
|
||||
RTC_DCHECK(!blobs.empty());
|
||||
|
||||
size_t result_length_bound = kMaxVarIntLengthBytes * blobs.size();
|
||||
for (const auto& blob : blobs) {
|
||||
// Providing an input so long that it would cause a wrap-around is an error.
|
||||
RTC_DCHECK_GE(result_length_bound + blob.length(), result_length_bound);
|
||||
result_length_bound += blob.length();
|
||||
}
|
||||
|
||||
std::string result;
|
||||
result.reserve(result_length_bound);
|
||||
|
||||
// First, encode all of the lengths.
|
||||
for (absl::string_view blob : blobs) {
|
||||
result += EncodeVarInt(blob.length());
|
||||
}
|
||||
|
||||
// Second, encode the actual blobs.
|
||||
for (absl::string_view blob : blobs) {
|
||||
result.append(blob.data(), blob.length());
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(result.size(), result_length_bound);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<absl::string_view> DecodeBlobs(absl::string_view encoded_blobs,
|
||||
size_t num_of_blobs) {
|
||||
if (encoded_blobs.empty()) {
|
||||
RTC_LOG(LS_WARNING) << "Corrupt input; empty input.";
|
||||
return std::vector<absl::string_view>();
|
||||
}
|
||||
|
||||
if (num_of_blobs == 0u) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Corrupt input; number of blobs must be greater than 0.";
|
||||
return std::vector<absl::string_view>();
|
||||
}
|
||||
|
||||
// Read the lengths of all blobs.
|
||||
std::vector<uint64_t> lengths(num_of_blobs);
|
||||
for (size_t i = 0; i < num_of_blobs; ++i) {
|
||||
bool success = false;
|
||||
std::tie(success, encoded_blobs) = DecodeVarInt(encoded_blobs, &lengths[i]);
|
||||
if (!success) {
|
||||
RTC_LOG(LS_WARNING) << "Corrupt input; varint decoding failed.";
|
||||
return std::vector<absl::string_view>();
|
||||
}
|
||||
}
|
||||
|
||||
// Read the blobs themselves.
|
||||
std::vector<absl::string_view> blobs(num_of_blobs);
|
||||
for (size_t i = 0; i < num_of_blobs; ++i) {
|
||||
if (lengths[i] > encoded_blobs.length()) {
|
||||
RTC_LOG(LS_WARNING) << "Corrupt input; blob sizes exceed input size.";
|
||||
return std::vector<absl::string_view>();
|
||||
}
|
||||
|
||||
blobs[i] = encoded_blobs.substr(0, lengths[i]);
|
||||
encoded_blobs = encoded_blobs.substr(lengths[i]);
|
||||
}
|
||||
|
||||
if (!encoded_blobs.empty()) {
|
||||
RTC_LOG(LS_WARNING) << "Corrupt input; unrecognized trailer.";
|
||||
return std::vector<absl::string_view>();
|
||||
}
|
||||
|
||||
return blobs;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_BLOB_ENCODING_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_BLOB_ENCODING_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Encode/decode a sequence of strings, whose length is not known to be
|
||||
// discernable from the blob itself (i.e. without being transmitted OOB),
|
||||
// in a way that would allow us to separate them again on the decoding side.
|
||||
// The number of blobs is assumed to be transmitted OOB. For example, if
|
||||
// multiple sequences of different blobs are sent, but all sequences contain
|
||||
// the same number of blobs, it is beneficial to not encode the number of blobs.
|
||||
//
|
||||
// EncodeBlobs() must be given a non-empty vector. The blobs themselves may
|
||||
// be equal to "", though.
|
||||
// EncodeBlobs() may not fail.
|
||||
// EncodeBlobs() never returns the empty string.
|
||||
//
|
||||
// Calling DecodeBlobs() on an empty string, or with `num_of_blobs` set to 0,
|
||||
// is an error.
|
||||
// DecodeBlobs() returns an empty vector if it fails, e.g. due to a mismatch
|
||||
// between `num_of_blobs` and `encoded_blobs`, which can happen if
|
||||
// `encoded_blobs` is corrupted.
|
||||
// When successful, DecodeBlobs() returns a vector of string_view objects,
|
||||
// which refer to the original input (`encoded_blobs`), and therefore may
|
||||
// not outlive it.
|
||||
//
|
||||
// Note that the returned std::string might have been reserved for significantly
|
||||
// more memory than it ends up using. If the caller to EncodeBlobs() intends
|
||||
// to store the result long-term, they should consider shrink_to_fit()-ing it.
|
||||
std::string EncodeBlobs(const std::vector<std::string>& blobs);
|
||||
std::vector<absl::string_view> DecodeBlobs(absl::string_view encoded_blobs,
|
||||
size_t num_of_blobs);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_BLOB_ENCODING_H_
|
||||
|
|
@ -0,0 +1,839 @@
|
|||
/*
|
||||
* 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 "logging/rtc_event_log/encoder/delta_encoding.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "logging/rtc_event_log/encoder/bit_writer.h"
|
||||
#include "logging/rtc_event_log/encoder/var_int.h"
|
||||
#include "rtc_base/bit_buffer.h"
|
||||
#include "rtc_base/bitstream_reader.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
// TODO(eladalon): Only build the decoder in tools and unit tests.
|
||||
|
||||
bool g_force_unsigned_for_testing = false;
|
||||
bool g_force_signed_for_testing = false;
|
||||
|
||||
size_t BitsToBytes(size_t bits) {
|
||||
return (bits / 8) + (bits % 8 > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
// TODO(eladalon): Replace by something more efficient.
|
||||
uint64_t UnsignedBitWidth(uint64_t input, bool zero_val_as_zero_width = false) {
|
||||
if (zero_val_as_zero_width && input == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t width = 0;
|
||||
do { // input == 0 -> width == 1
|
||||
width += 1;
|
||||
input >>= 1;
|
||||
} while (input != 0);
|
||||
return width;
|
||||
}
|
||||
|
||||
uint64_t SignedBitWidth(uint64_t max_pos_magnitude,
|
||||
uint64_t max_neg_magnitude) {
|
||||
const uint64_t bitwidth_pos = UnsignedBitWidth(max_pos_magnitude, true);
|
||||
const uint64_t bitwidth_neg =
|
||||
(max_neg_magnitude > 0) ? UnsignedBitWidth(max_neg_magnitude - 1, true)
|
||||
: 0;
|
||||
return 1 + std::max(bitwidth_pos, bitwidth_neg);
|
||||
}
|
||||
|
||||
// Return the maximum integer of a given bit width.
|
||||
// Examples:
|
||||
// MaxUnsignedValueOfBitWidth(1) = 0x01
|
||||
// MaxUnsignedValueOfBitWidth(6) = 0x3f
|
||||
// MaxUnsignedValueOfBitWidth(8) = 0xff
|
||||
// MaxUnsignedValueOfBitWidth(32) = 0xffffffff
|
||||
uint64_t MaxUnsignedValueOfBitWidth(uint64_t bit_width) {
|
||||
RTC_DCHECK_GE(bit_width, 1);
|
||||
RTC_DCHECK_LE(bit_width, 64);
|
||||
return (bit_width == 64) ? std::numeric_limits<uint64_t>::max()
|
||||
: ((static_cast<uint64_t>(1) << bit_width) - 1);
|
||||
}
|
||||
|
||||
// Computes the delta between `previous` and `current`, under the assumption
|
||||
// that wrap-around occurs after `width` is exceeded.
|
||||
uint64_t UnsignedDelta(uint64_t previous, uint64_t current, uint64_t bit_mask) {
|
||||
return (current - previous) & bit_mask;
|
||||
}
|
||||
|
||||
// Determines the encoding type (e.g. fixed-size encoding).
|
||||
// Given an encoding type, may also distinguish between some variants of it
|
||||
// (e.g. which fields of the fixed-size encoding are explicitly mentioned by
|
||||
// the header, and which are implicitly assumed to hold certain default values).
|
||||
enum class EncodingType {
|
||||
kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt = 0,
|
||||
kFixedSizeSignedDeltasEarlyWrapAndOptSupported = 1,
|
||||
kReserved1 = 2,
|
||||
kReserved2 = 3,
|
||||
kNumberOfEncodingTypes // Keep last
|
||||
};
|
||||
|
||||
// The width of each field in the encoding header. Note that this is the
|
||||
// width in case the field exists; not all fields occur in all encoding types.
|
||||
constexpr size_t kBitsInHeaderForEncodingType = 2;
|
||||
constexpr size_t kBitsInHeaderForDeltaWidthBits = 6;
|
||||
constexpr size_t kBitsInHeaderForSignedDeltas = 1;
|
||||
constexpr size_t kBitsInHeaderForValuesOptional = 1;
|
||||
constexpr size_t kBitsInHeaderForValueWidthBits = 6;
|
||||
|
||||
static_assert(static_cast<size_t>(EncodingType::kNumberOfEncodingTypes) <=
|
||||
1 << kBitsInHeaderForEncodingType,
|
||||
"Not all encoding types fit.");
|
||||
|
||||
// Default values for when the encoding header does not specify explicitly.
|
||||
constexpr bool kDefaultSignedDeltas = false;
|
||||
constexpr bool kDefaultValuesOptional = false;
|
||||
constexpr uint64_t kDefaultValueWidthBits = 64;
|
||||
|
||||
// Parameters for fixed-size delta-encoding/decoding.
|
||||
// These are tailored for the sequence which will be encoded (e.g. widths).
|
||||
class FixedLengthEncodingParameters final {
|
||||
public:
|
||||
static bool ValidParameters(uint64_t delta_width_bits,
|
||||
bool signed_deltas,
|
||||
bool values_optional,
|
||||
uint64_t value_width_bits) {
|
||||
return (1 <= delta_width_bits && delta_width_bits <= 64 &&
|
||||
1 <= value_width_bits && value_width_bits <= 64 &&
|
||||
delta_width_bits <= value_width_bits);
|
||||
}
|
||||
|
||||
FixedLengthEncodingParameters(uint64_t delta_width_bits,
|
||||
bool signed_deltas,
|
||||
bool values_optional,
|
||||
uint64_t value_width_bits)
|
||||
: delta_width_bits_(delta_width_bits),
|
||||
signed_deltas_(signed_deltas),
|
||||
values_optional_(values_optional),
|
||||
value_width_bits_(value_width_bits),
|
||||
delta_mask_(MaxUnsignedValueOfBitWidth(delta_width_bits_)),
|
||||
value_mask_(MaxUnsignedValueOfBitWidth(value_width_bits_)) {
|
||||
RTC_DCHECK(ValidParameters(delta_width_bits, signed_deltas, values_optional,
|
||||
value_width_bits));
|
||||
}
|
||||
|
||||
// Number of bits necessary to hold the widest(*) of the deltas between the
|
||||
// values in the sequence.
|
||||
// (*) - Widest might not be the largest, if signed deltas are used.
|
||||
uint64_t delta_width_bits() const { return delta_width_bits_; }
|
||||
|
||||
// Whether deltas are signed.
|
||||
bool signed_deltas() const { return signed_deltas_; }
|
||||
|
||||
// Whether the values of the sequence are optional. That is, it may be
|
||||
// that some of them do not have a value (not even a sentinel value indicating
|
||||
// invalidity).
|
||||
bool values_optional() const { return values_optional_; }
|
||||
|
||||
// Number of bits necessary to hold the largest value in the sequence.
|
||||
uint64_t value_width_bits() const { return value_width_bits_; }
|
||||
|
||||
// Masks where only the bits relevant to the deltas/values are turned on.
|
||||
uint64_t delta_mask() const { return delta_mask_; }
|
||||
uint64_t value_mask() const { return value_mask_; }
|
||||
|
||||
void SetSignedDeltas(bool signed_deltas) { signed_deltas_ = signed_deltas; }
|
||||
void SetDeltaWidthBits(uint64_t delta_width_bits) {
|
||||
delta_width_bits_ = delta_width_bits;
|
||||
delta_mask_ = MaxUnsignedValueOfBitWidth(delta_width_bits);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t delta_width_bits_; // Normally const, but mutable in tests.
|
||||
bool signed_deltas_; // Normally const, but mutable in tests.
|
||||
const bool values_optional_;
|
||||
const uint64_t value_width_bits_;
|
||||
|
||||
uint64_t delta_mask_; // Normally const, but mutable in tests.
|
||||
const uint64_t value_mask_;
|
||||
};
|
||||
|
||||
// Performs delta-encoding of a single (non-empty) sequence of values, using
|
||||
// an encoding where all deltas are encoded using the same number of bits.
|
||||
// (With the exception of optional elements; those are encoded as a bit vector
|
||||
// with one bit per element, plus a fixed number of bits for every element that
|
||||
// has a value.)
|
||||
class FixedLengthDeltaEncoder final {
|
||||
public:
|
||||
// See webrtc::EncodeDeltas() for general details.
|
||||
// This function return a bit pattern that would allow the decoder to
|
||||
// determine whether it was produced by FixedLengthDeltaEncoder, and can
|
||||
// therefore be decoded by FixedLengthDeltaDecoder, or whether it was produced
|
||||
// by a different encoder.
|
||||
static std::string EncodeDeltas(
|
||||
absl::optional<uint64_t> base,
|
||||
const std::vector<absl::optional<uint64_t>>& values);
|
||||
|
||||
FixedLengthDeltaEncoder(const FixedLengthDeltaEncoder&) = delete;
|
||||
FixedLengthDeltaEncoder& operator=(const FixedLengthDeltaEncoder&) = delete;
|
||||
|
||||
private:
|
||||
// Calculate min/max values of unsigned/signed deltas, given the bit width
|
||||
// of all the values in the series.
|
||||
static void CalculateMinAndMaxDeltas(
|
||||
absl::optional<uint64_t> base,
|
||||
const std::vector<absl::optional<uint64_t>>& values,
|
||||
uint64_t bit_width,
|
||||
uint64_t* max_unsigned_delta,
|
||||
uint64_t* max_pos_signed_delta,
|
||||
uint64_t* min_neg_signed_delta);
|
||||
|
||||
// No effect outside of unit tests.
|
||||
// In unit tests, may lead to forcing signed/unsigned deltas, etc.
|
||||
static void ConsiderTestOverrides(FixedLengthEncodingParameters* params,
|
||||
uint64_t delta_width_bits_signed,
|
||||
uint64_t delta_width_bits_unsigned);
|
||||
|
||||
// FixedLengthDeltaEncoder objects are to be created by EncodeDeltas() and
|
||||
// released by it before it returns. They're mostly a convenient way to
|
||||
// avoid having to pass a lot of state between different functions.
|
||||
// Therefore, it was deemed acceptable to let them have a reference to
|
||||
// `values`, whose lifetime must exceed the lifetime of `this`.
|
||||
FixedLengthDeltaEncoder(const FixedLengthEncodingParameters& params,
|
||||
absl::optional<uint64_t> base,
|
||||
const std::vector<absl::optional<uint64_t>>& values,
|
||||
size_t existent_values_count);
|
||||
|
||||
// Perform delta-encoding using the parameters given to the ctor on the
|
||||
// sequence of values given to the ctor.
|
||||
std::string Encode();
|
||||
|
||||
// Exact lengths.
|
||||
size_t OutputLengthBytes(size_t existent_values_count) const;
|
||||
size_t HeaderLengthBits() const;
|
||||
size_t EncodedDeltasLengthBits(size_t existent_values_count) const;
|
||||
|
||||
// Encode the compression parameters into the stream.
|
||||
void EncodeHeader();
|
||||
|
||||
// Encode a given delta into the stream.
|
||||
void EncodeDelta(uint64_t previous, uint64_t current);
|
||||
void EncodeUnsignedDelta(uint64_t previous, uint64_t current);
|
||||
void EncodeSignedDelta(uint64_t previous, uint64_t current);
|
||||
|
||||
// The parameters according to which encoding will be done (width of
|
||||
// fields, whether signed deltas should be used, etc.)
|
||||
const FixedLengthEncodingParameters params_;
|
||||
|
||||
// The encoding scheme assumes that at least one value is transmitted OOB,
|
||||
// so that the first value can be encoded as a delta from that OOB value,
|
||||
// which is `base_`.
|
||||
const absl::optional<uint64_t> base_;
|
||||
|
||||
// The values to be encoded.
|
||||
// Note: This is a non-owning reference. See comment above ctor for details.
|
||||
const std::vector<absl::optional<uint64_t>>& values_;
|
||||
|
||||
// Buffer into which encoded values will be written.
|
||||
// This is created dynmically as a way to enforce that the rest of the
|
||||
// ctor has finished running when this is constructed, so that the lower
|
||||
// bound on the buffer size would be guaranteed correct.
|
||||
std::unique_ptr<BitWriter> writer_;
|
||||
};
|
||||
|
||||
// TODO(eladalon): Reduce the number of passes.
|
||||
std::string FixedLengthDeltaEncoder::EncodeDeltas(
|
||||
absl::optional<uint64_t> base,
|
||||
const std::vector<absl::optional<uint64_t>>& values) {
|
||||
RTC_DCHECK(!values.empty());
|
||||
|
||||
// As a special case, if all of the elements are identical to the base,
|
||||
// (including, for optional fields, about their existence/non-existence),
|
||||
// the empty string is used to signal that.
|
||||
if (std::all_of(
|
||||
values.cbegin(), values.cend(),
|
||||
[base](absl::optional<uint64_t> val) { return val == base; })) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
bool non_decreasing = true;
|
||||
uint64_t max_value_including_base = base.value_or(0u);
|
||||
size_t existent_values_count = 0;
|
||||
{
|
||||
uint64_t previous = base.value_or(0u);
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
if (!values[i].has_value()) {
|
||||
continue;
|
||||
}
|
||||
++existent_values_count;
|
||||
non_decreasing &= (previous <= values[i].value());
|
||||
max_value_including_base =
|
||||
std::max(max_value_including_base, values[i].value());
|
||||
previous = values[i].value();
|
||||
}
|
||||
}
|
||||
|
||||
// If the sequence is non-decreasing, it may be assumed to have width = 64;
|
||||
// there's no reason to encode the actual max width in the encoding header.
|
||||
const uint64_t value_width_bits =
|
||||
non_decreasing ? 64 : UnsignedBitWidth(max_value_including_base);
|
||||
|
||||
uint64_t max_unsigned_delta;
|
||||
uint64_t max_pos_signed_delta;
|
||||
uint64_t min_neg_signed_delta;
|
||||
CalculateMinAndMaxDeltas(base, values, value_width_bits, &max_unsigned_delta,
|
||||
&max_pos_signed_delta, &min_neg_signed_delta);
|
||||
|
||||
const uint64_t delta_width_bits_unsigned =
|
||||
UnsignedBitWidth(max_unsigned_delta);
|
||||
const uint64_t delta_width_bits_signed =
|
||||
SignedBitWidth(max_pos_signed_delta, min_neg_signed_delta);
|
||||
|
||||
// Note: Preference for unsigned if the two have the same width (efficiency).
|
||||
const bool signed_deltas =
|
||||
delta_width_bits_signed < delta_width_bits_unsigned;
|
||||
const uint64_t delta_width_bits =
|
||||
signed_deltas ? delta_width_bits_signed : delta_width_bits_unsigned;
|
||||
|
||||
const bool values_optional =
|
||||
!base.has_value() || (existent_values_count < values.size());
|
||||
|
||||
FixedLengthEncodingParameters params(delta_width_bits, signed_deltas,
|
||||
values_optional, value_width_bits);
|
||||
|
||||
// No effect in production.
|
||||
ConsiderTestOverrides(¶ms, delta_width_bits_signed,
|
||||
delta_width_bits_unsigned);
|
||||
|
||||
FixedLengthDeltaEncoder encoder(params, base, values, existent_values_count);
|
||||
return encoder.Encode();
|
||||
}
|
||||
|
||||
void FixedLengthDeltaEncoder::CalculateMinAndMaxDeltas(
|
||||
absl::optional<uint64_t> base,
|
||||
const std::vector<absl::optional<uint64_t>>& values,
|
||||
uint64_t bit_width,
|
||||
uint64_t* max_unsigned_delta_out,
|
||||
uint64_t* max_pos_signed_delta_out,
|
||||
uint64_t* min_neg_signed_delta_out) {
|
||||
RTC_DCHECK(!values.empty());
|
||||
RTC_DCHECK(max_unsigned_delta_out);
|
||||
RTC_DCHECK(max_pos_signed_delta_out);
|
||||
RTC_DCHECK(min_neg_signed_delta_out);
|
||||
|
||||
const uint64_t bit_mask = MaxUnsignedValueOfBitWidth(bit_width);
|
||||
|
||||
uint64_t max_unsigned_delta = 0;
|
||||
uint64_t max_pos_signed_delta = 0;
|
||||
uint64_t min_neg_signed_delta = 0;
|
||||
|
||||
absl::optional<uint64_t> prev = base;
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
if (!values[i].has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prev.has_value()) {
|
||||
// If the base is non-existent, the first existent value is encoded as
|
||||
// a varint, rather than as a delta.
|
||||
RTC_DCHECK(!base.has_value());
|
||||
prev = values[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint64_t current = values[i].value();
|
||||
|
||||
const uint64_t forward_delta = UnsignedDelta(*prev, current, bit_mask);
|
||||
const uint64_t backward_delta = UnsignedDelta(current, *prev, bit_mask);
|
||||
|
||||
max_unsigned_delta = std::max(max_unsigned_delta, forward_delta);
|
||||
|
||||
if (forward_delta < backward_delta) {
|
||||
max_pos_signed_delta = std::max(max_pos_signed_delta, forward_delta);
|
||||
} else {
|
||||
min_neg_signed_delta = std::max(min_neg_signed_delta, backward_delta);
|
||||
}
|
||||
|
||||
prev = current;
|
||||
}
|
||||
|
||||
*max_unsigned_delta_out = max_unsigned_delta;
|
||||
*max_pos_signed_delta_out = max_pos_signed_delta;
|
||||
*min_neg_signed_delta_out = min_neg_signed_delta;
|
||||
}
|
||||
|
||||
void FixedLengthDeltaEncoder::ConsiderTestOverrides(
|
||||
FixedLengthEncodingParameters* params,
|
||||
uint64_t delta_width_bits_signed,
|
||||
uint64_t delta_width_bits_unsigned) {
|
||||
if (g_force_unsigned_for_testing) {
|
||||
params->SetDeltaWidthBits(delta_width_bits_unsigned);
|
||||
params->SetSignedDeltas(false);
|
||||
} else if (g_force_signed_for_testing) {
|
||||
params->SetDeltaWidthBits(delta_width_bits_signed);
|
||||
params->SetSignedDeltas(true);
|
||||
} else {
|
||||
// Unchanged.
|
||||
}
|
||||
}
|
||||
|
||||
FixedLengthDeltaEncoder::FixedLengthDeltaEncoder(
|
||||
const FixedLengthEncodingParameters& params,
|
||||
absl::optional<uint64_t> base,
|
||||
const std::vector<absl::optional<uint64_t>>& values,
|
||||
size_t existent_values_count)
|
||||
: params_(params), base_(base), values_(values) {
|
||||
RTC_DCHECK(!values_.empty());
|
||||
writer_ =
|
||||
std::make_unique<BitWriter>(OutputLengthBytes(existent_values_count));
|
||||
}
|
||||
|
||||
std::string FixedLengthDeltaEncoder::Encode() {
|
||||
EncodeHeader();
|
||||
|
||||
if (params_.values_optional()) {
|
||||
// Encode which values exist and which don't.
|
||||
for (absl::optional<uint64_t> value : values_) {
|
||||
writer_->WriteBits(value.has_value() ? 1u : 0u, 1);
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<uint64_t> previous = base_;
|
||||
for (absl::optional<uint64_t> value : values_) {
|
||||
if (!value.has_value()) {
|
||||
RTC_DCHECK(params_.values_optional());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!previous.has_value()) {
|
||||
// If the base is non-existent, the first existent value is encoded as
|
||||
// a varint, rather than as a delta.
|
||||
RTC_DCHECK(!base_.has_value());
|
||||
writer_->WriteBits(EncodeVarInt(value.value()));
|
||||
} else {
|
||||
EncodeDelta(previous.value(), value.value());
|
||||
}
|
||||
|
||||
previous = value;
|
||||
}
|
||||
|
||||
return writer_->GetString();
|
||||
}
|
||||
|
||||
size_t FixedLengthDeltaEncoder::OutputLengthBytes(
|
||||
size_t existent_values_count) const {
|
||||
return BitsToBytes(HeaderLengthBits() +
|
||||
EncodedDeltasLengthBits(existent_values_count));
|
||||
}
|
||||
|
||||
size_t FixedLengthDeltaEncoder::HeaderLengthBits() const {
|
||||
if (params_.signed_deltas() == kDefaultSignedDeltas &&
|
||||
params_.values_optional() == kDefaultValuesOptional &&
|
||||
params_.value_width_bits() == kDefaultValueWidthBits) {
|
||||
return kBitsInHeaderForEncodingType + kBitsInHeaderForDeltaWidthBits;
|
||||
} else {
|
||||
return kBitsInHeaderForEncodingType + kBitsInHeaderForDeltaWidthBits +
|
||||
kBitsInHeaderForSignedDeltas + kBitsInHeaderForValuesOptional +
|
||||
kBitsInHeaderForValueWidthBits;
|
||||
}
|
||||
}
|
||||
|
||||
size_t FixedLengthDeltaEncoder::EncodedDeltasLengthBits(
|
||||
size_t existent_values_count) const {
|
||||
if (!params_.values_optional()) {
|
||||
return values_.size() * params_.delta_width_bits();
|
||||
} else {
|
||||
RTC_DCHECK_EQ(std::count_if(values_.begin(), values_.end(),
|
||||
[](absl::optional<uint64_t> val) {
|
||||
return val.has_value();
|
||||
}),
|
||||
existent_values_count);
|
||||
// One bit for each delta, to indicate if the value exists, and delta_width
|
||||
// for each existent value, to indicate the delta itself.
|
||||
// If base_ is non-existent, the first value (if any) is encoded as a varint
|
||||
// rather than as a delta.
|
||||
const size_t existence_bitmap_size_bits = 1 * values_.size();
|
||||
const bool first_value_is_varint =
|
||||
!base_.has_value() && existent_values_count >= 1;
|
||||
const size_t first_value_varint_size_bits = 8 * kMaxVarIntLengthBytes;
|
||||
const size_t deltas_count = existent_values_count - first_value_is_varint;
|
||||
const size_t deltas_size_bits = deltas_count * params_.delta_width_bits();
|
||||
return existence_bitmap_size_bits + first_value_varint_size_bits +
|
||||
deltas_size_bits;
|
||||
}
|
||||
}
|
||||
|
||||
void FixedLengthDeltaEncoder::EncodeHeader() {
|
||||
RTC_DCHECK(writer_);
|
||||
|
||||
const EncodingType encoding_type =
|
||||
(params_.value_width_bits() == kDefaultValueWidthBits &&
|
||||
params_.signed_deltas() == kDefaultSignedDeltas &&
|
||||
params_.values_optional() == kDefaultValuesOptional)
|
||||
? EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt
|
||||
: EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported;
|
||||
|
||||
writer_->WriteBits(static_cast<uint64_t>(encoding_type),
|
||||
kBitsInHeaderForEncodingType);
|
||||
|
||||
// Note: Since it's meaningless for a field to be of width 0, when it comes
|
||||
// to fields that relate widths, we encode width 1 as 0, width 2 as 1,
|
||||
|
||||
writer_->WriteBits(params_.delta_width_bits() - 1,
|
||||
kBitsInHeaderForDeltaWidthBits);
|
||||
|
||||
if (encoding_type == EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt) {
|
||||
return;
|
||||
}
|
||||
|
||||
writer_->WriteBits(static_cast<uint64_t>(params_.signed_deltas()),
|
||||
kBitsInHeaderForSignedDeltas);
|
||||
writer_->WriteBits(static_cast<uint64_t>(params_.values_optional()),
|
||||
kBitsInHeaderForValuesOptional);
|
||||
writer_->WriteBits(params_.value_width_bits() - 1,
|
||||
kBitsInHeaderForValueWidthBits);
|
||||
}
|
||||
|
||||
void FixedLengthDeltaEncoder::EncodeDelta(uint64_t previous, uint64_t current) {
|
||||
if (params_.signed_deltas()) {
|
||||
EncodeSignedDelta(previous, current);
|
||||
} else {
|
||||
EncodeUnsignedDelta(previous, current);
|
||||
}
|
||||
}
|
||||
|
||||
void FixedLengthDeltaEncoder::EncodeUnsignedDelta(uint64_t previous,
|
||||
uint64_t current) {
|
||||
RTC_DCHECK(writer_);
|
||||
const uint64_t delta = UnsignedDelta(previous, current, params_.value_mask());
|
||||
writer_->WriteBits(delta, params_.delta_width_bits());
|
||||
}
|
||||
|
||||
void FixedLengthDeltaEncoder::EncodeSignedDelta(uint64_t previous,
|
||||
uint64_t current) {
|
||||
RTC_DCHECK(writer_);
|
||||
|
||||
const uint64_t forward_delta =
|
||||
UnsignedDelta(previous, current, params_.value_mask());
|
||||
const uint64_t backward_delta =
|
||||
UnsignedDelta(current, previous, params_.value_mask());
|
||||
|
||||
uint64_t delta;
|
||||
if (forward_delta <= backward_delta) {
|
||||
delta = forward_delta;
|
||||
} else {
|
||||
// Compute the unsigned representation of a negative delta.
|
||||
// This is the two's complement representation of this negative value,
|
||||
// when deltas are of width params_.delta_mask().
|
||||
RTC_DCHECK_GE(params_.delta_mask(), backward_delta);
|
||||
RTC_DCHECK_LT(params_.delta_mask() - backward_delta, params_.delta_mask());
|
||||
delta = params_.delta_mask() - backward_delta + 1;
|
||||
RTC_DCHECK_LE(delta, params_.delta_mask());
|
||||
}
|
||||
|
||||
writer_->WriteBits(delta, params_.delta_width_bits());
|
||||
}
|
||||
|
||||
// Perform decoding of a a delta-encoded stream, extracting the original
|
||||
// sequence of values.
|
||||
class FixedLengthDeltaDecoder final {
|
||||
public:
|
||||
// Checks whether FixedLengthDeltaDecoder is a suitable decoder for this
|
||||
// bitstream. Note that this does NOT imply that stream is valid, and will
|
||||
// be decoded successfully. It DOES imply that all other decoder classes
|
||||
// will fail to decode this input, though.
|
||||
static bool IsSuitableDecoderFor(absl::string_view input);
|
||||
|
||||
// Assuming that `input` is the result of fixed-size delta-encoding
|
||||
// that took place with the same value to `base` and over `num_of_deltas`
|
||||
// original values, this will return the sequence of original values.
|
||||
// If an error occurs (can happen if `input` is corrupt), an empty
|
||||
// vector will be returned.
|
||||
static std::vector<absl::optional<uint64_t>> DecodeDeltas(
|
||||
absl::string_view input,
|
||||
absl::optional<uint64_t> base,
|
||||
size_t num_of_deltas);
|
||||
|
||||
FixedLengthDeltaDecoder(const FixedLengthDeltaDecoder&) = delete;
|
||||
FixedLengthDeltaDecoder& operator=(const FixedLengthDeltaDecoder&) = delete;
|
||||
|
||||
private:
|
||||
// Reads the encoding header in `input` and returns a FixedLengthDeltaDecoder
|
||||
// with the corresponding configuration, that can be used to decode the
|
||||
// values in `input`.
|
||||
// If the encoding header is corrupt (contains an illegal configuration),
|
||||
// nullptr will be returned.
|
||||
// When a valid FixedLengthDeltaDecoder is returned, this does not mean that
|
||||
// the entire stream is free of error. Rather, only the encoding header is
|
||||
// examined and guaranteed.
|
||||
static std::unique_ptr<FixedLengthDeltaDecoder> Create(
|
||||
absl::string_view input,
|
||||
absl::optional<uint64_t> base,
|
||||
size_t num_of_deltas);
|
||||
|
||||
// FixedLengthDeltaDecoder objects are to be created by DecodeDeltas() and
|
||||
// released by it before it returns. They're mostly a convenient way to
|
||||
// avoid having to pass a lot of state between different functions.
|
||||
// Therefore, it was deemed acceptable that `reader` does not own the buffer
|
||||
// it reads, meaning the lifetime of `this` must not exceed the lifetime
|
||||
// of `reader`'s underlying buffer.
|
||||
FixedLengthDeltaDecoder(BitstreamReader reader,
|
||||
const FixedLengthEncodingParameters& params,
|
||||
absl::optional<uint64_t> base,
|
||||
size_t num_of_deltas);
|
||||
|
||||
// Perform the decoding using the parameters given to the ctor.
|
||||
std::vector<absl::optional<uint64_t>> Decode();
|
||||
|
||||
// Add `delta` to `base` to produce the next value in a sequence.
|
||||
// The delta is applied as signed/unsigned depending on the parameters
|
||||
// given to the ctor. Wrap-around is taken into account according to the
|
||||
// values' width, as specified by the aforementioned encoding parameters.
|
||||
uint64_t ApplyDelta(uint64_t base, uint64_t delta) const;
|
||||
|
||||
// Helpers for ApplyDelta().
|
||||
uint64_t ApplyUnsignedDelta(uint64_t base, uint64_t delta) const;
|
||||
uint64_t ApplySignedDelta(uint64_t base, uint64_t delta) const;
|
||||
|
||||
// Reader of the input stream to be decoded. Does not own that buffer.
|
||||
// See comment above ctor for details.
|
||||
BitstreamReader reader_;
|
||||
|
||||
// The parameters according to which encoding will be done (width of
|
||||
// fields, whether signed deltas should be used, etc.)
|
||||
const FixedLengthEncodingParameters params_;
|
||||
|
||||
// The encoding scheme assumes that at least one value is transmitted OOB,
|
||||
// so that the first value can be encoded as a delta from that OOB value,
|
||||
// which is `base_`.
|
||||
const absl::optional<uint64_t> base_;
|
||||
|
||||
// The number of values to be known to be decoded.
|
||||
const size_t num_of_deltas_;
|
||||
};
|
||||
|
||||
bool FixedLengthDeltaDecoder::IsSuitableDecoderFor(absl::string_view input) {
|
||||
BitstreamReader reader(input);
|
||||
uint64_t encoding_type_bits = reader.ReadBits(kBitsInHeaderForEncodingType);
|
||||
if (!reader.Ok()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto encoding_type = static_cast<EncodingType>(encoding_type_bits);
|
||||
return encoding_type ==
|
||||
EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt ||
|
||||
encoding_type ==
|
||||
EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported;
|
||||
}
|
||||
|
||||
std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::DecodeDeltas(
|
||||
absl::string_view input,
|
||||
absl::optional<uint64_t> base,
|
||||
size_t num_of_deltas) {
|
||||
auto decoder = FixedLengthDeltaDecoder::Create(input, base, num_of_deltas);
|
||||
if (!decoder) {
|
||||
return std::vector<absl::optional<uint64_t>>();
|
||||
}
|
||||
|
||||
return decoder->Decode();
|
||||
}
|
||||
|
||||
std::unique_ptr<FixedLengthDeltaDecoder> FixedLengthDeltaDecoder::Create(
|
||||
absl::string_view input,
|
||||
absl::optional<uint64_t> base,
|
||||
size_t num_of_deltas) {
|
||||
BitstreamReader reader(input);
|
||||
// Encoding type
|
||||
uint32_t encoding_type_bits = reader.ReadBits(kBitsInHeaderForEncodingType);
|
||||
if (!reader.Ok()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const EncodingType encoding = static_cast<EncodingType>(encoding_type_bits);
|
||||
if (encoding != EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt &&
|
||||
encoding !=
|
||||
EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported) {
|
||||
RTC_LOG(LS_WARNING) << "Unrecognized encoding type.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// See encoding for +1's rationale.
|
||||
const uint64_t delta_width_bits =
|
||||
reader.ReadBits(kBitsInHeaderForDeltaWidthBits) + 1;
|
||||
RTC_DCHECK_LE(delta_width_bits, 64);
|
||||
|
||||
// signed_deltas, values_optional, value_width_bits
|
||||
bool signed_deltas;
|
||||
bool values_optional;
|
||||
uint64_t value_width_bits;
|
||||
if (encoding == EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt) {
|
||||
signed_deltas = kDefaultSignedDeltas;
|
||||
values_optional = kDefaultValuesOptional;
|
||||
value_width_bits = kDefaultValueWidthBits;
|
||||
} else {
|
||||
signed_deltas = reader.Read<bool>();
|
||||
values_optional = reader.Read<bool>();
|
||||
// See encoding for +1's rationale.
|
||||
value_width_bits = reader.ReadBits(kBitsInHeaderForValueWidthBits) + 1;
|
||||
RTC_DCHECK_LE(value_width_bits, 64);
|
||||
}
|
||||
|
||||
if (!reader.Ok()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Note: Because of the way the parameters are read, it is not possible
|
||||
// for illegal values to be read. We check nevertheless, in case the code
|
||||
// changes in the future in a way that breaks this promise.
|
||||
if (!FixedLengthEncodingParameters::ValidParameters(
|
||||
delta_width_bits, signed_deltas, values_optional, value_width_bits)) {
|
||||
RTC_LOG(LS_WARNING) << "Corrupt log; illegal encoding parameters.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FixedLengthEncodingParameters params(delta_width_bits, signed_deltas,
|
||||
values_optional, value_width_bits);
|
||||
return absl::WrapUnique(
|
||||
new FixedLengthDeltaDecoder(reader, params, base, num_of_deltas));
|
||||
}
|
||||
|
||||
FixedLengthDeltaDecoder::FixedLengthDeltaDecoder(
|
||||
BitstreamReader reader,
|
||||
const FixedLengthEncodingParameters& params,
|
||||
absl::optional<uint64_t> base,
|
||||
size_t num_of_deltas)
|
||||
: reader_(reader),
|
||||
params_(params),
|
||||
base_(base),
|
||||
num_of_deltas_(num_of_deltas) {
|
||||
RTC_DCHECK(reader_.Ok());
|
||||
}
|
||||
|
||||
std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::Decode() {
|
||||
RTC_DCHECK(reader_.Ok());
|
||||
std::vector<bool> existing_values(num_of_deltas_);
|
||||
if (params_.values_optional()) {
|
||||
for (size_t i = 0; i < num_of_deltas_; ++i) {
|
||||
existing_values[i] = reader_.Read<bool>();
|
||||
}
|
||||
} else {
|
||||
std::fill(existing_values.begin(), existing_values.end(), true);
|
||||
}
|
||||
|
||||
absl::optional<uint64_t> previous = base_;
|
||||
std::vector<absl::optional<uint64_t>> values(num_of_deltas_);
|
||||
|
||||
for (size_t i = 0; i < num_of_deltas_; ++i) {
|
||||
if (!existing_values[i]) {
|
||||
RTC_DCHECK(params_.values_optional());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!previous) {
|
||||
// If the base is non-existent, the first existent value is encoded as
|
||||
// a varint, rather than as a delta.
|
||||
RTC_DCHECK(!base_.has_value());
|
||||
values[i] = DecodeVarInt(reader_);
|
||||
} else {
|
||||
uint64_t delta = reader_.ReadBits(params_.delta_width_bits());
|
||||
values[i] = ApplyDelta(*previous, delta);
|
||||
}
|
||||
|
||||
previous = values[i];
|
||||
}
|
||||
|
||||
if (!reader_.Ok()) {
|
||||
values = {};
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
uint64_t FixedLengthDeltaDecoder::ApplyDelta(uint64_t base,
|
||||
uint64_t delta) const {
|
||||
RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
|
||||
RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
|
||||
return params_.signed_deltas() ? ApplySignedDelta(base, delta)
|
||||
: ApplyUnsignedDelta(base, delta);
|
||||
}
|
||||
|
||||
uint64_t FixedLengthDeltaDecoder::ApplyUnsignedDelta(uint64_t base,
|
||||
uint64_t delta) const {
|
||||
// Note: May still be used if signed deltas used.
|
||||
RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
|
||||
RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
|
||||
return (base + delta) & params_.value_mask();
|
||||
}
|
||||
|
||||
uint64_t FixedLengthDeltaDecoder::ApplySignedDelta(uint64_t base,
|
||||
uint64_t delta) const {
|
||||
RTC_DCHECK(params_.signed_deltas());
|
||||
RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
|
||||
RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
|
||||
|
||||
const uint64_t top_bit = static_cast<uint64_t>(1)
|
||||
<< (params_.delta_width_bits() - 1);
|
||||
|
||||
const bool positive_delta = ((delta & top_bit) == 0);
|
||||
if (positive_delta) {
|
||||
return ApplyUnsignedDelta(base, delta);
|
||||
}
|
||||
|
||||
const uint64_t delta_abs = (~delta & params_.delta_mask()) + 1;
|
||||
return (base - delta_abs) & params_.value_mask();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string EncodeDeltas(absl::optional<uint64_t> base,
|
||||
const std::vector<absl::optional<uint64_t>>& values) {
|
||||
// TODO(eladalon): Support additional encodings.
|
||||
return FixedLengthDeltaEncoder::EncodeDeltas(base, values);
|
||||
}
|
||||
|
||||
std::vector<absl::optional<uint64_t>> DecodeDeltas(
|
||||
absl::string_view input,
|
||||
absl::optional<uint64_t> base,
|
||||
size_t num_of_deltas) {
|
||||
RTC_DCHECK_GT(num_of_deltas, 0); // Allows empty vector to indicate error.
|
||||
|
||||
// The empty string is a special case indicating that all values were equal
|
||||
// to the base.
|
||||
if (input.empty()) {
|
||||
std::vector<absl::optional<uint64_t>> result(num_of_deltas);
|
||||
std::fill(result.begin(), result.end(), base);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (FixedLengthDeltaDecoder::IsSuitableDecoderFor(input)) {
|
||||
return FixedLengthDeltaDecoder::DecodeDeltas(input, base, num_of_deltas);
|
||||
}
|
||||
|
||||
RTC_LOG(LS_WARNING) << "Could not decode delta-encoded stream.";
|
||||
return std::vector<absl::optional<uint64_t>>();
|
||||
}
|
||||
|
||||
void SetFixedLengthEncoderDeltaSignednessForTesting(bool signedness) {
|
||||
g_force_unsigned_for_testing = !signedness;
|
||||
g_force_signed_for_testing = signedness;
|
||||
}
|
||||
|
||||
void UnsetFixedLengthEncoderDeltaSignednessForTesting() {
|
||||
g_force_unsigned_for_testing = false;
|
||||
g_force_signed_for_testing = false;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_DELTA_ENCODING_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_DELTA_ENCODING_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Encode `values` as a sequence of deltas following on `base` and return it.
|
||||
// If all of the values were equal to the base, an empty string will be
|
||||
// returned; this is a valid encoding of that edge case.
|
||||
// `base` is not guaranteed to be written into `output`, and must therefore
|
||||
// be provided separately to the decoder.
|
||||
// This function never fails.
|
||||
// TODO(eladalon): Split into optional and non-optional variants (efficiency).
|
||||
std::string EncodeDeltas(absl::optional<uint64_t> base,
|
||||
const std::vector<absl::optional<uint64_t>>& values);
|
||||
|
||||
// EncodeDeltas() and DecodeDeltas() are inverse operations;
|
||||
// invoking DecodeDeltas() over the output of EncodeDeltas(), will return
|
||||
// the input originally given to EncodeDeltas().
|
||||
// `num_of_deltas` must be greater than zero. If input is not a valid encoding
|
||||
// of `num_of_deltas` elements based on `base`, the function returns an empty
|
||||
// vector, which signals an error.
|
||||
// TODO(eladalon): Split into optional and non-optional variants (efficiency).
|
||||
std::vector<absl::optional<uint64_t>> DecodeDeltas(
|
||||
absl::string_view input,
|
||||
absl::optional<uint64_t> base,
|
||||
size_t num_of_deltas);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_DELTA_ENCODING_H_
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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 "logging/rtc_event_log/encoder/optional_blob_encoding.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "rtc_base/bit_buffer.h"
|
||||
#include "rtc_base/bitstream_reader.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
std::string EncodeOptionalBlobs(
|
||||
const std::vector<absl::optional<std::string>>& blobs) {
|
||||
if (blobs.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t reserve_size_bits = 1;
|
||||
size_t num_blobs_present = 0;
|
||||
for (const auto& blob : blobs) {
|
||||
if (blob.has_value()) {
|
||||
++num_blobs_present;
|
||||
reserve_size_bits +=
|
||||
(rtc::BitBufferWriter::kMaxLeb128Length.bytes() + blob->size()) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_blobs_present == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const bool all_blobs_present = num_blobs_present == blobs.size();
|
||||
if (!all_blobs_present) {
|
||||
reserve_size_bits += blobs.size();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> buffer((reserve_size_bits + 7) / 8);
|
||||
rtc::BitBufferWriter writer(buffer.data(), buffer.size());
|
||||
|
||||
// Write present bits if all blobs are not present.
|
||||
writer.WriteBits(all_blobs_present, 1);
|
||||
if (!all_blobs_present) {
|
||||
for (const auto& blob : blobs) {
|
||||
writer.WriteBits(blob.has_value(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Byte align the writer.
|
||||
writer.ConsumeBits(writer.RemainingBitCount() % 8);
|
||||
|
||||
// Write blobs.
|
||||
for (const auto& blob : blobs) {
|
||||
if (blob.has_value()) {
|
||||
writer.WriteLeb128(blob->length());
|
||||
writer.WriteString(*blob);
|
||||
}
|
||||
}
|
||||
|
||||
size_t bytes_written;
|
||||
size_t bits_written;
|
||||
writer.GetCurrentOffset(&bytes_written, &bits_written);
|
||||
RTC_CHECK_EQ(bits_written, 0);
|
||||
RTC_CHECK_LE(bytes_written, buffer.size());
|
||||
|
||||
return std::string(buffer.data(), buffer.data() + bytes_written);
|
||||
}
|
||||
|
||||
std::vector<absl::optional<std::string>> DecodeOptionalBlobs(
|
||||
absl::string_view encoded_blobs,
|
||||
size_t num_of_blobs) {
|
||||
std::vector<absl::optional<std::string>> res(num_of_blobs);
|
||||
if (encoded_blobs.empty() || num_of_blobs == 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
BitstreamReader reader(encoded_blobs);
|
||||
const bool all_blobs_present = reader.ReadBit();
|
||||
|
||||
// Read present bits if all blobs are not present.
|
||||
std::vector<uint8_t> present;
|
||||
if (!all_blobs_present) {
|
||||
present.resize(num_of_blobs);
|
||||
for (size_t i = 0; i < num_of_blobs; ++i) {
|
||||
present[i] = reader.ReadBit();
|
||||
}
|
||||
}
|
||||
|
||||
// Byte align the reader.
|
||||
reader.ConsumeBits(reader.RemainingBitCount() % 8);
|
||||
|
||||
// Read the blobs.
|
||||
for (size_t i = 0; i < num_of_blobs; ++i) {
|
||||
if (!all_blobs_present && !present[i]) {
|
||||
continue;
|
||||
}
|
||||
res[i] = reader.ReadString(reader.ReadLeb128());
|
||||
}
|
||||
|
||||
// The result is only valid if exactly all bits was consumed during decoding.
|
||||
if (!reader.Ok() || reader.RemainingBitCount() > 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_OPTIONAL_BLOB_ENCODING_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_OPTIONAL_BLOB_ENCODING_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Encode a sequence of optional strings, whose length is not known to be
|
||||
// discernable from the blob itself (i.e. without being transmitted OOB),
|
||||
// in a way that would allow us to separate them again on the decoding side.
|
||||
// EncodeOptionalBlobs() may not fail but may return an empty string
|
||||
std::string EncodeOptionalBlobs(
|
||||
const std::vector<absl::optional<std::string>>& blobs);
|
||||
|
||||
// Calling DecodeOptionalBlobs() on an empty string, or with `num_of_blobs` set
|
||||
// to 0, is an error. DecodeOptionalBlobs() returns an empty vector if it fails,
|
||||
// which can happen if `encoded_blobs` is corrupted.
|
||||
std::vector<absl::optional<std::string>> DecodeOptionalBlobs(
|
||||
absl::string_view encoded_blobs,
|
||||
size_t num_of_blobs);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_OPTIONAL_BLOB_ENCODING_H_
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_H_
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "api/rtc_event_log/rtc_event.h"
|
||||
|
||||
namespace webrtc {
|
||||
class RtcEventLogEncoder {
|
||||
public:
|
||||
virtual ~RtcEventLogEncoder() = default;
|
||||
|
||||
virtual std::string EncodeLogStart(int64_t timestamp_us,
|
||||
int64_t utc_time_us) = 0;
|
||||
virtual std::string EncodeLogEnd(int64_t timestamp_us) = 0;
|
||||
|
||||
virtual std::string EncodeBatch(
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_H_
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
// We use 0x3fff because that gives decent precision (compared to the underlying
|
||||
// measurement producing the packet loss fraction) on the one hand, while
|
||||
// allowing us to use no more than 2 bytes in varint form on the other hand.
|
||||
// (We might also fixed-size encode using at most 14 bits.)
|
||||
constexpr uint32_t kPacketLossFractionRange = (1 << 14) - 1; // 0x3fff
|
||||
constexpr float kPacketLossFractionRangeFloat =
|
||||
static_cast<float>(kPacketLossFractionRange);
|
||||
} // namespace
|
||||
|
||||
uint32_t ConvertPacketLossFractionToProtoFormat(float packet_loss_fraction) {
|
||||
RTC_DCHECK_GE(packet_loss_fraction, 0);
|
||||
RTC_DCHECK_LE(packet_loss_fraction, 1);
|
||||
return static_cast<uint32_t>(packet_loss_fraction * kPacketLossFractionRange);
|
||||
}
|
||||
|
||||
bool ParsePacketLossFractionFromProtoFormat(uint32_t proto_packet_loss_fraction,
|
||||
float* output) {
|
||||
if (proto_packet_loss_fraction >= kPacketLossFractionRange) {
|
||||
return false;
|
||||
}
|
||||
*output = proto_packet_loss_fraction / kPacketLossFractionRangeFloat;
|
||||
return true;
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Convert between the packet fraction loss (a floating point number in
|
||||
// the range [0.0, 1.0]), and a uint32_t with up to a fixed number of bits.
|
||||
// The latter can be more efficiently stored in a protobuf and/or delta-encoded.
|
||||
uint32_t ConvertPacketLossFractionToProtoFormat(float packet_loss_fraction);
|
||||
bool ParsePacketLossFractionFromProtoFormat(uint32_t proto_packet_loss_fraction,
|
||||
float* output);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
namespace webrtc_event_logging {
|
||||
|
||||
// Produce an unsigned representation of a signed integer. On two's complement
|
||||
// machines, this is equivalent to:
|
||||
// static_cast<uint64_t>(static_cast<std::make_unsigned<T>>(y))
|
||||
template <typename T>
|
||||
uint64_t ToUnsigned(T y) {
|
||||
static_assert(std::is_integral<T>::value, "");
|
||||
static_assert(std::is_signed<T>::value, "");
|
||||
|
||||
// Note that a signed integer whose width is N bits, has N-1 digits.
|
||||
static_assert(std::numeric_limits<T>::digits < 64, "");
|
||||
|
||||
constexpr T MIN_T = std::numeric_limits<T>::min();
|
||||
constexpr T MAX_T = std::numeric_limits<T>::max();
|
||||
|
||||
static_assert(MAX_T + MIN_T + 1 >= 0, "MAX_T >= abs(MIN_T) - 1");
|
||||
|
||||
if (y >= 0) {
|
||||
return static_cast<uint64_t>(y);
|
||||
} else {
|
||||
// y is in the range [MIN_T, -1], so (y - MIN_T) is in the
|
||||
// range [0, abs(MIN_T) - 1]. This is representable in a T
|
||||
// because MAX_T >= abs(MIN_T) - 1, as per the static_assert above.
|
||||
return static_cast<uint64_t>(MAX_T) + 1 + static_cast<uint64_t>(y - MIN_T);
|
||||
}
|
||||
}
|
||||
|
||||
// Assuming x = ToUnsigned(y), return `y`.
|
||||
// Note: static_cast<T>(x) would work on most platforms and compilers, but
|
||||
// involves undefined behavior. This function is well-defined, and can be
|
||||
// optimized to a noop for 64 bit types, or a few arithmetic
|
||||
// instructions and a single conditional jump for narrower types.
|
||||
template <typename T>
|
||||
bool ToSigned(uint64_t x, T* y) {
|
||||
static_assert(std::is_integral<T>::value, "");
|
||||
static_assert(std::is_signed<T>::value, "");
|
||||
|
||||
// Note that a signed integer whose width is N bits, has N-1 digits.
|
||||
static_assert(std::numeric_limits<T>::digits < 64, "");
|
||||
|
||||
constexpr T MIN_T = std::numeric_limits<T>::min();
|
||||
constexpr T MAX_T = std::numeric_limits<T>::max();
|
||||
|
||||
using UNSIGNED_T = typename std::make_unsigned<T>::type;
|
||||
constexpr auto MAX_UNSIGNED_T = std::numeric_limits<UNSIGNED_T>::max();
|
||||
if (x > static_cast<uint64_t>(MAX_UNSIGNED_T)) {
|
||||
return false; // `x` cannot be represented using a T.
|
||||
}
|
||||
|
||||
if (x <= static_cast<uint64_t>(MAX_T)) {
|
||||
// The original value was positive, so it is safe to just static_cast.
|
||||
*y = static_cast<T>(x);
|
||||
} else { // x > static_cast<uint64_t>(MAX_T)
|
||||
const uint64_t neg_x = x - static_cast<uint64_t>(MAX_T) - 1;
|
||||
*y = static_cast<T>(neg_x) + MIN_T;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace webrtc_event_logging
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_
|
||||
|
|
@ -0,0 +1,806 @@
|
|||
/*
|
||||
* 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 "logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/array_view.h"
|
||||
#include "api/network_state_predictor.h"
|
||||
#include "api/rtp_headers.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_alr_state.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_probe_result_success.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_remote_estimate.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
|
||||
#include "logging/rtc_event_log/rtc_stream_config.h"
|
||||
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/app.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_packet.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
// *.pb.h files are generated at build-time by the protobuf compiler.
|
||||
#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
|
||||
#include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log.pb.h"
|
||||
#else
|
||||
#include "logging/rtc_event_log/rtc_event_log.pb.h"
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
rtclog::DelayBasedBweUpdate::DetectorState ConvertDetectorState(
|
||||
BandwidthUsage state) {
|
||||
switch (state) {
|
||||
case BandwidthUsage::kBwNormal:
|
||||
return rtclog::DelayBasedBweUpdate::BWE_NORMAL;
|
||||
case BandwidthUsage::kBwUnderusing:
|
||||
return rtclog::DelayBasedBweUpdate::BWE_UNDERUSING;
|
||||
case BandwidthUsage::kBwOverusing:
|
||||
return rtclog::DelayBasedBweUpdate::BWE_OVERUSING;
|
||||
case BandwidthUsage::kLast:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return rtclog::DelayBasedBweUpdate::BWE_NORMAL;
|
||||
}
|
||||
|
||||
rtclog::BweProbeResult::ResultType ConvertProbeResultType(
|
||||
ProbeFailureReason failure_reason) {
|
||||
switch (failure_reason) {
|
||||
case ProbeFailureReason::kInvalidSendReceiveInterval:
|
||||
return rtclog::BweProbeResult::INVALID_SEND_RECEIVE_INTERVAL;
|
||||
case ProbeFailureReason::kInvalidSendReceiveRatio:
|
||||
return rtclog::BweProbeResult::INVALID_SEND_RECEIVE_RATIO;
|
||||
case ProbeFailureReason::kTimeout:
|
||||
return rtclog::BweProbeResult::TIMEOUT;
|
||||
case ProbeFailureReason::kLast:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return rtclog::BweProbeResult::SUCCESS;
|
||||
}
|
||||
|
||||
rtclog::VideoReceiveConfig_RtcpMode ConvertRtcpMode(RtcpMode rtcp_mode) {
|
||||
switch (rtcp_mode) {
|
||||
case RtcpMode::kCompound:
|
||||
return rtclog::VideoReceiveConfig::RTCP_COMPOUND;
|
||||
case RtcpMode::kReducedSize:
|
||||
return rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE;
|
||||
case RtcpMode::kOff:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return rtclog::VideoReceiveConfig::RTCP_COMPOUND;
|
||||
}
|
||||
|
||||
rtclog::IceCandidatePairConfig::IceCandidatePairConfigType
|
||||
ConvertIceCandidatePairConfigType(IceCandidatePairConfigType type) {
|
||||
switch (type) {
|
||||
case IceCandidatePairConfigType::kAdded:
|
||||
return rtclog::IceCandidatePairConfig::ADDED;
|
||||
case IceCandidatePairConfigType::kUpdated:
|
||||
return rtclog::IceCandidatePairConfig::UPDATED;
|
||||
case IceCandidatePairConfigType::kDestroyed:
|
||||
return rtclog::IceCandidatePairConfig::DESTROYED;
|
||||
case IceCandidatePairConfigType::kSelected:
|
||||
return rtclog::IceCandidatePairConfig::SELECTED;
|
||||
case IceCandidatePairConfigType::kNumValues:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return rtclog::IceCandidatePairConfig::ADDED;
|
||||
}
|
||||
|
||||
rtclog::IceCandidatePairConfig::IceCandidateType ConvertIceCandidateType(
|
||||
IceCandidateType type) {
|
||||
switch (type) {
|
||||
case IceCandidateType::kHost:
|
||||
return rtclog::IceCandidatePairConfig::LOCAL;
|
||||
case IceCandidateType::kSrflx:
|
||||
return rtclog::IceCandidatePairConfig::STUN;
|
||||
case IceCandidateType::kPrflx:
|
||||
return rtclog::IceCandidatePairConfig::PRFLX;
|
||||
case IceCandidateType::kRelay:
|
||||
return rtclog::IceCandidatePairConfig::RELAY;
|
||||
}
|
||||
}
|
||||
|
||||
rtclog::IceCandidatePairConfig::Protocol ConvertIceCandidatePairProtocol(
|
||||
IceCandidatePairProtocol protocol) {
|
||||
switch (protocol) {
|
||||
case IceCandidatePairProtocol::kUnknown:
|
||||
return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL;
|
||||
case IceCandidatePairProtocol::kUdp:
|
||||
return rtclog::IceCandidatePairConfig::UDP;
|
||||
case IceCandidatePairProtocol::kTcp:
|
||||
return rtclog::IceCandidatePairConfig::TCP;
|
||||
case IceCandidatePairProtocol::kSsltcp:
|
||||
return rtclog::IceCandidatePairConfig::SSLTCP;
|
||||
case IceCandidatePairProtocol::kTls:
|
||||
return rtclog::IceCandidatePairConfig::TLS;
|
||||
case IceCandidatePairProtocol::kNumValues:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL;
|
||||
}
|
||||
|
||||
rtclog::IceCandidatePairConfig::AddressFamily
|
||||
ConvertIceCandidatePairAddressFamily(
|
||||
IceCandidatePairAddressFamily address_family) {
|
||||
switch (address_family) {
|
||||
case IceCandidatePairAddressFamily::kUnknown:
|
||||
return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY;
|
||||
case IceCandidatePairAddressFamily::kIpv4:
|
||||
return rtclog::IceCandidatePairConfig::IPV4;
|
||||
case IceCandidatePairAddressFamily::kIpv6:
|
||||
return rtclog::IceCandidatePairConfig::IPV6;
|
||||
case IceCandidatePairAddressFamily::kNumValues:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY;
|
||||
}
|
||||
|
||||
rtclog::IceCandidatePairConfig::NetworkType ConvertIceCandidateNetworkType(
|
||||
IceCandidateNetworkType network_type) {
|
||||
switch (network_type) {
|
||||
case IceCandidateNetworkType::kUnknown:
|
||||
return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE;
|
||||
case IceCandidateNetworkType::kEthernet:
|
||||
return rtclog::IceCandidatePairConfig::ETHERNET;
|
||||
case IceCandidateNetworkType::kLoopback:
|
||||
return rtclog::IceCandidatePairConfig::LOOPBACK;
|
||||
case IceCandidateNetworkType::kWifi:
|
||||
return rtclog::IceCandidatePairConfig::WIFI;
|
||||
case IceCandidateNetworkType::kVpn:
|
||||
return rtclog::IceCandidatePairConfig::VPN;
|
||||
case IceCandidateNetworkType::kCellular:
|
||||
return rtclog::IceCandidatePairConfig::CELLULAR;
|
||||
case IceCandidateNetworkType::kNumValues:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE;
|
||||
}
|
||||
|
||||
rtclog::IceCandidatePairEvent::IceCandidatePairEventType
|
||||
ConvertIceCandidatePairEventType(IceCandidatePairEventType type) {
|
||||
switch (type) {
|
||||
case IceCandidatePairEventType::kCheckSent:
|
||||
return rtclog::IceCandidatePairEvent::CHECK_SENT;
|
||||
case IceCandidatePairEventType::kCheckReceived:
|
||||
return rtclog::IceCandidatePairEvent::CHECK_RECEIVED;
|
||||
case IceCandidatePairEventType::kCheckResponseSent:
|
||||
return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT;
|
||||
case IceCandidatePairEventType::kCheckResponseReceived:
|
||||
return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED;
|
||||
case IceCandidatePairEventType::kNumValues:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return rtclog::IceCandidatePairEvent::CHECK_SENT;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeLogStart(int64_t timestamp_us,
|
||||
int64_t utc_time_us) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(timestamp_us);
|
||||
rtclog_event.set_type(rtclog::Event::LOG_START);
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeLogEnd(int64_t timestamp_us) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(timestamp_us);
|
||||
rtclog_event.set_type(rtclog::Event::LOG_END);
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeBatch(
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) {
|
||||
std::string encoded_output;
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
// TODO(terelius): Can we avoid the slight inefficiency of reallocating the
|
||||
// string?
|
||||
RTC_CHECK(it->get() != nullptr);
|
||||
encoded_output += Encode(**it);
|
||||
}
|
||||
return encoded_output;
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::Encode(const RtcEvent& event) {
|
||||
switch (event.GetType()) {
|
||||
case RtcEvent::Type::AudioNetworkAdaptation: {
|
||||
auto& rtc_event =
|
||||
static_cast<const RtcEventAudioNetworkAdaptation&>(event);
|
||||
return EncodeAudioNetworkAdaptation(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::AlrStateEvent: {
|
||||
auto& rtc_event = static_cast<const RtcEventAlrState&>(event);
|
||||
return EncodeAlrState(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::AudioPlayout: {
|
||||
auto& rtc_event = static_cast<const RtcEventAudioPlayout&>(event);
|
||||
return EncodeAudioPlayout(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::AudioReceiveStreamConfig: {
|
||||
auto& rtc_event =
|
||||
static_cast<const RtcEventAudioReceiveStreamConfig&>(event);
|
||||
return EncodeAudioReceiveStreamConfig(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::AudioSendStreamConfig: {
|
||||
auto& rtc_event =
|
||||
static_cast<const RtcEventAudioSendStreamConfig&>(event);
|
||||
return EncodeAudioSendStreamConfig(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::BweUpdateDelayBased: {
|
||||
auto& rtc_event = static_cast<const RtcEventBweUpdateDelayBased&>(event);
|
||||
return EncodeBweUpdateDelayBased(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::BweUpdateLossBased: {
|
||||
auto& rtc_event = static_cast<const RtcEventBweUpdateLossBased&>(event);
|
||||
return EncodeBweUpdateLossBased(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::DtlsTransportState: {
|
||||
return "";
|
||||
}
|
||||
|
||||
case RtcEvent::Type::DtlsWritableState: {
|
||||
return "";
|
||||
}
|
||||
|
||||
case RtcEvent::Type::IceCandidatePairConfig: {
|
||||
auto& rtc_event =
|
||||
static_cast<const RtcEventIceCandidatePairConfig&>(event);
|
||||
return EncodeIceCandidatePairConfig(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::IceCandidatePairEvent: {
|
||||
auto& rtc_event = static_cast<const RtcEventIceCandidatePair&>(event);
|
||||
return EncodeIceCandidatePairEvent(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::ProbeClusterCreated: {
|
||||
auto& rtc_event = static_cast<const RtcEventProbeClusterCreated&>(event);
|
||||
return EncodeProbeClusterCreated(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::ProbeResultFailure: {
|
||||
auto& rtc_event = static_cast<const RtcEventProbeResultFailure&>(event);
|
||||
return EncodeProbeResultFailure(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::ProbeResultSuccess: {
|
||||
auto& rtc_event = static_cast<const RtcEventProbeResultSuccess&>(event);
|
||||
return EncodeProbeResultSuccess(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::RemoteEstimateEvent: {
|
||||
auto& rtc_event = static_cast<const RtcEventRemoteEstimate&>(event);
|
||||
return EncodeRemoteEstimate(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::RtcpPacketIncoming: {
|
||||
auto& rtc_event = static_cast<const RtcEventRtcpPacketIncoming&>(event);
|
||||
return EncodeRtcpPacketIncoming(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::RtcpPacketOutgoing: {
|
||||
auto& rtc_event = static_cast<const RtcEventRtcpPacketOutgoing&>(event);
|
||||
return EncodeRtcpPacketOutgoing(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::RtpPacketIncoming: {
|
||||
auto& rtc_event = static_cast<const RtcEventRtpPacketIncoming&>(event);
|
||||
return EncodeRtpPacketIncoming(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::RtpPacketOutgoing: {
|
||||
auto& rtc_event = static_cast<const RtcEventRtpPacketOutgoing&>(event);
|
||||
return EncodeRtpPacketOutgoing(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::VideoReceiveStreamConfig: {
|
||||
auto& rtc_event =
|
||||
static_cast<const RtcEventVideoReceiveStreamConfig&>(event);
|
||||
return EncodeVideoReceiveStreamConfig(rtc_event);
|
||||
}
|
||||
|
||||
case RtcEvent::Type::VideoSendStreamConfig: {
|
||||
auto& rtc_event =
|
||||
static_cast<const RtcEventVideoSendStreamConfig&>(event);
|
||||
return EncodeVideoSendStreamConfig(rtc_event);
|
||||
}
|
||||
case RtcEvent::Type::BeginV3Log:
|
||||
case RtcEvent::Type::EndV3Log:
|
||||
// These special events are written as part of starting
|
||||
// and stopping the log, and only as part of version 3 of the format.
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
break;
|
||||
case RtcEvent::Type::FakeEvent:
|
||||
// Fake event used for unit test.
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
break;
|
||||
case RtcEvent::Type::RouteChangeEvent:
|
||||
case RtcEvent::Type::GenericPacketReceived:
|
||||
case RtcEvent::Type::GenericPacketSent:
|
||||
case RtcEvent::Type::GenericAckReceived:
|
||||
case RtcEvent::Type::FrameDecoded:
|
||||
case RtcEvent::Type::NetEqSetMinimumDelay:
|
||||
// These are unsupported in the old format, but shouldn't crash.
|
||||
return "";
|
||||
}
|
||||
|
||||
int event_type = static_cast<int>(event.GetType());
|
||||
RTC_DCHECK_NOTREACHED() << "Unknown event type (" << event_type << ")";
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeAlrState(
|
||||
const RtcEventAlrState& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::ALR_STATE_EVENT);
|
||||
|
||||
auto* alr_state = rtclog_event.mutable_alr_state();
|
||||
alr_state->set_in_alr(event.in_alr());
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeAudioNetworkAdaptation(
|
||||
const RtcEventAudioNetworkAdaptation& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT);
|
||||
|
||||
auto* audio_network_adaptation =
|
||||
rtclog_event.mutable_audio_network_adaptation();
|
||||
if (event.config().bitrate_bps)
|
||||
audio_network_adaptation->set_bitrate_bps(*event.config().bitrate_bps);
|
||||
if (event.config().frame_length_ms)
|
||||
audio_network_adaptation->set_frame_length_ms(
|
||||
*event.config().frame_length_ms);
|
||||
if (event.config().uplink_packet_loss_fraction) {
|
||||
audio_network_adaptation->set_uplink_packet_loss_fraction(
|
||||
*event.config().uplink_packet_loss_fraction);
|
||||
}
|
||||
if (event.config().enable_fec)
|
||||
audio_network_adaptation->set_enable_fec(*event.config().enable_fec);
|
||||
if (event.config().enable_dtx)
|
||||
audio_network_adaptation->set_enable_dtx(*event.config().enable_dtx);
|
||||
if (event.config().num_channels)
|
||||
audio_network_adaptation->set_num_channels(*event.config().num_channels);
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeAudioPlayout(
|
||||
const RtcEventAudioPlayout& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::AUDIO_PLAYOUT_EVENT);
|
||||
|
||||
auto* playout_event = rtclog_event.mutable_audio_playout_event();
|
||||
playout_event->set_local_ssrc(event.ssrc());
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeAudioReceiveStreamConfig(
|
||||
const RtcEventAudioReceiveStreamConfig& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT);
|
||||
|
||||
rtclog::AudioReceiveConfig* receiver_config =
|
||||
rtclog_event.mutable_audio_receiver_config();
|
||||
receiver_config->set_remote_ssrc(event.config().remote_ssrc);
|
||||
receiver_config->set_local_ssrc(event.config().local_ssrc);
|
||||
|
||||
for (const auto& e : event.config().rtp_extensions) {
|
||||
rtclog::RtpHeaderExtension* extension =
|
||||
receiver_config->add_header_extensions();
|
||||
extension->set_name(e.uri);
|
||||
extension->set_id(e.id);
|
||||
}
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeAudioSendStreamConfig(
|
||||
const RtcEventAudioSendStreamConfig& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::AUDIO_SENDER_CONFIG_EVENT);
|
||||
|
||||
rtclog::AudioSendConfig* sender_config =
|
||||
rtclog_event.mutable_audio_sender_config();
|
||||
|
||||
sender_config->set_ssrc(event.config().local_ssrc);
|
||||
|
||||
for (const auto& e : event.config().rtp_extensions) {
|
||||
rtclog::RtpHeaderExtension* extension =
|
||||
sender_config->add_header_extensions();
|
||||
extension->set_name(e.uri);
|
||||
extension->set_id(e.id);
|
||||
}
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeBweUpdateDelayBased(
|
||||
const RtcEventBweUpdateDelayBased& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::DELAY_BASED_BWE_UPDATE);
|
||||
|
||||
auto* bwe_event = rtclog_event.mutable_delay_based_bwe_update();
|
||||
bwe_event->set_bitrate_bps(event.bitrate_bps());
|
||||
bwe_event->set_detector_state(ConvertDetectorState(event.detector_state()));
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeBweUpdateLossBased(
|
||||
const RtcEventBweUpdateLossBased& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::LOSS_BASED_BWE_UPDATE);
|
||||
|
||||
auto* bwe_event = rtclog_event.mutable_loss_based_bwe_update();
|
||||
bwe_event->set_bitrate_bps(event.bitrate_bps());
|
||||
bwe_event->set_fraction_loss(event.fraction_loss());
|
||||
bwe_event->set_total_packets(event.total_packets());
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeIceCandidatePairConfig(
|
||||
const RtcEventIceCandidatePairConfig& event) {
|
||||
rtclog::Event encoded_rtc_event;
|
||||
encoded_rtc_event.set_timestamp_us(event.timestamp_us());
|
||||
encoded_rtc_event.set_type(rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG);
|
||||
|
||||
auto* encoded_ice_event =
|
||||
encoded_rtc_event.mutable_ice_candidate_pair_config();
|
||||
encoded_ice_event->set_config_type(
|
||||
ConvertIceCandidatePairConfigType(event.type()));
|
||||
encoded_ice_event->set_candidate_pair_id(event.candidate_pair_id());
|
||||
const auto& desc = event.candidate_pair_desc();
|
||||
encoded_ice_event->set_local_candidate_type(
|
||||
ConvertIceCandidateType(desc.local_candidate_type));
|
||||
encoded_ice_event->set_local_relay_protocol(
|
||||
ConvertIceCandidatePairProtocol(desc.local_relay_protocol));
|
||||
encoded_ice_event->set_local_network_type(
|
||||
ConvertIceCandidateNetworkType(desc.local_network_type));
|
||||
encoded_ice_event->set_local_address_family(
|
||||
ConvertIceCandidatePairAddressFamily(desc.local_address_family));
|
||||
encoded_ice_event->set_remote_candidate_type(
|
||||
ConvertIceCandidateType(desc.remote_candidate_type));
|
||||
encoded_ice_event->set_remote_address_family(
|
||||
ConvertIceCandidatePairAddressFamily(desc.remote_address_family));
|
||||
encoded_ice_event->set_candidate_pair_protocol(
|
||||
ConvertIceCandidatePairProtocol(desc.candidate_pair_protocol));
|
||||
return Serialize(&encoded_rtc_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeIceCandidatePairEvent(
|
||||
const RtcEventIceCandidatePair& event) {
|
||||
rtclog::Event encoded_rtc_event;
|
||||
encoded_rtc_event.set_timestamp_us(event.timestamp_us());
|
||||
encoded_rtc_event.set_type(rtclog::Event::ICE_CANDIDATE_PAIR_EVENT);
|
||||
|
||||
auto* encoded_ice_event =
|
||||
encoded_rtc_event.mutable_ice_candidate_pair_event();
|
||||
encoded_ice_event->set_event_type(
|
||||
ConvertIceCandidatePairEventType(event.type()));
|
||||
encoded_ice_event->set_candidate_pair_id(event.candidate_pair_id());
|
||||
return Serialize(&encoded_rtc_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeProbeClusterCreated(
|
||||
const RtcEventProbeClusterCreated& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT);
|
||||
|
||||
auto* probe_cluster = rtclog_event.mutable_probe_cluster();
|
||||
probe_cluster->set_id(event.id());
|
||||
probe_cluster->set_bitrate_bps(event.bitrate_bps());
|
||||
probe_cluster->set_min_packets(event.min_probes());
|
||||
probe_cluster->set_min_bytes(event.min_bytes());
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeProbeResultFailure(
|
||||
const RtcEventProbeResultFailure& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::BWE_PROBE_RESULT_EVENT);
|
||||
|
||||
auto* probe_result = rtclog_event.mutable_probe_result();
|
||||
probe_result->set_id(event.id());
|
||||
probe_result->set_result(ConvertProbeResultType(event.failure_reason()));
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeProbeResultSuccess(
|
||||
const RtcEventProbeResultSuccess& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::BWE_PROBE_RESULT_EVENT);
|
||||
|
||||
auto* probe_result = rtclog_event.mutable_probe_result();
|
||||
probe_result->set_id(event.id());
|
||||
probe_result->set_result(rtclog::BweProbeResult::SUCCESS);
|
||||
probe_result->set_bitrate_bps(event.bitrate_bps());
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeRemoteEstimate(
|
||||
const RtcEventRemoteEstimate& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::REMOTE_ESTIMATE);
|
||||
|
||||
auto* remote_estimate = rtclog_event.mutable_remote_estimate();
|
||||
if (event.link_capacity_lower_.IsFinite())
|
||||
remote_estimate->set_link_capacity_lower_kbps(
|
||||
event.link_capacity_lower_.kbps<uint32_t>());
|
||||
if (event.link_capacity_upper_.IsFinite())
|
||||
remote_estimate->set_link_capacity_upper_kbps(
|
||||
event.link_capacity_upper_.kbps<uint32_t>());
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeRtcpPacketIncoming(
|
||||
const RtcEventRtcpPacketIncoming& event) {
|
||||
return EncodeRtcpPacket(event.timestamp_us(), event.packet(), true);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeRtcpPacketOutgoing(
|
||||
const RtcEventRtcpPacketOutgoing& event) {
|
||||
return EncodeRtcpPacket(event.timestamp_us(), event.packet(), false);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeRtpPacketIncoming(
|
||||
const RtcEventRtpPacketIncoming& event) {
|
||||
return EncodeRtpPacket(event.timestamp_us(), event.RawHeader(),
|
||||
event.packet_length(), PacedPacketInfo::kNotAProbe,
|
||||
true);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeRtpPacketOutgoing(
|
||||
const RtcEventRtpPacketOutgoing& event) {
|
||||
return EncodeRtpPacket(event.timestamp_us(), event.RawHeader(),
|
||||
event.packet_length(), event.probe_cluster_id(),
|
||||
false);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeVideoReceiveStreamConfig(
|
||||
const RtcEventVideoReceiveStreamConfig& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT);
|
||||
|
||||
rtclog::VideoReceiveConfig* receiver_config =
|
||||
rtclog_event.mutable_video_receiver_config();
|
||||
receiver_config->set_remote_ssrc(event.config().remote_ssrc);
|
||||
receiver_config->set_local_ssrc(event.config().local_ssrc);
|
||||
|
||||
// TODO(perkj): Add field for rsid.
|
||||
receiver_config->set_rtcp_mode(ConvertRtcpMode(event.config().rtcp_mode));
|
||||
receiver_config->set_remb(event.config().remb);
|
||||
|
||||
for (const auto& e : event.config().rtp_extensions) {
|
||||
rtclog::RtpHeaderExtension* extension =
|
||||
receiver_config->add_header_extensions();
|
||||
extension->set_name(e.uri);
|
||||
extension->set_id(e.id);
|
||||
}
|
||||
|
||||
for (const auto& d : event.config().codecs) {
|
||||
rtclog::DecoderConfig* decoder = receiver_config->add_decoders();
|
||||
decoder->set_name(d.payload_name);
|
||||
decoder->set_payload_type(d.payload_type);
|
||||
if (d.rtx_payload_type != 0) {
|
||||
rtclog::RtxMap* rtx = receiver_config->add_rtx_map();
|
||||
rtx->set_payload_type(d.payload_type);
|
||||
rtx->mutable_config()->set_rtx_ssrc(event.config().rtx_ssrc);
|
||||
rtx->mutable_config()->set_rtx_payload_type(d.rtx_payload_type);
|
||||
}
|
||||
}
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeVideoSendStreamConfig(
|
||||
const RtcEventVideoSendStreamConfig& event) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(event.timestamp_us());
|
||||
rtclog_event.set_type(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT);
|
||||
|
||||
rtclog::VideoSendConfig* sender_config =
|
||||
rtclog_event.mutable_video_sender_config();
|
||||
|
||||
// TODO(perkj): rtclog::VideoSendConfig should only contain one SSRC.
|
||||
sender_config->add_ssrcs(event.config().local_ssrc);
|
||||
if (event.config().rtx_ssrc != 0) {
|
||||
sender_config->add_rtx_ssrcs(event.config().rtx_ssrc);
|
||||
}
|
||||
|
||||
for (const auto& e : event.config().rtp_extensions) {
|
||||
rtclog::RtpHeaderExtension* extension =
|
||||
sender_config->add_header_extensions();
|
||||
extension->set_name(e.uri);
|
||||
extension->set_id(e.id);
|
||||
}
|
||||
|
||||
// TODO(perkj): rtclog::VideoSendConfig should contain many possible codec
|
||||
// configurations.
|
||||
for (const auto& codec : event.config().codecs) {
|
||||
sender_config->set_rtx_payload_type(codec.rtx_payload_type);
|
||||
rtclog::EncoderConfig* encoder = sender_config->mutable_encoder();
|
||||
encoder->set_name(codec.payload_name);
|
||||
encoder->set_payload_type(codec.payload_type);
|
||||
|
||||
if (event.config().codecs.size() > 1) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "LogVideoSendStreamConfig currently only supports one "
|
||||
"codec. Logging codec :"
|
||||
<< codec.payload_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeRtcpPacket(
|
||||
int64_t timestamp_us,
|
||||
const rtc::Buffer& packet,
|
||||
bool is_incoming) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(timestamp_us);
|
||||
rtclog_event.set_type(rtclog::Event::RTCP_EVENT);
|
||||
rtclog_event.mutable_rtcp_packet()->set_incoming(is_incoming);
|
||||
|
||||
rtcp::CommonHeader header;
|
||||
const uint8_t* block_begin = packet.data();
|
||||
const uint8_t* packet_end = packet.data() + packet.size();
|
||||
std::vector<uint8_t> buffer(packet.size());
|
||||
uint32_t buffer_length = 0;
|
||||
while (block_begin < packet_end) {
|
||||
if (!header.Parse(block_begin, packet_end - block_begin)) {
|
||||
break; // Incorrect message header.
|
||||
}
|
||||
const uint8_t* next_block = header.NextPacket();
|
||||
uint32_t block_size = next_block - block_begin;
|
||||
switch (header.type()) {
|
||||
case rtcp::Bye::kPacketType:
|
||||
case rtcp::ExtendedReports::kPacketType:
|
||||
case rtcp::Psfb::kPacketType:
|
||||
case rtcp::ReceiverReport::kPacketType:
|
||||
case rtcp::Rtpfb::kPacketType:
|
||||
case rtcp::SenderReport::kPacketType:
|
||||
// We log sender reports, receiver reports, bye messages, third-party
|
||||
// loss reports, payload-specific feedback and extended reports.
|
||||
memcpy(buffer.data() + buffer_length, block_begin, block_size);
|
||||
buffer_length += block_size;
|
||||
break;
|
||||
case rtcp::App::kPacketType:
|
||||
case rtcp::Sdes::kPacketType:
|
||||
default:
|
||||
// We don't log sender descriptions, application defined messages
|
||||
// or message blocks of unknown type.
|
||||
break;
|
||||
}
|
||||
|
||||
block_begin += block_size;
|
||||
}
|
||||
rtclog_event.mutable_rtcp_packet()->set_packet_data(buffer.data(),
|
||||
buffer_length);
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::EncodeRtpPacket(
|
||||
int64_t timestamp_us,
|
||||
rtc::ArrayView<const uint8_t> header,
|
||||
size_t packet_length,
|
||||
int probe_cluster_id,
|
||||
bool is_incoming) {
|
||||
rtclog::Event rtclog_event;
|
||||
rtclog_event.set_timestamp_us(timestamp_us);
|
||||
rtclog_event.set_type(rtclog::Event::RTP_EVENT);
|
||||
|
||||
rtclog_event.mutable_rtp_packet()->set_incoming(is_incoming);
|
||||
rtclog_event.mutable_rtp_packet()->set_packet_length(packet_length);
|
||||
rtclog_event.mutable_rtp_packet()->set_header(header.data(), header.size());
|
||||
if (probe_cluster_id != PacedPacketInfo::kNotAProbe) {
|
||||
RTC_DCHECK(!is_incoming);
|
||||
rtclog_event.mutable_rtp_packet()->set_probe_cluster_id(probe_cluster_id);
|
||||
}
|
||||
|
||||
return Serialize(&rtclog_event);
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderLegacy::Serialize(rtclog::Event* event) {
|
||||
// Even though we're only serializing a single event during this call, what
|
||||
// we intend to get is a list of events, with a tag and length preceding
|
||||
// each actual event. To produce that, we serialize a list of a single event.
|
||||
// If we later concatenate several results from this function, the result will
|
||||
// be a proper concatenation of all those events.
|
||||
|
||||
rtclog::EventStream event_stream;
|
||||
event_stream.add_stream();
|
||||
|
||||
// As a tweak, we swap the new event into the event-stream, write that to
|
||||
// file, then swap back. This saves on some copying, while making sure that
|
||||
// the caller wouldn't be surprised by Serialize() modifying the object.
|
||||
rtclog::Event* output_event = event_stream.mutable_stream(0);
|
||||
output_event->Swap(event);
|
||||
|
||||
std::string output_string = event_stream.SerializeAsString();
|
||||
RTC_DCHECK(!output_string.empty());
|
||||
|
||||
// When the function returns, the original Event will be unchanged.
|
||||
output_event->Swap(event);
|
||||
|
||||
return output_string;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_LEGACY_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_LEGACY_H_
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "logging/rtc_event_log/encoder/rtc_event_log_encoder.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace rtclog {
|
||||
class Event; // Auto-generated from protobuf.
|
||||
} // namespace rtclog
|
||||
|
||||
class RtcEventAlrState;
|
||||
class RtcEventAudioNetworkAdaptation;
|
||||
class RtcEventAudioPlayout;
|
||||
class RtcEventAudioReceiveStreamConfig;
|
||||
class RtcEventAudioSendStreamConfig;
|
||||
class RtcEventBweUpdateDelayBased;
|
||||
class RtcEventBweUpdateLossBased;
|
||||
class RtcEventIceCandidatePairConfig;
|
||||
class RtcEventIceCandidatePair;
|
||||
class RtcEventLoggingStarted;
|
||||
class RtcEventLoggingStopped;
|
||||
class RtcEventProbeClusterCreated;
|
||||
class RtcEventProbeResultFailure;
|
||||
class RtcEventProbeResultSuccess;
|
||||
class RtcEventRemoteEstimate;
|
||||
class RtcEventRtcpPacketIncoming;
|
||||
class RtcEventRtcpPacketOutgoing;
|
||||
class RtcEventRtpPacketIncoming;
|
||||
class RtcEventRtpPacketOutgoing;
|
||||
class RtcEventVideoReceiveStreamConfig;
|
||||
class RtcEventVideoSendStreamConfig;
|
||||
class RtpPacket;
|
||||
|
||||
class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder {
|
||||
public:
|
||||
~RtcEventLogEncoderLegacy() override = default;
|
||||
|
||||
std::string EncodeLogStart(int64_t timestamp_us,
|
||||
int64_t utc_time_us) override;
|
||||
std::string EncodeLogEnd(int64_t timestamp_us) override;
|
||||
|
||||
std::string EncodeBatch(
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) override;
|
||||
|
||||
private:
|
||||
std::string Encode(const RtcEvent& event);
|
||||
// Encoding entry-point for the various RtcEvent subclasses.
|
||||
std::string EncodeAlrState(const RtcEventAlrState& event);
|
||||
std::string EncodeAudioNetworkAdaptation(
|
||||
const RtcEventAudioNetworkAdaptation& event);
|
||||
std::string EncodeAudioPlayout(const RtcEventAudioPlayout& event);
|
||||
std::string EncodeAudioReceiveStreamConfig(
|
||||
const RtcEventAudioReceiveStreamConfig& event);
|
||||
std::string EncodeAudioSendStreamConfig(
|
||||
const RtcEventAudioSendStreamConfig& event);
|
||||
std::string EncodeBweUpdateDelayBased(
|
||||
const RtcEventBweUpdateDelayBased& event);
|
||||
std::string EncodeBweUpdateLossBased(const RtcEventBweUpdateLossBased& event);
|
||||
std::string EncodeIceCandidatePairConfig(
|
||||
const RtcEventIceCandidatePairConfig& event);
|
||||
std::string EncodeIceCandidatePairEvent(
|
||||
const RtcEventIceCandidatePair& event);
|
||||
std::string EncodeProbeClusterCreated(
|
||||
const RtcEventProbeClusterCreated& event);
|
||||
std::string EncodeProbeResultFailure(const RtcEventProbeResultFailure& event);
|
||||
std::string EncodeProbeResultSuccess(const RtcEventProbeResultSuccess&);
|
||||
std::string EncodeRemoteEstimate(const RtcEventRemoteEstimate& event);
|
||||
std::string EncodeRtcpPacketIncoming(const RtcEventRtcpPacketIncoming& event);
|
||||
std::string EncodeRtcpPacketOutgoing(const RtcEventRtcpPacketOutgoing& event);
|
||||
std::string EncodeRtpPacketIncoming(const RtcEventRtpPacketIncoming& event);
|
||||
std::string EncodeRtpPacketOutgoing(const RtcEventRtpPacketOutgoing& event);
|
||||
std::string EncodeVideoReceiveStreamConfig(
|
||||
const RtcEventVideoReceiveStreamConfig& event);
|
||||
std::string EncodeVideoSendStreamConfig(
|
||||
const RtcEventVideoSendStreamConfig& event);
|
||||
|
||||
// RTCP/RTP are handled similarly for incoming/outgoing.
|
||||
std::string EncodeRtcpPacket(int64_t timestamp_us,
|
||||
const rtc::Buffer& packet,
|
||||
bool is_incoming);
|
||||
std::string EncodeRtpPacket(int64_t timestamp_us,
|
||||
rtc::ArrayView<const uint8_t> header,
|
||||
size_t packet_length,
|
||||
int probe_cluster_id,
|
||||
bool is_incoming);
|
||||
|
||||
std::string Serialize(rtclog::Event* event);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_LEGACY_H_
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_NEW_FORMAT_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_NEW_FORMAT_H_
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "logging/rtc_event_log/encoder/rtc_event_log_encoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace rtclog2 {
|
||||
class EventStream; // Auto-generated from protobuf.
|
||||
} // namespace rtclog2
|
||||
|
||||
class RtcEventAlrState;
|
||||
class RtcEventRouteChange;
|
||||
class RtcEventRemoteEstimate;
|
||||
class RtcEventAudioNetworkAdaptation;
|
||||
class RtcEventAudioPlayout;
|
||||
class RtcEventAudioReceiveStreamConfig;
|
||||
class RtcEventAudioSendStreamConfig;
|
||||
class RtcEventBweUpdateDelayBased;
|
||||
class RtcEventBweUpdateLossBased;
|
||||
class RtcEventDtlsTransportState;
|
||||
class RtcEventDtlsWritableState;
|
||||
class RtcEventLoggingStarted;
|
||||
class RtcEventLoggingStopped;
|
||||
class RtcEventNetEqSetMinimumDelay;
|
||||
class RtcEventProbeClusterCreated;
|
||||
class RtcEventProbeResultFailure;
|
||||
class RtcEventProbeResultSuccess;
|
||||
class RtcEventRtcpPacketIncoming;
|
||||
class RtcEventRtcpPacketOutgoing;
|
||||
class RtcEventRtpPacketIncoming;
|
||||
class RtcEventRtpPacketOutgoing;
|
||||
class RtcEventVideoReceiveStreamConfig;
|
||||
class RtcEventVideoSendStreamConfig;
|
||||
class RtcEventIceCandidatePairConfig;
|
||||
class RtcEventIceCandidatePair;
|
||||
class RtpPacket;
|
||||
class RtcEventFrameDecoded;
|
||||
class RtcEventGenericAckReceived;
|
||||
class RtcEventGenericPacketReceived;
|
||||
class RtcEventGenericPacketSent;
|
||||
|
||||
class RtcEventLogEncoderNewFormat final : public RtcEventLogEncoder {
|
||||
public:
|
||||
explicit RtcEventLogEncoderNewFormat(const FieldTrialsView& field_trials);
|
||||
~RtcEventLogEncoderNewFormat() override = default;
|
||||
|
||||
std::string EncodeBatch(
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) override;
|
||||
|
||||
std::string EncodeLogStart(int64_t timestamp_us,
|
||||
int64_t utc_time_us) override;
|
||||
std::string EncodeLogEnd(int64_t timestamp_us) override;
|
||||
|
||||
private:
|
||||
// Encoding entry-point for the various RtcEvent subclasses.
|
||||
void EncodeAlrState(rtc::ArrayView<const RtcEventAlrState*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeAudioNetworkAdaptation(
|
||||
rtc::ArrayView<const RtcEventAudioNetworkAdaptation*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeAudioPlayout(rtc::ArrayView<const RtcEventAudioPlayout*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeAudioRecvStreamConfig(
|
||||
rtc::ArrayView<const RtcEventAudioReceiveStreamConfig*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeAudioSendStreamConfig(
|
||||
rtc::ArrayView<const RtcEventAudioSendStreamConfig*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeBweUpdateDelayBased(
|
||||
rtc::ArrayView<const RtcEventBweUpdateDelayBased*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeBweUpdateLossBased(
|
||||
rtc::ArrayView<const RtcEventBweUpdateLossBased*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeDtlsTransportState(
|
||||
rtc::ArrayView<const RtcEventDtlsTransportState*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeDtlsWritableState(
|
||||
rtc::ArrayView<const RtcEventDtlsWritableState*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeFramesDecoded(
|
||||
rtc::ArrayView<const RtcEventFrameDecoded* const> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeGenericAcksReceived(
|
||||
rtc::ArrayView<const RtcEventGenericAckReceived*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeGenericPacketsReceived(
|
||||
rtc::ArrayView<const RtcEventGenericPacketReceived*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeGenericPacketsSent(
|
||||
rtc::ArrayView<const RtcEventGenericPacketSent*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeIceCandidatePairConfig(
|
||||
rtc::ArrayView<const RtcEventIceCandidatePairConfig*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeIceCandidatePairEvent(
|
||||
rtc::ArrayView<const RtcEventIceCandidatePair*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeLoggingStarted(rtc::ArrayView<const RtcEventLoggingStarted*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeLoggingStopped(rtc::ArrayView<const RtcEventLoggingStopped*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeNetEqSetMinimumDelay(
|
||||
rtc::ArrayView<const RtcEventNetEqSetMinimumDelay*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeProbeClusterCreated(
|
||||
rtc::ArrayView<const RtcEventProbeClusterCreated*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeProbeResultFailure(
|
||||
rtc::ArrayView<const RtcEventProbeResultFailure*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeProbeResultSuccess(
|
||||
rtc::ArrayView<const RtcEventProbeResultSuccess*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeRouteChange(rtc::ArrayView<const RtcEventRouteChange*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeRemoteEstimate(rtc::ArrayView<const RtcEventRemoteEstimate*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeRtcpPacketIncoming(
|
||||
rtc::ArrayView<const RtcEventRtcpPacketIncoming*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeRtcpPacketOutgoing(
|
||||
rtc::ArrayView<const RtcEventRtcpPacketOutgoing*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeRtpPacketIncoming(
|
||||
const std::map<uint32_t, std::vector<const RtcEventRtpPacketIncoming*>>&
|
||||
batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeRtpPacketOutgoing(
|
||||
const std::map<uint32_t, std::vector<const RtcEventRtpPacketOutgoing*>>&
|
||||
batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeVideoRecvStreamConfig(
|
||||
rtc::ArrayView<const RtcEventVideoReceiveStreamConfig*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeVideoSendStreamConfig(
|
||||
rtc::ArrayView<const RtcEventVideoSendStreamConfig*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
template <typename Batch, typename ProtoType>
|
||||
void EncodeRtpPacket(const Batch& batch, ProtoType* proto_batch);
|
||||
|
||||
const bool encode_neteq_set_minimum_delay_kill_switch_;
|
||||
const bool encode_dependency_descriptor_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_NEW_FORMAT_H_
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* 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 "logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
|
||||
#include "logging/rtc_event_log/encoder/var_int.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_alr_state.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_begin_log.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_end_log.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_frame_decoded.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_generic_ack_received.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_generic_packet_received.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_generic_packet_sent.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_probe_result_success.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_remote_estimate.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_route_change.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
std::string RtcEventLogEncoderV3::EncodeLogStart(int64_t timestamp_us,
|
||||
int64_t utc_time_us) {
|
||||
std::unique_ptr<RtcEventBeginLog> begin_log =
|
||||
std::make_unique<RtcEventBeginLog>(Timestamp::Micros(timestamp_us),
|
||||
Timestamp::Micros(utc_time_us));
|
||||
std::vector<const RtcEvent*> batch;
|
||||
batch.push_back(begin_log.get());
|
||||
|
||||
std::string encoded_event = RtcEventBeginLog::Encode(batch);
|
||||
|
||||
return encoded_event;
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderV3::EncodeLogEnd(int64_t timestamp_us) {
|
||||
std::unique_ptr<RtcEventEndLog> end_log =
|
||||
std::make_unique<RtcEventEndLog>(Timestamp::Micros(timestamp_us));
|
||||
std::vector<const RtcEvent*> batch;
|
||||
batch.push_back(end_log.get());
|
||||
|
||||
std::string encoded_event = RtcEventEndLog::Encode(batch);
|
||||
|
||||
return encoded_event;
|
||||
}
|
||||
|
||||
RtcEventLogEncoderV3::RtcEventLogEncoderV3() {
|
||||
encoders_[RtcEvent::Type::AlrStateEvent] = RtcEventAlrState::Encode;
|
||||
encoders_[RtcEvent::Type::AudioNetworkAdaptation] =
|
||||
RtcEventAudioNetworkAdaptation::Encode;
|
||||
encoders_[RtcEvent::Type::AudioPlayout] = RtcEventAudioPlayout::Encode;
|
||||
encoders_[RtcEvent::Type::AudioReceiveStreamConfig] =
|
||||
RtcEventAudioReceiveStreamConfig::Encode;
|
||||
encoders_[RtcEvent::Type::AudioSendStreamConfig] =
|
||||
RtcEventAudioSendStreamConfig::Encode;
|
||||
encoders_[RtcEvent::Type::BweUpdateDelayBased] =
|
||||
RtcEventBweUpdateDelayBased::Encode;
|
||||
encoders_[RtcEvent::Type::BweUpdateLossBased] =
|
||||
RtcEventBweUpdateLossBased::Encode;
|
||||
encoders_[RtcEvent::Type::DtlsTransportState] =
|
||||
RtcEventDtlsTransportState::Encode;
|
||||
encoders_[RtcEvent::Type::DtlsWritableState] =
|
||||
RtcEventDtlsWritableState::Encode;
|
||||
encoders_[RtcEvent::Type::FrameDecoded] = RtcEventFrameDecoded::Encode;
|
||||
encoders_[RtcEvent::Type::GenericAckReceived] =
|
||||
RtcEventGenericAckReceived::Encode;
|
||||
encoders_[RtcEvent::Type::GenericPacketReceived] =
|
||||
RtcEventGenericPacketReceived::Encode;
|
||||
encoders_[RtcEvent::Type::GenericPacketSent] =
|
||||
RtcEventGenericPacketSent::Encode;
|
||||
encoders_[RtcEvent::Type::IceCandidatePairConfig] =
|
||||
RtcEventIceCandidatePairConfig::Encode;
|
||||
encoders_[RtcEvent::Type::IceCandidatePairEvent] =
|
||||
RtcEventIceCandidatePair::Encode;
|
||||
encoders_[RtcEvent::Type::ProbeClusterCreated] =
|
||||
RtcEventProbeClusterCreated::Encode;
|
||||
encoders_[RtcEvent::Type::ProbeResultFailure] =
|
||||
RtcEventProbeResultFailure::Encode;
|
||||
encoders_[RtcEvent::Type::ProbeResultSuccess] =
|
||||
RtcEventProbeResultSuccess::Encode;
|
||||
encoders_[RtcEvent::Type::RemoteEstimateEvent] =
|
||||
RtcEventRemoteEstimate::Encode;
|
||||
encoders_[RtcEvent::Type::RouteChangeEvent] = RtcEventRouteChange::Encode;
|
||||
encoders_[RtcEvent::Type::RtcpPacketIncoming] =
|
||||
RtcEventRtcpPacketIncoming::Encode;
|
||||
encoders_[RtcEvent::Type::RtcpPacketOutgoing] =
|
||||
RtcEventRtcpPacketOutgoing::Encode;
|
||||
encoders_[RtcEvent::Type::RtpPacketIncoming] =
|
||||
RtcEventRtpPacketIncoming::Encode;
|
||||
encoders_[RtcEvent::Type::RtpPacketOutgoing] =
|
||||
RtcEventRtpPacketOutgoing::Encode;
|
||||
encoders_[RtcEvent::Type::VideoReceiveStreamConfig] =
|
||||
RtcEventVideoReceiveStreamConfig::Encode;
|
||||
encoders_[RtcEvent::Type::VideoSendStreamConfig] =
|
||||
RtcEventVideoSendStreamConfig::Encode;
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderV3::EncodeBatch(
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) {
|
||||
struct EventGroupKey {
|
||||
// Events are grouped by event type. For compression efficiency,
|
||||
// events can optionally have a secondary key, in most cases the
|
||||
// SSRC.
|
||||
RtcEvent::Type type;
|
||||
uint32_t secondary_group_key;
|
||||
|
||||
bool operator<(EventGroupKey other) const {
|
||||
return type < other.type ||
|
||||
(type == other.type &&
|
||||
secondary_group_key < other.secondary_group_key);
|
||||
}
|
||||
};
|
||||
|
||||
std::map<EventGroupKey, std::vector<const RtcEvent*>> event_groups;
|
||||
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
event_groups[{(*it)->GetType(), (*it)->GetGroupKey()}].push_back(it->get());
|
||||
}
|
||||
|
||||
std::string encoded_output;
|
||||
for (auto& kv : event_groups) {
|
||||
auto it = encoders_.find(kv.first.type);
|
||||
RTC_DCHECK(it != encoders_.end());
|
||||
if (it != encoders_.end()) {
|
||||
auto& encoder = it->second;
|
||||
// TODO(terelius): Use some "string builder" or preallocate?
|
||||
encoded_output += encoder(kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
return encoded_output;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_V3_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_V3_H_
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "logging/rtc_event_log/encoder/rtc_event_log_encoder.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_definition.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RtcEventLogEncoderV3 final : public RtcEventLogEncoder {
|
||||
public:
|
||||
RtcEventLogEncoderV3();
|
||||
~RtcEventLogEncoderV3() override = default;
|
||||
|
||||
std::string EncodeBatch(
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
|
||||
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) override;
|
||||
|
||||
std::string EncodeLogStart(int64_t timestamp_us,
|
||||
int64_t utc_time_us) override;
|
||||
std::string EncodeLogEnd(int64_t timestamp_us) override;
|
||||
|
||||
private:
|
||||
std::map<RtcEvent::Type,
|
||||
std::function<std::string(rtc::ArrayView<const RtcEvent*>)>>
|
||||
encoders_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_V3_H_
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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 "logging/rtc_event_log/encoder/var_int.h"
|
||||
|
||||
#include "rtc_base/bitstream_reader.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
// TODO(eladalon): Add unit tests.
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const size_t kMaxVarIntLengthBytes = 10; // ceil(64 / 7.0) is 10.
|
||||
|
||||
std::string EncodeVarInt(uint64_t input) {
|
||||
std::string output;
|
||||
output.reserve(kMaxVarIntLengthBytes);
|
||||
|
||||
do {
|
||||
uint8_t byte = static_cast<uint8_t>(input & 0x7f);
|
||||
input >>= 7;
|
||||
if (input > 0) {
|
||||
byte |= 0x80;
|
||||
}
|
||||
output += byte;
|
||||
} while (input > 0);
|
||||
|
||||
RTC_DCHECK_GE(output.size(), 1u);
|
||||
RTC_DCHECK_LE(output.size(), kMaxVarIntLengthBytes);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// There is some code duplication between the flavors of this function.
|
||||
// For performance's sake, it's best to just keep it.
|
||||
std::pair<bool, absl::string_view> DecodeVarInt(absl::string_view input,
|
||||
uint64_t* output) {
|
||||
RTC_DCHECK(output);
|
||||
|
||||
uint64_t decoded = 0;
|
||||
for (size_t i = 0; i < input.length() && i < kMaxVarIntLengthBytes; ++i) {
|
||||
decoded += (static_cast<uint64_t>(input[i] & 0x7f)
|
||||
<< static_cast<uint64_t>(7 * i));
|
||||
if (!(input[i] & 0x80)) {
|
||||
*output = decoded;
|
||||
return {true, input.substr(i + 1)};
|
||||
}
|
||||
}
|
||||
|
||||
return {false, input};
|
||||
}
|
||||
|
||||
// There is some code duplication between the flavors of this function.
|
||||
// For performance's sake, it's best to just keep it.
|
||||
uint64_t DecodeVarInt(BitstreamReader& input) {
|
||||
uint64_t decoded = 0;
|
||||
for (size_t i = 0; i < kMaxVarIntLengthBytes; ++i) {
|
||||
uint8_t byte = input.Read<uint8_t>();
|
||||
decoded +=
|
||||
(static_cast<uint64_t>(byte & 0x7f) << static_cast<uint64_t>(7 * i));
|
||||
if (!(byte & 0x80)) {
|
||||
return decoded;
|
||||
}
|
||||
}
|
||||
|
||||
input.Invalidate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 LOGGING_RTC_EVENT_LOG_ENCODER_VAR_INT_H_
|
||||
#define LOGGING_RTC_EVENT_LOG_ENCODER_VAR_INT_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/bitstream_reader.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
extern const size_t kMaxVarIntLengthBytes;
|
||||
|
||||
// Encode a given uint64_t as a varint. From least to most significant,
|
||||
// each batch of seven bits are put into the lower bits of a byte, and the last
|
||||
// remaining bit in that byte (the highest one) marks whether additional bytes
|
||||
// follow (which happens if and only if there are other bits in `input` which
|
||||
// are non-zero).
|
||||
// Notes: If input == 0, one byte is used. If input is uint64_t::max, exactly
|
||||
// kMaxVarIntLengthBytes are used.
|
||||
std::string EncodeVarInt(uint64_t input);
|
||||
|
||||
// Inverse of EncodeVarInt().
|
||||
// Returns true and the remaining (unread) slice of the input if decoding
|
||||
// succeeds. Returns false otherwise and `output` is not modified.
|
||||
std::pair<bool, absl::string_view> DecodeVarInt(absl::string_view input,
|
||||
uint64_t* output);
|
||||
|
||||
// Same as other version, but uses a BitstreamReader for input.
|
||||
// If decoding is successful returns the decoded varint.
|
||||
// If not successful, `input` reader is set into the failure state, return value
|
||||
// is unspecified.
|
||||
uint64_t DecodeVarInt(BitstreamReader& input);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_ENCODER_VAR_INT_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue