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:
Björn Terelius 2022-02-08 18:20:18 +01:00 committed by WebRTC LUCI CQ
parent 3ed36c0521
commit d12a14e21f
14 changed files with 350 additions and 150 deletions

View file

@ -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",
]
}

View file

@ -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(

View file

@ -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"

View file

@ -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)

View file

@ -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

View file

@ -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();
}

View file

@ -15,6 +15,12 @@
namespace webrtc {
constexpr RtcEventDefinition<RtcEventBweUpdateDelayBased,
LoggedBweDelayBasedUpdate,
int32_t,
BandwidthUsage>
RtcEventBweUpdateDelayBased::definition_;
RtcEventBweUpdateDelayBased::RtcEventBweUpdateDelayBased(
int32_t bitrate_bps,
BandwidthUsage detector_state)

View file

@ -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

View file

@ -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,
status = PopulateRtcEventTimestamp(result.value(), &LoggedType::timestamp,
output_batch);
if (!status.ok())
return status;
return fields_.ParseImpl(parser, output_batch);
return RtcEventLogParseStatus::Success();
}
private:

View file

@ -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();
}

View file

@ -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_

View file

@ -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_

View file

@ -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_

View file

@ -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;
}
}