Use delta-encoding in new WebRTC event logs
The new event log format makes use of delta encoding to compress parts of the log. Bug: webrtc:8111 Change-Id: I7bec839555323a7537dcec831d4ac1d5eb109932 Reviewed-on: https://webrtc-review.googlesource.com/c/109161 Commit-Queue: Elad Alon <eladalon@webrtc.org> Reviewed-by: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25584}
This commit is contained in:
parent
72467209a8
commit
d95b0a2fbd
@ -153,6 +153,8 @@ rtc_source_set("rtc_event_video") {
|
||||
]
|
||||
}
|
||||
|
||||
# TODO(eladalon): Break down into (1) encoder and (2) decoder; we don't need
|
||||
# the decoder code in the WebRTC library, only in unit tests and tools.
|
||||
rtc_static_library("rtc_event_log_impl_encoder") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
@ -160,6 +162,8 @@ rtc_static_library("rtc_event_log_impl_encoder") {
|
||||
"rtc_event_log/encoder/blob_encoding.h",
|
||||
"rtc_event_log/encoder/delta_encoding.cc",
|
||||
"rtc_event_log/encoder/delta_encoding.h",
|
||||
"rtc_event_log/encoder/rtc_event_log_encoder_common.cc",
|
||||
"rtc_event_log/encoder/rtc_event_log_encoder_common.h",
|
||||
"rtc_event_log/encoder/varint.cc",
|
||||
"rtc_event_log/encoder/varint.h",
|
||||
]
|
||||
@ -291,6 +295,7 @@ if (rtc_enable_protobuf) {
|
||||
":rtc_event_bwe",
|
||||
":rtc_event_log2_proto",
|
||||
":rtc_event_log_api",
|
||||
":rtc_event_log_impl_encoder",
|
||||
":rtc_event_log_proto",
|
||||
":rtc_stream_config",
|
||||
"..:webrtc_common",
|
||||
@ -317,6 +322,7 @@ if (rtc_enable_protobuf) {
|
||||
sources = [
|
||||
"rtc_event_log/encoder/blob_encoding_unittest.cc",
|
||||
"rtc_event_log/encoder/delta_encoding_unittest.cc",
|
||||
"rtc_event_log/encoder/rtc_event_log_encoder_common_unittest.cc",
|
||||
"rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc",
|
||||
"rtc_event_log/output/rtc_event_log_output_file_unittest.cc",
|
||||
"rtc_event_log/rtc_event_log_unittest.cc",
|
||||
|
||||
@ -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
|
||||
93
logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h
Normal file
93
logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h
Normal file
@ -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,83 @@
|
||||
/*
|
||||
* 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 <limits>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc_event_logging {
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
class SignednessConversionTest : public testing::Test {
|
||||
public:
|
||||
static_assert(std::is_integral<T>::value, "");
|
||||
static_assert(std::is_signed<T>::value, "");
|
||||
};
|
||||
|
||||
TYPED_TEST_CASE_P(SignednessConversionTest);
|
||||
|
||||
TYPED_TEST_P(SignednessConversionTest, CorrectlyConvertsLegalValues) {
|
||||
using T = TypeParam;
|
||||
std::vector<T> legal_values = {std::numeric_limits<T>::min(),
|
||||
std::numeric_limits<T>::min() + 1,
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
std::numeric_limits<T>::max() - 1,
|
||||
std::numeric_limits<T>::max()};
|
||||
for (T val : legal_values) {
|
||||
const auto unsigned_val = ToUnsigned(val);
|
||||
T signed_val;
|
||||
ASSERT_TRUE(ToSigned<T>(unsigned_val, &signed_val))
|
||||
<< "Failed on " << static_cast<uint64_t>(unsigned_val) << ".";
|
||||
EXPECT_EQ(val, signed_val)
|
||||
<< "Failed on " << static_cast<uint64_t>(unsigned_val) << ".";
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(SignednessConversionTest, FailsOnConvertingIllegalValues) {
|
||||
using T = TypeParam;
|
||||
|
||||
// Note that a signed integer whose width is N bits, has N-1 digits.
|
||||
constexpr bool width_is_64 = std::numeric_limits<T>::digits == 63;
|
||||
|
||||
if (width_is_64) {
|
||||
return; // Test irrelevant; illegal values do not exist.
|
||||
}
|
||||
|
||||
const uint64_t max_legal_value = ToUnsigned(static_cast<T>(-1));
|
||||
|
||||
const std::vector<uint64_t> illegal_values = {
|
||||
max_legal_value + 1u, max_legal_value + 2u,
|
||||
std::numeric_limits<uint64_t>::max() - 1u,
|
||||
std::numeric_limits<uint64_t>::max()};
|
||||
|
||||
for (uint64_t unsigned_val : illegal_values) {
|
||||
T signed_val;
|
||||
EXPECT_FALSE(ToSigned<T>(unsigned_val, &signed_val))
|
||||
<< "Failed on " << static_cast<uint64_t>(unsigned_val) << ".";
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(SignednessConversionTest,
|
||||
CorrectlyConvertsLegalValues,
|
||||
FailsOnConvertingIllegalValues);
|
||||
|
||||
using Types = ::testing::Types<int8_t, int16_t, int32_t, int64_t>;
|
||||
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(_, SignednessConversionTest, Types);
|
||||
|
||||
} // namespace
|
||||
} // namespace webrtc_event_logging
|
||||
@ -10,9 +10,11 @@
|
||||
|
||||
#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/array_view.h"
|
||||
#include "logging/rtc_event_log/encoder/blob_encoding.h"
|
||||
#include "logging/rtc_event_log/encoder/delta_encoding.h"
|
||||
#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.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"
|
||||
@ -61,6 +63,8 @@ RTC_PUSH_IGNORING_WUNDEF()
|
||||
#endif
|
||||
RTC_POP_IGNORING_WUNDEF()
|
||||
|
||||
using webrtc_event_logging::ToUnsigned;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
@ -235,6 +239,13 @@ rtclog2::IceCandidatePairEvent::IceCandidatePairEventType ConvertToProtoFormat(
|
||||
return rtclog2::IceCandidatePairEvent::UNKNOWN_CHECK_TYPE;
|
||||
}
|
||||
|
||||
uint8_t ConvertAudioLevelToProtoFormat(bool voice_activity,
|
||||
uint8_t audio_level) {
|
||||
RTC_DCHECK_EQ(audio_level & static_cast<uint8_t>(0x80), 0);
|
||||
constexpr uint8_t kVoiceActivityBit = 0x80;
|
||||
return audio_level | (voice_activity ? kVoiceActivityBit : 0);
|
||||
}
|
||||
|
||||
// Copies all RTCP blocks except APP, SDES and unknown from |packet| to
|
||||
// |buffer|. |buffer| must have space for |IP_PACKET_SIZE| bytes. |packet| must
|
||||
// be at most |IP_PACKET_SIZE| bytes long.
|
||||
@ -282,6 +293,311 @@ size_t RemoveNonWhitelistedRtcpBlocks(const rtc::Buffer& packet,
|
||||
}
|
||||
return buffer_length;
|
||||
}
|
||||
|
||||
template <typename EventType, typename ProtoType>
|
||||
void EncodeRtcpPacket(rtc::ArrayView<const EventType*> batch,
|
||||
ProtoType* proto_batch) {
|
||||
if (batch.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Base event
|
||||
const EventType* const base_event = batch[0];
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
{
|
||||
uint8_t buffer[IP_PACKET_SIZE];
|
||||
size_t buffer_length =
|
||||
RemoveNonWhitelistedRtcpBlocks(base_event->packet_, buffer);
|
||||
proto_batch->set_raw_packet(buffer, buffer_length);
|
||||
}
|
||||
|
||||
if (batch.size() == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delta encoding
|
||||
proto_batch->set_number_of_deltas(batch.size() - 1);
|
||||
std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
|
||||
std::string encoded_deltas;
|
||||
|
||||
// timestamp_ms
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->timestamp_us_ / 1000;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->timestamp_us_ / 1000, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_timestamp_deltas_ms(encoded_deltas);
|
||||
}
|
||||
|
||||
// raw_packet
|
||||
std::vector<std::string> scrubed_packets(batch.size() - 1);
|
||||
for (size_t i = 0; i < scrubed_packets.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
scrubed_packets[i].resize(event->packet_.size());
|
||||
static_assert(sizeof(std::string::value_type) == sizeof(uint8_t), "");
|
||||
const size_t buffer_length = RemoveNonWhitelistedRtcpBlocks(
|
||||
event->packet_, reinterpret_cast<uint8_t*>(&scrubed_packets[i][0]));
|
||||
scrubed_packets[i].resize(buffer_length);
|
||||
}
|
||||
// TODO(eladalon): s/deltas/blobs in separate CL.
|
||||
proto_batch->set_raw_packet_deltas(EncodeBlobs(scrubed_packets));
|
||||
}
|
||||
|
||||
template <typename EventType, typename ProtoType>
|
||||
void EncodeRtpPacket(const std::vector<const EventType*>& batch,
|
||||
ProtoType* proto_batch) {
|
||||
if (batch.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Base event
|
||||
const EventType* const base_event = batch[0];
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_marker(base_event->header_.Marker());
|
||||
// TODO(terelius): Is payload type needed?
|
||||
proto_batch->set_payload_type(base_event->header_.PayloadType());
|
||||
proto_batch->set_sequence_number(base_event->header_.SequenceNumber());
|
||||
proto_batch->set_rtp_timestamp(base_event->header_.Timestamp());
|
||||
proto_batch->set_ssrc(base_event->header_.Ssrc());
|
||||
proto_batch->set_payload_size(base_event->payload_length_);
|
||||
proto_batch->set_header_size(base_event->header_length_);
|
||||
proto_batch->set_padding_size(base_event->padding_length_);
|
||||
|
||||
// Add header extensions (base event).
|
||||
absl::optional<uint64_t> base_transport_sequence_number;
|
||||
{
|
||||
uint16_t seqnum;
|
||||
if (base_event->header_.template GetExtension<TransportSequenceNumber>(
|
||||
&seqnum)) {
|
||||
proto_batch->set_transport_sequence_number(seqnum);
|
||||
base_transport_sequence_number = seqnum;
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<uint64_t> unsigned_base_transmission_time_offset;
|
||||
{
|
||||
int32_t offset;
|
||||
if (base_event->header_.template GetExtension<TransmissionOffset>(
|
||||
&offset)) {
|
||||
proto_batch->set_transmission_time_offset(offset);
|
||||
unsigned_base_transmission_time_offset = ToUnsigned(offset);
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<uint64_t> base_absolute_send_time;
|
||||
{
|
||||
uint32_t sendtime;
|
||||
if (base_event->header_.template GetExtension<AbsoluteSendTime>(
|
||||
&sendtime)) {
|
||||
proto_batch->set_absolute_send_time(sendtime);
|
||||
base_absolute_send_time = sendtime;
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<uint64_t> base_video_rotation;
|
||||
{
|
||||
VideoRotation video_rotation;
|
||||
if (base_event->header_.template GetExtension<VideoOrientation>(
|
||||
&video_rotation)) {
|
||||
proto_batch->set_video_rotation(
|
||||
ConvertVideoRotationToCVOByte(video_rotation));
|
||||
base_video_rotation = ConvertVideoRotationToCVOByte(video_rotation);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(eladalon): Separate audio level from voice activity.
|
||||
absl::optional<uint64_t> base_audio_level;
|
||||
{
|
||||
bool voice_activity;
|
||||
uint8_t audio_level;
|
||||
if (base_event->header_.template GetExtension<AudioLevel>(&voice_activity,
|
||||
&audio_level)) {
|
||||
proto_batch->set_audio_level(
|
||||
ConvertAudioLevelToProtoFormat(voice_activity, audio_level));
|
||||
base_audio_level =
|
||||
ConvertAudioLevelToProtoFormat(voice_activity, audio_level);
|
||||
}
|
||||
}
|
||||
|
||||
if (batch.size() == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delta encoding
|
||||
proto_batch->set_number_of_deltas(batch.size() - 1);
|
||||
std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
|
||||
std::string encoded_deltas;
|
||||
|
||||
// timestamp_ms (event)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->timestamp_us_ / 1000;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->timestamp_us_ / 1000, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_timestamp_deltas_ms(encoded_deltas);
|
||||
}
|
||||
|
||||
// marker (RTP base)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->header_.Marker();
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->header_.Marker(), values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_marker_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// payload_type (RTP base)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->header_.PayloadType();
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->header_.PayloadType(), values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_payload_type_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// sequence_number (RTP base)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->header_.SequenceNumber();
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->header_.SequenceNumber(), values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_sequence_number_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// rtp_timestamp (RTP base)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->header_.Timestamp();
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->header_.Timestamp(), values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_rtp_timestamp_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// ssrc (RTP base)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->header_.Ssrc();
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->header_.Ssrc(), values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_ssrc_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// payload_size (RTP base)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->payload_length_;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->payload_length_, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_payload_size_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// header_size (RTP base)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->header_length_;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->header_length_, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_header_size_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// padding_size (RTP base)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
values[i] = event->padding_length_;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->padding_length_, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_padding_size_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// transport_sequence_number (RTP extension)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
uint16_t seqnum;
|
||||
if (event->header_.template GetExtension<TransportSequenceNumber>(
|
||||
&seqnum)) {
|
||||
values[i] = seqnum;
|
||||
} else {
|
||||
values[i].reset();
|
||||
}
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_transport_sequence_number, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_transport_sequence_number_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// transmission_time_offset (RTP extension)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
int32_t offset;
|
||||
if (event->header_.template GetExtension<TransmissionOffset>(&offset)) {
|
||||
values[i] = ToUnsigned(offset);
|
||||
} else {
|
||||
values[i].reset();
|
||||
}
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(unsigned_base_transmission_time_offset, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_transmission_time_offset_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// absolute_send_time (RTP extension)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
uint32_t sendtime;
|
||||
if (event->header_.template GetExtension<AbsoluteSendTime>(&sendtime)) {
|
||||
values[i] = sendtime;
|
||||
} else {
|
||||
values[i].reset();
|
||||
}
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_absolute_send_time, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_absolute_send_time_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// video_rotation (RTP extension)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
VideoRotation video_rotation;
|
||||
if (event->header_.template GetExtension<VideoOrientation>(
|
||||
&video_rotation)) {
|
||||
values[i] = ConvertVideoRotationToCVOByte(video_rotation);
|
||||
} else {
|
||||
values[i].reset();
|
||||
}
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_video_rotation, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_video_rotation_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// audio_level (RTP extension)
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const EventType* event = batch[i + 1];
|
||||
bool voice_activity;
|
||||
uint8_t audio_level;
|
||||
if (event->header_.template GetExtension<AudioLevel>(&voice_activity,
|
||||
&audio_level)) {
|
||||
values[i] = ConvertAudioLevelToProtoFormat(voice_activity, audio_level);
|
||||
} else {
|
||||
values[i].reset();
|
||||
}
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_audio_level, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_audio_level_deltas(encoded_deltas);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string RtcEventLogEncoderNewFormat::EncodeLogStart(int64_t timestamp_us) {
|
||||
@ -320,8 +636,10 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch(
|
||||
std::vector<const RtcEventProbeResultSuccess*> probe_result_success_events;
|
||||
std::vector<const RtcEventRtcpPacketIncoming*> incoming_rtcp_packets;
|
||||
std::vector<const RtcEventRtcpPacketOutgoing*> outgoing_rtcp_packets;
|
||||
std::vector<const RtcEventRtpPacketIncoming*> incoming_rtp_packets;
|
||||
std::vector<const RtcEventRtpPacketOutgoing*> outgoing_rtp_packets;
|
||||
std::map<uint32_t /* SSRC */, std::vector<const RtcEventRtpPacketIncoming*>>
|
||||
incoming_rtp_packets;
|
||||
std::map<uint32_t /* SSRC */, std::vector<const RtcEventRtpPacketOutgoing*>>
|
||||
outgoing_rtp_packets;
|
||||
std::vector<const RtcEventVideoReceiveStreamConfig*>
|
||||
video_recv_stream_configs;
|
||||
std::vector<const RtcEventVideoSendStreamConfig*> video_send_stream_configs;
|
||||
@ -408,13 +726,15 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch(
|
||||
case RtcEvent::Type::RtpPacketIncoming: {
|
||||
auto* rtc_event =
|
||||
static_cast<const RtcEventRtpPacketIncoming* const>(it->get());
|
||||
incoming_rtp_packets.push_back(rtc_event);
|
||||
auto& v = incoming_rtp_packets[rtc_event->header_.Ssrc()];
|
||||
v.emplace_back(rtc_event);
|
||||
break;
|
||||
}
|
||||
case RtcEvent::Type::RtpPacketOutgoing: {
|
||||
auto* rtc_event =
|
||||
static_cast<const RtcEventRtpPacketOutgoing* const>(it->get());
|
||||
outgoing_rtp_packets.push_back(rtc_event);
|
||||
auto& v = outgoing_rtp_packets[rtc_event->header_.Ssrc()];
|
||||
v.emplace_back(rtc_event);
|
||||
break;
|
||||
}
|
||||
case RtcEvent::Type::VideoReceiveStreamConfig: {
|
||||
@ -487,28 +807,130 @@ void RtcEventLogEncoderNewFormat::EncodeAudioNetworkAdaptation(
|
||||
rtclog2::EventStream* event_stream) {
|
||||
if (batch.size() == 0)
|
||||
return;
|
||||
for (const RtcEventAudioNetworkAdaptation* base_event : batch) {
|
||||
rtclog2::AudioNetworkAdaptations* proto_batch =
|
||||
event_stream->add_audio_network_adaptations();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
if (base_event->config_->bitrate_bps.has_value())
|
||||
proto_batch->set_bitrate_bps(base_event->config_->bitrate_bps.value());
|
||||
if (base_event->config_->frame_length_ms.has_value()) {
|
||||
proto_batch->set_frame_length_ms(
|
||||
base_event->config_->frame_length_ms.value());
|
||||
}
|
||||
if (base_event->config_->uplink_packet_loss_fraction.has_value()) {
|
||||
proto_batch->set_uplink_packet_loss_fraction(
|
||||
base_event->config_->uplink_packet_loss_fraction.value());
|
||||
}
|
||||
if (base_event->config_->enable_fec.has_value())
|
||||
proto_batch->set_enable_fec(base_event->config_->enable_fec.value());
|
||||
if (base_event->config_->enable_dtx.has_value())
|
||||
proto_batch->set_enable_dtx(base_event->config_->enable_dtx.value());
|
||||
if (base_event->config_->num_channels.has_value())
|
||||
proto_batch->set_num_channels(base_event->config_->num_channels.value());
|
||||
|
||||
// Base event
|
||||
const RtcEventAudioNetworkAdaptation* const base_event = batch[0];
|
||||
rtclog2::AudioNetworkAdaptations* proto_batch =
|
||||
event_stream->add_audio_network_adaptations();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
if (base_event->config_->bitrate_bps.has_value())
|
||||
proto_batch->set_bitrate_bps(base_event->config_->bitrate_bps.value());
|
||||
if (base_event->config_->frame_length_ms.has_value()) {
|
||||
proto_batch->set_frame_length_ms(
|
||||
base_event->config_->frame_length_ms.value());
|
||||
}
|
||||
absl::optional<uint64_t> base_uplink_packet_loss_fraction;
|
||||
if (base_event->config_->uplink_packet_loss_fraction.has_value()) {
|
||||
base_uplink_packet_loss_fraction = ConvertPacketLossFractionToProtoFormat(
|
||||
base_event->config_->uplink_packet_loss_fraction.value());
|
||||
proto_batch->set_uplink_packet_loss_fraction(
|
||||
base_uplink_packet_loss_fraction.value());
|
||||
}
|
||||
if (base_event->config_->enable_fec.has_value())
|
||||
proto_batch->set_enable_fec(base_event->config_->enable_fec.value());
|
||||
if (base_event->config_->enable_dtx.has_value())
|
||||
proto_batch->set_enable_dtx(base_event->config_->enable_dtx.value());
|
||||
if (base_event->config_->num_channels.has_value())
|
||||
proto_batch->set_num_channels(base_event->config_->num_channels.value());
|
||||
|
||||
if (batch.size() == 1)
|
||||
return;
|
||||
|
||||
// Delta encoding
|
||||
proto_batch->set_number_of_deltas(batch.size() - 1);
|
||||
std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
|
||||
std::string encoded_deltas;
|
||||
|
||||
// timestamp_ms
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
|
||||
values[i] = event->timestamp_us_ / 1000;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->timestamp_us_ / 1000, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_timestamp_deltas_ms(encoded_deltas);
|
||||
}
|
||||
|
||||
// bitrate_bps
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
|
||||
if (event->config_->bitrate_bps.has_value()) {
|
||||
values[i] = ToUnsigned(event->config_->bitrate_bps.value());
|
||||
} else {
|
||||
values[i].reset();
|
||||
}
|
||||
}
|
||||
const absl::optional<uint64_t> unsigned_base_bitrate_bps =
|
||||
base_event->config_->bitrate_bps.has_value()
|
||||
? ToUnsigned(base_event->config_->bitrate_bps.value())
|
||||
: absl::optional<uint64_t>();
|
||||
encoded_deltas = EncodeDeltas(unsigned_base_bitrate_bps, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_bitrate_deltas_bps(encoded_deltas);
|
||||
}
|
||||
|
||||
// frame_length_ms
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
|
||||
if (event->config_->frame_length_ms.has_value()) {
|
||||
values[i] = ToUnsigned(event->config_->frame_length_ms.value());
|
||||
} else {
|
||||
values[i].reset();
|
||||
}
|
||||
}
|
||||
const absl::optional<uint64_t> unsigned_base_frame_length_ms =
|
||||
base_event->config_->frame_length_ms.has_value()
|
||||
? ToUnsigned(base_event->config_->frame_length_ms.value())
|
||||
: absl::optional<uint64_t>();
|
||||
encoded_deltas = EncodeDeltas(unsigned_base_frame_length_ms, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_frame_length_deltas_ms(encoded_deltas);
|
||||
}
|
||||
|
||||
// uplink_packet_loss_fraction
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
|
||||
if (event->config_->uplink_packet_loss_fraction.has_value()) {
|
||||
values[i] = ConvertPacketLossFractionToProtoFormat(
|
||||
event->config_->uplink_packet_loss_fraction.value());
|
||||
} else {
|
||||
values[i].reset();
|
||||
}
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_uplink_packet_loss_fraction, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_uplink_packet_loss_fraction_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// enable_fec
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
|
||||
values[i] = event->config_->enable_fec;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->config_->enable_fec, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_enable_fec_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// enable_dtx
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
|
||||
values[i] = event->config_->enable_dtx;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->config_->enable_dtx, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_enable_dtx_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// num_channels
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
|
||||
values[i] = event->config_->num_channels;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->config_->num_channels, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_num_channels_deltas(encoded_deltas);
|
||||
}
|
||||
// TODO(terelius): Delta-compress rest of batch.
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderNewFormat::EncodeAudioPlayout(
|
||||
@ -516,13 +938,41 @@ void RtcEventLogEncoderNewFormat::EncodeAudioPlayout(
|
||||
rtclog2::EventStream* event_stream) {
|
||||
if (batch.size() == 0)
|
||||
return;
|
||||
for (const RtcEventAudioPlayout* base_event : batch) {
|
||||
rtclog2::AudioPlayoutEvents* proto_batch =
|
||||
event_stream->add_audio_playout_events();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_local_ssrc(base_event->ssrc_);
|
||||
|
||||
// Base event
|
||||
const RtcEventAudioPlayout* const base_event = batch[0];
|
||||
rtclog2::AudioPlayoutEvents* proto_batch =
|
||||
event_stream->add_audio_playout_events();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_local_ssrc(base_event->ssrc_);
|
||||
|
||||
if (batch.size() == 1)
|
||||
return;
|
||||
|
||||
// Delta encoding
|
||||
proto_batch->set_number_of_deltas(batch.size() - 1);
|
||||
std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
|
||||
std::string encoded_deltas;
|
||||
|
||||
// timestamp_ms
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioPlayout* event = batch[i + 1];
|
||||
values[i] = event->timestamp_us_ / 1000;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->timestamp_us_ / 1000, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_timestamp_deltas_ms(encoded_deltas);
|
||||
}
|
||||
|
||||
// local_ssrc
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventAudioPlayout* event = batch[i + 1];
|
||||
values[i] = event->ssrc_;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->ssrc_, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_local_ssrc_deltas(encoded_deltas);
|
||||
}
|
||||
// TODO(terelius): Delta-compress rest of batch.
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderNewFormat::EncodeAudioRecvStreamConfig(
|
||||
@ -571,15 +1021,56 @@ void RtcEventLogEncoderNewFormat::EncodeBweUpdateDelayBased(
|
||||
rtclog2::EventStream* event_stream) {
|
||||
if (batch.size() == 0)
|
||||
return;
|
||||
for (const RtcEventBweUpdateDelayBased* base_event : batch) {
|
||||
rtclog2::DelayBasedBweUpdates* proto_batch =
|
||||
event_stream->add_delay_based_bwe_updates();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_bitrate_bps(base_event->bitrate_bps_);
|
||||
proto_batch->set_detector_state(
|
||||
ConvertToProtoFormat(base_event->detector_state_));
|
||||
|
||||
// Base event
|
||||
const RtcEventBweUpdateDelayBased* const base_event = batch[0];
|
||||
rtclog2::DelayBasedBweUpdates* proto_batch =
|
||||
event_stream->add_delay_based_bwe_updates();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_bitrate_bps(base_event->bitrate_bps_);
|
||||
proto_batch->set_detector_state(
|
||||
ConvertToProtoFormat(base_event->detector_state_));
|
||||
|
||||
if (batch.size() == 1)
|
||||
return;
|
||||
|
||||
// Delta encoding
|
||||
proto_batch->set_number_of_deltas(batch.size() - 1);
|
||||
std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
|
||||
std::string encoded_deltas;
|
||||
|
||||
// timestamp_ms
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventBweUpdateDelayBased* event = batch[i + 1];
|
||||
values[i] = event->timestamp_us_ / 1000;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->timestamp_us_ / 1000, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_timestamp_deltas_ms(encoded_deltas);
|
||||
}
|
||||
|
||||
// bitrate_bps
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventBweUpdateDelayBased* event = batch[i + 1];
|
||||
values[i] = event->bitrate_bps_;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->bitrate_bps_, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_bitrate_deltas_bps(encoded_deltas);
|
||||
}
|
||||
|
||||
// detector_state
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventBweUpdateDelayBased* event = batch[i + 1];
|
||||
values[i] =
|
||||
static_cast<uint64_t>(ConvertToProtoFormat(event->detector_state_));
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(
|
||||
static_cast<uint64_t>(ConvertToProtoFormat(base_event->detector_state_)),
|
||||
values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_detector_state_deltas(encoded_deltas);
|
||||
}
|
||||
// TODO(terelius): Delta-compress rest of batch.
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderNewFormat::EncodeBweUpdateLossBased(
|
||||
@ -587,15 +1078,63 @@ void RtcEventLogEncoderNewFormat::EncodeBweUpdateLossBased(
|
||||
rtclog2::EventStream* event_stream) {
|
||||
if (batch.size() == 0)
|
||||
return;
|
||||
for (const RtcEventBweUpdateLossBased* base_event : batch) {
|
||||
rtclog2::LossBasedBweUpdates* proto_batch =
|
||||
event_stream->add_loss_based_bwe_updates();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_bitrate_bps(base_event->bitrate_bps_);
|
||||
proto_batch->set_fraction_loss(base_event->fraction_loss_);
|
||||
proto_batch->set_total_packets(base_event->total_packets_);
|
||||
|
||||
// Base event
|
||||
const RtcEventBweUpdateLossBased* const base_event = batch[0];
|
||||
rtclog2::LossBasedBweUpdates* proto_batch =
|
||||
event_stream->add_loss_based_bwe_updates();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_bitrate_bps(base_event->bitrate_bps_);
|
||||
proto_batch->set_fraction_loss(base_event->fraction_loss_);
|
||||
proto_batch->set_total_packets(base_event->total_packets_);
|
||||
|
||||
if (batch.size() == 1)
|
||||
return;
|
||||
|
||||
// Delta encoding
|
||||
proto_batch->set_number_of_deltas(batch.size() - 1);
|
||||
std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
|
||||
std::string encoded_deltas;
|
||||
|
||||
// timestamp_ms
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventBweUpdateLossBased* event = batch[i + 1];
|
||||
values[i] = event->timestamp_us_ / 1000;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->timestamp_us_ / 1000, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_timestamp_deltas_ms(encoded_deltas);
|
||||
}
|
||||
|
||||
// bitrate_bps
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventBweUpdateLossBased* event = batch[i + 1];
|
||||
values[i] = event->bitrate_bps_;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->bitrate_bps_, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_bitrate_deltas_bps(encoded_deltas);
|
||||
}
|
||||
|
||||
// fraction_loss
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventBweUpdateLossBased* event = batch[i + 1];
|
||||
values[i] = event->fraction_loss_;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->fraction_loss_, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_fraction_loss_deltas(encoded_deltas);
|
||||
}
|
||||
|
||||
// total_packets
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
const RtcEventBweUpdateLossBased* event = batch[i + 1];
|
||||
values[i] = event->total_packets_;
|
||||
}
|
||||
encoded_deltas = EncodeDeltas(base_event->total_packets_, values);
|
||||
if (!encoded_deltas.empty()) {
|
||||
proto_batch->set_total_packets_deltas(encoded_deltas);
|
||||
}
|
||||
// TODO(terelius): Delta-compress rest of batch.
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderNewFormat::EncodeProbeClusterCreated(
|
||||
@ -640,149 +1179,39 @@ void RtcEventLogEncoderNewFormat::EncodeProbeResultSuccess(
|
||||
void RtcEventLogEncoderNewFormat::EncodeRtcpPacketIncoming(
|
||||
rtc::ArrayView<const RtcEventRtcpPacketIncoming*> batch,
|
||||
rtclog2::EventStream* event_stream) {
|
||||
if (batch.size() == 0)
|
||||
if (batch.empty()) {
|
||||
return;
|
||||
for (const RtcEventRtcpPacketIncoming* base_event : batch) {
|
||||
rtclog2::IncomingRtcpPackets* proto_batch =
|
||||
event_stream->add_incoming_rtcp_packets();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
|
||||
uint8_t buffer[IP_PACKET_SIZE];
|
||||
size_t buffer_length =
|
||||
RemoveNonWhitelistedRtcpBlocks(base_event->packet_, buffer);
|
||||
proto_batch->set_raw_packet(buffer, buffer_length);
|
||||
}
|
||||
// TODO(terelius): Delta-compress rest of batch.
|
||||
EncodeRtcpPacket(batch, event_stream->add_incoming_rtcp_packets());
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderNewFormat::EncodeRtcpPacketOutgoing(
|
||||
rtc::ArrayView<const RtcEventRtcpPacketOutgoing*> batch,
|
||||
rtclog2::EventStream* event_stream) {
|
||||
if (batch.size() == 0)
|
||||
if (batch.empty()) {
|
||||
return;
|
||||
for (const RtcEventRtcpPacketOutgoing* base_event : batch) {
|
||||
rtclog2::OutgoingRtcpPackets* proto_batch =
|
||||
event_stream->add_outgoing_rtcp_packets();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
|
||||
uint8_t buffer[IP_PACKET_SIZE];
|
||||
size_t buffer_length =
|
||||
RemoveNonWhitelistedRtcpBlocks(base_event->packet_, buffer);
|
||||
proto_batch->set_raw_packet(buffer, buffer_length);
|
||||
}
|
||||
// TODO(terelius): Delta-compress rest of batch.
|
||||
EncodeRtcpPacket(batch, event_stream->add_outgoing_rtcp_packets());
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderNewFormat::EncodeRtpPacketIncoming(
|
||||
rtc::ArrayView<const RtcEventRtpPacketIncoming*> batch,
|
||||
const std::map<uint32_t, std::vector<const RtcEventRtpPacketIncoming*>>&
|
||||
batch,
|
||||
rtclog2::EventStream* event_stream) {
|
||||
if (batch.size() == 0)
|
||||
return;
|
||||
for (const RtcEventRtpPacketIncoming* base_event : batch) {
|
||||
rtclog2::IncomingRtpPackets* proto_batch =
|
||||
event_stream->add_incoming_rtp_packets();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_marker(base_event->header_.Marker());
|
||||
// TODO(terelius): Is payload type needed?
|
||||
proto_batch->set_payload_type(base_event->header_.PayloadType());
|
||||
proto_batch->set_sequence_number(base_event->header_.SequenceNumber());
|
||||
proto_batch->set_rtp_timestamp(base_event->header_.Timestamp());
|
||||
proto_batch->set_ssrc(base_event->header_.Ssrc());
|
||||
proto_batch->set_payload_size(base_event->payload_length_);
|
||||
proto_batch->set_header_size(base_event->header_length_);
|
||||
proto_batch->set_padding_size(base_event->padding_length_);
|
||||
|
||||
// Add header extensions.
|
||||
if (base_event->header_.HasExtension<TransmissionOffset>()) {
|
||||
int32_t offset;
|
||||
base_event->header_.GetExtension<TransmissionOffset>(&offset);
|
||||
proto_batch->set_transmission_time_offset(offset);
|
||||
}
|
||||
if (base_event->header_.HasExtension<AbsoluteSendTime>()) {
|
||||
uint32_t sendtime;
|
||||
base_event->header_.GetExtension<AbsoluteSendTime>(&sendtime);
|
||||
proto_batch->set_absolute_send_time(sendtime);
|
||||
}
|
||||
if (base_event->header_.HasExtension<TransportSequenceNumber>()) {
|
||||
uint16_t seqnum;
|
||||
base_event->header_.GetExtension<TransportSequenceNumber>(&seqnum);
|
||||
proto_batch->set_transport_sequence_number(seqnum);
|
||||
}
|
||||
if (base_event->header_.HasExtension<AudioLevel>()) {
|
||||
bool voice_activity;
|
||||
uint8_t audio_level;
|
||||
base_event->header_.GetExtension<AudioLevel>(&voice_activity,
|
||||
&audio_level);
|
||||
RTC_DCHECK(audio_level < 128);
|
||||
if (voice_activity) {
|
||||
audio_level += 128; // Most significant bit indicates voice activity.
|
||||
}
|
||||
proto_batch->set_audio_level(audio_level);
|
||||
}
|
||||
if (base_event->header_.HasExtension<VideoOrientation>()) {
|
||||
VideoRotation video_rotation;
|
||||
base_event->header_.GetExtension<VideoOrientation>(&video_rotation);
|
||||
proto_batch->set_video_rotation(
|
||||
ConvertVideoRotationToCVOByte(video_rotation));
|
||||
}
|
||||
for (auto it : batch) {
|
||||
RTC_DCHECK(!it.second.empty());
|
||||
EncodeRtpPacket(it.second, event_stream->add_incoming_rtp_packets());
|
||||
}
|
||||
// TODO(terelius): Delta-compress rest of batch.
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderNewFormat::EncodeRtpPacketOutgoing(
|
||||
rtc::ArrayView<const RtcEventRtpPacketOutgoing*> batch,
|
||||
const std::map<uint32_t, std::vector<const RtcEventRtpPacketOutgoing*>>&
|
||||
batch,
|
||||
rtclog2::EventStream* event_stream) {
|
||||
if (batch.size() == 0)
|
||||
return;
|
||||
for (const RtcEventRtpPacketOutgoing* base_event : batch) {
|
||||
rtclog2::OutgoingRtpPackets* proto_batch =
|
||||
event_stream->add_outgoing_rtp_packets();
|
||||
proto_batch->set_timestamp_ms(base_event->timestamp_us_ / 1000);
|
||||
proto_batch->set_marker(base_event->header_.Marker());
|
||||
// TODO(terelius): Is payload type needed?
|
||||
proto_batch->set_payload_type(base_event->header_.PayloadType());
|
||||
proto_batch->set_sequence_number(base_event->header_.SequenceNumber());
|
||||
proto_batch->set_rtp_timestamp(base_event->header_.Timestamp());
|
||||
proto_batch->set_ssrc(base_event->header_.Ssrc());
|
||||
proto_batch->set_payload_size(base_event->payload_length_);
|
||||
proto_batch->set_header_size(base_event->header_length_);
|
||||
proto_batch->set_padding_size(base_event->padding_length_);
|
||||
|
||||
// Add header extensions.
|
||||
if (base_event->header_.HasExtension<TransmissionOffset>()) {
|
||||
int32_t offset;
|
||||
base_event->header_.GetExtension<TransmissionOffset>(&offset);
|
||||
proto_batch->set_transmission_time_offset(offset);
|
||||
}
|
||||
if (base_event->header_.HasExtension<AbsoluteSendTime>()) {
|
||||
uint32_t sendtime;
|
||||
base_event->header_.GetExtension<AbsoluteSendTime>(&sendtime);
|
||||
proto_batch->set_absolute_send_time(sendtime);
|
||||
}
|
||||
if (base_event->header_.HasExtension<TransportSequenceNumber>()) {
|
||||
uint16_t seqnum;
|
||||
base_event->header_.GetExtension<TransportSequenceNumber>(&seqnum);
|
||||
proto_batch->set_transport_sequence_number(seqnum);
|
||||
}
|
||||
if (base_event->header_.HasExtension<AudioLevel>()) {
|
||||
bool voice_activity;
|
||||
uint8_t audio_level;
|
||||
base_event->header_.GetExtension<AudioLevel>(&voice_activity,
|
||||
&audio_level);
|
||||
RTC_DCHECK(audio_level < 128);
|
||||
if (voice_activity) {
|
||||
audio_level += 128; // Most significant bit indicates voice activity.
|
||||
}
|
||||
proto_batch->set_audio_level(audio_level);
|
||||
}
|
||||
if (base_event->header_.HasExtension<VideoOrientation>()) {
|
||||
VideoRotation video_rotation;
|
||||
base_event->header_.GetExtension<VideoOrientation>(&video_rotation);
|
||||
proto_batch->set_video_rotation(
|
||||
ConvertVideoRotationToCVOByte(video_rotation));
|
||||
}
|
||||
for (auto it : batch) {
|
||||
RTC_DCHECK(!it.second.empty());
|
||||
EncodeRtpPacket(it.second, event_stream->add_outgoing_rtp_packets());
|
||||
}
|
||||
// TODO(terelius): Delta-compress rest of batch.
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderNewFormat::EncodeVideoRecvStreamConfig(
|
||||
|
||||
@ -12,8 +12,10 @@
|
||||
#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 "logging/rtc_event_log/encoder/rtc_event_log_encoder.h"
|
||||
@ -98,10 +100,12 @@ class RtcEventLogEncoderNewFormat final : public RtcEventLogEncoder {
|
||||
rtc::ArrayView<const RtcEventRtcpPacketOutgoing*> batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeRtpPacketIncoming(
|
||||
rtc::ArrayView<const RtcEventRtpPacketIncoming*> batch,
|
||||
const std::map<uint32_t, std::vector<const RtcEventRtpPacketIncoming*>>&
|
||||
batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeRtpPacketOutgoing(
|
||||
rtc::ArrayView<const RtcEventRtpPacketOutgoing*> batch,
|
||||
const std::map<uint32_t, std::vector<const RtcEventRtpPacketOutgoing*>>&
|
||||
batch,
|
||||
rtclog2::EventStream* event_stream);
|
||||
void EncodeVideoRecvStreamConfig(
|
||||
rtc::ArrayView<const RtcEventVideoReceiveStreamConfig*> batch,
|
||||
|
||||
@ -41,13 +41,17 @@
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RtcEventLogEncoderTest
|
||||
: public testing::TestWithParam<std::tuple<int, bool>> {
|
||||
: public testing::TestWithParam<std::tuple<int, bool, size_t, bool>> {
|
||||
protected:
|
||||
RtcEventLogEncoderTest()
|
||||
: seed_(std::get<0>(GetParam())), prng_(seed_), gen_(seed_ * 880001UL) {
|
||||
if (std::get<1>(GetParam()))
|
||||
: seed_(std::get<0>(GetParam())),
|
||||
prng_(seed_),
|
||||
gen_(seed_ * 880001UL),
|
||||
new_encoding_(std::get<1>(GetParam())),
|
||||
event_count_(std::get<2>(GetParam())),
|
||||
force_repeated_fields_(std::get<3>(GetParam())) {
|
||||
if (new_encoding_)
|
||||
encoder_ = absl::make_unique<RtcEventLogEncoderNewFormat>();
|
||||
else
|
||||
encoder_ = absl::make_unique<RtcEventLogEncoderLegacy>();
|
||||
@ -58,140 +62,345 @@ class RtcEventLogEncoderTest
|
||||
// correct behavior both when all of the values are there, as well as when
|
||||
// only some.
|
||||
void TestRtcEventAudioNetworkAdaptation(
|
||||
std::unique_ptr<AudioEncoderRuntimeConfig> runtime_config);
|
||||
const std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>>&);
|
||||
|
||||
template <typename EventType>
|
||||
std::unique_ptr<EventType> NewRtpPacket(
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map);
|
||||
|
||||
template <typename ParsedType>
|
||||
const std::vector<ParsedType>& GetRtpPacketsBySsrc(
|
||||
const ParsedRtcEventLogNew* parsed_log);
|
||||
|
||||
template <typename EventType, typename ParsedType>
|
||||
void TestRtpPackets();
|
||||
|
||||
std::deque<std::unique_ptr<RtcEvent>> history_;
|
||||
// TODO(eladalon): Once we have more than one possible encoder, parameterize
|
||||
// encoder selection.
|
||||
std::unique_ptr<RtcEventLogEncoder> encoder_;
|
||||
ParsedRtcEventLogNew parsed_log_;
|
||||
const uint64_t seed_;
|
||||
Random prng_;
|
||||
test::EventGenerator gen_;
|
||||
const bool new_encoding_;
|
||||
const size_t event_count_;
|
||||
const bool force_repeated_fields_;
|
||||
};
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAlrState) {
|
||||
std::unique_ptr<RtcEventAlrState> event = gen_.NewAlrState();
|
||||
history_.push_back(event->Copy());
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
const auto& alr_state_events = parsed_log_.alr_state_events();
|
||||
|
||||
ASSERT_EQ(alr_state_events.size(), 1u);
|
||||
test::VerifyLoggedAlrStateEvent(*event, alr_state_events[0]);
|
||||
}
|
||||
|
||||
void RtcEventLogEncoderTest::TestRtcEventAudioNetworkAdaptation(
|
||||
std::unique_ptr<AudioEncoderRuntimeConfig> runtime_config) {
|
||||
// This function is called repeatedly. Clear state between calls.
|
||||
history_.clear();
|
||||
auto original_runtime_config = *runtime_config;
|
||||
auto event = absl::make_unique<RtcEventAudioNetworkAdaptation>(
|
||||
std::move(runtime_config));
|
||||
history_.push_back(event->Copy());
|
||||
const std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>>&
|
||||
events) {
|
||||
ASSERT_TRUE(history_.empty()) << "Function should be called once per test.";
|
||||
|
||||
for (auto& event : events) {
|
||||
history_.push_back(event->Copy());
|
||||
}
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
const auto& ana_configs = parsed_log_.audio_network_adaptation_events();
|
||||
|
||||
ASSERT_EQ(ana_configs.size(), 1u);
|
||||
test::VerifyLoggedAudioNetworkAdaptationEvent(*event, ana_configs[0]);
|
||||
ASSERT_EQ(ana_configs.size(), events.size());
|
||||
for (size_t i = 0; i < events.size(); ++i) {
|
||||
test::VerifyLoggedAudioNetworkAdaptationEvent(*events[i], ana_configs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<RtcEventRtpPacketIncoming> RtcEventLogEncoderTest::NewRtpPacket(
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map) {
|
||||
return gen_.NewRtpPacketIncoming(ssrc, extension_map, false);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<RtcEventRtpPacketOutgoing> RtcEventLogEncoderTest::NewRtpPacket(
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map) {
|
||||
return gen_.NewRtpPacketOutgoing(ssrc, extension_map, false);
|
||||
}
|
||||
|
||||
template <>
|
||||
const std::vector<ParsedRtcEventLogNew::LoggedRtpStreamIncoming>&
|
||||
RtcEventLogEncoderTest::GetRtpPacketsBySsrc(
|
||||
const ParsedRtcEventLogNew* parsed_log) {
|
||||
return parsed_log->incoming_rtp_packets_by_ssrc();
|
||||
}
|
||||
|
||||
template <>
|
||||
const std::vector<ParsedRtcEventLogNew::LoggedRtpStreamOutgoing>&
|
||||
RtcEventLogEncoderTest::GetRtpPacketsBySsrc(
|
||||
const ParsedRtcEventLogNew* parsed_log) {
|
||||
return parsed_log->outgoing_rtp_packets_by_ssrc();
|
||||
}
|
||||
|
||||
template <typename EventType, typename ParsedType>
|
||||
void CompareRtpPacketSequences(
|
||||
const std::vector<std::unique_ptr<EventType>>& original_events,
|
||||
const ParsedType& parsed_events);
|
||||
|
||||
template <>
|
||||
void CompareRtpPacketSequences(
|
||||
const std::vector<std::unique_ptr<RtcEventRtpPacketIncoming>>& original,
|
||||
const ParsedRtcEventLogNew::LoggedRtpStreamIncoming& parsed) {
|
||||
ASSERT_EQ(parsed.incoming_packets.size(), original.size());
|
||||
for (size_t i = 0; i < original.size(); ++i) {
|
||||
test::VerifyLoggedRtpPacketIncoming(*original[i],
|
||||
parsed.incoming_packets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void CompareRtpPacketSequences(
|
||||
const std::vector<std::unique_ptr<RtcEventRtpPacketOutgoing>>& original,
|
||||
const ParsedRtcEventLogNew::LoggedRtpStreamOutgoing& parsed) {
|
||||
ASSERT_EQ(parsed.outgoing_packets.size(), original.size());
|
||||
for (size_t i = 0; i < original.size(); ++i) {
|
||||
test::VerifyLoggedRtpPacketOutgoing(*original[i],
|
||||
parsed.outgoing_packets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename EventType, typename ParsedType>
|
||||
void RtcEventLogEncoderTest::TestRtpPackets() {
|
||||
// SSRCs will be randomly assigned out of this small pool, significant only
|
||||
// in that it also covers such edge cases as SSRC = 0 and SSRC = 0xffffffff.
|
||||
// The pool is intentionally small, so as to produce collisions.
|
||||
const std::vector<uint32_t> kSsrcPool = {0x00000000, 0x12345678, 0xabcdef01,
|
||||
0xffffffff, 0x20171024, 0x19840730,
|
||||
0x19831230};
|
||||
|
||||
// TODO(terelius): Test extensions for legacy encoding, too.
|
||||
RtpHeaderExtensionMap extension_map;
|
||||
if (new_encoding_) {
|
||||
extension_map = gen_.NewRtpHeaderExtensionMap(true);
|
||||
}
|
||||
|
||||
// Simulate |event_count_| RTP packets, with SSRCs assigned randomly
|
||||
// out of the small pool above.
|
||||
std::map<uint32_t, std::vector<std::unique_ptr<EventType>>> events_by_ssrc;
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
const uint32_t ssrc = kSsrcPool[prng_.Rand(kSsrcPool.size() - 1)];
|
||||
std::unique_ptr<EventType> event =
|
||||
(events_by_ssrc[ssrc].empty() || !force_repeated_fields_)
|
||||
? NewRtpPacket<EventType>(ssrc, extension_map)
|
||||
: events_by_ssrc[ssrc][0]->Copy();
|
||||
history_.push_back(event->Copy());
|
||||
events_by_ssrc[ssrc].emplace_back(std::move(event));
|
||||
}
|
||||
|
||||
// Encode and parse.
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
|
||||
// Expect as many distinct SSRCs to be parsed, as were simulated.
|
||||
const std::vector<ParsedType>& parsed_rtp_packets =
|
||||
GetRtpPacketsBySsrc<ParsedType>(&parsed_log_);
|
||||
ASSERT_EQ(parsed_rtp_packets.size(), events_by_ssrc.size());
|
||||
|
||||
// For each SSRC, make sure the RTP packets associated with it to have been
|
||||
// correctly encoded and parsed.
|
||||
for (auto it = events_by_ssrc.begin(); it != events_by_ssrc.end(); ++it) {
|
||||
const uint32_t ssrc = it->first;
|
||||
auto parsed = std::find_if(
|
||||
parsed_rtp_packets.begin(), parsed_rtp_packets.end(),
|
||||
[ssrc](const ParsedType& packet) { return packet.ssrc == ssrc; });
|
||||
ASSERT_NE(parsed, parsed_rtp_packets.end());
|
||||
CompareRtpPacketSequences(it->second, *parsed);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAlrState) {
|
||||
std::vector<std::unique_ptr<RtcEventAlrState>> events(event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
events[i] = (i == 0 || !force_repeated_fields_) ? gen_.NewAlrState()
|
||||
: events[0]->Copy();
|
||||
history_.push_back(events[i]->Copy());
|
||||
}
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
const auto& alr_state_events = parsed_log_.alr_state_events();
|
||||
|
||||
ASSERT_EQ(alr_state_events.size(), event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
test::VerifyLoggedAlrStateEvent(*events[i], alr_state_events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationBitrate) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
const int bitrate_bps = rtc::checked_cast<int>(
|
||||
prng_.Rand(0, std::numeric_limits<int32_t>::max()));
|
||||
runtime_config->bitrate_bps = bitrate_bps;
|
||||
TestRtcEventAudioNetworkAdaptation(std::move(runtime_config));
|
||||
std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
|
||||
event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
if (i == 0 || !force_repeated_fields_) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
const int bitrate_bps = rtc::checked_cast<int>(
|
||||
prng_.Rand(0, std::numeric_limits<int32_t>::max()));
|
||||
runtime_config->bitrate_bps = bitrate_bps;
|
||||
events[i] = absl::make_unique<RtcEventAudioNetworkAdaptation>(
|
||||
std::move(runtime_config));
|
||||
} else {
|
||||
events[i] = events[0]->Copy();
|
||||
}
|
||||
}
|
||||
TestRtcEventAudioNetworkAdaptation(events);
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationFrameLength) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
const int frame_length_ms = prng_.Rand(1, 1000);
|
||||
runtime_config->frame_length_ms = frame_length_ms;
|
||||
TestRtcEventAudioNetworkAdaptation(std::move(runtime_config));
|
||||
std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
|
||||
event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
if (i == 0 || !force_repeated_fields_) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
const int frame_length_ms = prng_.Rand(1, 1000);
|
||||
runtime_config->frame_length_ms = frame_length_ms;
|
||||
events[i] = absl::make_unique<RtcEventAudioNetworkAdaptation>(
|
||||
std::move(runtime_config));
|
||||
} else {
|
||||
events[i] = events[0]->Copy();
|
||||
}
|
||||
}
|
||||
TestRtcEventAudioNetworkAdaptation(events);
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationPacketLoss) {
|
||||
// To simplify the test, we just check powers of two.
|
||||
const float plr = std::pow(0.5f, prng_.Rand(1, 8));
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->uplink_packet_loss_fraction = plr;
|
||||
TestRtcEventAudioNetworkAdaptation(std::move(runtime_config));
|
||||
std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
|
||||
event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
if (i == 0 || !force_repeated_fields_) {
|
||||
// To simplify the test, we just check powers of two.
|
||||
const float plr = std::pow(0.5f, prng_.Rand(1, 8));
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->uplink_packet_loss_fraction = plr;
|
||||
events[i] = absl::make_unique<RtcEventAudioNetworkAdaptation>(
|
||||
std::move(runtime_config));
|
||||
} else {
|
||||
events[i] = events[0]->Copy();
|
||||
}
|
||||
}
|
||||
TestRtcEventAudioNetworkAdaptation(events);
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationFec) {
|
||||
// The test might be trivially passing for one of the two boolean values, so
|
||||
// for safety's sake, we test both.
|
||||
for (bool fec_enabled : {false, true}) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->enable_fec = fec_enabled;
|
||||
TestRtcEventAudioNetworkAdaptation(std::move(runtime_config));
|
||||
std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
|
||||
event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
if (i == 0 || !force_repeated_fields_) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->enable_fec = prng_.Rand<bool>();
|
||||
events[i] = absl::make_unique<RtcEventAudioNetworkAdaptation>(
|
||||
std::move(runtime_config));
|
||||
} else {
|
||||
events[i] = events[0]->Copy();
|
||||
}
|
||||
}
|
||||
TestRtcEventAudioNetworkAdaptation(events);
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationDtx) {
|
||||
// The test might be trivially passing for one of the two boolean values, so
|
||||
// for safety's sake, we test both.
|
||||
for (bool dtx_enabled : {false, true}) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->enable_dtx = dtx_enabled;
|
||||
TestRtcEventAudioNetworkAdaptation(std::move(runtime_config));
|
||||
std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
|
||||
event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
if (i == 0 || !force_repeated_fields_) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->enable_dtx = prng_.Rand<bool>();
|
||||
events[i] = absl::make_unique<RtcEventAudioNetworkAdaptation>(
|
||||
std::move(runtime_config));
|
||||
} else {
|
||||
events[i] = events[0]->Copy();
|
||||
}
|
||||
}
|
||||
TestRtcEventAudioNetworkAdaptation(events);
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationChannels) {
|
||||
// The test might be trivially passing for one of the two possible values, so
|
||||
// for safety's sake, we test both.
|
||||
for (size_t channels : {1, 2}) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->num_channels = channels;
|
||||
TestRtcEventAudioNetworkAdaptation(std::move(runtime_config));
|
||||
std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
|
||||
event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
if (i == 0 || !force_repeated_fields_) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->num_channels = prng_.Rand(1, 2);
|
||||
events[i] = absl::make_unique<RtcEventAudioNetworkAdaptation>(
|
||||
std::move(runtime_config));
|
||||
} else {
|
||||
events[i] = events[0]->Copy();
|
||||
}
|
||||
}
|
||||
TestRtcEventAudioNetworkAdaptation(events);
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationAll) {
|
||||
const int bitrate_bps = rtc::checked_cast<int>(
|
||||
prng_.Rand(0, std::numeric_limits<int32_t>::max()));
|
||||
const int frame_length_ms = prng_.Rand(1, 1000);
|
||||
const float plr = std::pow(0.5f, prng_.Rand(1, 8));
|
||||
for (bool fec_enabled : {false, true}) {
|
||||
for (bool dtx_enabled : {false, true}) {
|
||||
for (size_t channels : {1, 2}) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->bitrate_bps = bitrate_bps;
|
||||
runtime_config->frame_length_ms = frame_length_ms;
|
||||
runtime_config->uplink_packet_loss_fraction = plr;
|
||||
runtime_config->enable_fec = fec_enabled;
|
||||
runtime_config->enable_dtx = dtx_enabled;
|
||||
runtime_config->num_channels = channels;
|
||||
|
||||
TestRtcEventAudioNetworkAdaptation(std::move(runtime_config));
|
||||
}
|
||||
std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
|
||||
event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
if (i == 0 || !force_repeated_fields_) {
|
||||
auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>();
|
||||
runtime_config->bitrate_bps = rtc::checked_cast<int>(
|
||||
prng_.Rand(0, std::numeric_limits<int32_t>::max()));
|
||||
runtime_config->frame_length_ms = prng_.Rand(1, 1000);
|
||||
runtime_config->uplink_packet_loss_fraction =
|
||||
std::pow(0.5f, prng_.Rand(1, 8));
|
||||
runtime_config->enable_fec = prng_.Rand<bool>();
|
||||
runtime_config->enable_dtx = prng_.Rand<bool>();
|
||||
runtime_config->num_channels = prng_.Rand(1, 2);
|
||||
events[i] = absl::make_unique<RtcEventAudioNetworkAdaptation>(
|
||||
std::move(runtime_config));
|
||||
} else {
|
||||
events[i] = events[0]->Copy();
|
||||
}
|
||||
}
|
||||
TestRtcEventAudioNetworkAdaptation(events);
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioPlayout) {
|
||||
uint32_t ssrc = prng_.Rand<uint32_t>();
|
||||
std::unique_ptr<RtcEventAudioPlayout> event = gen_.NewAudioPlayout(ssrc);
|
||||
history_.push_back(event->Copy());
|
||||
// SSRCs will be randomly assigned out of this small pool, significant only
|
||||
// in that it also covers such edge cases as SSRC = 0 and SSRC = 0xffffffff.
|
||||
// The pool is intentionally small, so as to produce collisions.
|
||||
const std::vector<uint32_t> kSsrcPool = {0x00000000, 0x12345678, 0xabcdef01,
|
||||
0xffffffff, 0x20171024, 0x19840730,
|
||||
0x19831230};
|
||||
|
||||
std::map<uint32_t, std::vector<std::unique_ptr<RtcEventAudioPlayout>>>
|
||||
original_events_by_ssrc;
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
const uint32_t ssrc = kSsrcPool[prng_.Rand(kSsrcPool.size() - 1)];
|
||||
std::unique_ptr<RtcEventAudioPlayout> event =
|
||||
(original_events_by_ssrc[ssrc].empty() || !force_repeated_fields_)
|
||||
? gen_.NewAudioPlayout(ssrc)
|
||||
: original_events_by_ssrc[ssrc][0]->Copy();
|
||||
history_.push_back(event->Copy());
|
||||
original_events_by_ssrc[ssrc].push_back(std::move(event));
|
||||
}
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
|
||||
const auto& playout_events = parsed_log_.audio_playout_events();
|
||||
ASSERT_EQ(playout_events.size(), 1u);
|
||||
const auto playout_stream = playout_events.find(ssrc);
|
||||
ASSERT_TRUE(playout_stream != playout_events.end());
|
||||
const auto& parsed_playout_events_by_ssrc =
|
||||
parsed_log_.audio_playout_events();
|
||||
|
||||
ASSERT_EQ(playout_stream->second.size(), 1u);
|
||||
LoggedAudioPlayoutEvent playout_event = playout_stream->second[0];
|
||||
test::VerifyLoggedAudioPlayoutEvent(*event, playout_event);
|
||||
// Same number of distinct SSRCs.
|
||||
ASSERT_EQ(parsed_playout_events_by_ssrc.size(),
|
||||
original_events_by_ssrc.size());
|
||||
|
||||
for (auto& original_event_it : original_events_by_ssrc) {
|
||||
const uint32_t ssrc = original_event_it.first;
|
||||
const auto& original_playout_events = original_event_it.second;
|
||||
|
||||
const auto& parsed_event_it = parsed_playout_events_by_ssrc.find(ssrc);
|
||||
ASSERT_TRUE(parsed_event_it != parsed_playout_events_by_ssrc.end());
|
||||
const auto& parsed_playout_events = parsed_event_it->second;
|
||||
|
||||
// Same number playout events for the SSRC under examination.
|
||||
ASSERT_EQ(original_playout_events.size(), parsed_playout_events.size());
|
||||
|
||||
for (size_t i = 0; i < original_playout_events.size(); ++i) {
|
||||
test::VerifyLoggedAudioPlayoutEvent(*original_playout_events[i],
|
||||
parsed_playout_events[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioReceiveStreamConfig) {
|
||||
uint32_t ssrc = prng_.Rand<uint32_t>();
|
||||
RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
|
||||
@ -207,6 +416,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioReceiveStreamConfig) {
|
||||
test::VerifyLoggedAudioRecvConfig(*event, audio_recv_configs[0]);
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventAudioSendStreamConfig) {
|
||||
uint32_t ssrc = prng_.Rand<uint32_t>();
|
||||
RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
|
||||
@ -223,31 +433,47 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioSendStreamConfig) {
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateDelayBased) {
|
||||
std::unique_ptr<RtcEventBweUpdateDelayBased> event =
|
||||
gen_.NewBweUpdateDelayBased();
|
||||
history_.push_back(event->Copy());
|
||||
std::vector<std::unique_ptr<RtcEventBweUpdateDelayBased>> events(
|
||||
event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
events[i] = (i == 0 || !force_repeated_fields_)
|
||||
? gen_.NewBweUpdateDelayBased()
|
||||
: events[0]->Copy();
|
||||
history_.push_back(events[i]->Copy());
|
||||
}
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
const auto& bwe_delay_updates = parsed_log_.bwe_delay_updates();
|
||||
|
||||
ASSERT_EQ(bwe_delay_updates.size(), 1u);
|
||||
test::VerifyLoggedBweDelayBasedUpdate(*event, bwe_delay_updates[0]);
|
||||
const auto& bwe_delay_updates = parsed_log_.bwe_delay_updates();
|
||||
ASSERT_EQ(bwe_delay_updates.size(), event_count_);
|
||||
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
test::VerifyLoggedBweDelayBasedUpdate(*events[i], bwe_delay_updates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateLossBased) {
|
||||
std::unique_ptr<RtcEventBweUpdateLossBased> event =
|
||||
gen_.NewBweUpdateLossBased();
|
||||
history_.push_back(event->Copy());
|
||||
std::vector<std::unique_ptr<RtcEventBweUpdateLossBased>> events(event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
events[i] = (i == 0 || !force_repeated_fields_)
|
||||
? gen_.NewBweUpdateLossBased()
|
||||
: events[0]->Copy();
|
||||
history_.push_back(events[i]->Copy());
|
||||
}
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
const auto& bwe_loss_updates = parsed_log_.bwe_loss_updates();
|
||||
|
||||
ASSERT_EQ(bwe_loss_updates.size(), 1u);
|
||||
test::VerifyLoggedBweLossBasedUpdate(*event, bwe_loss_updates[0]);
|
||||
const auto& bwe_loss_updates = parsed_log_.bwe_loss_updates();
|
||||
ASSERT_EQ(bwe_loss_updates.size(), event_count_);
|
||||
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
test::VerifyLoggedBweLossBasedUpdate(*events[i], bwe_loss_updates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePairConfig) {
|
||||
std::unique_ptr<RtcEventIceCandidatePairConfig> event =
|
||||
gen_.NewIceCandidatePairConfig();
|
||||
@ -263,6 +489,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePairConfig) {
|
||||
ice_candidate_pair_configs[0]);
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePair) {
|
||||
std::unique_ptr<RtcEventIceCandidatePair> event = gen_.NewIceCandidatePair();
|
||||
history_.push_back(event->Copy());
|
||||
@ -276,6 +503,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePair) {
|
||||
test::VerifyLoggedIceCandidatePairEvent(*event, ice_candidate_pair_events[0]);
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch, or prevent
|
||||
// it from happening.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStarted) {
|
||||
const int64_t timestamp_us = rtc::TimeMicros();
|
||||
|
||||
@ -286,6 +515,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStarted) {
|
||||
test::VerifyLoggedStartEvent(timestamp_us, start_log_events[0]);
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch, or prevent
|
||||
// it from happening.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStopped) {
|
||||
const int64_t timestamp_us = rtc::TimeMicros();
|
||||
|
||||
@ -296,6 +527,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStopped) {
|
||||
test::VerifyLoggedStopEvent(timestamp_us, stop_log_events[0]);
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventProbeClusterCreated) {
|
||||
std::unique_ptr<RtcEventProbeClusterCreated> event =
|
||||
gen_.NewProbeClusterCreated();
|
||||
@ -311,6 +543,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventProbeClusterCreated) {
|
||||
*event, bwe_probe_cluster_created_events[0]);
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultFailure) {
|
||||
std::unique_ptr<RtcEventProbeResultFailure> event =
|
||||
gen_.NewProbeResultFailure();
|
||||
@ -324,6 +557,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultFailure) {
|
||||
test::VerifyLoggedBweProbeFailureEvent(*event, bwe_probe_failure_events[0]);
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultSuccess) {
|
||||
std::unique_ptr<RtcEventProbeResultSuccess> event =
|
||||
gen_.NewProbeResultSuccess();
|
||||
@ -338,73 +572,62 @@ TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultSuccess) {
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketIncoming) {
|
||||
std::unique_ptr<RtcEventRtcpPacketIncoming> event =
|
||||
gen_.NewRtcpPacketIncoming();
|
||||
history_.push_back(event->Copy());
|
||||
if (!new_encoding_ && force_repeated_fields_) {
|
||||
// The old encoding does not work with duplicated packets. Since the legacy
|
||||
// encoding is being phased out, we will not fix this.
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<RtcEventRtcpPacketIncoming>> events(event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
events[i] = (i == 0 || !force_repeated_fields_)
|
||||
? gen_.NewRtcpPacketIncoming()
|
||||
: events[0]->Copy();
|
||||
history_.push_back(events[i]->Copy());
|
||||
}
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
|
||||
const auto& incoming_rtcp_packets = parsed_log_.incoming_rtcp_packets();
|
||||
ASSERT_EQ(incoming_rtcp_packets.size(), event_count_);
|
||||
|
||||
ASSERT_EQ(incoming_rtcp_packets.size(), 1u);
|
||||
|
||||
test::VerifyLoggedRtcpPacketIncoming(*event, incoming_rtcp_packets[0]);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
test::VerifyLoggedRtcpPacketIncoming(*events[i], incoming_rtcp_packets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketOutgoing) {
|
||||
std::unique_ptr<RtcEventRtcpPacketOutgoing> event =
|
||||
gen_.NewRtcpPacketOutgoing();
|
||||
history_.push_back(event->Copy());
|
||||
std::vector<std::unique_ptr<RtcEventRtcpPacketOutgoing>> events(event_count_);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
events[i] = (i == 0 || !force_repeated_fields_)
|
||||
? gen_.NewRtcpPacketOutgoing()
|
||||
: events[0]->Copy();
|
||||
history_.push_back(events[i]->Copy());
|
||||
}
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
|
||||
const auto& outgoing_rtcp_packets = parsed_log_.outgoing_rtcp_packets();
|
||||
ASSERT_EQ(outgoing_rtcp_packets.size(), event_count_);
|
||||
|
||||
ASSERT_EQ(outgoing_rtcp_packets.size(), 1u);
|
||||
|
||||
test::VerifyLoggedRtcpPacketOutgoing(*event, outgoing_rtcp_packets[0]);
|
||||
for (size_t i = 0; i < event_count_; ++i) {
|
||||
test::VerifyLoggedRtcpPacketOutgoing(*events[i], outgoing_rtcp_packets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventRtpPacketIncoming) {
|
||||
uint32_t ssrc = prng_.Rand<uint32_t>();
|
||||
RtpHeaderExtensionMap extension_map; // TODO(terelius): Test extensions too.
|
||||
std::unique_ptr<RtcEventRtpPacketIncoming> event =
|
||||
gen_.NewRtpPacketIncoming(ssrc, extension_map);
|
||||
history_.push_back(event->Copy());
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
const auto& incoming_rtp_packets_by_ssrc =
|
||||
parsed_log_.incoming_rtp_packets_by_ssrc();
|
||||
|
||||
ASSERT_EQ(incoming_rtp_packets_by_ssrc.size(), 1u);
|
||||
const auto& stream = incoming_rtp_packets_by_ssrc[0];
|
||||
EXPECT_EQ(stream.ssrc, ssrc);
|
||||
ASSERT_EQ(stream.incoming_packets.size(), 1u);
|
||||
|
||||
test::VerifyLoggedRtpPacketIncoming(*event, stream.incoming_packets[0]);
|
||||
TestRtpPackets<RtcEventRtpPacketIncoming,
|
||||
ParsedRtcEventLogNew::LoggedRtpStreamIncoming>();
|
||||
}
|
||||
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventRtpPacketOutgoing) {
|
||||
uint32_t ssrc = prng_.Rand<uint32_t>();
|
||||
RtpHeaderExtensionMap extension_map; // TODO(terelius): Test extensions too.
|
||||
std::unique_ptr<RtcEventRtpPacketOutgoing> event =
|
||||
gen_.NewRtpPacketOutgoing(ssrc, extension_map);
|
||||
history_.push_back(event->Copy());
|
||||
|
||||
std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
|
||||
ASSERT_TRUE(parsed_log_.ParseString(encoded));
|
||||
const auto& outgoing_rtp_packets_by_ssrc =
|
||||
parsed_log_.outgoing_rtp_packets_by_ssrc();
|
||||
|
||||
ASSERT_EQ(outgoing_rtp_packets_by_ssrc.size(), 1u);
|
||||
const auto& stream = outgoing_rtp_packets_by_ssrc[0];
|
||||
EXPECT_EQ(stream.ssrc, ssrc);
|
||||
ASSERT_EQ(stream.outgoing_packets.size(), 1u);
|
||||
|
||||
test::VerifyLoggedRtpPacketOutgoing(*event, stream.outgoing_packets[0]);
|
||||
TestRtpPackets<RtcEventRtpPacketOutgoing,
|
||||
ParsedRtcEventLogNew::LoggedRtpStreamOutgoing>();
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventVideoReceiveStreamConfig) {
|
||||
uint32_t ssrc = prng_.Rand<uint32_t>();
|
||||
RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
|
||||
@ -420,6 +643,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventVideoReceiveStreamConfig) {
|
||||
test::VerifyLoggedVideoRecvConfig(*event, video_recv_configs[0]);
|
||||
}
|
||||
|
||||
// TODO(eladalon/terelius): Test with multiple events in the batch.
|
||||
TEST_P(RtcEventLogEncoderTest, RtcEventVideoSendStreamConfig) {
|
||||
uint32_t ssrc = prng_.Rand<uint32_t>();
|
||||
RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
|
||||
@ -435,9 +659,12 @@ TEST_P(RtcEventLogEncoderTest, RtcEventVideoSendStreamConfig) {
|
||||
test::VerifyLoggedVideoSendConfig(*event, video_send_configs[0]);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(RandomSeeds,
|
||||
RtcEventLogEncoderTest,
|
||||
::testing::Combine(::testing::Values(1, 2, 3, 4, 5),
|
||||
::testing::Bool()));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
RandomSeeds,
|
||||
RtcEventLogEncoderTest,
|
||||
::testing::Combine(/* Random seed*: */ ::testing::Values(1, 2, 3, 4, 5),
|
||||
/* Encoding: */ ::testing::Bool(),
|
||||
/* Event count: */ ::testing::Values(1, 2, 10, 100),
|
||||
/* Repeated fields: */ ::testing::Bool()));
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -10,6 +10,8 @@ package webrtc.rtclog2;
|
||||
// single EventStream object containing the same events. Hence, it is not
|
||||
// necessary to wait for the entire log to be complete before beginning to
|
||||
// write it to a file.
|
||||
// Note: For all X_deltas fields, we rely on the default value being an
|
||||
// empty string.
|
||||
message EventStream {
|
||||
// Deprecated - Maintained for compatibility with the old event log.
|
||||
repeated Event stream = 1 [deprecated = true];
|
||||
@ -395,7 +397,12 @@ message AudioNetworkAdaptations {
|
||||
|
||||
// Packet loss fraction that the encoder's forward error correction (FEC) is
|
||||
// optimized for.
|
||||
optional float uplink_packet_loss_fraction = 4;
|
||||
// Instead of encoding a float, we encode a value between 0 and 16383, which
|
||||
// if divided by 16383, will give a value close to the original float.
|
||||
// The value 16383 (2^14 - 1) was chosen so that it would give good precision
|
||||
// on the one hand, and would be encodable with two bytes in varint form
|
||||
// on the other hand.
|
||||
optional uint32 uplink_packet_loss_fraction = 4;
|
||||
|
||||
// Whether forward error correction (FEC) is turned on or off.
|
||||
optional bool enable_fec = 5;
|
||||
|
||||
@ -24,6 +24,9 @@
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/rtp_headers.h"
|
||||
#include "api/rtpparameters.h"
|
||||
#include "logging/rtc_event_log/encoder/blob_encoding.h"
|
||||
#include "logging/rtc_event_log/encoder/delta_encoding.h"
|
||||
#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
|
||||
#include "logging/rtc_event_log/rtc_event_log.h"
|
||||
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
|
||||
#include "modules/congestion_controller/rtp/transport_feedback_adapter.h"
|
||||
@ -35,8 +38,12 @@
|
||||
#include "modules/rtp_rtcp/source/rtp_utility.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
#include "rtc_base/protobuf_utils.h"
|
||||
|
||||
using webrtc_event_logging::ToSigned;
|
||||
using webrtc_event_logging::ToUnsigned;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
@ -442,6 +449,276 @@ void SortPacketFeedbackVectorWithLoss(std::vector<PacketFeedback>* vec) {
|
||||
std::sort(vec->begin(), vec->end(), LossHandlingPacketFeedbackComparator());
|
||||
}
|
||||
|
||||
template <typename ProtoType, typename LoggedType>
|
||||
void StoreRtpPackets(
|
||||
const ProtoType& proto,
|
||||
std::map<uint32_t, std::vector<LoggedType>>* rtp_packets_map) {
|
||||
RTC_CHECK(proto.has_timestamp_ms());
|
||||
RTC_CHECK(proto.has_marker());
|
||||
RTC_CHECK(proto.has_payload_type());
|
||||
RTC_CHECK(proto.has_sequence_number());
|
||||
RTC_CHECK(proto.has_rtp_timestamp());
|
||||
RTC_CHECK(proto.has_ssrc());
|
||||
RTC_CHECK(proto.has_payload_size());
|
||||
RTC_CHECK(proto.has_header_size());
|
||||
RTC_CHECK(proto.has_padding_size());
|
||||
|
||||
// Base event
|
||||
{
|
||||
RTPHeader header;
|
||||
header.markerBit = rtc::checked_cast<bool>(proto.marker());
|
||||
header.payloadType = rtc::checked_cast<uint8_t>(proto.payload_type());
|
||||
header.sequenceNumber =
|
||||
rtc::checked_cast<uint16_t>(proto.sequence_number());
|
||||
header.timestamp = rtc::checked_cast<uint32_t>(proto.rtp_timestamp());
|
||||
header.ssrc = rtc::checked_cast<uint32_t>(proto.ssrc());
|
||||
header.numCSRCs = 0; // TODO(terelius): Implement CSRC.
|
||||
header.paddingLength = rtc::checked_cast<size_t>(proto.padding_size());
|
||||
header.headerLength = rtc::checked_cast<size_t>(proto.header_size());
|
||||
// TODO(terelius): Should we implement payload_type_frequency?
|
||||
if (proto.has_transport_sequence_number()) {
|
||||
header.extension.hasTransportSequenceNumber = true;
|
||||
header.extension.transportSequenceNumber =
|
||||
rtc::checked_cast<uint16_t>(proto.transport_sequence_number());
|
||||
}
|
||||
if (proto.has_transmission_time_offset()) {
|
||||
header.extension.hasTransmissionTimeOffset = true;
|
||||
header.extension.transmissionTimeOffset =
|
||||
rtc::checked_cast<int32_t>(proto.transmission_time_offset());
|
||||
}
|
||||
if (proto.has_absolute_send_time()) {
|
||||
header.extension.hasAbsoluteSendTime = true;
|
||||
header.extension.absoluteSendTime =
|
||||
rtc::checked_cast<uint32_t>(proto.absolute_send_time());
|
||||
}
|
||||
if (proto.has_video_rotation()) {
|
||||
header.extension.hasVideoRotation = true;
|
||||
header.extension.videoRotation = ConvertCVOByteToVideoRotation(
|
||||
rtc::checked_cast<uint8_t>(proto.video_rotation()));
|
||||
}
|
||||
if (proto.has_audio_level()) {
|
||||
header.extension.hasAudioLevel = true;
|
||||
const uint8_t audio_level =
|
||||
rtc::checked_cast<uint8_t>(proto.audio_level());
|
||||
header.extension.voiceActivity = (audio_level >> 7) != 0;
|
||||
header.extension.audioLevel = audio_level & 0x7Fu;
|
||||
}
|
||||
(*rtp_packets_map)[header.ssrc].emplace_back(
|
||||
proto.timestamp_ms() * 1000, header, proto.header_size(),
|
||||
proto.payload_size() + header.headerLength + header.paddingLength);
|
||||
}
|
||||
|
||||
const size_t number_of_deltas =
|
||||
proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
|
||||
if (number_of_deltas == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// timestamp_ms (event)
|
||||
std::vector<absl::optional<uint64_t>> timestamp_ms_values = DecodeDeltas(
|
||||
proto.timestamp_deltas_ms(), proto.timestamp_ms(), number_of_deltas);
|
||||
RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
|
||||
|
||||
// marker (RTP base)
|
||||
std::vector<absl::optional<uint64_t>> marker_values =
|
||||
DecodeDeltas(proto.marker_deltas(), proto.marker(), number_of_deltas);
|
||||
RTC_CHECK_EQ(marker_values.size(), number_of_deltas);
|
||||
|
||||
// payload_type (RTP base)
|
||||
std::vector<absl::optional<uint64_t>> payload_type_values = DecodeDeltas(
|
||||
proto.payload_type_deltas(), proto.payload_type(), number_of_deltas);
|
||||
RTC_CHECK_EQ(payload_type_values.size(), number_of_deltas);
|
||||
|
||||
// sequence_number (RTP base)
|
||||
std::vector<absl::optional<uint64_t>> sequence_number_values =
|
||||
DecodeDeltas(proto.sequence_number_deltas(), proto.sequence_number(),
|
||||
number_of_deltas);
|
||||
RTC_CHECK_EQ(sequence_number_values.size(), number_of_deltas);
|
||||
|
||||
// rtp_timestamp (RTP base)
|
||||
std::vector<absl::optional<uint64_t>> rtp_timestamp_values = DecodeDeltas(
|
||||
proto.rtp_timestamp_deltas(), proto.rtp_timestamp(), number_of_deltas);
|
||||
RTC_CHECK_EQ(rtp_timestamp_values.size(), number_of_deltas);
|
||||
|
||||
// ssrc (RTP base)
|
||||
std::vector<absl::optional<uint64_t>> ssrc_values =
|
||||
DecodeDeltas(proto.ssrc_deltas(), proto.ssrc(), number_of_deltas);
|
||||
RTC_CHECK_EQ(ssrc_values.size(), number_of_deltas);
|
||||
|
||||
// payload_size (RTP base)
|
||||
std::vector<absl::optional<uint64_t>> payload_size_values = DecodeDeltas(
|
||||
proto.payload_size_deltas(), proto.payload_size(), number_of_deltas);
|
||||
RTC_CHECK_EQ(payload_size_values.size(), number_of_deltas);
|
||||
|
||||
// header_size (RTP base)
|
||||
std::vector<absl::optional<uint64_t>> header_size_values = DecodeDeltas(
|
||||
proto.header_size_deltas(), proto.header_size(), number_of_deltas);
|
||||
RTC_CHECK_EQ(header_size_values.size(), number_of_deltas);
|
||||
|
||||
// padding_size (RTP base)
|
||||
std::vector<absl::optional<uint64_t>> padding_size_values = DecodeDeltas(
|
||||
proto.padding_size_deltas(), proto.padding_size(), number_of_deltas);
|
||||
RTC_CHECK_EQ(padding_size_values.size(), number_of_deltas);
|
||||
|
||||
// transport_sequence_number (RTP extension)
|
||||
std::vector<absl::optional<uint64_t>> transport_sequence_number_values;
|
||||
{
|
||||
const absl::optional<uint64_t> base_transport_sequence_number =
|
||||
proto.has_transport_sequence_number()
|
||||
? proto.transport_sequence_number()
|
||||
: absl::optional<uint64_t>();
|
||||
transport_sequence_number_values =
|
||||
DecodeDeltas(proto.transport_sequence_number_deltas(),
|
||||
base_transport_sequence_number, number_of_deltas);
|
||||
RTC_CHECK_EQ(transport_sequence_number_values.size(), number_of_deltas);
|
||||
}
|
||||
|
||||
// transmission_time_offset (RTP extension)
|
||||
std::vector<absl::optional<uint64_t>> transmission_time_offset_values;
|
||||
{
|
||||
const absl::optional<uint64_t> unsigned_base_transmission_time_offset =
|
||||
proto.has_transmission_time_offset()
|
||||
? ToUnsigned(proto.transmission_time_offset())
|
||||
: absl::optional<uint64_t>();
|
||||
transmission_time_offset_values =
|
||||
DecodeDeltas(proto.transmission_time_offset_deltas(),
|
||||
unsigned_base_transmission_time_offset, number_of_deltas);
|
||||
RTC_CHECK_EQ(transmission_time_offset_values.size(), number_of_deltas);
|
||||
}
|
||||
|
||||
// absolute_send_time (RTP extension)
|
||||
std::vector<absl::optional<uint64_t>> absolute_send_time_values;
|
||||
{
|
||||
const absl::optional<uint64_t> base_absolute_send_time =
|
||||
proto.has_absolute_send_time() ? proto.absolute_send_time()
|
||||
: absl::optional<uint64_t>();
|
||||
absolute_send_time_values =
|
||||
DecodeDeltas(proto.absolute_send_time_deltas(), base_absolute_send_time,
|
||||
number_of_deltas);
|
||||
RTC_CHECK_EQ(absolute_send_time_values.size(), number_of_deltas);
|
||||
}
|
||||
|
||||
// video_rotation (RTP extension)
|
||||
std::vector<absl::optional<uint64_t>> video_rotation_values;
|
||||
{
|
||||
const absl::optional<uint64_t> base_video_rotation =
|
||||
proto.has_video_rotation() ? proto.video_rotation()
|
||||
: absl::optional<uint64_t>();
|
||||
video_rotation_values = DecodeDeltas(proto.video_rotation_deltas(),
|
||||
base_video_rotation, number_of_deltas);
|
||||
RTC_CHECK_EQ(video_rotation_values.size(), number_of_deltas);
|
||||
}
|
||||
|
||||
// audio_level (RTP extension)
|
||||
std::vector<absl::optional<uint64_t>> audio_level_values;
|
||||
{
|
||||
const absl::optional<uint64_t> base_audio_level =
|
||||
proto.has_audio_level() ? proto.audio_level()
|
||||
: absl::optional<uint64_t>();
|
||||
audio_level_values = DecodeDeltas(proto.audio_level_deltas(),
|
||||
base_audio_level, number_of_deltas);
|
||||
RTC_CHECK_EQ(audio_level_values.size(), number_of_deltas);
|
||||
}
|
||||
|
||||
// Delta decoding
|
||||
for (size_t i = 0; i < number_of_deltas; ++i) {
|
||||
RTC_CHECK(timestamp_ms_values[i].has_value());
|
||||
RTC_CHECK(marker_values[i].has_value());
|
||||
RTC_CHECK(payload_type_values[i].has_value());
|
||||
RTC_CHECK(sequence_number_values[i].has_value());
|
||||
RTC_CHECK(rtp_timestamp_values[i].has_value());
|
||||
RTC_CHECK(ssrc_values[i].has_value());
|
||||
RTC_CHECK(payload_size_values[i].has_value());
|
||||
RTC_CHECK(header_size_values[i].has_value());
|
||||
RTC_CHECK(padding_size_values[i].has_value());
|
||||
|
||||
RTPHeader header;
|
||||
header.markerBit = rtc::checked_cast<bool>(*marker_values[i]);
|
||||
header.payloadType = rtc::checked_cast<uint8_t>(*payload_type_values[i]);
|
||||
header.sequenceNumber =
|
||||
rtc::checked_cast<uint16_t>(*sequence_number_values[i]);
|
||||
header.timestamp = rtc::checked_cast<uint32_t>(*rtp_timestamp_values[i]);
|
||||
header.ssrc = rtc::checked_cast<uint32_t>(*ssrc_values[i]);
|
||||
header.numCSRCs = 0; // TODO(terelius): Implement CSRC.
|
||||
header.paddingLength = rtc::checked_cast<size_t>(*padding_size_values[i]);
|
||||
header.headerLength = rtc::checked_cast<size_t>(*header_size_values[i]);
|
||||
// TODO(terelius): Should we implement payload_type_frequency?
|
||||
if (transport_sequence_number_values.size() > i &&
|
||||
transport_sequence_number_values[i].has_value()) {
|
||||
header.extension.hasTransportSequenceNumber = true;
|
||||
header.extension.transportSequenceNumber = rtc::checked_cast<uint16_t>(
|
||||
transport_sequence_number_values[i].value());
|
||||
}
|
||||
if (transmission_time_offset_values.size() > i &&
|
||||
transmission_time_offset_values[i].has_value()) {
|
||||
header.extension.hasTransmissionTimeOffset = true;
|
||||
int32_t transmission_time_offset;
|
||||
RTC_CHECK(ToSigned(transmission_time_offset_values[i].value(),
|
||||
&transmission_time_offset));
|
||||
header.extension.transmissionTimeOffset = transmission_time_offset;
|
||||
}
|
||||
if (absolute_send_time_values.size() > i &&
|
||||
absolute_send_time_values[i].has_value()) {
|
||||
header.extension.hasAbsoluteSendTime = true;
|
||||
header.extension.absoluteSendTime =
|
||||
rtc::checked_cast<uint32_t>(absolute_send_time_values[i].value());
|
||||
}
|
||||
if (video_rotation_values.size() > i &&
|
||||
video_rotation_values[i].has_value()) {
|
||||
header.extension.hasVideoRotation = true;
|
||||
header.extension.videoRotation = ConvertCVOByteToVideoRotation(
|
||||
rtc::checked_cast<uint8_t>(video_rotation_values[i].value()));
|
||||
}
|
||||
if (audio_level_values.size() > i && audio_level_values[i].has_value()) {
|
||||
header.extension.hasAudioLevel = true;
|
||||
const uint8_t audio_level =
|
||||
rtc::checked_cast<uint8_t>(audio_level_values[i].value());
|
||||
header.extension.voiceActivity = (audio_level >> 7) != 0;
|
||||
header.extension.audioLevel = audio_level & 0x7Fu;
|
||||
}
|
||||
(*rtp_packets_map)[header.ssrc].emplace_back(
|
||||
timestamp_ms_values[i].value() * 1000, header, header.headerLength,
|
||||
payload_size_values[i].value() + header.headerLength +
|
||||
header.paddingLength);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ProtoType, typename LoggedType>
|
||||
void StoreRtcpPackets(const ProtoType& proto,
|
||||
std::vector<LoggedType>* rtcp_packets) {
|
||||
RTC_CHECK(proto.has_timestamp_ms());
|
||||
RTC_CHECK(proto.has_raw_packet());
|
||||
|
||||
// Base event
|
||||
rtcp_packets->emplace_back(proto.timestamp_ms() * 1000, proto.raw_packet());
|
||||
|
||||
const size_t number_of_deltas =
|
||||
proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
|
||||
if (number_of_deltas == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// timestamp_ms
|
||||
std::vector<absl::optional<uint64_t>> timestamp_ms_values = DecodeDeltas(
|
||||
proto.timestamp_deltas_ms(), proto.timestamp_ms(), number_of_deltas);
|
||||
RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
|
||||
|
||||
// raw_packet
|
||||
RTC_CHECK(proto.has_raw_packet_deltas());
|
||||
std::vector<absl::string_view> raw_packet_values =
|
||||
DecodeBlobs(proto.raw_packet_deltas(), number_of_deltas);
|
||||
RTC_CHECK_EQ(raw_packet_values.size(), number_of_deltas);
|
||||
|
||||
// Delta decoding
|
||||
for (size_t i = 0; i < number_of_deltas; ++i) {
|
||||
RTC_CHECK(timestamp_ms_values[i].has_value());
|
||||
rtcp_packets->emplace_back(
|
||||
1000 * timestamp_ms_values[i].value(),
|
||||
reinterpret_cast<const uint8_t*>(raw_packet_values[i].data()),
|
||||
raw_packet_values[i].size());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LoggedRtcpPacket::LoggedRtcpPacket(uint64_t timestamp_us,
|
||||
@ -1675,109 +1952,71 @@ const std::vector<MatchedSendArrivalTimes> GetNetworkTrace(
|
||||
return rtp_rtcp_matched;
|
||||
}
|
||||
|
||||
// Helper functions for new format starts here
|
||||
// Helper functions for new format start here
|
||||
void ParsedRtcEventLogNew::StoreParsedNewFormatEvent(
|
||||
const rtclog2::EventStream& stream) {
|
||||
RTC_DCHECK_EQ(stream.stream_size(), 0);
|
||||
|
||||
RTC_DCHECK_LE(stream.incoming_rtp_packets_size(), 1);
|
||||
RTC_DCHECK_EQ(
|
||||
stream.incoming_rtp_packets_size() + stream.outgoing_rtp_packets_size() +
|
||||
stream.incoming_rtcp_packets_size() +
|
||||
stream.outgoing_rtcp_packets_size() +
|
||||
stream.audio_playout_events_size() + stream.begin_log_events_size() +
|
||||
stream.end_log_events_size() + stream.loss_based_bwe_updates_size() +
|
||||
stream.delay_based_bwe_updates_size() +
|
||||
stream.audio_network_adaptations_size() +
|
||||
stream.probe_clusters_size() + stream.probe_success_size() +
|
||||
stream.probe_failure_size() + stream.alr_states_size() +
|
||||
stream.ice_candidate_configs_size() +
|
||||
stream.ice_candidate_events_size() +
|
||||
stream.audio_recv_stream_configs_size() +
|
||||
stream.audio_send_stream_configs_size() +
|
||||
stream.video_recv_stream_configs_size() +
|
||||
stream.video_send_stream_configs_size(),
|
||||
1u);
|
||||
|
||||
if (stream.incoming_rtp_packets_size() == 1) {
|
||||
StoreIncomingRtpPackets(stream.incoming_rtp_packets(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.outgoing_rtp_packets_size(), 1);
|
||||
if (stream.outgoing_rtp_packets_size() == 1) {
|
||||
StoreOutgoingRtpPacket(stream.outgoing_rtp_packets(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.incoming_rtcp_packets_size(), 1);
|
||||
if (stream.incoming_rtcp_packets_size() == 1) {
|
||||
} else if (stream.outgoing_rtp_packets_size() == 1) {
|
||||
StoreOutgoingRtpPackets(stream.outgoing_rtp_packets(0));
|
||||
} else if (stream.incoming_rtcp_packets_size() == 1) {
|
||||
StoreIncomingRtcpPackets(stream.incoming_rtcp_packets(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.outgoing_rtcp_packets_size(), 1);
|
||||
if (stream.outgoing_rtcp_packets_size() == 1) {
|
||||
} else if (stream.outgoing_rtcp_packets_size() == 1) {
|
||||
StoreOutgoingRtcpPackets(stream.outgoing_rtcp_packets(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.audio_playout_events_size(), 1);
|
||||
if (stream.audio_playout_events_size() == 1) {
|
||||
} else if (stream.audio_playout_events_size() == 1) {
|
||||
StoreAudioPlayoutEvent(stream.audio_playout_events(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.begin_log_events_size(), 1);
|
||||
if (stream.begin_log_events_size() == 1) {
|
||||
} else if (stream.begin_log_events_size() == 1) {
|
||||
StoreStartEvent(stream.begin_log_events(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.end_log_events_size(), 1);
|
||||
if (stream.end_log_events_size() == 1) {
|
||||
} else if (stream.end_log_events_size() == 1) {
|
||||
StoreStopEvent(stream.end_log_events(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.loss_based_bwe_updates_size(), 1);
|
||||
if (stream.loss_based_bwe_updates_size() == 1) {
|
||||
} else if (stream.loss_based_bwe_updates_size() == 1) {
|
||||
StoreBweLossBasedUpdate(stream.loss_based_bwe_updates(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.delay_based_bwe_updates_size(), 1);
|
||||
if (stream.delay_based_bwe_updates_size() == 1) {
|
||||
} else if (stream.delay_based_bwe_updates_size() == 1) {
|
||||
StoreBweDelayBasedUpdate(stream.delay_based_bwe_updates(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.audio_network_adaptations_size(), 1);
|
||||
if (stream.audio_network_adaptations_size() == 1) {
|
||||
} else if (stream.audio_network_adaptations_size() == 1) {
|
||||
StoreAudioNetworkAdaptationEvent(stream.audio_network_adaptations(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.probe_clusters_size(), 1);
|
||||
if (stream.probe_clusters_size() == 1) {
|
||||
} else if (stream.probe_clusters_size() == 1) {
|
||||
StoreBweProbeClusterCreated(stream.probe_clusters(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.probe_success_size(), 1);
|
||||
if (stream.probe_success_size() == 1) {
|
||||
} else if (stream.probe_success_size() == 1) {
|
||||
StoreBweProbeSuccessEvent(stream.probe_success(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.probe_failure_size(), 1);
|
||||
if (stream.probe_failure_size() == 1) {
|
||||
} else if (stream.probe_failure_size() == 1) {
|
||||
StoreBweProbeFailureEvent(stream.probe_failure(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.alr_states_size(), 1);
|
||||
if (stream.alr_states_size() == 1) {
|
||||
} else if (stream.alr_states_size() == 1) {
|
||||
StoreAlrStateEvent(stream.alr_states(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.ice_candidate_configs_size(), 1);
|
||||
if (stream.ice_candidate_configs_size() == 1) {
|
||||
} else if (stream.ice_candidate_configs_size() == 1) {
|
||||
StoreIceCandidatePairConfig(stream.ice_candidate_configs(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.ice_candidate_events_size(), 1);
|
||||
if (stream.ice_candidate_events_size() == 1) {
|
||||
} else if (stream.ice_candidate_events_size() == 1) {
|
||||
StoreIceCandidateEvent(stream.ice_candidate_events(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.audio_recv_stream_configs_size(), 1);
|
||||
if (stream.audio_recv_stream_configs_size() == 1) {
|
||||
} else if (stream.audio_recv_stream_configs_size() == 1) {
|
||||
StoreAudioRecvConfig(stream.audio_recv_stream_configs(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.audio_send_stream_configs_size(), 1);
|
||||
if (stream.audio_send_stream_configs_size() == 1) {
|
||||
} else if (stream.audio_send_stream_configs_size() == 1) {
|
||||
StoreAudioSendConfig(stream.audio_send_stream_configs(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.video_recv_stream_configs_size(), 1);
|
||||
if (stream.video_recv_stream_configs_size() == 1) {
|
||||
} else if (stream.video_recv_stream_configs_size() == 1) {
|
||||
StoreVideoRecvConfig(stream.video_recv_stream_configs(0));
|
||||
}
|
||||
|
||||
RTC_DCHECK_LE(stream.video_send_stream_configs_size(), 1);
|
||||
if (stream.video_send_stream_configs_size() == 1) {
|
||||
} else if (stream.video_send_stream_configs_size() == 1) {
|
||||
StoreVideoSendConfig(stream.video_send_stream_configs(0));
|
||||
} else {
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1796,157 +2035,59 @@ void ParsedRtcEventLogNew::StoreAudioPlayoutEvent(
|
||||
const rtclog2::AudioPlayoutEvents& proto) {
|
||||
RTC_CHECK(proto.has_timestamp_ms());
|
||||
RTC_CHECK(proto.has_local_ssrc());
|
||||
LoggedAudioPlayoutEvent audio_playout_event;
|
||||
audio_playout_event.timestamp_us = proto.timestamp_ms() * 1000;
|
||||
audio_playout_event.ssrc = proto.local_ssrc();
|
||||
|
||||
audio_playout_events_[audio_playout_event.ssrc].push_back(
|
||||
audio_playout_event);
|
||||
// TODO(terelius): Parse deltas.
|
||||
// Base event
|
||||
auto map_it = audio_playout_events_[proto.local_ssrc()];
|
||||
audio_playout_events_[proto.local_ssrc()].emplace_back(
|
||||
1000 * proto.timestamp_ms(), proto.local_ssrc());
|
||||
|
||||
const size_t number_of_deltas =
|
||||
proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
|
||||
if (number_of_deltas == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// timestamp_ms
|
||||
std::vector<absl::optional<uint64_t>> timestamp_ms_values = DecodeDeltas(
|
||||
proto.timestamp_deltas_ms(), proto.timestamp_ms(), number_of_deltas);
|
||||
RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
|
||||
|
||||
// local_ssrc
|
||||
std::vector<absl::optional<uint64_t>> local_ssrc_values = DecodeDeltas(
|
||||
proto.local_ssrc_deltas(), proto.local_ssrc(), number_of_deltas);
|
||||
RTC_CHECK_EQ(local_ssrc_values.size(), number_of_deltas);
|
||||
|
||||
// Delta decoding
|
||||
for (size_t i = 0; i < number_of_deltas; ++i) {
|
||||
RTC_CHECK(timestamp_ms_values[i].has_value());
|
||||
RTC_CHECK(local_ssrc_values[i].has_value());
|
||||
RTC_CHECK_LE(local_ssrc_values[i].value(),
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
const uint32_t local_ssrc =
|
||||
static_cast<uint32_t>(local_ssrc_values[i].value());
|
||||
audio_playout_events_[local_ssrc].emplace_back(
|
||||
1000 * timestamp_ms_values[i].value(), local_ssrc);
|
||||
}
|
||||
}
|
||||
|
||||
void ParsedRtcEventLogNew::StoreIncomingRtpPackets(
|
||||
const rtclog2::IncomingRtpPackets& proto) {
|
||||
RTC_CHECK(proto.has_timestamp_ms());
|
||||
int64_t timestamp_ms = proto.timestamp_ms();
|
||||
|
||||
RTC_CHECK(proto.has_header_size());
|
||||
size_t header_length = proto.header_size();
|
||||
|
||||
RTC_CHECK(proto.has_padding_size());
|
||||
size_t padding_length = proto.padding_size();
|
||||
|
||||
RTC_CHECK(proto.has_payload_size());
|
||||
size_t total_length = proto.payload_size() + header_length + padding_length;
|
||||
|
||||
RTPHeader header;
|
||||
RTC_CHECK(proto.has_marker());
|
||||
header.markerBit = proto.marker();
|
||||
RTC_CHECK(proto.has_payload_type());
|
||||
header.payloadType = proto.payload_type();
|
||||
RTC_CHECK(proto.has_sequence_number());
|
||||
header.sequenceNumber = proto.sequence_number();
|
||||
RTC_CHECK(proto.has_rtp_timestamp());
|
||||
header.timestamp = proto.rtp_timestamp();
|
||||
RTC_CHECK(proto.has_ssrc());
|
||||
header.ssrc = proto.ssrc();
|
||||
|
||||
header.numCSRCs = 0; // TODO(terelius): Implement CSRC.
|
||||
header.paddingLength = padding_length;
|
||||
header.headerLength = header_length;
|
||||
// TODO(terelius): Should we implement payload_type_frequency?
|
||||
|
||||
if (proto.has_transmission_time_offset()) {
|
||||
header.extension.hasTransmissionTimeOffset = true;
|
||||
header.extension.transmissionTimeOffset = proto.transmission_time_offset();
|
||||
}
|
||||
if (proto.has_absolute_send_time()) {
|
||||
header.extension.hasAbsoluteSendTime = true;
|
||||
header.extension.absoluteSendTime = proto.absolute_send_time();
|
||||
}
|
||||
if (proto.has_transport_sequence_number()) {
|
||||
header.extension.hasTransportSequenceNumber = true;
|
||||
header.extension.transportSequenceNumber =
|
||||
proto.transport_sequence_number();
|
||||
}
|
||||
if (proto.has_audio_level()) {
|
||||
header.extension.hasAudioLevel = true;
|
||||
header.extension.voiceActivity = (proto.audio_level() >> 7) != 0;
|
||||
header.extension.audioLevel = proto.audio_level() & 0x7Fu;
|
||||
}
|
||||
if (proto.has_video_rotation()) {
|
||||
header.extension.hasVideoRotation = true;
|
||||
header.extension.videoRotation =
|
||||
ConvertCVOByteToVideoRotation(proto.video_rotation());
|
||||
}
|
||||
|
||||
incoming_rtp_packets_map_[header.ssrc].push_back(LoggedRtpPacketIncoming(
|
||||
timestamp_ms * 1000, header, header_length, total_length));
|
||||
// TODO(terelius): Parse deltas.
|
||||
StoreRtpPackets(proto, &incoming_rtp_packets_map_);
|
||||
}
|
||||
|
||||
void ParsedRtcEventLogNew::StoreOutgoingRtpPacket(
|
||||
void ParsedRtcEventLogNew::StoreOutgoingRtpPackets(
|
||||
const rtclog2::OutgoingRtpPackets& proto) {
|
||||
RTC_CHECK(proto.has_timestamp_ms());
|
||||
int64_t timestamp_ms = proto.timestamp_ms();
|
||||
|
||||
RTC_CHECK(proto.has_header_size());
|
||||
size_t header_length = proto.header_size();
|
||||
|
||||
RTC_CHECK(proto.has_padding_size());
|
||||
size_t padding_length = proto.padding_size();
|
||||
|
||||
RTC_CHECK(proto.has_payload_size());
|
||||
size_t total_length = proto.payload_size() + header_length + padding_length;
|
||||
|
||||
RTPHeader header;
|
||||
RTC_CHECK(proto.has_marker());
|
||||
header.markerBit = proto.marker();
|
||||
RTC_CHECK(proto.has_payload_type());
|
||||
header.payloadType = proto.payload_type();
|
||||
RTC_CHECK(proto.has_sequence_number());
|
||||
header.sequenceNumber = proto.sequence_number();
|
||||
RTC_CHECK(proto.has_rtp_timestamp());
|
||||
header.timestamp = proto.rtp_timestamp();
|
||||
RTC_CHECK(proto.has_ssrc());
|
||||
header.ssrc = proto.ssrc();
|
||||
|
||||
header.numCSRCs = 0; // TODO(terelius): Implement CSRC.
|
||||
header.paddingLength = padding_length;
|
||||
header.headerLength = header_length;
|
||||
// TODO(terelius): Should we implement payload_type_frequency?
|
||||
|
||||
if (proto.has_transmission_time_offset()) {
|
||||
header.extension.hasTransmissionTimeOffset = true;
|
||||
header.extension.transmissionTimeOffset = proto.transmission_time_offset();
|
||||
}
|
||||
if (proto.has_absolute_send_time()) {
|
||||
header.extension.hasAbsoluteSendTime = true;
|
||||
header.extension.absoluteSendTime = proto.absolute_send_time();
|
||||
}
|
||||
if (proto.has_transport_sequence_number()) {
|
||||
header.extension.hasTransportSequenceNumber = true;
|
||||
header.extension.transportSequenceNumber =
|
||||
proto.transport_sequence_number();
|
||||
}
|
||||
if (proto.has_audio_level()) {
|
||||
header.extension.hasAudioLevel = true;
|
||||
header.extension.voiceActivity = (proto.audio_level() >> 7) != 0;
|
||||
header.extension.audioLevel = proto.audio_level() & 0x7Fu;
|
||||
}
|
||||
if (proto.has_video_rotation()) {
|
||||
header.extension.hasVideoRotation = true;
|
||||
header.extension.videoRotation =
|
||||
ConvertCVOByteToVideoRotation(proto.video_rotation());
|
||||
}
|
||||
|
||||
outgoing_rtp_packets_map_[header.ssrc].push_back(LoggedRtpPacketOutgoing(
|
||||
timestamp_ms * 1000, header, header_length, total_length));
|
||||
// TODO(terelius): Parse deltas.
|
||||
StoreRtpPackets(proto, &outgoing_rtp_packets_map_);
|
||||
}
|
||||
|
||||
void ParsedRtcEventLogNew::StoreIncomingRtcpPackets(
|
||||
const rtclog2::IncomingRtcpPackets& proto) {
|
||||
RTC_CHECK(proto.has_timestamp_ms());
|
||||
int64_t timestamp_ms = proto.timestamp_ms();
|
||||
|
||||
RTC_CHECK(proto.has_raw_packet());
|
||||
incoming_rtcp_packets_.push_back(
|
||||
LoggedRtcpPacketIncoming(timestamp_ms * 1000, proto.raw_packet()));
|
||||
|
||||
// TODO(terelius): Parse deltas.
|
||||
StoreRtcpPackets(proto, &incoming_rtcp_packets_);
|
||||
}
|
||||
|
||||
void ParsedRtcEventLogNew::StoreOutgoingRtcpPackets(
|
||||
const rtclog2::OutgoingRtcpPackets& proto) {
|
||||
RTC_CHECK(proto.has_timestamp_ms());
|
||||
int64_t timestamp_ms = proto.timestamp_ms();
|
||||
|
||||
RTC_CHECK(proto.has_raw_packet());
|
||||
outgoing_rtcp_packets_.push_back(
|
||||
LoggedRtcpPacketOutgoing(timestamp_ms * 1000, proto.raw_packet()));
|
||||
|
||||
// TODO(terelius): Parse deltas.
|
||||
StoreRtcpPackets(proto, &outgoing_rtcp_packets_);
|
||||
}
|
||||
|
||||
void ParsedRtcEventLogNew::StoreStartEvent(
|
||||
@ -1971,15 +2112,62 @@ void ParsedRtcEventLogNew::StoreBweLossBasedUpdate(
|
||||
RTC_CHECK(proto.has_fraction_loss());
|
||||
RTC_CHECK(proto.has_total_packets());
|
||||
|
||||
LoggedBweLossBasedUpdate loss_update;
|
||||
loss_update.timestamp_us = proto.timestamp_ms() * 1000;
|
||||
loss_update.bitrate_bps = proto.bitrate_bps();
|
||||
loss_update.fraction_lost = proto.fraction_loss();
|
||||
loss_update.expected_packets = proto.total_packets();
|
||||
// Base event
|
||||
bwe_loss_updates_.emplace_back(1000 * proto.timestamp_ms(),
|
||||
proto.bitrate_bps(), proto.fraction_loss(),
|
||||
proto.total_packets());
|
||||
|
||||
bwe_loss_updates_.push_back(loss_update);
|
||||
const size_t number_of_deltas =
|
||||
proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
|
||||
if (number_of_deltas == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(terelius): Parse deltas.
|
||||
// timestamp_ms
|
||||
std::vector<absl::optional<uint64_t>> timestamp_ms_values = DecodeDeltas(
|
||||
proto.timestamp_deltas_ms(), proto.timestamp_ms(), number_of_deltas);
|
||||
RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
|
||||
|
||||
// bitrate_bps
|
||||
std::vector<absl::optional<uint64_t>> bitrate_bps_values = DecodeDeltas(
|
||||
proto.bitrate_deltas_bps(), proto.bitrate_bps(), number_of_deltas);
|
||||
RTC_CHECK_EQ(bitrate_bps_values.size(), number_of_deltas);
|
||||
|
||||
// fraction_loss
|
||||
std::vector<absl::optional<uint64_t>> fraction_loss_values = DecodeDeltas(
|
||||
proto.fraction_loss_deltas(), proto.fraction_loss(), number_of_deltas);
|
||||
RTC_CHECK_EQ(fraction_loss_values.size(), number_of_deltas);
|
||||
|
||||
// total_packets
|
||||
std::vector<absl::optional<uint64_t>> total_packets_values = DecodeDeltas(
|
||||
proto.total_packets_deltas(), proto.total_packets(), number_of_deltas);
|
||||
RTC_CHECK_EQ(total_packets_values.size(), number_of_deltas);
|
||||
|
||||
// Delta decoding
|
||||
for (size_t i = 0; i < number_of_deltas; ++i) {
|
||||
RTC_CHECK(timestamp_ms_values[i].has_value());
|
||||
|
||||
RTC_CHECK(bitrate_bps_values[i].has_value());
|
||||
RTC_CHECK_LE(bitrate_bps_values[i].value(),
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
const uint32_t bitrate_bps =
|
||||
static_cast<uint32_t>(bitrate_bps_values[i].value());
|
||||
|
||||
RTC_CHECK(fraction_loss_values[i].has_value());
|
||||
RTC_CHECK_LE(fraction_loss_values[i].value(),
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
const uint32_t fraction_loss =
|
||||
static_cast<uint32_t>(fraction_loss_values[i].value());
|
||||
|
||||
RTC_CHECK(total_packets_values[i].has_value());
|
||||
RTC_CHECK_LE(total_packets_values[i].value(),
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
const uint32_t total_packets =
|
||||
static_cast<uint32_t>(total_packets_values[i].value());
|
||||
|
||||
bwe_loss_updates_.emplace_back(1000 * timestamp_ms_values[i].value(),
|
||||
bitrate_bps, fraction_loss, total_packets);
|
||||
}
|
||||
}
|
||||
|
||||
void ParsedRtcEventLogNew::StoreBweDelayBasedUpdate(
|
||||
@ -1988,14 +2176,53 @@ void ParsedRtcEventLogNew::StoreBweDelayBasedUpdate(
|
||||
RTC_CHECK(proto.has_bitrate_bps());
|
||||
RTC_CHECK(proto.has_detector_state());
|
||||
|
||||
LoggedBweDelayBasedUpdate delay_update;
|
||||
delay_update.timestamp_us = proto.timestamp_ms() * 1000;
|
||||
delay_update.bitrate_bps = proto.bitrate_bps();
|
||||
delay_update.detector_state = GetRuntimeDetectorState(proto.detector_state());
|
||||
// Base event
|
||||
const BandwidthUsage base_detector_state =
|
||||
GetRuntimeDetectorState(proto.detector_state());
|
||||
bwe_delay_updates_.emplace_back(1000 * proto.timestamp_ms(),
|
||||
proto.bitrate_bps(), base_detector_state);
|
||||
|
||||
bwe_delay_updates_.push_back(delay_update);
|
||||
const size_t number_of_deltas =
|
||||
proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
|
||||
if (number_of_deltas == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(terelius): Parse deltas.
|
||||
// timestamp_ms
|
||||
std::vector<absl::optional<uint64_t>> timestamp_ms_values = DecodeDeltas(
|
||||
proto.timestamp_deltas_ms(), proto.timestamp_ms(), number_of_deltas);
|
||||
RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
|
||||
|
||||
// bitrate_bps
|
||||
std::vector<absl::optional<uint64_t>> bitrate_bps_values = DecodeDeltas(
|
||||
proto.bitrate_deltas_bps(), proto.bitrate_bps(), number_of_deltas);
|
||||
RTC_CHECK_EQ(bitrate_bps_values.size(), number_of_deltas);
|
||||
|
||||
// detector_state
|
||||
std::vector<absl::optional<uint64_t>> detector_state_values = DecodeDeltas(
|
||||
proto.detector_state_deltas(),
|
||||
static_cast<uint64_t>(proto.detector_state()), number_of_deltas);
|
||||
RTC_CHECK_EQ(detector_state_values.size(), number_of_deltas);
|
||||
|
||||
// Delta decoding
|
||||
for (size_t i = 0; i < number_of_deltas; ++i) {
|
||||
RTC_CHECK(timestamp_ms_values[i].has_value());
|
||||
|
||||
RTC_CHECK(bitrate_bps_values[i].has_value());
|
||||
RTC_CHECK_LE(bitrate_bps_values[i].value(),
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
const uint32_t bitrate_bps =
|
||||
static_cast<uint32_t>(bitrate_bps_values[i].value());
|
||||
|
||||
RTC_CHECK(detector_state_values[i].has_value());
|
||||
const auto detector_state =
|
||||
static_cast<rtclog2::DelayBasedBweUpdates::DetectorState>(
|
||||
detector_state_values[i].value());
|
||||
|
||||
bwe_delay_updates_.emplace_back(1000 * timestamp_ms_values[i].value(),
|
||||
bitrate_bps,
|
||||
GetRuntimeDetectorState(detector_state));
|
||||
}
|
||||
}
|
||||
|
||||
void ParsedRtcEventLogNew::StoreBweProbeClusterCreated(
|
||||
@ -2049,33 +2276,139 @@ void ParsedRtcEventLogNew::StoreBweProbeFailureEvent(
|
||||
|
||||
void ParsedRtcEventLogNew::StoreAudioNetworkAdaptationEvent(
|
||||
const rtclog2::AudioNetworkAdaptations& proto) {
|
||||
LoggedAudioNetworkAdaptationEvent ana_event;
|
||||
RTC_CHECK(proto.has_timestamp_ms());
|
||||
ana_event.timestamp_us = proto.timestamp_ms() * 1000;
|
||||
|
||||
if (proto.has_bitrate_bps()) {
|
||||
ana_event.config.bitrate_bps = proto.bitrate_bps();
|
||||
}
|
||||
if (proto.has_frame_length_ms()) {
|
||||
ana_event.config.frame_length_ms = proto.frame_length_ms();
|
||||
}
|
||||
if (proto.has_uplink_packet_loss_fraction()) {
|
||||
ana_event.config.uplink_packet_loss_fraction =
|
||||
proto.uplink_packet_loss_fraction();
|
||||
}
|
||||
if (proto.has_enable_fec()) {
|
||||
ana_event.config.enable_fec = proto.enable_fec();
|
||||
}
|
||||
if (proto.has_enable_dtx()) {
|
||||
ana_event.config.enable_dtx = proto.enable_dtx();
|
||||
}
|
||||
if (proto.has_num_channels()) {
|
||||
ana_event.config.num_channels = proto.num_channels();
|
||||
// Base event
|
||||
{
|
||||
AudioEncoderRuntimeConfig runtime_config;
|
||||
if (proto.has_bitrate_bps()) {
|
||||
runtime_config.bitrate_bps = proto.bitrate_bps();
|
||||
}
|
||||
if (proto.has_frame_length_ms()) {
|
||||
runtime_config.frame_length_ms = proto.frame_length_ms();
|
||||
}
|
||||
if (proto.has_uplink_packet_loss_fraction()) {
|
||||
float uplink_packet_loss_fraction;
|
||||
RTC_CHECK(ParsePacketLossFractionFromProtoFormat(
|
||||
proto.uplink_packet_loss_fraction(), &uplink_packet_loss_fraction));
|
||||
runtime_config.uplink_packet_loss_fraction = uplink_packet_loss_fraction;
|
||||
}
|
||||
if (proto.has_enable_fec()) {
|
||||
runtime_config.enable_fec = proto.enable_fec();
|
||||
}
|
||||
if (proto.has_enable_dtx()) {
|
||||
runtime_config.enable_dtx = proto.enable_dtx();
|
||||
}
|
||||
if (proto.has_num_channels()) {
|
||||
runtime_config.num_channels = proto.num_channels();
|
||||
}
|
||||
audio_network_adaptation_events_.emplace_back(1000 * proto.timestamp_ms(),
|
||||
runtime_config);
|
||||
}
|
||||
|
||||
audio_network_adaptation_events_.push_back(ana_event);
|
||||
const size_t number_of_deltas =
|
||||
proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
|
||||
if (number_of_deltas == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(terelius): Parse deltas.
|
||||
// timestamp_ms
|
||||
std::vector<absl::optional<uint64_t>> timestamp_ms_values = DecodeDeltas(
|
||||
proto.timestamp_deltas_ms(), proto.timestamp_ms(), number_of_deltas);
|
||||
RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
|
||||
|
||||
// bitrate_bps
|
||||
const absl::optional<uint64_t> unsigned_base_bitrate_bps =
|
||||
proto.has_bitrate_bps()
|
||||
? absl::optional<uint64_t>(ToUnsigned(proto.bitrate_bps()))
|
||||
: absl::optional<uint64_t>();
|
||||
std::vector<absl::optional<uint64_t>> bitrate_bps_values = DecodeDeltas(
|
||||
proto.bitrate_deltas_bps(), unsigned_base_bitrate_bps, number_of_deltas);
|
||||
RTC_CHECK_EQ(bitrate_bps_values.size(), number_of_deltas);
|
||||
|
||||
// frame_length_ms
|
||||
const absl::optional<uint64_t> unsigned_base_frame_length_ms =
|
||||
proto.has_frame_length_ms()
|
||||
? absl::optional<uint64_t>(ToUnsigned(proto.frame_length_ms()))
|
||||
: absl::optional<uint64_t>();
|
||||
std::vector<absl::optional<uint64_t>> frame_length_ms_values =
|
||||
DecodeDeltas(proto.frame_length_deltas_ms(),
|
||||
unsigned_base_frame_length_ms, number_of_deltas);
|
||||
RTC_CHECK_EQ(frame_length_ms_values.size(), number_of_deltas);
|
||||
|
||||
// uplink_packet_loss_fraction
|
||||
const absl::optional<uint64_t> uplink_packet_loss_fraction =
|
||||
proto.has_uplink_packet_loss_fraction()
|
||||
? absl::optional<uint64_t>(proto.uplink_packet_loss_fraction())
|
||||
: absl::optional<uint64_t>();
|
||||
std::vector<absl::optional<uint64_t>> uplink_packet_loss_fraction_values =
|
||||
DecodeDeltas(proto.uplink_packet_loss_fraction_deltas(),
|
||||
uplink_packet_loss_fraction, number_of_deltas);
|
||||
RTC_CHECK_EQ(uplink_packet_loss_fraction_values.size(), number_of_deltas);
|
||||
|
||||
// enable_fec
|
||||
const absl::optional<uint64_t> enable_fec =
|
||||
proto.has_enable_fec() ? absl::optional<uint64_t>(proto.enable_fec())
|
||||
: absl::optional<uint64_t>();
|
||||
std::vector<absl::optional<uint64_t>> enable_fec_values =
|
||||
DecodeDeltas(proto.enable_fec_deltas(), enable_fec, number_of_deltas);
|
||||
RTC_CHECK_EQ(enable_fec_values.size(), number_of_deltas);
|
||||
|
||||
// enable_dtx
|
||||
const absl::optional<uint64_t> enable_dtx =
|
||||
proto.has_enable_dtx() ? absl::optional<uint64_t>(proto.enable_dtx())
|
||||
: absl::optional<uint64_t>();
|
||||
std::vector<absl::optional<uint64_t>> enable_dtx_values =
|
||||
DecodeDeltas(proto.enable_dtx_deltas(), enable_dtx, number_of_deltas);
|
||||
RTC_CHECK_EQ(enable_dtx_values.size(), number_of_deltas);
|
||||
|
||||
// num_channels
|
||||
const absl::optional<uint64_t> num_channels =
|
||||
proto.has_num_channels() ? absl::optional<uint64_t>(proto.num_channels())
|
||||
: absl::optional<uint64_t>();
|
||||
std::vector<absl::optional<uint64_t>> num_channels_values =
|
||||
DecodeDeltas(proto.num_channels_deltas(), num_channels, number_of_deltas);
|
||||
RTC_CHECK_EQ(num_channels_values.size(), number_of_deltas);
|
||||
|
||||
// Delta decoding
|
||||
for (size_t i = 0; i < number_of_deltas; ++i) {
|
||||
RTC_CHECK(timestamp_ms_values[i].has_value());
|
||||
|
||||
AudioEncoderRuntimeConfig runtime_config;
|
||||
if (bitrate_bps_values[i].has_value()) {
|
||||
int signed_bitrate_bps;
|
||||
RTC_CHECK(ToSigned(bitrate_bps_values[i].value(), &signed_bitrate_bps));
|
||||
runtime_config.bitrate_bps = signed_bitrate_bps;
|
||||
}
|
||||
if (frame_length_ms_values[i].has_value()) {
|
||||
int signed_frame_length_ms;
|
||||
RTC_CHECK(
|
||||
ToSigned(frame_length_ms_values[i].value(), &signed_frame_length_ms));
|
||||
runtime_config.frame_length_ms = signed_frame_length_ms;
|
||||
}
|
||||
if (uplink_packet_loss_fraction_values[i].has_value()) {
|
||||
float uplink_packet_loss_fraction;
|
||||
RTC_CHECK(ParsePacketLossFractionFromProtoFormat(
|
||||
rtc::checked_cast<uint32_t>(
|
||||
uplink_packet_loss_fraction_values[i].value()),
|
||||
&uplink_packet_loss_fraction));
|
||||
runtime_config.uplink_packet_loss_fraction = uplink_packet_loss_fraction;
|
||||
}
|
||||
if (enable_fec_values[i].has_value()) {
|
||||
runtime_config.enable_fec =
|
||||
rtc::checked_cast<bool>(enable_fec_values[i].value());
|
||||
}
|
||||
if (enable_dtx_values[i].has_value()) {
|
||||
runtime_config.enable_dtx =
|
||||
rtc::checked_cast<bool>(enable_dtx_values[i].value());
|
||||
}
|
||||
if (num_channels_values[i].has_value()) {
|
||||
runtime_config.num_channels =
|
||||
rtc::checked_cast<size_t>(num_channels_values[i].value());
|
||||
}
|
||||
audio_network_adaptation_events_.emplace_back(
|
||||
1000 * timestamp_ms_values[i].value(), runtime_config);
|
||||
}
|
||||
}
|
||||
|
||||
void ParsedRtcEventLogNew::StoreIceCandidatePairConfig(
|
||||
|
||||
@ -1013,9 +1013,8 @@ class ParsedRtcEventLogNew {
|
||||
|
||||
// Parsing functions for new format.
|
||||
void StoreParsedNewFormatEvent(const rtclog2::EventStream& event);
|
||||
|
||||
void StoreIncomingRtpPackets(const rtclog2::IncomingRtpPackets& proto);
|
||||
void StoreOutgoingRtpPacket(const rtclog2::OutgoingRtpPackets& proto);
|
||||
void StoreOutgoingRtpPackets(const rtclog2::OutgoingRtpPackets& proto);
|
||||
void StoreIncomingRtcpPackets(const rtclog2::IncomingRtcpPackets& proto);
|
||||
void StoreOutgoingRtcpPackets(const rtclog2::OutgoingRtcpPackets& proto);
|
||||
void StoreAudioPlayoutEvent(const rtclog2::AudioPlayoutEvents& proto);
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include <string.h> // memcmp
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
@ -279,7 +280,8 @@ void EventGenerator::RandomizeRtpPacket(
|
||||
size_t padding_size,
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map,
|
||||
RtpPacket* rtp_packet) {
|
||||
RtpPacket* rtp_packet,
|
||||
bool all_configured_exts) {
|
||||
constexpr int kMaxPayloadType = 127;
|
||||
rtp_packet->SetPayloadType(prng_.Rand(kMaxPayloadType));
|
||||
rtp_packet->SetMarker(prng_.Rand<bool>());
|
||||
@ -294,16 +296,30 @@ void EventGenerator::RandomizeRtpPacket(
|
||||
}
|
||||
rtp_packet->SetCsrcs(csrcs);
|
||||
|
||||
if (extension_map.IsRegistered(TransmissionOffset::kId))
|
||||
if (extension_map.IsRegistered(TransmissionOffset::kId) &&
|
||||
(all_configured_exts || prng_.Rand<bool>())) {
|
||||
rtp_packet->SetExtension<TransmissionOffset>(prng_.Rand(0x00ffffff));
|
||||
if (extension_map.IsRegistered(AudioLevel::kId))
|
||||
}
|
||||
|
||||
if (extension_map.IsRegistered(AudioLevel::kId) &&
|
||||
(all_configured_exts || prng_.Rand<bool>())) {
|
||||
rtp_packet->SetExtension<AudioLevel>(prng_.Rand<bool>(), prng_.Rand(127));
|
||||
if (extension_map.IsRegistered(AbsoluteSendTime::kId))
|
||||
}
|
||||
|
||||
if (extension_map.IsRegistered(AbsoluteSendTime::kId) &&
|
||||
(all_configured_exts || prng_.Rand<bool>())) {
|
||||
rtp_packet->SetExtension<AbsoluteSendTime>(prng_.Rand(0x00ffffff));
|
||||
if (extension_map.IsRegistered(VideoOrientation::kId))
|
||||
}
|
||||
|
||||
if (extension_map.IsRegistered(VideoOrientation::kId) &&
|
||||
(all_configured_exts || prng_.Rand<bool>())) {
|
||||
rtp_packet->SetExtension<VideoOrientation>(prng_.Rand(3));
|
||||
if (extension_map.IsRegistered(TransportSequenceNumber::kId))
|
||||
}
|
||||
|
||||
if (extension_map.IsRegistered(TransportSequenceNumber::kId) &&
|
||||
(all_configured_exts || prng_.Rand<bool>())) {
|
||||
rtp_packet->SetExtension<TransportSequenceNumber>(prng_.Rand<uint16_t>());
|
||||
}
|
||||
|
||||
RTC_CHECK_LE(rtp_packet->headers_size() + payload_size, IP_PACKET_SIZE);
|
||||
|
||||
@ -317,7 +333,8 @@ void EventGenerator::RandomizeRtpPacket(
|
||||
|
||||
std::unique_ptr<RtcEventRtpPacketIncoming> EventGenerator::NewRtpPacketIncoming(
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map) {
|
||||
const RtpHeaderExtensionMap& extension_map,
|
||||
bool all_configured_exts) {
|
||||
constexpr size_t kMaxPaddingLength = 224;
|
||||
const bool padding = prng_.Rand(0, 9) == 0; // Let padding be 10% probable.
|
||||
const size_t padding_size = !padding ? 0u : prng_.Rand(0u, kMaxPaddingLength);
|
||||
@ -338,14 +355,15 @@ std::unique_ptr<RtcEventRtpPacketIncoming> EventGenerator::NewRtpPacketIncoming(
|
||||
|
||||
RtpPacketReceived rtp_packet(&extension_map);
|
||||
RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map,
|
||||
&rtp_packet);
|
||||
&rtp_packet, all_configured_exts);
|
||||
|
||||
return absl::make_unique<RtcEventRtpPacketIncoming>(rtp_packet);
|
||||
}
|
||||
|
||||
std::unique_ptr<RtcEventRtpPacketOutgoing> EventGenerator::NewRtpPacketOutgoing(
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map) {
|
||||
const RtpHeaderExtensionMap& extension_map,
|
||||
bool all_configured_exts) {
|
||||
constexpr size_t kMaxPaddingLength = 224;
|
||||
const bool padding = prng_.Rand(0, 9) == 0; // Let padding be 10% probable.
|
||||
const size_t padding_size = !padding ? 0u : prng_.Rand(0u, kMaxPaddingLength);
|
||||
@ -367,33 +385,34 @@ std::unique_ptr<RtcEventRtpPacketOutgoing> EventGenerator::NewRtpPacketOutgoing(
|
||||
RtpPacketToSend rtp_packet(&extension_map,
|
||||
kMaxHeaderSize + payload_size + padding_size);
|
||||
RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map,
|
||||
&rtp_packet);
|
||||
&rtp_packet, all_configured_exts);
|
||||
|
||||
int probe_cluster_id = prng_.Rand(0, 100000);
|
||||
return absl::make_unique<RtcEventRtpPacketOutgoing>(rtp_packet,
|
||||
probe_cluster_id);
|
||||
}
|
||||
|
||||
RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap() {
|
||||
RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap(
|
||||
bool configure_all) {
|
||||
RtpHeaderExtensionMap extension_map;
|
||||
std::vector<int> id(RtpExtension::kOneByteHeaderExtensionMaxId -
|
||||
RtpExtension::kMinId + 1);
|
||||
std::iota(id.begin(), id.end(), RtpExtension::kMinId);
|
||||
ShuffleInPlace(&prng_, rtc::ArrayView<int>(id));
|
||||
|
||||
if (prng_.Rand<bool>()) {
|
||||
if (configure_all || prng_.Rand<bool>()) {
|
||||
extension_map.Register<AudioLevel>(id[0]);
|
||||
}
|
||||
if (prng_.Rand<bool>()) {
|
||||
if (configure_all || prng_.Rand<bool>()) {
|
||||
extension_map.Register<TransmissionOffset>(id[1]);
|
||||
}
|
||||
if (prng_.Rand<bool>()) {
|
||||
if (configure_all || prng_.Rand<bool>()) {
|
||||
extension_map.Register<AbsoluteSendTime>(id[2]);
|
||||
}
|
||||
if (prng_.Rand<bool>()) {
|
||||
if (configure_all || prng_.Rand<bool>()) {
|
||||
extension_map.Register<VideoOrientation>(id[3]);
|
||||
}
|
||||
if (prng_.Rand<bool>()) {
|
||||
if (configure_all || prng_.Rand<bool>()) {
|
||||
extension_map.Register<TransportSequenceNumber>(id[4]);
|
||||
}
|
||||
|
||||
@ -508,8 +527,18 @@ void VerifyLoggedAudioNetworkAdaptationEvent(
|
||||
logged_event.config.frame_length_ms);
|
||||
EXPECT_EQ(original_event.config_->num_channels,
|
||||
logged_event.config.num_channels);
|
||||
EXPECT_EQ(original_event.config_->uplink_packet_loss_fraction,
|
||||
logged_event.config.uplink_packet_loss_fraction);
|
||||
|
||||
// uplink_packet_loss_fraction
|
||||
ASSERT_EQ(original_event.config_->uplink_packet_loss_fraction.has_value(),
|
||||
logged_event.config.uplink_packet_loss_fraction.has_value());
|
||||
if (original_event.config_->uplink_packet_loss_fraction.has_value()) {
|
||||
const float original =
|
||||
original_event.config_->uplink_packet_loss_fraction.value();
|
||||
const float logged =
|
||||
logged_event.config.uplink_packet_loss_fraction.value();
|
||||
const float uplink_packet_loss_fraction_delta = std::abs(original - logged);
|
||||
EXPECT_LE(uplink_packet_loss_fraction_delta, 0.0001f);
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyLoggedBweDelayBasedUpdate(
|
||||
@ -603,7 +632,7 @@ void VerifyLoggedRtpHeader(const RtpPacket& original_header,
|
||||
logged_header.extension.hasTransmissionTimeOffset);
|
||||
if (logged_header.extension.hasTransmissionTimeOffset) {
|
||||
int32_t offset;
|
||||
original_header.GetExtension<TransmissionOffset>(&offset);
|
||||
ASSERT_TRUE(original_header.GetExtension<TransmissionOffset>(&offset));
|
||||
EXPECT_EQ(offset, logged_header.extension.transmissionTimeOffset);
|
||||
}
|
||||
|
||||
@ -612,7 +641,7 @@ void VerifyLoggedRtpHeader(const RtpPacket& original_header,
|
||||
logged_header.extension.hasAbsoluteSendTime);
|
||||
if (logged_header.extension.hasAbsoluteSendTime) {
|
||||
uint32_t sendtime;
|
||||
original_header.GetExtension<AbsoluteSendTime>(&sendtime);
|
||||
ASSERT_TRUE(original_header.GetExtension<AbsoluteSendTime>(&sendtime));
|
||||
EXPECT_EQ(sendtime, logged_header.extension.absoluteSendTime);
|
||||
}
|
||||
|
||||
@ -621,7 +650,7 @@ void VerifyLoggedRtpHeader(const RtpPacket& original_header,
|
||||
logged_header.extension.hasTransportSequenceNumber);
|
||||
if (logged_header.extension.hasTransportSequenceNumber) {
|
||||
uint16_t seqnum;
|
||||
original_header.GetExtension<TransportSequenceNumber>(&seqnum);
|
||||
ASSERT_TRUE(original_header.GetExtension<TransportSequenceNumber>(&seqnum));
|
||||
EXPECT_EQ(seqnum, logged_header.extension.transportSequenceNumber);
|
||||
}
|
||||
|
||||
@ -631,7 +660,8 @@ void VerifyLoggedRtpHeader(const RtpPacket& original_header,
|
||||
if (logged_header.extension.hasAudioLevel) {
|
||||
bool voice_activity;
|
||||
uint8_t audio_level;
|
||||
original_header.GetExtension<AudioLevel>(&voice_activity, &audio_level);
|
||||
ASSERT_TRUE(original_header.GetExtension<AudioLevel>(&voice_activity,
|
||||
&audio_level));
|
||||
EXPECT_EQ(voice_activity, logged_header.extension.voiceActivity);
|
||||
EXPECT_EQ(audio_level, logged_header.extension.audioLevel);
|
||||
}
|
||||
@ -641,7 +671,7 @@ void VerifyLoggedRtpHeader(const RtpPacket& original_header,
|
||||
logged_header.extension.hasVideoRotation);
|
||||
if (logged_header.extension.hasVideoRotation) {
|
||||
uint8_t rotation;
|
||||
original_header.GetExtension<VideoOrientation>(&rotation);
|
||||
ASSERT_TRUE(original_header.GetExtension<VideoOrientation>(&rotation));
|
||||
EXPECT_EQ(ConvertCVOByteToVideoRotation(rotation),
|
||||
logged_header.extension.videoRotation);
|
||||
}
|
||||
|
||||
@ -71,21 +71,32 @@ class EventGenerator {
|
||||
|
||||
std::unique_ptr<RtcEventRtcpPacketOutgoing> NewRtcpPacketOutgoing();
|
||||
|
||||
// |all_configured_exts| determines whether the RTP packet exhibits all
|
||||
// configured extensions, or a random subset thereof.
|
||||
void RandomizeRtpPacket(size_t payload_size,
|
||||
size_t padding_size,
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map,
|
||||
RtpPacket* rtp_packet);
|
||||
RtpPacket* rtp_packet,
|
||||
bool all_configured_exts);
|
||||
|
||||
// |all_configured_exts| determines whether the RTP packet exhibits all
|
||||
// configured extensions, or a random subset thereof.
|
||||
std::unique_ptr<RtcEventRtpPacketIncoming> NewRtpPacketIncoming(
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map);
|
||||
const RtpHeaderExtensionMap& extension_map,
|
||||
bool all_configured_exts = true);
|
||||
|
||||
// |all_configured_exts| determines whether the RTP packet exhibits all
|
||||
// configured extensions, or a random subset thereof.
|
||||
std::unique_ptr<RtcEventRtpPacketOutgoing> NewRtpPacketOutgoing(
|
||||
uint32_t ssrc,
|
||||
const RtpHeaderExtensionMap& extension_map);
|
||||
const RtpHeaderExtensionMap& extension_map,
|
||||
bool all_configured_exts = true);
|
||||
|
||||
RtpHeaderExtensionMap NewRtpHeaderExtensionMap();
|
||||
// |configure_all| determines whether all supported extensions are configured,
|
||||
// or a random subset.
|
||||
RtpHeaderExtensionMap NewRtpHeaderExtensionMap(bool configure_all = false);
|
||||
|
||||
std::unique_ptr<RtcEventAudioReceiveStreamConfig> NewAudioReceiveStreamConfig(
|
||||
uint32_t ssrc,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user