webrtc/logging/rtc_event_log/rtc_event_log_parser_new.cc
Bjorn Terelius 59b4e3ea8c Split IceCandidatePairEventType enum.
Disjoint subsets of the enum values are used for Ice candidate config
events and Ice candidate check events. This CL breaks out the config
part to a separate enum and by extension changes the icelogger interface
for config events.

Bug: webrtc:9336, webrtc:8111
Change-Id: I405b5c3981905c3c504b45afdddb3649469ed141
Reviewed-on: https://webrtc-review.googlesource.com/79943
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23464}
2018-05-31 08:42:10 +00:00

1306 lines
50 KiB
C++

/*
* Copyright (c) 2016 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/rtc_event_log_parser_new.h"
#include <stdint.h>
#include <string.h>
#include <algorithm>
#include <fstream>
#include <istream> // no-presubmit-check TODO(webrtc:8982)
#include <limits>
#include <map>
#include <utility>
#include "api/rtp_headers.h"
#include "api/rtpparameters.h"
#include "logging/rtc_event_log/rtc_event_log.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/protobuf_utils.h"
#include "rtc_base/ptr_util.h"
namespace webrtc {
namespace {
RtcpMode GetRuntimeRtcpMode(rtclog::VideoReceiveConfig::RtcpMode rtcp_mode) {
switch (rtcp_mode) {
case rtclog::VideoReceiveConfig::RTCP_COMPOUND:
return RtcpMode::kCompound;
case rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE:
return RtcpMode::kReducedSize;
}
RTC_NOTREACHED();
return RtcpMode::kOff;
}
ParsedRtcEventLogNew::EventType GetRuntimeEventType(
rtclog::Event::EventType event_type) {
switch (event_type) {
case rtclog::Event::UNKNOWN_EVENT:
return ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT;
case rtclog::Event::LOG_START:
return ParsedRtcEventLogNew::EventType::LOG_START;
case rtclog::Event::LOG_END:
return ParsedRtcEventLogNew::EventType::LOG_END;
case rtclog::Event::RTP_EVENT:
return ParsedRtcEventLogNew::EventType::RTP_EVENT;
case rtclog::Event::RTCP_EVENT:
return ParsedRtcEventLogNew::EventType::RTCP_EVENT;
case rtclog::Event::AUDIO_PLAYOUT_EVENT:
return ParsedRtcEventLogNew::EventType::AUDIO_PLAYOUT_EVENT;
case rtclog::Event::LOSS_BASED_BWE_UPDATE:
return ParsedRtcEventLogNew::EventType::LOSS_BASED_BWE_UPDATE;
case rtclog::Event::DELAY_BASED_BWE_UPDATE:
return ParsedRtcEventLogNew::EventType::DELAY_BASED_BWE_UPDATE;
case rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT:
return ParsedRtcEventLogNew::EventType::VIDEO_RECEIVER_CONFIG_EVENT;
case rtclog::Event::VIDEO_SENDER_CONFIG_EVENT:
return ParsedRtcEventLogNew::EventType::VIDEO_SENDER_CONFIG_EVENT;
case rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT:
return ParsedRtcEventLogNew::EventType::AUDIO_RECEIVER_CONFIG_EVENT;
case rtclog::Event::AUDIO_SENDER_CONFIG_EVENT:
return ParsedRtcEventLogNew::EventType::AUDIO_SENDER_CONFIG_EVENT;
case rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT:
return ParsedRtcEventLogNew::EventType::AUDIO_NETWORK_ADAPTATION_EVENT;
case rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT:
return ParsedRtcEventLogNew::EventType::BWE_PROBE_CLUSTER_CREATED_EVENT;
case rtclog::Event::BWE_PROBE_RESULT_EVENT:
// Probe successes and failures are currently stored in the same proto
// message, we are moving towards separate messages. Probe results
// therefore need special treatment in the parser.
return ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT;
case rtclog::Event::ALR_STATE_EVENT:
return ParsedRtcEventLogNew::EventType::ALR_STATE_EVENT;
case rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG:
return ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_CONFIG;
case rtclog::Event::ICE_CANDIDATE_PAIR_EVENT:
return ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_EVENT;
}
return ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT;
}
BandwidthUsage GetRuntimeDetectorState(
rtclog::DelayBasedBweUpdate::DetectorState detector_state) {
switch (detector_state) {
case rtclog::DelayBasedBweUpdate::BWE_NORMAL:
return BandwidthUsage::kBwNormal;
case rtclog::DelayBasedBweUpdate::BWE_UNDERUSING:
return BandwidthUsage::kBwUnderusing;
case rtclog::DelayBasedBweUpdate::BWE_OVERUSING:
return BandwidthUsage::kBwOverusing;
}
RTC_NOTREACHED();
return BandwidthUsage::kBwNormal;
}
IceCandidatePairConfigType GetRuntimeIceCandidatePairConfigType(
rtclog::IceCandidatePairConfig::IceCandidatePairConfigType type) {
switch (type) {
case rtclog::IceCandidatePairConfig::ADDED:
return IceCandidatePairConfigType::kAdded;
case rtclog::IceCandidatePairConfig::UPDATED:
return IceCandidatePairConfigType::kUpdated;
case rtclog::IceCandidatePairConfig::DESTROYED:
return IceCandidatePairConfigType::kDestroyed;
case rtclog::IceCandidatePairConfig::SELECTED:
return IceCandidatePairConfigType::kSelected;
}
RTC_NOTREACHED();
return IceCandidatePairConfigType::kAdded;
}
IceCandidateType GetRuntimeIceCandidateType(
rtclog::IceCandidatePairConfig::IceCandidateType type) {
switch (type) {
case rtclog::IceCandidatePairConfig::LOCAL:
return IceCandidateType::kLocal;
case rtclog::IceCandidatePairConfig::STUN:
return IceCandidateType::kStun;
case rtclog::IceCandidatePairConfig::PRFLX:
return IceCandidateType::kPrflx;
case rtclog::IceCandidatePairConfig::RELAY:
return IceCandidateType::kRelay;
case rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE:
return IceCandidateType::kUnknown;
}
RTC_NOTREACHED();
return IceCandidateType::kUnknown;
}
IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol(
rtclog::IceCandidatePairConfig::Protocol protocol) {
switch (protocol) {
case rtclog::IceCandidatePairConfig::UDP:
return IceCandidatePairProtocol::kUdp;
case rtclog::IceCandidatePairConfig::TCP:
return IceCandidatePairProtocol::kTcp;
case rtclog::IceCandidatePairConfig::SSLTCP:
return IceCandidatePairProtocol::kSsltcp;
case rtclog::IceCandidatePairConfig::TLS:
return IceCandidatePairProtocol::kTls;
case rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL:
return IceCandidatePairProtocol::kUnknown;
}
RTC_NOTREACHED();
return IceCandidatePairProtocol::kUnknown;
}
IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily(
rtclog::IceCandidatePairConfig::AddressFamily address_family) {
switch (address_family) {
case rtclog::IceCandidatePairConfig::IPV4:
return IceCandidatePairAddressFamily::kIpv4;
case rtclog::IceCandidatePairConfig::IPV6:
return IceCandidatePairAddressFamily::kIpv6;
case rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY:
return IceCandidatePairAddressFamily::kUnknown;
}
RTC_NOTREACHED();
return IceCandidatePairAddressFamily::kUnknown;
}
IceCandidateNetworkType GetRuntimeIceCandidateNetworkType(
rtclog::IceCandidatePairConfig::NetworkType network_type) {
switch (network_type) {
case rtclog::IceCandidatePairConfig::ETHERNET:
return IceCandidateNetworkType::kEthernet;
case rtclog::IceCandidatePairConfig::LOOPBACK:
return IceCandidateNetworkType::kLoopback;
case rtclog::IceCandidatePairConfig::WIFI:
return IceCandidateNetworkType::kWifi;
case rtclog::IceCandidatePairConfig::VPN:
return IceCandidateNetworkType::kVpn;
case rtclog::IceCandidatePairConfig::CELLULAR:
return IceCandidateNetworkType::kCellular;
case rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE:
return IceCandidateNetworkType::kUnknown;
}
RTC_NOTREACHED();
return IceCandidateNetworkType::kUnknown;
}
IceCandidatePairEventType GetRuntimeIceCandidatePairEventType(
rtclog::IceCandidatePairEvent::IceCandidatePairEventType type) {
switch (type) {
case rtclog::IceCandidatePairEvent::CHECK_SENT:
return IceCandidatePairEventType::kCheckSent;
case rtclog::IceCandidatePairEvent::CHECK_RECEIVED:
return IceCandidatePairEventType::kCheckReceived;
case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT:
return IceCandidatePairEventType::kCheckResponseSent;
case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED:
return IceCandidatePairEventType::kCheckResponseReceived;
}
RTC_NOTREACHED();
return IceCandidatePairEventType::kCheckSent;
}
// Return default values for header extensions, to use on streams without stored
// mapping data. Currently this only applies to audio streams, since the mapping
// is not stored in the event log.
// TODO(ivoc): Remove this once this mapping is stored in the event log for
// audio streams. Tracking bug: webrtc:6399
webrtc::RtpHeaderExtensionMap GetDefaultHeaderExtensionMap() {
webrtc::RtpHeaderExtensionMap default_map;
default_map.Register<AudioLevel>(webrtc::RtpExtension::kAudioLevelDefaultId);
default_map.Register<TransmissionOffset>(
webrtc::RtpExtension::kTimestampOffsetDefaultId);
default_map.Register<AbsoluteSendTime>(
webrtc::RtpExtension::kAbsSendTimeDefaultId);
default_map.Register<VideoOrientation>(
webrtc::RtpExtension::kVideoRotationDefaultId);
default_map.Register<VideoContentTypeExtension>(
webrtc::RtpExtension::kVideoContentTypeDefaultId);
default_map.Register<VideoTimingExtension>(
webrtc::RtpExtension::kVideoTimingDefaultId);
default_map.Register<TransportSequenceNumber>(
webrtc::RtpExtension::kTransportSequenceNumberDefaultId);
default_map.Register<PlayoutDelayLimits>(
webrtc::RtpExtension::kPlayoutDelayDefaultId);
return default_map;
}
std::pair<uint64_t, bool> ParseVarInt(
std::istream& stream) { // no-presubmit-check TODO(webrtc:8982)
uint64_t varint = 0;
for (size_t bytes_read = 0; bytes_read < 10; ++bytes_read) {
// The most significant bit of each byte is 0 if it is the last byte in
// the varint and 1 otherwise. Thus, we take the 7 least significant bits
// of each byte and shift them 7 bits for each byte read previously to get
// the (unsigned) integer.
int byte = stream.get();
if (stream.eof()) {
return std::make_pair(varint, false);
}
RTC_DCHECK_GE(byte, 0);
RTC_DCHECK_LE(byte, 255);
varint |= static_cast<uint64_t>(byte & 0x7F) << (7 * bytes_read);
if ((byte & 0x80) == 0) {
return std::make_pair(varint, true);
}
}
return std::make_pair(varint, false);
}
void GetHeaderExtensions(std::vector<RtpExtension>* header_extensions,
const RepeatedPtrField<rtclog::RtpHeaderExtension>&
proto_header_extensions) {
header_extensions->clear();
for (auto& p : proto_header_extensions) {
RTC_CHECK(p.has_name());
RTC_CHECK(p.has_id());
const std::string& name = p.name();
int id = p.id();
header_extensions->push_back(RtpExtension(name, id));
}
}
} // namespace
ParsedRtcEventLogNew::ParsedRtcEventLogNew(
UnconfiguredHeaderExtensions parse_unconfigured_header_extensions)
: parse_unconfigured_header_extensions_(
parse_unconfigured_header_extensions) {
Clear();
}
void ParsedRtcEventLogNew::Clear() {
events_.clear();
default_extension_map_ = GetDefaultHeaderExtensionMap();
incoming_rtx_ssrcs_.clear();
incoming_video_ssrcs_.clear();
incoming_audio_ssrcs_.clear();
outgoing_rtx_ssrcs_.clear();
outgoing_video_ssrcs_.clear();
outgoing_audio_ssrcs_.clear();
incoming_rtp_packets_map_.clear();
outgoing_rtp_packets_map_.clear();
incoming_rtp_packets_by_ssrc_.clear();
outgoing_rtp_packets_by_ssrc_.clear();
incoming_rtp_packet_views_by_ssrc_.clear();
outgoing_rtp_packet_views_by_ssrc_.clear();
incoming_rtcp_packets_.clear();
outgoing_rtcp_packets_.clear();
incoming_rr_.clear();
outgoing_rr_.clear();
incoming_sr_.clear();
outgoing_sr_.clear();
incoming_nack_.clear();
outgoing_nack_.clear();
incoming_remb_.clear();
outgoing_remb_.clear();
incoming_transport_feedback_.clear();
outgoing_transport_feedback_.clear();
start_log_events_.clear();
stop_log_events_.clear();
audio_playout_events_.clear();
audio_network_adaptation_events_.clear();
bwe_probe_cluster_created_events_.clear();
bwe_probe_failure_events_.clear();
bwe_probe_success_events_.clear();
bwe_delay_updates_.clear();
bwe_loss_updates_.clear();
alr_state_events_.clear();
ice_candidate_pair_configs_.clear();
ice_candidate_pair_events_.clear();
audio_recv_configs_.clear();
audio_send_configs_.clear();
video_recv_configs_.clear();
video_send_configs_.clear();
memset(last_incoming_rtcp_packet_, 0, IP_PACKET_SIZE);
last_incoming_rtcp_packet_length_ = 0;
first_timestamp_ = std::numeric_limits<int64_t>::max();
last_timestamp_ = std::numeric_limits<int64_t>::min();
incoming_rtp_extensions_maps_.clear();
outgoing_rtp_extensions_maps_.clear();
}
bool ParsedRtcEventLogNew::ParseFile(const std::string& filename) {
std::ifstream file( // no-presubmit-check TODO(webrtc:8982)
filename, std::ios_base::in | std::ios_base::binary);
if (!file.good() || !file.is_open()) {
RTC_LOG(LS_WARNING) << "Could not open file for reading.";
return false;
}
return ParseStream(file);
}
bool ParsedRtcEventLogNew::ParseString(const std::string& s) {
std::istringstream stream( // no-presubmit-check TODO(webrtc:8982)
s, std::ios_base::in | std::ios_base::binary);
return ParseStream(stream);
}
bool ParsedRtcEventLogNew::ParseStream(
std::istream& stream) { // no-presubmit-check TODO(webrtc:8982)
Clear();
bool success = ParseStreamInternal(stream);
// ParseStreamInternal stores the RTP packets in a map indexed by SSRC.
// Since we dont need rapid lookup based on SSRC after parsing, we move the
// packets_streams from map to vector.
incoming_rtp_packets_by_ssrc_.reserve(incoming_rtp_packets_map_.size());
for (const auto& kv : incoming_rtp_packets_map_) {
incoming_rtp_packets_by_ssrc_.emplace_back(LoggedRtpStreamIncoming());
incoming_rtp_packets_by_ssrc_.back().ssrc = kv.first;
incoming_rtp_packets_by_ssrc_.back().incoming_packets =
std::move(kv.second);
}
incoming_rtp_packets_map_.clear();
outgoing_rtp_packets_by_ssrc_.reserve(outgoing_rtp_packets_map_.size());
for (const auto& kv : outgoing_rtp_packets_map_) {
outgoing_rtp_packets_by_ssrc_.emplace_back(LoggedRtpStreamOutgoing());
outgoing_rtp_packets_by_ssrc_.back().ssrc = kv.first;
outgoing_rtp_packets_by_ssrc_.back().outgoing_packets =
std::move(kv.second);
}
outgoing_rtp_packets_map_.clear();
// Build PacketViews for easier iteration over RTP packets
for (const auto& stream : incoming_rtp_packets_by_ssrc_) {
incoming_rtp_packet_views_by_ssrc_.emplace_back(
LoggedRtpStreamView(stream.ssrc, stream.incoming_packets.data(),
stream.incoming_packets.size()));
}
for (const auto& stream : outgoing_rtp_packets_by_ssrc_) {
outgoing_rtp_packet_views_by_ssrc_.emplace_back(
LoggedRtpStreamView(stream.ssrc, stream.outgoing_packets.data(),
stream.outgoing_packets.size()));
}
return success;
}
bool ParsedRtcEventLogNew::ParseStreamInternal(
std::istream& stream) { // no-presubmit-check TODO(webrtc:8982)
const size_t kMaxEventSize = (1u << 16) - 1;
std::vector<char> tmp_buffer(kMaxEventSize);
uint64_t tag;
uint64_t message_length;
bool success;
RTC_DCHECK(stream.good());
while (1) {
// Check whether we have reached end of file.
stream.peek();
if (stream.eof()) {
break;
}
// Read the next message tag. The tag number is defined as
// (fieldnumber << 3) | wire_type. In our case, the field number is
// supposed to be 1 and the wire type for an
// length-delimited field is 2.
const uint64_t kExpectedTag = (1 << 3) | 2;
std::tie(tag, success) = ParseVarInt(stream);
if (!success) {
RTC_LOG(LS_WARNING)
<< "Missing field tag from beginning of protobuf event.";
return false;
} else if (tag != kExpectedTag) {
RTC_LOG(LS_WARNING)
<< "Unexpected field tag at beginning of protobuf event.";
return false;
}
// Read the length field.
std::tie(message_length, success) = ParseVarInt(stream);
if (!success) {
RTC_LOG(LS_WARNING) << "Missing message length after protobuf field tag.";
return false;
} else if (message_length > kMaxEventSize) {
RTC_LOG(LS_WARNING) << "Protobuf message length is too large.";
return false;
}
// Read the next protobuf event to a temporary char buffer.
stream.read(tmp_buffer.data(), message_length);
if (stream.gcount() != static_cast<int>(message_length)) {
RTC_LOG(LS_WARNING) << "Failed to read protobuf message from file.";
return false;
}
// Parse the protobuf event from the buffer.
rtclog::Event event;
if (!event.ParseFromArray(tmp_buffer.data(), message_length)) {
RTC_LOG(LS_WARNING) << "Failed to parse protobuf message.";
return false;
}
StoreParsedEvent(event);
events_.push_back(event);
}
return true;
}
void ParsedRtcEventLogNew::StoreParsedEvent(const rtclog::Event& event) {
if (event.type() != rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT &&
event.type() != rtclog::Event::VIDEO_SENDER_CONFIG_EVENT &&
event.type() != rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT &&
event.type() != rtclog::Event::AUDIO_SENDER_CONFIG_EVENT &&
event.type() != rtclog::Event::LOG_START &&
event.type() != rtclog::Event::LOG_END) {
RTC_CHECK(event.has_timestamp_us());
int64_t timestamp = event.timestamp_us();
first_timestamp_ = std::min(first_timestamp_, timestamp);
last_timestamp_ = std::max(last_timestamp_, timestamp);
}
switch (GetEventType(event)) {
case ParsedRtcEventLogNew::EventType::VIDEO_RECEIVER_CONFIG_EVENT: {
rtclog::StreamConfig config = GetVideoReceiveConfig(event);
video_recv_configs_.emplace_back(GetTimestamp(event), config);
incoming_rtp_extensions_maps_[config.remote_ssrc] =
RtpHeaderExtensionMap(config.rtp_extensions);
// TODO(terelius): I don't understand the reason for configuring header
// extensions for the local SSRC. I think it should be removed, but for
// now I want to preserve the previous functionality.
incoming_rtp_extensions_maps_[config.local_ssrc] =
RtpHeaderExtensionMap(config.rtp_extensions);
incoming_video_ssrcs_.insert(config.remote_ssrc);
incoming_video_ssrcs_.insert(config.rtx_ssrc);
incoming_rtx_ssrcs_.insert(config.rtx_ssrc);
break;
}
case ParsedRtcEventLogNew::EventType::VIDEO_SENDER_CONFIG_EVENT: {
std::vector<rtclog::StreamConfig> configs = GetVideoSendConfig(event);
video_send_configs_.emplace_back(GetTimestamp(event), configs);
for (const auto& config : configs) {
outgoing_rtp_extensions_maps_[config.local_ssrc] =
RtpHeaderExtensionMap(config.rtp_extensions);
outgoing_rtp_extensions_maps_[config.rtx_ssrc] =
RtpHeaderExtensionMap(config.rtp_extensions);
outgoing_video_ssrcs_.insert(config.local_ssrc);
outgoing_video_ssrcs_.insert(config.rtx_ssrc);
outgoing_rtx_ssrcs_.insert(config.rtx_ssrc);
}
break;
}
case ParsedRtcEventLogNew::EventType::AUDIO_RECEIVER_CONFIG_EVENT: {
rtclog::StreamConfig config = GetAudioReceiveConfig(event);
audio_recv_configs_.emplace_back(GetTimestamp(event), config);
incoming_rtp_extensions_maps_[config.remote_ssrc] =
RtpHeaderExtensionMap(config.rtp_extensions);
incoming_rtp_extensions_maps_[config.local_ssrc] =
RtpHeaderExtensionMap(config.rtp_extensions);
incoming_audio_ssrcs_.insert(config.remote_ssrc);
break;
}
case ParsedRtcEventLogNew::EventType::AUDIO_SENDER_CONFIG_EVENT: {
rtclog::StreamConfig config = GetAudioSendConfig(event);
audio_send_configs_.emplace_back(GetTimestamp(event), config);
outgoing_rtp_extensions_maps_[config.local_ssrc] =
RtpHeaderExtensionMap(config.rtp_extensions);
outgoing_audio_ssrcs_.insert(config.local_ssrc);
break;
}
case ParsedRtcEventLogNew::EventType::RTP_EVENT: {
PacketDirection direction;
uint8_t header[IP_PACKET_SIZE];
size_t header_length;
size_t total_length;
const RtpHeaderExtensionMap* extension_map = GetRtpHeader(
event, &direction, header, &header_length, &total_length, nullptr);
RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
RTPHeader parsed_header;
if (extension_map != nullptr) {
rtp_parser.Parse(&parsed_header, extension_map);
} else {
// Use the default extension map.
// TODO(ivoc): Once configuration of audio streams is stored in the
// event log, this can be removed.
// Tracking bug: webrtc:6399
rtp_parser.Parse(&parsed_header, &default_extension_map_);
}
RTC_CHECK(event.has_timestamp_us());
uint64_t timestamp_us = event.timestamp_us();
if (direction == kIncomingPacket) {
incoming_rtp_packets_map_[parsed_header.ssrc].push_back(
LoggedRtpPacketIncoming(timestamp_us, parsed_header, header_length,
total_length));
} else {
outgoing_rtp_packets_map_[parsed_header.ssrc].push_back(
LoggedRtpPacketOutgoing(timestamp_us, parsed_header, header_length,
total_length));
}
break;
}
case ParsedRtcEventLogNew::EventType::RTCP_EVENT: {
PacketDirection direction;
uint8_t packet[IP_PACKET_SIZE];
size_t total_length;
GetRtcpPacket(event, &direction, packet, &total_length);
uint64_t timestamp_us = GetTimestamp(event);
RTC_CHECK_LE(total_length, IP_PACKET_SIZE);
if (direction == kIncomingPacket) {
// Currently incoming RTCP packets are logged twice, both for audio and
// video. Only act on one of them. Compare against the previous parsed
// incoming RTCP packet.
if (total_length == last_incoming_rtcp_packet_length_ &&
memcmp(last_incoming_rtcp_packet_, packet, total_length) == 0)
break;
incoming_rtcp_packets_.push_back(
LoggedRtcpPacketIncoming(timestamp_us, packet, total_length));
last_incoming_rtcp_packet_length_ = total_length;
memcpy(last_incoming_rtcp_packet_, packet, total_length);
} else {
outgoing_rtcp_packets_.push_back(
LoggedRtcpPacketOutgoing(timestamp_us, packet, total_length));
}
rtcp::CommonHeader header;
const uint8_t* packet_end = packet + total_length;
for (const uint8_t* block = packet; block < packet_end;
block = header.NextPacket()) {
RTC_CHECK(header.Parse(block, packet_end - block));
if (header.type() == rtcp::TransportFeedback::kPacketType &&
header.fmt() == rtcp::TransportFeedback::kFeedbackMessageType) {
if (direction == kIncomingPacket) {
incoming_transport_feedback_.emplace_back();
LoggedRtcpPacketTransportFeedback& parsed_block =
incoming_transport_feedback_.back();
parsed_block.timestamp_us = GetTimestamp(event);
if (!parsed_block.transport_feedback.Parse(header))
incoming_transport_feedback_.pop_back();
} else {
outgoing_transport_feedback_.emplace_back();
LoggedRtcpPacketTransportFeedback& parsed_block =
outgoing_transport_feedback_.back();
parsed_block.timestamp_us = GetTimestamp(event);
if (!parsed_block.transport_feedback.Parse(header))
outgoing_transport_feedback_.pop_back();
}
} else if (header.type() == rtcp::SenderReport::kPacketType) {
LoggedRtcpPacketSenderReport parsed_block;
parsed_block.timestamp_us = GetTimestamp(event);
if (parsed_block.sr.Parse(header)) {
if (direction == kIncomingPacket)
incoming_sr_.push_back(std::move(parsed_block));
else
outgoing_sr_.push_back(std::move(parsed_block));
}
} else if (header.type() == rtcp::ReceiverReport::kPacketType) {
LoggedRtcpPacketReceiverReport parsed_block;
parsed_block.timestamp_us = GetTimestamp(event);
if (parsed_block.rr.Parse(header)) {
if (direction == kIncomingPacket)
incoming_rr_.push_back(std::move(parsed_block));
else
outgoing_rr_.push_back(std::move(parsed_block));
}
} else if (header.type() == rtcp::Remb::kPacketType &&
header.fmt() == rtcp::Remb::kFeedbackMessageType) {
LoggedRtcpPacketRemb parsed_block;
parsed_block.timestamp_us = GetTimestamp(event);
if (parsed_block.remb.Parse(header)) {
if (direction == kIncomingPacket)
incoming_remb_.push_back(std::move(parsed_block));
else
outgoing_remb_.push_back(std::move(parsed_block));
}
} else if (header.type() == rtcp::Nack::kPacketType &&
header.fmt() == rtcp::Nack::kFeedbackMessageType) {
LoggedRtcpPacketNack parsed_block;
parsed_block.timestamp_us = GetTimestamp(event);
if (parsed_block.nack.Parse(header)) {
if (direction == kIncomingPacket)
incoming_nack_.push_back(std::move(parsed_block));
else
outgoing_nack_.push_back(std::move(parsed_block));
}
}
}
break;
}
case ParsedRtcEventLogNew::EventType::LOG_START: {
start_log_events_.push_back(LoggedStartEvent(GetTimestamp(event)));
break;
}
case ParsedRtcEventLogNew::EventType::LOG_END: {
stop_log_events_.push_back(LoggedStopEvent(GetTimestamp(event)));
break;
}
case ParsedRtcEventLogNew::EventType::AUDIO_PLAYOUT_EVENT: {
LoggedAudioPlayoutEvent playout_event = GetAudioPlayout(event);
audio_playout_events_[playout_event.ssrc].push_back(playout_event);
break;
}
case ParsedRtcEventLogNew::EventType::LOSS_BASED_BWE_UPDATE: {
bwe_loss_updates_.push_back(GetLossBasedBweUpdate(event));
break;
}
case ParsedRtcEventLogNew::EventType::DELAY_BASED_BWE_UPDATE: {
bwe_delay_updates_.push_back(GetDelayBasedBweUpdate(event));
break;
}
case ParsedRtcEventLogNew::EventType::AUDIO_NETWORK_ADAPTATION_EVENT: {
LoggedAudioNetworkAdaptationEvent ana_event =
GetAudioNetworkAdaptation(event);
audio_network_adaptation_events_.push_back(ana_event);
break;
}
case ParsedRtcEventLogNew::EventType::BWE_PROBE_CLUSTER_CREATED_EVENT: {
bwe_probe_cluster_created_events_.push_back(
GetBweProbeClusterCreated(event));
break;
}
case ParsedRtcEventLogNew::EventType::BWE_PROBE_FAILURE_EVENT: {
bwe_probe_failure_events_.push_back(GetBweProbeFailure(event));
break;
}
case ParsedRtcEventLogNew::EventType::BWE_PROBE_SUCCESS_EVENT: {
bwe_probe_success_events_.push_back(GetBweProbeSuccess(event));
break;
}
case ParsedRtcEventLogNew::EventType::ALR_STATE_EVENT: {
alr_state_events_.push_back(GetAlrState(event));
break;
}
case ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_CONFIG: {
ice_candidate_pair_configs_.push_back(GetIceCandidatePairConfig(event));
break;
}
case ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_EVENT: {
ice_candidate_pair_events_.push_back(GetIceCandidatePairEvent(event));
break;
}
case ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT: {
break;
}
}
}
size_t ParsedRtcEventLogNew::GetNumberOfEvents() const {
return events_.size();
}
int64_t ParsedRtcEventLogNew::GetTimestamp(size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetTimestamp(event);
}
int64_t ParsedRtcEventLogNew::GetTimestamp(const rtclog::Event& event) const {
RTC_CHECK(event.has_timestamp_us());
return event.timestamp_us();
}
ParsedRtcEventLogNew::EventType ParsedRtcEventLogNew::GetEventType(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetEventType(event);
}
ParsedRtcEventLogNew::EventType ParsedRtcEventLogNew::GetEventType(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
if (event.type() == rtclog::Event::BWE_PROBE_RESULT_EVENT) {
RTC_CHECK(event.has_probe_result());
RTC_CHECK(event.probe_result().has_result());
if (event.probe_result().result() == rtclog::BweProbeResult::SUCCESS)
return ParsedRtcEventLogNew::EventType::BWE_PROBE_SUCCESS_EVENT;
return ParsedRtcEventLogNew::EventType::BWE_PROBE_FAILURE_EVENT;
}
return GetRuntimeEventType(event.type());
}
// The header must have space for at least IP_PACKET_SIZE bytes.
const webrtc::RtpHeaderExtensionMap* ParsedRtcEventLogNew::GetRtpHeader(
size_t index,
PacketDirection* incoming,
uint8_t* header,
size_t* header_length,
size_t* total_length,
int* probe_cluster_id) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetRtpHeader(event, incoming, header, header_length, total_length,
probe_cluster_id);
}
const webrtc::RtpHeaderExtensionMap* ParsedRtcEventLogNew::GetRtpHeader(
const rtclog::Event& event,
PacketDirection* incoming,
uint8_t* header,
size_t* header_length,
size_t* total_length,
int* probe_cluster_id) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::RTP_EVENT);
RTC_CHECK(event.has_rtp_packet());
const rtclog::RtpPacket& rtp_packet = event.rtp_packet();
// Get direction of packet.
RTC_CHECK(rtp_packet.has_incoming());
if (incoming != nullptr) {
*incoming = rtp_packet.incoming() ? kIncomingPacket : kOutgoingPacket;
}
// Get packet length.
RTC_CHECK(rtp_packet.has_packet_length());
if (total_length != nullptr) {
*total_length = rtp_packet.packet_length();
}
// Get header length.
RTC_CHECK(rtp_packet.has_header());
if (header_length != nullptr) {
*header_length = rtp_packet.header().size();
}
if (probe_cluster_id != nullptr) {
if (rtp_packet.has_probe_cluster_id()) {
*probe_cluster_id = rtp_packet.probe_cluster_id();
RTC_CHECK_NE(*probe_cluster_id, PacedPacketInfo::kNotAProbe);
} else {
*probe_cluster_id = PacedPacketInfo::kNotAProbe;
}
}
// Get header contents.
if (header != nullptr) {
const size_t kMinRtpHeaderSize = 12;
RTC_CHECK_GE(rtp_packet.header().size(), kMinRtpHeaderSize);
RTC_CHECK_LE(rtp_packet.header().size(),
static_cast<size_t>(IP_PACKET_SIZE));
memcpy(header, rtp_packet.header().data(), rtp_packet.header().size());
uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(header + 8);
auto& extensions_maps = rtp_packet.incoming()
? incoming_rtp_extensions_maps_
: outgoing_rtp_extensions_maps_;
auto it = extensions_maps.find(ssrc);
if (it != extensions_maps.end()) {
return &(it->second);
}
if (parse_unconfigured_header_extensions_ ==
UnconfiguredHeaderExtensions::kAttemptWebrtcDefaultConfig) {
RTC_LOG(LS_WARNING) << "Using default header extension map for SSRC "
<< ssrc;
extensions_maps.insert(std::make_pair(ssrc, default_extension_map_));
return &default_extension_map_;
}
}
return nullptr;
}
// The packet must have space for at least IP_PACKET_SIZE bytes.
void ParsedRtcEventLogNew::GetRtcpPacket(size_t index,
PacketDirection* incoming,
uint8_t* packet,
size_t* length) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
GetRtcpPacket(event, incoming, packet, length);
}
void ParsedRtcEventLogNew::GetRtcpPacket(const rtclog::Event& event,
PacketDirection* incoming,
uint8_t* packet,
size_t* length) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::RTCP_EVENT);
RTC_CHECK(event.has_rtcp_packet());
const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet();
// Get direction of packet.
RTC_CHECK(rtcp_packet.has_incoming());
if (incoming != nullptr) {
*incoming = rtcp_packet.incoming() ? kIncomingPacket : kOutgoingPacket;
}
// Get packet length.
RTC_CHECK(rtcp_packet.has_packet_data());
if (length != nullptr) {
*length = rtcp_packet.packet_data().size();
}
// Get packet contents.
if (packet != nullptr) {
RTC_CHECK_LE(rtcp_packet.packet_data().size(),
static_cast<unsigned>(IP_PACKET_SIZE));
memcpy(packet, rtcp_packet.packet_data().data(),
rtcp_packet.packet_data().size());
}
}
rtclog::StreamConfig ParsedRtcEventLogNew::GetVideoReceiveConfig(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
return GetVideoReceiveConfig(events_[index]);
}
rtclog::StreamConfig ParsedRtcEventLogNew::GetVideoReceiveConfig(
const rtclog::Event& event) const {
rtclog::StreamConfig config;
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT);
RTC_CHECK(event.has_video_receiver_config());
const rtclog::VideoReceiveConfig& receiver_config =
event.video_receiver_config();
// Get SSRCs.
RTC_CHECK(receiver_config.has_remote_ssrc());
config.remote_ssrc = receiver_config.remote_ssrc();
RTC_CHECK(receiver_config.has_local_ssrc());
config.local_ssrc = receiver_config.local_ssrc();
config.rtx_ssrc = 0;
// Get RTCP settings.
RTC_CHECK(receiver_config.has_rtcp_mode());
config.rtcp_mode = GetRuntimeRtcpMode(receiver_config.rtcp_mode());
RTC_CHECK(receiver_config.has_remb());
config.remb = receiver_config.remb();
// Get RTX map.
std::map<uint32_t, const rtclog::RtxConfig> rtx_map;
for (int i = 0; i < receiver_config.rtx_map_size(); i++) {
const rtclog::RtxMap& map = receiver_config.rtx_map(i);
RTC_CHECK(map.has_payload_type());
RTC_CHECK(map.has_config());
RTC_CHECK(map.config().has_rtx_ssrc());
RTC_CHECK(map.config().has_rtx_payload_type());
rtx_map.insert(std::make_pair(map.payload_type(), map.config()));
}
// Get header extensions.
GetHeaderExtensions(&config.rtp_extensions,
receiver_config.header_extensions());
// Get decoders.
config.codecs.clear();
for (int i = 0; i < receiver_config.decoders_size(); i++) {
RTC_CHECK(receiver_config.decoders(i).has_name());
RTC_CHECK(receiver_config.decoders(i).has_payload_type());
int rtx_payload_type = 0;
auto rtx_it = rtx_map.find(receiver_config.decoders(i).payload_type());
if (rtx_it != rtx_map.end()) {
rtx_payload_type = rtx_it->second.rtx_payload_type();
if (config.rtx_ssrc != 0 &&
config.rtx_ssrc != rtx_it->second.rtx_ssrc()) {
RTC_LOG(LS_WARNING)
<< "RtcEventLog protobuf contained different SSRCs for "
"different received RTX payload types. Will only use "
"rtx_ssrc = "
<< config.rtx_ssrc << ".";
} else {
config.rtx_ssrc = rtx_it->second.rtx_ssrc();
}
}
config.codecs.emplace_back(receiver_config.decoders(i).name(),
receiver_config.decoders(i).payload_type(),
rtx_payload_type);
}
return config;
}
std::vector<rtclog::StreamConfig> ParsedRtcEventLogNew::GetVideoSendConfig(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
return GetVideoSendConfig(events_[index]);
}
std::vector<rtclog::StreamConfig> ParsedRtcEventLogNew::GetVideoSendConfig(
const rtclog::Event& event) const {
std::vector<rtclog::StreamConfig> configs;
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_SENDER_CONFIG_EVENT);
RTC_CHECK(event.has_video_sender_config());
const rtclog::VideoSendConfig& sender_config = event.video_sender_config();
if (sender_config.rtx_ssrcs_size() > 0 &&
sender_config.ssrcs_size() != sender_config.rtx_ssrcs_size()) {
RTC_LOG(WARNING)
<< "VideoSendConfig is configured for RTX but the number of "
"SSRCs doesn't match the number of RTX SSRCs.";
}
configs.resize(sender_config.ssrcs_size());
for (int i = 0; i < sender_config.ssrcs_size(); i++) {
// Get SSRCs.
configs[i].local_ssrc = sender_config.ssrcs(i);
if (sender_config.rtx_ssrcs_size() > 0 &&
i < sender_config.rtx_ssrcs_size()) {
RTC_CHECK(sender_config.has_rtx_payload_type());
configs[i].rtx_ssrc = sender_config.rtx_ssrcs(i);
}
// Get header extensions.
GetHeaderExtensions(&configs[i].rtp_extensions,
sender_config.header_extensions());
// Get the codec.
RTC_CHECK(sender_config.has_encoder());
RTC_CHECK(sender_config.encoder().has_name());
RTC_CHECK(sender_config.encoder().has_payload_type());
configs[i].codecs.emplace_back(
sender_config.encoder().name(), sender_config.encoder().payload_type(),
sender_config.has_rtx_payload_type() ? sender_config.rtx_payload_type()
: 0);
}
return configs;
}
rtclog::StreamConfig ParsedRtcEventLogNew::GetAudioReceiveConfig(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
return GetAudioReceiveConfig(events_[index]);
}
rtclog::StreamConfig ParsedRtcEventLogNew::GetAudioReceiveConfig(
const rtclog::Event& event) const {
rtclog::StreamConfig config;
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT);
RTC_CHECK(event.has_audio_receiver_config());
const rtclog::AudioReceiveConfig& receiver_config =
event.audio_receiver_config();
// Get SSRCs.
RTC_CHECK(receiver_config.has_remote_ssrc());
config.remote_ssrc = receiver_config.remote_ssrc();
RTC_CHECK(receiver_config.has_local_ssrc());
config.local_ssrc = receiver_config.local_ssrc();
// Get header extensions.
GetHeaderExtensions(&config.rtp_extensions,
receiver_config.header_extensions());
return config;
}
rtclog::StreamConfig ParsedRtcEventLogNew::GetAudioSendConfig(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
return GetAudioSendConfig(events_[index]);
}
rtclog::StreamConfig ParsedRtcEventLogNew::GetAudioSendConfig(
const rtclog::Event& event) const {
rtclog::StreamConfig config;
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_SENDER_CONFIG_EVENT);
RTC_CHECK(event.has_audio_sender_config());
const rtclog::AudioSendConfig& sender_config = event.audio_sender_config();
// Get SSRCs.
RTC_CHECK(sender_config.has_ssrc());
config.local_ssrc = sender_config.ssrc();
// Get header extensions.
GetHeaderExtensions(&config.rtp_extensions,
sender_config.header_extensions());
return config;
}
LoggedAudioPlayoutEvent ParsedRtcEventLogNew::GetAudioPlayout(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetAudioPlayout(event);
}
LoggedAudioPlayoutEvent ParsedRtcEventLogNew::GetAudioPlayout(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_PLAYOUT_EVENT);
RTC_CHECK(event.has_audio_playout_event());
const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event();
LoggedAudioPlayoutEvent res;
res.timestamp_us = GetTimestamp(event);
RTC_CHECK(playout_event.has_local_ssrc());
res.ssrc = playout_event.local_ssrc();
return res;
}
LoggedBweLossBasedUpdate ParsedRtcEventLogNew::GetLossBasedBweUpdate(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetLossBasedBweUpdate(event);
}
LoggedBweLossBasedUpdate ParsedRtcEventLogNew::GetLossBasedBweUpdate(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::LOSS_BASED_BWE_UPDATE);
RTC_CHECK(event.has_loss_based_bwe_update());
const rtclog::LossBasedBweUpdate& loss_event = event.loss_based_bwe_update();
LoggedBweLossBasedUpdate bwe_update;
bwe_update.timestamp_us = GetTimestamp(event);
RTC_CHECK(loss_event.has_bitrate_bps());
bwe_update.bitrate_bps = loss_event.bitrate_bps();
RTC_CHECK(loss_event.has_fraction_loss());
bwe_update.fraction_lost = loss_event.fraction_loss();
RTC_CHECK(loss_event.has_total_packets());
bwe_update.expected_packets = loss_event.total_packets();
return bwe_update;
}
LoggedBweDelayBasedUpdate ParsedRtcEventLogNew::GetDelayBasedBweUpdate(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetDelayBasedBweUpdate(event);
}
LoggedBweDelayBasedUpdate ParsedRtcEventLogNew::GetDelayBasedBweUpdate(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::DELAY_BASED_BWE_UPDATE);
RTC_CHECK(event.has_delay_based_bwe_update());
const rtclog::DelayBasedBweUpdate& delay_event =
event.delay_based_bwe_update();
LoggedBweDelayBasedUpdate res;
res.timestamp_us = GetTimestamp(event);
RTC_CHECK(delay_event.has_bitrate_bps());
res.bitrate_bps = delay_event.bitrate_bps();
RTC_CHECK(delay_event.has_detector_state());
res.detector_state = GetRuntimeDetectorState(delay_event.detector_state());
return res;
}
LoggedAudioNetworkAdaptationEvent
ParsedRtcEventLogNew::GetAudioNetworkAdaptation(size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetAudioNetworkAdaptation(event);
}
LoggedAudioNetworkAdaptationEvent
ParsedRtcEventLogNew::GetAudioNetworkAdaptation(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT);
RTC_CHECK(event.has_audio_network_adaptation());
const rtclog::AudioNetworkAdaptation& ana_event =
event.audio_network_adaptation();
LoggedAudioNetworkAdaptationEvent res;
res.timestamp_us = GetTimestamp(event);
if (ana_event.has_bitrate_bps())
res.config.bitrate_bps = ana_event.bitrate_bps();
if (ana_event.has_enable_fec())
res.config.enable_fec = ana_event.enable_fec();
if (ana_event.has_enable_dtx())
res.config.enable_dtx = ana_event.enable_dtx();
if (ana_event.has_frame_length_ms())
res.config.frame_length_ms = ana_event.frame_length_ms();
if (ana_event.has_num_channels())
res.config.num_channels = ana_event.num_channels();
if (ana_event.has_uplink_packet_loss_fraction())
res.config.uplink_packet_loss_fraction =
ana_event.uplink_packet_loss_fraction();
return res;
}
LoggedBweProbeClusterCreatedEvent
ParsedRtcEventLogNew::GetBweProbeClusterCreated(size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetBweProbeClusterCreated(event);
}
LoggedBweProbeClusterCreatedEvent
ParsedRtcEventLogNew::GetBweProbeClusterCreated(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT);
RTC_CHECK(event.has_probe_cluster());
const rtclog::BweProbeCluster& pcc_event = event.probe_cluster();
LoggedBweProbeClusterCreatedEvent res;
res.timestamp_us = GetTimestamp(event);
RTC_CHECK(pcc_event.has_id());
res.id = pcc_event.id();
RTC_CHECK(pcc_event.has_bitrate_bps());
res.bitrate_bps = pcc_event.bitrate_bps();
RTC_CHECK(pcc_event.has_min_packets());
res.min_packets = pcc_event.min_packets();
RTC_CHECK(pcc_event.has_min_bytes());
res.min_bytes = pcc_event.min_bytes();
return res;
}
LoggedBweProbeFailureEvent ParsedRtcEventLogNew::GetBweProbeFailure(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetBweProbeFailure(event);
}
LoggedBweProbeFailureEvent ParsedRtcEventLogNew::GetBweProbeFailure(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PROBE_RESULT_EVENT);
RTC_CHECK(event.has_probe_result());
const rtclog::BweProbeResult& pr_event = event.probe_result();
RTC_CHECK(pr_event.has_result());
RTC_CHECK_NE(pr_event.result(), rtclog::BweProbeResult::SUCCESS);
LoggedBweProbeFailureEvent res;
res.timestamp_us = GetTimestamp(event);
RTC_CHECK(pr_event.has_id());
res.id = pr_event.id();
RTC_CHECK(pr_event.has_result());
if (pr_event.result() ==
rtclog::BweProbeResult::INVALID_SEND_RECEIVE_INTERVAL) {
res.failure_reason = ProbeFailureReason::kInvalidSendReceiveInterval;
} else if (pr_event.result() ==
rtclog::BweProbeResult::INVALID_SEND_RECEIVE_RATIO) {
res.failure_reason = ProbeFailureReason::kInvalidSendReceiveRatio;
} else if (pr_event.result() == rtclog::BweProbeResult::TIMEOUT) {
res.failure_reason = ProbeFailureReason::kTimeout;
} else {
RTC_NOTREACHED();
}
RTC_CHECK(!pr_event.has_bitrate_bps());
return res;
}
LoggedBweProbeSuccessEvent ParsedRtcEventLogNew::GetBweProbeSuccess(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetBweProbeSuccess(event);
}
LoggedBweProbeSuccessEvent ParsedRtcEventLogNew::GetBweProbeSuccess(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PROBE_RESULT_EVENT);
RTC_CHECK(event.has_probe_result());
const rtclog::BweProbeResult& pr_event = event.probe_result();
RTC_CHECK(pr_event.has_result());
RTC_CHECK_EQ(pr_event.result(), rtclog::BweProbeResult::SUCCESS);
LoggedBweProbeSuccessEvent res;
res.timestamp_us = GetTimestamp(event);
RTC_CHECK(pr_event.has_id());
res.id = pr_event.id();
RTC_CHECK(pr_event.has_bitrate_bps());
res.bitrate_bps = pr_event.bitrate_bps();
return res;
}
LoggedAlrStateEvent ParsedRtcEventLogNew::GetAlrState(size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& event = events_[index];
return GetAlrState(event);
}
LoggedAlrStateEvent ParsedRtcEventLogNew::GetAlrState(
const rtclog::Event& event) const {
RTC_CHECK(event.has_type());
RTC_CHECK_EQ(event.type(), rtclog::Event::ALR_STATE_EVENT);
RTC_CHECK(event.has_alr_state());
const rtclog::AlrState& alr_event = event.alr_state();
LoggedAlrStateEvent res;
res.timestamp_us = GetTimestamp(event);
RTC_CHECK(alr_event.has_in_alr());
res.in_alr = alr_event.in_alr();
return res;
}
LoggedIceCandidatePairConfig ParsedRtcEventLogNew::GetIceCandidatePairConfig(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& rtc_event = events_[index];
return GetIceCandidatePairConfig(rtc_event);
}
LoggedIceCandidatePairConfig ParsedRtcEventLogNew::GetIceCandidatePairConfig(
const rtclog::Event& rtc_event) const {
RTC_CHECK(rtc_event.has_type());
RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG);
LoggedIceCandidatePairConfig res;
const rtclog::IceCandidatePairConfig& config =
rtc_event.ice_candidate_pair_config();
res.timestamp_us = GetTimestamp(rtc_event);
RTC_CHECK(config.has_config_type());
res.type = GetRuntimeIceCandidatePairConfigType(config.config_type());
RTC_CHECK(config.has_candidate_pair_id());
res.candidate_pair_id = config.candidate_pair_id();
RTC_CHECK(config.has_local_candidate_type());
res.local_candidate_type =
GetRuntimeIceCandidateType(config.local_candidate_type());
RTC_CHECK(config.has_local_relay_protocol());
res.local_relay_protocol =
GetRuntimeIceCandidatePairProtocol(config.local_relay_protocol());
RTC_CHECK(config.has_local_network_type());
res.local_network_type =
GetRuntimeIceCandidateNetworkType(config.local_network_type());
RTC_CHECK(config.has_local_address_family());
res.local_address_family =
GetRuntimeIceCandidatePairAddressFamily(config.local_address_family());
RTC_CHECK(config.has_remote_candidate_type());
res.remote_candidate_type =
GetRuntimeIceCandidateType(config.remote_candidate_type());
RTC_CHECK(config.has_remote_address_family());
res.remote_address_family =
GetRuntimeIceCandidatePairAddressFamily(config.remote_address_family());
RTC_CHECK(config.has_candidate_pair_protocol());
res.candidate_pair_protocol =
GetRuntimeIceCandidatePairProtocol(config.candidate_pair_protocol());
return res;
}
LoggedIceCandidatePairEvent ParsedRtcEventLogNew::GetIceCandidatePairEvent(
size_t index) const {
RTC_CHECK_LT(index, GetNumberOfEvents());
const rtclog::Event& rtc_event = events_[index];
return GetIceCandidatePairEvent(rtc_event);
}
LoggedIceCandidatePairEvent ParsedRtcEventLogNew::GetIceCandidatePairEvent(
const rtclog::Event& rtc_event) const {
RTC_CHECK(rtc_event.has_type());
RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_EVENT);
LoggedIceCandidatePairEvent res;
const rtclog::IceCandidatePairEvent& event =
rtc_event.ice_candidate_pair_event();
res.timestamp_us = GetTimestamp(rtc_event);
RTC_CHECK(event.has_event_type());
res.type = GetRuntimeIceCandidatePairEventType(event.event_type());
RTC_CHECK(event.has_candidate_pair_id());
res.candidate_pair_id = event.candidate_pair_id();
return res;
}
// Returns the MediaType for registered SSRCs. Search from the end to use last
// registered types first.
ParsedRtcEventLogNew::MediaType ParsedRtcEventLogNew::GetMediaType(
uint32_t ssrc,
PacketDirection direction) const {
if (direction == kIncomingPacket) {
if (std::find(incoming_video_ssrcs_.begin(), incoming_video_ssrcs_.end(),
ssrc) != incoming_video_ssrcs_.end()) {
return MediaType::VIDEO;
}
if (std::find(incoming_audio_ssrcs_.begin(), incoming_audio_ssrcs_.end(),
ssrc) != incoming_audio_ssrcs_.end()) {
return MediaType::AUDIO;
}
} else {
if (std::find(outgoing_video_ssrcs_.begin(), outgoing_video_ssrcs_.end(),
ssrc) != outgoing_video_ssrcs_.end()) {
return MediaType::VIDEO;
}
if (std::find(outgoing_audio_ssrcs_.begin(), outgoing_audio_ssrcs_.end(),
ssrc) != outgoing_audio_ssrcs_.end()) {
return MediaType::AUDIO;
}
}
return MediaType::ANY;
}
} // namespace webrtc