diff --git a/logging/BUILD.gn b/logging/BUILD.gn index edfef156aa..385a35dde9 100644 --- a/logging/BUILD.gn +++ b/logging/BUILD.gn @@ -154,6 +154,7 @@ rtc_static_library("rtc_event_log_impl_encoder") { defines = [] deps = [ + ":ice_log", ":rtc_event_audio", ":rtc_event_bwe", ":rtc_event_log_api", @@ -206,6 +207,7 @@ rtc_static_library("rtc_event_log_impl_base") { defines = [] deps = [ + ":ice_log", ":rtc_event_log_api", ":rtc_event_log_impl_encoder", ":rtc_event_log_impl_output", @@ -243,6 +245,7 @@ if (rtc_enable_protobuf) { ] deps = [ + ":ice_log", ":rtc_event_bwe", ":rtc_event_log2_proto", ":rtc_event_log_api", @@ -380,6 +383,23 @@ if (rtc_enable_protobuf) { } } +rtc_source_set("ice_log") { + sources = [ + "rtc_event_log/events/rtc_event_ice_candidate_pair.cc", + "rtc_event_log/events/rtc_event_ice_candidate_pair.h", + "rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc", + "rtc_event_log/events/rtc_event_ice_candidate_pair_config.h", + "rtc_event_log/icelogger.cc", + "rtc_event_log/icelogger.h", + ] + + deps = [ + ":rtc_event_log_api", + "../api:libjingle_logging_api", + "../rtc_base:rtc_base_approved", + ] +} + if (rtc_include_tests) { rtc_source_set("mocks") { testonly = true diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc index 1f02bccbaf..9ebdcbc985 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc @@ -17,6 +17,8 @@ #include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h" #include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h" #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" #include "logging/rtc_event_log/events/rtc_event_probe_result_success.h" @@ -103,6 +105,122 @@ rtclog::VideoReceiveConfig_RtcpMode ConvertRtcpMode(RtcpMode rtcp_mode) { RTC_NOTREACHED(); return rtclog::VideoReceiveConfig::RTCP_COMPOUND; } + +rtclog::IceCandidatePairConfig::IceCandidatePairConfigType +ConvertIceCandidatePairConfigType(IceCandidatePairEventType type) { + switch (type) { + case IceCandidatePairEventType::kAdded: + return rtclog::IceCandidatePairConfig::ADDED; + case IceCandidatePairEventType::kUpdated: + return rtclog::IceCandidatePairConfig::UPDATED; + case IceCandidatePairEventType::kDestroyed: + return rtclog::IceCandidatePairConfig::DESTROYED; + case IceCandidatePairEventType::kSelected: + return rtclog::IceCandidatePairConfig::SELECTED; + default: + RTC_NOTREACHED(); + } + RTC_NOTREACHED(); + return rtclog::IceCandidatePairConfig::ADDED; +} + +rtclog::IceCandidatePairConfig::IceCandidateType ConvertIceCandidateType( + IceCandidateType type) { + switch (type) { + case IceCandidateType::kLocal: + return rtclog::IceCandidatePairConfig::LOCAL; + case IceCandidateType::kStun: + return rtclog::IceCandidatePairConfig::STUN; + case IceCandidateType::kPrflx: + return rtclog::IceCandidatePairConfig::PRFLX; + case IceCandidateType::kRelay: + return rtclog::IceCandidatePairConfig::RELAY; + case IceCandidateType::kUnknown: + return rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE; + default: + RTC_NOTREACHED(); + } + RTC_NOTREACHED(); + return rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE; +} + +rtclog::IceCandidatePairConfig::Protocol ConvertIceCandidatePairProtocol( + IceCandidatePairProtocol protocol) { + switch (protocol) { + case IceCandidatePairProtocol::kUdp: + return rtclog::IceCandidatePairConfig::UDP; + case IceCandidatePairProtocol::kTcp: + return rtclog::IceCandidatePairConfig::TCP; + case IceCandidatePairProtocol::kSsltcp: + return rtclog::IceCandidatePairConfig::SSLTCP; + case IceCandidatePairProtocol::kTls: + return rtclog::IceCandidatePairConfig::TLS; + case IceCandidatePairProtocol::kUnknown: + return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL; + default: + RTC_NOTREACHED(); + } + RTC_NOTREACHED(); + return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL; +} + +rtclog::IceCandidatePairConfig::AddressFamily +ConvertIceCandidatePairAddressFamily( + IceCandidatePairAddressFamily address_family) { + switch (address_family) { + case IceCandidatePairAddressFamily::kIpv4: + return rtclog::IceCandidatePairConfig::IPV4; + case IceCandidatePairAddressFamily::kIpv6: + return rtclog::IceCandidatePairConfig::IPV6; + case IceCandidatePairAddressFamily::kUnknown: + return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY; + default: + RTC_NOTREACHED(); + } + RTC_NOTREACHED(); + return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY; +} + +rtclog::IceCandidatePairConfig::NetworkType ConvertIceCandidateNetworkType( + IceCandidateNetworkType network_type) { + switch (network_type) { + case IceCandidateNetworkType::kEthernet: + return rtclog::IceCandidatePairConfig::ETHERNET; + case IceCandidateNetworkType::kLoopback: + return rtclog::IceCandidatePairConfig::LOOPBACK; + case IceCandidateNetworkType::kWifi: + return rtclog::IceCandidatePairConfig::WIFI; + case IceCandidateNetworkType::kVpn: + return rtclog::IceCandidatePairConfig::VPN; + case IceCandidateNetworkType::kCellular: + return rtclog::IceCandidatePairConfig::CELLULAR; + case IceCandidateNetworkType::kUnknown: + return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE; + default: + RTC_NOTREACHED(); + } + RTC_NOTREACHED(); + return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE; +} + +rtclog::IceCandidatePairEvent::IceCandidatePairEventType +ConvertIceCandidatePairEventType(IceCandidatePairEventType type) { + switch (type) { + case IceCandidatePairEventType::kCheckSent: + return rtclog::IceCandidatePairEvent::CHECK_SENT; + case IceCandidatePairEventType::kCheckReceived: + return rtclog::IceCandidatePairEvent::CHECK_RECEIVED; + case IceCandidatePairEventType::kCheckResponseSent: + return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT; + case IceCandidatePairEventType::kCheckResponseReceived: + return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED; + default: + RTC_NOTREACHED(); + } + RTC_NOTREACHED(); + return rtclog::IceCandidatePairEvent::CHECK_SENT; +} + } // namespace std::string RtcEventLogEncoderLegacy::EncodeLogStart(int64_t timestamp_us) { @@ -171,6 +289,17 @@ std::string RtcEventLogEncoderLegacy::Encode(const RtcEvent& event) { return EncodeBweUpdateLossBased(rtc_event); } + case RtcEvent::Type::IceCandidatePairConfig: { + auto& rtc_event = + static_cast(event); + return EncodeIceCandidatePairConfig(rtc_event); + } + + case RtcEvent::Type::IceCandidatePairEvent: { + auto& rtc_event = static_cast(event); + return EncodeIceCandidatePairEvent(rtc_event); + } + case RtcEvent::Type::ProbeClusterCreated: { auto& rtc_event = static_cast(event); return EncodeProbeClusterCreated(rtc_event); @@ -343,6 +472,48 @@ std::string RtcEventLogEncoderLegacy::EncodeBweUpdateLossBased( return Serialize(&rtclog_event); } +std::string RtcEventLogEncoderLegacy::EncodeIceCandidatePairConfig( + const RtcEventIceCandidatePairConfig& event) { + rtclog::Event encoded_rtc_event; + encoded_rtc_event.set_timestamp_us(event.timestamp_us_); + encoded_rtc_event.set_type(rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG); + + auto encoded_ice_event = + encoded_rtc_event.mutable_ice_candidate_pair_config(); + encoded_ice_event->set_config_type( + ConvertIceCandidatePairConfigType(event.type_)); + encoded_ice_event->set_candidate_pair_id(event.candidate_pair_id_); + const auto& desc = event.candidate_pair_desc_; + encoded_ice_event->set_local_candidate_type( + ConvertIceCandidateType(desc.local_candidate_type)); + encoded_ice_event->set_local_relay_protocol( + ConvertIceCandidatePairProtocol(desc.local_relay_protocol)); + encoded_ice_event->set_local_network_type( + ConvertIceCandidateNetworkType(desc.local_network_type)); + encoded_ice_event->set_local_address_family( + ConvertIceCandidatePairAddressFamily(desc.local_address_family)); + encoded_ice_event->set_remote_candidate_type( + ConvertIceCandidateType(desc.remote_candidate_type)); + encoded_ice_event->set_remote_address_family( + ConvertIceCandidatePairAddressFamily(desc.remote_address_family)); + encoded_ice_event->set_candidate_pair_protocol( + ConvertIceCandidatePairProtocol(desc.candidate_pair_protocol)); + return Serialize(&encoded_rtc_event); +} + +std::string RtcEventLogEncoderLegacy::EncodeIceCandidatePairEvent( + const RtcEventIceCandidatePair& event) { + rtclog::Event encoded_rtc_event; + encoded_rtc_event.set_timestamp_us(event.timestamp_us_); + encoded_rtc_event.set_type(rtclog::Event::ICE_CANDIDATE_PAIR_EVENT); + + auto encoded_ice_event = encoded_rtc_event.mutable_ice_candidate_pair_event(); + encoded_ice_event->set_event_type( + ConvertIceCandidatePairEventType(event.type_)); + encoded_ice_event->set_candidate_pair_id(event.candidate_pair_id_); + return Serialize(&encoded_rtc_event); +} + std::string RtcEventLogEncoderLegacy::EncodeProbeClusterCreated( const RtcEventProbeClusterCreated& event) { rtclog::Event rtclog_event; diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h index 63102c502a..87db039e3a 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h @@ -32,6 +32,8 @@ class RtcEventAudioReceiveStreamConfig; class RtcEventAudioSendStreamConfig; class RtcEventBweUpdateDelayBased; class RtcEventBweUpdateLossBased; +class RtcEventIceCandidatePairConfig; +class RtcEventIceCandidatePair; class RtcEventLoggingStarted; class RtcEventLoggingStopped; class RtcEventProbeClusterCreated; @@ -71,6 +73,10 @@ class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder { std::string EncodeBweUpdateDelayBased( const RtcEventBweUpdateDelayBased& event); std::string EncodeBweUpdateLossBased(const RtcEventBweUpdateLossBased& event); + std::string EncodeIceCandidatePairConfig( + const RtcEventIceCandidatePairConfig& event); + std::string EncodeIceCandidatePairEvent( + const RtcEventIceCandidatePair& event); std::string EncodeProbeClusterCreated( const RtcEventProbeClusterCreated& event); std::string EncodeProbeResultFailure(const RtcEventProbeResultFailure& event); diff --git a/logging/rtc_event_log/events/rtc_event.h b/logging/rtc_event_log/events/rtc_event.h index 6410698673..25820ef8dc 100644 --- a/logging/rtc_event_log/events/rtc_event.h +++ b/logging/rtc_event_log/events/rtc_event.h @@ -37,6 +37,8 @@ class RtcEvent { AudioSendStreamConfig, BweUpdateDelayBased, BweUpdateLossBased, + IceCandidatePairConfig, + IceCandidatePairEvent, ProbeClusterCreated, ProbeResultFailure, ProbeResultSuccess, diff --git a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc new file mode 100644 index 0000000000..b3d084e51c --- /dev/null +++ b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" + +namespace webrtc { + +RtcEventIceCandidatePair::RtcEventIceCandidatePair( + IceCandidatePairEventType type, + uint32_t candidate_pair_id) + : type_(type), candidate_pair_id_(candidate_pair_id) {} + +RtcEventIceCandidatePair::~RtcEventIceCandidatePair() = default; + +RtcEvent::Type RtcEventIceCandidatePair::GetType() const { + return RtcEvent::Type::IceCandidatePairEvent; +} + +bool RtcEventIceCandidatePair::IsConfigEvent() const { + return false; +} + +} // namespace webrtc diff --git a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h new file mode 100644 index 0000000000..b6cd61f48b --- /dev/null +++ b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_H_ +#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_H_ + +#include "logging/rtc_event_log/events/rtc_event.h" + +#include + +namespace webrtc { + +enum class IceCandidatePairEventType { + // Config event types for events related to the candiate pair creation and + // life-cycle management. + kAdded, + kUpdated, + kDestroyed, + kSelected, + // Non-config event types. + kCheckSent, + kCheckReceived, + kCheckResponseSent, + kCheckResponseReceived, +}; + +class RtcEventIceCandidatePair final : public RtcEvent { + public: + RtcEventIceCandidatePair(IceCandidatePairEventType type, + uint32_t candidate_pair_id); + + ~RtcEventIceCandidatePair() override; + + Type GetType() const override; + + bool IsConfigEvent() const override; + + const IceCandidatePairEventType type_; + const uint32_t candidate_pair_id_; +}; + +} // namespace webrtc + +#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_H_ diff --git a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc new file mode 100644 index 0000000000..33fd8c7751 --- /dev/null +++ b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" + +namespace webrtc { + +IceCandidatePairDescription::IceCandidatePairDescription() { + local_candidate_type = IceCandidateType::kUnknown; + local_relay_protocol = IceCandidatePairProtocol::kUnknown; + local_network_type = IceCandidateNetworkType::kUnknown; + local_address_family = IceCandidatePairAddressFamily::kUnknown; + remote_candidate_type = IceCandidateType::kUnknown; + remote_address_family = IceCandidatePairAddressFamily::kUnknown; + candidate_pair_protocol = IceCandidatePairProtocol::kUnknown; +} + +IceCandidatePairDescription::IceCandidatePairDescription( + const IceCandidatePairDescription& other) { + local_candidate_type = other.local_candidate_type; + local_relay_protocol = other.local_relay_protocol; + local_network_type = other.local_network_type; + local_address_family = other.local_address_family; + remote_candidate_type = other.remote_candidate_type; + remote_address_family = other.remote_address_family; + candidate_pair_protocol = other.candidate_pair_protocol; +} + +IceCandidatePairDescription::~IceCandidatePairDescription() {} + +RtcEventIceCandidatePairConfig::RtcEventIceCandidatePairConfig( + IceCandidatePairEventType type, + uint32_t candidate_pair_id, + const IceCandidatePairDescription& candidate_pair_desc) + : type_(type), + candidate_pair_id_(candidate_pair_id), + candidate_pair_desc_(candidate_pair_desc) {} + +RtcEventIceCandidatePairConfig::~RtcEventIceCandidatePairConfig() = default; + +RtcEvent::Type RtcEventIceCandidatePairConfig::GetType() const { + return RtcEvent::Type::IceCandidatePairConfig; +} + +// The ICE candidate pair config event is not equivalent to a RtcEventLog config +// event. +bool RtcEventIceCandidatePairConfig::IsConfigEvent() const { + return false; +} + +} // namespace webrtc diff --git a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h new file mode 100644 index 0000000000..70c81bf820 --- /dev/null +++ b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_CONFIG_H_ +#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_CONFIG_H_ + +#include "logging/rtc_event_log/events/rtc_event.h" + +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" + +#include + +namespace webrtc { + +// TODO(qingsi): Change the names of candidate types to "host", "srflx", "prflx" +// and "relay" after the naming is spec-compliant in the signaling part +enum class IceCandidateType { + kLocal, + kStun, + kPrflx, + kRelay, + kUnknown, +}; + +enum class IceCandidatePairProtocol { + kUdp, + kTcp, + kSsltcp, + kTls, + kUnknown, +}; + +enum class IceCandidatePairAddressFamily { + kIpv4, + kIpv6, + kUnknown, +}; + +enum class IceCandidateNetworkType { + kEthernet, + kLoopback, + kWifi, + kVpn, + kCellular, + kUnknown, +}; + +class IceCandidatePairDescription { + public: + IceCandidatePairDescription(); + explicit IceCandidatePairDescription( + const IceCandidatePairDescription& other); + + ~IceCandidatePairDescription(); + + IceCandidateType local_candidate_type; + IceCandidatePairProtocol local_relay_protocol; + IceCandidateNetworkType local_network_type; + IceCandidatePairAddressFamily local_address_family; + IceCandidateType remote_candidate_type; + IceCandidatePairAddressFamily remote_address_family; + IceCandidatePairProtocol candidate_pair_protocol; +}; + +class RtcEventIceCandidatePairConfig final : public RtcEvent { + public: + RtcEventIceCandidatePairConfig( + IceCandidatePairEventType type, + uint32_t candidate_pair_id, + const IceCandidatePairDescription& candidate_pair_desc); + + ~RtcEventIceCandidatePairConfig() override; + + Type GetType() const override; + + bool IsConfigEvent() const override; + + const IceCandidatePairEventType type_; + const uint32_t candidate_pair_id_; + const IceCandidatePairDescription candidate_pair_desc_; +}; + +} // namespace webrtc + +#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_CONFIG_H_ diff --git a/logging/rtc_event_log/icelogger.cc b/logging/rtc_event_log/icelogger.cc new file mode 100644 index 0000000000..108f966519 --- /dev/null +++ b/logging/rtc_event_log/icelogger.cc @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "logging/rtc_event_log/icelogger.h" + +#include "logging/rtc_event_log/rtc_event_log.h" +#include "rtc_base/ptr_util.h" + +namespace webrtc { + +IceEventLog::IceEventLog() {} +IceEventLog::~IceEventLog() {} + +bool IceEventLog::IsIceCandidatePairConfigEvent( + IceCandidatePairEventType type) { + return (type == IceCandidatePairEventType::kAdded) || + (type == IceCandidatePairEventType::kUpdated) || + (type == IceCandidatePairEventType::kDestroyed) || + (type == IceCandidatePairEventType::kSelected); +} + +void IceEventLog::LogCandidatePairEvent( + IceCandidatePairEventType type, + uint32_t candidate_pair_id, + const IceCandidatePairDescription& candidate_pair_desc) { + if (event_log_ == nullptr) { + return; + } + if (IsIceCandidatePairConfigEvent(type)) { + candidate_pair_desc_by_id_[candidate_pair_id] = candidate_pair_desc; + event_log_->Log(rtc::MakeUnique( + type, candidate_pair_id, candidate_pair_desc)); + return; + } + event_log_->Log( + rtc::MakeUnique(type, candidate_pair_id)); +} + +void IceEventLog::DumpCandidatePairDescriptionToMemoryAsConfigEvents() const { + for (const auto& desc_id_pair : candidate_pair_desc_by_id_) { + event_log_->Log(rtc::MakeUnique( + IceCandidatePairEventType::kUpdated, desc_id_pair.first, + desc_id_pair.second)); + } +} + +} // namespace webrtc diff --git a/logging/rtc_event_log/icelogger.h b/logging/rtc_event_log/icelogger.h new file mode 100644 index 0000000000..b3689c7c10 --- /dev/null +++ b/logging/rtc_event_log/icelogger.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef LOGGING_RTC_EVENT_LOG_ICELOGGER_H_ +#define LOGGING_RTC_EVENT_LOG_ICELOGGER_H_ + +#include + +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" + +namespace webrtc { + +class RtcEventLog; + +// IceEventLog wraps RtcEventLog and provides structural logging of ICE-specific +// events. The logged events are serialized with other RtcEvent's if protobuf is +// enabled in the build. +class IceEventLog { + public: + IceEventLog(); + ~IceEventLog(); + void set_event_log(RtcEventLog* event_log) { event_log_ = event_log; } + void LogCandidatePairEvent( + IceCandidatePairEventType type, + uint32_t candidate_pair_id, + const IceCandidatePairDescription& candidate_pair_desc); + // This method constructs a config event for each candidate pair with their + // description and logs these config events. It is intended to be called when + // logging starts to ensure that we have at least one config for each + // candidate pair id. + void DumpCandidatePairDescriptionToMemoryAsConfigEvents() const; + + private: + bool IsIceCandidatePairConfigEvent(IceCandidatePairEventType type); + + RtcEventLog* event_log_ = nullptr; + std::unordered_map + candidate_pair_desc_by_id_; +}; + +} // namespace webrtc + +#endif // LOGGING_RTC_EVENT_LOG_ICELOGGER_H_ diff --git a/logging/rtc_event_log/null_rtc_event_log.cc b/logging/rtc_event_log/null_rtc_event_log.cc new file mode 100644 index 0000000000..a1ee020125 --- /dev/null +++ b/logging/rtc_event_log/null_rtc_event_log.cc @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "logging/rtc_event_log/rtc_event_log.h" + +namespace webrtc { + +bool RtcEventLogNullImpl::StartLogging( + std::unique_ptr output, + int64_t output_period_ms) { + return false; +} + +} // namespace webrtc diff --git a/logging/rtc_event_log/rtc_event_log.proto b/logging/rtc_event_log/rtc_event_log.proto index 8d2e22a6f8..bfac4f60dc 100644 --- a/logging/rtc_event_log/rtc_event_log.proto +++ b/logging/rtc_event_log/rtc_event_log.proto @@ -41,6 +41,8 @@ message Event { BWE_PROBE_CLUSTER_CREATED_EVENT = 17; BWE_PROBE_RESULT_EVENT = 18; ALR_STATE_EVENT = 19; + ICE_CANDIDATE_PAIR_CONFIG = 20; + ICE_CANDIDATE_PAIR_EVENT = 21; } // required - Indicates the type of this event @@ -85,6 +87,12 @@ message Event { // required if type == ALR_STATE_EVENT AlrState alr_state = 19; + + // required if type == ICE_CANDIDATE_PAIR_CONFIG + IceCandidatePairConfig ice_candidate_pair_config = 20; + + // required if type == ICE_CANDIDATE_PAIR_EVENT + IceCandidatePairEvent ice_candidate_pair_event = 21; } } @@ -323,3 +331,85 @@ message AlrState { // required - If we are in ALR or not. optional bool in_alr = 1; } + +message IceCandidatePairConfig { + enum IceCandidatePairConfigType { + ADDED = 0; + UPDATED = 1; + DESTROYED = 2; + SELECTED = 3; + } + + enum IceCandidateType { + LOCAL = 0; + STUN = 1; + PRFLX = 2; + RELAY = 3; + UNKNOWN_CANDIDATE_TYPE = 4; + } + + enum Protocol { + UDP = 0; + TCP = 1; + SSLTCP = 2; + TLS = 3; + UNKNOWN_PROTOCOL = 4; + } + + enum AddressFamily { + IPV4 = 0; + IPV6 = 1; + UNKNOWN_ADDRESS_FAMILY = 2; + } + + enum NetworkType { + ETHERNET = 0; + LOOPBACK = 1; + WIFI = 2; + VPN = 3; + CELLULAR = 4; + UNKNOWN_NETWORK_TYPE = 5; + } + + // required + optional IceCandidatePairConfigType config_type = 1; + + // required + optional uint32 candidate_pair_id = 2; + + // required + optional IceCandidateType local_candidate_type = 3; + + // required + optional Protocol local_relay_protocol = 4; + + // required + optional NetworkType local_network_type = 5; + + // required + optional AddressFamily local_address_family = 6; + + // required + optional IceCandidateType remote_candidate_type = 7; + + // required + optional AddressFamily remote_address_family = 8; + + // required + optional Protocol candidate_pair_protocol = 9; +} + +message IceCandidatePairEvent { + enum IceCandidatePairEventType { + CHECK_SENT = 0; + CHECK_RECEIVED = 1; + CHECK_RESPONSE_SENT = 2; + CHECK_RESPONSE_RECEIVED = 3; + } + + // required + optional IceCandidatePairEventType event_type = 1; + + // required + optional uint32 candidate_pair_id = 2; +} diff --git a/logging/rtc_event_log/rtc_event_log2stats.cc b/logging/rtc_event_log/rtc_event_log2stats.cc index f38322d5bd..6b0c4c0222 100644 --- a/logging/rtc_event_log/rtc_event_log2stats.cc +++ b/logging/rtc_event_log/rtc_event_log2stats.cc @@ -166,6 +166,10 @@ std::string EventTypeToString(webrtc::rtclog::Event::EventType event_type) { return "BWE_PROBE_RESULT"; case webrtc::rtclog::Event::ALR_STATE_EVENT: return "ALR_STATE_EVENT"; + case webrtc::rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG: + return "ICE_CANDIDATE_PAIR_CONFIG"; + case webrtc::rtclog::Event::ICE_CANDIDATE_PAIR_EVENT: + return "ICE_CANDIDATE_PAIR_EVENT"; } RTC_NOTREACHED(); return "UNKNOWN_EVENT"; diff --git a/logging/rtc_event_log/rtc_event_log2text.cc b/logging/rtc_event_log/rtc_event_log2text.cc index 42ff732430..c71a2b8023 100644 --- a/logging/rtc_event_log/rtc_event_log2text.cc +++ b/logging/rtc_event_log/rtc_event_log2text.cc @@ -60,6 +60,7 @@ DEFINE_bool(rtcp, true, "Use --nortcp to exclude RTCP packets."); DEFINE_bool(playout, true, "Use --noplayout to exclude audio playout events."); DEFINE_bool(ana, true, "Use --noana to exclude ANA events."); DEFINE_bool(probe, true, "Use --noprobe to exclude probe events."); +DEFINE_bool(ice, true, "Use --noice to exclude ICE events."); DEFINE_bool(print_full_packets, false, @@ -796,6 +797,34 @@ int main(int argc, char* argv[]) { event_recognized = true; break; } + + case webrtc::ParsedRtcEventLog::ICE_CANDIDATE_PAIR_CONFIG: { + if (FLAG_ice) { + webrtc::ParsedRtcEventLog::IceCandidatePairConfig ice_cp_config = + parsed_stream.GetIceCandidatePairConfig(i); + // TODO(qingsi): convert the numeric representation of states to text + std::cout << parsed_stream.GetTimestamp(i) + << "\tICE_CANDIDATE_PAIR_CONFIG" + << "\ttype=" << static_cast(ice_cp_config.type) + << std::endl; + } + event_recognized = true; + break; + } + + case webrtc::ParsedRtcEventLog::ICE_CANDIDATE_PAIR_EVENT: { + if (FLAG_ice) { + webrtc::ParsedRtcEventLog::IceCandidatePairEvent ice_cp_event = + parsed_stream.GetIceCandidatePairEvent(i); + // TODO(qingsi): convert the numeric representation of states to text + std::cout << parsed_stream.GetTimestamp(i) + << "\tICE_CANDIDATE_PAIR_EVENT" + << "\ttype=" << static_cast(ice_cp_event.type) + << std::endl; + } + event_recognized = true; + break; + } } if (!event_recognized) { diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc index 194da57b6d..69789287ba 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.cc +++ b/logging/rtc_event_log/rtc_event_log_parser.cc @@ -76,6 +76,10 @@ ParsedRtcEventLog::EventType GetRuntimeEventType( return ParsedRtcEventLog::EventType::BWE_PROBE_RESULT_EVENT; case rtclog::Event::ALR_STATE_EVENT: return ParsedRtcEventLog::EventType::ALR_STATE_EVENT; + case rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG: + return ParsedRtcEventLog::EventType::ICE_CANDIDATE_PAIR_CONFIG; + case rtclog::Event::ICE_CANDIDATE_PAIR_EVENT: + return ParsedRtcEventLog::EventType::ICE_CANDIDATE_PAIR_EVENT; } return ParsedRtcEventLog::EventType::UNKNOWN_EVENT; } @@ -94,6 +98,108 @@ BandwidthUsage GetRuntimeDetectorState( return BandwidthUsage::kBwNormal; } +IceCandidatePairEventType GetRuntimeIceCandidatePairConfigType( + rtclog::IceCandidatePairConfig::IceCandidatePairConfigType type) { + switch (type) { + case rtclog::IceCandidatePairConfig::ADDED: + return IceCandidatePairEventType::kAdded; + case rtclog::IceCandidatePairConfig::UPDATED: + return IceCandidatePairEventType::kUpdated; + case rtclog::IceCandidatePairConfig::DESTROYED: + return IceCandidatePairEventType::kDestroyed; + case rtclog::IceCandidatePairConfig::SELECTED: + return IceCandidatePairEventType::kSelected; + } + RTC_NOTREACHED(); + return IceCandidatePairEventType::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; +} + std::pair ParseVarInt(std::istream& stream) { uint64_t varint = 0; for (size_t bytes_read = 0; bytes_read < 10; ++bytes_read) { @@ -670,6 +776,61 @@ ParsedRtcEventLog::AlrStateEvent ParsedRtcEventLog::GetAlrState( return res; } +ParsedRtcEventLog::IceCandidatePairConfig +ParsedRtcEventLog::GetIceCandidatePairConfig(size_t index) const { + RTC_CHECK_LT(index, GetNumberOfEvents()); + const rtclog::Event& rtc_event = events_[index]; + RTC_CHECK(rtc_event.has_type()); + RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG); + IceCandidatePairConfig res; + const rtclog::IceCandidatePairConfig& config = + rtc_event.ice_candidate_pair_config(); + res.timestamp = GetTimestamp(index); + 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; +} + +ParsedRtcEventLog::IceCandidatePairEvent +ParsedRtcEventLog::GetIceCandidatePairEvent(size_t index) const { + RTC_CHECK_LT(index, GetNumberOfEvents()); + const rtclog::Event& rtc_event = events_[index]; + RTC_CHECK(rtc_event.has_type()); + RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_EVENT); + IceCandidatePairEvent res; + const rtclog::IceCandidatePairEvent& event = + rtc_event.ice_candidate_pair_event(); + res.timestamp = GetTimestamp(index); + 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. ParsedRtcEventLog::MediaType ParsedRtcEventLog::GetMediaType( diff --git a/logging/rtc_event_log/rtc_event_log_parser.h b/logging/rtc_event_log/rtc_event_log_parser.h index 6438918774..d4488bc449 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.h +++ b/logging/rtc_event_log/rtc_event_log_parser.h @@ -17,6 +17,8 @@ #include "call/video_receive_stream.h" #include "call/video_send_stream.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" #include "logging/rtc_event_log/rtc_event_log.h" #include "logging/rtc_event_log/rtc_stream_config.h" @@ -70,6 +72,25 @@ class ParsedRtcEventLog { bool in_alr; }; + struct IceCandidatePairConfig { + uint64_t timestamp; + IceCandidatePairEventType type; + uint32_t candidate_pair_id; + IceCandidateType local_candidate_type; + IceCandidatePairProtocol local_relay_protocol; + IceCandidateNetworkType local_network_type; + IceCandidatePairAddressFamily local_address_family; + IceCandidateType remote_candidate_type; + IceCandidatePairAddressFamily remote_address_family; + IceCandidatePairProtocol candidate_pair_protocol; + }; + + struct IceCandidatePairEvent { + uint64_t timestamp; + IceCandidatePairEventType type; + uint32_t candidate_pair_id; + }; + enum EventType { UNKNOWN_EVENT = 0, LOG_START = 1, @@ -86,7 +107,9 @@ class ParsedRtcEventLog { AUDIO_NETWORK_ADAPTATION_EVENT = 16, BWE_PROBE_CLUSTER_CREATED_EVENT = 17, BWE_PROBE_RESULT_EVENT = 18, - ALR_STATE_EVENT = 19 + ALR_STATE_EVENT = 19, + ICE_CANDIDATE_PAIR_CONFIG = 20, + ICE_CANDIDATE_PAIR_EVENT = 21, }; enum class MediaType { ANY, AUDIO, VIDEO, DATA }; @@ -188,6 +211,9 @@ class ParsedRtcEventLog { AlrStateEvent GetAlrState(size_t index) const; + IceCandidatePairConfig GetIceCandidatePairConfig(size_t index) const; + IceCandidatePairEvent GetIceCandidatePairEvent(size_t index) const; + private: rtclog::StreamConfig GetVideoReceiveConfig(const rtclog::Event& event) const; std::vector GetVideoSendConfig( diff --git a/rtc_tools/event_log_visualizer/analyzer.cc b/rtc_tools/event_log_visualizer/analyzer.cc index 3c6a074a0d..2bbb09cbc8 100644 --- a/rtc_tools/event_log_visualizer/analyzer.cc +++ b/rtc_tools/event_log_visualizer/analyzer.cc @@ -62,6 +62,8 @@ namespace plotting { namespace { +const int kNumMicrosecsPerSec = 1000000; + void SortPacketFeedbackVector(std::vector* vec) { auto pred = [](const PacketFeedback& packet_feedback) { return packet_feedback.arrival_time_ms == PacketFeedback::kNotReceived; @@ -88,9 +90,10 @@ bool MatchingSsrc(uint32_t ssrc, const std::vector& desired_ssrc) { double AbsSendTimeToMicroseconds(int64_t abs_send_time) { // The timestamp is a fixed point representation with 6 bits for seconds // and 18 bits for fractions of a second. Thus, we divide by 2^18 to get the - // time in seconds and then multiply by 1000000 to convert to microseconds. + // time in seconds and then multiply by kNumMicrosecsPerSec to convert to + // microseconds. static constexpr double kTimestampToMicroSec = - 1000000.0 / static_cast(1ul << 18); + static_cast(kNumMicrosecsPerSec) / static_cast(1ul << 18); return abs_send_time * kTimestampToMicroSec; } @@ -193,7 +196,9 @@ rtc::Optional NetworkDelayDiff_CaptureTime( RTC_LOG(LS_WARNING) << "New capture time " << new_packet.header.timestamp << ", received time " << new_packet.timestamp; RTC_LOG(LS_WARNING) << "Receive time difference " << recv_time_diff << " = " - << static_cast(recv_time_diff) / 1000000 << "s"; + << static_cast(recv_time_diff) / + kNumMicrosecsPerSec + << "s"; RTC_LOG(LS_WARNING) << "Send time difference " << send_time_diff << " = " << static_cast(send_time_diff) / kVideoSampleRate @@ -211,7 +216,8 @@ void ProcessPoints( uint64_t begin_time, TimeSeries* result) { for (size_t i = 0; i < data.size(); i++) { - float x = static_cast(data[i].timestamp - begin_time) / 1000000; + float x = static_cast(data[i].timestamp - begin_time) / + kNumMicrosecsPerSec; rtc::Optional y = get_y(data[i]); if (y) result->points.emplace_back(x, *y); @@ -229,7 +235,8 @@ void ProcessPairs( uint64_t begin_time, TimeSeries* result) { for (size_t i = 1; i < data.size(); i++) { - float x = static_cast(data[i].timestamp - begin_time) / 1000000; + float x = static_cast(data[i].timestamp - begin_time) / + kNumMicrosecsPerSec; rtc::Optional y = get_y(data[i - 1], data[i]); if (y) result->points.emplace_back(x, static_cast(*y)); @@ -246,7 +253,8 @@ void AccumulatePoints( TimeSeries* result) { ResultType sum = 0; for (size_t i = 0; i < data.size(); i++) { - float x = static_cast(data[i].timestamp - begin_time) / 1000000; + float x = static_cast(data[i].timestamp - begin_time) / + kNumMicrosecsPerSec; rtc::Optional y = extract(data[i]); if (y) { sum += *y; @@ -267,7 +275,8 @@ void AccumulatePairs( TimeSeries* result) { ResultType sum = 0; for (size_t i = 1; i < data.size(); i++) { - float x = static_cast(data[i].timestamp - begin_time) / 1000000; + float x = static_cast(data[i].timestamp - begin_time) / + kNumMicrosecsPerSec; rtc::Optional y = extract(data[i - 1], data[i]); if (y) sum += *y; @@ -307,13 +316,118 @@ void MovingAverage( sum_in_window -= *value; ++window_index_begin; } - float window_duration_s = static_cast(window_duration_us) / 1000000; - float x = static_cast(t - begin_time) / 1000000; + float window_duration_s = + static_cast(window_duration_us) / kNumMicrosecsPerSec; + float x = static_cast(t - begin_time) / kNumMicrosecsPerSec; float y = sum_in_window / window_duration_s; result->points.emplace_back(x, y); } } +const char kUnknownEnumValue[] = "unknown"; + +const char kIceCandidateTypeLocal[] = "local"; +const char kIceCandidateTypeStun[] = "stun"; +const char kIceCandidateTypePrflx[] = "prflx"; +const char kIceCandidateTypeRelay[] = "relay"; + +const char kProtocolUdp[] = "udp"; +const char kProtocolTcp[] = "tcp"; +const char kProtocolSsltcp[] = "ssltcp"; +const char kProtocolTls[] = "tls"; + +const char kAddressFamilyIpv4[] = "ipv4"; +const char kAddressFamilyIpv6[] = "ipv6"; + +const char kNetworkTypeEthernet[] = "ethernet"; +const char kNetworkTypeLoopback[] = "loopback"; +const char kNetworkTypeWifi[] = "wifi"; +const char kNetworkTypeVpn[] = "vpn"; +const char kNetworkTypeCellular[] = "cellular"; + +std::string GetIceCandidateTypeAsString(webrtc::IceCandidateType type) { + switch (type) { + case webrtc::IceCandidateType::kLocal: + return kIceCandidateTypeLocal; + case webrtc::IceCandidateType::kStun: + return kIceCandidateTypeStun; + case webrtc::IceCandidateType::kPrflx: + return kIceCandidateTypePrflx; + case webrtc::IceCandidateType::kRelay: + return kIceCandidateTypeRelay; + default: + return kUnknownEnumValue; + } +} + +std::string GetProtocolAsString(webrtc::IceCandidatePairProtocol protocol) { + switch (protocol) { + case webrtc::IceCandidatePairProtocol::kUdp: + return kProtocolUdp; + case webrtc::IceCandidatePairProtocol::kTcp: + return kProtocolTcp; + case webrtc::IceCandidatePairProtocol::kSsltcp: + return kProtocolSsltcp; + case webrtc::IceCandidatePairProtocol::kTls: + return kProtocolTls; + default: + return kUnknownEnumValue; + } +} + +std::string GetAddressFamilyAsString( + webrtc::IceCandidatePairAddressFamily family) { + switch (family) { + case webrtc::IceCandidatePairAddressFamily::kIpv4: + return kAddressFamilyIpv4; + case webrtc::IceCandidatePairAddressFamily::kIpv6: + return kAddressFamilyIpv6; + default: + return kUnknownEnumValue; + } +} + +std::string GetNetworkTypeAsString(webrtc::IceCandidateNetworkType type) { + switch (type) { + case webrtc::IceCandidateNetworkType::kEthernet: + return kNetworkTypeEthernet; + case webrtc::IceCandidateNetworkType::kLoopback: + return kNetworkTypeLoopback; + case webrtc::IceCandidateNetworkType::kWifi: + return kNetworkTypeWifi; + case webrtc::IceCandidateNetworkType::kVpn: + return kNetworkTypeVpn; + case webrtc::IceCandidateNetworkType::kCellular: + return kNetworkTypeCellular; + default: + return kUnknownEnumValue; + } +} + +std::string GetCandidatePairLogDescriptionAsString( + const ParsedRtcEventLog::IceCandidatePairConfig& config) { + // Example: stun:wifi->relay(tcp):cellular@udp:ipv4 + // represents a pair of a local server-reflexive candidate on a WiFi network + // and a remote relay candidate using TCP as the relay protocol on a cell + // network, when the candidate pair communicates over UDP using IPv4. + std::stringstream ss; + std::string local_candidate_type = + GetIceCandidateTypeAsString(config.local_candidate_type); + std::string remote_candidate_type = + GetIceCandidateTypeAsString(config.remote_candidate_type); + if (config.local_candidate_type == webrtc::IceCandidateType::kRelay) { + local_candidate_type += + "(" + GetProtocolAsString(config.local_relay_protocol) + ")"; + } + ss << local_candidate_type << ":" + << GetNetworkTypeAsString(config.local_network_type) << ":" + << GetAddressFamilyAsString(config.local_address_family) << "->" + << remote_candidate_type << ":" + << GetAddressFamilyAsString(config.remote_address_family) << "@" + << GetProtocolAsString(config.candidate_pair_protocol); + return ss.str(); +} + } // namespace EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log) @@ -526,6 +640,16 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log) alr_state_events_.push_back(parsed_log_.GetAlrState(i)); break; } + case ParsedRtcEventLog::ICE_CANDIDATE_PAIR_CONFIG: { + ice_candidate_pair_configs_.push_back( + parsed_log_.GetIceCandidatePairConfig(i)); + break; + } + case ParsedRtcEventLog::ICE_CANDIDATE_PAIR_EVENT: { + ice_candidate_pair_events_.push_back( + parsed_log_.GetIceCandidatePairEvent(i)); + break; + } case ParsedRtcEventLog::UNKNOWN_EVENT: { break; } @@ -538,7 +662,7 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log) } begin_time_ = first_timestamp; end_time_ = last_timestamp; - call_duration_s_ = static_cast(end_time_ - begin_time_) / 1000000; + call_duration_s_ = ToCallTime(end_time_); if (last_log_start) { // The log was missing the last LOG_END event. Fake it. log_segments_.push_back(std::make_pair(*last_log_start, end_time_)); @@ -625,7 +749,7 @@ rtc::Optional EventLogAnalyzer::EstimateRtpClockFrequency( last_rtp_timestamp = unwrapper.Unwrap(packets[i].header.timestamp); last_log_timestamp = packets[i].timestamp; } - if (last_log_timestamp - first_log_timestamp < 1000000) { + if (last_log_timestamp - first_log_timestamp < kNumMicrosecsPerSec) { RTC_LOG(LS_WARNING) << "Failed to estimate RTP clock frequency: Stream too short. (" << packets.size() << " packets, " @@ -633,7 +757,8 @@ rtc::Optional EventLogAnalyzer::EstimateRtpClockFrequency( return rtc::nullopt; } double duration = - static_cast(last_log_timestamp - first_log_timestamp) / 1000000; + static_cast(last_log_timestamp - first_log_timestamp) / + kNumMicrosecsPerSec; double estimated_frequency = (last_rtp_timestamp - first_rtp_timestamp) / duration; for (uint32_t f : {8000, 16000, 32000, 48000, 90000}) { @@ -648,7 +773,7 @@ rtc::Optional EventLogAnalyzer::EstimateRtpClockFrequency( } float EventLogAnalyzer::ToCallTime(int64_t timestamp) const { - return static_cast(timestamp - begin_time_) / 1000000; + return static_cast(timestamp - begin_time_) / kNumMicrosecsPerSec; } void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction, @@ -699,8 +824,7 @@ void EventLogAnalyzer::CreateAccumulatedPacketsTimeSeries( std::string label = label_prefix + " " + GetStreamName(stream_id); TimeSeries time_series(label, LineStyle::kStep); for (size_t i = 0; i < packet_stream.size(); i++) { - float x = static_cast(packet_stream[i].timestamp - begin_time_) / - 1000000; + float x = ToCallTime(packet_stream[i].timestamp); time_series.points.emplace_back(x, i + 1); } @@ -738,7 +862,7 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) { parsed_log_.GetAudioPlayout(i, &ssrc); uint64_t timestamp = parsed_log_.GetTimestamp(i); if (MatchingSsrc(ssrc, desired_ssrc_)) { - float x = static_cast(timestamp - begin_time_) / 1000000; + float x = ToCallTime(timestamp); float y = static_cast(timestamp - last_playout[ssrc]) / 1000; if (time_series[ssrc].points.size() == 0) { // There were no previusly logged playout for this SSRC. @@ -776,7 +900,7 @@ void EventLogAnalyzer::CreateAudioLevelGraph(Plot* plot) { // streams. Tracking bug: webrtc:6399 for (auto& packet : packet_stream) { if (packet.header.extension.hasAudioLevel) { - float x = static_cast(packet.timestamp - begin_time_) / 1000000; + float x = ToCallTime(packet.timestamp); // The audio level is stored in -dBov (so e.g. -10 dBov is stored as 10) // Here we convert it to dBov. float y = static_cast(-packet.header.extension.audioLevel); @@ -867,7 +991,7 @@ void EventLogAnalyzer::CreateIncomingPacketLossGraph(Plot* plot) { std::max(highest_prior_seq_number, sequence_number); ++window_index_begin; } - float x = static_cast(t - begin_time_) / 1000000; + float x = ToCallTime(t); int64_t expected_packets = highest_seq_number - highest_prior_seq_number; if (expected_packets > 0) { int64_t received_packets = window_index_end - window_index_begin; @@ -956,7 +1080,7 @@ void EventLogAnalyzer::CreateFractionLossGraph(Plot* plot) { TimeSeries time_series("Fraction lost", LineStyle::kLine, PointStyle::kHighlight); for (auto& bwe_update : bwe_loss_updates_) { - float x = static_cast(bwe_update.timestamp - begin_time_) / 1000000; + float x = ToCallTime(bwe_update.timestamp); float y = static_cast(bwe_update.fraction_loss) / 255 * 100; time_series.points.emplace_back(x, y); } @@ -1016,8 +1140,8 @@ void EventLogAnalyzer::CreateTotalBitrateGraph( ++window_index_begin; } float window_duration_in_seconds = - static_cast(window_duration_) / 1000000; - float x = static_cast(time - begin_time_) / 1000000; + static_cast(window_duration_) / kNumMicrosecsPerSec; + float x = ToCallTime(time); float y = bytes_in_window * 8 / window_duration_in_seconds / 1000; bitrate_series.points.emplace_back(x, y); } @@ -1027,8 +1151,7 @@ void EventLogAnalyzer::CreateTotalBitrateGraph( if (desired_direction == kOutgoingPacket) { TimeSeries loss_series("Loss-based estimate", LineStyle::kStep); for (auto& loss_update : bwe_loss_updates_) { - float x = - static_cast(loss_update.timestamp - begin_time_) / 1000000; + float x = ToCallTime(loss_update.timestamp); float y = static_cast(loss_update.new_bitrate) / 1000; loss_series.points.emplace_back(x, y); } @@ -1046,8 +1169,7 @@ void EventLogAnalyzer::CreateTotalBitrateGraph( BandwidthUsage last_detector_state = BandwidthUsage::kBwNormal; for (auto& delay_update : bwe_delay_updates_) { - float x = - static_cast(delay_update.timestamp - begin_time_) / 1000000; + float x = ToCallTime(delay_update.timestamp); float y = static_cast(delay_update.bitrate_bps) / 1000; if (last_detector_state != delay_update.detector_state) { @@ -1079,7 +1201,7 @@ void EventLogAnalyzer::CreateTotalBitrateGraph( TimeSeries created_series("Probe cluster created.", LineStyle::kNone, PointStyle::kHighlight); for (auto& cluster : bwe_probe_cluster_created_events_) { - float x = static_cast(cluster.timestamp - begin_time_) / 1000000; + float x = ToCallTime(cluster.timestamp); float y = static_cast(cluster.bitrate_bps) / 1000; created_series.points.emplace_back(x, y); } @@ -1088,7 +1210,7 @@ void EventLogAnalyzer::CreateTotalBitrateGraph( PointStyle::kHighlight); for (auto& result : bwe_probe_result_events_) { if (result.bitrate_bps) { - float x = static_cast(result.timestamp - begin_time_) / 1000000; + float x = ToCallTime(result.timestamp); float y = static_cast(*result.bitrate_bps) / 1000; result_series.points.emplace_back(x, y); } @@ -1150,7 +1272,7 @@ void EventLogAnalyzer::CreateTotalBitrateGraph( for (const auto& kv : remb_packets) { const LoggedRtcpPacket* const rtcp = kv.second; const rtcp::Remb* const remb = static_cast(rtcp->packet.get()); - float x = static_cast(rtcp->timestamp - begin_time_) / 1000000; + float x = ToCallTime(rtcp->timestamp); float y = static_cast(remb->bitrate_bps()) / 1000; remb_series.points.emplace_back(x, y); } @@ -1290,8 +1412,7 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) { acked_bitrate.Update(packet.payload_size, packet.arrival_time_ms); bitrate_bps = acked_bitrate.Rate(feedback.back().arrival_time_ms); } - float x = static_cast(clock.TimeInMicroseconds() - begin_time_) / - 1000000; + float x = ToCallTime(clock.TimeInMicroseconds()); float y = bitrate_bps.value_or(0) / 1000; acked_time_series.points.emplace_back(x, y); #if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE) @@ -1322,8 +1443,7 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) { if (observer.GetAndResetBitrateUpdated() || time_us - last_update_us >= 1e6) { uint32_t y = observer.last_bitrate_bps() / 1000; - float x = static_cast(clock.TimeInMicroseconds() - begin_time_) / - 1000000; + float x = ToCallTime(clock.TimeInMicroseconds()); time_series.points.emplace_back(x, y); last_update_us = time_us; } @@ -1396,15 +1516,13 @@ void EventLogAnalyzer::CreateReceiveSideBweSimulationGraph(Plot* plot) { rtc::Optional bitrate_bps = acked_bitrate.Rate(arrival_time_ms); if (bitrate_bps) { uint32_t y = *bitrate_bps / 1000; - float x = static_cast(clock.TimeInMicroseconds() - begin_time_) / - 1000000; + float x = ToCallTime(clock.TimeInMicroseconds()); acked_time_series.points.emplace_back(x, y); } if (packet_router.GetAndResetBitrateUpdated() || clock.TimeInMicroseconds() - last_update_us >= 1e6) { uint32_t y = packet_router.last_bitrate_bps() / 1000; - float x = static_cast(clock.TimeInMicroseconds() - begin_time_) / - 1000000; + float x = ToCallTime(clock.TimeInMicroseconds()); time_series.points.emplace_back(x, y); last_update_us = clock.TimeInMicroseconds(); } @@ -1475,9 +1593,7 @@ void EventLogAnalyzer::CreateNetworkDelayFeedbackGraph(Plot* plot) { feedback_adapter.GetTransportFeedbackVector(); SortPacketFeedbackVector(&feedback); for (const PacketFeedback& packet : feedback) { - float x = - static_cast(clock.TimeInMicroseconds() - begin_time_) / - 1000000; + float x = ToCallTime(clock.TimeInMicroseconds()); if (packet.send_time_ms == PacketFeedback::kNoSendTime) { late_feedback_series.points.emplace_back(x, prev_y); continue; @@ -1587,7 +1703,7 @@ void EventLogAnalyzer::CreatePacerDelayGraph(Plot* plot) { *estimated_frequency * 1000; double send_time_ms = static_cast(packet.timestamp - first_send_timestamp) / 1000; - float x = static_cast(packet.timestamp - begin_time_) / 1000000; + float x = ToCallTime(packet.timestamp); float y = send_time_ms - capture_time_ms; pacer_delay_series.points.emplace_back(x, y); } @@ -1609,7 +1725,7 @@ void EventLogAnalyzer::CreateTimestampGraph(Plot* plot) { TimeSeries timestamp_data(GetStreamName(stream_id) + " capture-time", LineStyle::kLine, PointStyle::kHighlight); for (LoggedRtpPacket packet : rtp_packets) { - float x = static_cast(packet.timestamp - begin_time_) / 1000000; + float x = ToCallTime(packet.timestamp); float y = packet.header.timestamp; timestamp_data.points.emplace_back(x, y); } @@ -1628,7 +1744,7 @@ void EventLogAnalyzer::CreateTimestampGraph(Plot* plot) { continue; rtcp::SenderReport* sr; sr = static_cast(rtcp.packet.get()); - float x = static_cast(rtcp.timestamp - begin_time_) / 1000000; + float x = ToCallTime(rtcp.timestamp); float y = sr->rtp_timestamp(); timestamp_data.points.emplace_back(x, y); } @@ -1986,6 +2102,81 @@ void EventLogAnalyzer::CreateAudioJitterBufferGraph( plot->SetTitle("NetEq timing"); } +void EventLogAnalyzer::CreateIceCandidatePairConfigGraph(Plot* plot) { + std::map configs_by_cp_id; + for (const auto& config : ice_candidate_pair_configs_) { + if (configs_by_cp_id.find(config.candidate_pair_id) == + configs_by_cp_id.end()) { + const std::string candidate_pair_desc = + GetCandidatePairLogDescriptionAsString(config); + configs_by_cp_id[config.candidate_pair_id] = TimeSeries( + candidate_pair_desc, LineStyle::kNone, PointStyle::kHighlight); + candidate_pair_desc_by_id_[config.candidate_pair_id] = + candidate_pair_desc; + } + float x = ToCallTime(config.timestamp); + float y = static_cast(config.type); + configs_by_cp_id[config.candidate_pair_id].points.emplace_back(x, y); + } + + // TODO(qingsi): There can be a large number of candidate pairs generated by + // certain calls and the frontend cannot render the chart in this case due to + // the failure of generating a palette with the same number of colors. + for (auto& kv : configs_by_cp_id) { + plot->AppendTimeSeries(std::move(kv.second)); + } + + plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); + plot->SetSuggestedYAxis(0, 3, "Numeric Config Type", kBottomMargin, + kTopMargin); + plot->SetTitle("[IceEventLog] ICE candidate pair configs"); +} + +std::string EventLogAnalyzer::GetCandidatePairLogDescriptionFromId( + uint32_t candidate_pair_id) { + if (candidate_pair_desc_by_id_.find(candidate_pair_id) != + candidate_pair_desc_by_id_.end()) { + return candidate_pair_desc_by_id_[candidate_pair_id]; + } + for (const auto& config : ice_candidate_pair_configs_) { + // TODO(qingsi): Add the handling of the "Updated" config event after the + // visualization of property change for candidate pairs is introduced. + if (candidate_pair_desc_by_id_.find(config.candidate_pair_id) == + candidate_pair_desc_by_id_.end()) { + const std::string candidate_pair_desc = + GetCandidatePairLogDescriptionAsString(config); + candidate_pair_desc_by_id_[config.candidate_pair_id] = + candidate_pair_desc; + } + } + return candidate_pair_desc_by_id_[candidate_pair_id]; +} + +void EventLogAnalyzer::CreateIceConnectivityCheckGraph(Plot* plot) { + std::map checks_by_cp_id; + for (const auto& event : ice_candidate_pair_events_) { + if (checks_by_cp_id.find(event.candidate_pair_id) == + checks_by_cp_id.end()) { + checks_by_cp_id[event.candidate_pair_id] = TimeSeries( + GetCandidatePairLogDescriptionFromId(event.candidate_pair_id), + LineStyle::kNone, PointStyle::kHighlight); + } + float x = ToCallTime(event.timestamp); + float y = static_cast(event.type); + checks_by_cp_id[event.candidate_pair_id].points.emplace_back(x, y); + } + + // TODO(qingsi): The same issue as in CreateIceCandidatePairConfigGraph. + for (auto& kv : checks_by_cp_id) { + plot->AppendTimeSeries(std::move(kv.second)); + } + + plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); + plot->SetSuggestedYAxis(0, 4, "Numeric Connectivity State", kBottomMargin, + kTopMargin); + plot->SetTitle("[IceEventLog] ICE connectivity checks"); +} + void EventLogAnalyzer::Notification( std::unique_ptr notification) { notifications_.push_back(std::move(notification)); diff --git a/rtc_tools/event_log_visualizer/analyzer.h b/rtc_tools/event_log_visualizer/analyzer.h index 5d0faaba61..fafce66d73 100644 --- a/rtc_tools/event_log_visualizer/analyzer.h +++ b/rtc_tools/event_log_visualizer/analyzer.h @@ -109,6 +109,9 @@ class EventLogAnalyzer { int file_sample_rate_hz, Plot* plot); + void CreateIceCandidatePairConfigGraph(Plot* plot); + void CreateIceConnectivityCheckGraph(Plot* plot); + // Returns a vector of capture and arrival timestamps for the video frames // of the stream with the most number of frames. std::vector> GetFrameTimestamps() const; @@ -159,6 +162,8 @@ class EventLogAnalyzer { void Notification(std::unique_ptr notification); + std::string GetCandidatePairLogDescriptionFromId(uint32_t candidate_pair_id); + const ParsedRtcEventLog& parsed_log_; // A list of SSRCs we are interested in analysing. @@ -204,6 +209,14 @@ class EventLogAnalyzer { std::vector alr_state_events_; + std::vector + ice_candidate_pair_configs_; + + std::vector + ice_candidate_pair_events_; + + std::map candidate_pair_desc_by_id_; + // Window and step size used for calculating moving averages, e.g. bitrate. // The generated data points will be |step_| microseconds apart. // Only events occuring at most |window_duration_| microseconds before the diff --git a/rtc_tools/event_log_visualizer/main.cc b/rtc_tools/event_log_visualizer/main.cc index b38f1a4fcf..862fcad27f 100644 --- a/rtc_tools/event_log_visualizer/main.cc +++ b/rtc_tools/event_log_visualizer/main.cc @@ -114,6 +114,12 @@ DEFINE_bool(plot_audio_encoder_num_channels, DEFINE_bool(plot_audio_jitter_buffer, false, "Plot the audio jitter buffer delay profile."); +DEFINE_bool(plot_ice_candidate_pair_config, + false, + "Plot the ICE candidate pair config events."); +DEFINE_bool(plot_ice_connectivity_check, + false, + "Plot the ICE candidate pair connectivity checks."); DEFINE_string( force_fieldtrials, @@ -314,6 +320,13 @@ int main(int argc, char* argv[]) { collection->AppendNewPlot()); } + if (FLAG_plot_ice_candidate_pair_config) { + analyzer.CreateIceCandidatePairConfigGraph(collection->AppendNewPlot()); + } + if (FLAG_plot_ice_connectivity_check) { + analyzer.CreateIceConnectivityCheckGraph(collection->AppendNewPlot()); + } + collection->Draw(); if (FLAG_print_triage_notifications) { @@ -352,4 +365,6 @@ void SetAllPlotFlags(bool setting) { FLAG_plot_audio_encoder_dtx = setting; FLAG_plot_audio_encoder_num_channels = setting; FLAG_plot_audio_jitter_buffer = setting; + FLAG_plot_ice_candidate_pair_config = setting; + FLAG_plot_ice_connectivity_check = setting; }