mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
Add new RTC event log encoding for AudioPlayout and DelayBasedBwe events.
Bug: webrtc:11933 Change-Id: Ia54d973099916c8dba9fedf362f25e46fe5cc541 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/246204 Reviewed-by: Sebastian Jansson <srte@webrtc.org> Commit-Queue: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/main@{#35959}
This commit is contained in:
parent
3ed36c0521
commit
d12a14e21f
14 changed files with 350 additions and 150 deletions
|
@ -85,7 +85,10 @@ rtc_library("rtc_event_pacing") {
|
|||
"../api/rtc_event_log",
|
||||
"../api/units:timestamp",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/memory" ]
|
||||
absl_deps = [
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("rtc_event_audio") {
|
||||
|
@ -101,13 +104,17 @@ rtc_library("rtc_event_audio") {
|
|||
]
|
||||
|
||||
deps = [
|
||||
":rtc_event_field",
|
||||
":rtc_stream_config",
|
||||
"../api/rtc_event_log",
|
||||
"../api/units:timestamp",
|
||||
"../modules/audio_coding:audio_network_adaptor_config",
|
||||
"../rtc_base:checks",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/memory" ]
|
||||
absl_deps = [
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("rtc_event_begin_end") {
|
||||
|
@ -144,6 +151,7 @@ rtc_library("rtc_event_bwe") {
|
|||
]
|
||||
|
||||
deps = [
|
||||
":rtc_event_field",
|
||||
"../api:network_state_predictor_api",
|
||||
"../api/rtc_event_log",
|
||||
"../api/units:data_rate",
|
||||
|
@ -151,6 +159,7 @@ rtc_library("rtc_event_bwe") {
|
|||
]
|
||||
absl_deps = [
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -75,6 +75,9 @@ std::string RtcEventLogEncoderV3::EncodeLogEnd(int64_t timestamp_us) {
|
|||
|
||||
RtcEventLogEncoderV3::RtcEventLogEncoderV3() {
|
||||
encoders_[RtcEvent::Type::AlrStateEvent] = RtcEventAlrState::Encode;
|
||||
encoders_[RtcEvent::Type::AudioPlayout] = RtcEventAudioPlayout::Encode;
|
||||
encoders_[RtcEvent::Type::BweUpdateDelayBased] =
|
||||
RtcEventBweUpdateDelayBased::Encode;
|
||||
}
|
||||
|
||||
std::string RtcEventLogEncoderV3::EncodeBatch(
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/rtc_event_log/rtc_event.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_definition.h"
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
|
||||
namespace webrtc {
|
||||
|
||||
constexpr RtcEventDefinition<RtcEventAudioPlayout,
|
||||
LoggedAudioPlayoutEvent,
|
||||
uint32_t>
|
||||
RtcEventAudioPlayout::definition_;
|
||||
|
||||
RtcEventAudioPlayout::RtcEventAudioPlayout(uint32_t ssrc) : ssrc_(ssrc) {}
|
||||
|
||||
RtcEventAudioPlayout::RtcEventAudioPlayout(const RtcEventAudioPlayout& other)
|
||||
|
|
|
@ -13,10 +13,15 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/rtc_event_log/rtc_event.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_definition.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
|
@ -46,10 +51,35 @@ class RtcEventAudioPlayout final : public RtcEvent {
|
|||
|
||||
uint32_t ssrc() const { return ssrc_; }
|
||||
|
||||
static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
|
||||
return RtcEventAudioPlayout::definition_.EncodeBatch(batch);
|
||||
}
|
||||
|
||||
static RtcEventLogParseStatus Parse(
|
||||
absl::string_view s,
|
||||
bool batched,
|
||||
std::map<uint32_t, std::vector<LoggedAudioPlayoutEvent>>& output) {
|
||||
std::vector<LoggedAudioPlayoutEvent> temp_output;
|
||||
auto status =
|
||||
RtcEventAudioPlayout::definition_.ParseBatch(s, batched, temp_output);
|
||||
for (const LoggedAudioPlayoutEvent& event : temp_output) {
|
||||
output[event.ssrc].push_back(event);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
private:
|
||||
RtcEventAudioPlayout(const RtcEventAudioPlayout& other);
|
||||
|
||||
const uint32_t ssrc_;
|
||||
|
||||
static constexpr RtcEventDefinition<RtcEventAudioPlayout,
|
||||
LoggedAudioPlayoutEvent,
|
||||
uint32_t>
|
||||
definition_{{"AudioPlayout", RtcEventAudioPlayout::kType},
|
||||
{&RtcEventAudioPlayout::ssrc_,
|
||||
&LoggedAudioPlayoutEvent::ssrc,
|
||||
{"ssrc", /*id=*/1, FieldType::kFixed32, /*width=*/32}}};
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -54,14 +54,18 @@ RtcEventLogParseStatus RtcEventBeginLog::Parse(
|
|||
parser.ParseNumericField(timestamp_params);
|
||||
if (!result.ok())
|
||||
return result.status();
|
||||
PopulateRtcEventTimestamp(result.value(), &LoggedStartEvent::timestamp,
|
||||
output_batch);
|
||||
status = PopulateRtcEventTimestamp(
|
||||
result.value(), &LoggedStartEvent::timestamp, output_batch);
|
||||
if (!status.ok())
|
||||
return status;
|
||||
|
||||
result = parser.ParseNumericField(utc_start_time_params_);
|
||||
if (!result.ok())
|
||||
return result.status();
|
||||
PopulateRtcEventTimestamp(result.value(), &LoggedStartEvent::utc_start_time,
|
||||
output_batch);
|
||||
status = PopulateRtcEventTimestamp(
|
||||
result.value(), &LoggedStartEvent::utc_start_time, output_batch);
|
||||
if (!status.ok())
|
||||
return status;
|
||||
|
||||
return RtcEventLogParseStatus::Success();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
|
||||
namespace webrtc {
|
||||
|
||||
constexpr RtcEventDefinition<RtcEventBweUpdateDelayBased,
|
||||
LoggedBweDelayBasedUpdate,
|
||||
int32_t,
|
||||
BandwidthUsage>
|
||||
RtcEventBweUpdateDelayBased::definition_;
|
||||
|
||||
RtcEventBweUpdateDelayBased::RtcEventBweUpdateDelayBased(
|
||||
int32_t bitrate_bps,
|
||||
BandwidthUsage detector_state)
|
||||
|
|
|
@ -13,14 +13,58 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/network_state_predictor.h"
|
||||
#include "api/rtc_event_log/rtc_event.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_definition.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Separate the event log encoding from the enum values.
|
||||
// As long as the enum values are the same as the encodings,
|
||||
// the two conversion functions can be compiled to (roughly)
|
||||
// a range check each.
|
||||
template <>
|
||||
class RtcEventLogEnum<BandwidthUsage> {
|
||||
static constexpr uint64_t kBwNormal = 0;
|
||||
static constexpr uint64_t kBwUnderusing = 1;
|
||||
static constexpr uint64_t kBwOverusing = 2;
|
||||
|
||||
public:
|
||||
static uint64_t Encode(BandwidthUsage x) {
|
||||
switch (x) {
|
||||
case BandwidthUsage::kBwNormal:
|
||||
return kBwNormal;
|
||||
case BandwidthUsage::kBwUnderusing:
|
||||
return kBwUnderusing;
|
||||
case BandwidthUsage::kBwOverusing:
|
||||
return kBwOverusing;
|
||||
case BandwidthUsage::kLast:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
static RtcEventLogParseStatusOr<BandwidthUsage> Decode(uint64_t x) {
|
||||
switch (x) {
|
||||
case kBwNormal:
|
||||
return BandwidthUsage::kBwNormal;
|
||||
case kBwUnderusing:
|
||||
return BandwidthUsage::kBwUnderusing;
|
||||
case kBwOverusing:
|
||||
return BandwidthUsage::kBwOverusing;
|
||||
}
|
||||
return RtcEventLogParseStatus::Error("Failed to decode BandwidthUsage enum",
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
};
|
||||
|
||||
struct LoggedBweDelayBasedUpdate {
|
||||
LoggedBweDelayBasedUpdate() = default;
|
||||
LoggedBweDelayBasedUpdate(Timestamp timestamp,
|
||||
|
@ -54,11 +98,36 @@ class RtcEventBweUpdateDelayBased final : public RtcEvent {
|
|||
int32_t bitrate_bps() const { return bitrate_bps_; }
|
||||
BandwidthUsage detector_state() const { return detector_state_; }
|
||||
|
||||
static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
|
||||
return RtcEventBweUpdateDelayBased::definition_.EncodeBatch(batch);
|
||||
}
|
||||
|
||||
static RtcEventLogParseStatus Parse(
|
||||
absl::string_view s,
|
||||
bool batched,
|
||||
std::vector<LoggedBweDelayBasedUpdate>& output) {
|
||||
return RtcEventBweUpdateDelayBased::definition_.ParseBatch(s, batched,
|
||||
output);
|
||||
}
|
||||
|
||||
private:
|
||||
RtcEventBweUpdateDelayBased(const RtcEventBweUpdateDelayBased& other);
|
||||
|
||||
const int32_t bitrate_bps_;
|
||||
const BandwidthUsage detector_state_;
|
||||
|
||||
static constexpr RtcEventDefinition<RtcEventBweUpdateDelayBased,
|
||||
LoggedBweDelayBasedUpdate,
|
||||
int32_t,
|
||||
BandwidthUsage>
|
||||
definition_{
|
||||
{"BweDelayBased", RtcEventBweUpdateDelayBased::kType},
|
||||
{&RtcEventBweUpdateDelayBased::bitrate_bps_,
|
||||
&LoggedBweDelayBasedUpdate::bitrate_bps,
|
||||
{"bitrate_bps", /*id=*/1, FieldType::kVarInt, /*width=*/32}},
|
||||
{&RtcEventBweUpdateDelayBased::detector_state_,
|
||||
&LoggedBweDelayBasedUpdate::detector_state,
|
||||
{"detector_state", /*id=*/2, FieldType::kVarInt, /*width=*/64}}};
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -67,7 +67,10 @@ class RtcEventDefinitionImpl<EventType, LoggedType, T, Ts...> {
|
|||
parser.ParseNumericField(field_.params);
|
||||
if (!result.ok())
|
||||
return result.status();
|
||||
PopulateRtcEventMember(result.value(), field_.logged_member, output_batch);
|
||||
auto status = PopulateRtcEventMember(result.value(), field_.logged_member,
|
||||
output_batch);
|
||||
if (!status.ok())
|
||||
return status;
|
||||
|
||||
return rest_.ParseImpl(parser, output_batch);
|
||||
}
|
||||
|
@ -131,12 +134,12 @@ class RtcEventDefinition {
|
|||
parser.ParseNumericField(timestamp_params);
|
||||
if (!result.ok())
|
||||
return result.status();
|
||||
PopulateRtcEventTimestamp(result.value(), &LoggedType::timestamp,
|
||||
output_batch);
|
||||
status = PopulateRtcEventTimestamp(result.value(), &LoggedType::timestamp,
|
||||
output_batch);
|
||||
if (!status.ok())
|
||||
return status;
|
||||
|
||||
return fields_.ParseImpl(parser, output_batch);
|
||||
|
||||
return RtcEventLogParseStatus::Success();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -47,8 +47,10 @@ RtcEventLogParseStatus RtcEventEndLog::Parse(
|
|||
parser.ParseNumericField(timestamp_params);
|
||||
if (!result.ok())
|
||||
return result.status();
|
||||
PopulateRtcEventTimestamp(result.value(), &LoggedStopEvent::timestamp,
|
||||
output_batch);
|
||||
status = PopulateRtcEventTimestamp(result.value(),
|
||||
&LoggedStopEvent::timestamp, output_batch);
|
||||
if (!status.ok())
|
||||
return status;
|
||||
|
||||
return RtcEventLogParseStatus::Success();
|
||||
}
|
||||
|
|
|
@ -93,5 +93,87 @@ std::string EncodeDeltasV3(FixedLengthEncodingParametersV3 params,
|
|||
uint64_t base,
|
||||
rtc::ArrayView<const uint64_t> values);
|
||||
|
||||
// Given a batch of RtcEvents and a member pointer, extract that
|
||||
// member from each event in the batch. Signed integer members are
|
||||
// encoded as unsigned, and the bitsize increased so the result can
|
||||
// represented as a std::vector<uint64_t>.
|
||||
// This is intended to be used in conjuction with
|
||||
// EventEncoder::EncodeField to encode a batch of events as follows:
|
||||
// auto values = ExtractRtcEventMember(batch, RtcEventFoo::timestamp_ms);
|
||||
// encoder.EncodeField(timestamp_params, values)
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
std::vector<uint64_t> ExtractRtcEventMember(
|
||||
rtc::ArrayView<const RtcEvent*> batch,
|
||||
const T E::*member) {
|
||||
std::vector<uint64_t> values;
|
||||
values.reserve(batch.size());
|
||||
for (const RtcEvent* event : batch) {
|
||||
RTC_CHECK_EQ(event->GetType(), E::kType);
|
||||
T value = static_cast<const E*>(event)->*member;
|
||||
values.push_back(EncodeAsUnsigned(value));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// Extract an optional field from a batch of RtcEvents.
|
||||
// The function returns a vector of positions in addition to the vector of
|
||||
// values. The vector `positions` has the same length as the batch where
|
||||
// `positions[i] == true` iff the batch[i]->member has a value.
|
||||
// The values vector only contains the values that exists, so it
|
||||
// may be shorter than the batch.
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
ValuesWithPositions ExtractRtcEventMember(rtc::ArrayView<const RtcEvent*> batch,
|
||||
const absl::optional<T> E::*member) {
|
||||
ValuesWithPositions result;
|
||||
result.position_mask.reserve(batch.size());
|
||||
result.values.reserve(batch.size());
|
||||
for (const RtcEvent* event : batch) {
|
||||
RTC_CHECK_EQ(event->GetType(), E::kType);
|
||||
absl::optional<T> field = static_cast<const E*>(event)->*member;
|
||||
result.position_mask.push_back(field.has_value());
|
||||
if (field.has_value()) {
|
||||
result.values.push_back(EncodeAsUnsigned(field.value()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Extract an enum field from a batch of RtcEvents.
|
||||
// Requires specializing RtcEventLogEnum<T> for the enum type T.
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_enum<T>::value, bool> = true>
|
||||
std::vector<uint64_t> ExtractRtcEventMember(
|
||||
rtc::ArrayView<const RtcEvent*> batch,
|
||||
const T E::*member) {
|
||||
std::vector<uint64_t> values;
|
||||
values.reserve(batch.size());
|
||||
for (const RtcEvent* event : batch) {
|
||||
RTC_CHECK_EQ(event->GetType(), E::kType);
|
||||
T value = static_cast<const E*>(event)->*member;
|
||||
values.push_back(RtcEventLogEnum<T>::Encode(value));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// Extract a string field from a batch of RtcEvents.
|
||||
template <typename E>
|
||||
std::vector<absl::string_view> ExtractRtcEventMember(
|
||||
rtc::ArrayView<const RtcEvent*> batch,
|
||||
const std::string E::*member) {
|
||||
std::vector<absl::string_view> values;
|
||||
values.reserve(batch.size());
|
||||
for (const RtcEvent* event : batch) {
|
||||
RTC_CHECK_EQ(event->GetType(), E::kType);
|
||||
absl::string_view str = static_cast<const E*>(event)->*member;
|
||||
values.push_back(str);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_
|
||||
|
|
|
@ -174,5 +174,110 @@ class EventParser {
|
|||
uint64_t last_field_id_ = FieldParameters::kTimestampField;
|
||||
};
|
||||
|
||||
// Inverse of the ExtractRtcEventMember function used when parsing
|
||||
// a log. Uses a vector of values to populate a specific field in a
|
||||
// vector of structs.
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
ABSL_MUST_USE_RESULT RtcEventLogParseStatus
|
||||
PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,
|
||||
T E::*member,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = values.size();
|
||||
RTC_CHECK_EQ(output.size(), batch_size);
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
output[i].*member = DecodeFromUnsignedToType<T>(values[i]);
|
||||
}
|
||||
return RtcEventLogParseStatus::Success();
|
||||
}
|
||||
|
||||
// Same as above, but for optional fields.
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
ABSL_MUST_USE_RESULT RtcEventLogParseStatus
|
||||
PopulateRtcEventMember(const rtc::ArrayView<uint8_t> positions,
|
||||
const rtc::ArrayView<uint64_t> values,
|
||||
absl::optional<T> E::*member,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = positions.size();
|
||||
RTC_CHECK_EQ(output.size(), batch_size);
|
||||
RTC_CHECK_LE(values.size(), batch_size);
|
||||
auto value_it = values.begin();
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
if (positions[i]) {
|
||||
RTC_CHECK(value_it != values.end());
|
||||
output[i].*member = DecodeFromUnsignedToType<T>(value_it);
|
||||
++value_it;
|
||||
} else {
|
||||
output[i].*member = absl::nullopt;
|
||||
}
|
||||
}
|
||||
RTC_CHECK(value_it == values.end());
|
||||
return RtcEventLogParseStatus::Success();
|
||||
}
|
||||
|
||||
// Same as above, but for enum fields.
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_enum<T>::value, bool> = true>
|
||||
ABSL_MUST_USE_RESULT RtcEventLogParseStatus
|
||||
PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,
|
||||
T E::*member,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = values.size();
|
||||
RTC_CHECK_EQ(output.size(), batch_size);
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
auto result = RtcEventLogEnum<T>::Decode(values[i]);
|
||||
if (!result.ok()) {
|
||||
return result.status();
|
||||
}
|
||||
output[i].*member = result.value();
|
||||
}
|
||||
return RtcEventLogParseStatus::Success();
|
||||
}
|
||||
|
||||
// Same as above, but for string fields.
|
||||
template <typename E>
|
||||
ABSL_MUST_USE_RESULT RtcEventLogParseStatus
|
||||
PopulateRtcEventMember(const rtc::ArrayView<absl::string_view> values,
|
||||
std::string E::*member,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = values.size();
|
||||
RTC_CHECK_EQ(output.size(), batch_size);
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
output[i].*member = values[i];
|
||||
}
|
||||
return RtcEventLogParseStatus::Success();
|
||||
}
|
||||
|
||||
// Same as above, but for Timestamp fields.
|
||||
// N.B. Assumes that the encoded value uses millisecond precision.
|
||||
template <typename E>
|
||||
ABSL_MUST_USE_RESULT RtcEventLogParseStatus
|
||||
PopulateRtcEventTimestamp(const rtc::ArrayView<uint64_t>& values,
|
||||
Timestamp E::*timestamp,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = values.size();
|
||||
RTC_CHECK_EQ(batch_size, output.size());
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
output[i].*timestamp =
|
||||
Timestamp::Millis(DecodeFromUnsignedToType<int64_t>(values[i]));
|
||||
}
|
||||
return RtcEventLogParseStatus::Success();
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
rtc::ArrayView<E> ExtendLoggedBatch(std::vector<E>& output,
|
||||
size_t new_elements) {
|
||||
size_t old_size = output.size();
|
||||
output.insert(output.end(), old_size + new_elements, E());
|
||||
rtc::ArrayView<E> output_batch = output;
|
||||
output_batch.subview(old_size);
|
||||
RTC_DCHECK_EQ(output_batch.size(), new_elements);
|
||||
return output_batch;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_PARSER_H_
|
||||
|
|
|
@ -56,29 +56,16 @@ T DecodeFromUnsignedToType(uint64_t value) {
|
|||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
// Given a batch of RtcEvents and a member pointer, extract that
|
||||
// member from each event in the batch. Signed integer members are
|
||||
// encoded as unsigned, and the bitsize increased so the result can
|
||||
// represented as a std::vector<uin64_t>.
|
||||
// This is intended to be used in conjuction with
|
||||
// EventEncoder::EncodeField to encode a batch of events as follows:
|
||||
// auto values = ExtractRtcEventMember(batch, RtcEventFoo::timestamp_ms);
|
||||
// encoder.EncodeField(timestamp_params, values)
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
std::vector<uint64_t> ExtractRtcEventMember(
|
||||
rtc::ArrayView<const RtcEvent*> batch,
|
||||
const T E::*member) {
|
||||
std::vector<uint64_t> values;
|
||||
values.reserve(batch.size());
|
||||
for (const RtcEvent* event : batch) {
|
||||
RTC_CHECK_EQ(event->GetType(), E::kType);
|
||||
T value = static_cast<const E*>(event)->*member;
|
||||
values.push_back(EncodeAsUnsigned(value));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
// RtcEventLogEnum<T> defines a mapping between an enum T
|
||||
// and the event log encodings. To log a new enum type T,
|
||||
// specialize RtcEventLogEnum<T> and add static methods
|
||||
// static uint64_t Encode(T x) {}
|
||||
// static RtcEventLogParseStatusOr<T> Decode(uint64_t x) {}
|
||||
template <typename T>
|
||||
class RtcEventLogEnum {
|
||||
static_assert(sizeof(T) != sizeof(T),
|
||||
"Missing specialisation of RtcEventLogEnum for type");
|
||||
};
|
||||
|
||||
// Represents a vector<optional<uint64_t>> optional_values
|
||||
// as a bit-vector `position_mask` which identifies the positions
|
||||
|
@ -92,119 +79,6 @@ struct ValuesWithPositions {
|
|||
std::vector<uint64_t> values;
|
||||
};
|
||||
|
||||
// Same as above but for optional fields. It returns a struct
|
||||
// containing a vector of positions in addition to the vector of values.
|
||||
// The vector `positions` has the same length as the batch where
|
||||
// `positions[i] == true` iff the batch[i]->member has a value.
|
||||
// The values vector only contains the values that exists, so it
|
||||
// may be shorter than the batch.
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
ValuesWithPositions ExtractRtcEventMember(rtc::ArrayView<const RtcEvent*> batch,
|
||||
const absl::optional<T> E::*member) {
|
||||
ValuesWithPositions result;
|
||||
result.position_mask.reserve(batch.size());
|
||||
result.values.reserve(batch.size());
|
||||
for (const RtcEvent* event : batch) {
|
||||
RTC_CHECK_EQ(event->GetType(), E::kType);
|
||||
absl::optional<T> field = static_cast<const E*>(event)->*member;
|
||||
result.position_mask.push_back(field.has_value());
|
||||
if (field.has_value()) {
|
||||
result.values.push_back(EncodeAsUnsigned(field.value()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
std::vector<absl::string_view> ExtractRtcEventMember(
|
||||
rtc::ArrayView<const RtcEvent*> batch,
|
||||
const std::string E::*member) {
|
||||
std::vector<absl::string_view> values;
|
||||
values.reserve(batch.size());
|
||||
for (const RtcEvent* event : batch) {
|
||||
RTC_CHECK_EQ(event->GetType(), E::kType);
|
||||
absl::string_view str = static_cast<const E*>(event)->*member;
|
||||
values.push_back(str);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// Inverse of the ExtractRtcEventMember function used when parsing
|
||||
// a log. Uses a vector of values to populate a specific field in a
|
||||
// vector of structs.
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
void PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,
|
||||
T E::*member,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = values.size();
|
||||
RTC_CHECK_EQ(output.size(), batch_size);
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
output[i].*member = DecodeFromUnsignedToType<T>(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Same as above, but for optional fields.
|
||||
template <typename T,
|
||||
typename E,
|
||||
std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
void PopulateRtcEventMember(const rtc::ArrayView<uint8_t> positions,
|
||||
const rtc::ArrayView<uint64_t> values,
|
||||
absl::optional<T> E::*member,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = positions.size();
|
||||
RTC_CHECK_EQ(output.size(), batch_size);
|
||||
RTC_CHECK_LE(values.size(), batch_size);
|
||||
auto value_it = values.begin();
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
if (positions[i]) {
|
||||
RTC_CHECK(value_it != values.end());
|
||||
output[i].*member = DecodeFromUnsignedToType<T>(value_it);
|
||||
++value_it;
|
||||
} else {
|
||||
output[i].*member = absl::nullopt;
|
||||
}
|
||||
}
|
||||
RTC_CHECK(value_it == values.end());
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void PopulateRtcEventMember(const rtc::ArrayView<absl::string_view> values,
|
||||
std::string E::*member,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = values.size();
|
||||
RTC_CHECK_EQ(output.size(), batch_size);
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
output[i].*member = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void PopulateRtcEventTimestamp(const rtc::ArrayView<uint64_t>& values,
|
||||
Timestamp E::*timestamp,
|
||||
rtc::ArrayView<E> output) {
|
||||
size_t batch_size = values.size();
|
||||
RTC_CHECK_EQ(batch_size, output.size());
|
||||
for (size_t i = 0; i < batch_size; ++i) {
|
||||
output[i].*timestamp =
|
||||
Timestamp::Millis(DecodeFromUnsignedToType<int64_t>(values[i]));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
rtc::ArrayView<E> ExtendLoggedBatch(std::vector<E>& output,
|
||||
size_t new_elements) {
|
||||
size_t old_size = output.size();
|
||||
output.insert(output.end(), old_size + new_elements, E());
|
||||
rtc::ArrayView<E> output_batch = output;
|
||||
output_batch.subview(old_size);
|
||||
RTC_DCHECK_EQ(output_batch.size(), new_elements);
|
||||
return output_batch;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_EXTRACTION_H_
|
||||
|
|
|
@ -1425,7 +1425,14 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStreamInternalV3(
|
|||
case static_cast<uint32_t>(RtcEvent::Type::AlrStateEvent):
|
||||
RtcEventAlrState::Parse(event_fields, batched, alr_state_events_);
|
||||
break;
|
||||
// ADD NEW EVENTS HERE
|
||||
case static_cast<uint32_t>(RtcEvent::Type::AudioPlayout):
|
||||
RtcEventAudioPlayout::Parse(event_fields, batched,
|
||||
audio_playout_events_);
|
||||
break;
|
||||
case static_cast<uint32_t>(RtcEvent::Type::BweUpdateDelayBased):
|
||||
RtcEventBweUpdateDelayBased::Parse(event_fields, batched,
|
||||
bwe_delay_updates_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue